                ],
            }
        ),
        encoding="utf-8",
    )

    manifest = repro.build_manifest(
        repo_root=repo_root,
        env_snapshot_path=env,
        dep_report_path=deps,
        gap_registry_path=gaps,
        exp_index_path=exp,
        local_gate_path=gate,
    )

    s = manifest["summary"]
    assert s["environment"]["available"] is True
    assert s["environment"]["python_version"] == "3.11.0"
    assert "CODEX_MODE" in s["environment"]["codex_env_var_keys"]

    assert s["dependencies"]["available"] is True
    assert s["dependencies"]["total_packages"] == 2
    assert s["dependencies"]["direct_dependencies"] == 1

    assert s["gaps"]["available"] is True
    assert s["gaps"]["total_gaps"] == 2
    assert s["gaps"]["by_status"]["open"] == 1

    assert s["experiments"]["available"] is True
    assert s["experiments"]["total_runs"] == 2
    assert "conf/train.yaml" in s["experiments"]["unique_config_paths"]

    assert s["local_gate"]["available"] is True
    assert s["local_gate"]["overall_returncode"] == 1
    assert "pytest_codex_ml" in s["local_gate"]["failed_commands"]


def test_main_writes_files(tmp_path: Path, monkeypatch):
    repo_root = tmp_path
    json_out = tmp_path / "repro.json"
    md_out = tmp_path / "repro.md"

    # Patch cwd-style args by monkeypatching argv via direct call to main()
    rc = repro.main(
        [
            "--repo-root",
            str(repo_root),
            "--env-snapshot",
            str(tmp_path / "codex_env_snapshot.json"),
            "--dep-report",
            str(tmp_path / "codex_dependency_report.json"),
            "--gap-registry",
            str(tmp_path / "codex_gap_registry.yaml"),
            "--experiment-index",
            str(tmp_path / "codex_experiment_index.json"),
            "--local-gate",
            str(tmp_path / "codex_local_gate_report.json"),
            "--json-out",
            str(json_out),
            "--md-out",
            str(md_out),
        ]
    )
    assert rc == 0
    assert json_out.exists()
    assert md_out.exists()

    data = json.loads(json_out.read_text(encoding="utf-8"))
    assert "summary" in data
```

===============================================================================
3) Documentation – docs/reproducibility/repro_manifest_and_status_digest.md
===========================================================================

Create/overwrite: docs/reproducibility/repro_manifest_and_status_digest.md

````markdown
# Reproducibility Manifest & Status Digest for `_codex_` (Scaffolding)

This document describes the current reproducibility manifest tooling in
`_codex_`, and how it ties together:

- Environment snapshot
- Dependencies
- Gap registry
- Experiment index
- Local gate (internal CI spine)

The implementation is deliberately minimal and offline-only.

## 1. Tool: `codex_repro_manifest.py`

Path:

- `tools/codex_repro_manifest.py`

Purpose:

- Aggregate several existing artifacts into a single, structured
  manifest and a human-readable Markdown digest.

Inputs (all optional, best-effort):

- `codex_env_snapshot.json`
- `codex_dependency_report.json`
- `codex_gap_registry.yaml`
- `codex_experiment_index.json`
- `codex_local_gate_report.json`

Outputs:

- `codex_reproducibility_manifest.json`
- `codex_reproducibility_manifest.md`

Example usage:

```bash
python tools/codex_repro_manifest.py \
  --repo-root . \
  --env-snapshot codex_env_snapshot.json \
  --dep-report codex_dependency_report.json \
  --gap-registry codex_gap_registry.yaml \
  --experiment-index codex_experiment_index.json \
  --local-gate codex_local_gate_report.json \
  --json-out codex_reproducibility_manifest.json \
  --md-out codex_reproducibility_manifest.md
````

If any of the input files are missing, the corresponding section in the
manifest is marked as `available: false` and omitted from detailed
summaries.

## 2. Manifest Structure

Top-level fields (JSON):

* `generated_at` – UTC timestamp when the manifest was built.
* `repo_root` – repository root path used.
* `inputs` – absolute paths of each input file.
* `summary` – aggregate sections:

  * `environment`
  * `dependencies`
  * `gaps`
  * `experiments`
  * `local_gate`

Each section contains a small, non-sensitive summary:

* Environment:

  * Python version
  * OS platform/release
  * Keys of any `CODEX_*` environment variables.
* Dependencies:

  * Total package count
  * Count of packages marked as `kind: direct` (if present).
* Gaps:

  * Total gaps
  * Counts by `status`
  * Counts by `risk_level`
