feat: wire state-fingerprint into 6 unchanged-state-skip workflows - #2002
Conversation
|
No description provided. |
143e518 to
39afdae
Compare
Automated Status SummaryHead SHA: 588792b
Coverage Overview
Coverage Trend
Top Coverage Hotspots (lowest coverage)
Updated automatically; will refresh on subsequent CI/Docker completions. Keepalive checklistScope
Tasks
Acceptance criteria
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 39afdae37e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| steps.fingerprint.outputs.should_run == 'true' && | ||
| github.event_name == 'pull_request' && | ||
| github.event.action == 'labeled' && | ||
| github.event.label.name == 'agent:retry' |
There was a problem hiding this comment.
Allow agent:retry handling to run when fingerprint matches
Gating the agent:retry handler behind steps.fingerprint.outputs.should_run == 'true' breaks repeat retries on an unchanged PR state. After one retry run, the next pull_request:labeled event with agent:retry can produce the same fingerprint, so this step is skipped, which also skips removing the agent:retry label and prevents the requested retry path from executing.
Useful? React with 👍 / 👎.
| payload = { | ||
| "pr_number": int(pr_number), | ||
| "head_sha": pr.get("head", {}).get("sha", ""), | ||
| "diff_hash": diff_hash, | ||
| "verifier_trigger_labels": sorted( |
There was a problem hiding this comment.
Include dispatch mode/model inputs in verifier fingerprint
The fingerprint payload excludes manual dispatch parameters (mode, model, model2, provider), so two workflow_dispatch runs on the same merged PR can hash identically even when the operator changes verification settings. In that case fingerprint_should_run becomes false and the verifier job is skipped, defeating manual re-verification and compare-mode reruns.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR introduces a reusable “state fingerprint” helper (scripts/state_fingerprint.py) and wires it into several workflows (and consumer templates) to allow those workflows to quickly skip execution when the relevant PR/workflow state is unchanged.
Changes:
- Add
scripts/state_fingerprint.pyplus unit tests to compute/compare/persist a canonical hash of selected workflow inputs. - Integrate fingerprint comparison into multiple workflows (verifier, keepalive loop + reporter, PR meta, and gate branch protection) and gate downstream steps/jobs based on
should_run. - Register the new script in
.github/sync-manifest.ymlso it can be distributed to consumer repos.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/scripts/test_state_fingerprint.py | Adds unit tests covering hashing, compare decisions, warning mode, and marker parsing tolerance. |
| scripts/state_fingerprint.py | New helper implementing hash computation + storage backends (PR comment / repo variable) with GitHub Actions outputs. |
| .github/workflows/agents-verifier.yml | Computes fingerprint from PR diff surface + verify labels and gates verifier execution. |
| templates/consumer-repo/.github/workflows/agents-verifier.yml | Mirrors verifier fingerprint gating for consumer repos. |
| .github/workflows/agents-pr-meta-v4.yml | Adds fingerprint gating based on PR body sections + labels to skip redundant PR-body updates. |
| .github/workflows/agents-keepalive-loop.yml | Adds fingerprint gating based on PR head SHA, gate conclusion, and autofix/agent labels. |
| .github/workflows/agents-keepalive-loop-reporter.yml | Adds fingerprint gating based on workflow_run state (status/conclusion/head SHA). |
| templates/consumer-repo/.github/workflows/agents-keepalive-loop-reporter.yml | Mirrors keepalive reporter fingerprint gating for consumer repos. |
| templates/consumer-repo/.github/workflows/agents-81-gate-followups.yml | Adds fingerprint gating for gate followups based on PR state + labels. |
| .github/workflows/health-44-gate-branch-protection.yml | Adds repo-variable fingerprint gate to skip branch protection checks when required-contexts/default branch state is unchanged. |
| .github/sync-manifest.yml | Adds scripts/state_fingerprint.py to the list of synced consumer scripts. |
|
|
||
| pr = api(f"/repos/{repo}/pulls/{pr_number}") | ||
| files = paged(f"/repos/{repo}/pulls/{pr_number}/files") | ||
| labels = api(f"/repos/{repo}/issues/{pr_number}/labels") |
|
|
||
| pr = api(f"/repos/{repo}/pulls/{pr_number}") | ||
| files = paged(f"/repos/{repo}/pulls/{pr_number}/files") | ||
| labels = api(f"/repos/{repo}/issues/{pr_number}/labels") |
| pr = api(f"/repos/{repo}/pulls/{pr_number}") | ||
| labels = api(f"/repos/{repo}/issues/{pr_number}/labels") | ||
| body = pr.get("body") or "" | ||
| payload = { | ||
| "pr_number": int(pr_number), | ||
| "head_sha": pr.get("head", {}).get("sha", ""), | ||
| "body_section_hashes": { | ||
| marker: block_hash(body, marker) | ||
| for marker in ("pr-preamble", "auto-status-summary") | ||
| }, | ||
| "labels": sorted(label.get("name", "") for label in labels if label.get("name")), | ||
| } |
| pr = api(f"/repos/{repo}/pulls/{pr_number}") | ||
| labels = api(f"/repos/{repo}/issues/{pr_number}/labels") | ||
| label_names = sorted(label.get("name", "") for label in labels if label.get("name")) | ||
| payload = { |
| pr = api(f"/repos/{repo}/pulls/{pr_number}") | ||
| labels = api(f"/repos/{repo}/issues/{pr_number}/labels") |
| - source: scripts/state_fingerprint.py | ||
| description: "Computes workflow state fingerprints for unchanged-state skip gates" | ||
|
|
…TECTION_TOKEN in health-44 Wave 1's state-fingerprint helper (#1998 + #2002 wireup) broke Health 44 enforce because the workflow's GITHUB_TOKEN can't access the actions/variables endpoint even with `actions: write` set — that endpoint requires a token with Variables permission (PAT, GitHub App, or fine-grained PAT). Resulting failure observed on every PR running Health 44 enforce since #2002 merged (incl. PR #2006, PR #2007 today): GET /repos/stranske/Workflows/actions/variables/STATE_FINGERPRINT_HEALTH_44_GATE_BRANCH_PROTECTION_* failed: 403 "Resource not accessible by integration" Two-part fix: 1) `scripts/state_fingerprint.py` — `RepoVariableStorage` now treats 401/403 from the variables API as "storage unavailable" rather than fatal. Read returns None (no prior fingerprint), write skips silently, and a warning goes to stderr so the operator sees the misconfiguration in workflow logs. The existing 404 (no prior) path is unchanged. Effect: any workflow that adopts `--storage repo-variable` but doesn't have the right token degrades gracefully (skips the optimization, runs anyway) instead of failing outright. Future Wave 1+ workflows using repo-variable storage benefit from this. 2) `.github/workflows/health-44-gate-branch-protection.yml` — uses `BRANCH_PROTECTION_TOKEN` (already used downstream by `enforce`) when present, falling back to `GITHUB_TOKEN`. Now the fingerprint optimization actually works when the secret is configured. Existing 6 tests in tests/scripts/test_state_fingerprint.py still pass. py_compile clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…back (#2010) * fix(keepalive): handle no-checklist draft PRs with accurate disposition Phase 6 sync-PR review surfaced two related bugs in keepalive_orchestrator_gate_runner.js (Copilot review on stranske/* sync PRs): - routeDraftToHuman() emitted "0 unchecked checklist item(s)" when the PR had no checkboxes at all, suggesting the user just needed to check boxes that didn't exist. - The branching at line 404 fell through to the same "needs human" path for both genuine missing-acceptance-items cases and PRs that legitimately have no checklist at all. This change distinguishes the no-checklist case end-to-end: - Adds a noChecklist flag in the caller (computed once where checkboxCounts is built). - Threads noChecklist through routeDraftToHuman so the comment body and summary line accurately describe "no acceptance checklist found" vs "N unchecked items". - Adds a distinct reason key 'pr-draft-no-checklist' so weekly metrics can distinguish the two cases. Lockstep edit: canonical .github/scripts/ + templates/consumer-repo/ both updated identically. node --check passes on both. Out of scope here: the perceived "missing closing brace" Copilot flagged was already addressed by PR #1985 / #1986 on 2026-04-30 — the GraphQL mutation block in markDraftReadyForReview() has the correct three closing braces. The isConcreteAgentLabel() concern about agent:rate-limited / agent:retry routing as concrete agent labels is separate and needs broader review of the keepalive loop's label-routing semantics; deferred. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(state-fingerprint): graceful fallback on 401/403 + use BRANCH_PROTECTION_TOKEN in health-44 Wave 1's state-fingerprint helper (#1998 + #2002 wireup) broke Health 44 enforce because the workflow's GITHUB_TOKEN can't access the actions/variables endpoint even with `actions: write` set — that endpoint requires a token with Variables permission (PAT, GitHub App, or fine-grained PAT). Resulting failure observed on every PR running Health 44 enforce since #2002 merged (incl. PR #2006, PR #2007 today): GET /repos/stranske/Workflows/actions/variables/STATE_FINGERPRINT_HEALTH_44_GATE_BRANCH_PROTECTION_* failed: 403 "Resource not accessible by integration" Two-part fix: 1) `scripts/state_fingerprint.py` — `RepoVariableStorage` now treats 401/403 from the variables API as "storage unavailable" rather than fatal. Read returns None (no prior fingerprint), write skips silently, and a warning goes to stderr so the operator sees the misconfiguration in workflow logs. The existing 404 (no prior) path is unchanged. Effect: any workflow that adopts `--storage repo-variable` but doesn't have the right token degrades gracefully (skips the optimization, runs anyway) instead of failing outright. Future Wave 1+ workflows using repo-variable storage benefit from this. 2) `.github/workflows/health-44-gate-branch-protection.yml` — uses `BRANCH_PROTECTION_TOKEN` (already used downstream by `enforce`) when present, falling back to `GITHUB_TOKEN`. Now the fingerprint optimization actually works when the secret is configured. Existing 6 tests in tests/scripts/test_state_fingerprint.py still pass. py_compile clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: apply Black formatting to state_fingerprint.py 401/403 fallback --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes #1
Automated Status Summary
Scope
scripts/validate_fast.shcontains 12 TODO Phase 4 markers referencing Trend_Model_Project-specific features (SRC_FILES detection, autofix tests, coverage requirements) that are not applicable to this workflow repository. These dead code paths and stale references cause confusion and add maintenance burden.Tasks
src/directory patterns not present in this repo.scripts/and.github/instead ofsrc/ tests/.Acceptance criteria
grep -c "TODO Phase" scripts/validate_fast.shreturns 0.bash scripts/validate_fast.sh --helpworks.src/directory or Trend_Model_Project-specific patterns remain.Head SHA: 39afdae
Latest Runs: ✅ success — Gate
Required: gate: ✅ success