Skip to content

backlog: close #339's stale OPEN item, correct #197's banner, file #346 - #148

Merged
wshallwshall merged 2 commits into
mainfrom
claude/sandbox-codec-handoff-2243ae
Aug 2, 2026
Merged

backlog: close #339's stale OPEN item, correct #197's banner, file #346#148
wshallwshall merged 2 commits into
mainfrom
claude/sandbox-codec-handoff-2243ae

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Ledger tail for PR #136 (55bbafb1, the ADR 0087 sandbox codec fix). Docs only — one file, +22/-2.

What this corrects

1. #339's OPEN item 2 asserted something false about its own PR. It read "The edit was NOT made" about docs/adr/README.md:121. That edit was made — 08d898bc, in PR #136 itself, once claude/adr-asvs-scorecard-as-data merged (ADR 0156, PR #120) and the worktree guard released.

Corrected rather than deleted: the sentence stood for the life of the branch and at least four sessions read it in that state. The record should show what happened, not merely end up right.

2. #197's banner carried the last surviving copy of a false closure claim"Closes the WP-L3-17 (ASVS 15.2.5) residual". Two independent reasons it is wrong, both checked against code rather than inferred from the ADR:

  • DEFAULT_FORBIDDEN_MODULES blocks socket/ssl/asyncio/multiprocessing and the secret-bearing packages but not os/subprocess — a sandboxed Handler still reaches host command execution. Confinement is address-space only.
  • Until #339 the IPC pipe pickled the child's return value and the engine parent deserialized it, so the boundary was bypassable outright by any Handler with a custom __reduce__.

The other copies were fixed by 08d898bc (ADR README) and in the private vault (THREAT-MODEL.md 15.1.5, ASVS-L3-REMEDIATION-PLAN.md WP-L3-17, the risk register 1f). The banner also gains _sandbox_codec.py, which it did not name.

3. #346 filed — the sandbox import boundary is enforced only at runtime, under an off-by-default flag.

A type the child must construct or receive cannot live under a DEFAULT_FORBIDDEN_MODULES prefix. CapturedResponse violated that and made mode=subprocess + ADR 0013 loopback re-ingress DOA until #339 relocated it to config/response.py. The only guard runs in the child, at dispatch time, and only under mode=subprocess.

So a re-violation gives a green suite, a byte-identical mode=off, and breakage only for installs that enabled the sandbox for security reasons — it fails selectively against the population least able to report it.

Number allocated via scripts/coord/alloc.ps1, never grepped.

Verification

Measured for the item rather than asserted:

  • git grep -l FORBIDDEN_MODULES -- tests/empty. Nothing enforces the rule today.
  • _sandbox_codec.py's imports are all under config/ and parsing/, so the invariant currently holds — this item is about keeping it, not repairing it.

Gate checked by falsification rather than a green run: probing #346's banner to a non-banner line failed backlog_status_check.py at exactly BACKLOG.md:8429, naming item #346. Reverted; 269 items, each declaring exactly one status, exit 0.

Coordination

docs/BACKLOG.md is shared with several in-flight branches. My hunks are #197's banner, #339's item 2, and #346 appended at EOF — disjoint from #344 (ci-margin-correction), #323/#139 (repo-security-review), and #340 (#143/#144). Verified each target string was uniquely addressable before editing.

🤖 Generated with Claude Code

Three ledger corrections trailing PR #136 (55bbafb, the ADR 0087 sandbox codec fix).

1. #339 OPEN item 2 said "The edit was NOT made" about docs/adr/README.md:121.
   08d898b MADE it, in that same PR, once claude/adr-asvs-scorecard-as-data merged
   (ADR 0156, PR #120) and the worktree guard released. The item is CORRECTED rather
   than deleted: it read "was NOT made" for the life of the branch and at least four
   sessions saw it in that state, so the record should show what happened, not just
   end up right.

2. #197's banner still claimed "Closes the WP-L3-17 (ASVS 15.2.5) residual". That was
   the LAST copy of the claim in this file - README.md:121 was fixed by 08d898b and
   the private ASVS-L3-REMEDIATION-PLAN / THREAT-MODEL rows in the vault. Two reasons
   it is wrong, both verified against the code rather than inferred from the ADR:
     (a) DEFAULT_FORBIDDEN_MODULES blocks socket/ssl/asyncio/multiprocessing and the
         secret-bearing packages but NOT os/subprocess, so a sandboxed Handler still
         reaches host command execution - confinement is address-space only;
     (b) until #339 the pipe pickled the child's return and the ENGINE PARENT
         deserialized it, so the boundary was bypassable outright.
   Banner also gains _sandbox_codec.py, which it did not name.

3. #346 filed - the sandbox import boundary is enforced only at runtime, under an
   off-by-default flag. A type the child must construct or receive cannot live under a
   DEFAULT_FORBIDDEN_MODULES prefix; CapturedResponse violated that and made
   mode=subprocess + ADR 0013 loopback re-ingress DOA until #339 relocated it. The
   guard runs in the child, at dispatch time, only under mode=subprocess - so a
   re-violation gives a green suite, a byte-identical mode=off, and breakage ONLY for
   installs that enabled the sandbox for security reasons. It fails selectively against
   the population least able to report it.

   Number allocated via scripts/coord/alloc.ps1, never grepped.

   Measured for the item rather than asserted: `git grep -l FORBIDDEN_MODULES -- tests/`
   is EMPTY, and _sandbox_codec.py's imports are today all under config/ and parsing/,
   so the invariant currently HOLDS - this is about keeping it, not repairing it.

Verified by falsification, not by a green run: probing #346's banner to a non-banner
line failed the checker at exactly BACKLOG.md:8429 naming item #346, so the gate
demonstrably sees this item. Reverted; 269 items, each declaring exactly one status,
exit 0.
#141 (BACKLOG #345) landed while #148 was in CI. Both PRs append a new item at EOF
after #343, so this conflicted on exactly one hunk - the predicted collision, not a
surprise. gh pr update-branch CANNOT resolve it; it fails and leaves the PR DIRTY.

Resolution: TAKE BOTH. #346 and #345 are independent OPEN items appended at the same
point, so their relative order carries no meaning (this file has not been numerically
ordered since #340 - the tail reads 340, 344, 339, 341, 342, 343). Restored the `---`
separator the conflict markers had displaced.

Verified by measurement rather than by eyeballing whether the markers were gone:
  - conflict markers remaining: 0
  - backlog_status_check.py: 270 items, each with exactly one status banner
    (269 before + #345 - the count I predicted BEFORE resolving, which is what makes
    it a check rather than a description)
  - `git diff origin/main -- docs/BACKLOG.md` = exactly 3 hunks, all mine:
    #197's banner, #339's OPEN item 2, and #346 appended
  - #345's block diffed byte-identical against origin/main - nothing of #141's lost
  - CRLF preserved, 0 bare LF

Coordination: the resolving edit was blocked by the collision gate while the #347
session held this file dirty mid-rebase. Waited for it to commit rather than
overriding the gate or rewriting the file with a shell command - routing around a
guard through a tool it does not hook is overriding it with extra steps.
@wshallwshall
wshallwshall merged commit dc0da09 into main Aug 2, 2026
31 checks passed
@wshallwshall
wshallwshall deleted the claude/sandbox-codec-handoff-2243ae branch August 2, 2026 15:57
wshallwshall added a commit that referenced this pull request Aug 2, 2026
…re it is trusted

The item told an implementer HOW to fix the assertion but not how to know the fix
works. Shipping the replacement on an unfalsified green would reproduce the defect
inside the remedy -- a green taken as evidence for a property it cannot see is the
whole item.

So the fix direction now closes by requiring the deliberate break: hand the store
an IdentityCipher or plant a plaintext body, watch the rewritten test go RED, then
restore.

With the trap that makes it more than a formality, from the session that settled
#344's instance 2 today: proving the INSTRUMENT can fire is only half -- the
WORKLOAD must also be able to produce the failure class. Their 800-iteration repro
loop returned 800/800 green against a live SQL Server while hunting a lock-
contention bug, because running the two tests in isolation was the one
configuration that could not generate contention. They had falsified the probe and
not the rig, which felt like all of it. A rig that excludes the condition it hunts
reports silence, and silence reads like evidence.

Merged origin/main first (PR #148 / BACKLOG #346 landed): clean auto-merge, no
conflict this time, verified by CONTENT and not only by count -- 271 items, #345,
#346 and #347 all present, and all five of #347's late revisions still resolving in
the merged file.
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