Skip to content

docs(rules): three measured lessons folded into existing bullets, paid for without narrowing one (#193) - #489

Merged
ZacxDev merged 2 commits into
mainfrom
docs/rules-worktree-consolidation
Aug 15, 2026
Merged

docs(rules): three measured lessons folded into existing bullets, paid for without narrowing one (#193)#489
ZacxDev merged 2 commits into
mainfrom
docs/rules-worktree-consolidation

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

What this is

clawgate #193 plus three lessons measured 2026-08-14. The task card bundled them deliberately, and it was right to: all three landed inside paragraphs the consolidation had just rewritten.

The consolidation half of #193 was already done — PR #458 turned the five worktree bullets into three (recipe / "a worktree isolates a working DIRECTORY only" + REPO·SESSION·ENVIRONMENT sub-bullets / base-clone re-sync). No further worktree consolidation was available without losing scope, so this PR does not attempt one. What it does is the part that was actually left: fit three new rules into the budget without a ceiling bump, which the card called for in its own words — "the answer to the next real rule is consolidation, not another bump."

MAX_BYTES and MIN_HEADROOM_BYTES are unchanged.

Size, as printed by the test

before: 33,264 B
after:  34,268 B   headroom 932 (min 900)   slack above the floor: 32 B

The honest reading: the file is at capacity. 32 B is not a working margin. The next real rule needs either a genuine consolidation or an argued bump — the module comment already predicted this and is now correct twice over.

Where each lesson went, and why

Placement was chosen by where the reader already is when the hazard fires, not by which cluster the lesson came from. Two of the three are verification lessons, not worktree ones, and they went to the verification section.

lesson placement why there
cp -a of a worktree gives zero git isolation 4th sub-bullet under "a worktree isolates a working DIRECTORY only" It is that rule in a new shape. The frame, the "list is not closed" clause and the silent-failure framing are all reused — cost was 394 B, its own text only.
A guard on prose is walkable by rewording extends "A guard can be SPELLED rather than STRUCTURAL" Same question ("can it pass while the hazard exists in a different shape?"), new artifact type. When the thing under test is a sentence, the existing remedy ("assert the STATE — id plus attribute, a role") has no referent, so the reader is left with no move. The new one: pin the whole normalised string.
A fixture whose value equals the constant it tests extends "pick fixtures whose fields are pairwise distinct" in the mutation bullet Same collision, different pair — fixture vs constant, not field vs field. The existing clause is strictly narrower: a fixture with pairwise-distinct fields can still have one equal to the constant under test.

The last two reuse the → archive: anchor already on their bullet, so neither added a tag. Only the new sub-bullet needed one (worktree-copy-git).

Full evidence for all three is in RULES-ARCHIVE.md (no ceiling, not auto-loaded): the .git-is-a-FILE mechanism and the commit that landed on a real branch; the three prose walks with the exact strings that walked them; the three fixture-equals-constant instances including the one introduced inside the commit that fixed the previous one.

Paying the 202 B — without narrowing anything

The three additions overshot the budget by 202 B. What was reclaimed, and the test applied to each (can the shortened rule pass while the hazard exists in a shape the original covered?):

  • The stash section stated "for ANY reason" three times — the heading, a 🔴 clause, and a trailing "regardless of why". The third was dropped; the heading and the 🔴 clause (The prohibition is NOT scoped to rebases, and applies for ANY reason, plus "a narrower earlier wording is exactly how it failed") are kept verbatim. The consequence clause ("a concurrent agent or session can pop your stash") was moved, not deleted. This is the one rule whose narrowing is the documented origin incident, so it got the strictest check.
  • The pkill bullet's incident numbers (~15 PIDs, 0 files collected and exit 144) moved to sibling-agent-kill — which already held them verbatim and was already tagged on that bullet. The hazard shape survives in the core: a box-wide pattern destroys a sibling's run, and the result reads exactly like a code defect.
  • Two sentences of narrative trimmed from the new additions themselves.

🔴 What was deliberately NOT touched: the clause saying /proc/<pid>/cwd cannot separate two agents that both sit in the base clone. PR #447 trimmed exactly that and re-opened the original incident. It is now named in the test module's comment so the next person shaving that bullet knows which sentence is load-bearing.

Verification

Gatenix build .#checks.x86_64-linux.pytests -L --no-link, read by content:

PASS  scripts/tests  (collected=4119 passed=4119 skipped=0 floor=3970)
TOTAL collected=9919  passed=9918  skipped=1  failed=0  (floor: 9311)
RESULT: PASS (exit=0)

scripts/tests (which holds test_rules_size.py) is confirmed collected, so the target ran rather than being silently absent. No panic: test timed out.

Negative controls — all 5 test functions, 7 controls, each red with its own message, all green again after restore:

control fires message
ceiling forced below size under_hard_ceiling OVER BY: 1 bytes
headroom floor above free space keeps_working_headroom RECLAIM / free: 952 (minimum required: 953)
RULES_MD → missing path rules_md_exists not found -- the size gate below would be vacuous
ARCHIVE_MD → missing path archive_exists_and_has_anchors RULES.md's eviction target is gone
archive present but anchorless archive_exists_and_has_anchors has no ## <anchor> sections
playbook stops deriving its list archive_exists_and_has_anchors the eviction playbook omits existing archive anchors [...]
bogus → archive: tag injected every_archive_pointer_resolves points at archive anchors that do not exist: ['no-such-anchor']

The last one doubles as the positive control for the pointer test: it can observe a dangling anchor, so its green on the real file means something.

Anchors resolve both directions — 0 dangling refs; 0 archive sections unreferenced (excluding retired-*); 0 TOC drift; 0 duplicate refs.

Cold read — the check no test performs

Each changed bullet was re-read as someone who will never open the archive:

  • cp -a sub-bullet — mechanism (.git is a FILE), consequence (commit lands on the REAL branch), trigger (the SESSION surface tells you to make such copies), and fix (rm -f <copy>/.git) are all present. Reads correctly against the frame.
  • prose-guard — three walk mechanisms still named (static prose satisfying a computed-slot check; rewording; synonym). Remedy and its cost both stated, so a reader does not reject the fix.
  • fixture-equals-constant — imperative plus a mechanical control that needs no imagining of the mutant.
  • stash — every scope-bearing clause verbatim; only the third utterance of one qualifier gone.
  • pkill — the docs(rules): two multi-agent lessons that never landed, recovered from a merged branch #447 clause intact; only incident numbers moved.

🔴 This caught the one real regression. run a SINGLE agent in-place — never two file-modifying ones had been shortened to never two, which reads as forbidding a second read-only agent that the previous sentence explicitly permits. 20 B restored. No test would have caught it, and it is the reason the cold read is a required step rather than a nicety.

Not done

Not merged, not deployed. home-manager switch / ship.sh still required for this to reach either host.

ZacxDev and others added 2 commits August 14, 2026 21:35
…d for without narrowing one (#193)

The consolidation half of #193 already landed as #458 (five worktree bullets
became three). What was left was the harder half: fold three lessons measured
2026-08-14 into that cluster without a ceiling bump.

All three attach to bullets that already exist, because that is where a reader
already is when the hazard fires:

- `cp -a` of a worktree gives ZERO git isolation — a worktree's `.git` is a FILE
  holding `gitdir: …`, so the copy shares the ORIGINAL's git dir, index, refs and
  reflog, and a `git commit` inside it lands on the real branch. This is the
  fourth surface under "a worktree isolates a working DIRECTORY only", and it
  cost 394 B — its own text only, reusing the frame. It also sharpens the SESSION
  surface, whose own advice ("restore from `cp -a`") is what tells an agent to
  make these copies.
- A guard on PROSE is walkable by rewording — extends "SPELLED rather than
  STRUCTURAL" (same question, new artifact type: when the thing under test IS a
  sentence, "assert the STATE" has no referent, so pin the whole normalised
  string).
- A fixture whose value EQUALS the constant it tests — extends "pick fixtures
  whose fields are pairwise distinct" in the mutation bullet (same collision,
  different pair: fixture vs constant, not field vs field).

