Skip to content

Carry manifest rewrites into the shared Stage/StageRecord producer graph #721

Open

Description

@juaristi22

Found by the Codex adversarial review of #717 (medium; dispositioned as a deferral in the PR's review-response comment).

Mechanics

country_stage_plan compiles only stage.outputs into Stage.produces (packages/microcosm-build/src/microcosm/build/country_spec.py, plan-assembly block); the parsed rewrites key (source_manifest.py:202) never reaches StagePlan or StageRecord. A stage that rewrites already-produced columns — E3's frs_education_grant_split (housing_benefit_reported), and now E7's hmrc_spi_income_spine (38 rewrites: the six income components, the 29 stage-2 columns, the three retained leaves redrawn on SPI rows) — can materially change final column values while:

  • StageRecord.produced and per-stage nonzero_share still attribute the column to its original producer;
  • the driver's --emit-nonzero-shares "final" list is built from record.produced (plus a hardcoded FRS_EDUCATION_GRANT_REWRITES carve-out in tools/build_uk_frs_spine.py — evidence the gap has already forced one ad-hoc patch);
  • coverage/provenance evidence points at the pre-rewrite producer.

The declarations themselves are reviewable and lockstep-tested (E7's test_e7_outputs_and_rewrites_are_backed_by_runtime_constants pins them against runtime written-column constants), so this is a provenance/reviewability gap, not a correctness hole — but it weakens the one-canonical-producer story exactly where stages intentionally overwrite.

Proposed shape

  1. Carry rewrites as first-class metadata on Stage and StageRecord.
  2. Validate at plan assembly that every rewrite has an earlier canonical producer in the selected plan (fail closed on rewrites of never-produced columns).
  3. Record rewrite-stage provenance (and per-stage nonzero shares for rewritten columns) separately from newly produced columns, and derive the drivers' "final columns" lists from produces ∪ rewrites instead of hardcoded carve-outs.

Shared-layer change (US/BE unaffected behaviorally today — no US stage declares rewrites — but the validation applies country-agnostically).

Refs #717 (adversarial review), #683/#145 (E7/WS-E), #679 (E3's grant-split precedent).

🤖 Generated with Claude Code

Activity

  1. added a commit that references this issue on Aug 19, 2026
  2. juaristi22 commented on Aug 19, 2026

    @juaristi22
    CollaboratorAuthor

    Cross-increment evidence from E5 (#714) post-#717 rebase: in-place rewrites make a stage's input state unreconstructible from the final artifact. The E5 licensed acceptance carried an out-of-build instrument that refit the WAS wealth QRF chain at the declared seed and reproduced all 13 stored columns bitwise — on the E5-only roster. After #717 merged, the instrument can no longer bind: hmrc_spi_income_spine rewrites dividend_income in place on the FRS rows, so the predictor surface was_wealth actually saw (capital_income = savings interest + dividends) cannot be recovered from the final H5. E5's receipts now bind refit fidelity to the pre-rebase run plus byte-stable stage shares, with in-build determinism carried by payload-identical twins — but a shared producer graph that preserves pre-rewrite column state (or receipts it) would restore the stronger out-of-build instrument for every stage upstream of a rewrite.

    🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions