Bug-hunt round 7: guard quoting, redaction case-fold, site-generator and scaffold fixes - #439
Conversation
The tokenizer implemented single, double and backslash quoting but not bash's $'...' (ANSI-C) or $"..." (locale) forms, so the leading $ fell through to the default word branch and prefixed the token: $'--force' tokenised to $--force. A Tier-1 blocker naming --force (or rm -rf, or --no-verify) then missed while bash handed the child byte-identical argv, contradicting the doc.go invariant that quoting affects tokenisation, not argument semantics. ANSI-C escapes are decoded so an encoded spelling ($'\x2d\x2dforce') resolves to the same bytes. Assisted-by: Claude:claude-fable-5
The hard_fail local_username matcher was built without the (?i) its home-path sibling carries, though HomeUser is the last segment of that same home path. On a case-folding filesystem a case variant of the caller login (the natural prose spelling in a transcript) then resolved to the same account but was neither redacted nor caught by the blocking residual scan, leaking the login into the stored transcript. The system-directory exemption is lower-cased so the iss-31 suppression still holds under folding, and the encoded matcher folds with EqualFold. Assisted-by: Claude:claude-fable-5
- checkInlinableSVG refuses an XML prolog, comment and CDATA section: all three are inlined verbatim and the emitted-page reader refuses them, so a normal exporter SVG made the build pass and the check refuse a page whose message named no asset. - A page that fails to parse now denies every page-walking gate a pass rather than dropping out of their lists and letting them print ok, which had masked a genuine finding behind the parse fault. - LoadRepoMeta screens the repository address for an executable scheme like the bibliography URLs are, so a javascript: address (or a scheme-less typo) fails the build instead of shipping an href on every page. - BuildRecordExport refuses a frontmatter-free store id that collides with a typed record id rather than silently overwriting it in the export. - isolatedGit sets core.quotePath=false so the history walk reads non-ASCII paths verbatim, not the C-quoted form that left a record undated. Assisted-by: Claude:claude-fable-5
Two adopter-facing scaffold defects: - classify folded a symlinked target leaf into the path-free non-regular reason: ReadGuarded fails a symlink with ELOOP, not ErrNotRegular, so the symlink case named first in the contract fell through and embedded a raw absolute path in the dry-run report and its --json success envelope. - The race leg hardcoded go test -race ./internal/... outside the .Abcd guard, so a bare adopter module with no internal tree failed every release verify run and wedged the release. The bare profile now runs the race leg over the whole module; the abcd rendering is unchanged. Assisted-by: Claude:claude-fable-5
capture list/status --json emitted skipped[].error carrying a raw absolute path beside the deliberately-relativised skipped[].path, in an exit-0 success envelope the CLI error-path scrubber never sees. relativiseLedgerPaths now scrubs the error string at the same choke point as the path field. Assisted-by: Claude:claude-fable-5
site-src/ (including install.sh.tmpl, the byte source of the served /install.sh) and docs/requirements.txt (the pip input to the deployed site build) were outside CODEOWNERS, so a PR confined to them merged with no required code-owner review while shipping the install script to users. Assisted-by: Claude:claude-fable-5
…icks - The shipped abcd site check was still called a design target in 04-surfaces/README.md and 05-internals/10-site.md; 22-site.md is now pinned in the release-gate manifest (checkerCount 28) so Direction A reads the site chapter. - commands/site.md and brief 22-site.md named an exhaustive site-build read set that omitted record.js, install.sh.tmpl, CONTRIBUTING.md and ACKNOWLEDGEMENTS.md, and an output list missing install.sh and record.js. - The writing-style Escapes section overclaimed the docs-lint: allow line (only the banned-token families honour it) and its surface table omitted the names/* family. - 03-invariants.md declared PLACEHOLDER over fourteen live invariants; brief/README.md still called the evidence chapter placeholders; 00-meta.md named one home for open questions while nine live inline. - install.md dropped a planned-Windows sentence; ahoy.md's dry-run --json wording; the --no-color help string is US-English (reference regenerated). Assisted-by: Claude:claude-fable-5
Ledger records for the round: fifteen findings captured and resolved with their fixing commits, and the guard brace-expansion bypass recorded open as a scoped follow-up. CHANGELOG and DECISIONS updated for the round. Assisted-by: Claude:claude-fable-5
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
abcd | 0778f56 | Aug 23 2026, 01:08 AM |
The $'...' decoder handled \x and octal but not bash's \uHHHH / \UHHHHHHHH unicode escapes (nor \cX control), so $'\u002d\u002dforce' still decoded to --force in the shell while the guard read the literal bytes and allowed the Tier-1 block — the same encoded-hazard class the \x form closes, and the one the CHANGELOG claims is covered. All three encodings now decode to the same bytes bash produces. Assisted-by: Claude:claude-fable-5
Merge gate — CI green, dual review SHIP after remediationCI status on the final head Two independent adversarial pre-merge reviews of the full diff (one Claude Opus 5, one Claude Fable 5):
Auto-merge is not authorised: leaving this open for a human to merge. Assisted-by: Claude:claude-fable-5 Generated by Claude Code |
The two site brief chapters conflicted where round 7's corrections met main's newer website-ships rewrites (#440, #432): main's text supersedes the round's fixes in every conflicted hunk and wins each one, while the round's inputs-table rows in the surfaces chapter (record.js, install.sh.tmpl, the credit sources) stay — main had not updated that table. Preflight and gofmt green on the merged tree. Assisted-by: Claude:claude-fable-5
Merge gate resumed — conflict cleared, CI green, dual re-review SHIPMain moved after the first merge-gate pass (#440, #441, #432), leaving this PR conflicted in the two site brief chapters. Merge commit CI on Two independent adversarial re-reviews of the full diff (one Claude Opus 5, one Claude Fable 5): both SHIP. Both proved the merge lossless mechanically — the two-dot and three-dot diffs against The PR was merged by the maintainer while the re-verification ran; Assisted-by: Claude:claude-fable-5 Generated by Claude Code |
Autonomous all-dimensions bug-hunt, round 7. Five parallel hunt dimensions (code, docs-vs-functionality, infrastructure, internal-record consistency, hardened-primitive sibling sweep), every candidate adversarially refuted before fixing, every behaviour change pinned by a test watched fail before the change and pass after. Baseline (
make preflight+gofmt -l .) green before any change and on the final tree.Fixed — substantive (11)
Security / code
internal/core/guard/tokenize.go. The tokenizer implemented single/double/backslash quoting but not$'...'/$"...", so$'--force'tokenised to$--forceand a Tier-1 blocker missed while bash handed the child byte-identical argv — contradicting thedoc.goinvariant that quoting affects tokenisation, not argument semantics. ANSI-C escapes are decoded so$'\x2d\x2dforce'resolves too. (iss-2608221456463223)local_usernameredaction case-fold miss —internal/adapter/scanner/identity.go:165. The hard-fail matcher for the caller's own login lacked the(?i)its home-path sibling carries, so a case variant of the login survived redaction and the blocking residual scan into the stored transcript. The system-dir exemption is lower-cased so iss-31 stays closed. (iss-2608221456469938)internal/core/site/assets.go. An XML prolog/comment/CDATA was inlined verbatim but the emitted-page reader refuses all three, so a normal exporter SVG made the build pass and the check refuse a page whose message named no asset. (iss-2608221456462677)internal/core/site/check.go:411. A page that failed to parse dropped out of the page-walking gates, which then printedokfor a page they never examined. (iss-2608221456469558)hrefscheme —internal/core/site/build.goLoadRepoMeta..claude-plugin/plugin.json'srepositoryreached anhrefon every page with noexecutableSchemecheck; ajavascript:address (or scheme-less typo) passed every gate. (iss-2608221456466438)./internal/...race leg —internal/core/launch/scaffold/scaffold.go,templates/release.yml.tmpl. A symlinked target leaf (ELOOP, notErrNotRegular) leaked an absolute path into the--dry-run --json; and the hardcodedgo test -race ./internal/...wedged every release of a bare adopter with nointernal/tree. (iss-2608221456599559, iss-2608221456597173)skipped[].errorabsolute-path leak —internal/core/capture/workflow.go. Scrubbed at the same choke point asskipped[].path. (iss-2608221456599229).github/CODEOWNERS.site-src/(incl.install.sh.tmpl, the byte source of the served/install.sh) anddocs/requirements.txtnow require code-owner review. (iss-2608221456593173)Docs / record
docs/reference/writing-style.md. Thedocs-lint: allowline is honoured only by the banned-token families;links_resolve/stray_root_docs/citation_*ignore it. Also added the shippednames/*row. (iss-2608221456593814)commands/site.md, brief22-site.md. The exhaustive read/write set omittedrecord.js,install.sh.tmpl,CONTRIBUTING.md,ACKNOWLEDGEMENTS.md,install.sh. (iss-2608221457125132)abcd site checkstill called a design target —04-surfaces/README.md,05-internals/10-site.md, and unpinned inrelease-gate/manifest.json(now pinned, checkerCount 28). (iss-2608221457122761)Fixed — nitpick (4)
record.json; the history walk setscore.quotePath=falseso a non-ASCII record path keeps its dates (iss-2608221457123924).03-invariants.mdPLACEHOLDER banner over fourteen live invariants → LIVE;brief/README.mdevidence-chapter "placeholders" → live (iss-2608221457127152, iss-2608221457128333).00-meta.mdopen-questions home clause reconciled with the deliberate inline-notes design;install.mdplanned-Windows sentence;ahoy.mddry-run--jsonwording; the--no-colorhelp string is US-English (reference regenerated).Recorded, not fixed (stays open)
{--force,}expands to byte-identical argv yet the guard reads the literal token and allows it. Distinct from the$'...'gap (expansion, not quoting; breaks no written invariant); a correct bounded brace-expander is larger than this round's scope. (iss-2608221457227161)Considered and rejected / refuted
commands/site.md"runs in CI" claim for the overflow audit — in-flight PR ci: screenshot audit fails on rendered overflow at phone and desktop widths #436 adds exactly that workflow; touching the line now would invert on merge.--proto) and-qdeltas vshooks/bootstrap.sh— downgraded to nitpick / defence-in-depth: the pin closes no reachable path (the attacker who can inject a downgrade already holds a trusted cert; GitHub never redirects to http), and the.curlrc/proxy attacker already has code execution.iss-315guard-warn citation (the record does not disclaim the design target); the CIrecord-lintjob name (prior art iss-304); theprepare-this-repotemplate path (prior art iss-87).Model routing: orchestration on Claude Fable 5; five parallel hunters and the per-finding adversarial refuters on Claude Opus 5. The dual pre-merge review (one Opus 5, one Fable 5) and CI status will be posted as a PR comment.
Round 7 — findings: 11 substantive, 4 nitpick, plus 1 recorded-open and several refuted.
Assisted-by: Claude:claude-fable-5