Repository navigation
docs(attachment): state the real termination argument for the defuse loop - #4372
Conversation
|
👋 Some commits in this PR are not signed and verified by GitHub. Please sign your commits with a GPG or SSH key registered in your GitHub account, then force-push. Commits that are not verified: See GitHub's guide on signing commits for setup instructions. I've added |
…loop maxDefusePasses justified its bound with an argument that is measurably false: replacing a delimiter with the placeholder grows the body, because the placeholder is 42 bytes and </document-x> is 13. The claim that one pass can leave a residue is wrong too, since envelopeTagRe stops at the first '>' and so consumes a nested delimiter in the same pass. Termination actually rests on the replacement text containing no '<': a replacement can never introduce a delimiter start, while every match consumes at least one '<', so each changing pass strictly reduces the body's '<' count. Record that, since the loop returns silently when the bound is exhausted and the placeholder's character set is therefore load-bearing. Comment-only change; no behaviour change. Signed-off-by: PerryLink <255665900+PerryLink@users.noreply.github.com>
386a0b5 to
50dda3c
Compare
|
Confirming this is resolved: the branch now carries a signed commit — GitHub reports the head commit as Sorry for the silence on it. Nothing further needed from this end unless you would like the branch rebased onto the current base. |
A merge landed after the last round was written: docker/docker-agent#4372, merged 2026-10-05T12:14:03Z by maintainer aheritier. That is the whole of the movement - the contributor set goes 43 -> 44 repositories and 317 -> 318 merges, the merged total 350 -> 351 across 45 -> 46 repositories, open proposals 94 -> 102 across 56 -> 64, and the star table 20 -> 21 rows with Docker joining as the seventh company or jointly-governed organization. laya#943 also opened, so the laya line reads 46 merged of 50 opened, 1 open and 3 closed unmerged rather than 0 open. All twenty star counts re-measured.
Fixes #4054.
maxDefusePassesjustified its bound with an argument that is measurably false, and the issue is right about that. While correcting it I found the argument wrong in a third way the issue does not mention, so this records the real invariant instead of a patched-up version of the old one.What was wrong
</document-x>is 13, so defusing grows the body. Measured:13 -> 42, and26 -> 43.envelopeTagReruns to the first>, so</TAG</TAG>>is a single match and any nested delimiter is consumed with it. One pass is always sufficient.117 -> 50 (shrank)for many delimiters. I measured</document-x>× 9 (117 bytes) as117 -> 378 (grew). Shrinking happens when a match span is longer than 42 bytes, not when there are many delimiters.What actually holds
Termination rests on one property of the replacement text:
delimiterPlaceholdercontains no<. A replacement can therefore never introduce a delimiter start, while every match consumes at least one<. Each changing pass strictly reduces the body's<count, which is a non-negative integer — so the loop cannot run forever.I verified "one pass is always enough" rather than asserting it: brute-forced 846,383 bodies (all
{<,>}strings up to length 14, plus token-alphabet enumeration to depth 5). WithmaxPasses=1, zero delimiters survived and the<count never increased.The placeholder's character set is worth recording as load-bearing rather than cosmetic: the loop returns whatever it has once the bound is exhausted, silently and with no error, so a placeholder that gained an angle bracket (say
<removed>) could let a live delimiter through inside the envelope.Also
envelope_test.go:95's comment repeated the same false premise, so it is corrected too. The assertion itself is correct and unchanged — a nested delimiter must genuinely leave no residue, whether it is neutralised in the matching pass or a later one.Scope
Comment-only, 2 files, +23/−9. Verified no code line changes: every added/removed line is a
//comment.task test(go test ./...) has unrelated failures inpkg/rag/treesitter(needsCGO_ENABLED=1) andpkg/workspacemedia(Windows symlink privilege); both reproduce with my changes stashed.