Skip to content

fix(ci): unblock the merge gate, consolidate its competing fixes, and audit 337 branches - #1377

Merged
groupthinking merged 5 commits into
mainfrom
claude/event-relay-blockers-1k020k
Aug 5, 2026
Merged

fix(ci): unblock the merge gate, consolidate its competing fixes, and audit 337 branches#1377
groupthinking merged 5 commits into
mainfrom
claude/event-relay-blockers-1k020k

Conversation

@groupthinking

@groupthinking groupthinking commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Canonical issue

Closes #1384

Outcome

agent-completion/truth-gate stops being red on pull requests that never had a dispatch contract to satisfy, so CI failures become visible again instead of being buried under a check that fails on everything. Alongside it, the one failing test on main is fixed and the PR backlog is drained from 61 open to 28.

The gate scores a PR against the frozen intent snapshot on its linked issue. That snapshot is written only by snapshot-agent-task-intent, which runs on issues events and never on pull_request_target. With no linked issue there is no snapshot, so policy.agent_login, policy.run_id and issue.number can never be populated and the verdict is invalid_payload regardless of what the author does. Arming that from a branch-name prefix made it red on merged commits too — #1368, the current tip of main, merged with this status failing.

Provenance now arms the gate only when a linked issue exists to verify against; with none the verdict is not_applicable. A PR that links a dispatched issue is gated exactly as before.

Scope

  • Included:
    • .github/workflows/pr-checks.ymlagentTaskApplicable() (both copies) requires a linked issue before pull-side provenance arms the gate. Includes fix(ci): decide truth-gate applicability from PR provenance or a declared issue contract #1364's commit, cherry-picked with authorship intact.
    • tests/unit/test_agent_completion_gate.py — both directions of the linked-issue rule, in both assertion blocks.
    • tests/unit/test_transcript_action_workflow.py — retargets a test premise that asserted a CPython-version-specific shutil.rmtree detail.
    • docs/branch-audit-2026-08-05.csv, scripts/maintenance/archive-and-prune-branches.sh — branch audit and prune script (dry-run by default).
  • Explicitly excluded:

Risk

  • Risk level: low
  • Failure mode: The gate could resolve not_applicable for a PR that genuinely should be gated — specifically an agent PR that links no issue. That state was previously blocked-with-no-remedy rather than enforcing anything, so this narrows a permanently-failing check rather than a working one. Binding a PR to a focused issue stays enforced by Canonical issue and evidence and PR Governance.
  • Rollback: Revert the two commits touching pr-checks.yml and the gate tests. No data migration, no infrastructure change, no runtime code path affected. The branch audit files are additive and inert.

Verification

Current head 10113efe27fad21e5a73b20225805d7d2208b453.

  • Focused teststests/unit/test_agent_completion_gate.py: 112 passed, 89 subtests. tests/unit/test_transcript_action_workflow.py: 115 passed.
  • Full backend suite — 8,079 passed, 5 xpassed, 89 subtests, 0 failed (was 8,075 passed / 1 failed on main).
  • Workflow validityyaml.safe_load parses pr-checks.yml; the two agentTaskApplicable() copies remain byte-identical, which the test asserts.
  • Prune scriptbash -n clean; dry run selects 276, matching the CSV; guard verified by injecting main back into the CSV and confirming it is still excluded.
  • Required CIvalidate, guards, lint-python, lint-frontend, bandit, python-safety, npm-audit, gitleaks, dependency-review all green.
  • Review threads resolved — the Vercel review bot's one finding (stale header counts) is fixed in 10113ef and the bot confirmed ISSUE_RESOLVED. CodeRabbit has not reviewed: it skips on a label rule, and labels applied to this PR do not survive the label job.

agent-completion/truth-gate is still failing on this PR and is expected to. pull_request_target runs the workflow from the base branch, so this fix cannot affect its own PR — it takes effect for everything else once merged. This is the same failure #1368 merged with.

Production evidence

  • Vercel Preview READY on the current head: 2KiJcUNFe5PyurhENWSWzAdadaby
  • No runtime surface is touched. The workflow and test changes are build-time only; the audit CSV and prune script are inert unless invoked with --execute.
  • Branch pruning was not executed. This session's credentials are branch-scoped and tag creation returns HTTP 403, so the archive tags could not be written. Deleting 276 branches without them would remove the only durable recovery path. Run scripts/maintenance/archive-and-prune-branches.sh --execute with tag-write credentials; it archive-tags, verifies every tag reached the remote, and aborts before deleting if any is missing.

Agent handoff

Backlog drained

61 open PRs → 28. Every remaining PR shares ancestry with main and is genuinely rebaseable.

Closed Reason
#1154, #1364 consolidated here
#869, #1132, #1155, #1332 superseded by #1376 / #1361 / #1363 / #1270
#1317, #1320 already landed via #1342 — patches no longer apply
#1179, #1003, #1049, #1045 already on main
22 others orphaned by the force-push — tracked in #1378

