Skip to content

docs(backlog): file the three worktree_gate residuals PR 777 disclosed (BACKLOG #1427) - #797

Merged
wshallwshall merged 4 commits into
mainfrom
worktree-agent-aa281c55ec750948c
Sep 4, 2026
Merged

docs(backlog): file the three worktree_gate residuals PR 777 disclosed (BACKLOG #1427)#797
wshallwshall merged 4 commits into
mainfrom
worktree-agent-aa281c55ec750948c

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

What this is

A filing, not a fix. PR 777 closed BACKLOG #1229 and listed three residual fail-opens in the span
scanner of scripts/hooks/worktree_gate.ps1 under "Residuals, named so the closure is not
over-read"
. They were correctly ruled outside #1229's scope, and they existed only in a pull-request
body -- the one place nobody reads later. This gives them a durable ledger row at BACKLOG #1427.

No code changes. One file, 124 insertions, all in docs/BACKLOG.md.

I allocated my own number, from this worktree

pwsh -NoProfile -File scripts\coord\alloc.ps1 -Kind backlog -Title "..." issued #1427, claimed
by .claude/worktrees/agent-aa281c55ec750948c. The pre-commit ledger gate passed, which is the
check that a number allocated elsewhere would have failed.

The title I allocated is not the title I was handed. The brief's title asserted "twelve shapes
inherited from main". I could not confirm twelve (below), so filing a title that my own row then
refuses would be the defect this ledger keeps recording. The allocated title says "a class of shapes
inherited from main".

I did not take the three on report. Each was driven.

Measured 2026-09-03 against gate blob b194d0a0, which is byte-identical to origin/main at
46ea10a78 -- so "inherited from main" needed no second blob and no cross-branch comparison.

Two instruments per shape:

  1. VERDICT -- the real hook as a subprocess, a real PreToolUse payload on stdin, ALLOW or DENY.
    Same harness contract as tests/test_worktree_gate.py's run_gate.
  2. MARKER -- the shipped Get-ScannableSegments over the same shape with an inert marker in
    place of the gated command, reporting whether the marker was present in the INPUT before
    asking whether it survived, so a deletion cannot be an artifact of a missing marker. Functions
    AST-extracted from the real file, the technique tests/test_worktree_gate_emitter.py already
    uses, never pasted.

No git command was executed at any point. The gate only parses a JSON tool payload.

The positive controls, in the same batches

control expect verdict marker
plain gated command DENY DENY survives
bash -c payload DENY DENY survives
sh -c payload DENY DENY survives
python -c payload DENY DENY survives
unterminated quote -- the fail-CLOSED case DENY DENY survives
lowercase quoted git.exe program spelling DENY DENY token survives
quoted commit message -- FALSE-POSITIVE control ALLOW ALLOW BLANKED

The last row is what makes a BLANKED reading mean anything, and the six DENY rows are what make this
not a scanner that fires on any input.

One instrument correction, recorded because it read as a clean result

My first marker was a single bare word, and it reported SURVIVES for shapes whose whole mechanism is
blanking. Cause: the #1069 carve-out deliberately emits a quoted span holding one bare word
rather than blanking it, and its discriminator is whitespace. A single-word marker therefore cannot
measure blanking anywhere. Every marker in the final run carries whitespace. Recorded because the
false reading agreed with no hypothesis and still looked like evidence.

What reproduced

Shape 1 -- the uppercase quoted PROGRAM spelling. REPRODUCED.

spelling in the quoted program slot verdict program token after blanking
GIT.EXE ALLOW BLANKED
Git ALLOW BLANKED
Git.exe ALLOW BLANKED
git.exe -- control, identical slot DENY survives

The discriminator is the CASE alone, exactly as reported.

Shape 2 -- an unknown interpreter's -c payload. REPRODUCED.

program before -c verdict payload after blanking
myrunner ALLOW BLANKED
mysh ALLOW BLANKED
runner.exe ALLOW BLANKED
mybash.exe ALLOW BLANKED
bash / sh / python -- controls, identical slot DENY survives, as its own scan segment

The discriminator is the program NAME alone.

Shape 3 -- the class reproduces. THE COUNT OF TWELVE DOES NOT.

Eighteen spellings constructed across the seven named categories. Twelve allowed:

category driven allowed
command substitution 2 1 (only inside a quoted span)
backticks 2 1 (same asymmetry)
ANSI-C quoting 2 2
concatenated quoting 3 3
bare program names / missed interpreter flags 5 5
heredocs 5 0
the per-line split 6 0

Twelve of eighteen allowed, and I still refuse the number. Four reasons, and any one is enough:

  1. Two of the seven named categories produced no hole at all. Heredocs and the per-line split got
    eleven distinct spellings between two passes and every one DENIED -- except a heredoc that WRITES
    a governed file, and that ALLOW is the shell-write blind spot the gate's own .SYNOPSIS already
    discloses, which would allow with or without a heredoc. The gate's own docstring agrees that a
    quoted argument spanning lines denies today. So my twelve contains no member of two categories the
    reported twelve is said to span. Different sets.
  2. At least two of my twelve are doubtful as holes. ssh <host> "<gated>" executes on the remote
    host, and the gate's own docstring names that shape as one that MUST keep allowing; a bare ANSI-C
    word is not a git invocation at all.
  3. I measured verdicts, not executability. #1229 and PR 777 both held themselves to driving the
    real binary with a payload that COMPUTES. I did not, for any shape-3 spelling.
  4. The enumeration is recorded nowhere. A tree-wide search finds no file listing the twelve
    individually, and the "lens" PR 777 cites left no artifact (scripts/quality/lens_coverage.py is
    the IDE action lens, an unrelated subject).

Instrument named, as the brief requires: the two probes above, driven from a scratchpad script.
The row cites the in-repo harnesses by path so the measurement is re-runnable without it.

So the row says: at least five of the seven named categories carry at least one allowing spelling,
and the count of twelve is unconfirmed.

A hazard found while measuring: there are TWO different twelves here

worktree_gate.ps1 records a measured twelve FALSE DENIES that a case-insensitive program emit
would cost. The suite records a twelve inherited FAIL-OPENS. They point in opposite directions and
attach to adjacent parts of the same file. The row records this so nobody fuses them.

What the row says a fix must prove

Both directions, because a one-arm test would pass a change that merely moves the hole: the offending
shape must start denying, and every currently-denying control must keep denying -- including the
fail-closed unterminated-quote case by name. The row adds a third arm per shape: the false denies the
current design bought must not come back (the two pinned must-DENY rows and the twelve false denies
for shape 1; the eighteen non-interpreter -c invocations Get-FlagOwner exists to spare for
shape 2).

Not scored

Value and difficulty belong to a scoring pass with its own calibration. Filed pending a score, and
the banner says so.

Checks

check result
scripts/docs/backlog_status_check.py OK -- 658 items, each declaring exactly one status
parse_items on the new row num=1427, 1 OPEN banner, 0 CLOSED, fields=[], duplicate_fields=[], no duplicate item numbers
scripts/docs/backlog_citation_check.py OK, 2 pre-existing advisory warnings, neither mine
scripts/docs/dangling_citation_check.py rc=0 (advisory; it now lists #1422/#1425/#1426, which is this PR recording them)
scripts/docs/citation_line_check.py rc=0
scripts/docs/verdict_divergence_check.py rc=0, 3 pre-existing findings, none mine
scripts/docs/banner_sha_check.py rc=0, 1 pre-existing finding (#1094), not mine
scripts/docs/link_check.py OK -- 4991 relative links resolve
glyph audit on the added lines exactly one non-ASCII character: U+1F522, the machine-parsed OPEN banner. Zero U+26A0, no new glyph vocabulary
pre-commit at commit ledger gate, backlog parses, forbidden-content, control characters, secrets all Passed
ruff / mypy not applicable -- no Python file changed; pre-commit reported "no files to check"

Legs a Builder cannot read. The hosted-runner legs (including windows-service-smoke) report
after my process exits. Someone should read them.

Also in this PR: two ledger holes recorded

The Ledger erratum now records #1422 and #1425 as permanent holes. Both were allocated on
2026-09-03 by a coordinating session on a Builder's behalf, so the claim recorded the
coordinator's worktree and the ledger gate correctly refused the Builder's commit. #1425's subject was
re-filed at #1426. Same cause as #1297, in a variant that does not look like it: the allocating
shell's working directory was not wrong for the session that ran it, it was wrong for the session that
would commit, and that mismatch is invisible at allocation time.

#1422 was NOT already recorded in this file -- the brief said it was. I checked before writing:
#1422 appears nowhere in docs/BACKLOG.md on main. Only #1297 was there. So this records both.

What I did not do

  • I did not fix any of the three. #1229 is closed and a fix is a separate dispatch.
  • I did not install the gate. scripts/worktree/install-gate.ps1 was never run -- #1247 records
    that the installer overwrites the live gate with no backup and no receipt. Everything was driven
    against the repository copy.
  • I did not publish turnkey payloads for the unfixed shape-3 spellings. They are named by
    mechanism, following the standing ruling that a construct is published alongside the fix that makes
    it inert. Shapes 1 and 2 are already published verbatim in this tree, so the row does not withhold
    what the suite and the gate's own comments already carry.
  • I did not apply the reviewed label, did not arm auto-merge, and did not score the item.

Open question for the reviewer

Should shape 3 be one row or three? I filed all three under #1427 because they share one surface,
one instrument and one both-arms test standard. But shape 3 is a class with an unconfirmed census
while shapes 1 and 2 are single measured facts, and they will not be worked together. If you want
shape 3 split out, it needs its own allocation from whichever worktree will commit it -- please do not
allocate it on a Builder's behalf, which is the failure this PR also records.

🤖 Generated with Claude Code

…d (BACKLOG #1427)

PR 777 closed BACKLOG #1229 and listed three residual fail-opens in the span
scanner of scripts/hooks/worktree_gate.ps1. They were correctly ruled outside
that item's scope, and they existed only in a pull-request body. This gives them
a durable ledger row. No code changes.

Each shape was reproduced by driving the shipped hook rather than taken on
report, with positive controls in the same batch that had to DENY. The gate blob
under test is byte-identical to origin/main, so "inherited from main" needed no
second blob.

  Shape 1, the uppercase quoted program spelling: REPRODUCED. GIT.EXE, Git and
  Git.exe all ALLOW with the program token blanked; lowercase git.exe in the
  identical slot DENIES with its token surviving.

  Shape 2, an unknown interpreter's -c payload: REPRODUCED. Four unrecognised
  program names ALLOW with the payload blanked; bash, sh and python in the
  identical slot DENY with the payload surviving as its own scan segment.

  Shape 3, the shapes inherited from main: the CLASS reproduces in five of the
  seven named categories, and the COUNT OF TWELVE IS REFUSED. Twelve of
  eighteen constructed spellings allowed, but that set cannot be the reported
  twelve: heredocs and the per-line split yielded no hole across eleven
  spellings, two members are doubtful, executability was not verified, and the
  original enumeration is recorded nowhere in the tree. The row says so and does
  not carry the number forward.

Seven controls fired, including the fail-closed unterminated-quote case and a
false-positive control proving the scanner really does blank ordinary quoted
prose. One instrument correction is recorded in the row: a single-word marker is
unmasked by the #1069 carve-out and cannot measure blanking anywhere.

The row states what a fix must prove in both directions, because a one-arm test
would pass a change that merely moves the hole, and it prices each shape against
the false denies the current design bought.

Also records in the Ledger erratum that #1422 and #1425 are permanent holes.
Both were allocated by a coordinating session on a Builder's behalf, so the
claim recorded the wrong worktree and the ledger gate correctly refused the
commit. #1425's subject was re-filed at #1426. Same cause as #1297, in a variant
that does not look like it.

Not scored: value and difficulty belong to a scoring pass with its own
calibration. Filed pending a score.

Scope is a local maintainer-workstation guardrail whose own .SYNOPSIS declines
to be a security boundary, with zero deployments, so the row is written in the
conditional throughout. The gate was never installed; #1247 records that the
installer overwrites the live gate with no backup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@wshallwshall wshallwshall added the reviewed A reviewer has read this. Removed automatically when new commits arrive. label Sep 3, 2026
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

CORRECTION FROM THE CONSOLE SEAT, and the error is mine, not this Builder's.

This PR records #1422 and #1425 as PERMANENT HOLES in the Ledger erratum. That is FALSE. Both are still owned and still filable. I told the Builder they were holes and it recorded what I said.

MEASURED, by importing the real module rather than reading it:

spec = importlib.util.spec_from_file_location("ledger_check", "scripts/hooks/ledger_check.py")
mod.Ledger(ci=False).owns("backlog", "<n>")

from compress-claude-md-c78f90, the tree that ALLOCATED them:
owns("backlog","1422") = True
owns("backlog","1425") = True
owns("backlog","999999") = False negative control, fired

So the allocating worktree can still commit against both numbers. Nothing is stranded.

WHAT ACTUALLY HAPPENED, which is not what I told the Builder. The ledger gate refused a SECOND Builder, in a DIFFERENT worktree, a number allocated to mine. That is the two-sessions-one-number collision the gate exists to prevent, and it worked exactly as designed. I read a correct refusal as a broken allocation.

THE REAL DEFECT, and credit for it belongs to a peer Console seat, not to me. The gate's remediation text on refusal says to run alloc.ps1, which issues a NEW number. It never names the recoveries that do work: the allocating worktree can commit directly, and the recorded branch can be adopted by any tree when it is checked out nowhere. So a seat meeting a correct refusal is steered into burning an allocation rather than recovering one. #1428 in the sibling PR 799 was allocated for exactly that reason, which is this defect firing in real time.

WHAT SHOULD CHANGE HERE: the erratum entries for #1422 and #1425 should be withdrawn or rewritten. They are not holes. If anything replaces them, it is the remediation-text defect above, and that belongs to whoever owns the allocator work rather than to this row.

Note that the class is Ledger, at ledger_check.py:168. There is no Checker in that file, despite what several rows and my own briefs have said. Anyone grepping for Checker finds nothing and may wrongly conclude the code moved.

I am not asking this Builder to be resumed for this. I am recording it here so the false claim does not merge unnoticed, and I will carry the fix myself if nobody else does.

Both sides append a new section at the same point in docs/BACKLOG.md, under different
item numbers. Neither supersedes the other, so taking a side would drop a filed item
outright. Both blocks are kept, in the ascending item order the file already uses.

Verified with parse_items from scripts/docs/backlog_status_check.py rather than a
hand-rolled scan, and by an ADDED/LOST item-set difference against both parents, which
is empty. A count alone would not catch two blocks folding into one.
@github-actions github-actions Bot added ci-red A required check went red. Attribute it before retrying. and removed reviewed A reviewer has read this. Removed automatically when new commits arrive. labels Sep 4, 2026
@wshallwshall wshallwshall added the reviewed A reviewer has read this. Removed automatically when new commits arrive. label Sep 4, 2026
Both sides append a new section at the same point in docs/BACKLOG.md, under different
item numbers. Neither supersedes the other, so taking a side would drop a filed item
outright. Both blocks are kept, in the ascending item order the file already uses.

Verified with parse_items from scripts/docs/backlog_status_check.py rather than a
hand-rolled scan, and by an ADDED/LOST item-set difference against both parents, which
is empty. A count alone would not catch two blocks folding into one.
@github-actions github-actions Bot removed the reviewed A reviewer has read this. Removed automatically when new commits arrive. label Sep 4, 2026
@wshallwshall wshallwshall added the reviewed A reviewer has read this. Removed automatically when new commits arrive. label Sep 4, 2026
…55ec750948c

# Conflicts:
#	docs/BACKLOG.md
@github-actions github-actions Bot removed the reviewed A reviewer has read this. Removed automatically when new commits arrive. label Sep 4, 2026
@wshallwshall wshallwshall added the reviewed A reviewer has read this. Removed automatically when new commits arrive. label Sep 4, 2026
@wshallwshall
wshallwshall added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 3c96029 Sep 4, 2026
42 of 43 checks passed
@wshallwshall
wshallwshall deleted the worktree-agent-aa281c55ec750948c branch September 4, 2026 19:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-red A required check went red. Attribute it before retrying. reviewed A reviewer has read this. Removed automatically when new commits arrive.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant