From db666b117fbd6227b29e23bd3c4cedec23b12dad Mon Sep 17 00:00:00 2001 From: garrytan Date: Mon, 2 Nov 2026 11:29:33 +0000 Subject: [PATCH] docs(receipt): a fenced copy of the exception line is skipped too (GST-977 review) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- changelog.d/gst-977-prose-skips-exception-line.md | 2 +- docs/ship-policy.md | 3 ++- lib/ship-receipt-prose.ts | 5 +++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/changelog.d/gst-977-prose-skips-exception-line.md b/changelog.d/gst-977-prose-skips-exception-line.md index ca4e9179f..317b7e517 100644 --- a/changelog.d/gst-977-prose-skips-exception-line.md +++ b/changelog.d/gst-977-prose-skips-exception-line.md @@ -1,7 +1,7 @@ **`gstack-ship-receipt read --check-prose` no longer reads the required Review-loop exception line as counter claims (GST-977).** `write --review-loop-exception` requires the PR body to carry the whole `Review-loop exception: …` line word for word, but the prose check read that line as prose. On gstack-evals #139 the owner's reason "outside 1 and 2 skip detector" was read as a `2 skip` claim against the receipt's 70 skips, so no body could pass both checks. ### Fixed -- **`lib/ship-receipt-prose.ts`:** the line that matches the receipt's own exception exactly (the same test `write` applies) is skipped, like the rendered `## Approvals` block. The same words anywhere else, or a line for a different exception, are still checked. +- **`lib/ship-receipt-prose.ts`:** the line that matches the receipt's own exception exactly (the same test `write` applies) is skipped, like the rendered `## Approvals` block. A copy of that exact line inside a code fence is skipped too, as `write` accepts one. The same words inside a longer line, or a line for a different exception, are still checked. ### Tests - `test/ship-receipt-prose.test.ts`: the #139 exception text passes `--check-prose` beside a matching `70 skip` claim, and a wrong number elsewhere still fails. On main the same body failed with `gate.unit.skip body=2 receipt=70`. diff --git a/docs/ship-policy.md b/docs/ship-policy.md index 11e96f5ce..00f7123d7 100644 --- a/docs/ship-policy.md +++ b/docs/ship-policy.md @@ -1226,7 +1226,8 @@ a `## Approvals` example inside a code fence, are still checked. The `Review-loop exception: …` line the receipt's own exception requires is skipped the same way (GST-977): it quotes the owner's reason, so "outside 1 and 2 skip detector" is not a `2 skip` claim. Only a line that matches the rendered -line exactly is skipped; the same words anywhere else are still checked. Data PRs (evals, +line exactly is skipped, inside a code fence too, as the receipt check accepts +a fenced copy; the same words inside a longer line are still checked. Data PRs (evals, measurements, sweeps) run it before READY so the body's numbers are the run's. diff --git a/lib/ship-receipt-prose.ts b/lib/ship-receipt-prose.ts index c26ae36f4..a99ee1784 100644 --- a/lib/ship-receipt-prose.ts +++ b/lib/ship-receipt-prose.ts @@ -69,8 +69,9 @@ function withoutApprovalsBlocks(body: string): string { /** * The body without the `Review-loop exception: …` line the receipt's own exception requires (GST-977): write and the * receipt check want it word for word, and it quotes the owner's reason (`outside 1 and 2 skip detector`), not this - * PR's counters. Only a line whose trimmed text is that rendered line, the test write applies, is left out; the same - * words anywhere else stay prose. A marker line takes its place so the text on either side never joins into a claim. + * PR's counters. Only a line whose trimmed text is that rendered line, the test write applies, is left out (a fenced + * copy too, as write accepts one); the same words inside a longer line stay prose. A marker line takes its place so + * the text on either side never joins into a claim. */ function withoutExceptionLine(body: string, exception: unknown): string { if (exception === undefined) return body;