* Experiments:

  * Total runs
  * Runs by mode (`train`, `eval`, etc.)
  * Unique config paths
* Local gate:

  * Overall return code
  * Total commands
  * List of failed command names.

## 3. Markdown Digest

`codex_reproducibility_manifest.md` is a human-readable summary with:

1. Environment
2. Dependencies
3. Gaps
4. Experiments
5. Local gate

Each section shows whether the corresponding input was available and,
if so, prints small aggregates (counts, modes, status/risk breakdown).

This digest is intended for:

* Quick operator review
* Attaching to internal status reports
* Anchoring reproducibility discussions

## 4. Relationship to Reproducibility Checklist

This manifest addresses several key items from common MLOps
reproducibility checklists:

* **Environment**:

  * Python/OS version recorded in a machine-readable file.
* **Dependencies**:

  * Package counts and direct dependencies recorded.
* **Code & Gaps**:

  * Gaps are captured via `codex_gap_registry.yaml` summaries.
* **Experiments**:

  * Runs and configs are summarized via `codex_experiment_index.json`.
* **Tests / Local CI**:

  * Local gate results (pass/fail) captured and summarized.

It does *not* attempt to solve:

* Full artifact versioning
* Dataset snapshots or hashes
* Cryptographic signing

Those can be added in future iterations, using this manifest as a
stable anchor.

## 5. Integration with Task Sequence

The task sequence (`codex_task_sequence.yaml`) includes a dedicated
step for running `codex_repro_manifest.py` near the end of the
pipeline. This ensures that:

* Each run of the sequence leaves behind a fresh manifest.
* Downstream tools can consume `codex_reproducibility_manifest.*`
  instead of recombining raw inputs.

The step is run with `record_and_continue` error handling, so failures
to build the manifest do not wipe out other work but are recorded in
the logs and gap registry.

````

===============================================================================
4) Extend codex_task_sequence.yaml – reproducibility manifest step
===============================================================================

Do **not** rewrite the entire `codex_task_sequence.yaml`. Apply this
minimal textual extension:

1. Locate the phase that corresponds to **Reproducibility / Reporting**
   or the finalization phase (often near the end of the `phases` list).
   If such a phase exists (for example with a name like
   `"Finalization & Reporting"` or `"Reproducibility & Reports"`),
   append a new step under its `steps` list:

```yaml
       - id: "<PHASE_ID>.R1"
         description: >
           Generate a reproducibility manifest and status digest by
           aggregating environment snapshot, dependency report, gap
           registry, experiment index, and local gate report. This
           step is offline-only and produces both JSON and Markdown
           artifacts.
         actions:
           - >
             python tools/codex_repro_manifest.py
             --repo-root .
             --env-snapshot codex_env_snapshot.json
             --dep-report codex_dependency_report.json
             --gap-registry codex_gap_registry.yaml
             --experiment-index codex_experiment_index.json
             --local-gate codex_local_gate_report.json
             --json-out codex_reproducibility_manifest.json
             --md-out codex_reproducibility_manifest.md
         on_error:
           strategy: record_and_continue
````

Replace `<PHASE_ID>` with the numeric id of that phase (e.g. `"7.R1"`
if the phase id is 7). Match indentation with surrounding steps.

2. If there is **no** obvious Reproducibility/Reporting phase, append a
   new phase at the end of the `phases` list:

```yaml
       - id: 10
         name: Reproducibility Manifest & Status Digest
         steps:
           - id: "10.1"
             description: >
               Generate a reproducibility manifest and status digest by
               aggregating environment snapshot, dependency report, gap
               registry, experiment index, and local gate report. This
               step is offline-only and produces both JSON and Markdown
               artifacts.
             actions:
               - >
                 python tools/codex_repro_manifest.py
                 --repo-root .
                 --env-snapshot codex_env_snapshot.json
                 --dep-report codex_dependency_report.json
                 --gap-registry codex_gap_registry.yaml
                 --experiment-index codex_experiment_index.json
                 --local-gate codex_local_gate_report.json
                 --json-out codex_reproducibility_manifest.json
                 --md-out codex_reproducibility_manifest.md
             on_error:
               strategy: record_and_continue
```

Choose `id: 10` or the next unused integer, and align indentation with
existing phases.

===============================================================================
5) After applying this batch
============================

After you apply all changes from this batch, run locally (not by me):

* `pytest tests/tools/test_codex_repro_manifest.py -q`
* `pytest tests/tools -q`
* `python tools/codex_repro_manifest.py --repo-root . --json-out codex_reproducibility_manifest.json --md-out codex_reproducibility_manifest.md`
