Work Packages: Review-Cycle Verdict Seam Rebuild

Mission: review-cycle-verdict-seam-rebuild-01KZ2W7W Branch: pr/review-verdict-write-integrity-01KZ1CGF (planning base and merge target) Generated: 2026-08-03

Derived from plan.md's Implementation Concern Map. Concerns are not work packages — several split, one merged.

Ownership and the slicing gate

validate_no_overlap hard-fails finalize-tasks when two dependency-unordered work packages claim overlapping owned_files. Sequential pairs are exempt, and any two root WPs are always concurrent. Two files are convergence points and drive most of the edges below:

Convergence fileClaimed bySerialized as
src/specify_cli/review/cycle.pyWP10, WP13, WP14WP10 → WP13 → WP14
src/specify_cli/review/artifacts.pyWP09, WP13, WP14WP09 → WP13 → WP14
src/specify_cli/review/arbiter.pyWP12, WP13, WP14WP12 → WP13 → WP14
.../agent/tasks_verdict_persistence.py (new, WP06)WP06, WP11, WP12WP06 → WP11 → WP12
post_merge/review_artifact_consistency.pyWP07, WP13WP07 → WP13
tests/_arch_shard_map.pyWP01, WP02WP01 → WP02
tests/architectural/test_verdict_seam_census.pyWP01, WP08WP01 → WP08

Rules in force for every WP: file-granularity owned_files only (a directory-shaped entry swallows everything beneath it via a string prefix test), no scope: codebase-wide (it exempts a WP from the overlap check and two others), and create_intent for every planned-new path.