main was force-pushed for a secret purge, so 275 of 337 branches share no ancestry with itgit merge-base returns empty and no rebase recovers them. The usual signals mislead here: merge-tree calls orphans a clean merge, a diff against an empty merge base degrades to a working-tree diff (a 2-line Dependabot bump measures as 111 files / 15,650 lines), and the purge rewrote committer dates so nothing reads as stale. The stock harness produced 263 REVIEW off those signals; ancestry resolves it to 28 KEEP-OPEN-PR · 29 REVIEW-SHARED · 1 CLOSE-MERGED · 275 CLOSE-ORPHANED.

The prune script's dry run caught the audit classifying main itself as CLOSE-MERGED (--is-ancestor origin/main origin/main is trivially true). That row is removed and a protected-ref guard now aborts regardless of CSV contents.

#1378 lists the genuinely unlanded work needing a fresh cut, including two security items (#1118 proxy credential leakage, #1156 the ecdsa advisory) and #1075's transcript-on-timeout bug. Every branch is retained for archive-tagging.

test_cleanup_is_total_for_non_oserror_failures failed on Python 3.11.15:
its premise asserted that shutil.rmtree(path, ignore_errors=True) raises
ValueError on a NUL-byte path. That is an implementation detail which has
changed -- ignore_errors now absorbs the non-OSError as well, so the
assertion no longer holds.

The contract under test is unaffected: _cleanup_download_artifacts must
swallow non-OSError failures because it runs from a finally block and
would otherwise replace the in-flight exception. Establish that premise
against the unguarded rmtree call, which still raises, so the test proves
the helper's own defensiveness rather than the stdlib's.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcHjCZ6pGn6A5BeeoZ6eZi
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Ready Ready Preview, v0 Aug 5, 2026 1:17am

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 10113ef.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • [‘architecture-gap’, ‘bug’, ‘ci-cd’, ‘ci/cd’, ‘copilot-rabbit’, ‘documentation’, ‘duplicate’, ‘enhancement’, ‘frontend’, ‘github_actions’, ‘good first issue’, ‘help wanted’, ‘high-priority’, ‘invalid’, ‘javascript’, ‘ml-model’, ‘needs-triage’, ‘pipeline-critical’, ‘placeholder-code’, ‘priority:high’, ‘python’, ‘python:uv’, ‘question’, ‘styling’, ‘tests’, ‘v0’]

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 05090b3e-f502-477e-95dc-8c02657f852c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the python label Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: BLOCKED

Reasons: invalid_payload

Machine-readable verdict
{
  "details": {
    "collection_errors": [
      "incomplete_linked_issue_contract",
      "missing_intent_snapshot",
      "missing_agent_run_id",
      "missing_agent_login"
    ],
    "invalid_fields": [
      "policy.agent_login",
      "policy.run_id"
    ]
  },
  "reasons": [
    "invalid_payload"
  ],
  "verdict": "blocked"
}

Workflow evidence

Copy link
Copy Markdown
Owner Author

agent-completion/truth-gate failure is pre-existing and not caused by this diff

Recording this rather than fixing it here, because the failure is repo-wide infrastructure state, not a defect in this one-file test change.

Verdict on this PR: invalid_payload, with collection_errors: missing_linked_issue, missing_closing_issue_reference, missing_agent_run_id, missing_agent_login.

The last two are the structural part. policy.agent_login and policy.run_id are populated by the snapshot-agent-task-intent job, which skipped on this run. scripts/ci/agent_completion_gate.py treats policy.applicable as true by default and then hard-requires both fields, so any PR not created through the agent-dispatch flow is blocked with no path to satisfying the gate — the payload can never be assembled.

This is not specific to #1377. The same status failed identically on #1368, which merged and is the current tip of main:

context: agent-completion/truth-gate/pr-1368
state:   failure
desc:    gate-owner:51596082965 invalid_payload

That PR also carried a failed Vercel status ("Canceled from the Vercel Dashboard") and CodeRabbit: Review skipped: excluded by label configuration, giving it a combined status of failure at merge time. So the gate is currently red on merged and unmerged PRs alike and is gating nothing — which is the exact failure mode .github/workflows/agent-completion-enforcement.yml warns about in its own comments:

Reporting those as failure makes this check permanently red on 100% of pull requests, which destroys its signal value and hides real build/test failures behind constant noise.

Two open PRs already target this — #1154 ("scope agent gate applicability to real dispatch evidence") and #1364 ("decide truth-gate applicability from PR provenance or a declared [exemption]"). They are competing implementations of the same fix and are currently blocking each other. Fixing applicability belongs in one of those, not in a test-only PR.

