fix(claude-code-review): drop the callee's checks: read that startup-fails every caller without it (closes #831) - #832
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fails callers A reusable workflow's job cannot request a permission its caller lacks: the run ends in startup_failure before any job starts. #830 added checks: read to the claude-review job, and the v2 slide onto c07f7d4 killed review dispatch in every consumer that had not granted it. The parity test now pins the model job's permission SET rather than one key, so the next addition of any name fails offline instead of at a consumer's next PR. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ested at v2 Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
F1 The comment claimed the outage ended 'until the tag moved back'. v2 is still c07f7d4; the rollback never happened. Says so, and says plainly that merging fixes nothing until v2 is slid onto the merge commit. F2 '18 consumers' was the count of repos pinning @v2, not the count that broke. Derived: 16 of 18. gha and ucdavis/bcs already had the grant. F3 CLAUDE.md's tag-slide readiness bar still said green-and-none-pending, which c07f7d4 satisfied -- the policy that permitted the incident was the one site not updated. Adds the permission-addition gate, with a command verified to flag the real incident (898a3e2..c07f7d4). F4 The example stub and dogfood caller comments, and a test message, still said the model job reads check runs. It no longer can. F5 The workflows.qmd needle could not show the list 'ends' -- appending the grant left it green. Anchored on the closing paren; mutation-confirmed. Also adds the missing self-test case for an ADDED scope, which nothing in the suite demonstrated; confirmed non-vacuous by weakening the assertion. F6 'the v3 that will request it' now cites #833 at all five sites. F7 Rewrapped the header sentence at a clause boundary. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R2-F1 The '18 consumer repositories' the round-1 sweep missed, in the test
file's own comment -- invisible to a line-based grep because it spans
a line break. Swept by joining comment continuations instead.
R2-F2 CLAUDE.md said consumers 'lost review dispatch until gha#832'. That PR
is unmerged and merging it is not what ends the outage; the same diff
says so twelve lines away. Claim removed.
R2-F3 '16 broke' was the count STILL broken. bcs#966 merged 19:14Z, hours
after the slide, so bcs broke and was then repaired: 17 broke, 16
remain. Corrected at all six sites.
R2-F4 The gate command resolved the tag from a LOCAL ref, which this same
file documents as stale after a slide. Now resolves via ls-remote and
diffs against FETCH_HEAD.
R2-F5 The gate flagged this very PR: a caller's comment-only change on an
unchanged key. Now scoped to workflow_call callees, and labelled a
prompt rather than a gate, with its residual imprecision stated and
#836 filed for the parsed instrument.
R2-F6 'the one breaking change CI cannot see' was a false universal; it is
a family, and the siblings are named.
R2-F7 The round-1 rewrap produced a 128-char header line. Rewrapped.
R2-F8 'recommended but not yet used: ... so the reads fail' read as though
granting stops the 403. Says plainly that at @v2 the reads fail either
way, because the model job does not request the scope.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R3-F1 The residual count decayed while the PR was being written --
ai-config granted checks: read 15 minutes before the review, making
'16 still broken, only bcs has added it' false on both halves. The
consumer docs and changelog now carry only the fixed historical fact
(17 of 18 broke) and point at #831 for the number that moves; the
workflow comment dates its figure. #833's own '18' corrected too.
R3-F2 website/workflows.qmd was the one doc that never got round 2's F8
correction, so it still implied a caller's grant fixes the 403.
R3-F3 The gate globbed *.yml only -- the exact drift workflow_discovery.py
exists for, and untestable here since the tree has no *.yaml
workflow -- and enumerated callees from the working tree while
diffing FETCH_HEAD. Both fixed or disclosed, and the limitation list
now says it is partial.
R3-F4 'changing a required input's default' cannot break a caller: the
default is unreachable. Replaced with the two that do break --
changing an OPTIONAL input's default, and making an optional input
required.
R3-F5 checks: read sat in a must-grant list while the prose below called it
inert; marked '(recommended, see below)'. The reference page's
example stub was the third copy and lacked the comment the other two
gained.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R4-F1 The docs asserted present-tense that the 403 happens whether or not
the caller grants the scope. v2 still points at the commit that DOES
request it, so until the slide a grant is exactly what makes a caller
work -- bcs has been green since 19:15Z on the strength of it. As
written a repaired consumer could read the page and remove the grant.
Now states what holds before the slide, after it, and at the v3.
R4-F2 Three docs named #831 as the live tracker of the remaining count,
and this PR closes #831. Retargeted to #833, which stays open and is
where consumer adoption is the v3 precondition.
R4-F3 '18 repositories pin @v2' names a strictly larger population than the
one measured -- ucdavis/hac.sap pins quarto-publish@v2 and was never
affected. Says 'this workflow at @v2' at all six sites.
R4-F4 The closing-paren anchor guarded only workflows.qmd; the identical
parenthetical in three other docs was unguarded. Now looped over all
four, mutation-confirmed red in each.
R4-F5 perm_block tolerated a trailing comment on the target line but not on
the intermediate ones, so a pure reorder of two correct grants turned
the suite red. Fixed; reorder now passes.
R4-F6 'gha#836 carries the full list' was backwards -- CLAUDE.md's list is
a superset. Reworded to 'carries the reasoning'.
R4-F7 The CI-invisible family omitted renaming or removing a JOB, which is
the one this repo's own reference pages expose consumers to by
telling them to gate branch protection on job names.
R4-F8 '(recommended, see below)' was a forward reference. Replaced with a
self-contained qualifier.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R5-F4 is the substantive one. README already carries 'Widening permissions is a breaking change', with the identical prior incident measured (#685, when #638 added issues: read to ai-code-review.yml and the v2 slide delivered it). My CLAUDE.md addition re-derived that rule without citing it, and prescribed a WEAKER remedy: grep the diff, where README says sweep REVDEPS.md and PR the caller grants BEFORE sliding. An operator following CLAUDE.md alone would have shipped #830 exactly as it shipped. I found this by grepping for 'checks: read' rather than for the concept -- the corpus-gap-from-a-grep trap. CLAUDE.md now defers to README as the authority, adds only the check that makes it fire, and records the actual lesson: the rule was written down with a worked precedent and was not consulted, so the check belongs at the readiness bar that made it feel safe. R5-F1 Four sites still said checks: read is 'not yet used by @v2'. v2 points at the commit that DOES request it, so the grant is currently the only thing keeping a caller alive -- and one of the four is gha's own caller, whose grant is why this repo is the 1-of-18 still working. A maintainer trimming an 'unused' permission would have broken it. R5-F2 The workflow comment still named #831 as the live tracker of a moving count, and this PR closes #831. Retargeted to #833; #831's frozen figure is labelled as frozen and dated. R5-F3 '@v2' meant the tag as it resolves today in one sentence and the tag after the slide six lines later, unmarked. Both now say which. R5-F5 'currently points at' and 'required by the currently-tagged @v2' were undated volatile claims that go false at the slide. Dated. R5-F6 The same point was made three times and #833 linked twice in one paragraph. Duplicate sentence dropped. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R6-F1 The four-doc parity needle was a whitespace-intolerant substring, so
a semantic-line-break reflow -- the edit this repo's own review item 7
asks for -- turned it red claiming the model job holds checks: read.
Regex now tolerates the reflow; still red on an appended grant.
R6-F2 The gate flagged every permission line of a callee ADDED since the
tag, which has no callers to break (measured on
check-code-similarity.yml, new in #728). --diff-filter=M drops those;
the rename consequence is disclosed.
R6-F3 'the model job stops requesting it' was stated twice, six lines apart,
in three files. Merged, with the rationale attached to the first.
R6-F4 workflows.qmd was the one prose site left undated, and the three
consumer-copied stubs justified the grant by a fact that goes false at
the slide -- and then lives forever in every repo that copied them.
Reason is now durable: the v3 reinstates it on the callee.
R6-F5 The exact-set assertion fires on a REMOVAL too but reported it as an
addition needing a v3, contradicting CLAUDE.md.
R6-F6 Breaks fell mid-noun-phrase ('a called' / 'workflow').
R6-F7 The PR body still said 16 and called bcs unaffected -- written before
17 was derived. bcs broke for ~18h. Body rewritten.
R6-F8 'gha#831 ... freezes at 15' made the issue the subject; and the
population count was undated while the figure it counts was dated.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R7-F1 is the substantive one. My bullet's stop action was 'go do the REVDEPS
sweep', and REVDEPS.md lists 4 repos of which 1 names this workflow, while
its owner-scoped fallback omits Morrison-Lab and Lacaedemon -- the org this
repo now lives in. A sweep run during the outage would have found 1 of 18
consumers and reported the rest safe, so the remedy I pointed at would have
reproduced the incident. REVDEPS.md now leads with the unscoped per-workflow
search that actually worked, records why the scoped list is a fallback, and
adds the two missing owners; CLAUDE.md carries the derivation inline rather
than delegating it.
R7-F2 'only additions break callers' missed value escalation: contents: read
to contents: write adds no key and startup-fails every read-only
caller. The grep surfaces it and the prose said to dismiss it.
R7-F4 The workflow comment attributed the figure 15 to #831, whose body says
18 and whose comment said 16; #833 and #829 still said 18. Derivation
posted to all three.
R7-F5 perm_block tolerated trailing comments and reflows but not a full-line
comment inside the block -- which the sibling stub this PR touches
already uses. Mutation-confirmed both ways.
R7-F6 workflows.qmd kept the duplication fixed in the other three files, and
an 'It' whose nearest antecedent was the wrong noun.
R7-F7 'all three phases:' enumerated two; the middle one is now named.
R7-F8 The stub comment gave only the post-slide reason, so it omitted that
the tagged @v2 makes the grant mandatory today -- the mirror of the
round-6 error.
R7-F3 (branch unpushed) resolves with this push; the pre-push guard held it
until a clean verdict.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R8-F1 and R8-F2 are both on my own REVDEPS edit, and F1 is the same class
this PR keeps fixing: I asserted the old owner-scoped sweep would have found
'1 of the 18' without deriving it. Measured, it returns 10 of 18 -- the
figure 1 belonged to the consumer table, a different list. Both figures are
now derived and dated.
R8-F2 The fallback queries could never work: GitHub code search reads a
leading 'uses:' as a qualifier and drops the term, so both returned 0
hits under every owner list -- indistinguishable from no consumers.
Measured 0 with the prefix, 30 without. Prefix dropped.
R8-F3 The tag-slide section's closing Do/Don't still presented green CI as
the whole gate, which is what the new bullet exists to deny.
R8-F4 The consumer-search snippet hard-coded @v2 while the same section says
to derive the major -- and #833 cuts a v3 that would be missed.
R8-F5 CLAUDE.md's enumeration of what run-review-job-split-tests.py pins
omitted this change's central guard, describing the suite as weaker
than it is.
R8-F6 README and website/versioning.qmd -- the sections the new bullet calls
the authority -- still prescribed the REVDEPS sweep this PR documents
as having missed most affected repos.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every finding this round was on a numeric claim I wrote into documentation
without deriving it -- the third round running where that is the dominant
class, and the same failure the PR itself is about.
R9-F1 'the 6 under Morrison-Lab and Lacaedemon plus 2 more' invented a
residual category. Derived: the old five-owner list misses exactly 8,
all under those two owners (Morrison-Lab 7, Lacaedemon 1), and the
corrected list returns all 18.
R9-F2 README and versioning.qmd said 'its owner-scoped fallback returned 10',
dropping REVDEPS.md's own 'pre-2026-09-06' qualifier, so they
discredited the fallback this PR had just fixed. Both now attribute
the 10 to the retired list and say the current one returns 18.
R9-F3 CLAUDE.md still summarized README's remedy as 'sweep REVDEPS.md',
which this PR removed from README -- and contradicted its own text 35
lines later.
R9-F4 The search snippet interpolated $major before the block that assigns
it. Run verbatim it does not error: it drops to an unpinned query,
measured 34 hits against 29, silently widening a blast-radius check.
The assignment moved into the same block.
R9-F6 The --diff-filter=M rationale cited a false positive that cannot be
observed: check-code-similarity.yml predates the current tag, and the
v2..main range adds no workflow at all (11 M, 0 A). The comment now
says the filter drops nothing today and names a range that shows the
shape.
R9-F5 The owner-scoped fallbacks omitted --limit, so gh's default of 30
truncates silently -- the exact failure the surrounding note warns
about.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R10-F1 'The list below ... returns all 18' pointed at the BROAD fallback,
not the pinned query the 18 was derived from. Measured 2026-09-07:
that fallback returns 100 hits across 4 repositories at --limit 100,
and 304 across 28 at --limit 1000 -- so it was truncating exactly as
silently as the default 30, in the block whose own comment claimed
--limit fixed that. Cap raised, the measurement recorded, the
sentence scoped to the pinned query, and a re-raise instruction added
for when the hit count equals the cap.
R10-F2 The pre-slide grep matched only the values read and write, so a block
collapsing to permissions: write-all -- a widening that startup-fails
every narrower caller, and a spelling the suite's own fixture uses --
was invisible. Pattern and prose both widened; verified against a
synthetic write-all line, and confirmed still clean on the live range
and still red on the incident range.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R11-F1 The 'permissions: (read|write)-all' alternative I added last round was
dead code: the value pattern is unanchored, so 'write' already matches
the prefix of 'write-all'. Verified -- the full pattern and the first
alternative alone match an identical set. Removed, and the caveat list
now records what the pattern really does: an INDENTED write-all is
caught, a workflow-level one at column 0 is not, and that gap is
unreachable today because every callee job declares its own block.
R11-F2 'the pre-2026-09-06 owner list' asserted a supersession that never
happened -- git says the OWNERS line last changed 2026-07-28 and the
names 2026-06-18, and the list is replaced by THIS commit. Three
sites now say 'the list this change replaces' and date it from
history. README and versioning.qmd additionally narrated this diff's
own edit in the past tense, which is false on main.
R11-F3 The pre-slide caller search carried --limit 100 with no truncation
caveat, on the one surface where truncation costs an outage. REVDEPS
spells the hazard out; CLAUDE.md now does too, with the measured
busiest count (claude.yml, 29) so the cap is checkable.
R11-F4 REVDEPS's note still framed itself around moving @v1 and cutting @v2.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R12-F1 is the one that matters, and it inverts my own recommendation. The unscoped per-workflow search I had been telling operators to prefer returns 17 of the 18 consumers: reproduced across three runs, it omits d-morrison/rme, a public non-archived repo whose caller does pin this workflow at @v2. The owner-scoped form finds it. Neither form is complete, neither reports dropping anything, and the --limit guard cannot see it because 28 never equals the cap. Following my own instructions before the next slide would therefore have PRed 17 callers, slid the tag, and startup-failed the eighteenth -- the gha#831 outage reproduced by the procedure written to prevent it. Every site now says to run both forms and union them, with the measurement recorded. R12-F2 'the busiest workflow was claude.yml at 29 hits' was wrong on both identity and count -- 29 is claude.yml's UNPINNED figure, while claude-code-review.yml measures 28 pinned and 34 unpinned. The adjacent 34-against-29 pair mixed a scoped and an unscoped count. The specific ceiling is dropped in favour of the mechanical check, since a remembered ceiling is the same defect one level down. Also refreshes the dated consumer figure from the union query: 14 of 18 lack the grant as of 2026-09-07 02:24 PDT (rme added it since the last reading). Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Round 12's headline finding was my own, and it was wrong. I claimed the
unscoped per-workflow search structurally omits a consumer, on three
repeated runs. Re-measured: d-morrison/rme's caller was pushed at 01:55 PDT
(rme#1143), my readings were at ~02:24, and by 02:53 the same query returns
29 hits across 18 with rme present, stable over four runs. The omission was
code-search INDEX LAG, and my three repetitions were three samples of one
stale index inside a ~30-minute window -- repetition is not independent
sampling when the thing sampled is a cache.
All four sites now carry the true lesson instead: the index lags a recent
push, so union the two query forms, treat any count as a floor, and re-run
after a delay when a caller may have changed recently. The owner-list half
of the evidence was solid and is kept.
R13-F2 'Measured 2026-09-06: 0 with the prefix, 30 without' cited 30, which
is gh's default cap -- the exact truncation the next code block in
the same file warns about. Re-measured at --limit 1000: 0 and 304
across 28 repositories. The artifact is now named as one.
The adjacent '28 pinned' figure was stale at 29; the comment no
longer depends on either number.
Also corrects a prose overclaim the reviewer raised as non-blocking:
CLAUDE.md said the model job requests those four keys 'at read and nothing
more', but the exact-set assertion is over KEYS, with values pinned
separately against write. Mutation-confirmed: pull-requests: none passes.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R14-F1 The union instruction referenced ${OWNERS[@]} three lines before the
array was assigned, under a header introducing a different sweep. Followed
in order, bash expands an unset array to zero words, so the 'owner-scoped'
per-workflow query is byte-identical to the unscoped one already run and the
union silently collapses to a single form -- the exact failure the
surrounding note exists to prevent, reproduced inside the instrument written
to prevent it.
The block is reordered so OWNERS is assigned first (both sweeps use it), the
two per-workflow forms are spelled out as real adjacent commands rather than
one command and a comment, and the reason for the ordering is stated so a
later edit does not undo it. Run verbatim in order, both forms now execute:
29 hits / 18 repos each.
Refs #831
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
'returns all 18 -- under the PINNED per-workflow query, not under the broad fallback beside it' reads as saying the broad sweep would miss consumers the pinned query finds. Measured twice on 2026-09-07: the broad sweep returns 304 hits across 28 repositories, and that set is a strict superset of the 18 (pin - broad is empty). The true distinction is not coverage but specificity: the broad form cannot say WHICH callers pin the workflow being changed. Only the truncated --limit 100 run omits any of the 18, and the truncation note beside it already covers that. Reworded to say what actually separates the two forms. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
The @claude review's one finding, non-blocking but real and reproduced: the snippet resolved $tagsha with git ls-remote, which reads the remote without fetching anything, then diffed against that sha after fetching only main. On a shallow clone -- what actions/checkout gives by default, and what the review job itself runs in -- every loop iteration dies with 'fatal: bad object'. Reproduced on a --depth 1 clone and fixed by fetching the tag OBJECT (git fetch --tags --force) and diffing against the tag ref rather than a bare sha. Verified on both a shallow and a full clone: the loop completes, stays clean on v2..main, and still fires on the incident range. --force because a slide moves the tag, which this file already documents elsewhere. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Addressed the shallow-clone finding — thank you, it was real and I reproduced it. The block resolved Fixed by fetching the tag object and diffing against the ref rather than the SHA: git fetch -q --tags --force origin main
tagsha="refs/tags/$major"
Posted by Claude Code (AI agent) --- not written by a human. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
'required by the tagged @v2 now' dates itself with a word rather than a date, and becomes false the moment v2 is slid onto this merge -- which this PR's own body says must happen immediately. These three files are the ones consumers copy verbatim and then keep indefinitely, so a reason that expires is the worst place to put one. The reviewer's failure scenario is the outage this PR exists to prevent: a maintainer auditing unused permissions weeks later checks the stated reason, finds it false, drops the grant, and gets startup-failed by the v3. Reworded to a reason that holds through all three phases. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
I attributed the rme observation to 'a caller edited minutes ago may not be indexed yet'. The measurement rules that out: rme#1143 added only a comment and a checks: read line, leaving the uses: line the query matches on byte-identical since 2026-07-28 (verified from the commit's own patch -- the uses: line appears in neither the + nor the - side). So the document had matched for six weeks and was dropped anyway. That is a reindex DROP of an already-indexed file, not a not-yet-indexed new one, and the difference changes what a reader concludes. Under the old wording, a count that FELL between two readings reads as a consumer having removed its pin, because the stated hazard only covers new callers. All four sites now say a push to any caller's file can drop it until reindexed, and name the falling-count reading explicitly. The remedy was already right -- union the forms, treat counts as a floor, re-run after a delay -- so only the cause and its scope change. Refs #831 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:19 UTC |
|
Claude finished review — View run The most recent prior review comment is confirmed at that URL. I now have everything needed to write the final review. Code Review — #832What changed since the last review roundThe prior round reviewed commit
Verification performed
FindingsNone. Both commits are narrowly scoped, prose-only fixes that directly and correctly address the two non-blocking findings/self-corrections from prior review rounds (the "keep:" comment durability and the code-search index causal explanation), and both factual claims independently verify against the live external repository referenced. The prior round's verdict (comment, posted 2026-09-07T12:12:33Z) was Ready for merge with no findings. That verdict stands — this round adds two accurate, well-scoped prose corrections and introduces no regressions. VerdictReady for merge Structured Review Data (JSON){
"schema_version": "1.1",
"reviewer": "claude",
"commit_sha": "6ec1a62fc907af494ffce718d753a082c6de2fd",
"verdict": "CLEAN",
"findings": [],
"detailed_assessment": "The two new commits since the last round (5df7ab2 rewording the checks: read comment, e7f189e correcting the code-search index causal explanation) are prose-only edits across CLAUDE.md, README.md, REVDEPS.md, website/versioning.qmd, website/reference/claude-code-review.qmd, examples/claude-code-review.yml, and claude-review.yml, verified consistent and free of stale leftover wording.",
"holistic_assessment": "Both new commits directly resolve prior review findings, their central factual claim about d-morrison/rme#1143 was independently confirmed against the live GitHub API rather than trusted, and no regression, scope creep, or integration risk was introduced relative to the already-approved core permission fix."
}Reviewed commit: e7f189e |
Important
Live outage. Review dispatch has been dead in most consumers since the
v2slide to c07f7d4 (#830). Merging this does not fix them --v2must then be slid onto the merge commit.Closes #831.
Cause
A reusable workflow's job cannot request a permission its caller lacks: the run ends in
startup_failurebefore any job starts. #830 addedchecks: readto theclaude-reviewjob of the reusableclaude-code-review.yml, and slidingv2onto it broke every caller without that grant.This repo already documents the rule -- README's Widening permissions is a breaking change -- with the identical prior incident measured in #685. It was not consulted. That, rather than the mechanism, is the durable lesson.
Blast radius, derived
18 repositories pin this workflow at
@v2. At the slide (2026-09-06T00:58Z) onlyMorrison-Lab/ghagrantedchecks: read, because #830 updated the dogfood caller in the same PR -- so the one repo anyone would check first was immunized against the regression it shipped.17 of 18 broke. 15 still lack the grant as of 2026-09-06 22:27 PDT;
ucdavis/bcs(bcs#966, merged 19:14Z, ~18h after the slide) andMorrison-Lab/ai-config(2026-09-07T05:01Z) have since added it.Fix
Drop
checks: readfrom the callee only. Caller-side grants stay everywhere -- they are what keeps callers working until the slide, and what makes thev3(#833) cost nothing after it.Guard
The parity test pins the model job's permission set, so any future addition fails offline. Mutation-verified: adding
checks: read,packages: read, orid-token: write, and removingissues: read, each turn it red; a reflow or reorder does not.CLAUDE.md's tag-slide policy now defers to README's section and adds the pre-slide check that makes it fire, verified to flag the real incident (
898a3e2e..c07f7d45) and stay clean on the current tree.Tradeoff
Reinstates #829 (reopened, rescoped): the reviewer 403s on check-runs and can misreport a clean PR as blocked. A degraded review beats a total outage, and #829's real remedy -- not reading a 403 as "blocked" -- never needed the permission.
Follow-ups: #833 (v3), #836 (instrumented gate), #829 (403 handling).
🤖 Generated with Claude Code