Quickstart — Red-First Repro Recipes
How to reproduce each defect RED before its fix (ATDD, NFR-004). All use real git; mock only out-of-git side effects, per tests/integration/test_merge_lane_planning_data_loss.py Layer 2.
#4752 — primary checkout reset
1. Real repo + mission staged to merge; put the primary checkout on a non-target branch with an uncommitted tracked edit. 2. Drive _run_lane_based_merge with _real_merge_external_mocks; do NOT mock _refresh_primary_checkout_after_merge. 3. RED assert (pre-fix): the tracked edit is destroyed / SafeCommitHeadMismatch raised after the ref advanced. 4. GREEN (post-fix): preflight refuses with DestructiveOpRefused (MERGE_UNSAFE_PRIMARY_OFF_TARGET/_DIRTY) before any ref advance; edit survives; repo byte-identical. 5. Also add a --resume variant (US1 AC4).
#4753 — lane worktree force-remove
1. Real repo + one lane worktree; leave a tracked edit + an untracked file uncommitted in it (never on the lane branch). 2. Drive the merge through the cleanup phase; do NOT mock the worktree loop. 3. RED (pre-fix): worktree force-removed, files gone, exit 0. 4. GREEN (post-fix): preflight detects the dirty worktree; fail-closed refusal (no retention) OR retained (retention flag); files survive. 5. Coord variant: dirty coord worktree → refusal holds back the coupled coord branch + marker teardown (FR-004); assert all three survive together.
#4754 — abort of the user's own merge
1. Real repo; create a genuine in-progress user merge (MERGE_HEAD in repo_root) and NO spec-kitty merge state. 2. Run _dispatch_abort (the merge --abort path). 3. RED (pre-fix): git merge --abort fires on repo_root; user's resolution lost; "No active merge state to abort." followed by "Aborted in-progress git merge." 4. GREEN (post-fix): no abort on repo_root; user's MERGE_HEAD preserved; messaging internally consistent.
Parity + residue (regression safety)
(NFR-002).
(NFR-003) — dedicated unit test on assert_worktree_clean with the injected is_toolchain_generated_churn.
- Clean/on-target merge,
--resume, and abort-with-active-state: unchanged behavior meta.jsondiff limited to the VCS-lock stamp does NOT trigger a refusal
Local test commands (targeted)
cd <clone>
.venv/bin/python -m pytest tests/integration/test_merge_lane_planning_data_loss.py -q # harness home
.venv/bin/python -m pytest tests/git/ tests/specify_cli/merge -q # guard + merge units
.venv/bin/python -m pytest tests/architectural/ -k "destructive or routing" -q # NFR-006 gate (targeted)