Skip to content

chore(ci): bump spectacles reusable workflows/actions to v0.1.1 - #343

Closed
norrietaylor wants to merge 1 commit into
mainfrom
chore/bump-spectacles-v0.1.1
Closed

chore(ci): bump spectacles reusable workflows/actions to v0.1.1#343
norrietaylor wants to merge 1 commit into
mainfrom
chore/bump-spectacles-v0.1.1

Conversation

@norrietaylor

@norrietaylor norrietaylor commented Jun 4, 2026

Copy link
Copy Markdown
Member

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/spectacles reusable-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 updates
  • distillery-sync: grant discussions: write and pull-requests: write on 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

  • Chores
    • Updated automation infrastructure components to v0.1.1 across all workflows.
    • Enhanced handling of failed and blocked build check completions with automatic remediation routing.
    • Improved error handling for critical workflow steps with stricter failure detection.
    • Extended automation permissions to support additional safeguards and checks.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This 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.

Changes

Check Suite Auto-Revise Routing

Layer / File(s) Summary
sdd-execute-haiku check suite routing
.github/workflows/sdd-execute-haiku.yml
check_suite completed trigger routes failed/timed-out/cancelled/action_required suites on sdd/ branches to implicit /revise path; route job permissions include checks: read; component versions (sdd-route-execute, sdd-execute-haiku.lock.yml, sdd-auto-merge) bump to v0.1.1.
sdd-execute-opus check suite routing
.github/workflows/sdd-execute-opus.yml
check_suite completed trigger with expanded route if-gating; decision logic maps failure-like conclusions to /revise; route job and auto-merge App token permissions include checks: read and issues: write; component versions (sdd-route-execute, sdd-execute-opus.lock.yml, sdd-auto-merge, sdd-refresh-siblings) bump to v0.1.1.
sdd-execute-sonnet check suite routing
.github/workflows/sdd-execute-sonnet.yml
check_suite completed trigger with route if-gating for failed checks on sdd/ branches; route permissions include checks: read; auto-merge App token extends to issues: write; component versions (sdd-route-execute, sdd-execute-sonnet.lock.yml, sdd-auto-merge) bump to v0.1.1.

Dispatch Task Label State Transitions

Layer / File(s) Summary
Label transition logic and error handling
.github/workflows/sdd-dispatch.yml
dispatch job changes from applying sdd:ready to deterministically marking tasks sdd:in-progress with idempotent 422 conflict handling, then removing sdd:ready with tolerated 404 failure; lifecycle job tightens sdd:dispatched label failure from logging to core.setFailed() and throwing; route and compute actions bump to v0.1.1.

Spectacles Component Version Updates

Layer / File(s) Summary
Wrapper and utility workflow version updates
.github/workflows/distillery-sync.yml, .github/workflows/sdd-review.yml, .github/workflows/sdd-monitor.yml, .github/workflows/sdd-pr-sanitize.yml
Distillery-sync, review, monitor, and pr-sanitize workflows/actions update to v0.1.1; distillery-sync permissions comment is expanded across multiple lines.
Spec, triage, and validate workflow version updates
.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
Spec (route, fastpath-approve, reusable workflow, failure-handoff), triage-dedupe-tasks, triage-promote-ready, triage, and validate workflows bump their action and reusable workflow references to v0.1.1.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • gominimal/minspec-test#60: Updates the already-installed SDD workflow wrappers by bumping norrietaylor/spectacles version pins from v0.1.0 to v0.1.1 and adjusts workflow logic such as sdd-dispatch label transitions and sdd-execute-* check_suite revise routing.
  • gominimal/minimal#307: Updates the already-installed SDD wrapper workflows such as sdd-dispatch and sdd-execute-* by bumping norrietaylor/spectacles action/reusable-workflow versions from v0.1.0 to v0.1.1 and tweaking wrapper routing and labeling logic.

Suggested reviewers

  • twitchyliquid64

Poem

🐰 Version bumps dance from point-oh to point-one,
Check suites now revise when failing in the sun,
Labels shift from ready to in-progress states so true,
Every workflow now orchestrates the spectacles brew! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: bumping all Spectacles reusable workflow and action references from v0.1.0 to v0.1.1 across 13 workflow files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5862969 and 02e1806.

📒 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.yml
  • scripts/fetch-virtio-kernel.sh

Comment thread .github/workflows/ci-macos.yml Outdated
Comment thread scripts/fetch-virtio-kernel.sh Outdated
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>
@norrietaylor
norrietaylor force-pushed the chore/bump-spectacles-v0.1.1 branch from 02e1806 to 873ffd6 Compare June 4, 2026 17:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 02e1806 and 873ffd6.

📒 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

Comment on lines +231 to +242
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);
}

@coderabbitai coderabbitai Bot Jun 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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;
+                }
               }
             }
Based on learnings, this aligns with the stated deterministic label-transition contract for this workflow layer.
🤖 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).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodeRabbit create an issue in the upstream repo

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 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.

Comment on lines +68 to +76
# 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]

@coderabbitai coderabbitai Bot Jun 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodeRabbit create an issue in the upstream repo

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 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 norrietaylor

Length 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,url

Length of output: 401



@norrietaylor — done! The issue has been filed in the upstream repo:

norrietaylor/spectacles#224 — fix(sdd-execute): add stable concurrency key for check_suite revise path

(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.

Comment on lines +68 to +76
# 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]

@coderabbitai coderabbitai Bot Jun 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodeRabbit create an issue in the upstream repo

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 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#228fix(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.

Comment on lines +68 to +76
# 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]

@coderabbitai coderabbitai Bot Jun 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CodeRabbit create an issue in the upstream repo

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 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,url

Length 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.

@norrietaylor

Copy link
Copy Markdown
Member Author

Not planned. We will reinstall once failure modes from the previous run are addressed

@norrietaylor
norrietaylor deleted the chore/bump-spectacles-v0.1.1 branch June 4, 2026 17:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant