feat: add state-fingerprint shared helper for unchanged-state skip - #1998
Conversation
Automated Status SummaryHead SHA: 2b022a0
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.
Pull request overview
This PR introduces a new shared Python helper (scripts/state_fingerprint.py) intended to compute/persist a small JSON “state fingerprint” and emit GitHub Actions outputs that enable unchanged-state skip gates. It also adds unit tests for the helper and registers the script in the consumer sync manifest.
Changes:
- Add
scripts/state_fingerprint.pyCLI/library for computing, comparing, and storing workflow state fingerprints via PR comments or repo variables. - Add pytest coverage for core fingerprint/compare behavior plus the CLI “warning” mode output behavior.
- Register the new script in
.github/sync-manifest.ymlunder thescripts:section.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
scripts/state_fingerprint.py |
New helper script implementing fingerprint compute/compare + GitHub-backed storage backends and a compare CLI. |
tests/scripts/test_state_fingerprint.py |
Adds tests for canonicalization, compare decisions, warning mode behavior, and malformed marker tolerance. |
.github/sync-manifest.yml |
Adds the new helper to the scripts list so it can be distributed to consumer repos. |
| """Compute and persist workflow state fingerprints. | ||
|
|
||
| The helper gives workflows a cheap unchanged-state gate. Callers provide a | ||
| workflow name and a deliberately small JSON input surface; the script hashes the | ||
| canonical JSON representation, compares it with the prior stored value, and | ||
| emits GitHub Actions outputs that downstream steps can use for ``if:`` gates. | ||
| """ |
|
|
||
| if not payload: | ||
| return None | ||
| return json.loads(payload) |
| return int(os.environ["PR_NUMBER"]) | ||
|
|
||
| event_path = os.environ.get("GITHUB_EVENT_PATH") | ||
| if not event_path: | ||
| raise RuntimeError("PR_NUMBER or GITHUB_EVENT_PATH is required for pr-comment storage") | ||
|
|
||
| with open(event_path, encoding="utf-8") as handle: | ||
| event = json.load(handle) |
| - 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: 1b8a469
Latest Runs: ✅ success — Gate
Required: gate: ✅ success