Tasks: Mission-Type DRG Node + Cross-Grain Integrity Gate (S0 + seam completion)

Mission: resolver-seam-completion-01KXK0KG · Branch: feat/2651-resolver-seam-completion Plan: plan.md (12-IC map) · Design: ADR 2026-07-15-1 + 2026-07-14-2

WP → IC mapping & lanes

The 7-IC-grouping from the post-plan squad is realized as 5 WPs, refined so owned_files never overlap: IC-07's union logic is extracted into a new src/charter/action_grain.py module (WP02), so mission_type_profiles.py is owned by WP03 alone (IC-06+IC-10+IC-12), and the gate (WP04) + reconciled tests (WP05) reuse that one module — killing the second source. IC-03 (mission-type cascade) is deferred to S0-continuation (cosmetic without edges).

WPICsLaneDepends onOwns (no overlap)
WP01IC-01, IC-02DRGsrc/doctrine/drg/{models.py, migration/extractor.py}, graph.yaml + DRG tests
WP02IC-07 (+IC-11 spike)Resolver-helpernew src/charter/action_grain.py + its test
WP03IC-06, IC-10, IC-12Resolver-coreWP02src/charter/mission_type_profiles.py + its unit tests
WP04IC-04, IC-05, IC-11GateWP02new tests/doctrine/drg/test_cross_grain_integrity.py
WP05IC-08, IC-09TestWP03the 3 existing test-union / NFR files

Parallelism: WP01 ∥ WP02 (disjoint files). Critical path WP02 → WP03 → WP05; WP04 is a parallel tail after WP02. MVP: WP01 + WP02 + WP03 (the DRG node + the lazy union land the core); WP04/WP05 harden.

Subtask Index

IDDescriptionWPParallel
T001Register MISSION_TYPE NodeKind enum member + node-kind testWP01
T002Extractor _discover_mission_type_nodes from mission_types/*.yaml + wire into generate_graphWP01
T003Regenerate graph.yaml; keep regenerate-graph --check + freshness/totality/superset tests greenWP01
T004action_index_to_mapping pure adapter (ActionIndexMapping[str,list[str]]) + testWP02[P]
T005aggregate_action_grain(built_in_dir, type) — enumerate actions/*, load_action_index each, unionWP02[P]
T006IC-11 dup-scan spike: assert zero shipped cross-grain collisions (feeds WP04)WP02[P]
T007Make governance a lazy compare=False thunk (mirror _expected_artifacts_thunk)WP03
T008Rework _resolve_governance_slot(provenance,text,thunk); fix :469 provenance forceWP03
T009Wire aggregate_action_grain into the thunk; retire _EMPTY_GRAIN; guard fires on .governanceWP03
T010Campsite (IC-10): repoint _load_mission_type_profile test, drop ImportError fallback, TypedDict typing ×3, docstrings, parity-scaffold guardWP03
T011IC-12 regression pins: gating byte-identical; thunk severs collision→action_sequence couplingWP03
T012Doctrine-integrity gate: all (type,action) via action_grain union, disjoint + non-emptyWP04
T013Non-vacuity twin: temp-tree deliberate-collision fixture through load_action_index MUST failWP04
T014Reconcile _resolve_union + _resolve_union_from_mission to read bundle.governance onlyWP05
T015NFR spy: replace from_config p99 gate; spy load_action_index NOT called on hot pathWP05

WP01 — mission_type DRG node + generator

Goal: make mission_type a first-class DRG node (ADR S0). Independent test: graph.yaml has 4 mission_type nodes; regenerate-graph --check green. Prompt: tasks/WP01-mission-type-drg-node.md

  • ✅ T001 Register MISSION_TYPE NodeKind enum member + node-kind test (WP01)
  • ✅ T002 Extractor _discover_mission_type_nodes + wire into generate_graph (WP01)
  • ✅ T003 Regenerate graph.yaml; keep freshness/totality/superset green (WP01)

Dependencies: none. Parallel with: WP02.

WP02 — action-grain aggregation module (foundational)

Goal: the single canonical type-scoped action-grain union, in a new module. Independent test: aggregate_action_grain returns the unioned per-kind mapping for each built-in type; adapter round-trips. Prompt: tasks/WP02-action-grain-module.md

  • ✅ T004 action_index_to_mapping pure adapter + test (WP02)
  • ✅ T005 aggregate_action_grain builtin-root enumeration + union (WP02)
  • ✅ T006 IC-11 dup-scan spike: assert zero shipped collisions (WP02)

Dependencies: none. Parallel with: WP01.

WP03 — resolver lazy union + campsite + pins

Goal: wire the lazy action-grain union into the resolver, retire _EMPTY_GRAIN, campsite, keep gating byte-identical. Independent test: hot .action_sequence triggers no load_action_index; .governance fast-fails on collision; charter suite green. Prompt: tasks/WP03-resolver-lazy-union.md

  • ✅ T007 Lazy compare=False governance thunk (WP03)
  • ✅ T008 _resolve_governance_slot(provenance,text,thunk); fix :469 (WP03)
  • ✅ T009 Wire aggregate_action_grain into thunk; retire _EMPTY_GRAIN (WP03)
  • ✅ T010 Campsite: repoint test, drop fallback, TypedDict typing, docstrings, parity guard (WP03)
  • ✅ T011 IC-12 regression pins (WP03)

Dependencies: WP02.

WP04 — cross-grain integrity gate + non-vacuity twin

Goal: the load-bearing FR-013 enforcer as a doctrine-integrity gate reusing WP02's union. Independent test: gate passes on shipped tree, fails on the deliberate-collision fixture. Prompt: tasks/WP04-integrity-gate.md

  • ✅ T012 Doctrine-integrity gate over all (type,action) (WP04)
  • ✅ T013 Non-vacuity twin fixture (WP04)

Dependencies: WP02.

WP05 — test-union reconciliation + NFR spy

Goal: remove the second-source unions; correct the NFR-001 threshold. Independent test: the two former union sites read bundle.governance; a spy proves the hot path calls no load_action_index. Prompt: tasks/WP05-test-reconciliation.md

  • □ T014 Reconcile the two _resolve_union* sites to bundle.governance (WP05)
  • □ T015 NFR spy on the real hot path; drop from_config p99 citation (WP05)

Dependencies: WP03.