Source: docs/superpowers/plans/2026-08-12-v6-phase0-diagnostics.md · Plain text

V6 Phase 0 Diagnostics Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Produce immutable, provenance-complete V5 checkpoint, renderer-sampling, surface-evidence, appearance-oracle, and 16/8 multi-scene pilot artifacts before V6 changes are admitted.

Architecture: Keep the existing trainer and V5 model numerically unchanged. Add narrow CLI/output helpers around evaluation, a read-only evidence-audit module that samples the frozen state on target rays after inference, and deterministic label-blind scene selection. Every command writes to a new output directory and refuses an existing report.

Tech Stack: Python 3.11, PyTorch 2.7+, dataclasses, argparse, JSON, pytest, Ruff, uv, PowerShell.

Global Constraints


File Structure

Task 1: Immutable Evaluation Output Override

Files: - Modify: src/mcss/cli.py - Test: tests/test_cli_smoke.py

Interfaces: - Consumes: load_config(Path) -> ExperimentConfig, frozen dataclasses, Trainer.evaluate. - Produces: _with_evaluation_overrides(...) -> ExperimentConfig and CLI options mcss evaluate --output-dir PATH --n-samples N --ray-chunk-size N.

Add a test that trains the existing synthetic smoke config, evaluates to a temporary explicit directory, asserts evaluation_report.json exists there, then invokes the same command again and expects FileExistsError before model construction can overwrite it.

def test_evaluate_output_dir_is_explicit_and_immutable(tmp_path: Path) -> None:
    config_path = _synthetic_config(tmp_path, max_steps=1)
    checkpoint = _train_checkpoint(config_path)
    report_dir = tmp_path / "eval_step_000001_samples_8"

    assert main([
        "evaluate", "--config", str(config_path), "--checkpoint", str(checkpoint),
        "--output-dir", str(report_dir),
    ]) == 0
    assert (report_dir / "evaluation_report.json").is_file()

    with pytest.raises(FileExistsError, match="refusing to overwrite"):
        main([
            "evaluate", "--config", str(config_path), "--checkpoint", str(checkpoint),
            "--output-dir", str(report_dir),
        ])

Run:

uv run --extra dev pytest tests/test_cli_smoke.py::test_evaluate_output_dir_is_explicit_and_immutable -q

Expected: argparse rejects --output-dir or the report is written to the config output directory.

Add --output-dir, --n-samples, and --ray-chunk-size only to evaluate. Before constructing Trainer, replace the frozen nested training/model configs and refuse either existing report file.

from dataclasses import replace

def _with_evaluation_overrides(
    config: ExperimentConfig,
    *,
    output_dir: Path | None,
    n_samples: int | None,
    ray_chunk_size: int | None,
) -> ExperimentConfig:
    model = replace(
        config.model,
        n_samples=config.model.n_samples if n_samples is None else n_samples,
        ray_chunk_size=(
            config.model.ray_chunk_size if ray_chunk_size is None else ray_chunk_size
        ),
    )
    if output_dir is None:
        return replace(config, model=model)
    resolved = output_dir.resolve()
    for name in ("evaluation.json", "evaluation_report.json"):
        if (resolved / name).exists():
            raise FileExistsError(f"refusing to overwrite existing evaluation report: {resolved / name}")
    return replace(
        config,
        model=model,
        training=replace(config.training, output_dir=str(resolved)),
    )

The evaluate branch loads once, applies the override when provided, then constructs Trainer.

Run:

uv run --extra dev pytest tests/test_cli_smoke.py -q

Expected: all CLI tests pass.

Run:

Get-FileHash -Algorithm SHA256 src\mcss\cli.py,tests\test_cli_smoke.py

Expected: two SHA-256 rows; retain them in the execution log.

Task 2: Surface-Evidence Audit Core

Files: - Create: src/mcss/evidence_audit.py - Test: tests/test_evidence_audit.py

Interfaces: - Consumes: SceneState, Cameras, target depth [B,V,1,H,W], generate_rays, intersect_aabb, and _sample_volume. - Produces: audit_evidence(state, cameras, target_depth, target_visibility, n_samples=256) -> dict[str, object].

