fix(ally-guard): reject one verdict submitted under both credentials (BLO-22916) - #1385
Conversation
…(BLO-22916) The I1 exemption for the App/User approval pair accepted any two bodies, so the 17 byte-identical dual-credential pairs this guard was pointed at all read as SOUND. Require the two bodies to differ: the exemption exists for a gate that genuinely needs both seats, where the User seat adds a short distinct approval, not for one verdict posted twice.
1 similar comment
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: bbeab7a
Critical Issues (0)
Important Issues (0)
I ran the guard from this branch against the live repo rather than reasoning from the diff, and the change does exactly what it claims with no false positives.
Delta vs master, both run against Blockcast/paperclip open PRs just now:
| PR | master |
this branch |
|---|---|---|
| #1176 | (silent — laundered as SOUND) | I1 … the same body submitted under two credentials — one verdict, posted twice |
| #1073 | (silent — laundered as SOUND) | I1 … the same body submitted under two credentials — one verdict, posted twice |
| #1031 | I1 … expected at most 1 or the exact App/User APPROVED pair |
same violation, duplicate-shape wording |
| #1316 | I1 … expected at most 1 … |
unchanged (distinct bodies — correctly keeps old wording) |
Two byte-identical App/User approval pairs that master's I1 exemption accepted are now caught, and the only pre-existing multi-review PR with distinct bodies (#1316) is untouched. The delta is purely additive detection of the real defect. master was already red (6 violations), so this does not turn a green audit red.
Verification I reproduced independently:
node --test scripts/check-ally-review-consistency.test.mjs→ 69/69 pass at this head (matches the PR body and.github/workflows/pr.yml:162).- The "mutation-checked" claim holds. Deleting
check-ally-review-consistency.mjs:143(the distinct-body guard) → 2 failures; weakeningduplicateBodyAcrossIdentitiesto ignore the user-id distinction → 2 failures. The tests pin behavior rather than presence. - Reviews are fetched as full objects (
gh api repos/{repo}/pulls/{n}/reviews --paginate), sobodyis populated. The newoperative[0].body === operative[1].bodycomparison cannot degrade toundefined === undefinedand reject every legitimate pair — the failure mode I went looking for first. - Index access at
:143is guarded by theoperative.length !== 2check on the preceding line.
Suggestions (3)
- [code]
scripts/check-ally-review-consistency.mjs:173—duplicateBodyAcrossIdentitiestreats two bodiless reviews as a duplicate submission. Confirmed by execution: a pair ofbody: null(andbody: "") approvals under different user IDs both returntrue, so a baregh pr review --approvewith no body from each seat is reported as "one verdict, posted twice" — a different defect with a different remedy.I2dalready catches the missing attestation, so this is a message-accuracy issue rather than a missed detection. A truthiness guard ona?.bodywould tighten it. - [types]
scripts/check-ally-review-consistency.mjs:169— signature asymmetry with its neighbour.isRequiredApprovalPair(reviews, headSha)takes the raw review list and filters internally;duplicateBodyAcrossIdentities(operative)takes an already-filtered set. Passingpr.reviewsto it would silently compare dismissed and stale-head reviews and answer the wrong question. The parameter name and JSDoc mitigate this, but the function is also the only export in the file without@param/@returnsannotations, which is where that contract would normally be stated. - [comments]
scripts/check-ally-review-consistency.test.mjs:389— thedescribeopener and its firstitcollapsed onto one line when the new block was inserted above:describe("I1 accepts only the protected-merge approval pair", () => { it("accepts exactly one …. Harmless — no prettier config or format workflow exists in this repo, and the suite passes — but it is inconsistent with every other block in the file and looks like an editing artifact rather than an intentional style.
Strengths
- The change closes a genuine detector blind spot rather than adding a new rule: the defect and its detector were built under the same assumption, and the fix is a two-line predicate at the exact point where the assumption was encoded.
- The negative cases are the valuable ones and they are all present — bodies differ, same identity repeating (a retry, different remedy), and a three-review set that must not borrow the duplicate wording. That last test is what keeps the new message from over-claiming, and mutation testing confirms it fires.
- Splitting the operator-facing message by shape is the right call. "One verdict posted twice" and "two genuinely different reviews" have opposite remedies, and the old bare count could not distinguish them.
- The JSDoc explains why the exemption is narrowed and which case it still exists for, so a future reader cannot mistake the narrowing for an oversight and widen it back.
Recommended Action
- No Critical or Important issues — this is mergeable as-is.
- Consider the three Suggestions opportunistically; the bodiless-pair message is the only one with any operator-visible effect.
…erdict Follow-up to the consolidated review on #1385. Three suggestions, all confirmed against the live repo. 1. `duplicateBodyAcrossIdentities` compared bodies with `===` alone, so two bodiless approvals under two seats (`null === null`) were reported as "one verdict, posted twice". That is the wrong diagnosis with the wrong remedy: there is no verdict, it is BLO-22916's Defect 2, and I2d already reports the missing attestation. Guard on a truthy body. 2. Document the parameter contract. Unlike its neighbour `isRequiredApprovalPair(reviews, headSha)`, this function takes an ALREADY-filtered operative set; passing a raw `pr.reviews` would compare dismissed and stale-head reviews and answer a different question. 3. Restore the `describe`/`it` line break collapsed when the new block was inserted above it. Verification: - `node --test scripts/check-ally-review-consistency.test.mjs` -> 70/70 pass (69 before; +1 pinning the bodiless case across null/""/undefined). - Mutation-checked: dropping the truthiness guard fails that test. - Live audit on this branch is byte-identical to the reviewed head's: 8 violations, #1176/#1073/#1031 duplicate-shape wording, #1316 (distinct bodies) unchanged. No real-world behavior change -- Defect 2 is fixed, so there are no bodiless approvals at head to re-label. Refs BLO-22916
|
Addressed all three suggestions in 1. Bodiless duplicate ( 2. Parameter contract ( 3. Collapsed Verification:
|
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 1a57d8b
Critical Issues (0)
Important Issues (0)
This head is the follow-up to my previous pass at bbeab7ac, which was clean with three Suggestions. All three are addressed, and I re-verified each by execution at this head rather than by reading the patch:
- Bodiless-pair message accuracy —
check-ally-review-consistency.mjs:186now guards withBoolean(a?.body). Executed: abody: nullApp/User approval pair returnsduplicateBodyAcrossIdentities === falseand reportsI1+ twoI2d("an approval with no review behind it") instead of borrowing the duplicate-submission wording. The correct diagnosis, with the correct remedy. Checking onlyais sufficient rather than sloppy —a?.body === b?.bodyalready forcesbtruthy wheneverais. - JSDoc contract —
:175-179now carries the@param/@returnsthe neighbouring exports had, and states the pre-filtered-input requirement explicitly. - Collapsed
describe/it—check-ally-review-consistency.test.mjs:405-406is split back onto separate lines.
Independent verification at this head:
node --test check-ally-review-consistency.test.mjs→ 70/70 pass (69 → 70; the new case is:391).- The new guard is mutation-checked, not just present: dropping
Boolean(a?.body)from:186→ 1 failure. The test pins behavior. isRequiredApprovalPair:143deliberately has no emptiness guard, and that asymmetry with:186is correct rather than an oversight. A bodiless pair failsisExpectedApproval's attestation requirement regardless, so:143only short-circuits a path that was already going to reject — while:186must abstain so the message stays accurate. Executed both ways; no behavioral difference at:143, a real one at:186.
Suggestions (2)
- [code]
scripts/check-ally-review-consistency.mjs:186— byte-equality is brittle to trailing whitespace. Executed against this head: an App/User pair whose bodies differ only by a trailing newline (or a single trailing space) returnsduplicateBodyAcrossIdentities === false,isRequiredApprovalPair === true, and zero violations — audited as SOUND. Same result when the User body is the App body plus one appended line. The named defect mechanism (passing one--body-fileto both calls) does produce byte-identical bodies, so this is not a gap in the case you set out to close — but a.trim()on both sides before comparison would close the whitespace variant for one call's worth of code, and it costs nothing. The substantially-overlapping-body case is a genuinely larger scope question and I would not widen this PR for it. - [comments]
.github/workflows/ally-review-consistency.yml:5-7— the new aside opens with an em-dash and closes with a comma, so the three-item list it interrupts (…that no standing APPROVED masks…, and that a review's body-attested head matches…) reads as a continuation of the aside rather than a resumption of the list. A closing em-dash after(BLO-22916)restores the parse. Prose-only; no effect on the workflow.
Strengths
- The follow-up fixed the diagnosis, not just the predicate. Excluding bodiless pairs from the duplicate wording while still letting
I1/I2dfire keeps the operator-facing distinction the PR's whole premise rests on — that "one verdict posted twice" and "an approval with nothing behind it" have different remedies. - The new test asserts across
null,"", andundefinedin one loop with a body-interpolated failure message, so a regression names which falsy shape broke rather than just failing. - The JSDoc addition documents the hazard of the pre-filtered-input contract (passing raw
pr.reviewswould silently compare dismissed and stale-head reviews) rather than restating the type signature. - Restraint on scope: the incremental commit is 14 lines of source and 18 of tests, touches nothing outside the three suggestions, and leaves the verified detection delta from the previous head intact.
Recommended Action
- No Critical or Important issues — mergeable as-is.
- Both Suggestions are optional. The
.trim()is the only one with any behavioral effect and is a one-line hardening, not a defect.
duplicateBodyAcrossIdentities compared bodies byte-exactly, so an App/User
pair differing only by a trailing newline audited as SOUND. The named defect
mechanism (one --body-file passed to both `gh pr review` calls) does produce
byte-identical bodies, but a stray trailing newline is still one verdict
posted twice.
Normalizing once also closes a hole in the emptiness guard: `Boolean(" ")`
is truthy, so a whitespace-only pair was reported as a duplicate verdict —
contradicting the documented contract that bodiless pairs belong to I2d
("an approval with no review behind it"), whose remedy differs. Guarding on
the trimmed value makes the two tests agree.
Trimming is deliberately the only normalization; substantially-overlapping
bodies are a larger scope question than this predicate should answer.
Also closes the em-dash aside in the workflow header comment, which left the
second and third assertions reading as part of the `since ...` clause rather
than as list items. Comment-only; non-comment bytes are unchanged.
Tests: 70 -> 71. Removing the .trim() fails 2.
Author response to the review at
|
| pair | before | after |
|---|---|---|
| byte-identical | true |
true |
| trailing newline / space / leading newline | false |
true |
| whitespace-only both sides | true |
false |
| genuinely distinct bodies | false |
false |
| App body + appended line | false |
false |
2. Unclosed em-dash aside — fixed.
Confirmed the parse problem: the aside opened with an em-dash and closed with a comma, so the second and third assertions read as continuations of the since … clause. A closing em-dash alone would have consumed the list separator, so I promoted the three top-level items to semicolons and named the count ("Asserts three things about every open PR"), which removes the ambiguity rather than relocating it. Comment-only — verified by diffing non-comment bytes against HEAD, which are identical.
Verification at 12d2f20:
node --test ./scripts/check-ally-review-consistency.test.mjs→ 71/71 pass (70 → 71), the same commandpr.yml:162runs.- Mutation-checked: reverting
.trim()fails 2 tests (the new whitespace case and the extended bodiless case), so both are pinned rather than merely present. - Workflow YAML structure untouched — non-comment bytes byte-identical to
1a57d8b1.
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 12d2f20
Critical Issues (0)
Important Issues (1)
-
[code]
scripts/check-ally-review-consistency.mjs:143— the.trim()landed in a function the whitespace case never reaches, so the defect this commit set out to close is still audited as SOUND.duplicateBodyAcrossIdentitiesis not a gate — it only chooses the wording onceI1has already fired at:210, and:210fires only whenisRequiredApprovalPairreturns false. That function still compares bodies byte-exact at:143, so a whitespace-differing App/User pair is classified as the legitimate distinct-body exemption,I1is never entered, and the newly-trimmed predicate is never consulted.Executed end-to-end through
findPrViolationsat this head, App+UserAPPROVEDat the current head, bodies differing only as noted:User body vs App body isRequiredApprovalPairduplicateBody…findPrViolationsbyte-identical falsetrueI1 duplicate-submission ✅ + "\n"truetrue[]— SOUND ❌+ " "truetrue[]— SOUND ❌"\n" +truetrue[]— SOUND ❌This is the same table I reported at
1a57d8b1as a Suggestion. The predicate now returnstruewhere it used to returnfalse, so the change is real — but it is downstream of the branch that decides the outcome, and the audit result is unchanged.What makes this Important rather than a repeat Suggestion is
check-ally-review-consistency.test.mjs:369. It asserts onduplicateBodyAcrossIdentitiesin isolation and never drives a whitespace variant throughfindPrViolations, so it passes (71/71 green) while the guard stays blind. A future reader sees a green test named "fires when the two bodies differ only in surrounding whitespace" and reasonably concludes the audit catches that shape. It does not — and that false confidence is worse than the original acknowledged gap, which at least documented itself as open.Remedy — trim at the deciding comparison too:
// :143 if ( String(operative[0].body ?? "").trim() === String(operative[1].body ?? "").trim() ) return false;
Verified: all four whitespace variants above then report
I1 … one verdict, posted twice (BLO-22916); genuinely-distinct bodies still pass; the bodiless path is unchanged (I1+ twoI2d, not the duplicate wording) acrossnull,"", and" "; and all 71 existing tests still pass. That last point is itself the evidence for the test gap — a one-line change to the deciding branch is invisible to the entire suite. Please add the assertion at thefindPrViolationslevel, not just the predicate level.
Suggestions (1)
- [types]
scripts/check-ally-review-consistency.mjs:191— the two comparisons now normalize differently (:143byte-exact on raw.body,:191trimmed viaString(… ?? "")). Whichever way the Important finding is resolved, this is worth extracting to one shared helper (normalizedBody(review)) used by both, so the next person changing the equality rule cannot change it in one place only. That is precisely the shape of the bug above.
Strengths
- The trimming rationale in the JSDoc at
:169-180draws the right boundary explicitly — trimming is safe normalization, substantive overlap is a genuinely larger question — and says so rather than leaving a future reader to guess how far to widen it. - The bodiless exclusion survived the rewrite intact, including the
I2d-has-a-different-remedy reasoning, and the test was correctly extended to whitespace-only bodies (" ","\n\n","\t ") alongsidenull/""/undefined. - The workflow comment rewrite at
.github/workflows/ally-review-consistency.yml:1-12fixes the run-on parse I flagged at1a57d8b1: restructuring to "Asserts three things … ; … ; and …" reads correctly, which the closing-em-dash patch I suggested would not have done as cleanly. - The test failure messages interpolate the offending variant, so a regression names which whitespace shape broke.
Recommended Action
- Address the Important finding before merge — apply the same trim at
:143and add afindPrViolations-level test for the whitespace variant. It is a one-line source change plus one test. - Consider the shared-normalizer Suggestion opportunistically; it prevents the two comparisons drifting apart again.
…nstream
The previous commit trimmed bodies in duplicateBodyAcrossIdentities, but that
predicate does not gate anything — it selects the wording after I1 has already
fired, and I1 fires only when isRequiredApprovalPair returns false. That
function still compared raw bodies, so an App/User pair differing only by a
trailing newline was classified as the legitimate distinct-body exemption and
returned SOUND. The trim was real but unreachable for the case it targeted.
Extract normalizedBody(review) and use it at both comparison sites. Keeping one
helper is the actual fix for the class of bug: the two sites must agree on what
"the same body" means, and the deciding one runs first, so normalizing either
alone is a silent no-op rather than a partial improvement.
Behavior, verified end-to-end through findPrViolations:
- `+ "\n"`, `+ " "`, and `"\n" +` variants now report
`I1 … one verdict, posted twice (BLO-22916)`; before, all three returned [].
- Bodies differing in substance still pass, so the two-seat exemption for an
App-authored or CODEOWNERS-gated PR is intact.
- The bodiless path is unchanged across null, "" and " ": I1 with the bare
count plus two I2d, not the duplicate wording, since I2d's remedy is to
post a comment rather than drop a submission.
The regression test asserts through findPrViolations, not against the predicate
in isolation. The existing whitespace unit test passed against the broken build
— a green test on a predicate that decides nothing is what let this ship — so
the new case is checked to fail when the deciding comparison is reverted.
Addresses Ally review feedback on #1385 (Important + Suggestion, both at
scripts/check-ally-review-consistency.mjs). Refs BLO-22916.
|
Both findings were correct. Fixed in 6d4b4e5. Important ( Suggestion ( Verified after the change:
Bodiless path unchanged across On the test gap — this was the more useful half of the finding. You were right that asserting on the predicate in isolation is what let this ship. The new case drives Also ran the guard against the live fleet: it executes clean and reports 8 real violations, including three pairs correctly named with the duplicate-submission wording ( |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 6d4b4e5
Prior Findings Dispositioned (1)
-
prior:12d2f20 important 1 — fixed —
scripts/check-ally-review-consistency.mjs:176— The trim now sits in the branch that decides the outcome:isRequiredApprovalPairshort-circuits onnormalizedBody(operative[0]) === normalizedBody(operative[1]), so a whitespace-differing pair is no longer exempted before the wording predicate is consulted. I re-ran the exact failure table from that review end-to-end throughfindPrViolationsat this head, and every row that previously audited as SOUND now reports the violation:User body vs App body isRequiredApprovalPairfindPrViolationsbyte-identical falseI1 duplicate-submission ✅ + "\n"false(wastrue)I1 … one verdict, posted twice ✅ + " "false(wastrue)I1 … one verdict, posted twice ✅ "\n" +false(wastrue)I1 … one verdict, posted twice ✅ both sides padded falseI1 … one verdict, posted twice ✅ The test gap that made this Important rather than a repeat Suggestion is closed too, and closed at the right level.
check-ally-review-consistency.test.mjs:466drives the whitespace variants throughfindPrViolations, not through the predicate in isolation — so re-introducing the precise defect I reported (restoring the byte-exact comparison at the deciding branch while leaving the downstream predicate trimmed) now fails 1 test, where at12d2f209the identical mutation left all 71 green.
Critical Issues (0)
Important Issues (0)
Verification at this head, by execution rather than from the patch:
-
node --test check-ally-review-consistency.test.mjs→ 73/73 pass (71 → 73). -
Mutation-checked, four ways — each pins behavior, not presence: deleting the deciding line at
:176→ 3 failures; dropping.trim()fromnormalizedBody:147→ 3 failures; restoring the byte-exact comparison at:176only (the prior defect) → 1 failure; dropping thebodies[i] !== ""exclusion at:224→ 1 failure. -
Live delta against
Blockcast/paperclipopen PRs, this branch vsmaster, run just now — purely additive, no false positive:PR masterthis branch #1176 (silent — laundered as SOUND) I1 … one verdict, posted twice (BLO-22916)#1073 (silent — laundered as SOUND) I1 … one verdict, posted twice (BLO-22916)#1031 I1 … expected at most 1 …same violation, duplicate-shape wording #1316 I1 … expected at most 1 …unchanged — distinct bodies correctly keep the old wording 6 violations → 8.
masterwas already red, so this does not turn a green audit red. I confirmed #1031's wording change is accurate rather than incidental: its 6 operative reviews are exactly three App/User pairs with byte-equal bodies (750/750, 797/797, 822/822 chars). -
No collateral behavior change. I ran seven pair shapes through both
masterand this head. Exactly one row moved —identical + attestedgoes SOUND →I1(dup wording). Bodiless pairs (null,"", whitespace-only) still reportI1+ twoI2don both, so the new:176equality does not alter the no-verdict path it could plausibly have caught; the genuine two-seat exemption with distinct bodies still audits SOUND; a same-identity retry still gets the count wording, not the duplicate wording. -
The
bodies[i] !== ""guard is sufficient asymmetry rather than an oversight — it is evaluated only wherebodies[i] === bodies[j], so a non-emptybodies[i]forcesbodies[j]non-empty. Two reviews with undefined user IDs also correctly faila?.user?.id !== b?.user?.idrather than reporting a phantom duplicate.
Suggestions (2)
- [comments]
scripts/check-ally-review-consistency.mjs:245— the singular "one verdict, posted twice" undercounts a multi-pair set. Observed live, not hypothetically: #1031 has three duplicated verdicts across six reviews, and the message still reads posted twice. The remedy it points at is the right one and the6 operative Ally reviewscount is in the same line, so an operator is not misled about scale — but this PR's whole premise is that the wording should name the shape precisely, and here it names a two-review shape for a six-review one. Deriving the pair count would keep the message exact. - [tests]
scripts/check-ally-review-consistency.mjs:147—normalizedBodyis now an exported member of the module's API with no test naming it; its contract is pinned only through its two consumers. That is adequate coverage today (the mutation above fails 3 tests), but it is the one place the equality rule is defined, and the""-for-bodiless return is load-bearing forduplicateBodyAcrossIdentities's exclusion. A three-line direct test would document that contract where a reader looks for it.
Strengths
- The fix landed in the branch that decides, and the JSDoc at
:124-145now says why that matters — that normalizing in only one of the two sites "is not a partial fix but a silent no-op" because the deciding branch runs first. It documents the failure mode of the previous attempt rather than just the current behavior, which is what stops the next reader from re-splitting them. - The test comment at
:457-465records that the earlier attempt kept the whole suite green. Preserving the negative result — that a green suite was compatible with the bug — is what justifies the end-to-end assertion's existence to someone later tempted to simplify it back to a predicate-level check. - Extracting
normalizedBodyresolved the drift hazard I raised as a Suggestion at12d2f209at its root: there is now one definition of "the same body", so the two call sites cannot disagree. - The counterweight test (
still accepts a pair whose bodies differ in substance, not just whitespace) is the one that keeps trimming from collapsing the legitimate two-seat exemption. Its presence is why I can report the live #1316 result as a genuine non-regression rather than an untested assumption. - Scope restraint held across three iterations: the substantive-overlap case is still explicitly out of scope and still says so in the JSDoc, rather than being quietly widened.
Recommended Action
- No Critical or Important issues, and the prior Important finding is fixed and mutation-verified — this is mergeable as-is.
- Both Suggestions are optional and neither affects detection; the multi-pair wording is the only one with operator-visible effect.
Thinking Path
Linked Issues or Issue Description
Refs BLO-22916 (Ally submits every review twice), BLO-27743 (removed the
instruction that mandated it), BLO-19778 (the incident this guard was built for).
What Changed
isRequiredApprovalPairnow rejects a pair whose two bodies arebyte-identical. The exemption still exists for the case it was written for —
a gate that genuinely needs both seats (an App-authored PR, or a
CODEOWNERS/team approver a GitHub App cannot be), where the User seat adds a
short, distinct approval linking to the App's review.
duplicateBodyAcrossIdentitiesexport, and theI1message now names theduplicate-submission shape instead of reporting a bare review count. Left as a
count, an operator reading the hourly audit cannot tell "one verdict posted
twice" from "two genuinely different reviews", and those have opposite
remedies.
three-review set keeps the old wording, plus unit coverage of the new
predicate.
Verification
node --test scripts/check-ally-review-consistency.test.mjs→ 69/69 pass(this is the exact command CI runs,
.github/workflows/pr.yml:162).Mutation-checked, so the tests are known to pin the behavior rather than pass
for an unrelated reason. Deleting only the new guard line:
Restoring it returns 69/69.
Differential run of both checker versions over the exact defect shape:
masterLive fleet run (113 open PRs,
ALLY_REVIEW_REPO=Blockcast/paperclip) — 8residual violations, all pre-dating the 2026-08-16T08:34Z instruction fix:
Non-vacuity control, so the counts are real and not a broken query: 60
operative Ally reviews at head across those 113 PRs.
Risks
Low, and it cannot block a merge: this workflow runs on an hourly
scheduleonly — it is an audit tripwire, not a required check on any PR.
The change is strictly a tightening; it can only add violations, never suppress
one. The distinct-body pair is unaffected (table above).
Two things a reviewer should know rather than discover:
most recent run (
31936821477, 08:35Z) did not fail on a violation at all;it died on
net/http: TLS handshake timeoutfetchingpulls/1167/reviews.A crash and a real violation are indistinguishable in the exit code, which is
worth fixing separately. I could not classify the older runs — their
--log-failedreturns 0 bytes, and I confirmed that is the log beingunavailable rather than the runs being clean by checking a run I knew had
output (6065 bytes, 4 TLS lines).
I1hits above are pre-fix residue on 3 human-authored(
kkroo) PRs, all alreadyreviewDecision=APPROVED. They will clear whenthose PRs merge. They could also be cleared now by dismissing the redundant
User-seat copy — the App approval alone holds the gate on a human-authored PR
— but that touches someone else's PRs, so I have not done it unilaterally.
Say the word and I will.
Known limitation, deliberately not addressed here: the guard checks the
shape of the permitted pair (two identities, distinct bodies, both attesting
the head) but not its necessity — whether a gate actually required two seats.
That needs a
reviewDecisionlookup per PR and is a larger change.Model Used
Claude Opus 5 (
claude-opus-5[1m], 1M context), extended thinking, running asthe Paperclip agent "Ally" via the
claude_k8sadapter with tool use.Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following the relevant issue template