fix: clarify draft ready GraphQL mutation - #1985
Conversation
Automated Status SummaryHead SHA: fd540e9
Coverage Overview
Coverage Trend
Top Coverage Hotspots (lowest coverage)
Updated automatically; will refresh on subsequent CI/Docker completions. Keepalive checklistScopeNo scope information available Tasks
Acceptance criteria
|
There was a problem hiding this comment.
Pull request overview
This PR clarifies the “mark draft PR ready for review” GraphQL mutation used by the keepalive orchestrator gate runner by centralizing the mutation text in a named constant and adding a targeted regression assertion in the runner test.
Changes:
- Introduces a named
MARK_DRAFT_READY_FOR_REVIEW_MUTATIONconstant with an explicit outer selection set. - Updates the gate runner to pass the constant into
github.graphql(...)instead of an inline template literal. - Adds a test assertion that the emitted mutation is the expected ready-for-review mutation and that braces are balanced.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
templates/consumer-repo/.github/scripts/keepalive_orchestrator_gate_runner.js |
Intended to mirror the mutation-constant refactor for consumer templates. |
.github/scripts/keepalive_orchestrator_gate_runner.js |
Refactors the ready-for-review GraphQL mutation into a named constant and uses it in markDraftReadyForReview. |
.github/scripts/__tests__/keepalive-orchestrator-gate-runner.test.js |
Adds assertions validating the mutation emitted for checklist-complete draft PR conversion. |
| const braceBalance = [...github.__calls.graphql[0].query].reduce( | ||
| (balance, char) => balance + (char === '{' ? 1 : char === '}' ? -1 : 0), | ||
| 0 | ||
| ); |
There was a problem hiding this comment.
The brace-balance assertion only checks the final {/} count, so it can still pass for improperly nested braces (e.g., a leading } followed by { later). If the goal is to ensure the mutation has properly balanced braces, also assert that the running balance never drops below 0 while iterating through the query string.
| const braceBalance = [...github.__calls.graphql[0].query].reduce( | |
| (balance, char) => balance + (char === '{' ? 1 : char === '}' ? -1 : 0), | |
| 0 | |
| ); | |
| let braceBalance = 0; | |
| for (const char of github.__calls.graphql[0].query) { | |
| if (char === '{') { | |
| braceBalance += 1; | |
| } else if (char === '}') { | |
| braceBalance -= 1; | |
| } | |
| assert.ok(braceBalance >= 0); | |
| } |
| } | ||
|
|
||
| async function markDraftReadyForReview({ github, pr, core, summary }) { | ||
| const nodeId = String(pr?.node_id || '').trim(); | ||
| if (!nodeId || typeof github.graphql !== 'function') { | ||
| summary.addRaw('Draft PR could not be converted automatically: missing GraphQL PR node id.').addEOL(); | ||
| return false; | ||
| } | ||
|
|
||
| try { |
There was a problem hiding this comment.
The consumer template version of this runner is still using an inline anonymous GraphQL mutation string in markDraftReadyForReview, which means it won’t get the clarified named/fully-braced mutation used by the repo-local script. To keep consumer templates in sync with the source script, introduce the shared MARK_DRAFT_READY_FOR_REVIEW_MUTATION constant here and pass it to github.graphql(...) just like in .github/scripts/keepalive_orchestrator_gate_runner.js.
…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>
Summary
Validation
Source fix for sync-generated consumer PR review thread: stranske/Travel-Plan-Permission#1004.