Contracts

birth-cutover-and-repair.md

Contract — Birth-Cutover, Acceptance Lock, and Repair

Event-sourced authoring (FR-008)

  • Scope: exactly two paths — claim (shell_pid/agent) and subtask-completion (tasks.md checkboxes), per #2684.
  • Given a WP is claimed or a subtask completed, when the write occurs, then it is recorded as an event (not authored to frontmatter/tasks.md), so no un-seeded runtime accrues.
  • Bound: no other authoring path changes (C-002).

Birth-cutover (FR-009, NFR-003, C-004)

  • Given a mission is merged, when the cutover runs at the bake stage, then cutover_mission reconciles residual runtime and stamps status_phase, with meta.json/status_phase routed to PRIMARY and seed events to COORD via the placement port (FR-002).
  • Timing (corrected): the _bake_mission_number hook is pre-target (executor.py:1319 runs before _phase_mission_to_target). The PRIMARY meta flip therefore rides the mission→target merge atomically — if the merge aborts, the flip never reaches target, which stays consistent (the un-merged mission branch is discarded). The plan must choose ONE of: (a) keep the bake hook and rely on merge-atomicity for the PRIMARY leg, or (b) relocate the stamp to a post-_phase_commit_and_assert phase. Either way the earlier "fires only after the target commit is durable" wording was inaccurate for this hook.
  • Two-partition atomicity (OPEN — IC-08 must resolve): cutover_mission(feature_dir) is single-feature_dir by signature and cannot natively split meta→PRIMARY (mission branch) from seed events→COORD (coord branch). IC-08 must either add a two-target form to the cutover spine OR delegate the COORD seed-event write to the existing coord projection (_phase_record_done_and_project), with a transactional envelope / resume-heal so a crash between the COORD write and the PRIMARY flip cannot leave a half-born mission.
  • Idempotent: a re-run (merge --resume, or the one-time migration) seeds 0 events and leaves status_phase + the event log byte-identical.
  • Sole writer: reuses cutover_mission / _flip_phase (no parallel status_phase writer) — a two-target form extends the spine, it does not fork it (C-004).
  • Gate: the birth-write itself must satisfy IC-02's whole-tree write-placement gate.

Acceptance lock (FR-010, NFR-006, C-003)

  • Given a mission whose event log carries runtime (excluding the self-referential cutover mission), when test_dogfood_corpus_backfilled runs, then it requires status_phase>=1 + a non-empty snapshot, and preserves the verify_backfill parity assertion (no green-wash).
  • Durable: the lock stays green after ≥3 subsequent mission merges with no manual backfill (SC-001).
  • Migration coexistence: a regression proves the one-time migrate backfill-runtime-state path still cuts over a legacy corpus after FR-008.

agent mission repair (FR-005, NFR-005)

  • Given a mission with pre-existing content divergence across partitions:
  • strict-ancestor + clean worktree → forward-only (fast-forward), zero data loss;
  • non-ancestor divergencerefuse, emit a unified diff, zero mutation.
  • Bound: distinct command; doctor coordination --fix stays minimized (C-002/C-003).

placement-enforcement.md

Contract — Placement Enforcement (write + read)

Write (FR-001, NFR-001, NFR-004)

  • Given any src/ Python module, when it performs a mission-artifact commit (safe_commit(target=…) / constructs CommitTarget(ref=…) / calls write_meta(...) for a mission-artifact path), then the target MUST be derived from the placement seam (resolve_placement_only / placement_seam.write_target(kind)).
  • Gate: tests/architectural/test_no_write_side_rederivation.py scans all of src/ (no module allowlist); test_safe_commit_import_boundary.py additionally asserts target=CommitTarget(...) is seam-derived. A synthetic non-seam-derived write in any module reds the gate.
  • Exclusions: only individually-justified sanctioned primitives (e.g. lane-deliverable commit, invocation/upgrade commits) — each carries an inline rationale; the exclusion set is NOT a module allowlist.
  • Non-regression: the three existing gates stay green.

Read (FR-004, NFR-002)

  • Given a mission-artifact read for a kind, when it resolves a surface, then it MUST resolve through artifact_home_for(kind).read_surface; a coord-homed kind resolving to a primary substitute raises a typed partition-mismatch error (no silent fallback).
  • Gate: NEW tests/architectural/test_read_surface_placement_guard.py, symmetric to the write gate.
  • Reconciliation: existing #2906 accept-time read guards remain; the new authority generalizes them, it does not double-guard or regress the lenient diagnose path.

Routing coverage (FR-003, FR-006)

  • The emit _current_branch HEAD-derived fallback (#1716) is removed; bookkeeping_projection / bookkeeping_commit / decision_log route through the port; decisions.events.jsonl and traces/ are classified in the partition SSOT (COORD).