From f69cb57ab8ba9875eb265c5cb8de830a6c9973fd Mon Sep 17 00:00:00 2001 From: Jack Arturo Date: Mon, 22 Jun 2026 18:33:23 +0200 Subject: [PATCH 1/2] ci(docs): autonomous docs-audit merge gated on an explicit confidence marker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lets the docs-audit bot merge fully autonomously when it is confident, while still parking anything it flags for a human. - update-docs prompt: the auditing agent must end every PR body with exactly one marker — `` (everything verified, no open questions) or `` (open questions / unverifiable claims / follow-ups). Decision rule + "when unsure, HOLD". - docs-auto-merge: drop the `!draft` job gate so the workflow evaluates drafts too; replace the brittle prose-regex guard with a marker check. CLEAR -> mark ready for review + enable squash auto-merge. HOLD or no marker -> leave as a draft (fail-safe). Draft now means "the agent wasn't sure", which is the human-in-the-loop signal we actually want. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/prompts/update-docs.md | 24 ++++++++++++++++++ .github/workflows/docs-auto-merge.yml | 36 +++++++++++++++++++-------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/.github/prompts/update-docs.md b/.github/prompts/update-docs.md index 96da42b..c075d28 100644 --- a/.github/prompts/update-docs.md +++ b/.github/prompts/update-docs.md @@ -35,6 +35,30 @@ The documentation covers three repositories: See `scripts/file-doc-map.json` for the complete source-file-to-doc-page mapping. The map covers all three repos with exact paths and `/**` subtree patterns. +## PR description and confidence marker (REQUIRED) + +Write the PR description as a concise audit summary: + +- A `## Fixes` table (Claim | Current state | Fix) for every change you made, + citing the source SHA you verified against. +- An optional `## Open questions` or `## Follow-ups` section for anything you + could NOT confirm from the source, anything that needs a human decision, or + drift you noticed but did not fix. + +End the description with EXACTLY ONE confidence marker on its own line. This +marker controls whether the PR auto-merges, so it is mandatory: + +- `` — every edit is verified against the source at a + named SHA and you have NO open questions, unverifiable claims, or follow-ups. + The PR is marked ready for review and auto-merged once CI passes. +- `` — you have one or more open questions, claims you + could not confirm, or follow-up items. The PR stays a draft for a maintainer. + +Decision rule: if you wrote anything under an "Open questions", "Follow-ups", or +"could not confirm" heading, you MUST use HOLD. When genuinely unsure, choose +HOLD — a held PR costs a maintainer one glance, but a wrongly auto-merged guess +ships incorrect documentation. A missing marker is treated as HOLD. + ## Commit message format Use: `docs: update [page-names] to reflect [source-repo]@[short-sha]` diff --git a/.github/workflows/docs-auto-merge.yml b/.github/workflows/docs-auto-merge.yml index 7c8a017..c7f869a 100644 --- a/.github/workflows/docs-auto-merge.yml +++ b/.github/workflows/docs-auto-merge.yml @@ -1,5 +1,13 @@ name: Docs Auto-Merge +# Autonomous merge for the docs-audit bot (.github/workflows/docs-update.yml). +# The auditing agent ends every PR body with a confidence marker: +# -> agent verified everything; mark ready + auto-merge. +# -> agent flagged open questions; leave as a draft. +# Fail-safe: a HOLD marker OR no marker at all keeps the PR a draft for a human. +# To ship a HELD PR, a maintainer replaces the marker with CLEAR (or merges by hand); +# marking it "ready" alone will not auto-merge while the body still says HOLD. + on: pull_request_target: types: [opened, reopened, synchronize, ready_for_review] @@ -16,29 +24,37 @@ jobs: github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.repo.full_name == github.repository && startsWith(github.event.pull_request.head.ref, 'docs/audit-') && - startsWith(github.event.pull_request.title, 'docs:') && - !github.event.pull_request.draft + startsWith(github.event.pull_request.title, 'docs:') }} runs-on: ubuntu-latest concurrency: group: docs-auto-merge-${{ github.event.pull_request.number }} cancel-in-progress: false steps: - - name: Check for unresolved audit notes + - name: Check docs-audit confidence marker id: guard env: GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }} PR_URL: ${{ github.event.pull_request.html_url }} run: | BODY="$(gh pr view "$PR_URL" --json body --jq '.body // ""')" - if printf '%s\n' "$BODY" | grep -Eiq 'follow-up questions|open question|not addressed|maintainer input|needs maintainer|unresolved'; then - echo "PR body contains unresolved audit language; leaving it for maintainer review." + # HOLD always wins: the agent flagged something for a human to decide. + if printf '%s' "$BODY" | grep -Eiq ''; then + echo "PR is marked HOLD; leaving it as a draft for maintainer review." echo "eligible=false" >> "$GITHUB_OUTPUT" exit 0 fi - echo "eligible=true" >> "$GITHUB_OUTPUT" + # CLEAR is the only state that auto-merges. + if printf '%s' "$BODY" | grep -Eiq ''; then + echo "PR is marked CLEAR; eligible for ready + auto-merge." + echo "eligible=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + # No marker => fail safe to human review. + echo "PR has no docs-audit confidence marker; defaulting to HOLD (draft)." + echo "eligible=false" >> "$GITHUB_OUTPUT" - - name: Enable auto-merge for eligible docs PR + - name: Mark ready and enable auto-merge if: steps.guard.outputs.eligible == 'true' env: GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }} @@ -48,14 +64,14 @@ jobs: PR_JSON="$(gh pr view "$PR_URL" --json state,isDraft,autoMergeRequest)" PR_STATE="$(echo "$PR_JSON" | jq -r '.state')" if [ "$PR_STATE" != "OPEN" ]; then - echo "PR is $PR_STATE; auto-merge is no longer needed." + echo "PR is $PR_STATE; nothing to do." exit 0 fi IS_DRAFT="$(echo "$PR_JSON" | jq -r '.isDraft')" if [ "$IS_DRAFT" = "true" ]; then - echo "PR is still a draft; skipping auto-merge (the ready_for_review event will handle it)." - exit 0 + echo "Marking draft PR ready for review." + gh pr ready "$PR_URL" fi AUTO_MERGE_ENABLED="$(echo "$PR_JSON" | jq -r '.autoMergeRequest != null')" From d61bc320ddb952aac340c5161de8e54e9835a460 Mon Sep 17 00:00:00 2001 From: Jack Arturo Date: Mon, 22 Jun 2026 18:46:44 +0200 Subject: [PATCH 2/2] ci(docs): make the marker guard authoritative on re-runs (Codex review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cancel stale auto-merge on HOLD/no-marker: a prior CLEAR run enables auto-merge, and GitHub does not auto-cancel it for same-repo bot pushes (write access), so a CLEAR->HOLD flip would still merge after CI. The not-eligible path now runs `gh pr merge --disable-auto`. - Add the `edited` trigger so editing a PR body from HOLD to CLEAR actually re-runs the guard — the documented maintainer override. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/docs-auto-merge.yml | 28 +++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-auto-merge.yml b/.github/workflows/docs-auto-merge.yml index c7f869a..85767ac 100644 --- a/.github/workflows/docs-auto-merge.yml +++ b/.github/workflows/docs-auto-merge.yml @@ -4,13 +4,15 @@ name: Docs Auto-Merge # The auditing agent ends every PR body with a confidence marker: # -> agent verified everything; mark ready + auto-merge. # -> agent flagged open questions; leave as a draft. -# Fail-safe: a HOLD marker OR no marker at all keeps the PR a draft for a human. -# To ship a HELD PR, a maintainer replaces the marker with CLEAR (or merges by hand); -# marking it "ready" alone will not auto-merge while the body still says HOLD. +# Fail-safe: a HOLD marker OR no marker at all keeps the PR a draft for a human, +# and proactively cancels any auto-merge a prior CLEAR run may have enabled. +# To ship a HELD PR, a maintainer edits the body to replace HOLD with CLEAR (the +# `edited` trigger re-runs this guard) or merges by hand; marking it "ready" +# alone will not auto-merge while the body still says HOLD. on: pull_request_target: - types: [opened, reopened, synchronize, ready_for_review] + types: [opened, reopened, synchronize, ready_for_review, edited] permissions: contents: write @@ -54,6 +56,24 @@ jobs: echo "PR has no docs-audit confidence marker; defaulting to HOLD (draft)." echo "eligible=false" >> "$GITHUB_OUTPUT" + - name: Cancel stale auto-merge when held + if: steps.guard.outputs.eligible != 'true' + env: + GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }} + PR_URL: ${{ github.event.pull_request.html_url }} + run: | + # GitHub only auto-cancels auto-merge when a user WITHOUT write access + # pushes. Same-repo docs/audit- bot pushes keep a prior CLEAR run's + # auto-merge alive, so a CLEAR->HOLD flip would still merge after CI. + # Make the guard authoritative: tear down any active request on HOLD. + AUTO_MERGE_ENABLED="$(gh pr view "$PR_URL" --json autoMergeRequest --jq '.autoMergeRequest != null')" + if [ "$AUTO_MERGE_ENABLED" = "true" ]; then + echo "Marker is HOLD/absent but auto-merge was enabled; disabling it." + gh pr merge "$PR_URL" --disable-auto + else + echo "No active auto-merge request to disable." + fi + - name: Mark ready and enable auto-merge if: steps.guard.outputs.eligible == 'true' env: