Contracts
coord-commit-partition.md
Contract: coordination-commit path partition (#4905)
Surface: src/specify_cli/cli/commands/agent/workflow.py::_commit_via_coordination_transaction — the shared sink through which every coord lifecycle staging site funnels.
Staging sites covered (all funnel here)
cli/commands/agent/workflow_executor.py:881— claim (planned → claimed,paths=[wp_path, *status_artifacts]):1066— resume-refresh (_implement_emit_resume_refresh):1741— review-claim (for_review → in_review)
Behaviour
For each path in the transaction's paths, classify by artifact kind (mission_runtime.is_primary_artifact_kind):
- PRIMARY-partition (
WORK_PACKAGE_TASK, spec/plan/tasks): route to the PRIMARY target via the existingcommit_to_primary_targetmechanism — never written into the coord worktree / committed to the coordination branch. - STATUS_STATE (
status.events.jsonl,status.json): committed to the coordination branch as today.
Invariant
The coordination branch tree contains zero kitty-specs/<slug>/tasks/WP*.md blobs at every lifecycle point. Consequently the next lane cut from the coord tip carries no WP file, and _merge_recorded_planning_commit (FR-009 planning merge, worktree_allocator.py) completes without an add/add conflict.
Regression assertions (must be RED pre-fix)
1. After agent action implement WP01 on a coord mission → coord tree has no tasks/WP01-.md blob. 2. After WP01 review-claim (for_review → in_review) → coord tree still has no tasks/WP.md blob (multi-site coverage). 3. agent action implement WP02 → lane allocated, planning merge succeeds, no PlanningCommitMergeConflictError, exit 0. 4. lanes topology (no coord) → unchanged (control).
destroyed-lane-guard.md
Contract: destroyed-lane fail-closed guard (#4889)
Surface: src/specify_cli/lanes/worktree_allocator.py::allocate_lane_worktree — a pre-flight evaluated after the REUSE (worktree_path.exists()) and CRASH_RECOVERY (_branch_exists()) gates and before the FRESH routes.
Preconditions consulted
CTX= persistedWorkspaceContextfor the WP's lane exists (workspace/context.py::find_context_for_wp/load_context).STATE= canonical WP lane state via the reducer over the resolved coordination status surface (never the lane worktree tree).- refs: neither the local lane branch nor its worktree exists.
REACH= the lane's cut-from base (WorkspaceContext.base_commit, the parent SHA fixed at allocation — used as a proxy for the lane's work tip, which is not persisted) is an ancestor of the target branch.
> Known limitation (non-blocking, tracked as follow-up). WorkspaceContext persists only base_commit — the SHA the lane was cut from (its parent), never the lane's own committed-work tip (no work-tip SHA is persisted anywhere the guard can read once the branch is -D'd). So REACH is evaluated against the parent, not the work tip. This is sound in the dominant direction: ¬REACH(base) ⟹ the work tip is also unreachable ⟹ REFUSE is always correct, which covers the entire default coord topology (the coordination branch's lifecycle commits never land on target, so base is genuinely not an ancestor of target) — i.e. the filed #4889 P0 is fully closed. The residual is a narrow false-pass window when REACH(base)=True but the work commits did not land on target (e.g. a non-squash merge of the parent line only) with a stale non-terminal status — there the guard suppresses and a re-cut could still strand work. Closing it requires persisting the lane's work tip at commit time so REACH can key on the actual tip; deferred to avoid a WorkspaceContext schema + write-on-commit change inside this P0. See the mission PR body / follow-up issue.
Behaviour
- Trigger (
CTX∧STATE ∈ {in_progress, blocked, for_review, in_review}∧ ¬branch ∧ ¬worktree ∧ ¬REACH): raise a typed, fail-closed error → - non-zero exit;
- message names the missing lane branch (
branch_name) and a concrete recovery ref/command (reflog /git fsck --lost-found); - must not print
✓ Lane worktree ready; - must not overwrite
.kittify/workspaces/<slug>-lane-<id>.jsonor any lane metadata. - No trigger: fall through to existing routing unchanged (REUSE / CRASH_RECOVERY / FRESH / terminal / reachable-tip resume).
Caller-independence (FR-008)
Because the guard is inside allocate_lane_worktree, it fires for both callers:
lanes/implement_support.py::create_lane_workspace(CLIspec-kitty implement);orchestrator_api/commands.py::_resolve_start_workspace(agent action implement/start-implementation/transition --to claimed).
Regression assertions (must be RED pre-fix)
1. Destroyed lane + in_progress via CLI → non-zero, diagnostic, CTX unchanged, no Lane worktree ready. 2. Same via orchestrator/agent caller → identical refusal. 3. Non-in_progress non-terminal (blocked/for_review/in_review) destroyed lane → refusal. 4. Genuinely fresh lane (no CTX, planned) → normal fresh creation (no false positive). 5. Intact worktree → REUSE no-op; intact branch, gone worktree → CRASH_RECOVERY re-attach (control arms preserved). 6. Re-open after merge (tip ancestor of target) → resume/recreate, no false refusal.