diff --git a/.github/workflows/sdlc-audit-gemini.yml b/.github/workflows/sdlc-audit-gemini.yml index 98df16ed..8c51df82 100644 --- a/.github/workflows/sdlc-audit-gemini.yml +++ b/.github/workflows/sdlc-audit-gemini.yml @@ -1,13 +1,24 @@ # Auditor (Gemini) — third cross-model audit. Runs automatically when a PR opens (an # independent third opinion alongside the Claude reviewer and Codex auditor) and on -# demand via the `agent:audit` label. Read-only; posts Gemini's verdict as a PR comment. +# demand via the `agent:audit` label, which also keeps auditing every later push (see +# below). Read-only; posts Gemini's verdict as a PR comment. # Needs secret GEMINI_API_KEY — skips cleanly (no failure) when it is absent. -# Not on `synchronize`, so the fix loop's pushes don't re-spend Gemini credits each round. +# Re-auditing, and why it is opt-in: a plain push does NOT re-audit, so the fix +# loop's pushes don't re-spend Gemini credits each round. Label the PR `agent:audit` +# and every subsequent push re-audits until the label comes off — which is the ONLY +# way to re-audit, because re-adding a label the PR already has fires no `labeled` +# event at all, so "add the label again" silently does nothing. +# +# Reading the check status: the Classifier's `domain:*` labels land seconds after +# open and each one triggers this workflow, which then skips. That SKIPPED run is +# newer than the real audit, so `gh pr checks` shows "skipping" for it while the +# audit itself succeeded moments earlier. Check the run list, not the summary, +# before concluding an audit never ran. name: "sdlc · audit (Gemini)" on: pull_request: - types: [opened, reopened, labeled] + types: [opened, reopened, labeled, synchronize] permissions: contents: read @@ -15,9 +26,20 @@ permissions: jobs: audit-gemini: - # Auto on open/reopen, or on the agent:audit label. (label.name is null on open events.) + # Auto on open/reopen. On a label, ONLY `agent:audit` (any other label — the + # Classifier's `domain:*` land seconds after open — must not spend credits). + # On a push, only when the PR ALREADY carries `agent:audit`: that is the + # opt-in for "keep auditing this one as I fix it", and it is what makes a + # re-audit reachable at all (see the header). # dependabot-actor runs get Dependabot's (empty) secret store — agent can't auth, so skip - if: github.actor != 'dependabot[bot]' && (github.event.action != 'labeled' || github.event.label.name == 'agent:audit') + if: >- + github.actor != 'dependabot[bot]' && ( + github.event.action == 'opened' || + github.event.action == 'reopened' || + (github.event.action == 'labeled' && github.event.label.name == 'agent:audit') || + (github.event.action == 'synchronize' && + contains(github.event.pull_request.labels.*.name, 'agent:audit')) + ) runs-on: ubuntu-latest steps: # Secrets aren't readable in a job-level `if`, so gate every later step on this diff --git a/.github/workflows/sdlc-audit.yml b/.github/workflows/sdlc-audit.yml index 51d5fbdc..8c810ff2 100644 --- a/.github/workflows/sdlc-audit.yml +++ b/.github/workflows/sdlc-audit.yml @@ -1,12 +1,22 @@ # Auditor (Codex) — independent cross-audit. Runs automatically when a PR opens (an # independent second opinion to the Claude reviewer) and on demand via the `agent:audit` -# label. Read-only; posts Codex's verdict as a PR comment. Needs secret OPENAI_API_KEY. -# Not on `synchronize`, so the fix loop's pushes don't re-spend Codex credits each round. +# label, which also keeps auditing every later push (see below). Read-only; posts Codex's verdict as a PR comment. Needs secret OPENAI_API_KEY. +# Re-auditing, and why it is opt-in: a plain push does NOT re-audit, so the fix +# loop's pushes don't re-spend Codex credits each round. Label the PR `agent:audit` +# and every subsequent push re-audits until the label comes off — which is the ONLY +# way to re-audit, because re-adding a label the PR already has fires no `labeled` +# event at all, so "add the label again" silently does nothing. +# +# Reading the check status: the Classifier's `domain:*` labels land seconds after +# open and each one triggers this workflow, which then skips. That SKIPPED run is +# newer than the real audit, so `gh pr checks` shows "skipping" for it while the +# audit itself succeeded moments earlier. Check the run list, not the summary, +# before concluding an audit never ran. name: "sdlc · audit (Codex)" on: pull_request: - types: [opened, reopened, labeled] + types: [opened, reopened, labeled, synchronize] permissions: contents: read @@ -14,9 +24,20 @@ permissions: jobs: audit: - # Auto on open/reopen, or on the agent:audit label. (label.name is null on open events.) + # Auto on open/reopen. On a label, ONLY `agent:audit` (any other label — the + # Classifier's `domain:*` land seconds after open — must not spend credits). + # On a push, only when the PR ALREADY carries `agent:audit`: that is the + # opt-in for "keep auditing this one as I fix it", and it is what makes a + # re-audit reachable at all (see the header). # dependabot-actor runs get Dependabot's (empty) secret store — agent can't auth, so skip - if: github.actor != 'dependabot[bot]' && (github.event.action != 'labeled' || github.event.label.name == 'agent:audit') + if: >- + github.actor != 'dependabot[bot]' && ( + github.event.action == 'opened' || + github.event.action == 'reopened' || + (github.event.action == 'labeled' && github.event.label.name == 'agent:audit') || + (github.event.action == 'synchronize' && + contains(github.event.pull_request.labels.*.name, 'agent:audit')) + ) runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1