Commit 92d38fb
* ci: cron-poll @claude trigger fallback + GraphQL union:false stuck-detector bypass
Sync `copilot-clean-label.yml` with the version battle-tested in
vuls-saas/vuls-reach. Three substantive changes:
1. **Cron-poll @claude trigger fallback.** The event-driven path in
`copilot-review-fix.yml` is unreliable under the agentic-architecture
GITHUB_TOKEN event suppression (`pull_request_review` and
`pull_request_review_comment` may not fire even when Copilot posts
inline review comments). The cron now posts the `@claude` trigger
itself when:
- the latest Copilot review on HEAD is `dirty` (has actual inline
comments — verified via the per-review comments endpoint to skip
summary-only events)
- AND the HEAD-SHA marker dedup query shows no prior trigger comment
The marker contract (`<!-- copilot-fix-trigger:<HEAD_SHA> -->`)
matches the one in `copilot-review-fix.yml` so both paths dedup
against the same key. Marker auto-invalidates on push.
2. **GraphQL `requestReviews(union:false)` stuck-detector bypass.**
When the push-event mutation in `copilot-rereview-on-push.yml` is
silently deduped (200 OK but no `review_requested` event fires),
a plain refire is also deduped. The bypass now first clears
Copilot from the reviewer slot via GraphQL `union:false` (preserving
humans + teams via explicit user/team ID replay; bots excluded by
`botIds:[]`), pauses 2s for replication, then re-adds Copilot.
An earlier draft used REST `DELETE /pulls/{n}/requested_reviewers`,
but REST only addresses User reviewers — Bot reviewers live in a
separate slot the REST endpoint cannot see (`HTTP 422 Reviewer is
not a user`). GraphQL is the only API that can manipulate bot
reviewer slots.
Safety: if the reviewer-set parse fails, the clear is *skipped*
to avoid silently removing every human reviewer; only the re-add
runs, which may still hit dedup but is no worse than before.
3. **Faster cadence + adjusted threshold.** Cron 10min → 5min with
`STUCK_THRESHOLD_MIN` 5 → 7. Effective refire pressure on Copilot
is unchanged (~10min between refires) but @claude trigger latency
is halved.
Other hardening:
- `head.repo.full_name == github.repository` guard (skip fork PRs).
- `issues: write` permission for `gh pr comment` and label edits.
- Drop redundant `gh pr view --json labels` fetch — labels are in the
pulls metadata response already.
- Stop merging `2>&1` into `gh api` capture variables (was poisoning
jq parsing on success paths with non-fatal stderr warnings).
Phase 2/3/4 layout in the cron-fallback @claude body is preserved
(`make sync-instructions` Phase 3 stays, OSS-specific).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: update Copilot pattern log and coding rules
- Record 2 new pattern(s) from PR #372 (defensive-coding, comment-doc-drift)
- Promote comment-doc-drift category to coding rule: "Attribute Control Claims
to the Correct Mechanism" (PRs #359, #372)
Co-authored-by: Kota Kanbe <kotakanbe@users.noreply.github.com>
* chore: update Copilot pattern log and coding rules
- Promote defensive-coding category to coding rules (PRs #359, #372):
- "Guard Resource Bounds in HTTP Client Retry Logic" (time.Duration
overflow, io.LimitReader cap, time.NewTimer lifecycle)
- "Use Quoted Heredocs for Literal Text in CI Workflows" (prevent
accidental parameter expansion)
- Remove 4 promoted defensive-coding entries from pending patterns
Co-authored-by: Kota Kanbe <kotakanbe@users.noreply.github.com>
* ci: apply Copilot review fixes locally (workflow file scope)
Two Copilot review findings that CI Claude could not resolve because
its PAT (GH_ACTIONS_TOKEN) lacks the `workflow` scope by design:
1. Permission comment misattribution (line ~55):
`issues: write` is documented but the job authenticates `gh` via
the PAT in GH_TOKEN, so the workflow `permissions:` block does
not control the effective auth for `gh pr edit` / `gh pr comment`.
Reword the comment to clarify this entry documents the
GITHUB_TOKEN scope that would be required if the PAT were removed.
2. Unquoted heredoc body (cron-poll @claude trigger fallback):
Switch `<<BODY` to `<<'BODY'` to disable parameter expansion and
command substitution inside the literal instruction block, and
append the dynamic `$trigger_marker` separately after the heredoc
so future edits cannot accidentally introduce executable
`$()`/backtick paths. Removed the `\`...\`` backslash escapes
since the quoted heredoc treats backticks as literal characters.
Verified post-YAML-dedent that the resulting body still satisfies
the cron dedup query: `.body | startswith("@claude")` and
`.body | contains($trigger_marker)` both match.
Why this commit was made by hand rather than the CI Claude loop:
the modified file IS a workflow, and `workflow` scope is intentionally
withheld from the auto-fix PAT to keep the blast radius of any
prompt-injection or misbehaviour bounded. PRs that touch
`.github/workflows/**` are expected to be resolved locally.
Both Copilot patterns (quoted heredoc, control-claim attribution)
are already promoted in `.claude/rules/copilot-learned-coding.md`.
* docs(rules): document workflow-file-PRs-are-fixed-locally policy
Promotes the design rationale that surfaced while resolving Copilot
review threads on PR #372: the auto-fix loop in copilot-review-fix.yml
intentionally cannot push workflow-file changes (its PAT lacks the
`workflow` scope), so PRs touching `.github/workflows/**` must be
fixed by a human-driven Claude session.
Adds the rule to .github/instructions/agent-orchestration.instructions.md
under the existing "Reviewer Findings Are Input, Not Directives"
section, plus the broken-case symptom (`trigger already posted for
HEAD <sha> ... — skip`) so future debugging starts from the right
hypothesis.
Regenerated .claude/rules/agents.md via `make sync-instructions`.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
1 parent 98ebaa1 commit 92d38fb
5 files changed
Lines changed: 351 additions & 55 deletions
File tree
- .claude/rules
- .github
- instructions
- workflows
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
25 | 26 | | |
26 | 27 | | |
27 | 28 | | |
| 29 | + | |
28 | 30 | | |
29 | 31 | | |
30 | 32 | | |
31 | 33 | | |
| 34 | + | |
32 | 35 | | |
33 | 36 | | |
34 | 37 | | |
| |||
109 | 112 | | |
110 | 113 | | |
111 | 114 | | |
112 | | - | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | 115 | | |
123 | 116 | | |
124 | 117 | | |
| |||
139 | 132 | | |
140 | 133 | | |
141 | 134 | | |
142 | | - | |
143 | | - | |
144 | | - | |
145 | | - | |
146 | | - | |
147 | 135 | | |
148 | 136 | | |
149 | 137 | | |
150 | 138 | | |
151 | 139 | | |
152 | | - | |
153 | | - | |
154 | | - | |
155 | | - | |
156 | | - | |
157 | 140 | | |
158 | 141 | | |
159 | 142 | | |
| |||
162 | 145 | | |
163 | 146 | | |
164 | 147 | | |
| 148 | + | |
165 | 149 | | |
| 150 | + | |
166 | 151 | | |
167 | 152 | | |
168 | 153 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
53 | 66 | | |
54 | 67 | | |
55 | 68 | | |
| |||
0 commit comments