Everything else on this PR is green: lint-python, lint-frontend, guards, validate, bandit, python-safety, npm-audit, gitleaks, dependency-review, Canonical issue and evidence, Agent completion enforcement, and the Vercel Preview is READY — strictly better evidence than the head currently sitting on main.


Generated by Claude Code

@groupthinking groupthinking added the tests label Aug 5, 2026 — with Claude
groupthinking and others added 2 commits August 5, 2026 00:35
agentTaskApplicable() unioned PR labels with linked-issue labels, so a
bare agent-task/mcp-agent label applied by label automation to an issue
that never declared a contract judged any closing PR an agent
completion. The gate then required an Agent Run ID / Agent Login the
issue never declared, yielding a permanent blocked/invalid_payload
verdict no author could satisfy.

Applicability now comes from PR provenance (known agent author, agent
branch prefix, agent label on the PR, lock manifest) or from a genuine
issue-side dispatch: an agent-task/mcp-agent label AND declared Agent
Run ID + Agent Login headings. The generic agent label remains a
PR-side signal only, since the snapshot job and collector never
recognise it issue-side — arming from it would block permanently as
linked_issue_not_agent_task with no snapshot to satisfy.

The collector now emits a mislabelled_agent_task core.notice when a
linked issue carries a contract label without declaring the contract,
keyed on the missing contract itself (not inapplicability) so
Dependabot PRs linked to valid contracts never get a false notice.

