backlog: five more instances for #1000, and the asymmetry rule for its controls - #218
Merged
Merged
Conversation
…s controls
#1000 ("prove each required merge context can fail") was filed 2026-08-03 with
four instances, all found by hand and none by CI. 2026-08-05 produced at least
five more in a single day across three sessions. The rate is the argument: this
is an ongoing yield, not a backlog of historical mistakes.
- a ValidatePattern that did not enforce its own stated shape ("abc"+newline
MATCHES ^[A-Za-z0-9._-]+$, because .NET's $ also matches before a final
newline)
- a test that rendered the broken output and asserted a substring of it, so it
passed for the whole life of the defect it covered
- an exit code that masked the failure being asserted: pwsh -File returns 0
when the script inside died at parameter binding, so every execution
assertion without an explicit `exit $LASTEXITCODE` is vacuously green
- a probe that could not tell "found nothing" from "did not look": a gh call
errored, printed usage, and its EMPTY output was read as "nothing eligible"
while two PRs sat eligible
- a control too uniform to locate the layer doing the work
Also records the design rule the last of those produced, because it is the part
most likely to be skipped by whoever starts #1000: A NEGATIVE CONTROL MUST BE
ASYMMETRIC. It must fail for exactly the shapes its rule covers and KEEP PASSING
for shapes another layer catches, or it cannot say which layer does the work.
Measured: a rule-1b fix believed to cover two ADS spellings had its eight-case
control fail on ONE when reverted -- the ::$DATA forms were already refused by an
extension backstop, so the new code was load-bearing for a single shape. The
first draft of its comment credited it with both, an overstatement in the
direction that flatters one's own code. A control failing on all eight would have
looked stronger, confirmed the overstatement, and taught nothing.
No new number allocated: this strengthens an existing item rather than adding a
sibling. The near-duplicate that was considered and declined is recorded in the
session log -- backlog-hygiene's "passed by not firing" on a PR with no BACKLOG
citation is correct behaviour by that gate, which logs "nothing to enforce" in
plain words, and #1000 already owns the general class.
wshallwshall
enabled auto-merge (squash)
August 5, 2026 23:22
wshallwshall
added a commit
that referenced
this pull request
Aug 6, 2026
PR #214 landed rule 3b's fixes, so main's worktree_gate.ps1 now carries ConvertTo-WorktreeSlug where this branch carries Get-SafeForMessage. Both were inserted immediately after Get-ComparablePath, which is the conflict two sessions predicted in advance and agreed the resolution for. RESOLVED KEEP BOTH. They are additive and independent: ConvertTo-WorktreeSlug maps a verified refname to a legal worktree directory component for rule 3b's remediation; Get-SafeForMessage folds a caller-supplied value before it reaches a deny reason for rules 1a/1b. Neither replaces the other and neither is a revert of the other. Kept in the conflict's own order so main's trailing brace still closes main's function and the diff against main stays minimal. $GateVersion stays 2026.08.05.2 by agreement -- the other session ceded that line rather than re-bump it. VERIFIED ON PRESENCE OF BOTH MARKERS, never on content equality against either branch. A correct keep-both merge matches NEITHER parent byte-for-byte, so an equality check would report failure precisely when the merge succeeded -- a check that cannot fire on success is not a check. Measured on the merged file: ConvertTo-WorktreeSlug 2 occurrences (definition + rule 3b call site) Get-SafeForMessage 3 occurrences (definition + rules 1a and 1b call sites) 0 parse errors, 0 non-ASCII bytes 239 passed across the 9 runnable gate files -- both suites on one file, up from 230 because #214 added nine tests of its own. My 35-case decision probe unchanged at 35/35. backlog_status_check OK at 316 items each declaring exactly one status, zero duplicate numbers, and #1041 still present exactly once and open. docs/BACKLOG.md auto-merged: #218's additions land inside an existing item rather than as new headings, so no heading collided.
wshallwshall
added a commit
that referenced
this pull request
Aug 6, 2026
…lision PRs #222 and #223 landed since the last merge, so docs/BACKLOG.md collided at EOF again: #223 appends #1051-#1055 where this branch appends #1041. One conflicted file, resolved KEEP ALL SIDES, no renumbering and no re-sorting -- the file is not ordered by number and nothing enforces one, so a re-sort would be a large invented diff over a file several branches are appending to concurrently. Resolved here rather than by the coordinator for the same entitlement reason as before: a resolution that RE-INTRODUCES the `## 1041.` heading is a head-minus-base addition, so ledger_check.py consults owns() for it (:340, :355), and the allocation record names this worktree. No other worktree can commit it. THE REVERT CHECK RAN FIRST, because the last merge is what taught me to. This branch carried content main had since changed, and if my side won those lines the merge would silently revert them while the diff looked ordinary. Built the merged tree and read it rather than inferring from a clean-looking diff: headings on main but LOST here NONE headings this branch adds vs main ## 1041. -- exactly one #1032 banner "SHIPPED 2026-08-05 - merged as PR #214" (#222's close survives; my side still carried the pre-#222 banner) #1051-#1055 from #223 5 of 5 present "Lost nothing, gained exactly one" is the check that answers the revert question directly. An item count cannot: it held steady at 121 across the previous merge because #218's additions landed INSIDE item #1000 rather than as new headings. This time it grew 121 -> 126, matching #223's five, which is consistent rather than coincidental. Verified with the repo's own parser, never a hand-rolled scan of this file: zero conflict markers, backlog_status_check OK at 321 items each declaring exactly one status, parse_items reporting zero duplicate numbers, nothing in #1032-#1055 appearing more than once, and #1041 still open -- it lands open by design and is closed by the session building the rule 3d fix. KEEP-BOTH RE-CHECKED ON THE GATE, by AST rather than by grep. A string search cannot tell a definition from a call site or a comment, and the specific hazard here is that git left the two helpers' shared closing brace outside an earlier conflict region -- a careless resolve yields a file that parses cleanly with one function swallowed into the other's body. The parser reports both ConvertTo-WorktreeSlug and Get-SafeForMessage as FunctionDefinitionAst, 8 functions total, 0 parse errors.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Strengthens BACKLOG #1000 -- "Prove each required merge context can fail: negative controls for the gates that block merge" -- with five more measured instances and one design rule. Docs-only, one file.
No new number was allocated, deliberately. The conclusion that produced this change was that a near-duplicate sibling would dilute #1000 rather than add to it: #1000 already owns the class and was itself prompted by the backlog-hygiene gate. Verified: 120 items before, 120 after, zero new numbers.
The design rule, which is the part most likely to be skipped
A negative control must be ASYMMETRIC. A control that fails on everything when you neuter the rule cannot tell you which layer does the work -- so it cannot distinguish "the other cases are safe by design" from "safe by luck."
It is written with its measurement attached, including the uncomfortable half: the first draft of a comment credited new code with both ADS spellings when it covered one. That is an overstatement in the direction that flatters one's own code, which is the worst direction for it to be wrong in. A control failing on all eight inputs would have looked stronger, confirmed the overstatement, and taught nothing.
The five instances
Each is a check that was green while unable to see what it was trusted to report on:
ValidatePatternthat accepted a trailing newline --"abc\n"matches^[A-Za-z0-9._-]+$, because .NET's$also matches before a final newline, so the guard did not enforce its own stated shapeexit $LASTEXITCODE, without which pwsh reports 0 for a script that died at parameter binding--argtogh --jq; gh errored, printed usage, and the script read the empty stdout as "nothing eligible" while two PRs sat eligibleThe last is stated as a pattern rather than an incident, because its remedy generalises: a probe must validate the SHAPE of its own output, not merely read it. Otherwise "looked and found nothing" is indistinguishable from "did not look". The fix is to assert the probe returned the expected type before branching on it.
Verification
Banner invariant checked with the repo's own parser rather than a hand-rolled scan:
backlog_status_check.pyreports 315 items, each declaring exactly one status. Off currentorigin/main, zero behind, intersection with main empty,merge-treeclean.