Two further constraints surfaced during finalize-tasks --validate-only and are recorded because they shaped the design:

  • owned_files may not contain any kitty-specs/ path — the gate rejects it outright, with no planning_artifact exemption. The per-concern census fragments therefore live at tests/architectural/census/verdict_seam_ICNN.yaml and fold into tests/architectural/verdict_seam_census.yaml, which WP01's check reads as its expected-set fixture. That is a better shape for FR-020 than a markdown doc in a spec directory: the fixture sits next to the check that consumes it.
  • Requirement ids must match ^(?:FR|NFR|C)-\d+$. The FR-001a / FR-006a shape is rejected by design (#2066), so those were renumbered to FR-022 and FR-023 across spec, plan, data-model and the WP prompts.

Execution shape

L1  WP01 census        WP03 board-hygiene   WP06 seam-extraction        width 3
L2  WP02 date-rot      WP04 kind+plumbing   WP07 authority   WP09 numbering   width 4
L3  WP05 CI-shards   WP08 reconcile   WP10 atomicity   WP11 ordering   WP18 merge-driver   width 5
L4  WP12 arbiter                                                              width 1
L5  WP13 consumer-unification                                              width 1
L6  WP14 reader-polarity                                                   width 1
L7  WP15 durability-matrix   WP16 truthfulness+fold                        width 2
L8  WP17 mission-exit verification                                         width 1

18 work packages, 80 subtasks. WP18 was authored mid-mission by operator adjudication to discharge WP04's T017 ownership deadlock — see its own section below for the provenance. The original slicing was 17 WPs / 76 subtasks; every count in this file that predates WP18 refers to that original shape. Delivered shape, measured rather than drawn: a 7-level DAG at mean width 2.43, and a 9-slot lane wall clock — one lane binds to one worktree, and finalize-tasks collapses the overlap graph by union-find, so an 8-member connected component runs serially even where its members are pairwise disjoint.

The plan's recomputed target was 6 levels at width 2.83. The one level of growth traces to a single removable edge — WP11→WP12 over the new tasks_verdict_persistence.py. Recorded rather than fixed: removing it means splitting that module in two, which re-slices work packages rather than correcting a defect in them.

Subtask Index

Reference table only — completion is event-sourced via spec-kitty agent tasks mark-status, never by editing a row here.

IDDescriptionWPParallel
T001Author the verdict-seam census check enumerating writers, resolvers and readersWP01
T002Enforce: a retire row with no retiring FR is a census failureWP01
T003Reconcile the denominator against test_2093_authority_invariant.py's _EVENT_SLOTSWP01
T004Scope the census by concept, excluding pre_review_gate and verdict_aggregationWP01
T005Emit contracts/census/IC-01.md and register the shard-map rowWP01
T006Fix #3157's dated fixture without touching product codeWP02
T007Derive and record the mixture classifier rule; report the true denominatorWP02
T008Author the absolute-event-timestamp mixture checkWP02
T009Register the shard-map row for the new checkWP02
T010Re-pin the acceptance-verdict frozen flag contract with per-flag rationaleWP03[P]
T011Make the parity check assert resolved activation, not budget-dependent textWP03[P]
T012Introduce MissionArtifactKind.REVIEW_CYCLEWP04
T013Add it to _PLACEMENT_ARTIFACT_KINDS; add the PARTITION_RATIONALE rowWP04
T014Add the filename-anchored classifier leg for review-cycle-*.mdWP04
T015Make the commit router honour the kind for review-cycle pathsWP04
T016Rule on E2 eligibility for REVIEW_CYCLEWP04
T017Resolve the two-sided tasks/ reconciliation-class hazardWP04
T018Document the create-window artifact splitWP04
T019Decouple fast-tests-* from fast-tests-status.resultWP05
T020Decouple integration-tests- from their fast-tests- counterpartWP05
T021Add a topology assertion so a new result-gated edge redsWP05
T022Extract the four verdict sites into tasks_verdict_persistence.pyWP06
T023Preserve the import-cycle invariantWP06
T024Obtain and record the C-003 ruling for the module moveWP06
T025Add the reducer branch surfacing the event verdictWP07
T026Name the slot distinctly from review; state the precedence ruleWP07
T027Make the reader snapshot-first with PRIMARY fallbackWP07
T028Define behaviour for review_result: null under --forceWP07
T029Re-point the merge gate and _lane_gate at the slotWP07
T030Re-point merge/preflight.py and merge/forecast.pyWP07
T031Close the orchestrator_api ingress holeWP07
T032Derive cycle numbers from max(parsed) + 1WP09
T033Refuse on collision, including the unparseable-sibling caseWP09
T034Red-first reproduction of the gap-overwriteWP09
T035Build the reconciliation detector over the census's retired resolversWP08
T036Add the doctor subcommand shim and its sibling moduleWP08
T037Absorb CoordinationBranchDeleted for the 45 stranded missionsWP08
T038Regenerate docs/api/cli-commands.mdWP08
T039Report, never silently ignore, cross-branch coord recordsWP08
T040Red-first reproduction of concurrent verdict lossWP10
T041Serialize allocation and write under feature_status_lockWP10
T042Retry the commit on index contention via the existing probeWP10
T043Make the failure path leave no artifact, including validation failureWP10
T044Red-first reproduction of the crash-orphanWP10
T045Narrow the content-identity guard without disarming the #990 controlWP10
T046Ensure review fixtures run under a real initialized repoWP10
T047Red-first reproduction of the orphan surviving a failed transitionWP11
T048Order the verdict write against the transition emitWP11
T049Emit the --json durability key for --no-auto-commitWP11
T050Thread skip_target_branch_commit to the writerWP11
T051Retire the arbiter frontmatter block into ReviewOverrideWP12
T052Retire the JSON sidecars into ReviewOverrideWP12
T053Fix the bare-wp_id resolver and the lexicographic sortWP12
T054Surface arbiter-persist failure, including under --jsonWP12
T055Suppress the fabricated approval on the override pathWP12
T056Re-pin test_tasks_cli_contract_coord.py's arbiter pathWP12
T057Unify slug derivationWP13
T058Route all twelve read/write sites through one owner functionWP13
T059Narrow the merge-gate fan-out, after WP08 has reconciledWP13
T060Discharge C-001's premise against the unified resolverWP13
T061Correct the "PRIMARY-partition for every topology" docstringWP13
T062Re-pin the #2834 coord-husk test with the both-present caseWP13
T063Declare a polarity for every reader in the censusWP14
T064Fix the fail-open kanban readerWP14
T065Fix the uncaught arbiter crashWP14
T066Record why the merge gate is already fail-closedWP14
T067Exercise the durability matrix through the real command surfaceWP15
T068Prove each cell reds when the commit call is deletedWP15
T069Cover the real-router, real-git pathWP15
T070Audit test names against assertions over the bounded denominatorWP16
T071Fold the census fragments into the contract the check readsWP16
T072Correct workflow.py's inventory docstring and the doc surfacesWP16
T073Add the CHANGELOG entry for the behaviour changesWP16
T074Diff the affected-suites node-id set against the committed baselineWP17
T075Restate NFR-005's countable clause against one named port methodWP10
T076Draft the closing-clause block and the epic-#3044 carve-outWP16
T077Implement the review-cycle merge driver (never blend two verdicts)WP18
T078Register the driver across gitattributes, command table, init and lane-mergeWP18
T079Upgrade migration registering the driver for existing clonesWP18
T080Prove the create-window clobber is closed, red-firstWP18

WP01 — Verdict-seam census and its architectural check

Goal: Produce the authoritative enumeration of verdict writers, location resolvers and frontmatter readers, so every downstream reduction target is derived rather than asserted. Priority: P1 — three successive spec revisions pinned counts that were all wrong. Independent test: Introduce a new writer, resolver or reader anywhere in src/; the check must red. Subtasks: T001 T002 T003 T004 T005 · Dependencies: none · Estimated prompt: ~380 lines

WP02 — Time-dependent test rot

Goal: Fix #3157's fixture and ban the mixture of hard-coded and now()-generated event timestamps in one log. Priority: P1 — a prerequisite for measuring this mission, via WP05. Independent test: The lifecycle test passes with zero product-code change; the new check flags a mixed fixture and does not flag an all-hard-coded one. Subtasks: T006 T007 T008 T009 · Dependencies: WP01 (tests/_arch_shard_map.py) · Estimated prompt: ~320 lines

WP03 — Board hygiene

Goal: Clear two pre-existing mainline reds unrelated to the seam. Priority: P3 — the only genuinely droppable package. Independent test: Both named checks pass on the mainline. Subtasks: T010 T011 · Dependencies: none · Estimated prompt: ~220 lines

WP04 — The REVIEW_CYCLE kind and its plumbing

Goal: Give review cycles their own artifact kind on the COORD partition, and make the write side follow it. Priority: P1 — ADR 2026-08-03-1. Without the classifier leg every rejection write fails. Independent test: A kind=REVIEW_CYCLE write under a coord topology lands on the coord surface and commits there; the same write under SINGLE_BRANCH lands PRIMARY. Subtasks: T012 T013 T014 T015 T016 T017 T018 · Dependencies: WP01 · Estimated prompt: ~520 lines

WP05 — CI shard independence

Goal: Stop one failing shard starving the diff-coverage gate. Priority: P1 — fast-tests-review is the only shard covering this mission's own write surface. Independent test: A mainline push with one shard failing still produces coverage for every shard currently gated on another's result. Subtasks: T019 T020 T021 · Dependencies: WP02 · Estimated prompt: ~250 lines

WP06 — Extract the verdict seam out of tasks_move_task.py

Goal: Move the four verdict-relevant sites out of a 2554-line module so four later packages stop queueing on one file. Priority: P1 — a structural prerequisite, not a cleanup. Independent test: Behaviour unchanged; the import-cycle invariant holds; the new module is singly owned. Subtasks: T022 T023 T024 · Dependencies: none · Estimated prompt: ~300 lines

WP07 — Verdict authority and its reader

Goal: Make the reduced snapshot authoritative for which verdict is current, and give it a reader. Priority: P1 — the mission's core invariant. Independent test: A consumer asked "is this WP approved?" reaches the event, and an un-migrated mission still gets an answer rather than "no verdict". Subtasks: T025 T026 T027 T028 T029 T030 T031 · Dependencies: WP01 · Estimated prompt: ~540 lines

WP08 — Reconcile records stranded under divergent paths

Goal: Find and reconcile verdict records the fan-out currently tolerates and WP13 will stop resolving. Priority: P1 — must land before WP13's narrowing, or the merge gate opens a fail-open window. Independent test: Seed a record at each retired resolver's output; the command detects and reports every one. Subtasks: T035 T036 T037 T038 T039 · Dependencies: WP01, WP04 · Estimated prompt: ~420 lines

WP09 — Verdict numbering

Goal: A new record never overwrites an existing one. Priority: P1 — reproduced data loss. Independent test: With cycles 1 and 3 present, recording a new verdict does not touch cycle 3. Subtasks: T032 T033 T034 · Dependencies: WP01 · Estimated prompt: ~260 lines

WP10 — Atomicity, crash-safety, concurrency, and the guard narrowing

Goal: One critical section over allocation and write; no orphan on any failure path; repeat feedback recordable without disarming the #990 control. Priority: P1 — three reproduced failure modes. Independent test: Kill the process between write and commit; the identical retry succeeds and records the correct verdict with no manual cleanup. Subtasks: T040 T041 T042 T043 T044 T045 T046 T075 · Dependencies: WP06, WP07 · Estimated prompt: ~560 lines

WP11 — Transition ordering and the durability signal

Goal: No readable verdict survives a failed transition; the one sanctioned non-durable path announces itself. Priority: P1. Independent test: Force the transition emit to fail; no approved verdict is readable by any consumer. Subtasks: T047 T048 T049 T050 · Dependencies: WP06, WP07 · Estimated prompt: ~330 lines

WP12 — Arbiter override retirement

Goal: Retire the arbiter's two non-authoritative override representations into the event-sourced ReviewOverride. Priority: P1. Independent test: An override survives a fresh clone, clears the merge gate, and produces no approval record. Subtasks: T051 T052 T053 T054 T055 T056 · Dependencies: WP06, WP07, WP11 (both claim tasks_verdict_persistence.py) · Estimated prompt: ~470 lines

WP13 — Consumer unification

Goal: Every read, write, gate and display path resolves one identical location, through one owner function. Priority: P1 — owns C-001's discharge. Independent test: For each accepted filename separator, every path resolves the same directory. Subtasks: T057 T058 T059 T060 T061 T062 · Dependencies: WP04, WP07, WP08, WP09, WP10, WP12 · Estimated prompt: ~500 lines

WP14 — Declared reader polarity

Goal: Every reader in the census resolves a damaged record to a declared polarity; none crashes uncaught; no safety gate fails open. Priority: P2. Independent test: Seed a non-UTF-8 record; every census reader behaves as declared. Subtasks: T063 T064 T065 T066 · Dependencies: WP01, WP13 · Estimated prompt: ~340 lines

WP15 — Durability coverage matrix

Goal: Exercise the durable path through the real command surface across verdict × lane × topology × auto-commit. Priority: P1 — the commit branch has never run end-to-end through the real router. Independent test: Deleting the commit call turns each matrix cell red. Subtasks: T067 T068 T069 · Dependencies: WP05, WP10, WP11, WP12 · Estimated prompt: ~300 lines

WP16 — Truthfulness sweep, census fold, changelog

Goal: Make names, documents and the changelog describe what the code does; fold the census fragments into the contract the check reads. Priority: P2. Independent test: No test name or contract key contradicts its assertions within the bounded denominator; the census check reads the folded contract. Subtasks: T070 T071 T072 T073 T076 · Dependencies: WP04, WP07, WP08, WP10, WP12, WP13 · Estimated prompt: ~360 lines

WP18 — Review-cycle merge driver for the two-sided tasks/ hazard

Goal: Land the reconcile driver ADR 2026-08-03-1 names as a required deliverable, so a coord mission's review-cycle write cannot be clobbered by -X theirs during the migration window. Priority: P1 — it closes the #2804 clobber shape in a directory the reconciliation guard pre-classifies as safe. Independent test: Reproduce the create-window clobber (cycles on PRIMARY, cycle-1 write to COORD, -X theirs squash) and assert the target-side verdict survives with the driver registered — red without it. Subtasks: T077 T078 T079 T080 · Dependencies: WP04 · Estimated prompt: ~430 lines

Provenance — authored mid-mission, not part of the original slicing. WP04's T017 required either a merge-driver diff or a re-justification backed by a test demonstrating the clobber cannot occur. WP04 established that the re-justification is dishonest (the create-window split makes the clobber genuinely reachable, so no honest test can show otherwise) and that the driver needs .gitattributes, the command table, init.py, lanes/merge.py and an upgrade migration — all outside its owned_files. Neither permitted discharge was achievable within its slicing boundary. The operator adjudicated: land the driver in a new WP owning that registration surface. WP04's T017 is discharged by deferral to this WP.

All six of WP18's owned_files were verified unowned by every other WP before it was authored, so validate_no_overlap is not breached.

WP17 — Mission-exit verification

Goal: Discharge NFR-001 and SC-009 by diffing the measured baseline, and prove no prohibited method was used. Priority: P1 — the surface most tempting to discharge by re-run. Independent test: The failing node-id set is a subset of the committed baseline, and the affected-suites node-id set has not shrunk. Subtasks: T074 · Dependencies: WP02, WP03, WP05, WP13, WP14, WP15, WP16 · Estimated prompt: ~200 lines


MVP scope

WP01 + WP02 + WP05. The census makes every later target derivable, and WP02→WP05 restores coverage measurement for src/specify_cli/review — without which this mission cannot score itself. Nothing else can be honestly evaluated first.

Parallelization

Widest at L3 (four packages). The real critical path, computed from the dependency blocks rather than drawn, is WP01 → WP07 → WP11 → WP12 → WP13 → WP14 → WP17 — note it runs through the WP11→WP12 edge, and that WP10 is not on it.

Post-tasks findings, recorded

A two-lens post-tasks squad found and this pass fixed: four WPs with no Definition of Done at all (WP09–WP12, the four owning every reproduced defect); a census denominator empty by construction, because the prose read a path the ownership gate forbids WP01 to write; WP14 over-claiming two files no subtask touches, which was welding it to the spine; WP11 recommending an emit-first ordering that inverts US1 AC3 under FR-001's authority; a pinned CI edge count that was both wrong and did not sum; and nine requirements claimed by nobody — including C-007, whose entire purpose is preventing a dishonest epic claim.

Two items deliberately left open:

  • maxlane 8 is a 4× regression against this repo's precedent (19 of the last 22 missions ran at maxlane 1). The fix is to split WP06's module in two and extract the location resolver into its own, landing maxlane ≈ 3. That is a re-slice rather than a defect fix, so it is an operator decision.
  • analysis-report.md does not exist yet. /spec-kitty.implement refuses without it, and its freshness hash covers spec.md, plan.md and tasks.md — so it must be generated after this finalize run.