3.2.x — Doctrine-runtime depth · core-domain strangling · DevEx

Milestone: 3.2.x (open) · Status: active · Declared: 2026-06-16 · Advances: epics #1619 (runtime/state SSOT), #1868 (canonical seams), #1878 (coordination strangler).

Theme

A stabilization-and-depth cycle: make the governance layer actually shape runtime, strangle our core domains onto single sources of truth, and lower the cost of doing both. Shipped as emergent patches (3.2.1, 3.2.2, …) that each advance one of the three goals below; the cycle stays open until they hold. No new shadow paths — every change routes a duplicate onto an existing authority or extracts a pure seam from an inline blob, never builds a parallel one.

Goals

G1 — Deepen Doctrine / Charter / DRG impact on runtime execution

Wire the charter + doctrine layer and the Doctrine Resolution Graph (DRG) into the runtime execution loop, so directives, tactics, agent profiles, and mission-step contracts demonstrably shape what next/the commands do — not just sit as resolvable config. Close the gap between "doctrine exists" and "doctrine governs execution."

G2 — Strangle out our core domains

Continue the #1619 runtime/state decomposition: take each core domain (identity/naming, path/read-path, coordination/topology, status, lanes, ownership) onto its canonical SSOT, route every consumer to consume it, and ratchet the duplication class shut. Extract → route → enforce, domain by domain, behind characterization tests.