def test_depth_bins_use_half_max_voxel_edge_surface_band() -> None:
    distances = torch.tensor([[[1.0, 1.8, 2.0, 2.2, 3.0]]])
    target = torch.tensor([[[2.0]]])
    free, surface, behind = classify_depth_samples(distances, target, surface_band=0.25)
    assert free.tolist() == [[[True, False, False, False, False]]]
    assert surface.tolist() == [[[False, True, True, True, False]]]
    assert behind.tolist() == [[[False, False, False, False, True]]]

def test_flat_confidence_audit_returns_finite_counts() -> None:
    state, cameras, target_depth, visibility = _auditable_state()
    report = audit_evidence(state, cameras, target_depth, visibility, n_samples=16)
    assert report["schema_version"] == "mcss.evidence_audit.v1"
    assert report["bins"]["surface"]["count"] > 0
    assert report["bins"]["free"]["count"] > 0
    assert all(math.isfinite(v) for v in report["auroc"].values())

Run:

uv run --extra dev pytest tests/test_evidence_audit.py -q

Expected: import failure for mcss.evidence_audit.

Implement classify_depth_samples with strict free/behind comparisons and an inclusive surface band. In audit_evidence, reject states without StateEvidence; generate target rays, intersect the state AABB, sample exactly centered uniform distances, and sample only state.evidence.confidence. Compute voxel edges from state.bounds and state.spatial_shape; the surface band is half the largest edge. Valid audit rays require finite positive target depth, target visibility greater than 0.5, and an AABB hit.

Return JSON-safe counts, mean/std/deciles for free, surface, and behind, plus independently computed surface-vs-free and surface-vs-behind AUROC/AUPRC, Brier score, and ten-bin reliability data. Keep per-window and per-scene records; aggregate the primary result as an equal-weight scene macro and a deterministic seed-17 scene bootstrap confidence interval. Implement rank-based binary AUROC and precision-recall integration locally so Phase 0 adds no dependency. Return None, not NaN, when a class is empty, and include excluded-ray counts. Pooled ray samples are secondary diagnostics because samples on one ray are correlated.

def test_audit_rejects_targetless_state_and_counts_invalid_rays() -> None:
    state, cameras, depth, visibility = _auditable_state()
    with pytest.raises(ValueError, match="evidence"):
        audit_evidence(replace(state, evidence=None), cameras, depth, visibility)
    depth[..., 0, 0] = 0.0
    report = audit_evidence(state, cameras, depth, visibility, n_samples=16)
    assert report["rays"]["invalid_target_depth"] == 1

Run:

uv run --extra dev pytest tests/test_evidence_audit.py -q
uv run --extra dev ruff check src\mcss\evidence_audit.py tests\test_evidence_audit.py

Expected: tests and Ruff pass.

Task 3: Phase 0 Runner and Renderer Sweep

Files: - Create: src/mcss/phase0_runner.py - Create: scripts/run_v6_phase0.py - Test: tests/test_phase0_runner.py

Interfaces: - Consumes: ExperimentConfig, checkpoint paths, Trainer, audit_evidence. - Produces: evaluate_checkpoint, run_renderer_sweep, run_surface_audit, and an atomic top-level phase0_report.json.

def test_renderer_sweep_uses_unique_provenance_directories(tmp_path: Path) -> None:
    config, checkpoint = _trained_synthetic_case(tmp_path)
    report = run_renderer_sweep(config, checkpoint, tmp_path / "sweep", (8, 12))
    assert [item["n_samples"] for item in report["runs"]] == [8, 12]
    assert (tmp_path / "sweep" / "samples_0008" / "evaluation_report.json").is_file()
    assert (tmp_path / "sweep" / "samples_0012" / "evaluation_report.json").is_file()
    with pytest.raises(FileExistsError):
        run_renderer_sweep(config, checkpoint, tmp_path / "sweep", (8, 12))

Run:

uv run --extra dev pytest tests/test_phase0_runner.py::test_renderer_sweep_uses_unique_provenance_directories -q

Expected: import failure for mcss.phase0_runner.

Use dataclasses.replace to set model.n_samples and training.output_dir per run. Refuse the top-level report and every child evaluation report before doing work. Each run records checkpoint absolute path/SHA-256, source config absolute path/SHA-256, resolved config, scene/window counts, metrics, elapsed seconds, and device. Write JSON through a .part file plus os.replace.