The last two reuse the archive anchor already on their bullet, so neither added a
`→ archive:` tag. Evidence for all three is in RULES-ARCHIVE.md.

The additions overshot the budget by 202 B, reclaimed without narrowing anything:
the stash section stated "for ANY reason" three times, so the third was dropped
and the other two kept verbatim; and the pkill bullet's incident numbers moved to
`sibling-agent-kill`, which already held them verbatim. The clause saying
`/proc/<pid>/cwd` cannot separate two agents that both sit in the base clone was
NOT touched — PR #447 trimmed exactly that and re-opened the incident.

Numbers are owned by scripts/tests/test_rules_size.py; its comment ledger records
this pass, and the 2026-08-13 entry's explicitly-unmeasured prediction (that a
fourth hazard would attach for the cost of its own text) is now measured at one
instance.

The cold read caught the only regression: "never two" had been shortened from
"never two file-modifying ones" and read as forbidding a second read-only agent
that the previous sentence permits. No test performs that check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ring under-reported the one bullet this PR shortened

Audit findings on this PR. Both are claims in the gate's OWN source — the file a
future author reads to decide what is safe to trim — and both cost zero
`RULES.md` bytes, which is the point: the gated file is untouched.

🔴 THE COMMENT SAID A BULLET WAS UNTOUCHED WHEN IT SHIPPED 18 B SHORTER

