fix: whitespace is not a drill record, and align the heading grammar with box

This commit is contained in:
dan-claude-bot 2026-07-21 15:53:38 +00:00
parent 2578a570ca
commit 9f8df92484
2 changed files with 49 additions and 9 deletions

View file

@ -95,15 +95,31 @@ esac
# humans reading the log.
#
# grab is re-armed by every '## ' line, so the section ends at the next one —
# a record cannot borrow the body of the record below it. sed drops the blank
# padding under the heading and the command substitution eats the trailing
# blanks, which is what makes "present but EMPTY" distinguishable from
# "present with content": a heading with nothing but whitespace under it
# extracts to the empty string.
record="$(awk -v ver="$ver" '
/^## / { grab = ($2 == "Release" && $3 == "drill" && $4 == "—" && $5 == ver); next }
grab { print }
' "$runs" | sed '/./,$!d')"
# a record cannot borrow the body of the record below it.
#
# `grab && NF` is the non-blank rule, and it is load-bearing rather than
# tidiness. NF is 0 on a line that is empty OR contains only whitespace, so
# `record` is non-empty exactly when a line with real content exists. The
# first cut of this piped through `sed '/./,$!d'` and the comment here claimed
# "a heading with nothing but whitespace under it extracts to the empty
# string" — which is precisely what that pipeline did NOT guarantee, because
# `.` matches a space. A heading followed by one tab satisfied the gate. The
# comment documented the intended contract and the code did not meet it, which
# on a gate is the whole ballgame: an evidence-free release for the price of an
# invisible character. Found by all three reviewers on #138, independently.
#
# The '(NF == 5 || $6 == dash)' tail constraint keeps this in step with box's
# twin: without it '## Release drill — 0.2.0 stray words' counts as a record
# here and does not there. Two sibling guards disagreeing about what the same
# heading means is the same trap as disagreeing with release-notes.sh.
record="$(awk -v ver="$ver" -v dash="—" '
/^## / {
grab = ($2 == "Release" && $3 == "drill" && $4 == dash && $5 == ver \
&& (NF == 5 || $6 == dash))
next
}
grab && NF { print }
' "$runs")"
if [ -z "$record" ]; then
{

View file

@ -798,6 +798,30 @@ describe("drill-recorded.sh — a release version has a drill record", () => {
expect(r.output).toContain("no drill record for version '0.2.0'");
});
// ...and whitespace is not evidence either. The first cut extracted with
// `sed '/./,$!d'`, where `.` matches a space, so a heading followed by one
// tab passed the gate — while the comment above the extractor claimed the
// opposite. An evidence-free release for the price of an invisible
// character, on the one check whose whole job is to demand evidence.
// Found independently by all three reviewers on #138.
it("a record body of only spaces and tabs fails (#138)", async () => {
const runs = `# Drill runs\n\n${heading("0.2.0")}\n \n\t\n\n## Notes\n\nUnrelated.\n`;
const r = await check(treeWith("blank", "0.2.0", runs));
expect(r.code).toBe(1);
expect(r.output).toContain("no drill record for version '0.2.0'");
});
// The sibling guards must agree about what a heading IS, not just about the
// version in it. box#149 requires the version to be the last field or be
// followed by the em dash; without the same constraint here, this heading is
// a record in cast and not in box.
it("a stray tail after the version is not a heading — in step with box#149", async () => {
const runs = `# Drill runs\n\n## Release drill — 0.2.0 stray words\n${legs}`;
const r = await check(treeWith("tail", "0.2.0", runs));
expect(r.code).toBe(1);
expect(r.output).toContain("no drill record for version '0.2.0'");
});
// The version is matched WHOLE, both directions — release-notes.sh's trap,
// solved the same way (awk field equality, no regex, no dot-escaping). A
// release candidate's drill is not the release's drill: different tree,