First active slice — naming / identity routing rider (the 3-squad investigation, 2026-06-16, as narrowed by the neutral scoring panel). The static branch_naming/mid8() seam is a sound SSOT (built by the 3.2.0 work; ADR 2026-03-09-1 "Prompts do not discover context. Commands do"; FR-009/FR-012) — that survived every adversarial pass. The wider ExecutionContext compute-once-thread-through design is real but not yet load-bearing (built-and-parked, mutable, internally split-brained — see the evidence trail); threading it is a later builder-hardening effort (3.2.x parallel track), not this rider. So the rider is the cheap, low-risk subset: route the ~20 bare mission_id[:8] sites through mid8() (bulk/standalone/dashboard — wrong cardinality to thread), adopt the fragment only at the 2–3 sites that already hold a context, and extend the literal-ban ratchet to bare …_id[:8] repo-wide as a tripwire. The static composes (#2000/#1899-tail/#1900), the resolve_lanes_dir seam (#1993, returns both surfaces), the locate_project_root collapse (#1971-tail), and the ownership existence-check (#1888, verify-and-close) are the write/static end of the same superset. Guardrails: keep ExecutionContext action-scoped (no god-object); keep the three C-LANES-1 surfaces as three fragments; tests pin which fragment is consumed, not just the value (byte-identity masks wrong-fragment conflation under flattened topology). Full research: docs/plans/engineering-notes/naming-identity-ssot-strangler/.

Other core domains (status, coordination write-side, lanes) follow as later 3.2.x slices or roll to 3.3.x as they emerge.

G3 — DevEx & enablers

Lower the cost of the above and of contributing generally: pure-seam extractions for testability (e.g. #1993 removes ~12 mocks), the regression-proof ratchets/guards that make a strangled class stay strangled, and the maintainer governance surface (this docs/release-goals/ convention + HOW_TO_MAINTAIN.md — tracker structure, priorities, types, milestones).

Evidence trail — dialectic + neutral scoring (read this before trusting any metric)

Honesty note (supersedes the earlier "evidence-grounded" framing). The first corroboration squad was briefed to corroborate the operator's goals, which primed it toward agreement. A red-team squad then refuted the framing, the metrics-as-proof, and the sequencing (it did not refute that the engineering is real). A subsequent neutral scoring panel (severity · ROI · architecture) scored the candidate 3.2.1 leads with no predetermined answer. The honest, surviving statements:

  • The goals are legitimate operator intent, not a "proven data-driven continuation." The underlying epics (#1619/#1666/#1868/#1878) are real and pre-exist v3.1.10; the taxonomy mapping them to G1/G2/G3 was authored after the fact. Treat the goals as direction, not as something the metrics "prove."
  • The static branch_naming/mid8() seam is a genuine, sound SSOT — this survived every adversarial pass. The cheap routing of the bare mission_id[:8] sites through it is a real, low-risk win.
  • Stop citing the confounded metrics as proof. "−76% status bypass", "authorities cooled", "+550% mission_id[:8]" measure syntax / per-block complexity, not coupling quality; system-level src/ SLOC grew +115% in range and no legacy path was retired (extract-then-coexist). The ratchet is a useful regression tripwire, not a completeness oracle (it passes today with ~20 live [:8] sites and is defeated by mid[:8]/[0:8]/helper shape-shifts).
  • "Thread the ExecutionContext everywhere" is NOT the spine — the composite is built-and-parked, mutable, and internally split-brained (branch_name ≠ branch_ref.target_branch, resolution.py:793-801). Fixing that is a separate, later builder-hardening effort, not this slice.

Neutral 3.2.1 scoring verdict: all three scorers leaned impact-first — open the write-side/single-resolution authority surface (#1832 → #1716), demote naming to a parallel rider. The operator chose safety-first (the naming rider as the opener) as a deliberate low-risk-momentum trade-off — explicitly a values choice, not a data verdict. This declaration follows that choice: naming-rider-first below, with the impact work sequenced as fast-following 3.2.x patches. Full evidence and the decision record: docs/plans/engineering-notes/3-2-x-goal-corroboration/ (SCORING-SYNTHESIS.md · DIALECTIC-SYNTHESIS.md).

Operator bug evidence intake (#2007, 2026-06-16): the "3.2.0 training bugs that Robert witnessed" validate the same coord/read-path and mission-identity surface in this PR (STATUS_READ_PATH_NOT_FOUND, MISSION_NOT_FOUND, finalizer missing spec.md/meta.json in coord worktrees, and implement/finalize re-reading a different surface than the one the prior step created). They also add important non-overlap evidence: command-contract drift (doctrine list, setup-plan, agent action implement --json), stale-charter preflight/status loops, submodule/gitfile root resolution, decision command mission-path semantics, and raw Python template import failures. Treat #2007 as an expansion of the 3.2.x evidence base: fold overlapping single-resolution bugs into the #1832/#1716/#1878 fast-follow, and track the non-overlap items as separate DevEx/runtime repair work. The naming rider alone is not a complete explanation or fix for the witnessed 3.2.0 training failures.

Non-goals (→ 3.3.x or later)

  • UX / dashboard look-and-feel, user flows, SaaS tie-in — the 3.3.x focus.
  • The #1878 coord/primary WRITE/entry-side strangler (commit / protected-branch durability) — semantics-sensitive, characterization-first; tracked to 3.3.x. (Open call: a bounded, guarded #1878 read-side slice may enter G2's first mission — see the research 00-OVERVIEW §5.)
  • Extracting other emergent domains beyond the core set — surfaced and split in 3.3.x.

Success criteria (cycle closes when these hold)

  • G1: doctrine/DRG demonstrably gates a runtime decision path (with a test proving the directive/contract changes behaviour), not just resolves.
  • G2: the naming/identity/read-path class produces zero new regressions for a full cycle; consumers route through the SSOT (no inline mission_id[:8]/kitty/mission-{…}/.worktrees/…/ parents[N] outside the seams); the ratchet covers the full recurrence shape repo-wide incl. dashboard/scanner.py, and its allow-list shrinks; ≥1 additional core domain extracted.
  • G3: the DevEx enablers landed (seam extractions + ratchets + governance docs) are in use; no new shadow path introduced cycle-wide.

Emergent patches

  • 3.2.1 — naming routing rider (the deliberate low-risk opener; chosen over the impact lead the neutral panel preferred). Route the ~20 bare mission_id[:8] sites through resolve_mid8/mid8(), extend the literal-ban ratchet as a tripwire (scoped honestly — partial, syntax-level), land the resolve_lanes_dir (#1993) / locate_project_root (#1971) seams, and verify-and-close #1888. Sequencing constraint (binding): #1993 must not ship as a bare extraction — extracting resolve_lanes_dir alone half-strangles the read path into a new shadow path (the _lanes_feature_dir twin). Either carry a minimal read-side adoption of the new seam in the same WP, or defer #1993 to the write-side patch with #1832.
  • 3.2.2 — write-side / single-resolution surface (the impact work the panel ranked first, sequenced to fast-follow). Open with #1832 (agent action implement "no workspace resolved" — the safe, verified P1 that proves "consume the resolved context, don't re-derive"), drive to #1716 (P0 coord-topology authority root, keystone of #1619/#1878). Re-test #1827 first (it may be stale — the neutral panel could not reproduce the circular failure); fast-follow if real, close-with-evidence if not.
  • 3.2.x (parallel / emergent) — the #1619 builder-hardening slice (un-mutate the ExecutionContext builder, close the internal branch_name ≠ branch_ref.target_branch invariant); the #1891 residual (agent action implement --json, independent DevEx); G1 doctrine/DRG-into- runtime depth; the next core-domain strangle. Shapes pinned as each is scoped.
  • Tracker hygiene (do regardless of lead): milestone the currently-unmilestoned P0/P1 work (#1716, #1827, #1832, #1891, #1619/#1666) onto 3.2.x/3.3.x — the milestone currently holds only the (now-closed) naming issues, so the burndown understates the real cycle.
  • Cycle stays open until all three goals' success criteria hold.