It recorded the caught regression ("never two" -> "never two file-modifying
ones", 20 B restored) but not that the shipped wording is the MIDDLE position,
18 B below what was there before. To the next person sizing that bullet up it
read as untouched, which is exactly backwards for the one bullet whose
over-shortening this PR had to catch by cold read. Now states the shipped
wording, why the antecedent still survives (the full form appears earlier in the
same bullet), and that shaving further breaks it.

🔴 "202 B RECLAIMED WITHOUT NARROWING" MISATTRIBUTED ITS OWN SOURCES

An audit measured it: only **133 B** came out of existing rules (stash -89,
pkill -26, worktree -18). The remaining ~69 B came from trimming the three NEW
additions. The comment named only the two existing-rule sources, so it read as
though the whole 202 B came from prose already in the file — making
"reclaim without narrowing" look about 50% cheaper as a recipe than it is.

## The other direction of the anchor check was asserted in prose and gated nowhere

This module claimed anchors "resolve both directions" while only computing
`referenced - anchors`. The inverse — an archive section nothing points at — is
the same rot one step over, and this module's own `_archive_anchors` docstring
already argues the case: *"a hand-maintained list drifts, and a drifted list
steers a maintainer into duplicating an entry that already has a home."* An
orphan is how that happens: the evidence exists, nothing routes to it, so the
next author writes it again in the core, where bytes are the scarce thing.

⚠ **Labelled as an INVARIANT GUARD, not counted as regression coverage.** It was
green the moment it was written (0 orphans), so it has never caught the bug it
describes. Watched to fail rather than assumed:

- inject `## zzz-orphan-control` that nothing references -> RED with its own
  message, at its own assertion;
- rename the same section `retired-zzz-orphan-control` -> GREEN again.

The second is the control that matters: it proves the `retired-*` exclusion is
live rather than decorative. A prefix exclusion nobody exercises is how a guard
quietly stops covering the case it was scoped around.

Verified: `RULES.md` and `RULES-ARCHIVE.md` are byte-identical to the parent
commit — this spends none of the 32 B of slack the PR lands on.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ZacxDev
ZacxDev merged commit 3751e83 into main Aug 15, 2026
@ZacxDev
ZacxDev deleted the docs/rules-worktree-consolidation branch August 15, 2026 02:58
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.

1 participant