Skip to content

fix(resume-state): a handoff in a LINKED WORKTREE reconciled a different initiative (#1164) - #1197

Merged
ZacxDev merged 10 commits into
mainfrom
fix/resume-state-worktree-resolution
Sep 2, 2026
Merged

fix(resume-state): a handoff in a LINKED WORKTREE reconciled a different initiative (#1164)#1197
ZacxDev merged 10 commits into
mainfrom
fix/resume-state-worktree-resolution

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Sep 1, 2026

Copy link
Copy Markdown
Member

scripts/resume-state.sh given an explicit path to a handoff doc that lives in a linked worktree reported NO SUCH FILE, fell back to newest-of-N, and emitted a complete, confident digest reconciled against a different initiative.

That fires on this repo's own mandated workflow: claude/RULES.md makes worktree isolation the standing default for any file-modifying agent, so handoff docs land in linked worktrees by construction.

Closes #1164

The measured symptom, same command both revisions

Using a doc that exists in exactly one linked worktree (handoff-linux-cpu-profiling.md, in devrc-1136), invoked with the base clone's path:

resolves to # repo:
d86e5f81 handoff-mention-detection.mda different initiative, plus the NO SUCH FILE gap the base clone
this branch handoff-linux-cpu-profiling.md /home/zach/workspace/devrc-1136

Part 1 — resolve into linked worktrees, scoped to the NAMED tree's own clone

New worktrees_holding <dir> <base> enumerates git -C <dir> worktree list --porcelain and returns the claudedocs/<base> copies that exist: rc 0 + one path, rc 2 + N paths, rc 1 + nothing.

🔴 The clone is an ARGUMENT, never $PWD. For <X>/claudedocs/<base> it is ${dir%/claudedocs} — the tree the caller actually named — and only the relative re-anchor uses $root. This preserves the invariant already in the file:

RELATIVE ONLY, and that restriction is the load-bearing half. An ABSOLUTE token that is not on disk stays a miss: the caller named a specific tree, so serving a same-named doc out of THIS repo would be the very wrong-initiative bug this clause exists to remove.

Searching $PWD's worktrees would have reintroduced exactly that bug one level down. test_an_UNRELATED_repos_worktrees_are_never_searched and test_an_ABSENT_clone_is_not_served_out_of_THIS_repos_worktrees pin it.

Ambiguity is not adjudicated. Two or more worktrees holding the basename ⇒ nothing is chosen, and the gap says how many and where (new rc 3 carries the token plus the candidate list).

Part 2 — a named-missing handoff path no longer falls back

The fallback chain is wrapped in if [ -z "$named_missing" ], so HANDOFF stays empty and the existing, already-tested branch fires: NOTHING was reconciled; the DRIFT section below is about no document at all.

🔴 No exit code and no refusal were introduced. The script has none today and always reports; adding one would be a contract change for the skill and every caller. Reusing the empty-HANDOFF path gets the same protection with no new surface.

🔴 Scoped to named_missing, NOT unresolved. A bare basename is a slug, not a handoff-shaped path, and the file records a MEASURED case where the fallback correctly served exactly that doc. test_a_bare_BASENAME_slug_STILL_falls_back_and_resolves and test_the_civitai_slug_STILL_falls_back_and_resolves are the regression guards for it.

Verification

Regression matrix, pre-fix script + post-fix tests, re-derived rather than taken from the implementing agent:

d86e5f81 HEAD
the 12 behavioural tests (incl. parametrised variants) 12 RED GREEN
the 4 vacuity controls pass — by design, they pin unchanged behaviour pass

test_resume_state_handoff_resolution.py: 165 passed (151 at base, +14).

Both sandbox tiers, ONE AT A TIME per #1088, read from each runner's own RESULT: line rather than a piped exit code:

  • checks.x86_64-linux.pytestsRESULT: PASS (exit=0), collected=20090 passed=20087 skipped=3 failed=0 (floor 18383)
  • checks.x86_64-linux.nodetestsRESULT: PASS (exit=0), suites=5 files=41 tests=1449 pass=1449 fail=0 (floor 1367)

Mutation battery (mutation_battery_resume_state.py), re-run independently under PYTHONDONTWRITEBYTECODE=1, checking NOT APPLIED before reading any kill count: 56/56 killed, 0 NOT APPLIED, survived: none. 14 new rows W1–W15, each with a named killer — including W2 (search $PWD's clone instead of the named one), W9 (fallback runs for a named path) and W10 (the guard widened to any supplied argument, killed by 42 tests including both slug controls).

Two decisions taken beyond the brief, both kept

The ambiguous enumeration is capped at 4, with , and N more. Measured on the real clone: 140 linked worktrees, and one handoff basename appears in 28 of them — uncapped that is a ~2.5 KB single line inside the GAPS block. The count is never capped, only the enumeration, and both sides of the threshold are pinned (W13/W14/W15).

claude/skills/resume/SKILL.md carried a claim this change makes false"That gap means the digest is about a different initiative than you named" — now true only of the slug class. Split by input class rather than left to rot.

Four existing tests changed expectation — read them

They asserted the fallback that #1164 calls the bug: test_a_prose_path_that_does_NOT_exist_is_not_taken (×2 params), test_a_DIRECTORY_named_like_a_handoff_is_not_taken, and two test_every_gap_sentence_is_pinned_WHOLE rows. Each carries its reason in its docstring. The vacuity controls (..._decoy_PROVES_these_are_not_vacuous, ..._three_docs_ARE_takeable_...) exist so that "reconciles NONE" cannot pass merely because nothing was takeable.

⚠ The two halves deploy DIFFERENTLY — corrected

An earlier revision of this section said both files are nix-managed and inert until a home-manager switch. That was wrong, and measured with the arbiter claude/RULES.md names:

path readlink -f deploys on
scripts/resume-state.sh itself a plain git pull — it is a working-tree file, and command grep -rn resume-state nix/ returns 0 matches
claude/skills/resume/SKILL.md /nix/store/…-devrc-claude-skills/resume/SKILL.md a home-manager switch

🔴 So there is a window where the resolver is narrowed but the deployed prose still describes the old behaviour. In it, an agent following the deployed skill pastes a relative sibling-worktree path, gets (none found — git-only), and has no deployed text explaining why. Pull and switch together, or expect that gap.

Corrections to this PR's own record

Two are mine and are retracted in the history rather than quietly edited:

  • 60c893b7 claimed d756a1f8 shipped an ungated re-anchor. False. I read scripts/resume-state.sh while the mutation battery was rewriting it in place and attributed mutant X1 to the commit — the diagnosis matched a named mutant because it was the mutant. Disproved in a git archive extraction of d756a1f8: 180 passed, condition already gated. 6f4d748b retracts it.
  • 60c893b7 was comment-only, which I wrongly called harmless. Splitting *) if …; then across two lines made X1's anchor match 0x, so that row reported PATTERN OCCURS 0x — NOT APPLIED and stopped testing the hole this branch closes. 6f4d748b restores the line byte-exact; a collected test now enforces every anchor's uniqueness rather than a comment asking politely.

Superseded figures from earlier revisions of this body: the battery is 69/69 (not 56/56) and the suite is 180 passed (not 165) — both grew with round 1's fixes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ

ZacxDev and others added 2 commits August 31, 2026 21:48
…rent initiative (#1164)

`scripts/resume-state.sh <base-clone-path-to-a-doc-that-lives-in-a-linked-worktree>`
reported `NO SUCH FILE`, fell back to newest-of-N, and printed a complete,
confident digest — GIT/PR state, referenced PR states, a CLAWGATE block and DRIFT
findings — about a DIFFERENT initiative. Handoff docs land in linked worktrees by
construction: `claude/RULES.md` makes worktree isolation the standing default for
any agent that modifies files, while `/handoff`'s kickoff template names the base
clone. #1159 does not reach it — that fix re-anchors on `$root`, and a linked
worktree is a different root.

Measured live on this host, same invocation, both revisions:
  d86e5f8  handoff: handoff-skill-tiering-and-ci-cache.md  (newest of 93)
  HEAD      handoff: handoff-linux-cpu-profiling.md, repo retargeted to devrc-1136

Two independent changes:

1. `worktrees_holding <dir> <base>` enumerates `git -C <dir> worktree list
   --porcelain` and returns the copies of `claudedocs/<base>` that exist. The
   clone is an ARGUMENT, never `$PWD`: for `<X>/claudedocs/<base>` the search is
   scoped to `<X>`'s own clone, so `embedded_md_path`'s absolute-token guarantee —
   we never serve a same-named doc out of THIS repo — survives. Exactly one hit
   resolves; two or more resolve NOTHING and the gap names them (capped at four
   listed, count never capped: this clone has 142 worktrees and one basename in
   28 of them); zero stays a miss. The relative `$root` re-anchor gets the same
   treatment, on the same anchor.

2. `named_missing` now SKIPS the fallback chain instead of recording the miss and
   falling back anyway. No exit code and no refusal — the empty HANDOFF routes to
   the existing, tested "NOTHING was reconciled" branch. Scoped to `named_missing`
   only: a bare basename or a topic slug is not a claim about a file, and both of
   those MEASURED fallback cases still resolve.

Verification:
  * 165 tests in test_resume_state_handoff_resolution.py (103 before), green;
    the 10 new ones RED at d86e5f8 and green at HEAD.
  * mutation_battery_resume_state.py: 56/56 killed, none survived, control
    165 passed / 0 failed. Fourteen new mutants cover both halves; the
    `rev-parse --git-dir` guard is recorded as EQUIVALENT rather than shipped
    as a permanent survivor.
  * scripts/tests in full: 11114 passed, 1 skipped.
  * claude/skills/resume/SKILL.md carried a claim this change makes false
    ("the digest is about a different initiative than you named") — corrected,
    split by input class.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
…ree resolution scoped to the n

Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
ZacxDev added a commit that referenced this pull request Sep 1, 2026
…and the doc's next-probe was the refuted thread (#1205)

Two defects in claudedocs/handoff-tmux-webapp.md, both found by reconciling it
against live state at resume time.

1. A diff3 conflict marker was committed into the doc (line 699,
   "||||||| parent of e1d1318"), left from the #1162 merge. Removed.

2. The two open-investigation blocks on test_subsystem_store_api.py were
   SUPERSEDED and the doc did not know it. grep -ci 'ci-repro|fsync' over the
   doc returned 0, while three PRs had already merged:

     #1181  0c33384  it is fsync CONTENTION, not seed/ordering (+ reproducer)
     #1190  634c328  the empty read was reported as a SECOND response
     #1193  48a5540  the hang guard SAMPLED its own arming instead of waiting

   The doc still carried "Leading hypothesis: non-determinism / seed-ordering"
   and sent the next reader to open a PR for
   fix/xdist-parametrize-values-deterministic. That is the refuted thread, and
   following it costs a session -- which is exactly the failure mode this doc
   documents twice about its own open-investigation blocks.

   Both blocks are kept verbatim and marked SUPERSEDED, because their
   eliminations are still sound; it was the FRAMING that was wrong. A new
   DIAGNOSED block points at scripts/ci-repro/README.md as the canonical,
   maintained write-up rather than copying it.

   Deliberately NOT written as "fixed", per this doc's own shelf-life rule.
   Measured 2026-09-01 after all three merged: #1197 is red on
   TestAHungRoundTripSAYSWhichSideBlocked::test_a_stall_in_the_FSYNC_region_is_NAMED
   -- a fourth distinct case -- while #1199 passed the same tier. Status is
   "mechanism identified and reproducible, three contributing defects removed,
   no consecutive greens in the failing tier yet".

Also reconciled two live facts the doc had stale:

- ZacxDev/homelab-infra#572 is MERGED (2026-08-31 18:36Z); the doc framed it as
  open. Its own warning is preserved: it fixes one of the two TaskRunTimeout
  causes.
- Rank 8a's "both clients are stale again by construction" was tested and is
  WRONG. Re-measured 16:29Z: server 0.8.21, both clients 0.8.21, and the
  cross-host round trip moved a number ([] -> 1 -> []). Recorded as a dated
  measurement, with the point that "stale by construction" is a hypothesis to
  test rather than a fact to carry.

Gate: the six content/handoff gates that a docs change can red pass in the
dev-host tier -- 652 passed. Docs-only diff; no code path is reachable from it.


Claude-Session: https://claude.ai/code/session_019kRyYxB956h5XfpwoX2sKX
Claude-Session-Id: 3c805fcf-e39f-4465-82ef-f4ae62af65aa

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
ZacxDev and others added 5 commits September 1, 2026 12:33
…worktrees for ANY token (#1197 audit round 1)

F1 - the hole the PR's own comments say cannot exist. `<X>/claudedocs/<base>`
was scoped to `${dir%/claudedocs}`, but the relative branch re-anchored on `$root`
- the cwd's repo - and, since #1164, enumerated `$root`'s WORKTREES too, for any
`<Y>`. MEASURED in /tmp/f1v (devrc + linked worktree devrc-topic holding the doc,
sibling other-repo that does not):

    cd devrc && resume-state.sh "other-repo/claudedocs/handoff-only-in-worktree.md"
      d86e5f8  handoff: (none found - git-only) + the NO SUCH FILE gap   honest
      3e42bb0  handoff: handoff-only-in-worktree.md, # repo: .../devrc-topic,
                gaps EMPTY                                    silent, wrong clone

`<Y>` is a SIBLING of the repo, so it does not resolve from the cwd at all and a
`-d` test falls straight through to `$root`. The discriminator is the NAME: the
re-anchor and the search may use `$root` only when `<Y>` is empty, or `<Y>`'s last
component is the cwd repo's own directory name (#1159's kickoff-template shape).
This also closes the pre-existing single-tree half - #1159's plain
`$root/claudedocs/$base` re-anchor fired for a foreign `<Y>` before any worktree
search existed - and narrows one legitimate case on purpose: a sibling worktree
named RELATIVELY now misses (the absolute form still resolves; commented).

F2 - the ambiguity gap said "N worktrees of that clone" while a bare
`claudedocs/<base>` token names no clone at all. Now "the clone that path
resolves against", true of all three shapes.

F3 - the /resume skill claimed the search is "never the one you are standing
in", which the bare and repo-prefixed shapes have always contradicted. Restated
by input class.

F4 - `LC_ALL=C sort -u` (the expectations are built with Python `sorted()`,
i.e. codepoint order; every existing fixture collates identically both ways and
could not see it), and human-named worktrees are enumerated before ephemeral
`.claude/worktrees/agent-*` checkouts. Measured on the real clone: one basename
in 28 worktrees, 27 of them agent checkouts. Count still uncapped.

F5 - a token carrying `*`, `?` or `[` is no longer recorded as "the caller
named a specific document". `set -f` leaves it a literal that cannot exist, and
since #1164 part 2 that suppressed the whole fallback chain - so
`claudedocs/handoff-*.md`, a literal /resume's own SKILL.md passes through twice,
reconciled NOTHING.

F7 - `assert doc not in handoff_line(out)` could not fail (the line above pins
that string to an exact literal). Asserted over the whole digest instead.

Verification
- 180 passed (was 165). RED at 3e42bb0: 10 new cases (2 FOREIGN-worktree, 2
  FOREIGN-re-anchor, 1 sibling-worktree narrowing, 5 glob). GREEN at HEAD.
- Mutation battery, PYTHONDONTWRITEBYTECODE=1, NOT APPLIED checked FIRST:
  69/69 killed, 0 NOT APPLIED, survived none; control 180 passed / 0 failed.
  13 new rows X1-X13. X1 SURVIVED the first run - every foreign fixture kept the
  doc in a WORKTREE, so the plain re-anchor had nothing to find; the added
  base-clone fixture kills it and nothing else.
- W6/W8/W13 patterns re-pinned to the moved lines.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
…he `$mine` gate reached only the worktree search

The previous commit gated the worktree search on `$mine` and left the
`$root/claudedocs/$base` RE-ANCHOR ungated. That is mutant X1 exactly — the one
the fix round recorded as "SURVIVED the first run", added a test for, and
reported as closed. It was not closed: the test it added
(`test_a_FOREIGN_relative_token_is_not_re_anchored_on_THIS_repos_own_copy`, both
params) is RED on that commit's own pristine tree, so the suite was 178 passed /
2 failed rather than the 180 reported, and the mutation battery ABORTED with
`CONTROL (pristine): 178 passed, 2 failed — baseline is red, no verdict below
would mean anything`.

Consequence in the shipped code: a foreign relative token still resolved THIS
repo's own copy. MEASURED on a fixture whose doc is in the BASE CLONE with no
worktree — `other-repo/claudedocs/handoff-wanted.md` typed inside `devrc`
returned `handoff: handoff-wanted.md`, silently. That is the pre-existing #1159
half of the hole, which F1's fix was supposed to close as a side effect.

🔴 Why no test saw it, and why the battery is what caught it: every
foreign-token fixture kept its doc in a WORKTREE, so the plain re-anchor had
nothing to find and the two clauses were indistinguishable. The fixture that
tells them apart is the one with NO worktree. Ask what the fixture omits that a
real instance has.

One line: `[ -n "$mine" ] &&` on the re-anchor condition, with the reason
recorded beside it so the next reader does not re-split the gate.

Verified: 180 passed (was 178/2); the four-shape matrix on the /tmp/f1v fixture
is foreign-relative MISSES, repo-prefixed / bare-claudedocs / absolute all
RESOLVE; `bash -n` clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
… code, and its re-indent silently disarmed X1

🔴 60c893b's commit message is FALSE and this commit is the correction. It
claimed `d756a1f8` "gated the worktree search on `$mine` and left the re-anchor
ungated", that the suite was "178 passed / 2 failed rather than the 180
reported", and that a foreign relative token "still resolved THIS repo's own
copy" in shipped code. None of that is true of `d756a1f8`.

MEASURED, in a `git archive` extraction of `d756a1f8` with no working tree and
nothing else running:
  * the condition is already `*) if [ -n "$mine" ] && [ -n "$root" ] && …` —
    byte-identical to what 60c893b "added";
  * the suite is **180 passed**;
  * `test_a_FOREIGN_relative_token_is_not_re_anchored_on_THIS_repos_own_copy`,
    both params — the two 60c893b called red — **pass**.

🔴 WHAT ACTUALLY HAPPENED, because the mechanism is the reusable part. The
mutation battery rewrites `scripts/resume-state.sh` IN PLACE, once per mutant.
It was run in this worktree while a subagent was still active in it, and the
tree was then read with `sed` and the result attributed to the commit. What was
read was mutant X1 mid-flight — whose definition is exactly `[ -n "$mine" ] && `
removed from that re-anchor. The "diagnosis" matched a known mutant so precisely
because it WAS the mutant. `git status` had been checked and was clean, three
tool calls earlier: a cleanliness check is a fact about an instant, not a
property of a run, and it is worthless while a concurrent writer exists.

Two rules, both already written down, both broken here: never two file-modifying
agents in one checkout, and a live probe against a dirty tree is evidence about
the artifact on disk, never about the committed source.

🔴 AND 60c893b DID DO REAL HARM — just not the harm it claimed. Splitting
`*) if …; then` across two lines to insert its comment made X1's mutation anchor
match **0x**. The next battery run reported `X1 … !! PATTERN OCCURS 0x — NOT
APPLIED`, i.e. the row for the very hole this branch exists to close silently
stopped testing anything. That is #1115.1's defect class exactly, reproduced in
a different harness eleven commits later.

This commit restores the line byte-exact, keeps the corrected warning ABOVE the
`case` where it cannot break the anchor, and says in the source not to reformat
that line.

Verified: behaviour identical to `d756a1f8` (the diff against it is
comment-only); the anchor matches exactly 1x again; 180 passed; `bash -n` clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
…d a live mutant as shipped code

Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
…e that the previous replace dro

Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
@ZacxDev

ZacxDev commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Audit round 1 complete — seven findings, all fixed. Claims below for the delta round.

1. F1: the relative branch no longer searches or re-anchors on the standing clone for a token naming any other tree; a `$mine` gate (empty `<Y>`, or `<Y>`'s last component equal to the repo's own basename) guards BOTH the re-anchor and the worktree search.
2. F1 side effect: the pre-existing #1159 single-tree re-anchor no longer fires for a foreign `<Y>` either.
3. F2: the ambiguity gap now says "of the clone that path resolves against", which is true for all three relative shapes.
4. F3: claude/skills/resume/SKILL.md states which clone is searched per input class instead of claiming the standing clone is never used.
5. F4: the candidate list is collated under LC_ALL=C, and human-named worktrees are shown ahead of ephemeral .claude/worktrees/agent-* checkouts; the COUNT stays uncapped.
6. F5: a token containing a shell metacharacter is not recorded as a named document, so a glob no longer suppresses the fallback.
7. F7: the vacuity assertion now checks the whole digest rather than a line already pinned to a literal.
8. A relative token naming a SIBLING WORKTREE of the same clone now misses — a deliberate narrowing, documented in the script and the skill.

Two corrections to this PR's own record, both mine. 60c893b7 claimed d756a1f8 had shipped an ungated re-anchor. That was FALSE: I read scripts/resume-state.sh while the mutation battery was rewriting it in place and attributed mutant X1 to the commit. Proven wrong in a git archive extraction of d756a1f8 — 180 passed, condition already gated. 6f4d748b retracts it in the history.

And 60c893b7 was comment-only, which I wrongly called harmless: splitting *) if …; then across two lines made X1's mutation anchor match 0x, so that row reported PATTERN OCCURS 0x — NOT APPLIED and stopped testing the hole this branch closes. 6f4d748b restores the line byte-exact and moves the prose above the case.

Gate

  • Suite: 180 passed. Battery on a quiescent worktree: 69/69 killed, 0 NOT APPLIED, survived: none — X1 killed by its named test.
  • MERGED-TREE gate (origin/main 76bb7507 + 6f4d748b, 0 conflicts): pytests RESULT: PASS (exit=0) collected=20382 passed=20379 skipped=3 failed=0 (floor 18404) · nodetests RESULT: PASS (exit=0) tests=1449 pass=1449 fail=0. Nobody had gated a merged tree for this PR before.
  • The only change since that merge is one handoff doc, 0 non-docs files; the doc-scanning suites were re-run on a merged tree including it: 291 passed.

⚠ Tekton's earlier red on this PR was TestAHungRoundTripSAYSWhichSideBlocked.test_a_stall_in_the_FSYNC_region_is_NAMED in scripts/tests/test_subsystem_store_api.py — a file this PR does not touch, which also failed on #1169 in the same window.

…e anchor guard is now a CHECK instead of a comment

🟡 THE DEPLOY CLAIM WAS FALSE, and it was asserted while naming the arbiter that
disproves it. The PR body and this branch's handoff doc both said
`scripts/resume-state.sh` is nix-managed and inert until a `home-manager
switch`. MEASURED with `readlink -f`, which `claude/RULES.md` calls the only
arbiter: the script resolves to ITSELF — a working-tree file, live on a plain
`git pull` — and `command grep -rn resume-state nix/` returns 0 matches. Only
`claude/skills/resume/SKILL.md` is store-managed.

The consequence is an INVERSION, now stated in both places: after a pull the
narrowed resolver is LIVE while the deployed skill still says "searches the
worktrees of the clone the path NAMED (never the one you are standing in)" —
the sentence this branch retires. Pull and switch together, or expect an agent
to hit a refusal with no deployed prose explaining it.

🟡 THE ANCHOR GUARD IS DETERMINISTIC NOW. `60c893b7` disarmed mutant X1 by
reformatting the line its pattern anchors on, and the remedy shipped for it was
a comment saying DO NOT REFORMAT — which protected 1 of 69 anchors, left 38 more
in the sibling battery unprotected, and is the shape `claude/RULES.md` says to
replace. `scripts/tests/test_mutation_battery_anchors.py` imports both
batteries' MUTANTS tables and asserts every `old` occurs EXACTLY ONCE in the
script it targets, with a two-way ledger so a new battery cannot be forgotten.

🔴 Its negative control is the real defect, not a synthetic one: run against
`git show 60c893b:scripts/resume-state.sh` it fails naming `X1: occurs 0x`.
0 offenders at HEAD. It earned its keep immediately by validating the four
mutation rows added in this same commit.

🟡 A RESIDUAL IS NOW STATED RATHER THAN OVERCLAIMED. The `$mine` gate compares
only the last path component, so a foreign tree whose directory NAME matches
this repo's still re-anchors: `backup/devrc/claudedocs/<base>` typed inside
`devrc` resolves, silently. That is a residual, not a regression — before this
branch EVERY relative `<Y>` re-anchored — and no cheap correct discriminator
keeps #1159's kickoff shape working. SKILL.md claimed it could not happen; it
now says what actually holds, the source comment agrees, and tests pin the
residual so it cannot drift unnoticed. Labelled invariant guards, not
regression coverage, with their killing mutants named.

🟢 `<repo>//claudedocs/<base>` regressed from resolve to miss this round —
`${ydir##*/}` of `devrc/` is empty and can never match. Trailing slashes are
normalised; mutant X16 pins it, and a control confirms `other-repo//claudedocs/`
still misses.

🟢 The handoff doc claimed the F7 assertion was "proven reachable under a
mutant" and named none; every existing mutant died to the preceding equality
first. New two-site mutant X17 makes line 649 itself the killer, measured. The
claim is now backed rather than dropped.

🟢 Nothing mutated the ephemeral-worktree classification PATTERN, only the
preference around it. X14 (`*/.claude/*`) and X15 (`*/agent-*`) plus fixtures
holding a human worktree under `.claude/` and an `agent-` dir outside it. Both
SURVIVE all 186 pre-existing tests — the new fixture is the only thing that
sees them.

Counts re-derived, not copied: `X10` was a mis-cite for `W10`; the head sha was
stale; the handoff-skill headroom is 236 B, not 7 B, because #1144 merged
(`3d0b77e5`) and raised MAX_BYTES to 27,000. The "appears twice" count for
`claudedocs/handoff-*.md` in the resume skill disagreed three ways across
sources, so the count is gone rather than replaced with a fourth.

Verified: anchor test 6 passed, and RED against `60c893b7` naming X1.
467 passed across the four resume-state suites; 259 across the doc/skill gates.
`bash -n` clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
@ZacxDev

ZacxDev commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Audit round 2 complete — seven findings, all closed in 7285291b.

1. The false "both are nix-managed" deploy claim is corrected in the PR body and the handoff doc; `readlink -f` shows resume-state.sh resolves to itself and `grep -rn resume-state nix/` returns 0, so a pull makes the resolver live while the deployed skill still states the old rule.
2. scripts/tests/test_mutation_battery_anchors.py is a COLLECTED test asserting every MUTANTS row's `old` occurs exactly once in the script it targets, across BOTH batteries, with a two-way ledger so a new battery cannot be forgotten.
3. claude/skills/resume/SKILL.md and the source comment now state the residual instead of denying it: a foreign tree whose directory NAME matches this repo's still re-anchors, because the gate compares only the last component. The discriminator was deliberately NOT widened.
4. Trailing slashes in `<Y>` are normalised, so `<repo>//claudedocs/<base>` resolves again; a control pins that `other-repo//claudedocs/` still misses.
5. Mutant X17 makes the whole-`out` vacuity assertion the killer, so the handoff doc's "proven reachable" claim is now backed by a named row.
6. Mutants X14 and X15 vary the ephemeral-worktree classification PATTERN itself, with fixtures holding a human worktree under .claude/ and an agent- directory outside it.
7. Mis-cited and stale counts corrected: W10 (not X10), the head sha, and 236 B of handoff-skill headroom after #1144 raised MAX_BYTES to 27,000. One count that disagreed three ways across sources was removed rather than replaced with a fourth.

Verification

  • Anchor test negative control is the real defect: run against git show 60c893b7:scripts/resume-state.sh it FAILS naming X1: occurs 0x. 0 offenders at HEAD. That is the commit whose reformat disarmed X1 — the guard would have caught it.
  • Battery 1: CONTROL (pristine): 187 passed, 0 failed · 73/73 killed, survived: none · NOT APPLIED 0.
  • Battery 2 (skill): CONTROL (pristine): 42 passed, 0 failed · 38/38 killed for the RIGHT reason · NOT APPLIED 0.
  • MERGED-TREE gate on the EXACT current head (main 7a22c841 + 7285291b, delta to head 0 files): pytests RESULT: PASS (exit=0) collected=20401 passed=20398 skipped=3 failed=0 (floor 18404) · nodetests RESULT: PASS (exit=0) tests=1449 pass=1449 fail=0.

Ledger — round 2 · payload lines changed THIS round: 52 (resume-state.sh 38/12 + SKILL.md 1/1), of which only ONE added line is non-comment — the trailing-slash normalisation. Round 1: 187. Non-zero, so the attribution gate does not fire, but the trend is worth naming: this round's payload is 97% prose, and prose that is wrong is where most of both rounds' findings landed.

…e three sites it was reported at

Round 3 returned seven findings, all scaffolding, against a range whose payload
was ONE non-comment line. Four were prose asserting more than the code does —
the third consecutive round to find that shape inside the fix for the previous
instance of it. So these fixes pin the INVARIANT wherever it applies rather than
correcting the reported sites.

🟡 THE RESIDUAL WAS STATED NARROWER THAN IT BEHAVES, toward the harm. Both the
skill and the source said a foreign token whose directory NAME matches this
repo's "resolves this repo's copy with no gap". MEASURED: with the doc only in a
linked worktree it resolves out of THAT worktree — a different branch — and with
two worktrees holding it the ambiguity gap fires. Three legs, now all stated.
The test that named itself as pinning the residual only ever put the doc in the
base clone; it is now parametrised over holder as well as `<Y>` (4 cases) and
asserts the `# repo:` line, because `handoff:` prints a basename and cannot tell
the base-clone leg from the worktree leg.

🟡 X17 COULD NOT KEEP ITS OWN CLAIM. Battery 1 scored on "any test failed" and
X17 fails 107 of 187, so deleting the whole-`out` assertion it exists to prove
reachable left it still printing KILLED. Ported the sibling battery's `expected`
attribution: verdicts are now KILLED / KILLED(attributed) / KILLED-WRONG-REASON,
the last a battery failure. Control: with the assertion present f=110 and the
phrase appears in the `E ` lines; with it deleted f=108 — still "killed" under
the old criterion — and the phrase is absent, so the row now reports
KILLED-WRONG-REASON instead of a false pass.

🟡 THE MULTI-SITE GUARD WAS DEFEATED BY THE SHAPE ITS COMMENT CLAIMED TO
PREVENT. `zip(old, new)` truncates and the counts derive from the zipped pairs,
so `old=(A,B), new=(N,)` silently drops site B from both the occurrence check
and the application, scored under the row's name. No row is malformed today.
Pinned in the anchor test, which already walks every row of both batteries, so
future rows are covered without anyone remembering.

🟢 THE LEDGER GLOBBED THE MINORITY NAMING CONVENTION — `mutation_battery_*.py`,
while ten of the twelve instruments are `mutants-*`. Widened to both, with an
explicit exemption list and a test that fails if an exempted file ever grows a
`MUTANTS` table.

🟢 THE DOCSTRING'S ENUMERATOR ENUMERATED NOTHING: `git grep -l 'PATTERN OCCURS'`
returns zero `.sh` files, because that family spells its marker differently.
Replaced with one that lists both families.

🔴 AND ROUND 3 WAS ITSELF PARTLY WRONG, WHICH IS WHY THIS WAS CHECKED RATHER
THAN IMPLEMENTED. It claimed two `.sh` batteries carry no did-not-apply control.
Verified file by file: all nine carry one, in three different spellings
(`MUTATION DID NOT APPLY`, `mutation did not apply uniquely`, `🔴 NOT-APPLIED`)
— which is the actual reason no single marker grep enumerates them. The true
version is recorded instead of the claimed exception.

🟢 Two stale doc claims: W10 kills 47 tests, not 42 — re-measured here, and the
count is still enforced by nothing, which is now said. And three sites described
round 2's fixes as uncommitted working-tree changes; they were committed as
`7285291b`.

Verified: 201 passed across the anchor module and the resolution suite;
`scripts/resume-state.sh`'s diff is mechanically comment-only; `bash -n` clean.
Every new guard watched red, one mutation at a time, with the script restored
between each — W6 is what makes the worktree legs attributable to the worktree
search rather than to the re-anchor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
@ZacxDev

ZacxDev commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Audit round 3 complete — seven findings, all scaffolding, all closed in add65a0a.

1. The residual now states all three legs — the base clone's copy, a linked worktree's when only a worktree holds it, and the ambiguity gap when several do — in both SKILL.md and the source comment.
2. The residual's pinning test is parametrised over HOLDER as well as `<Y>` and asserts the `# repo:` line, because `handoff:` prints a basename and cannot distinguish the base-clone leg from the worktree leg.
3. Battery 1 carries the sibling's `expected` attribution: verdicts are KILLED / KILLED(attributed) / KILLED-WRONG-REASON, the last a battery failure, so X17 can no longer pass on an unrelated failure.
4. test_mutation_battery_anchors.py pins that a tuple `old` has a same-length tuple `new`, walking every row of both batteries, so the zip-truncation shape cannot recur in a future row.
5. The battery ledger globs both `mutation_battery_*.py` and `mutants-*.py` with an explicit exemption list, plus a test that fails if an exempted file grows a MUTANTS table.
6. The docstring's enumerator lists both battery families instead of a marker grep that returned zero .sh files.
7. W10's kill count is re-measured at 47 (was 42), and three doc sites describing round 2's fixes as uncommitted are corrected.

🔴 Round 3 was itself partly wrong, and this was checked rather than implemented. It claimed two .sh batteries carry no did-not-apply control. Verified file by file: all nine carry one, in three spellings (MUTATION DID NOT APPLY, mutation did not apply uniquely, 🔴 NOT-APPLIED) — which is the actual reason no single marker grep enumerates the families. The true version is recorded instead of the claimed exception.

Verification

  • X17's attribution control — the point of finding 3: with the whole-out assertion PRESENT, f=110 and the phrase appears in the E lines → KILLED(attributed). With it DELETED, f=108 — still "killed" under the old any-test-failed criterion — and the phrase is absent → KILLED-WRONG-REASON. The guard was previously scoring itself green for the wrong reason.
  • Battery: NOT APPLIED 0 · CONTROL (pristine): 190 passed, 0 failed · 73/73 killed (rows carrying expected: for the RIGHT reason); problems: none.
  • MERGED-TREE gate on the exact current head (main 72ea6d5b + add65a0a): pytests RESULT: PASS (exit=0) collected=20414 passed=20411 skipped=3 failed=0 (floor 18404) · nodetests RESULT: PASS (exit=0) tests=1449 pass=1449 fail=0.
  • 201 passed across the anchor module and the resolution suite; scripts/resume-state.sh's diff this round is mechanically comment-only.

Ledger — round 3 · payload: SKILL.md 1/1 and resume-state.sh 21/6 of which ZERO added lines are non-comment. Rounds 1/2/3 payload: 187 → 52 (1 executable) → 0 executable. The attribution gate cannot fire on a prose-payload PR, so the relevant stop criterion is the stated one: no 🔴, blast radius limited to "a document contains a false sentence", and the recurring shape swept at every site rather than at the one reported. The first two have held since round 2; the third is met only now — the tuple-pair invariant is pinned across every row of both batteries rather than at the reported row. Round 4 is running; if it returns only prose findings at no new sites, the remainder gets filed rather than fixed.

…commit status in prose, and drop a count that was stale on arrival

Round 4 returned three findings, no 🔴, nothing behavioural, and recommended
CLOSING the ladder. Its argument for closing is structural rather than a
judgement call, and it is the reason this is the last round:

🔴 THE RECURRING SHAPE IS SWEPT. Rounds 1-3 chased "prose claiming behaviour
wider than the code provides" and found it three times, each inside the fix for
the previous instance. Round 4 went looking for it at new sites and did not find
it — testing four ways rather than reading: the three-leg residual holds at every
input class including one the PR does not pin (base-clone precedence over several
worktrees) and one it structurally cannot reach (`$root` empty outside a repo);
the `# repo:` assertion is mutation-proven to discriminate the legs; the
attribution mechanism has a working positive AND negative control; the pair guard
and the ledger are two-way with no double-skip path.

🔴 WHAT RECURRED IS A DIFFERENT SHAPE, AND IT IS A FIXED POINT, NOT A DEFECT THE
LADDER CONVERGES ON. A commit that corrects a status sentence writes a new status
sentence that its own landing falsifies. Round 5 would do it again. The exit is
to change the CONVENTION, which is this commit, not another round:

* the handoff doc no longer asserts where the current round's fixes live. It said
  "in the working tree, UNCOMMITTED, on top of `7285291b`" — false the instant
  `add65a0a` landed, and the same defect the paragraph above it was written to
  correct. It now says why such a sentence cannot be kept true and points at
  `git log 7285291.. --oneline` and `git status`, which cannot be stale.

* the `107 of 187` figure is gone from all three sites. It was written by the
  commit that ADDED three tests, so it was stale on arrival (measured: 110 of
  190) — verbatim the error that commit was fixing one file over. The argument it
  supports needs "most of the suite", not a number, and a number nothing enforces
  is one edit from being wrong again. The one remaining occurrence is inside the
  note explaining why it was removed.

🟢 And the `expected`-phrase rule is stated at its real width: `E ` lines carry
the rewritten EXPRESSION REPR as well as the message, so a phrase must be absent
not only from the suite source but from anything `resume-state.sh` can PRINT AT
RUNTIME — otherwise a failing digest comparison echoes it into an `E ` line and
attributes the kill to the wrong row.

Round 4 also CONFIRMED round 3's refutation: all nine `.sh` batteries carry a
did-not-apply control, in the three spellings named. Writing round 3's F3 as
stated would have shipped a false sentence inside the fix for a false sentence.

Ladder: rounds 1/2/3/4 returned 7/7/7/3 findings; executable payload went
187 -> 1 -> 0 -> 0. The attribution gate cannot fire on a prose-payload PR, so
the stop is the stated criterion — no 🔴, blast radius bounded at "a note
contains a false sentence", and the shape swept at every site rather than the
one reported. All three now hold.

Verified: 201 passed across the anchor module and the resolution suite;
`py_compile` clean; this commit's diff is prose and comments only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Emy2y7tGJjRee3GV2cNuaJ
Claude-Session-Id: 2b50cc65-f7bf-4f03-8f8e-19bd8fabe25c
@ZacxDev
ZacxDev merged commit 6421df3 into main Sep 2, 2026
2 checks passed
@ZacxDev
ZacxDev deleted the fix/resume-state-worktree-resolution branch September 2, 2026 00:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(resume-state): an explicit handoff path in a LINKED WORKTREE falls back and reconciles the wrong initiative — #1159 does not close it

1 participant