HOMELAB-2682: fix(forgejo): id-less findings close only via the canonical review-citation sentence #100
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-2682-phrase-hardening"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up hardening to the landing lock (#99, merged
1ff5dd47).forgejo/subtree.The incident (Homelab/infra-core#850)
A steered reviewer's one-line comment closed an id-less finding:
isResolved's id-less arm matchedBLOCKER_RESOLUTION_PHRASE_RE—blockers? … resolved|fixed|closedanywhere in a trusted reviewer's comment body. That sentence satisfied it, the finding vanished, and the merge passed on that line alone. A phrase names no defect id and pins no head, so the lock could not tell it apart from prose that merely uses both words.The change (
forgejo/landing.ts)An id-less finding now closes only on the canonical citation sentence — the one
resolutionLineinforgejo/verdict.tscomposes for the verdict helper's--resolve-review <id>:CANONICAL_RESOLUTION_REaccepts exactly that shape, whole trimmed line:blockers, the nounrevieworcomment, an id token (22162,#22162,ABC-12—REVIEW_ID_RE's vocabulary),is resolved on head, and a full 40-hex head;pinNamesHead), so a sentence written about an earlier head closes nothing; a sha prefix is not a pin;policy.reviewerIdentitiescan close anything;What is gone:
blockers resolved/blocker fixedno longer closes an id-less finding (pinned, incident shape and all);blockers?directly followed by a resolution word —blockers resolved: B1 is fixed …) is not a finding of its own. Base never surfaced those because the phrase closed them, itself included; without it every reviewer note of that shape would leave an unclosable phantom finding behind and refuse the merge for the reviewer having answered the lock. The rule is strictly narrower than base's self-closure and never touches a line that carries an id.Unchanged: id-ed findings keep the citation grammar (
resolved <id>, HOMELAB-2521) and #99's author gate; the in-line restatement arm and #99's D1/D2 fixes are untouched; a formal APPROVE still is not a resolution.The id-less refusal hint (layered on #99's D3 text) now names the canonical sentence as the closure mechanism and points at
verdict-cli.ts --resolve-reviewas the way to compose it, so the advice is something a reviewer can actually do.Tests —
forgejo/tests/lock-idless-phrase-hardening.test.ts(25 cases)Failing-first, incident-shaped, all synthetic PR streams (no network):
ld-reviewer+ the verbatim-shaped… so it is resolved rather than a finding.line fromld-reviewer→ the finding stays open;done in <sha>) closes nothing;resolutionLineand against a body produced bycomposeVerdictBody, so the matcher and the CLI cannot drift apart;blockers, thecommentnoun,#22162, a labelled id, no trailing period);resolved B1closes, the canonical sentence does not close a labelled finding, the incident phrase does not either;## Blocker test appliedheading (22155's own heading) is a section title, not a finding — the full incident stream leaves exactly one finding open;--resolve-review, and posting the sentence at the current head lands it.Four pre-existing pins of the removed phrase path are updated to the new contract (
landing.test.ts,landing-blockers.test.ts,landing-lock-tightenings.test.ts), plus the real infra-core#670 corpus stream inlanding-fleet-verdict.test.ts: #16344's id-less finding was closed there by #16362's prose ("The blocker is closed, …"), so leg 4 now keeps it open — the verdict record legs are asserted unchanged, and the canonical sentence from the reviewer at that head lands it. Corpus bodies are not mutated.Both #99 seats' follow-up direction
Both reviews on #99 accepted this gap until a follow-up; this is that follow-up, and it keeps their decision intact rather than reopening it: the author gate, the D2 heading rule and the D3 hint text all stay, with the hint text extended.
Suite
Deployed shape (
npm run test:deployed, the shape that is actually deployed): 27/27 test files loaded and passed, 728/728 tests,tsc --noEmitclean on the pinned tree.Not merged by the author — two reviewer seats follow.
Round-2 delta — fix worker, head
ce7bb96The first head's id-less closure bound the CITATION to nothing: the sentence's review/comment id was captured and never read, so one canonical sentence closed every open id-less finding at the head (a sentence citing an id that raised no finding closed them all). The id is now bound to the item that raised the finding: the sentence closes only findings raised by the comment/review it names, an id that raised nothing closes nothing, and a labelled token (
ABC-12) names no PR item so it closes nothing either — while the several findings one comment raised close together, because they share their source. Also in this head: the matcher takes both verbs (is/are, so the grammaticalThe blockers … are resolved …works and has a test per verb), and the companion "a resolution statement is not a finding of its own" skip is now trusted-author only — it was author-agnostic, which made it WIDER than base for everyone else and silently deleted an untrustedBlocker fixed in 4f2a1bc but the guard still prints …finding; that report is back at base parity.docs/forgejo.mdleg 5 now documents the id-less closure (it previously described only the id-ed grammar and still listedblockers resolvedas a clearance spelling). Deployed-shape suite on this head: 27/27 test files, 736/736 tests,tsc --noEmitclean.Corrections to the text above, superseded by this delta: the id token must be the raising comment's numeric id (
ABC-12does not close),is/areare both accepted, and the case/test counts supersede 25 / 728.An id-less finding could be closed by PROSE. `isResolved`'s id-less arm matched BLOCKER_RESOLUTION_PHRASE_RE (`blockers? … resolved|fixed|closed`) anywhere in a trusted reviewer's comment. The measured incident is Homelab/infra-core#850: a steered reviewer's one line Comment 22155 at head afbcd529 reports no defect in that blocker test, so it is resolved rather than a finding. closed an id-less finding, and the merge passed on that line alone. A phrase names no defect and pins no head, so the lock could not tell it apart from prose that merely uses both words. The closure is now the sentence `resolutionLine` in forgejo/verdict.ts composes (the verdict helper's `--resolve-review <id>` output): The blocker raised in review <id> is resolved on head <40-hex sha>. CANONICAL_RESOLUTION_RE accepts exactly that shape on a whole trimmed line: singular or plural `blockers`, the noun `review` or `comment`, an id token, and a full 40-hex head that must name the head being judged (pinNamesHead). It is scanned per line, not per comment body. - the trusted-author gate is unchanged and still load-bearing (only policy.reviewerIdentities can close anything); - a bare "blockers resolved" / "blocker fixed" no longer closes, and a bare formal APPROVE never did — pinned; - an id-ed finding is untouched: `resolved <id>` still closes it, and the canonical sentence does not close one; - a line that IS a resolution statement (line-initial blocker token directly followed by a resolution word) is not a finding of its own. Base never surfaced those (the phrase closed them, itself included); without the rule every reviewer note of the shape "blockers resolved: B1 is fixed" would leave an unclosable phantom finding behind. The rule is strictly narrower than base's self-closure and does not touch a line carrying an id; - the id-less refusal hint now names the canonical sentence as the closure mechanism and points at `verdict-cli.ts --resolve-review` as the way to compose it (layered on #99's D3 hint). Tests: tests/lock-idless-phrase-hardening.test.ts (25 cases) — the incident replayed, the exact helper-composed sentence (asserted against `resolutionLine`), untrusted author, stale head, sha prefix, no id token, buried sentence, bare APPROVE, id-ed unchanged, the "resolution statement is not a finding" rule, and the D2 heading 22155 is not a finding. Four pre-existing pins of the removed phrase path are updated to the new contract (landing.test.ts, landing-blockers.test.ts, landing-lock-tightenings.test.ts, and the real infra-core#670 corpus stream in landing-fleet-verdict.test.ts, where the new leg 4 keeps #16344's id-less finding open and the canonical sentence lands it). Suite: 27/27 files, 728/728 tests, tsc --noEmit clean.Verdict of record — ld-reviewer — head
692e491a64: APPROVEmodel: deepseek-flash
session: sess-20261105-r100-ds1
Scope
Independent seat 1 of 2 (gate tooling). Read from primary sources only: the diff
1ff5dd4..692e491,forgejo/landing.tsandforgejo/verdict.tsat this head,forgejo/tests/lock-idless-phrase-hardening.test.ts, the four updated suites, anddocs/forgejo.md. CI on this head is green (run #296, every job). I re-ran the deployed-shape suite on this head: 27/27 files loaded and passed, 728/728 tests,tsc --noEmitclean — the PR body's numbers reproduce.Blockers
None.
Concerns
The cited review/comment id is captured, then discarded.
CANONICAL_RESOLUTION_REputs the id in group 1;closesIdlessFinding()reads group 2 (the head) and never group 1. Nothing checks the id against the PR text — not that an item carries it, not that it raised a finding. Every closing case in the suite happens to cite the finding's own comment id, so a non-existent id is never exercised. Effect: any id in the id vocabulary closes, including one copy-pasted from another review, or a plainreview 1— provided the head it pins is the head judged. Suggested: check the id againstitems(an item with that id exists and produced a finding), or soften the comment that calls it "the review/comment the sentence speaks for". This does not reopen the #850 class (that was prose with no id and no head) and the author gate is still the trust root — it is depth the sentence claims and does not have.Plural spelling: accepted only with the wrong verb. The matcher's comment and the PR body both say singular or plural is taken, but
is resolvedis hardcoded, so the plural a reviewer would actually hand-write —The blockers raised in review 22162 are resolved on head <sha>.— does not close, while the ungrammaticalThe blockers raised in review 22162 is resolved on head <sha>.does, and the sibling test pins that ungrammatical form. Refusal direction, so the cost is one more review round; the claim is simply wider than the grammar.docs/forgejo.mdis untouched. Leg 5 still documents only the id-ed citation grammar and repeats that "an id-less finding is not closed by a citation at all" without naming the one closure that now exists, and the HOMELAB-2661 paragraph still listsblockers resolvedas a clearance spelling that "still clears the finding it names" — a spelling the lock no longer honours. The refusal hint carries the mechanism; the contract doc a reviewer reads first does not.The residual is not stated in the PR body. The body explains what is gone and why, but not that a trusted reviewer — or anything holding the reviewer identity, which includes a steered reviewer session like the one behind #850 — closes an id-less finding by writing the sentence itself, once any id and the current head are in it. The code comments say as much; the PR body should too.
Checked, no finding
done in <sha>) closes nothing. The full incident stream leaves exactly one finding open, and 22155's own## Blocker test appliedheading does not become one (#99 D2 stands).resolutionLineand against a body produced bycomposeVerdictBody, so matcher/composer drift fails CI.The blocker raised in review 22162 is resolved on head <full sha>.is exactly what the matcher takes: whole trimmed line, nounreview/comment, an id in the same vocabulary the helper validates with, and a full 40-hex head.pinNamesHeadis equality in both directions (both sides are 40 chars), so a stale head, a sha prefix, and a sentence buried in a longer line all close nothing — all three pinned. Both of the lock'sfindOpenBlockerscall sites passheadSha. Without aheadSha(unit paths, and verdict.ts's informational leg-4 call) any 40-hex pin is taken; the gate always supplies one, so the refusal is unaffected.The blockers raised in review N are resolved on head <sha>: <why>.does not close (trailing clause, plus concern 2's verb), and neither does the plural-with-areform. A reviewer who has been hand-writing these must switch to the composed singular sentence or to--resolve-review.BLOCKER_RESOLUTION_PHRASE_REhas no remaining reference), the id-less arm is the only reader that changed, and the companionRESOLUTION_STATEMENT_LINE_REskip is narrower than base's self-closure: it needs a line-initial severity token immediately followed by a resolution word and no id of its own, and a line carrying an id is untouched. A defect that merely mentions a resolution word is still reported (pinned).resolved B1still closes; the canonical sentence does not close a labelled finding; the incident phrase does not either — all pinned.verdict-cli.ts --resolve-review, and says a bareblockers resolvedcloses nothing; I ran the helper's own usage at this head to confirm the flag it points at exists. The old id-ed advice that nothing could satisfy is gone.This seat approves at the exact head above. The dangerous class (
forgejo/**) still needs the second independent seat.Verdict of record — ld-reviewer — head
692e491a64: REQUEST_CHANGESmodel: deepseek-flash
session: seat2-2682-gate-tooling-7f31a4c2
Blockers
CANONICAL_RESOLUTION_REcaptures the review/comment id as group 1 andclosesIdlessFindingmatches on group 2 (the head) alone, so the id the sentence names is never read and the line closes EVERY open id-less defect at that head rather than the one it speaks for. Measured on the unit stream (trustedld-reviewer, judged head4f2a1bc0d7e3a95c1b8f6d24e0a7c39b5d18f2ea): with two genuine id-less defects open — one raised in comment 22155, one in comment 22170 — the sentence citing 22155 leaves ZERO open, so the one it does not name is closed by it; a sentence citing review 99999 (an id that raised nothing at all) closes it too, as does citing an unrelated existing comment id. The residual this ticket accepts is canonical form + a review id that RAISED the defect + the current head + a trusted author; what the code implements is canonical form + ANY id token + the current head + a trusted author. The steered case is no worse than accepted; the honest case is: a reviewer who resolves one of two id-less defects silently lands the PR with the other one open — the failure this lock exists to refuse. Ask: bind group 1 to the item that raised the defect (at minimum the defect's own item id; an id naming no item closes nothing), and pin two cases — canonical citing a non-raising id stays open, and of two id-less defects the sentence citing one leaves the other open.Concerns
1. My attack table (item 1), so the author has the measured set. All lines posted by
ld-reviewer, one id-less genuine finding open, judged at the current head: canonical + finding-raising id 22155 → closed (the accepted residual); canonical +#22155→ closed (same id, fine); canonical citing 22155 with a STALE head → open (head discipline holds);The blockers raised in review 22155 are resolved on head X.→ open (see concern 3);Resolved on head X: blocker from review 22155.→ open (whole-line grammar); canonical + a trailing clause → open; canonical frompi-landing→ open (author gate); canonical citing 22155 closing a second finding raised in 22170 → closed, and canonical citing 99999 → closed (these last two are the ones in this blocker). So the residual's shape holds everywhere except the id binding, which is decorative today.2. Negation and quoted-example guards, at id-ed parity. Structurally this path is safe for the single-line shapes:
is NOT resolved,unresolved, a trailing negation, a blockquote, an inline-backtick quote and a fenced block all leave the finding open, because the whole trimmed line must be the sentence. Two shapes still close: a 4-space-indented example, and prose that repudiates the claim and then puts the sentence on its own physical line. Both close on the id-ed arm as well, at base1ff5dd47and at head (measured), so this is the per-line reader's pre-existing limit rather than something this PR introduces — recorded for the record, not asked for here.3. Untrusted authors now lose a reported finding. The new
RESOLUTION_STATEMENT_LINE_REskip is author-agnostic, while the phrase closure it compensates for required a trusted author. Measured differential, base1ff5dd47vs this head:one itemfollowed byBlocker closed by the canary - but only the happy path; the empty case still prints.is REPORTED as an id-less finding at base and not reported at head when the author isfix-workeror absent; the same holds forBlocker fixed in 4f2a1bc but the guard still prints .... Narrow (line-initial severity token, immediate resolution word, untrusted author) and defensible as "not the reviewer's word", but the code comment and the PR body describe the rule as strictly narrower than base's self-closure, and for untrusted authors it is wider. Either gate the skip onauthorOwnsResolutionsor correct the claim.4. Plural asymmetry.
The blockers raised in review 22155 are resolved on head X.is refused while the ungrammaticalThe blockers raised in review 22155 is resolved on head X.is accepted and pinned by a test as a sibling spelling. Refusal is the safe direction, but a reviewer writing the grammatical plural is sent round the helper for nothing; consider acceptingare, or dropping the ungrammatical pin.5. Verified sound, no action asked. Head discipline is live on both lock call sites (both pass
headSha), a stale full-sha pin refuses, a sha prefix refuses by shape, an untrusted author refuses, a buried sentence refuses (the whole line is the grammar), a bare trusted APPROVE does not clear an id-less finding, id-edresolved <id>plus #99's author gate and the restatement arm are unchanged, the id-less refusal hint no longer offers a bare phrase and names the sentence and the helper, the CLI--resolve-reviewpath still composes the line this matcher reads, and the new self-skip rule is base-parity on every trusted-author shape I measured. Deployed shape on this head: 27/27 test files loaded and passed, 728/728 tests,tsc --noEmitclean.Verdict of record — ld-reviewer — head
ce7bb961c7: APPROVEmodel: deepseek-flash
session: sess-20261105-r100-s1r2-5f0c9a
Scope
Independent seat 1 of 2 (gate tooling), ROUND 2 delta check. Primary sources only: the diff
692e491..ce7bb961,forgejo/landing.tsat this head,forgejo/verdict.ts,forgejo/tests/lock-idless-phrase-hardening.test.ts, the two edited tests,docs/forgejo.md. Row 4 / 4b / 9 of the round-1 REQUEST_CHANGES (22209) were re-run by me on synthetic unit streams with my own ids (not the suite's fixtures), plus a base-vs-round-1-vs-round-2 differential built by importing1ff5dd47's and692e491'slanding.tsalongside this head's. No real PR was touched. CI on this head: run #300 every job success, run #301 (python) success. I re-ran the deployed-shape suite on this head myself: 27/27 test files, 736/736 tests,tsc --noEmitok — the delta's numbers reproduce.Blockers
None.
Resolutions
citationItemId()(numbers only — a labelled token names no PR item) and passes the finding's own raising item id intoclosesIdlessFinding, which refuses unlesscited === raisingItemId. Measured, my ids: two genuine id-less defects raised in comments 31337 and 31338, canonical citing 31337 -> exactly ONE finding open and it is 31338's; the mirror (citing 31338) leaves 31337 open; citing 99999 (raised nothing) and citing 31339 (an existing unrelated comment that reported nothing) both leave the finding open;The blocker raised in review ABC-31337 is resolved on head <head>.closes nothing. Seat 2's rows 4, 4b and 9 therefore now hold. The several findings one comment raised still close together, which is the same fact about a shared source rather than a wider rule.Concerns
The citation's noun is still decorative (the id's twin, much narrower).
citationItemIdcompares the number and ignores the itemkind, and the grammar'sreview|commentnoun is never read. Forgejo numbers comments and reviews in separate sequences, so one PR can carry a comment 500 and a review 500. Measured: comment 500 raising defect A, review 500 raising defect B,The blocker raised in review 500 is resolved on head <head>.-> BOTH close, and writing the noun ascommentgives the identical result. It is the B1 shape with a narrower window (a genuine numeric collision, both items raising id-less findings, same judged head), and every other gate still holds, so it is not a blocker. Ask: match the noun against the item's kind, or drop the noun from the grammar rather than advertise a distinction the code ignores.The
\d{1,6}id width is now a landability trap. Round 1 left the id decorative, so the 6-digit cap was harmless; the binding makes the id decide whether a finding can ever close. Measured: a comment cited with raising id 123456 closes its finding; with 1234567 (7 digits, no regex match) the finding stays open forever — the PR could never land, and no honest sentence exists that the lock would take. Today's item ids are ~22k, so this is remote, but it is a fail-closed hole created by making the id mean something. Widening the token to\d{1,12}closes it. Pre-existing from round 1, unchanged by this delta."Strictly narrower than base's self-closure" is true for the shapes base's phrase matched, and false for one it did not. The trusted-author gate on
RESOLUTION_STATEMENT_LINE_REis the right fix and restores untrusted parity:fix-worker/pi-landing/aaron/ no author,Blocker fixed in 4f2a1bc but the guard still prints …andBlocker closed by the canary - but only the happy path …are REPORTED again at base parity (base 2 open, round-1 head 1, this head 2 — measured). But base's phrase needed(?<![-\w])before the resolution word, so a hyphen-glued trusted line,blocker-resolved: the guard still prints the token on empty input, was REPORTED at base and is dropped by the skip at both heads (measured base 2 open, this head 1). Same direction forblocker-fixed …. It is a trusted reviewer's own line, it reads as a disposition note, and the em-dash / comma shapes go the other way (base 0, head 1) — but the code comment and the PR body claim a strict narrowing that holds only where base's phrase reached. Either say "narrower wherever base's phrase applied" or exclude the hyphen-glued separator fromRESOLUTION_STATEMENT_LINE_RE.The residual still is not stated in plain words in the PR body (round-1 concern 4). The delta paragraph calls the author gate "now load-bearing for the only id-less path there is", which is accurate but indirect. What a reader of this PR needs to see, as my round-1 comment asked: closing an id-less finding is now a single trusted-author act — the reviewer, or anything holding the reviewer identity including a steered reviewer session like the one behind infra-core#850, closes it by posting the canonical sentence itself, and what the lock adds is only the shape (a raising item's id, the current head). The binding narrows which findings one sentence closes; it does not change that the sentence is authority, not evidence. Documentation-level; the code comments do say it.
Checked, no finding
(?:is|are)takes both;was,were,has been,have been,got,gets,shall be,is NOT,is now,remainall refuse (11 non-forms measured). Both noun numbers are accepted with both verbs, so the ungrammaticalThe blockers … is resolvedstill closes as a superset of the composer — the widening seat 2 asked for, in the permissive direction only, and it changes nothing about WHO may close.composeVerdictBody({ event:"APPROVED", resolveReview:"31337", … })emitsThe blocker raised in review 31337 is resolved on head <40-hex>.and that body closes the finding it raised;resolutionLineand the matcher still cannot drift.resolved B1still closes an id-ed finding; bareblockers resolvedand the canonical sentence both still fail to close one; the restatement arm still requires the reviewer identity (trusted restatement closes,fix-workerrestatement is reported and never a closure);--resolve-reviewand the id-less refusal hint both name the sentence; a formal APPROVE is still not a resolution; an untrusted author or a stale/earlier head still refuses even with the correct raising id.index.tsbuildsitemsonly from comments, reviews and inline comments — every one carries a real Forgejo item id a reviewer can see — so binding cannot make an honest closure impossible by construction (an inline-comment finding is closed by citing that inline comment's id; measured).docs/forgejo.mdleg 5 now documents the id-less closure, the binding, the labelled-token refusal and the trusted-author-only skip, and the HOMELAB-2661 paragraph no longer listsblockers resolvedas a clearance spelling;blockers resolvedsurvives in the doc only as the spelling that does NOT clear. Of my round-1 22207 concerns, 1 and 2 are answered in code and 3 in the doc.Verdict of record — ld-reviewer — head
ce7bb961c7: APPROVEmodel: deepseek-flash
session: seat2-r2-2682-gate-9c41f7b2
Scope
Independent seat 2 of 2, ROUND 2 (adversarial, gate tooling), fresh context. Read from primary sources: the delta
692e491..ce7bb96inforgejo/landing.ts,docs/forgejo.md, the new cases inforgejo/tests/lock-idless-phrase-hardening.test.ts, andresolutionLine/REVIEW_ID_REinforgejo/verdict.ts. I re-ran the deployed shape on this head myself: 27/27 test files, 736/736 tests,[deployed-shape] typecheck: ok. CI on this head is green (run #300, every job; #301 also green). I did not take the author's summary as the review brief, and I posted no verdict on anyone's behalf.Blockers
None.
Resolutions
findOpenBlockers(the deployed sort) and the realevaluateLandingLockshape. Two genuine id-less defects at one head, sentence citing one of them: exactly one finding left open, and it is the un-named one; mirror direction identical. A citation naming99999(nonexistent) leaves the finding OPEN; a citation naming an unrelated EXISTING comment that raised nothing (22170) leaves it OPEN; the real lock REFUSES the merge in both cases (blocker (no id)in the refusal). The id is read (group 1), compared withitems[at.itemIndex].id, and a labelled token is rejected — the binding is real, not decorative. The plural form is also taken now:isandareboth close on a valid id, so the round-1 plural concern is closed too.Concerns
The binding is per ITEM, not per finding — and the doc reads as per-finding. Measured: one trusted comment that raises TWO id-less findings, plus a second comment raising a third; one sentence citing the two-finding comment closes BOTH of its findings and leaves only the third open. The code says so deliberately (its own case name is "closes every finding raised in the cited comment…"), and it is defensible — the sentence speaks for the source — but
docs/forgejo.mdleg 5 states the rule as "one sentence that names one of two open id-less findings leaves the other open", which is true only ACROSS items. A reviewer's verdict body is exactly where several findings live, and--resolve-review <id>can only speak at comment granularity, so there is no way to close one of two in the same comment. Ask: one clause in the doc naming the granularity ("per item; several id-less findings raised in one comment close together — label them B1/B2 if you need them separate"). No code change needed.Numeric-only binding is ambiguous across kinds. PR items arrive from three id sources (issue comments, formal reviews, inline comments); reviews are a separate sequence from comments in Forgejo, so the same NUMBER can be two different items in one stream. Measured: a formal review with id 900 and a comment with id 900 both present, the finding raised in the COMMENT, and a sentence citing 900 closes it — the sentence was written about the review. The noun (
review/comment) is accepted and then ignored, which is forced:resolutionLinealways writesreview, so binding the noun would break the very citations the refusal hint tells reviewers to write. Narrow (needs a collision plus the colliding item to be a raiser) and the trust root is still the reviewer, so I did not raise it as a blocker. Ask: either require the cited number to name exactly ONE item before it closes anything (small, local), or state the limit. Related, benign:022162is accepted for item 22162 (zero padding parses to the same number) — same item, no gain to an attacker.The citation vocabulary caps ids at 6 digits, and this PR makes that cap load-bearing for closure.
REVIEW_ID_RE(verbatim, both composer and matcher) takes\d{1,6}. Measured: an id-less finding raised in an item with id 1234567 can never be closed — the matcher's regex cannot read the sentence andcomposeVerdictBodyrefuses to compose it. Refusal direction, so the cost is a stuck PR rather than a wrong merge, and the 6-digit bound is inherited from HOMELAB-2521 rather than added here — but before this PR nothing depended on it for closure, and the hint text does not mention it. No ask on this head; worth a follow-up when the counter gets close.The residual is stated in the delta but the PR body still does not say it plainly. Round-1 seat 2 asked for one sentence: a trusted reviewer — or anything holding the reviewer identity, including a steered session — closes an id-less finding by writing the sentence, provided the id raises it and the head is current. The round-2 delta describes the binding well and never says the residual in those words. Documentation-grade, not code-grade.
Attacked, no finding
#-prefixed id) CLOSED; row 3 (pluralare, valid id) now CLOSED; row 4 (unknown id 99999) OPEN; row 4b (unrelated existing id that raised nothing) OPEN; row 5 (stale head) OPEN; row 6 (pi-landingauthor) OPEN; row 7 (sentence plus a trailing clause) OPEN; row 8 (prose formResolved on head X: blocker from review N) OPEN; row 9 (two findings, two different items, one citation) — cited one closes, the other stays OPEN, and the mirror direction too.withdrawnItemsfilter inevaluateLandingLock(a withdrawn hold drops findings sourced from that item), which exists at base1ff5dd47and is not a delta here.commentnoun, uppercase hex head. Refusing — sentence wrapped in**bold**, a bullet prefix, backticks, a negation (is not resolved), a labelled id (ABC-22162), a 7-digit id, a 12-char sha prefix. Whole-line grammar is intact; the reader is the sentence, and a prose prefix still defeats it.1ff5dd47vs the previous head692e491vs this head):Blocker fixed in 4f2a1bc but the guard still prints…andBlocker closed by the canary - but only the happy path; …were REPORTED at base, were SWALLOWED at692e491for an authorless item and forfix-worker/aaron, and are REPORTED again here for every untrusted author (the no-author case included). A trusted reviewer's same-shaped line is not a finding of its own — base parity, since base's phrase closure covered it. The skip never touches a line carrying an id.--resolve-review.docs/forgejo.mdleg 5 now documents the id-less closure and theblockers resolvedclearance claim is gone from the HOMELAB-2661 paragraph — round-1 concern 3 is addressed.blocker B1: resolved …line is absorbed as a resolution restatement rather than reported. It measures identically at base1ff5dd47, so it is the pre-existing restatement arm, not this delta.Verdict
APPROVE. The round-1 blocker is closed in the code I measured, the plural form is taken, the skip is narrowed to trusted authors and back at base parity, the doc is updated, and the deployed-shape suite reproduces green on this head. The four concerns are follow-up grade: two are doc/PR-body wording, one is a narrow collision of binding-by-number, one is an inherited 6-digit cap in the refusing direction. None of them reopens the #850 class, and none of them lets a sentence close a finding it does not name.
resolved S2-1: verified on the delta head
ce7bb961c7— the canonical sentence's cited id now binds to the item that raised the finding; unknown and unrelated ids close nothing (round-2 seats 22226 + 22230 re-ran the full mimicry table). Round 1's B1 label = this finding; the delta is the fix.