03 — Architecture Context: 3.x Intent, Deep-Dive Review, CAACS Audits
What the existing architecture already commits to, and what the audits already flag as debt that an
execution-context redesign would touch. Sources: docs/adr/3.x/*,
docs/plans/engineering-notes/architectural-review/2026-05-25-deep-dive-architectural-review.md,
docs/architecture/audits/2026-05-spec-kitty-caacs.md, docs/architecture/audits/2026-05-caacs-meta-assessment.md.
Note:
docs/3.xis currently empty — the 3.x ADR set is the architectural intent (there is no consolidated 3.x behavioral spec yet;docs/architecture/README-3.x.md:8-10). The redesign must reconcile the ADRs directly rather than cite one canonical runtime doc.
A. What the architecture already commits to (binding precedents)
A1 — Lanes own git; WPs own accounting
ADR 2026-04-03-1-execution-lanes-own-worktrees-and-mission-branches:
ExecutionLaneis the branch + worktree unit;WorkPackageis the planning / review / accounting unit (:61-66). One integration branch per mission; only it merges tomain.lanes.jsonis mandatory, fail-closed runtime input —implement/review/accept/mergeMUST fail closed when it is absent/malformed; no fallback to per-WP worktrees or detection (:86-89). Shipped commands must never create/merge.worktrees/<feature>-WP##(:155-156).- Branch naming:
kitty/mission-<slug>(integration),kitty/mission-<slug>-lane-<id>(lane). - Progress accounting is two-dimensional: WP state AND lane state must both be visible (
:132-134).
Consequence: the execution context is lane-scoped for git and WP-scoped for accounting. Both axes must be first-class. It must consume
lanes.json(includingdependencies).
A2 — Lane behavior is a polymorphic State Pattern over an event log
ADR 2026-04-06-1-wp-state-pattern-for-lane-behavior:
- Replaced lane logic scattered across 46 files / 358 string literals / 3 duplicated
LANEStuples with an ABC + frozen-dataclass State Pattern; each of the 9 lanes owns itsallowed_targets(), guards,progress_bucket(),display_category();TransitionContextreplaces an 8-arg kwargs bag (:42-54). - Promotes
in_reviewto a first-class 9th lane (:51,138).in_reviewoutbound transitions require aReviewResultinTransitionContext(:139).doingremains an alias resolved at the boundary (:63).
Consequence: route lane transitions through
wp_state_for()/TransitionContext+ the event log — do not re-scatter string literals. The status domain is already bounded; consume it.
A3 — Lifecycle starts are service-owned and atomic
ADR 2026-05-01-1-atomic-work-package-start-lifecycle:
- Start is semantic = two events (
planned→claimed,claimed→in_progress). Pre-ADR each surface emitted independently → crash strands atclaimed; retry semantics varied by surface (:28-44). - Spec Kitty supports 15 coding-agent hosts + orchestration/API — lifecycle correctness cannot
live in a host-specific wrapper (
:39-43). - Decision: a shared lifecycle service —
start_implementation_status()/start_review_status()— writes multi-edge atomic batches, materializes once, same-actor resume / different-actor conflict (:69-97). Atomic persistence = append full batch to temp JSONL then replace the canonical log (:99-101). - Layering rule: semantic lifecycle starts are service-owned; raw transition validation is state-machine-owned (
:116-118).
Consequence: this is the strongest existing precedent for a unified context/service seam. A
MissionExecutionContextshould extend, not bypass this service.
A4 — Identity is a ULID (mission_id), not a number
ADR 2026-04-09-1-mission-identity-uses-ulid-not-sequential-prefix (+ 2026-05-10-1 deterministic
historical repair):
mission_id(creation-time ULID) is the canonical machine identity for every selector, state file, merge primitive, WP reference, status artifact, sync payload (:74-78).mission_numberis display-only;feature_slugis a software-dev compat alias. Historical backfill is content-addressed and offline-deterministic.
Consequence: the context object keys identity on
mission_idfor lookup/locking/event routing — nevermission_number/feature_slug.
A5 — done ≠ approved; acceptance runs on the integration branch
ADRs 2026-04-03-2 (review/approval distinct) + 2026-04-03-3 (feature acceptance on the
integrated mission branch):
for_review= ready to inspect;approved= review granted;done= integrated + acceptance evidence recorded. Evidence is split per transition (:84-95).- WP review may happen on a lane branch, but feature QA and
acceptMUST happen on the mission integration branch (:53-58), with negative-invariant verifiers (proven absence).
Consequence: the context must carry differentiated evidence per transition and know that
done/acceptance is a mission-branch fact, not an aggregate of lane approvals.
A6 — The Mission Type / Mission / Mission Run ontology (critical noun boundary)
ADR 2026-04-04-2-mission-type-mission-and-mission-run-terminology-boundary:
- Mission Type = reusable blueprint (lifecycle actions, guards, templates, action indices, doctrine bindings).
- Mission = concrete tracked item under
kitty-specs/<mission-slug>/, canonical idmission_slug/mission_id. - Mission Run = one persisted runtime/session instance under
.kittify/runtime/, identified bymission_run_id; must never alias a tracked mission slug (:113-124).
Consequence (most important for #1619): a
MissionExecutionContextis, in the canonical ontology, a Mission Run concept — runtime/session state keyed bymission_run_id, distinct from the tracked Mission (mission_id) and the Mission Type blueprint. Conflating these is the exact failure this ADR exists to prevent. Name and layer the new object accordingly.
A7 — Runtime is CLI-internal; events/tracker are public-import-only
ADR 2026-04-25-1-shared-package-boundary: runtime surface lives under
src/specify_cli/next/_internal_runtime/; spec-kitty-runtime is retired; events/tracker consumed
only via spec_kitty_events.* / spec_kitty_tracker.*; enforced by architectural import tests + clean-install CI.
Consequence: keep the redesign's runtime home CLI-internal and the events/tracker access on the public-import boundary.
A8 — Layered doctrine config is field-merge + visible collisions
ADR 2026-05-16-1-doctrine-layer-merge-semantics: layered config resolution is field-level merge
with explicit DoctrineLayerCollisionWarning. Peripheral, but relevant if the context assembles layered mission/doctrine config.
B. The current bounded-context map (from the 2026-05-25 deep-dive review)
| Bounded Context | Canonical package | Boundary status |
|---|---|---|
| Charter (governance source) | src/charter/ |
clean — zero inverse imports |
| Doctrine (rulebook + DRG + profiles) | src/doctrine/ |
clean — zero inverse imports |
| Constitution | src/constitution/ |
self-contained (not investigated) |
| Dashboard | src/dashboard/ + src/specify_cli/dashboard/ |
bifurcated |
| Mission lifecycle (specify→…→merge) | cli/commands/*.py + specify_cli/runtime/ + src/runtime/ |
scattered |
| Status / kanban (lane state machine) | src/specify_cli/status/ |
clean per 060-cleanup; bounded |
| Glossary / terminology | specify_cli/glossary/ + src/doctrine/ |
acceptable, re-check |
Protected strength: dependency direction is correct — charter and doctrine do not import
specify_cli (:35-36). Keep it.
Named smell directly relevant to us (:37-38): the four charter packages under specify_cli/
are a runtime split (lifecycle vs read-only vs check), not a domain split → leaky boundary. This
is the canonical example of the anti-pattern the overhaul must avoid.
Review's decomposition stance: a moratorium on new top-level specify_cli/*/ packages;
scattered mission-lifecycle concerns should land under a mission_runtime/-style umbrella (:108-112).
Execution/state bugs the review flags as architectural:
- F-02 —
agent action implementworktree creation does not consumelanes.json::dependencies→ lane workspaces don't inherit upstream commits (:127). - F-03 — squash-merge path does not emit post-merge
doneevents on the target branch (:128). - F-06 — no
lane-cross-cuttingclass for integrative/QA work spanning lanes (:131).
C. CAACS audit findings (complexity / coupling hotspots)
2026-05-spec-kitty-caacs.md + meta-assessment:
- Bus factor ≈ 1 (≈89.5% src single-author) — highest knowledge-concentration risk in the repo (
:141-146). - F2 = the execution/state hotspot cluster (all DDD=core):
File SLOC Worst fn (CC) cli/commands/agent/tasks.py3746 finalize_tasksCC=160,move_taskCC=139cli/commands/agent/workflow.py1895 reviewCC=84cli/commands/implement.py718 CC=44 (workspace resolution) cli/commands/merge.py1599 _run_lane_based_merge_lockedCC=63next/runtime_bridge.py2552 "a hub, not a bridge"; F-46 fn; MI=C status/emit.py656 batchCC=40core/worktree.py681 git worktree mgmt orchestrator_api/commands.py1097 external orchestration API - Densest temporal coupling is exactly the mission-state ↔ git-worktree transaction:
agent/{tasks,workflow}.py↔implement.py↔merge.py↔core/worktree.py— 22 of the top-30 coupled pairs involve one of these six files (:289-330). ~70% of changes there ship without matching test updates (:429-445). finalize_tasks(CC=160) actually lives inmission.pydespitetasks.pynaming — a name/location coupling smell (:683-685).- Cross-cutting observation: "the
agent/directory is doing too much … everything-the-mission-touches-funnels-here" (:732-737). - Team has already filed epic [#992 "centralize domain invariants"] as the F2 remediation vehicle (meta-assessment
:25-28), plus #984 (wrong-checkout reads from detached worktrees). DM-D resolution: document/transfer knowledge first, then refactor (:181).
D. Net architectural reading for #1619
A MissionExecutionContext is — in the project's own ontology — a Mission Run object that must:
- key identity on
mission_id(ULID), distinct frommission_run_id(A4, A6); - be lane-scoped for git and WP-scoped for accounting, consuming fail-closed
lanes.jsonincluding dependencies (A1, F-02); - delegate lifecycle starts to the existing atomic service (A3) and lane transitions to the State-Pattern + event log (A2) — consume the bounded status domain, don't re-implement it;
- respect
approved≠doneand integration-branch acceptance (A5, F-03); - live under a
mission_runtime/-style home that decomposes today's scattered lifecycle code and theruntime_bridge.pyhub (deep-dive:108-112); - align with epic #992 and pair structural change with test build-out + knowledge transfer (bus-factor / DM-D), because it lands in the repo's single densest, most complex, least-tested core cluster.