chore(ci): bump spectacles reusable workflows/actions to v0.1.1 - #343
chore(ci): bump spectacles reusable workflows/actions to v0.1.1#343norrietaylor wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughThis PR updates 13 GitHub Actions workflow wrappers to pin norrietaylor/spectacles action and reusable workflow versions from v0.1.0 to v0.1.1. Three execute workflows (haiku, opus, sonnet) introduce check_suite event handling to auto-revise on failed checks, the dispatch workflow changes task labeling to sdd:in-progress with tighter error handling, and all remaining workflows receive simple version bumps. ChangesCheck Suite Auto-Revise Routing
Dispatch Task Label State Transitions
Spectacles Component Version Updates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci-macos.yml:
- Around line 60-73: The boot-e2e job can time out waiting for the single
matching macOS runner; update the workflow so boot-e2e is guaranteed to run
after build-macos or has a larger timeout: either add a dependency on the
build-macos job (e.g. add build-macos to boot-e2e's needs list) to serialize
runner usage, or increase the timeout-minutes value for the boot-e2e job (and
similarly for the other job at lines 119-131) so queue time plus execution fits
within the budget; ensure you modify the boot-e2e job block (job name "boot-e2e"
and its timeout-minutes: 20) and the corresponding other job block accordingly.
In `@scripts/fetch-virtio-kernel.sh`:
- Around line 43-46: The script currently writes a minimal.toml with repo =
"https://github.com/gominimal/pkgs" and branch = "main" (the heredoc to
"$TMP/proj/.minimal/minimal.toml"), which lets `minimal update` track live main;
change this to pin the promoted/pinned ref for the package source used to
resolve virtio-linux instead of "main". Update the heredoc so the [upstream]
branch (or a new ref field) uses the specific promoted commit/tag/sha you
resolved from the CLI metadata, and ensure any subsequent code that calls
`minimal update` or fetches the virtio-linux package uses that pinned ref (the
same promoted ref used to resolve the CLI) rather than tracking main; apply the
same change for the second occurrence that writes minimal.toml later in the
script.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5be12ae3-74b4-403a-abff-550c0d47e05c
📒 Files selected for processing (15)
.github/workflows/ci-macos.yml.github/workflows/distillery-sync.yml.github/workflows/sdd-dispatch.yml.github/workflows/sdd-execute-haiku.yml.github/workflows/sdd-execute-opus.yml.github/workflows/sdd-execute-sonnet.yml.github/workflows/sdd-monitor.yml.github/workflows/sdd-pr-sanitize.yml.github/workflows/sdd-review.yml.github/workflows/sdd-spec.yml.github/workflows/sdd-triage-dedupe-tasks.yml.github/workflows/sdd-triage-promote-ready.yml.github/workflows/sdd-triage.yml.github/workflows/sdd-validate.ymlscripts/fetch-virtio-kernel.sh
Re-render all 13 thin wrappers from the spectacles v0.1.1 sources via
quick-setup's ref rewrite. This bumps the hosted reusable-workflow and
composite-action pins from @v0.1.0 to @v0.1.1 AND pulls the v0.1.1
wrapper-body changes (not just the version string):
- sdd-dispatch, sdd-execute-{haiku,sonnet,opus}: v0.1.1 wrapper-body updates
- distillery-sync: grant discussions: write and pull-requests: write on the
nested job permissions to match the lock's job permissions (spectacles 899c74f)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
02e1806 to
873ffd6
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/sdd-dispatch.yml:
- Around line 231-242: The current catch around github.rest.issues.removeLabel
swallows all errors; change it to only tolerate a 404 ("label not found") by
inspecting the error (err) returned by github.rest.issues.removeLabel and
logging the info only when the HTTP status or error code indicates 404; for any
other error (permission/API/transient), rethrow or call core.setFailed so the
job fails. Update the catch block that references
github.rest.issues.removeLabel, core.info and err to perform the conditional
handling (log+ignore for 404, propagate/fail for others).
In @.github/workflows/sdd-execute-haiku.yml:
- Around line 68-76: The new check_suite path is currently using github.run_id
in concurrency.group which allows parallel revise runs; update the
concurrency.group expression to use the associated PR number
(github.event.check_suite.pull_requests[0].number) and fall back to the
branch/ref (github.ref_name or github.ref) so check_suite events are keyed
per-PR/branch; locate the concurrency block (concurrency.group) and replace the
github.run_id key with a conditional expression that uses
github.event.check_suite.pull_requests[0].number if present, otherwise uses the
branch/ref.
In @.github/workflows/sdd-execute-opus.yml:
- Around line 68-76: The check_suite path uses the volatile github.run_id in the
concurrency.group which allows parallel /revise runs; update the concurrency
configuration for the check_suite job to use a stable PR/branch-derived key
(e.g., based on the pull request number or branch/ref) instead of github.run_id
so it joins the existing dedupe group used by the haiku wrapper; apply the same
change to the other similar block referenced (the second concurrency definition
around lines 144-171) so both check_suite entries share the stable concurrency
key.
In @.github/workflows/sdd-execute-sonnet.yml:
- Around line 68-76: The workflow's concurrency.group falls back to
github.run_id for the new check_suite path, allowing parallel /revise runs;
update the concurrency.group logic to include a stable key for check_suite
events (e.g., use github.ref or the PR number + 'sdd' identifier) so runs for
the same sdd/ PR share a single concurrency group; apply the same change to the
other concurrency.group occurrence mentioned (lines ~144-171) so both places
dedupe check_suite events consistently; adjust any conditional branches that
build the group string (identify and modify the concurrency.group expression and
the check_suite event handling) to return the stable key instead of
github.run_id.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7c1e87b0-fc9f-4281-933c-b237cef54a48
📒 Files selected for processing (13)
.github/workflows/distillery-sync.yml.github/workflows/sdd-dispatch.yml.github/workflows/sdd-execute-haiku.yml.github/workflows/sdd-execute-opus.yml.github/workflows/sdd-execute-sonnet.yml.github/workflows/sdd-monitor.yml.github/workflows/sdd-pr-sanitize.yml.github/workflows/sdd-review.yml.github/workflows/sdd-spec.yml.github/workflows/sdd-triage-dedupe-tasks.yml.github/workflows/sdd-triage-promote-ready.yml.github/workflows/sdd-triage.yml.github/workflows/sdd-validate.yml
| try { | ||
| await github.rest.issues.removeLabel({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: task, | ||
| name: 'sdd:ready', | ||
| }); | ||
| } catch (err) { | ||
| // A 404 here means sdd:ready was not present; ignore. | ||
| core.info('Could not remove sdd:ready from #' + task + ': ' | ||
| + err.message); | ||
| } |
There was a problem hiding this comment.
Handle only 404 as tolerated when removing sdd:ready
Line 231 currently swallows all removeLabel failures, but the intended behavior is to tolerate only “label absent” (404). Non-404 errors (permission/API/transient failures) should fail the job so dispatch state drift is visible.
Suggested fix
if (inProgressPresent) {
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: task,
name: 'sdd:ready',
});
} catch (err) {
- // A 404 here means sdd:ready was not present; ignore.
- core.info('Could not remove sdd:ready from #' + task + ': '
- + err.message);
+ // A 404 here means sdd:ready was not present; ignore.
+ if (err.status === 404) {
+ core.info('sdd:ready already absent on #' + task);
+ } else {
+ throw err;
+ }
}
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sdd-dispatch.yml around lines 231 - 242, The current catch
around github.rest.issues.removeLabel swallows all errors; change it to only
tolerate a 404 ("label not found") by inspecting the error (err) returned by
github.rest.issues.removeLabel and logging the info only when the HTTP status or
error code indicates 404; for any other error (permission/API/transient),
rethrow or call core.setFailed so the job fails. Update the catch block that
references github.rest.issues.removeLabel, core.info and err to perform the
conditional handling (log+ignore for 404, propagate/fail for others).
There was a problem hiding this comment.
@CodeRabbit create an issue in the upstream repo
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
gh issue create \
--repo norrietaylor/spectacles \
--title "fix(sdd-dispatch): scope removeLabel 404 tolerance in dispatch job" \
--assignee norrietaylor \
--body "## Summary
In \`sdd-dispatch\`'s \`dispatch\` job, the catch block around \`github.rest.issues.removeLabel\` (for \`sdd:ready\`) currently swallows **all** errors. The intended behavior is to tolerate only a \`404\` (label already absent) and propagate any other status (permission errors, transient API failures, etc.) so that dispatch state drift is immediately visible as a job failure.
## Details
The \`addLabels\` call for \`sdd:in-progress\` correctly inspects \`err.status === 422\` and rethrows anything else. The paired \`removeLabel\` call for \`sdd:ready\` should apply the same principle, inspecting \`err.status === 404\` and rethrowing (or calling \`core.setFailed\`) for all other statuses.
**Proposed fix:**
\`\`\`js
} catch (err) {
// A 404 here means sdd:ready was not present; ignore.
if (err.status === 404) {
core.info('sdd:ready already absent on #' + task);
} else {
throw err;
}
}
\`\`\`
## References
- Flagged in: https://github.com/gominimal/minimal/pull/343#discussion_r3357870567
- PR context: https://github.com/gominimal/minimal/pull/343
- Reported by: `@norrietaylor`"Length of output: 1624
🏁 Script executed:
#!/bin/bash
gh issue create \
--repo norrietaylor/spectacles \
--title "fix(sdd-dispatch): scope removeLabel 404 tolerance in dispatch job" \
--body "## Summary
In \`sdd-dispatch\`'s \`dispatch\` job, the catch block around \`github.rest.issues.removeLabel\` (for \`sdd:ready\`) currently swallows **all** errors. The intended behavior is to tolerate only a \`404\` (label already absent) and propagate any other status (permission errors, transient API failures, etc.) so that dispatch state drift is immediately visible as a job failure.
## Details
The \`addLabels\` call for \`sdd:in-progress\` correctly inspects \`err.status === 422\` and rethrows anything else. The paired \`removeLabel\` call for \`sdd:ready\` should apply the same principle, inspecting \`err.status === 404\` and rethrowing (or calling \`core.setFailed\`) for all other statuses.
**Proposed fix:**
\`\`\`js
} catch (err) {
// A 404 here means sdd:ready was not present; ignore.
if (err.status === 404) {
core.info('sdd:ready already absent on #' + task);
} else {
throw err;
}
}
\`\`\`
## References
- Flagged in: https://github.com/gominimal/minimal/pull/343#discussion_r3357870567
- PR context: https://github.com/gominimal/minimal/pull/343
- Reported by: `@norrietaylor`"Length of output: 1375
@norrietaylor — done! Issue filed at norrietaylor/spectacles#225: fix(sdd-dispatch): scope removeLabel 404 tolerance in dispatch job.
🧠 Learnings used
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:59.044Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:50.429Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-opus.md:55-56
Timestamp: 2026-05-20T23:24:35.034Z
Learning: In the spectacles SDD fast-path flow (ADR 0012), the lifecycle label transition for the tracking issue is a deliberate two-step process: (1) when the stub spec PR merges, `sdd-spec` (step 8 stub-merge handler) moves the tracking issue from `sdd:fastpath-review → sdd:fastpath`; (2) when a human issues `/approve`, `sdd-spec` dispatches `sdd-execute-{tier}` and moves the tracking issue from `sdd:fastpath → sdd:in-progress`. Therefore, at the moment `sdd-execute` runs, the tracking issue carries `sdd:fastpath` (not `sdd:fastpath-review`), and the `remove-labels` allowlist only needing `sdd:fastpath` (not `sdd:fastpath-review`) is correct. The prose in `sdd-execute-*.md` describing "sdd:fastpath → sdd:in-progress" and the allowlist `[sdd:ready, sdd:review, sdd:fastpath, sdd:in-progress]` are intentional and correct.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/api-surface-drift.lock.yml : `api-surface-drift` chore must file one issue per surface change with label `agent:api-drift` on fuzzy weekly Tuesday and `pull_request` on source (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-fix.lock.yml : `worker-fix` chore must produce draft PRs fixing one open `agent:*` issue per run
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/*.yml : Audit chores cap at 1 issue per run (3 for `test-coverage-detector`); older open issues with the same `agent:*` label must be closed in-place when a new one is filed
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 302
File: workflows/pr-conflict-resolver.md:87-103
Timestamp: 2026-05-25T17:10:07.450Z
Learning: In `gominimal/min-aw` side-repo-ops workflows (e.g., `workflows/pr-conflict-resolver.md`, `worker-iterate.md`, `worker-fix.md`), the "Validate dispatch inputs (target-repo / target-ref)" step intentionally carries `if: ${{ github.event_name == 'workflow_dispatch' }}`. On a `schedule` run, `target-repo` resolves to the hardcoded literal default (e.g., `gominimal/minimal`), which trivially passes the regex — making the check a no-op. The guard correctly scopes validation to the only path that carries untrusted user input (manual dispatch). Do not flag this conditional as missing validation on schedule runs.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/test-coverage-detector.lock.yml : `test-coverage-detector` chore must file up to 3 issues for untested high-complexity paths with label `agent:coverage` on fuzzy weekly Tuesday and `pull_request: closed` (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/dependency-review.lock.yml : `dependency-review` chore must file one issue per advisory or semver concern with label `agent:dep-drift` on `pull_request` to lockfile and fuzzy twice-weekly (Rust targets today; Go/Node next)
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 305
File: .github/workflows/pr-nudge.lock.yml:0-0
Timestamp: 2026-05-26T15:16:24.947Z
Learning: In gominimal/min-aw, `workflow_dispatch` inputs (e.g. `target-repo`, `stale-after-days`) cannot use a native `pattern:` constraint, so the accepted pattern is to add a host-side `steps:` validate block in the source `.md` workflow that regex-checks the input (e.g. `^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$` for `target-repo`, numeric range check for `stale-after-days`) and exits with `exit 1` on failure — BEFORE any safe-outputs config heredoc or GitHub App token mint step. The reference implementation is `chore-error-quality-rust`; the same guard was added to `pr-nudge` in commit 1f144bf. As of PR `#305`, 11 of the 13 side-repo-ops chores still lack this pre-heredoc validation guard (only `chore-error-quality-rust` and `pr-nudge` have it). A separate hardening sweep is planned to cover the remaining chores.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/dependency-review.lock.yml : Label taxonomy: `agent:dep-drift` is filed by `dependency-review` chore and indicates a dependency advisory or semver concern needs review
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Applies to .github/labels.yml : Only the following `agent:*` issue labels are permitted: `agent:doc-drift` (filed by `docs-patrol`), `agent:coverage` (filed by `test-coverage-detector`), `agent:dep-drift` (filed by `dependency-review`), `agent:api-drift` (filed by `api-surface-drift`), and `agent:not-gating-audit` (filed by `not-gating-audit` against `gominimal/min-aw`).
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/api-surface-drift.lock.yml : Label taxonomy: `agent:api-drift` is filed by `api-surface-drift` chore and indicates an external API surface this repo depends on has changed
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 8
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:26:56.756Z
Learning: In gominimal/ch-oracles, the planned approach for SHA-pinning all GitHub Actions `uses:` references repo-wide is a dedicated follow-up PR that enables Dependabot `package-ecosystem: github-actions` to flip every `uses:` in `.github/workflows/` to immutable commit SHAs in one atomic pass. Until that follow-up lands, hand-edited workflows continue to use floating version tags (e.g., `v4`, `v5`). During code review, do not flag individual new jobs/steps in hand-edited workflows for missing SHA pins or missing `persist-credentials: false`; defer those to the repo-wide hardening PR.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:42:27.432Z
Learning: In gominimal/spectacles, `.github/workflows/lint.yml` is the only hand-authored workflow. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. The hand-authored `lint.yml` intentionally uses tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` across all jobs — this is an accepted convention in the file, not a per-job deficiency. Hardening it is a repo-wide change tracked as a separate follow-up, not scoped to individual jobs or PRs.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 7
File: .github/workflows/lint.yml:53-54
Timestamp: 2026-05-21T01:24:10.250Z
Learning: In gominimal/ch-oracles, the five hand-edited CI workflow files — lint.yml, codeql.yml, docs.yml, gh-aw-validate.yml, and dogfood-md-sync.yml — all intentionally use mutable action version tags (e.g., v4, v5) and do not set persist-credentials: false. This is a deliberate, uniform repo-wide convention for hand-edited helpers. Only the compiled .lock.yml files (generated by `gh aw compile`) are SHA-pinned. During code review, do not flag individual jobs in these five files for missing SHA pins or missing persist-credentials: false; any hardening should be done in a dedicated repo-wide change covering all five files at once.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:55:34.788Z
Learning: In gominimal/spectacles, the following are all hand-authored workflow files: `.github/workflows/lint.yml`, `.github/workflows/docs.yml`, `.github/workflows/leak-scan.yml`, and `.github/workflows/pages.yml`. All of them use tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` — this is an intentional, repo-wide convention. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. Reviewers should not flag tag-based refs or missing `persist-credentials: false` in any of these hand-authored workflows as a per-PR or per-job deficiency; hardening is a separate repo-wide follow-up.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 97
File: .github/workflows/sdd-spec.lock.yml:708-709
Timestamp: 2026-05-20T21:46:31.814Z
Learning: In the `norrietaylor/spectacles` repository, `sdd-*` workflow source files import shared fragments (e.g., `shared/sdd-interaction.md`) pinned to `main`. When a PR updates a shared fragment, compiled lock files (`*.lock.yml`) cannot fully inline the updated fragment content until the PR merges to `main` and downstream workflows recompile. It is by design that a lock file in a PR only carries the minimum change possible (e.g., a literal string update) rather than the full inlined contract update, to avoid temporarily depinning the `main` import and breaking the reproducibility guarantee. Do not flag this as an out-of-sync lock file — it is the expected state for in-flight PRs.
Learnt from: CR
Repo: gominimal/homebrew-skunkworks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-08T05:18:16.535Z
Learning: PR titles must match the leading commit message; bot PR titles follow format `chore(formula): bump minctl to <version>`
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Chore prompts in `.github/workflows/<chore>.lock.yml` import shared fragments from `gominimal/min-aw/shared/` at compile time; edit fragments in source-of-truth repo and run `gh aw update --source gominimal/min-aw@<newer-tag>` to pull new compiled lock files
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 216
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-05-19T00:22:09.330Z
Learning: In gominimal/min-aw, CodeRabbit automatically reviews bot-authored PRs (e.g. those opened by worker-fix / gominimal-aw-bot[bot]) without requiring an explicit `coderabbitai review` trigger comment. This has been confirmed on PRs `#208`, `#209`, and `#211`. Do not suggest adding a `gh pr comment <pr-number> --body "coderabbitai review"` step to the worker-fix or similar agentic workflows in this repo — the trigger is unnecessary.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 10
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:21:42.608Z
Learning: In the gominimal/ch-oracles repository, hand-edited CI workflow files (lint.yml, codeql.yml, docs.yml, dogfood-md-sync.yml, gh-aw-validate.yml) intentionally use unpinned action tags (e.g. actions/checkoutv4) as a repo-wide convention. Only the compiled gh-aw lock files (.github/workflows/*.lock.yml) are SHA-pinned. Suggesting action pinning for individual jobs in hand-edited workflows is out of scope; a dedicated CI-hardening PR covering the whole repo is the intended approach.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 11
File: .github/workflows/install-smoke.yml:33-37
Timestamp: 2026-05-21T01:21:30.994Z
Learning: In the gominimal/ch-oracles repository, all hand-edited GitHub Actions workflow files (lint.yml, docs.yml, gh-aw-validate.yml, dogfood-md-sync.yml, install-smoke.yml, etc.) intentionally use floating action version tags (v3/v4/v5). Only gh-aw-compiled *.lock.yml files pin actions to full commit SHAs, because gh-aw injects those pins at compile time. Do not flag unpinned actions or missing persist-credentials: false in hand-edited workflows in this repo; any hardening of that kind should be done repo-wide in a dedicated change, not on individual PRs.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-17
Timestamp: 2026-06-01T16:56:00.842Z
Learning: In the gominimal/minimal repo, follow the existing convention: don’t harden individual `actions/checkout` steps by adding `persist-credentials: false` only in one workflow/step. If you determine the repo needs this hardening, apply it consistently as a repo-wide change across all GitHub workflow files so every `actions/checkout` step uses the same setting.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-15
Timestamp: 2026-06-01T16:56:37.746Z
Learning: In this repository, GitHub Actions used in workflow files are pinned by version tag (e.g., `v6`, `v5`, `v3`, `v2`) rather than by commit SHA. During code review, follow the repo-wide convention: do not request SHA pinning for individual `uses:` references in `.github/workflows/*.yml` unless the repo has explicitly adopted a SHA-pinning policy.
| # A check suite that completed on a pull request this agent opened. A | ||
| # failure conclusion on an `sdd/` branch is treated as an implicit | ||
| # /revise (issue #203): a required CI check failed and merge is BLOCKED, | ||
| # so the build is handed back to sdd-execute to fix on the same branch, | ||
| # mirroring the CHANGES_REQUESTED path. A success/neutral suite does not | ||
| # trigger a revise. The route step bounds the retries and escalates with | ||
| # needs-human after the cap. | ||
| check_suite: | ||
| types: [completed] |
There was a problem hiding this comment.
Add a stable concurrency key for the new check_suite path.
These new events currently fall through to github.run_id in concurrency.group, so two failing suites on the same sdd/ PR can launch parallel /revise runs against the same branch. Key this path by the associated PR (or branch as a fallback) so it stays in the existing per-task/per-tier dedupe lane.
Suggested follow-up
concurrency:
- group: sdd-execute-haiku-${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
+ group: sdd-execute-haiku-${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}Also applies to: 144-171
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sdd-execute-haiku.yml around lines 68 - 76, The new
check_suite path is currently using github.run_id in concurrency.group which
allows parallel revise runs; update the concurrency.group expression to use the
associated PR number (github.event.check_suite.pull_requests[0].number) and fall
back to the branch/ref (github.ref_name or github.ref) so check_suite events are
keyed per-PR/branch; locate the concurrency block (concurrency.group) and
replace the github.run_id key with a conditional expression that uses
github.event.check_suite.pull_requests[0].number if present, otherwise uses the
branch/ref.
There was a problem hiding this comment.
@CodeRabbit create an issue in the upstream repo
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
gh issue create \
--repo norrietaylor/spectacles \
--title "fix(sdd-execute): add stable concurrency key for check_suite revise path" \
--body "## Summary
The \`sdd-execute-{haiku,sonnet,opus}\` wrapper workflows added a \`check_suite: completed\` trigger in [gominimal/minimal#343](https://github.com/gominimal/minimal/pull/343), but the \`concurrency.group\` expression for that event path falls through to \`github.run_id\`. This means two failing check suites on the same \`sdd/\` PR can launch parallel \`/revise\` runs against the same branch, defeating the per-task/per-tier deduplication the concurrency block is designed to provide.
## Suggested fix
Key the \`check_suite\` path by the associated PR number (falling back to the head branch) so it lands in the same dedupe lane as other events for the same task:
\`\`\`diff
concurrency:
- group: sdd-execute-haiku-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
+ group: sdd-execute-haiku-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
\`\`\`
The same fix applies to \`sdd-execute-sonnet.yml\` and \`sdd-execute-opus.yml\`.
## References
- Flagged in: https://github.com/gominimal/minimal/pull/343#discussion_r3357870577
- Requested by: `@norrietaylor`
" \
--assignee norrietaylorLength of output: 2369
🏁 Script executed:
#!/bin/bash
# Check if the issue was created despite the assignee error
gh issue list --repo norrietaylor/spectacles --search "add stable concurrency key for check_suite" --json number,title,urlLength of output: 401
@norrietaylor — done! The issue has been filed in the upstream repo:
(The assignee couldn't be set automatically due to integration permissions — you can assign it manually.)
🧠 Learnings used
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/test-coverage-detector.lock.yml : `test-coverage-detector` chore must file up to 3 issues for untested high-complexity paths with label `agent:coverage` on fuzzy weekly Tuesday and `pull_request: closed` (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Chore workflows must not appear in `required_status_checks`. Branch protection depends only on the existing CI, per ADR 0001. The `not-gating-audit` chore on `gominimal/min-aw` actively defends this and files an issue if drift is detected on any target.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/api-surface-drift.lock.yml : `api-surface-drift` chore must file one issue per surface change with label `agent:api-drift` on fuzzy weekly Tuesday and `pull_request` on source (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/*.yml : Audit chores cap at 1 issue per run (3 for `test-coverage-detector`); older open issues with the same `agent:*` label must be closed in-place when a new one is filed
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-iterate.lock.yml : `worker-iterate` chore pushes commits to existing `worker-fix` PR branches addressing CodeRabbit review feedback and replies inline per the saved-memory rule
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 305
File: .github/workflows/pr-nudge.lock.yml:0-0
Timestamp: 2026-05-26T15:16:24.947Z
Learning: In gominimal/min-aw, `workflow_dispatch` inputs (e.g. `target-repo`, `stale-after-days`) cannot use a native `pattern:` constraint, so the accepted pattern is to add a host-side `steps:` validate block in the source `.md` workflow that regex-checks the input (e.g. `^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$` for `target-repo`, numeric range check for `stale-after-days`) and exits with `exit 1` on failure — BEFORE any safe-outputs config heredoc or GitHub App token mint step. The reference implementation is `chore-error-quality-rust`; the same guard was added to `pr-nudge` in commit 1f144bf. As of PR `#305`, 11 of the 13 side-repo-ops chores still lack this pre-heredoc validation guard (only `chore-error-quality-rust` and `pr-nudge` have it). A separate hardening sweep is planned to cover the remaining chores.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:59.044Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:50.429Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 257
File: .github/workflows/worker-fix.md:17-26
Timestamp: 2026-05-21T23:07:43.561Z
Learning: In gominimal/min-aw workflows (e.g., `.github/workflows/worker-fix.md`), gh-aw injects custom `steps:` AFTER its own checkout step. Therefore, preflight validation steps added under `steps:` cannot guard the checkout itself; they guard safe-outputs target-repo routing and the agent prompt. This is an intentional limitation — pre-checkout guards would require forking gh-aw.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-fix.lock.yml : `worker-fix` chore must produce draft PRs fixing one open `agent:*` issue per run
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/dependency-review.lock.yml : `dependency-review` chore must file one issue per advisory or semver concern with label `agent:dep-drift` on `pull_request` to lockfile and fuzzy twice-weekly (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Audit chores must cap at 1 issue per run (3 for `test-coverage-detector` only); fix chores must cap at 1 PR per run. Older open issues with the same `agent:*` label are closed in-place when a new one is filed (`close-older-issues: true`).
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 216
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-05-19T00:22:09.330Z
Learning: In gominimal/min-aw, CodeRabbit automatically reviews bot-authored PRs (e.g. those opened by worker-fix / gominimal-aw-bot[bot]) without requiring an explicit `coderabbitai review` trigger comment. This has been confirmed on PRs `#208`, `#209`, and `#211`. Do not suggest adding a `gh pr comment <pr-number> --body "coderabbitai review"` step to the worker-fix or similar agentic workflows in this repo — the trigger is unnecessary.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 331
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-06-02T04:41:33.104Z
Learning: In gominimal/min-aw worker-fix workflows (workflows/worker-fix.md and .github/workflows/worker-fix.md), the `in:body "/issues/<n>"` search_pull_requests query is intentionally kept as a *dedup/scan signal* (to catch prior PR bodies that contain a raw GitHub issue URL) and is distinct from the *closing-keyword recommendation*. The closing keyword is mandated as plain-text `Closes #<n>` on its own line (no backticks, no code spans, no raw URL form). Do not conflate the scan query with endorsing raw issue URLs as valid GitHub closing-keyword syntax.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 8
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:26:56.756Z
Learning: In gominimal/ch-oracles, the planned approach for SHA-pinning all GitHub Actions `uses:` references repo-wide is a dedicated follow-up PR that enables Dependabot `package-ecosystem: github-actions` to flip every `uses:` in `.github/workflows/` to immutable commit SHAs in one atomic pass. Until that follow-up lands, hand-edited workflows continue to use floating version tags (e.g., `v4`, `v5`). During code review, do not flag individual new jobs/steps in hand-edited workflows for missing SHA pins or missing `persist-credentials: false`; defer those to the repo-wide hardening PR.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 302
File: workflows/pr-conflict-resolver.md:87-103
Timestamp: 2026-05-25T17:10:07.450Z
Learning: In `gominimal/min-aw` side-repo-ops workflows (e.g., `workflows/pr-conflict-resolver.md`, `worker-iterate.md`, `worker-fix.md`), the "Validate dispatch inputs (target-repo / target-ref)" step intentionally carries `if: ${{ github.event_name == 'workflow_dispatch' }}`. On a `schedule` run, `target-repo` resolves to the hardcoded literal default (e.g., `gominimal/minimal`), which trivially passes the regex — making the check a no-op. The guard correctly scopes validation to the only path that carries untrusted user input (manual dispatch). Do not flag this conditional as missing validation on schedule runs.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/trivial-dep-bump.lock.yml : `trivial-dep-bump` chore must create one PR with patch-level lockfile bumps, auto-merged via `safe-outputs.create-pull-request.auto-merge: true` once CI is green (Rust targets today; Go/Node next)
Learnt from: norrietaylor
Repo: gominimal/minimal-vm-image PR: 12
File: .github/workflows/build.yml:18-43
Timestamp: 2026-05-09T02:06:30.499Z
Learning: In gominimal/minimal-vm-image, only the **chore-suite subset** of `.github/workflows/` is template-managed from `gominimal/min-aw`: specifically any workflow that has a corresponding upstream `.md` source file (e.g. `worker-fix.md`, `worker-iterate.md`, `sync-from-source-of-truth.md`) and its compiled `.lock.yml` sibling. These files carry an explicit `# Managed by gominimal/min-aw. Edit upstream; do not modify locally.` header and are overwritten by the weekly sync workflow.
Workflows that are **locally owned** (no upstream `.md` source, no managed header) — such as `build.yml` — are NOT touched by the sync script (`gominimal/min-aw/scripts/sync-workflows.sh` → `fetch_workflow_list` enumerates upstream-listed `.md` sources only; a deletion-safety fix preserves target-repo-owned workflows). Local edits to these files persist across sync runs.
`build.yml` carries an explicit `# Provenance: LOCAL to gominimal/minimal-vm-image (NOT template-managed).` header (added in commit b8f0ee7) to make this distinction unambiguous for future reviewers.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:42:27.432Z
Learning: In gominimal/spectacles, `.github/workflows/lint.yml` is the only hand-authored workflow. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. The hand-authored `lint.yml` intentionally uses tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` across all jobs — this is an accepted convention in the file, not a per-job deficiency. Hardening it is a repo-wide change tracked as a separate follow-up, not scoped to individual jobs or PRs.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:55:34.788Z
Learning: In gominimal/spectacles, the following are all hand-authored workflow files: `.github/workflows/lint.yml`, `.github/workflows/docs.yml`, `.github/workflows/leak-scan.yml`, and `.github/workflows/pages.yml`. All of them use tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` — this is an intentional, repo-wide convention. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. Reviewers should not flag tag-based refs or missing `persist-credentials: false` in any of these hand-authored workflows as a per-PR or per-job deficiency; hardening is a separate repo-wide follow-up.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 97
File: .github/workflows/sdd-spec.lock.yml:708-709
Timestamp: 2026-05-20T21:46:31.814Z
Learning: In the `norrietaylor/spectacles` repository, `sdd-*` workflow source files import shared fragments (e.g., `shared/sdd-interaction.md`) pinned to `main`. When a PR updates a shared fragment, compiled lock files (`*.lock.yml`) cannot fully inline the updated fragment content until the PR merges to `main` and downstream workflows recompile. It is by design that a lock file in a PR only carries the minimum change possible (e.g., a literal string update) rather than the full inlined contract update, to avoid temporarily depinning the `main` import and breaking the reproducibility guarantee. Do not flag this as an out-of-sync lock file — it is the expected state for in-flight PRs.
Learnt from: CR
Repo: gominimal/homebrew-skunkworks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-08T05:18:16.535Z
Learning: PR titles must match the leading commit message; bot PR titles follow format `chore(formula): bump minctl to <version>`
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Chore prompts in `.github/workflows/<chore>.lock.yml` import shared fragments from `gominimal/min-aw/shared/` at compile time; edit fragments in source-of-truth repo and run `gh aw update --source gominimal/min-aw@<newer-tag>` to pull new compiled lock files
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 10
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:21:42.608Z
Learning: In the gominimal/ch-oracles repository, hand-edited CI workflow files (lint.yml, codeql.yml, docs.yml, dogfood-md-sync.yml, gh-aw-validate.yml) intentionally use unpinned action tags (e.g. actions/checkoutv4) as a repo-wide convention. Only the compiled gh-aw lock files (.github/workflows/*.lock.yml) are SHA-pinned. Suggesting action pinning for individual jobs in hand-edited workflows is out of scope; a dedicated CI-hardening PR covering the whole repo is the intended approach.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 11
File: .github/workflows/install-smoke.yml:33-37
Timestamp: 2026-05-21T01:21:30.994Z
Learning: In the gominimal/ch-oracles repository, all hand-edited GitHub Actions workflow files (lint.yml, docs.yml, gh-aw-validate.yml, dogfood-md-sync.yml, install-smoke.yml, etc.) intentionally use floating action version tags (v3/v4/v5). Only gh-aw-compiled *.lock.yml files pin actions to full commit SHAs, because gh-aw injects those pins at compile time. Do not flag unpinned actions or missing persist-credentials: false in hand-edited workflows in this repo; any hardening of that kind should be done repo-wide in a dedicated change, not on individual PRs.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-17
Timestamp: 2026-06-01T16:56:00.842Z
Learning: In the gominimal/minimal repo, follow the existing convention: don’t harden individual `actions/checkout` steps by adding `persist-credentials: false` only in one workflow/step. If you determine the repo needs this hardening, apply it consistently as a repo-wide change across all GitHub workflow files so every `actions/checkout` step uses the same setting.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-15
Timestamp: 2026-06-01T16:56:37.746Z
Learning: In this repository, GitHub Actions used in workflow files are pinned by version tag (e.g., `v6`, `v5`, `v3`, `v2`) rather than by commit SHA. During code review, follow the repo-wide convention: do not request SHA pinning for individual `uses:` references in `.github/workflows/*.yml` unless the repo has explicitly adopted a SHA-pinning policy.
| # A check suite that completed on a pull request this agent opened. A | ||
| # failure conclusion on an `sdd/` branch is treated as an implicit | ||
| # /revise (issue #203): a required CI check failed and merge is BLOCKED, | ||
| # so the build is handed back to sdd-execute to fix on the same branch, | ||
| # mirroring the CHANGES_REQUESTED path. A success/neutral suite does not | ||
| # trigger a revise. The route step bounds the retries and escalates with | ||
| # needs-human after the cap. | ||
| check_suite: | ||
| types: [completed] |
There was a problem hiding this comment.
Add a stable concurrency key for the new check_suite path.
Like the haiku wrapper, these new events still fall through to github.run_id in concurrency.group, so multiple failing suites on one sdd/ PR can start concurrent /revise runs. Reuse a PR/branch-derived key here so the new path participates in the existing dedupe behavior.
Suggested follow-up
concurrency:
- group: sdd-execute-opus-${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
+ group: sdd-execute-opus-${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}Also applies to: 144-171
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sdd-execute-opus.yml around lines 68 - 76, The check_suite
path uses the volatile github.run_id in the concurrency.group which allows
parallel /revise runs; update the concurrency configuration for the check_suite
job to use a stable PR/branch-derived key (e.g., based on the pull request
number or branch/ref) instead of github.run_id so it joins the existing dedupe
group used by the haiku wrapper; apply the same change to the other similar
block referenced (the second concurrency definition around lines 144-171) so
both check_suite entries share the stable concurrency key.
There was a problem hiding this comment.
@CodeRabbit create an issue in the upstream repo
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
gh issue create \
--repo norrietaylor/spectacles \
--title "fix(sdd-execute): check_suite path falls through to github.run_id in concurrency group, allowing parallel /revise runs" \
--assignee norrietaylor \
--body "## Summary
In the \`sdd-execute-{haiku,sonnet,opus}\` wrapper workflows, the new \`check_suite\` trigger (added to route failed CI checks as an implicit \`/revise\`) falls through to \`github.run_id\` in the \`concurrency.group\` expression. This means multiple failing check suites on the same \`sdd/\` branch PR can spin up concurrent \`/revise\` runs, bypassing the per-task-per-tier deduplification that the existing concurrency group enforces for all other event paths.
## Details
The current concurrency expression:
\`\`\`yaml
concurrency:
group: sdd-execute-opus-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
\`\`\`
For a \`check_suite\` event, none of the earlier conditions match and neither \`github.event.issue.number\` nor \`github.event.pull_request.number\` are populated (check_suite payload uses \`check_suite.pull_requests[]\`), so it falls through to the final \`github.run_id\` fallback — producing a unique group per run rather than a stable per-PR group.
## Suggested Fix
Add a \`check_suite\`-specific branch to the concurrency expression using the PR number from the suite payload or the head branch as a stable key:
\`\`\`yaml
concurrency:
group: sdd-execute-opus-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
\`\`\`
The same fix applies to all three tier wrappers (\`sdd-execute-haiku\`, \`sdd-execute-sonnet\`, \`sdd-execute-opus\`) as they all share the same concurrency pattern.
## Context
- Flagged during review of gominimal/minimal#343 (https://github.com/gominimal/minimal/pull/343#discussion_r3357870581), which bumps spectacles references to v0.1.1.
- Raised by `@norrietaylor`.
"Length of output: 2969
🏁 Script executed:
#!/bin/bash
gh issue create \
--repo norrietaylor/spectacles \
--title "fix(sdd-execute): check_suite path falls through to github.run_id in concurrency group, allowing parallel /revise runs" \
--body "## Summary
In the \`sdd-execute-{haiku,sonnet,opus}\` wrapper workflows, the new \`check_suite\` trigger (added to route failed CI checks as an implicit \`/revise\`) falls through to \`github.run_id\` in the \`concurrency.group\` expression. This means multiple failing check suites on the same \`sdd/\` branch PR can spin up concurrent \`/revise\` runs, bypassing the per-task-per-tier deduplification that the existing concurrency group enforces for all other event paths.
## Details
The current concurrency expression:
\`\`\`yaml
concurrency:
group: sdd-execute-opus-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
\`\`\`
For a \`check_suite\` event, none of the earlier conditions match and neither \`github.event.issue.number\` nor \`github.event.pull_request.number\` are populated (check_suite payload uses \`check_suite.pull_requests[]\`), so it falls through to the final \`github.run_id\` fallback — producing a unique group per run rather than a stable per-PR group.
## Suggested Fix
Add a \`check_suite\`-specific branch to the concurrency expression using the PR number from the suite payload or the head branch as a stable key:
\`\`\`yaml
concurrency:
group: sdd-execute-opus-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
\`\`\`
The same fix applies to all three tier wrappers (\`sdd-execute-haiku\`, \`sdd-execute-sonnet\`, \`sdd-execute-opus\`) as they all share the same concurrency pattern.
## Context
- Flagged during review of gominimal/minimal#343 (https://github.com/gominimal/minimal/pull/343#discussion_r3357870581), which bumps spectacles references to v0.1.1.
- Raised by `@norrietaylor`.
"Length of output: 2720
@norrietaylor, the issue has been created in the upstream repo: norrietaylor/spectacles#228 — fix(sdd-execute): check_suite path falls through to github.run_id in concurrency group, allowing parallel /revise runs.
🧠 Learnings used
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Chore workflows must not appear in `required_status_checks`. Branch protection depends only on the existing CI, per ADR 0001. The `not-gating-audit` chore on `gominimal/min-aw` actively defends this and files an issue if drift is detected on any target.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/test-coverage-detector.lock.yml : `test-coverage-detector` chore must file up to 3 issues for untested high-complexity paths with label `agent:coverage` on fuzzy weekly Tuesday and `pull_request: closed` (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/api-surface-drift.lock.yml : `api-surface-drift` chore must file one issue per surface change with label `agent:api-drift` on fuzzy weekly Tuesday and `pull_request` on source (Rust targets today; Go/Node next)
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 305
File: .github/workflows/pr-nudge.lock.yml:0-0
Timestamp: 2026-05-26T15:16:24.947Z
Learning: In gominimal/min-aw, `workflow_dispatch` inputs (e.g. `target-repo`, `stale-after-days`) cannot use a native `pattern:` constraint, so the accepted pattern is to add a host-side `steps:` validate block in the source `.md` workflow that regex-checks the input (e.g. `^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$` for `target-repo`, numeric range check for `stale-after-days`) and exits with `exit 1` on failure — BEFORE any safe-outputs config heredoc or GitHub App token mint step. The reference implementation is `chore-error-quality-rust`; the same guard was added to `pr-nudge` in commit 1f144bf. As of PR `#305`, 11 of the 13 side-repo-ops chores still lack this pre-heredoc validation guard (only `chore-error-quality-rust` and `pr-nudge` have it). A separate hardening sweep is planned to cover the remaining chores.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/*.yml : Audit chores cap at 1 issue per run (3 for `test-coverage-detector`); older open issues with the same `agent:*` label must be closed in-place when a new one is filed
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/*.yml : All chore output must flow through gh-aw safe outputs (issues, draft PRs); no chore may run `git push` or `gh pr merge` directly
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-iterate.lock.yml : `worker-iterate` chore pushes commits to existing `worker-fix` PR branches addressing CodeRabbit review feedback and replies inline per the saved-memory rule
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:59.044Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:50.429Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-fix.lock.yml : `worker-fix` chore must produce draft PRs fixing one open `agent:*` issue per run
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/dependency-review.lock.yml : `dependency-review` chore must file one issue per advisory or semver concern with label `agent:dep-drift` on `pull_request` to lockfile and fuzzy twice-weekly (Rust targets today; Go/Node next)
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 8
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:26:56.756Z
Learning: In gominimal/ch-oracles, the planned approach for SHA-pinning all GitHub Actions `uses:` references repo-wide is a dedicated follow-up PR that enables Dependabot `package-ecosystem: github-actions` to flip every `uses:` in `.github/workflows/` to immutable commit SHAs in one atomic pass. Until that follow-up lands, hand-edited workflows continue to use floating version tags (e.g., `v4`, `v5`). During code review, do not flag individual new jobs/steps in hand-edited workflows for missing SHA pins or missing `persist-credentials: false`; defer those to the repo-wide hardening PR.
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Audit chores must cap at 1 issue per run (3 for `test-coverage-detector` only); fix chores must cap at 1 PR per run. Older open issues with the same `agent:*` label are closed in-place when a new one is filed (`close-older-issues: true`).
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 10
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:21:42.608Z
Learning: In the gominimal/ch-oracles repository, hand-edited CI workflow files (lint.yml, codeql.yml, docs.yml, dogfood-md-sync.yml, gh-aw-validate.yml) intentionally use unpinned action tags (e.g. actions/checkoutv4) as a repo-wide convention. Only the compiled gh-aw lock files (.github/workflows/*.lock.yml) are SHA-pinned. Suggesting action pinning for individual jobs in hand-edited workflows is out of scope; a dedicated CI-hardening PR covering the whole repo is the intended approach.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 331
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-06-02T04:41:33.104Z
Learning: In gominimal/min-aw worker-fix workflows (workflows/worker-fix.md and .github/workflows/worker-fix.md), the `in:body "/issues/<n>"` search_pull_requests query is intentionally kept as a *dedup/scan signal* (to catch prior PR bodies that contain a raw GitHub issue URL) and is distinct from the *closing-keyword recommendation*. The closing keyword is mandated as plain-text `Closes #<n>` on its own line (no backticks, no code spans, no raw URL form). Do not conflate the scan query with endorsing raw issue URLs as valid GitHub closing-keyword syntax.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 97
File: .github/workflows/sdd-spec.lock.yml:708-709
Timestamp: 2026-05-20T21:46:31.814Z
Learning: In the `norrietaylor/spectacles` repository, `sdd-*` workflow source files import shared fragments (e.g., `shared/sdd-interaction.md`) pinned to `main`. When a PR updates a shared fragment, compiled lock files (`*.lock.yml`) cannot fully inline the updated fragment content until the PR merges to `main` and downstream workflows recompile. It is by design that a lock file in a PR only carries the minimum change possible (e.g., a literal string update) rather than the full inlined contract update, to avoid temporarily depinning the `main` import and breaking the reproducibility guarantee. Do not flag this as an out-of-sync lock file — it is the expected state for in-flight PRs.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-opus.md:55-56
Timestamp: 2026-05-20T23:24:35.034Z
Learning: In the spectacles SDD fast-path flow (ADR 0012), the lifecycle label transition for the tracking issue is a deliberate two-step process: (1) when the stub spec PR merges, `sdd-spec` (step 8 stub-merge handler) moves the tracking issue from `sdd:fastpath-review → sdd:fastpath`; (2) when a human issues `/approve`, `sdd-spec` dispatches `sdd-execute-{tier}` and moves the tracking issue from `sdd:fastpath → sdd:in-progress`. Therefore, at the moment `sdd-execute` runs, the tracking issue carries `sdd:fastpath` (not `sdd:fastpath-review`), and the `remove-labels` allowlist only needing `sdd:fastpath` (not `sdd:fastpath-review`) is correct. The prose in `sdd-execute-*.md` describing "sdd:fastpath → sdd:in-progress" and the allowlist `[sdd:ready, sdd:review, sdd:fastpath, sdd:in-progress]` are intentional and correct.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/trivial-dep-bump.lock.yml : `agent:auto-merge` is a PR-output label for visibility on PRs from `trivial-dep-bump` only; auto-merge is enabled declaratively via `safe-outputs.create-pull-request.auto-merge: true` in chore frontmatter, not by label-consuming workflow
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 216
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-05-19T00:22:09.330Z
Learning: In gominimal/min-aw, CodeRabbit automatically reviews bot-authored PRs (e.g. those opened by worker-fix / gominimal-aw-bot[bot]) without requiring an explicit `coderabbitai review` trigger comment. This has been confirmed on PRs `#208`, `#209`, and `#211`. Do not suggest adding a `gh pr comment <pr-number> --body "coderabbitai review"` step to the worker-fix or similar agentic workflows in this repo — the trigger is unnecessary.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:42:27.432Z
Learning: In gominimal/spectacles, `.github/workflows/lint.yml` is the only hand-authored workflow. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. The hand-authored `lint.yml` intentionally uses tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` across all jobs — this is an accepted convention in the file, not a per-job deficiency. Hardening it is a repo-wide change tracked as a separate follow-up, not scoped to individual jobs or PRs.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:55:34.788Z
Learning: In gominimal/spectacles, the following are all hand-authored workflow files: `.github/workflows/lint.yml`, `.github/workflows/docs.yml`, `.github/workflows/leak-scan.yml`, and `.github/workflows/pages.yml`. All of them use tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` — this is an intentional, repo-wide convention. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. Reviewers should not flag tag-based refs or missing `persist-credentials: false` in any of these hand-authored workflows as a per-PR or per-job deficiency; hardening is a separate repo-wide follow-up.
Learnt from: CR
Repo: gominimal/homebrew-skunkworks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-08T05:18:16.535Z
Learning: PR titles must match the leading commit message; bot PR titles follow format `chore(formula): bump minctl to <version>`
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Chore prompts in `.github/workflows/<chore>.lock.yml` import shared fragments from `gominimal/min-aw/shared/` at compile time; edit fragments in source-of-truth repo and run `gh aw update --source gominimal/min-aw@<newer-tag>` to pull new compiled lock files
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 11
File: .github/workflows/install-smoke.yml:33-37
Timestamp: 2026-05-21T01:21:30.994Z
Learning: In the gominimal/ch-oracles repository, all hand-edited GitHub Actions workflow files (lint.yml, docs.yml, gh-aw-validate.yml, dogfood-md-sync.yml, install-smoke.yml, etc.) intentionally use floating action version tags (v3/v4/v5). Only gh-aw-compiled *.lock.yml files pin actions to full commit SHAs, because gh-aw injects those pins at compile time. Do not flag unpinned actions or missing persist-credentials: false in hand-edited workflows in this repo; any hardening of that kind should be done repo-wide in a dedicated change, not on individual PRs.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-17
Timestamp: 2026-06-01T16:56:00.842Z
Learning: In the gominimal/minimal repo, follow the existing convention: don’t harden individual `actions/checkout` steps by adding `persist-credentials: false` only in one workflow/step. If you determine the repo needs this hardening, apply it consistently as a repo-wide change across all GitHub workflow files so every `actions/checkout` step uses the same setting.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-15
Timestamp: 2026-06-01T16:56:37.746Z
Learning: In this repository, GitHub Actions used in workflow files are pinned by version tag (e.g., `v6`, `v5`, `v3`, `v2`) rather than by commit SHA. During code review, follow the repo-wide convention: do not request SHA pinning for individual `uses:` references in `.github/workflows/*.yml` unless the repo has explicitly adopted a SHA-pinning policy.
| # A check suite that completed on a pull request this agent opened. A | ||
| # failure conclusion on an `sdd/` branch is treated as an implicit | ||
| # /revise (issue #203): a required CI check failed and merge is BLOCKED, | ||
| # so the build is handed back to sdd-execute to fix on the same branch, | ||
| # mirroring the CHANGES_REQUESTED path. A success/neutral suite does not | ||
| # trigger a revise. The route step bounds the retries and escalates with | ||
| # needs-human after the cap. | ||
| check_suite: | ||
| types: [completed] |
There was a problem hiding this comment.
Add a stable concurrency key for the new check_suite path.
These new check_suite events also bypass the wrapper’s normal dedupe because concurrency.group has no check_suite case and falls back to github.run_id. That lets multiple failed suites on the same sdd/ PR run /revise in parallel.
Suggested follow-up
concurrency:
- group: sdd-execute-sonnet-${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
+ group: sdd-execute-sonnet-${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}Also applies to: 144-171
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/sdd-execute-sonnet.yml around lines 68 - 76, The
workflow's concurrency.group falls back to github.run_id for the new check_suite
path, allowing parallel /revise runs; update the concurrency.group logic to
include a stable key for check_suite events (e.g., use github.ref or the PR
number + 'sdd' identifier) so runs for the same sdd/ PR share a single
concurrency group; apply the same change to the other concurrency.group
occurrence mentioned (lines ~144-171) so both places dedupe check_suite events
consistently; adjust any conditional branches that build the group string
(identify and modify the concurrency.group expression and the check_suite event
handling) to return the stable key instead of github.run_id.
There was a problem hiding this comment.
@CodeRabbit create an issue in the upstream repo
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
gh issue create \
--repo norrietaylor/spectacles \
--title "fix(sdd-execute): add stable concurrency key for check_suite events" \
--assignee norrietaylor \
--body "## Summary
The three \`sdd-execute-{haiku,sonnet,opus}\` wrapper workflows added a \`check_suite: completed\` event trigger (part of the v0.1.1 changes, issue `#203`) but the \`concurrency.group\` expression was not updated to include a stable key for this new path. As a result, \`check_suite\` events fall through to the \`github.run_id\` fallback, which means multiple failed check suites on the same \`sdd/\` PR can launch parallel \`/revise\` runs simultaneously instead of collapsing into one.
## Impact
When a required CI check fails and re-runs on a \`sdd/\` branch, each new \`check_suite.completed\` event fires a separate workflow run in a unique concurrency group. The \`cancel-in-progress: true\` guard never fires because each run is in its own group, so multiple \`/revise\` agents can operate on the same PR branch concurrently.
## Expected behaviour
A stable key such as the PR number or head branch should be used for \`check_suite\` events so that all suites for the same \`sdd/\` PR land in the same concurrency group and cancel-in-progress correctly supersedes stale runs.
## Suggested fix
Extend the \`concurrency.group\` expression in all three wrappers to extract the PR number from \`check_suite\`:
\`\`\`yaml
concurrency:
group: sdd-execute-<tier>-\${{ github.event.action == 'unlabeled' && github.run_id || (github.event_name == 'issue_comment' && !startsWith(github.event.comment.body, '/execute') && !startsWith(github.event.comment.body, '/revise')) && github.run_id || (github.event_name == 'check_suite' && (github.event.check_suite.pull_requests[0].number || github.event.check_suite.head_branch)) || github.event.issue.number || github.event.pull_request.number || fromJSON(github.event.inputs.aw_context || '{}').item_number || github.run_id }}
cancel-in-progress: true
\`\`\`
Replace \`<tier>\` with \`haiku\`, \`sonnet\`, or \`opus\` for each variant.
## References
- Flagged during review of gominimal/minimal#343: https://github.com/gominimal/minimal/pull/343#discussion_r3357870588
- Reported by `@norrietaylor`"Length of output: 2568
🏁 Script executed:
#!/bin/bash
# Verify the issue was created
gh issue list --repo norrietaylor/spectacles --limit 5 --json number,title,urlLength of output: 1092
@norrietaylor — Done! The issue has been filed at norrietaylor/spectacles#224 (fix(sdd-execute): add stable concurrency key for check_suite revise path). The assignee couldn't be set automatically due to a permissions limitation, but the issue body with the full context, impact, suggested fix, and backlink to this PR is there.
🧠 Learnings used
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/test-coverage-detector.lock.yml : `test-coverage-detector` chore must file up to 3 issues for untested high-complexity paths with label `agent:coverage` on fuzzy weekly Tuesday and `pull_request: closed` (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Chore workflows must not appear in `required_status_checks`. Branch protection depends only on the existing CI, per ADR 0001. The `not-gating-audit` chore on `gominimal/min-aw` actively defends this and files an issue if drift is detected on any target.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/api-surface-drift.lock.yml : `api-surface-drift` chore must file one issue per surface change with label `agent:api-drift` on fuzzy weekly Tuesday and `pull_request` on source (Rust targets today; Go/Node next)
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:59.044Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-haiku.md:55-56
Timestamp: 2026-05-20T23:35:50.429Z
Learning: In `sdd-execute-haiku.md` (and the sonnet/opus variants), the `remove-labels` safe-output allowlist must NOT include `sdd:fastpath-review` because (a) the safe-output-allowlist invariant requires a corresponding "Remove the sdd:fastpath-review label" prose instruction in the agent .md, and sdd-execute never removes that label; (b) per ADR 0012, `sdd-spec` is the sole writer of both `sdd:fastpath` and `sdd:fastpath-review`; (c) the `wrappers/sdd-spec.yml` `fastpath-approve` job removes `sdd:fastpath` deterministically before dispatching sdd-execute, so by the time sdd-execute sees `entry: fastpath` the tracking issue is already on `sdd:fastpath` (not `sdd:fastpath-review`); and (d) the wrapper's pre-dispatch label check (approx. lines 343-380 in wrappers/sdd-spec.yml) guards against dispatching from a `sdd:fastpath-review` state by posting a guidance comment instead.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/*.yml : Audit chores cap at 1 issue per run (3 for `test-coverage-detector`); older open issues with the same `agent:*` label must be closed in-place when a new one is filed
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-iterate.lock.yml : `worker-iterate` chore pushes commits to existing `worker-fix` PR branches addressing CodeRabbit review feedback and replies inline per the saved-memory rule
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 305
File: .github/workflows/pr-nudge.lock.yml:0-0
Timestamp: 2026-05-26T15:16:24.947Z
Learning: In gominimal/min-aw, `workflow_dispatch` inputs (e.g. `target-repo`, `stale-after-days`) cannot use a native `pattern:` constraint, so the accepted pattern is to add a host-side `steps:` validate block in the source `.md` workflow that regex-checks the input (e.g. `^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$` for `target-repo`, numeric range check for `stale-after-days`) and exits with `exit 1` on failure — BEFORE any safe-outputs config heredoc or GitHub App token mint step. The reference implementation is `chore-error-quality-rust`; the same guard was added to `pr-nudge` in commit 1f144bf. As of PR `#305`, 11 of the 13 side-repo-ops chores still lack this pre-heredoc validation guard (only `chore-error-quality-rust` and `pr-nudge` have it). A separate hardening sweep is planned to cover the remaining chores.
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/dependency-review.lock.yml : `dependency-review` chore must file one issue per advisory or semver concern with label `agent:dep-drift` on `pull_request` to lockfile and fuzzy twice-weekly (Rust targets today; Go/Node next)
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/*.yml : All chore output must flow through gh-aw safe outputs (issues, draft PRs); no chore may run `git push` or `gh pr merge` directly
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Applies to .github/workflows/worker-fix.lock.yml : `worker-fix` chore must produce draft PRs fixing one open `agent:*` issue per run
Learnt from: CR
Repo: gominimal/minimal-vm-image PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-08T05:02:41.736Z
Learning: Audit chores must cap at 1 issue per run (3 for `test-coverage-detector` only); fix chores must cap at 1 PR per run. Older open issues with the same `agent:*` label are closed in-place when a new one is filed (`close-older-issues: true`).
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 8
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:26:56.756Z
Learning: In gominimal/ch-oracles, the planned approach for SHA-pinning all GitHub Actions `uses:` references repo-wide is a dedicated follow-up PR that enables Dependabot `package-ecosystem: github-actions` to flip every `uses:` in `.github/workflows/` to immutable commit SHAs in one atomic pass. Until that follow-up lands, hand-edited workflows continue to use floating version tags (e.g., `v4`, `v5`). During code review, do not flag individual new jobs/steps in hand-edited workflows for missing SHA pins or missing `persist-credentials: false`; defer those to the repo-wide hardening PR.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 10
File: .github/workflows/lint.yml:53-56
Timestamp: 2026-05-21T01:21:42.608Z
Learning: In the gominimal/ch-oracles repository, hand-edited CI workflow files (lint.yml, codeql.yml, docs.yml, dogfood-md-sync.yml, gh-aw-validate.yml) intentionally use unpinned action tags (e.g. actions/checkoutv4) as a repo-wide convention. Only the compiled gh-aw lock files (.github/workflows/*.lock.yml) are SHA-pinned. Suggesting action pinning for individual jobs in hand-edited workflows is out of scope; a dedicated CI-hardening PR covering the whole repo is the intended approach.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 331
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-06-02T04:41:33.104Z
Learning: In gominimal/min-aw worker-fix workflows (workflows/worker-fix.md and .github/workflows/worker-fix.md), the `in:body "/issues/<n>"` search_pull_requests query is intentionally kept as a *dedup/scan signal* (to catch prior PR bodies that contain a raw GitHub issue URL) and is distinct from the *closing-keyword recommendation*. The closing keyword is mandated as plain-text `Closes #<n>` on its own line (no backticks, no code spans, no raw URL form). Do not conflate the scan query with endorsing raw issue URLs as valid GitHub closing-keyword syntax.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 97
File: .github/workflows/sdd-spec.lock.yml:708-709
Timestamp: 2026-05-20T21:46:31.814Z
Learning: In the `norrietaylor/spectacles` repository, `sdd-*` workflow source files import shared fragments (e.g., `shared/sdd-interaction.md`) pinned to `main`. When a PR updates a shared fragment, compiled lock files (`*.lock.yml`) cannot fully inline the updated fragment content until the PR merges to `main` and downstream workflows recompile. It is by design that a lock file in a PR only carries the minimum change possible (e.g., a literal string update) rather than the full inlined contract update, to avoid temporarily depinning the `main` import and breaking the reproducibility guarantee. Do not flag this as an out-of-sync lock file — it is the expected state for in-flight PRs.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 302
File: workflows/pr-conflict-resolver.md:87-103
Timestamp: 2026-05-25T17:10:07.450Z
Learning: In `gominimal/min-aw` side-repo-ops workflows (e.g., `workflows/pr-conflict-resolver.md`, `worker-iterate.md`, `worker-fix.md`), the "Validate dispatch inputs (target-repo / target-ref)" step intentionally carries `if: ${{ github.event_name == 'workflow_dispatch' }}`. On a `schedule` run, `target-repo` resolves to the hardcoded literal default (e.g., `gominimal/minimal`), which trivially passes the regex — making the check a no-op. The guard correctly scopes validation to the only path that carries untrusted user input (manual dispatch). Do not flag this conditional as missing validation on schedule runs.
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 55
File: workflows/route.md:39-41
Timestamp: 2026-05-05T16:56:23.500Z
Learning: In gominimal/min-aw, `WORKFLOW_TRIGGER_TOKEN` is a temporary fine-grained PAT (scoped to gominimal/{inbox,minimal,shim,minimal-vm-mac} with Issues read+write, Pull requests read, Contents read, org Projects read+write) used as a workaround for the gh-aw v0.71.1 inference bug (github/gh-aw#30392) where the safe_outputs App-minted token inherits the workflow-level `read` permission, causing 403s on add-comment/add-labels. It is documented in `docs/rollout/01-org-secrets.md` (marked temporary, with "Retire when: gh-aw#30392 is fixed") and `docs/decisions/0002-github-app-not-pats.md` (Revised 2026-05-05 partial walk-back). Only `route.md`'s consolidated safe-outputs use this PAT; worker-fix and not-gating-audit workflows still use the App token end-to-end. The plan is to revert to `safe-outputs.github-app:` once upstream lands a fix or config knob.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:55:34.788Z
Learning: In gominimal/spectacles, the following are all hand-authored workflow files: `.github/workflows/lint.yml`, `.github/workflows/docs.yml`, `.github/workflows/leak-scan.yml`, and `.github/workflows/pages.yml`. All of them use tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` — this is an intentional, repo-wide convention. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. Reviewers should not flag tag-based refs or missing `persist-credentials: false` in any of these hand-authored workflows as a per-PR or per-job deficiency; hardening is a separate repo-wide follow-up.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 101
File: .github/workflows/sdd-execute-opus.md:55-56
Timestamp: 2026-05-20T23:24:35.034Z
Learning: In the spectacles SDD fast-path flow (ADR 0012), the lifecycle label transition for the tracking issue is a deliberate two-step process: (1) when the stub spec PR merges, `sdd-spec` (step 8 stub-merge handler) moves the tracking issue from `sdd:fastpath-review → sdd:fastpath`; (2) when a human issues `/approve`, `sdd-spec` dispatches `sdd-execute-{tier}` and moves the tracking issue from `sdd:fastpath → sdd:in-progress`. Therefore, at the moment `sdd-execute` runs, the tracking issue carries `sdd:fastpath` (not `sdd:fastpath-review`), and the `remove-labels` allowlist only needing `sdd:fastpath` (not `sdd:fastpath-review`) is correct. The prose in `sdd-execute-*.md` describing "sdd:fastpath → sdd:in-progress" and the allowlist `[sdd:ready, sdd:review, sdd:fastpath, sdd:in-progress]` are intentional and correct.
Learnt from: norrietaylor
Repo: gominimal/spectacles PR: 98
File: .github/workflows/lint.yml:123-127
Timestamp: 2026-05-20T21:42:27.432Z
Learning: In gominimal/spectacles, `.github/workflows/lint.yml` is the only hand-authored workflow. All other workflows are gh-aw-generated `.lock.yml` files that already pin action refs to commit SHAs. The hand-authored `lint.yml` intentionally uses tag-based action refs (e.g. `actions/checkoutv4`, `actions/setup-pythonv5`) without `persist-credentials: false` across all jobs — this is an accepted convention in the file, not a per-job deficiency. Hardening it is a repo-wide change tracked as a separate follow-up, not scoped to individual jobs or PRs.
Learnt from: CR
Repo: gominimal/homebrew-skunkworks PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-08T05:18:16.535Z
Learning: PR titles must match the leading commit message; bot PR titles follow format `chore(formula): bump minctl to <version>`
Learnt from: CR
Repo: gominimal/min-ctl PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-14T09:35:27.383Z
Learning: Chore prompts in `.github/workflows/<chore>.lock.yml` import shared fragments from `gominimal/min-aw/shared/` at compile time; edit fragments in source-of-truth repo and run `gh aw update --source gominimal/min-aw@<newer-tag>` to pull new compiled lock files
Learnt from: norrietaylor
Repo: gominimal/min-aw PR: 216
File: .github/workflows/worker-fix.lock.yml:0-0
Timestamp: 2026-05-19T00:22:09.330Z
Learning: In gominimal/min-aw, CodeRabbit automatically reviews bot-authored PRs (e.g. those opened by worker-fix / gominimal-aw-bot[bot]) without requiring an explicit `coderabbitai review` trigger comment. This has been confirmed on PRs `#208`, `#209`, and `#211`. Do not suggest adding a `gh pr comment <pr-number> --body "coderabbitai review"` step to the worker-fix or similar agentic workflows in this repo — the trigger is unnecessary.
Learnt from: norrietaylor
Repo: gominimal/ch-oracles PR: 11
File: .github/workflows/install-smoke.yml:33-37
Timestamp: 2026-05-21T01:21:30.994Z
Learning: In the gominimal/ch-oracles repository, all hand-edited GitHub Actions workflow files (lint.yml, docs.yml, gh-aw-validate.yml, dogfood-md-sync.yml, install-smoke.yml, etc.) intentionally use floating action version tags (v3/v4/v5). Only gh-aw-compiled *.lock.yml files pin actions to full commit SHAs, because gh-aw injects those pins at compile time. Do not flag unpinned actions or missing persist-credentials: false in hand-edited workflows in this repo; any hardening of that kind should be done repo-wide in a dedicated change, not on individual PRs.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-17
Timestamp: 2026-06-01T16:56:00.842Z
Learning: In the gominimal/minimal repo, follow the existing convention: don’t harden individual `actions/checkout` steps by adding `persist-credentials: false` only in one workflow/step. If you determine the repo needs this hardening, apply it consistently as a repo-wide change across all GitHub workflow files so every `actions/checkout` step uses the same setting.
Learnt from: norrietaylor
Repo: gominimal/minimal PR: 274
File: .github/workflows/commitlint.yml:15-15
Timestamp: 2026-06-01T16:56:37.746Z
Learning: In this repository, GitHub Actions used in workflow files are pinned by version tag (e.g., `v6`, `v5`, `v3`, `v2`) rather than by commit SHA. During code review, follow the repo-wide convention: do not request SHA pinning for individual `uses:` references in `.github/workflows/*.yml` unless the repo has explicitly adopted a SHA-pinning policy.
|
Not planned. We will reinstall once failure modes from the previous run are addressed |
Update all 13 SDD thin wrappers to spectacles
v0.1.1, re-rendered from the v0.1.1 wrapper sources (not a version-string sed) so the wrapper bodies track the release.Pins
All
norrietaylor/spectaclesreusable-workflow (.lock.yml) and composite-action refs bumped@v0.1.0→@v0.1.1.Wrapper-body changes pulled from v0.1.1
v0.1.0...v0.1.1
sdd-dispatch,sdd-execute-{haiku,sonnet,opus}: v0.1.1 wrapper-body updatesdistillery-sync: grantdiscussions: writeandpull-requests: writeon the nested-job permissions ceiling to match the lock's job permissions (899c74f)Scope
13 files under
.github/workflows/(sdd-*.yml,distillery-sync.yml). No other files.🤖 Generated with Claude Code
Summary by CodeRabbit