Research: Dead-Port Disposition

Mission: dead-port-disposition-01M1TZVN · Date: 2026-09-06 · HEAD verified: branch missions/coreloop-proto-missions after merging origin/main (ba58652f0, includes PR #3888) Inputs: spec.md, research/29-missionB-research-dossier.md (binding), nine decision records in decisions/, live gh checks of PRs #3888/#3898/#3899.

1. Gate-state verification (the three external gates)

GateState at plan timeConsequence
PR #3888 (touches test_layer_rules.py)Merged into main (c0054153b); present in this branch since ba58652f0FR-013 (constitution exclusion at test_layer_rules.py:65-73, verified present) is unblocked; C-002 satisfied by construction.
PR #3898 (RuntimeEventEmitter disposition ADR, docs/adr/3.x/2026-09-06-2-runtime-event-emitter-disposition.md)Open, ADR status: ProposedFR-012 is NOT executable; WP03 ships the shrunk variant (decision OD7). Re-check at tasks-finalize.
PR #3899 (quick-wins, draft)Open; files: CODEOWNERS, CONTRIBUTING, Makefile, testing-parallel.md, pyproject.toml, pytest.ini, six scripts/, one tests/ci/, uv.lockCarries none of the src/mission_runtime residue → OD8 default (ride this mission) holds. Shared-file note: #3899 edits pyproject.toml + uv.lock (truststore); this mission's WP01 edits the same two files (transitions). Whichever lands second rebases; keep one dependency change per PR (C-004).
Mission A (fsm-write-path-integrity-01M1TZV6)In implementation on this branch (WP01/WP02/WP05 claimed)C-001: B's WPs are claimed only after A merges into the branch.

2. Decisions (Decision / Rationale / Alternatives)

ODDecision (id)RationaleAlternatives
OD1FULL (01M1VAHEBB…)guards.py's "shape precedent" is docstring prose in review/gate_registry.py:7,132, citable via git history; keeping ~680 test-only LOC for a citation is the rot shape this mission removes. FULL adds four gate edits (fold-gate :60, _gate_coverage.py:1456, the two schema-validation test halves) plus the :3278 pin (drift D-1).MIN (keeps guards/schema; leaves the pack-DSL validator alive with nothing to validate).
OD2DEFERRED — assume NO/retire (01M1VAHFNE…)Operator-only; operator delegated completion. Spec, dossier, and reports 20/21/24/25/27 all frame retirement; no roadmap item references DSL v1. Override before WP01 claim.YES → WP01 becomes re-justification; pin stays.
OD3Delete pack blocks; keep MISSION_COMPAT_IGNORED_FIELDS (01M1VAHGZM…)Post-FULL the blocks have no interpreter; shipped templates must not imply one; mission.py:59-67,260-261 tolerance stays for consumer overrides that still carry them.Keep-with-comment (leaves inert YAML in every consumer's upgrade payload).
OD4events.py stays; docstring rewritten (01M1VAHJ9R…)Relocation touches next_invocation_lifecycle.py:332, decision.py:200, the seam test, and the runtime ledger row mission_v1 (test_layer_rules.py:194) — runtime files adjacent to Mission A.Relocate under status/ (candidate for Mission D).
OD5(a) canonicalize self-bootstrap; #1868 tracker note (01M1VAHKNX…)(b) is a design change with no driver; report 27 recommends (a). Mission C unminted → tracker note owns the FR-020 follow-through.(b) real registration seam.
OD6DEFERRED — assume ACCEPT documented-but-unwired (01M1VAHN0C…)Operator-only; spec non-goal 3 already excludes wiring. No WP depends on it.Mint the wiring feature issue.
OD7Shrunk variant; follow-up for execution (01M1VAHPAR…)ADR not merged-and-Accepted (verified).Wait for the ADR (blocks the whole P3/P4 slice on an external PR).
OD8Residue rides this mission (01M1VAHQN3…)#3899 edits no gate file and none of the residue; one owner for test_no_dead_symbols.py (WP01), WP03 re-pins sequenced behind it.Extend #3899 (two PRs on the same gate file).
OD9Mission B WP04 owns decision.py after A merges (01M1VAHS32…)A's WP05 is claimed and deliberately small; the mission_v1 ledger edge survives via next_invocation_lifecycle.py:332, so no ledger edit is triggered by the deletion.Add a rider to A-WP05 mid-flight.

3. Dossier/spec drift found during planning

  • D-1 — a fourth dead-symbol pin. tests/architectural/test_no_dead_symbols.py:3278 pins specify_cli.mission_v1.schema::strip_v1_keys. Under FULL, schema.py is deleted, so this pin must go in the same change as the three at :720-727. Folded into contracts/dsl-retirement.md §3. Spec C-005/SC-006 text left as-is (spec committed).
  • D-2 — eager block line numbers. Spec says :20-28; at HEAD the eager imports are :20-29 (compat :20, events :21, guards :22, runner :23, schema :24-29). Cosmetic.
  • D-3 — evaluate_guards consumers. tests/next/test_decision_unit.py:28,189-219 imports and tests derive_mission_state; the dossier says zero callers (true for src/); the test section is WP04's to delete.
  • D-4 — glossary_hook.py line drift. The fiction sentence is at glossary_hook.py:16-17 as stated; the self-bootstrap is at :127-137 (verified :130-135). No impact.

4. Domain rules and invariants (Phase 0 targets — resolved)

UnknownResolution
What must survive in mission_v1events.py (emit_event, read_events) + a thin __init__.py re-exporting exactly those two; package docstring rewritten.
How to prove the hot-path fixSubprocess-isolated test: python -c "import sys, specify_cli.mission_v1.events; assert 'transitions' not in sys.modules and 'six' not in sys.modules"; RED today, permanent after.
Dependency mechanicsDelete pyproject.toml:82; uv lock; verify six remains (via python-dateutil); CHANGELOG entry under [Unreleased] - 3.2.7rc1 (no version bump: the rc cycle is already open; __init__.py version untouched).
Gate ledger (NFR-003)Every deletion edits its gate in the same WP: dead-symbol pins ×4, _gate_coverage.py:1456 (row stays if tests/specify_cli/mission_v1/ keeps the trimmed events test + the new ratchet — it does), fold-gate :60, schema-validation halves, test_pyproject_shape.py, runtime ledger (no change expected).
Glossary contractSelf-bootstrap canonical; degradation only when glossary.attachment is unimportable; pinned by a behaviour test in tests/doctrine/missions/test_glossary_hook.py.
FR-020 honesty.. note:: in glossary_hook.py module docstring + tracker text for #1868 drafted in WP02's design note (operator posts).
Emitter sliceRecord only: research/emitter-adr-inputs.md (name-collision map, 29-site sync_emitter map, flush-target defect at runtime_bridge.py:2149-2150/:2187 vs :1560-1565, spec_kitty_events 9.1.6 VOLATILE_EVENT_TYPES, parity oracle test_bridge_parity.py:1131-1152); docstring correction at event_emitter.py:1-10 pointing at status/adapters.py:364-366.
Residueconstitution exclusion (test_layer_rules.py:65-73); team_projection/ (only __init__.py; bans at test_no_retired_subsystems.py:39-40,99-100 + pyproject.toml TID251 assert absence — stay green; check wheel includes); ActionContext (two files); 13 __all__ demotions (demote, never delete: content_present_at_primary_tip, get_packs_root_default have in-package callers).

5. Integration points

  • runtime/next/next_invocation_lifecycle.py:332 (emit_event) — must keep working unchanged (FR-003); seam test tests/specify_cli/next/test_next_invocation_lifecycle_seam.py:49.
  • runtime/next/decision.py:200 (read_events) — consumer deleted by WP04; until then unchanged.
  • tests/architectural/test_layer_rules.py:194 runtime ledger row mission_v1 — stays (live edge preserved).
  • specify_cli/mission.py MISSION_COMPAT_IGNORED_FIELDS — stays; comment updated.
  • charter/offering/missions/glossary_hook.py ↔ kernel/glossary_runner.py ↔ glossary/attachment.py — the self-bootstrap triangle; no behaviour change.
  • Mission A — none of B's owned files overlap A's; B waits for A's merge (C-001).

6. Supply-chain security check (directive 051)

Dependency decision: removal of transitions only; no additions or upgrades. Registry authenticity, freshness, and lifecycle-script discipline are not exercised by a removal; uv lock regeneration must be reviewed for an unchanged set of other pins (the only expected lock diff: the transitions entry and its six edge; six itself remains). Node LTS: N/A. Adversarial evidence: no security-impacting decision; deferred_with_rationale — the mission's adversarial pass is the operator's post-plan squad; nothing contested here.

7. Risks

#RiskMitigation
R1Deleting files without breaking the eager block (or vice versa)Ratchet test (FR-004) + FULL deletion in one WP.
R2A gate goes red or vacuous after deletionNFR-003 checklist in contracts/dsl-retirement.md §3; run the full tests/architectural/ once in WP01 (pyproject touched).
R3uv.lock conflict with PR #3899Rebase whichever lands second; one dependency per PR.
R4Consumer projects' mission.yaml overrides still carry DSL blocksMISSION_COMPAT_IGNORED_FIELDS retained (OD3).
R5Operator answers OD2 "yes" after WP01 landsOverride window stated in plan.md; WP01 not claimed until Mission A merges, leaving time.
R6team_projection/ deletion breaks wheel buildCheck [tool.hatch.build.targets.wheel].packages and test_pyproject_shape.py in WP03.
R7FR-020 note reads as a promise to wireNote text explicitly says "documented-but-unwired; wiring is a separate feature decision" (OD6).

8. Recommendations for /spec-kitty.tasks

1. Four WPs: WP01 DSL retirement (∥), WP02 glossary repair (∥), WP03 residue + emitter shrunk (after WP01), WP04 decision.py dead readers (∥). Mission-level gate: claim nothing until Mission A merges. 2. WP01 carries the CHANGELOG entry and the clean-install smoke; WP03 carries the FR-011 extraction and the follow-up mint text for the emitter execution. 3. Re-check PR #3898 at tasks-finalize; if merged-and-Accepted, extend WP03 per FR-012 (or mint WP05).