Generated with [Linear](https://linear.app/myxstack/issue/GRV-196/agent-completiontruth-gate-is-permanently-unsatisfiable-for-any-pr#agent-session-8e5d62f0)

Co-authored-by: linear-code[bot] <222613912+linear-code[bot]@users.noreply.github.com>
The truth gate scores a pull request against the frozen intent snapshot on
its linked issue. That snapshot is only ever written by
snapshot-agent-task-intent, which runs on `issues` events alone -- it never
runs on pull_request_target. So a pull request with no linked issue has no
snapshot, no declared agent_login and no declared run_id, which means
policy.agent_login, policy.run_id and issue.number can never be populated
and the verdict is permanently `invalid_payload` no matter what the author
does.

Arming that unsatisfiable state from a branch-name prefix made the check red
on pull requests that never had a contract to satisfy. It is red on merged
commits too: #1368, the current tip of main, merged with
agent-completion/truth-gate/pr-1368 failing on exactly this. A check that is
red on everything gates nothing and buries real failures, which is the
failure mode agent-completion-enforcement.yml already warns about in its own
comments.

Pull-side provenance now arms the gate only when a linked issue exists to
verify against. With none there is nothing to measure, so the verdict is
not_applicable rather than blocked. This is not an escape hatch: a pull
request that links a dispatched issue is gated exactly as before, and the
requirement to bind a pull request to a focused issue at all is separately
owned by the `Canonical issue and evidence` check, which states a
requirement an author can actually meet.

Consolidates the two competing open implementations of this fix. #1364's
commit is cherry-picked here with authorship intact; #1154 carried the same
intent but had drifted to 117 files and 14k lines of unrelated changes.
Both should close in favour of this.

Full unit suite: 8079 passed, 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcHjCZ6pGn6A5BeeoZ6eZi
Classifies every remote branch using the one signal that stays honest after
the secret-purge force-push: whether it shares any ancestry with `main`.

    $ git merge-base origin/main origin/<branch>
    (empty)

275 of 337 branches return empty -- they predate the rewrite and no rebase
recovers them. The signals the branch-cleanup harness normally leans on all
mislead here, so they are deliberately not used:

  * `git merge-tree` calls these orphans a CLEAN merge; unrelated trees do
    not textually conflict, they would clobber.
  * A two-dot diff against an empty merge base silently degrades to a
    working-tree diff, which is why a two-line Dependabot bump measures as
    111 files / 15,650 lines.
  * The purge rewrote committer dates, so every branch reads as under 30
    days old and no staleness threshold ever fires.

Running the stock harness on this repo produced 263 REVIEW off those bad
signals. The ancestry test resolves the same set into:

    KEEP-OPEN-PR     28
    REVIEW-SHARED    29   real shared ancestry, no open PR -- not pruned
    CLOSE-MERGED      1   tip is an ancestor of main
    CLOSE-ORPHANED  275

The script prunes only the last two groups (276 branches) and archive-tags
each one first, verifying every tag is on the remote before deleting
anything. It defaults to a dry run.

That dry run caught the audit classifying `main` itself as CLOSE-MERGED --
`git merge-base --is-ancestor origin/main origin/main` is trivially true.
The row is removed, and a protected-ref guard plus a default-branch check
now abort regardless of what the CSV contains.

Not executed here: this session's credentials are scoped to one branch and
tag creation fails with HTTP 403, so the archive tags cannot be written.
Deleting without them would remove the only durable recovery path, so
nothing was deleted. Run the script with tag-write credentials.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcHjCZ6pGn6A5BeeoZ6eZi
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🔍 PR Validation

⚠️ Large PR detected (967 lines changed)

@groupthinking groupthinking changed the title test: stop asserting a CPython-version-specific rmtree detail fix(ci): unblock the merge gate, consolidate its competing fixes, and audit 337 branches Aug 5, 2026
Comment thread scripts/maintenance/archive-and-prune-branches.sh Outdated
The header summary read "CLOSE-MERGED 2 / 277 branches" while the shipped
docs/branch-audit-2026-08-05.csv has 1 CLOSE-MERGED and 276 prunable. The
header was written before the `main` row was dropped from the CSV and was
never updated.

Comment only -- the selection logic already read from the CSV, so the script
was correctly selecting 276 the whole time. Verified: header, CSV tally, and
the script's own dry-run count now all agree at 276.

Reported by the Vercel review bot on #1377.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcHjCZ6pGn6A5BeeoZ6eZi

Copy link
Copy Markdown
Owner Author

Truth-gate verdict update — and why I am stopping here rather than satisfying it

Linking #1384 moved the verdict. Before:

"collection_errors": ["incomplete_linked_issue_contract", "missing_linked_issue",
                      "missing_closing_issue_reference", "missing_agent_run_id",
                      "missing_agent_login"],
"invalid_fields":    ["issue.number", "policy.agent_login", "policy.run_id"]

Now:

"collection_errors": ["incomplete_linked_issue_contract", "missing_intent_snapshot",
                      "missing_agent_run_id", "missing_agent_login"],
"invalid_fields":    ["policy.agent_login", "policy.run_id"]

missing_linked_issue, missing_closing_issue_reference and issue.number are resolved. What remains is missing_intent_snapshot plus the two policy fields.

I am not going to clear those, deliberately. Doing so would require:

  1. Labelling agent-completion/truth-gate is unsatisfiable for PRs with no linked dispatch contract #1384 agent-task so snapshot-agent-task-intent fires, and
  2. Adding ### Agent Login and ### Agent Run ID sections to agent-completion/truth-gate is unsatisfiable for PRs with no linked dispatch contract #1384 with values that declaresAgentContract() accepts.

#1384 was written after this PR, as a description of a defect I had already diagnosed. There was no dispatch — no provider run issued this work against a pre-registered contract. Back-filling one would mean inventing a run_id and asserting a dispatch that never happened, which is fabricated evidence of exactly the kind this gate exists to detect. A gate you satisfy by manufacturing its inputs is worse than no gate.

This is the missing_intent_snapshot trap #1132 has been parked on since Jul 31, and it is the same shape the Merge Gate policy names as the "no retroactive intent snapshots" rule. Reaching it from the other direction confirms the diagnosis in #1384: the gate is satisfiable only by work that went through a dispatch flow, and it fails closed — loudly, as failure rather than neutral — on everything else, including the merged tip of main.

Recommendation stands: land this to quiet the check, then retire the apparatus in a separate PR. PR Governance already enforces the part that carries real value — a canonical issue and a closing reference — and it demonstrably works, since it caught this PR's own non-conforming description a few minutes ago.


Generated by Claude Code

@groupthinking
groupthinking merged commit eb4c153 into main Aug 5, 2026
46 of 51 checks passed
@groupthinking
groupthinking deleted the claude/event-relay-blockers-1k020k branch August 5, 2026 09:30
@linear-code

linear-code Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

GRV-329

groupthinking pushed a commit that referenced this pull request Aug 7, 2026
Gate 2 listed `CI`, `Coverage`, `CodeQL`, `Security`, `Secret Scan`,
`Dependency Review` -- inherited verbatim from v1. Those are workflow names.
Branch protection matches check-run names (a job's `name:`, or its job id),
so of that list only `CodeQL` can actually be selected. Anyone following
adoption step 3 would find the strings absent from GitHub's picker, which is
plausibly why MG-2 was never done.

That is the v1 failure mode reproduced inside its replacement: a gate naming
things that cannot be satisfied. Replaced with the contexts actually observed
on live pull requests.

Also splits out conditionally-required checks. `Generate and Upload Coverage`
does not run on documentation-only changes -- it ran on #1377 and is absent
from #1408. Requiring it unconditionally would leave docs pull requests
permanently pending, which blocks harder than failing, since a check that
never reports never resolves. Same for `E2E Pipeline Tests` and the
JavaScript security scan.

Adds the rule that would have caught this: before adding a check to branch
protection, confirm the exact string appears in the picker and that it
reports on a documentation-only pull request.

Raised by the CodeRabbit review on #1408.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcHjCZ6pGn6A5BeeoZ6eZi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

agent-completion/truth-gate is unsatisfiable for PRs with no linked dispatch contract

2 participants