Research: Second clones reconcile with origin before every terminus gate
Sources: pre-spec squad (implementer-ivan reproductions, architect-alphonso gate map, researcher-robbie tracker sweep, python-pedro brownfield cut) and post-spec squad (reviewer-renata, doctrine-daphne); dispositions in traces/design-decisions.md.
R-1 Fetch at the gate vs read existing remote-tracking refs
- Decision: the gate contacts the remote itself (
ls-remotethenfetchof the listed branches). - Rationale: #5780's clone never fetched; a ref-only read (the #4969 shape) stays red. FR-006.
- Alternatives: read
refs/remotes/*only (keeps ADR 2026-06-05-1 network-free, leaves the P0 open — operator rejected); fullgit fetch <remote>(unbounded set of refs, slower, can prune unrelated refs).
R-2 Why ls-remote before fetch
- Decision: one
ls-remote --headsfor the branch set, then fetch only the listed branches. - Rationale:
git fetch r +refs/heads/x:...fails the whole fetch whenxis absent on the remote; ls-remote also makesremote_missinga positive answer from the remote (FR-006 fail-closed rule), never an inference from an absent local ref. - Alternatives: fetch with a glob refspec (fetches every lane of every mission); per-branch fetch (N contacts).
R-3 Scoping the status-evidence verdict
- Decision:
behindfor status evidence counts remote-only commits that changekitty-specs/<slug>/status.events.jsonl. - Rationale: in lanes /
--commit-to-targettopologies the evidence branch is the target; an unscoped check would refuse whenever a teammate landed anything (#1706, FR-015). The event log is the sole lifecycle authority (status model), so it is the right scope. - Alternatives: whole branch (contradicts FR-015); in-memory union of logs (stricter, more code; noted as a later refinement).
R-4 Remote resolution rule
- Decision:
branch.<b>.remote→ sole configured remote →origin→ none (FR-017). - Rationale: one rule for freshness; a dead secondary remote (fork
upstream) must not trip FR-008.remote_probeskeeps its documented all-remotes existence semantics inside the same owner (#4979 C-001 honoured). - Alternatives: hard-coded
origin(#4969 today; wrong for non-origin setups); all remotes (any dead remote refuses).
R-5 Status evidence: refuse vs fast-forward
- Decision: refuse (operator ruling). The gate never moves the evidence branch (C-002).
- Rationale: the evidence branch is the authority the gate is about to judge; moving it mid-gate needs merge-driver config that #5759 shows is often missing, and on a resume would trip
UNEXPLAINED_BRANCH_MOVE(#5686).
R-6 Review lane: fast-forward through CAS
- Decision:
advance_branch_ref(repo, lane, remote_sha, expected_old_sha=local_sha, is_residue=<review-lock residue>), thenrecord_tip. - Rationale: existing single authority for moving a branch with checkouts; dirty-checks and resyncs every checkout atomically; compare-and-swap; C-003. Not editing
ref_advance.py(C-007).
R-7 Opt-out shape
- Decision:
--origin-check {enforce,warn}on consolidate, accept, orchestrator-api accept-mission / consolidate-mission; default fromSPEC_KITTY_ORIGIN_CHECK(unset →enforce; unknown →enforce+ warning). The warning names the source. - Rationale: operator ruling (fail closed + opt-out + env default); valued variable mirrors
SPEC_KITTY_MODE; avoids the retired "sync" vocabulary (C-006). - Alternatives: boolean
--skip-origin-check(no env symmetry), reason-required attestation (heavier; not asked for).
R-8 Where the merge-driver install goes
- Decision: init's already-initialized branch and upgrade's always-run finalizer call the existing
_ensure_merge_driver_git_config; upgrade reports it inUpgradeOutcome. - Rationale: the config is clone-local and never in the committed migration ledger, so a recorded migration can never install it on a second clone (#5759); ADR 2026-10-04-3 says upgrade reports one outcome.
R-9 Architectural gates
- Decision: (a) census: no
fetch/ls-remote/pull/clone/remote show(without-n) git argv outsidesrc/kernel/git/, empty allowlist after draining push_preflight, remote_probes, protection_policy, doctrine git_source; modelled ontest_git_path_listing_owner.py(scanned-file floor, planted hit per argv form). (b) registry: named evidence-gate entry points must callorigin_freshness; floor 5; planted omission fails. - Rationale: Standing Order #5 / ADR 2026-09-30-1 (empty allowlists).
- Alternatives: a single "every gate reconciles" AST rule (not expressible statically without a registry).
R-10 Orchestrator-api envelope
- Decision:
consolidate-mission→PREFLIGHT_FAILEDwithdata.preflight_error_code/data.preflight_error_codes(the shape #5668 introduced);accept-mission→MISSION_NOT_READYwithdata.preflight_error_code; both adddata.origin_freshness(verdict list). CONTRACT_VERSION 1.10.0 → 1.11.0. - Rationale: reuse existing envelope codes (no new top-level error code), additive data fields.
Findings disposition (squads)
See traces/design-decisions.md (pre-spec and post-spec squad dispositions: every finding accepted, changed or deferred with rationale).