Skip to content

Publish and enforce the cohort-final freeze #1757

Description

@pinin4fjords

Parent: #1745

Predecessor: #1756 and its stacked draft PR, which performed the single typed materialization.

Reopened by the 2026-08-17 programme review follow-up with a corrected purpose: the original body's deletion targets were checkpoint-branch-only or nonexistent (see the close comment below), but final-freeze publication and enforcement is a valid separate behavioral boundary, and keeping it separate keeps #1756 within one working day. The stack remains unmerged until complete, so this split introduces no dual-ownership window on main.

Prototype evidence: draft PR #1743 and checkpoint 3f11f175, especially the nominal final-state checks in svg.py and the post-final compilation assertions in tests/test_corridor_cohort_integration.py.

Retrieving the prototype: git fetch origin refs/pull/1743/head:pr-1743-checkpoint, then read files with git show 3f11f1758f16341ace6b1409eff53a36a36ec715:<path>. Never check that branch out into your worktree.

Outcome

Publish cohort-final as the binding geometry and ownership freeze, prohibit all later mutation, bind plan-level compatibility completeness, and convert the checkpoint's replay expectations into final-freeze locks.

Estimate: 4-6 focused hours, hard maximum one working day. Use a fresh worktree based on the predecessor PR.

Starting reproduction

pytest -q -n 0 "tests/test_corridor_cohort_integration.py::test_post_freeze_stages_are_validation_only" --collect-only -q

Zero collected on the predecessor. #1746's test_post_cohort_final_mutation_is_rejected guards the generic trace boundary; this issue makes the freeze binding for cohort ownership specifically.

Scope

  • svg.py: publish cohort-final (the COHORT_FINAL event from Trace final settlement and resolve seed-72 routing defects #1746, now cohort-backed with unchanged semantics: after it, validation only) immediately after Materialize accepted grants once through owner frames #1756's single typed materialization.
  • Enforce the freeze: patched compiler, solver, convergence-settlement, ownership-discovery, and geometry materialization functions may raise after cohort-final without affecting validation; instrumentation records zero geometry, owner, clearance, compiler, or solver mutation after cohort-final.
  • Owner sets and accepted grants cannot change after freeze; later stages perform no geometry translation.
  • Bind plan-level compatibility completeness: the accepted plan contains only explicit dispositions; every compatibility component in it carries the typed whole-group provenance required since Join convergence variables into the one cohort problem #1752; a silent witnesses_complete fallback anywhere in the accepted plan fails.
  • Convert the checkpoint's replay expectations into freeze locks: the checkpoint's test_curve_guard_observes_the_mandatory_canonical_replay and test_finalized_ledger_realizes_exact_keys_in_the_current_coordinate_frame asserted that replay compilation happened and reproduced ownership; their freeze property is re-expressed as test_post_freeze_stages_are_validation_only, and their geometric content is already carried by the opposing-bypass geometry lock from Retire the pre-request convergence settlement chain and land the four-case gate #1761, which must keep passing.

Non-goals

Code expected to become obsolete

None expected. If enforcement exposes a surviving mutation path, that path belongs to the child that owned its coordinate family; stop and repair there rather than deleting here.

Acceptance

  • Instrumentation proves zero compiler/solver calls after cohort-final and proves all post-cohort-final stages are validation-only with zero geometry, owner, or clearance mutation.
  • Owner sets and accepted grants cannot change after freeze.
  • The accepted plan contains only explicit, provenance-carrying dispositions; no migrated coordinate sits under a legacy owner via compatibility.
  • test_post_freeze_stages_are_validation_only passes; the opposing-bypass geometry lock and the four-case gate still pass.
  • The behavior-changing stacked PR runs CI and the authoritative render diff; it remains draft and unmerged until the complete stack is green.

Verification

pytest -q -n 0 tests/test_corridor_cohort_integration.py -k 'final or freeze or validation_only'
pytest -q -n 0 tests/test_deferred_final_guards.py
pytest -q -n 0 tests/test_member_geometry.py -k 'seed_15 or seed_77 or reservation_reroute_reseats'
pytest -q -n 0 tests/test_corridor_cohort_integration.py -k 'opposing_bypass or opposite_running'
ruff check src/nf_metro/layout/routing/corridor_cohort_integration.py src/nf_metro/render/svg.py tests/test_corridor_cohort_integration.py
ruff format --check src/nf_metro/layout/routing/corridor_cohort_integration.py src/nf_metro/render/svg.py tests/test_corridor_cohort_integration.py
mypy

Check the collected count on every -k run; zero collected exits 5, which reads like success.

#1653 guardrail and stop condition

The freeze is a fact to enforce, not a mechanism to extend. If enforcement reveals a stage that still needs to move geometry, stop: that is evidence an earlier owner model or translation basis is incomplete. Do not add another finalization pass, exemption, or adapter.

Activity

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