run_surface_audit loads the checkpoint once, iterates the evaluation dataset without shuffle, runs model forward before accessing target depth, and aggregates per-window audit records without matching samples across scenes.

The script accepts:

--config PATH --checkpoint PATH --output-root PATH
--checkpoint-sweep PATH [PATH ...]
--sample-counts 64 128 256
--surface-audit

It requires at least one requested action and returns nonzero on any overwrite refusal or missing modality. It does not start training.

Run:

uv run --extra dev pytest tests/test_phase0_runner.py -q
uv run python scripts\run_v6_phase0.py --help

Expected: tests pass and help lists all arguments.

Task 4: V5 Typed-Appearance Oracle

Files: - Modify: src/mcss/appearance_oracle.py - Modify: src/mcss/oracle_runner.py - Modify: tests/test_appearance_oracle.py - Modify: tests/test_appearance_oracle_runner.py

Interfaces: - Produces: CLI option --field native|typed_appearance; native preserves the existing V4 variants, typed appearance runs typed_shared and typed_per_view on the existing V5 appearance resolution.

def test_typed_appearance_oracle_keeps_native_geometry_and_optimizes_typed_color() -> None:
    state = _state_with_typed_appearance(native_resolution=4, appearance_resolution=8)
    oracle = AppearanceOracle(
        state, target_views=2, variant="typed_shared", field="typed_appearance"
    )
    assert oracle.spatial_shape == (8, 8, 8)
    torch.testing.assert_close(oracle.density_logits, state.density_logits)
    rgb = oracle.render_rgb(FixedMeasurementRenderer(n_samples=8), _two_cameras())
    rgb.mean().backward()
    assert oracle.color_logits.grad is not None

Add a runner test asserting --field typed_appearance refuses a state without StateAppearance, writes field/shape/checkpoint hashes, and reports only shared/per-view typed variants.

uv run --extra dev pytest tests/test_appearance_oracle.py tests/test_appearance_oracle_runner.py -q

Expected: parser/variant rejection for typed_appearance and typed_shared.

For field="typed_appearance", initialize logits from reference_state.appearance.color; retain native density, native color, log variance, and bounds. To render, build a StateAppearance whose base color is 0.5, completion gate is one, residual is the optimized color logits, confidence and provenance are zero, and unknown probability is one. Attach it to a native SceneState. For the per-view variant, construct one such state per target view. Never upsample density or create a second 2x grid beyond the existing typed appearance shape.

Keep field="native" behavior and report schema compatible. Add field, native state shape, and optimized field shape to the report.

Tests render depth before and after oracle color optimization and require exact equality within dtype tolerance. Re-running into an existing oracle.json must raise FileExistsError without truncating oracle.jsonl.

uv run --extra dev pytest tests/test_appearance_oracle.py tests/test_appearance_oracle_runner.py -q
uv run --extra dev ruff check src\mcss\appearance_oracle.py src\mcss\oracle_runner.py tests\test_appearance_oracle.py tests\test_appearance_oracle_runner.py

Expected: all oracle tests and Ruff pass.

Task 5: Deterministic 16/8 Pilot Scene Selection

Files: - Modify: src/mcss/config.py - Modify: src/mcss/engine.py - Modify: src/mcss/data/manifest_dataset.py - Modify: tests/test_config.py - Modify: tests/test_manifest_dataset.py - Modify: src/mcss/phase0_runner.py - Test: tests/test_phase0_runner.py

Interfaces: - Produces: DatasetConfig.scene_ids: tuple[str, ...] | None, dataset manifest filtering, and select_pilot_scenes(root, split, count) -> tuple[str, ...].

def test_pilot_selection_is_label_blind_and_order_independent(tmp_path: Path) -> None:
    for scene_id in ("scene_c", "scene_a", "scene_b"):
        _write_minimal_manifest(tmp_path / scene_id, scene_id)
    first = select_pilot_scenes(tmp_path, split="train", count=2)
    second = select_pilot_scenes(tmp_path, split="train", count=2)
    assert first == second
    expected = tuple(sorted(
        ("scene_a", "scene_b", "scene_c"),
        key=lambda value: hashlib.sha256(f"v6-pilot:train:{value}".encode()).hexdigest(),
    )[:2])
    assert first == expected

Add config and dataset tests proving that unknown scene IDs fail and only selected manifests create entries.

Run:

uv run --extra dev pytest tests/test_phase0_runner.py tests/test_config.py tests/test_manifest_dataset.py -q

Expected: failures for missing scene_ids and selection function.

Parse optional YAML dataset.scene_ids as a nonempty unique string list and store it as a tuple. Pass it through build_dataset into ManifestSceneDataset. Filter loaded manifests by exact manifest.scene_id before constructing entries. Raise ValueError listing requested IDs not found. Omitted scene_ids preserves current behavior exactly.

Implement selection by discovering manifest.json, loading only each manifest's scene ID, sorting by the specified SHA-256 key, and refusing count greater than available scenes.

phase0_runner writes pilot_selection.json with input root, split, selection rule, candidate count, selected IDs, and manifest hashes. Generate train and validation YAML by replacing only root, scene_ids, length, max_steps, and output_dir from the accepted V5 config. The train pilot uses 10,000 micro-steps; validation never trains.

Run:

uv run --extra dev pytest tests/test_phase0_runner.py tests/test_config.py tests/test_manifest_dataset.py -q
uv run --extra dev pytest -q

Expected: full suite passes.

Task 6: Execute Phase 0 on Persisted V5 Artifacts

Files: - Create: configs/hypersim_er_v5_phase0.yaml - Create runtime artifacts only below: outputs/hypersim_er_v6_phase0_*

Interfaces: - Consumes checkpoints step_004000.pt, step_004500.pt, and step_005000.pt from the V5 overfit output. - Produces immutable reports used to decide V6a and renderer changes.

uv run --extra dev pytest -q
uv run --extra dev ruff check .
uv run python -m compileall -q src scripts
uv run python scripts\cuda_smoke.py

Expected: all commands exit zero; CUDA smoke reports every current architecture/mode finite.

uv run python scripts\run_v6_phase0.py `
  --config configs\hypersim_er_v5_phase0.yaml `
  --checkpoint outputs\hypersim_er_v5_appearance2x_overfit\checkpoints\step_004500.pt `
  --checkpoint-sweep `
    outputs\hypersim_er_v5_appearance2x_overfit\checkpoints\step_004000.pt `
    outputs\hypersim_er_v5_appearance2x_overfit\checkpoints\step_004500.pt `
    outputs\hypersim_er_v5_appearance2x_overfit\checkpoints\step_005000.pt `
  --sample-counts 64 128 256 `
  --surface-audit `
  --output-root outputs\hypersim_er_v6_phase0_v5_diagnostics

Expected: separate nonempty reports for each checkpoint and sample count, plus one surface audit.

Use unique directories and the diagnostic step-4500 checkpoint. This is a training-window capacity audit, not a final checkpoint-selection rule:

uv run python scripts\run_appearance_oracle.py `
  --config configs\hypersim_er_v5_phase0.yaml `
  --checkpoint outputs\hypersim_er_v5_appearance2x_overfit\checkpoints\step_004500.pt `
  --output-dir outputs\hypersim_er_v6_phase0_oracle_step4500 `
  --field typed_appearance `
  --steps 1000 `
  --learning-rate 0.05

Expected: oracle.json records checkpoint/config hashes and typed shared/per-view variants while native density remains fixed.

Generate selection/config artifacts, inspect that they contain 16 train and 8 validation IDs and no test IDs, then run:

uv run mcss train --config configs\hypersim_er_v5_phase0_pilot_train.yaml
uv run mcss evaluate `
  --config configs\hypersim_er_v5_phase0_pilot_val.yaml `
  --checkpoint outputs\hypersim_er_v6_phase0_v5_pilot_train\checkpoints\step_010000.pt `
  --output-dir outputs\hypersim_er_v6_phase0_v5_pilot_val_step10000

Expected: training and untouched validation reports reference only selected scene IDs.

Aggregate checkpoint replay, renderer delta, V5 per-scene surface-bin ordering/AUROC/AUPRC/calibration, oracle gaps, and pilot validation metrics into outputs/hypersim_er_v6_phase0_decision.json. Include a verdict for each spec gate and SHA-256 for every source report. Explicitly state that evidence-audit metrics do not select checkpoints. Do not modify V6 code until this report exists.

Run:

Get-FileHash -Algorithm SHA256 outputs\hypersim_er_v6_phase0_decision.json

Expected: one SHA-256 row and a decision report with no missing gate.