Skip to content

fix(agent-actions): re-verify live CI before a merge or heuristic close - #2364

Merged
JSONbored merged 8 commits into
mainfrom
claude/actuation-live-ci-recheck
Jul 1, 2026
Merged

fix(agent-actions): re-verify live CI before a merge or heuristic close#2364
JSONbored merged 8 commits into
mainfrom
claude/actuation-live-ci-recheck

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

What

The freshness guard in executeAgentMaintenanceActions re-checks head SHA and PR state before every live action, but not CI. The CI aggregate that drove a heuristic close or a merge decision is read once in the planning pass, seconds-to-tens-of-seconds before actuation, and never re-read at the moment of mutation. GitHub's own merge endpoint enforces branch-protection required checks server-side, but only as a backstop when a repo actually configures them — and a heuristic close has no server-side check at all. A required check that flips green in the narrow window between planning and actuation could still get a PR closed on stale information: unlike the deterministic linked-issue-hard-rule close, a heuristic CI-driven close has no flag-then-verify pass.

Fix

Add a new guard step to executeAgentMaintenanceActions (src/services/agent-action-executor.ts), right after the existing freshness guard: immediately before a merge or a heuristic close (closeKind: "heuristic"), re-derive live CI via the existing fetchLiveCiAggregate helper and deny the action if:

  • merge: live CI now shows "failed" (a regression since planning), or
  • close: live CI no longer shows "failed" (the failure that justified the close no longer holds — pending/passed/unverified all invalidate it).

Deterministic closes (linked-issue hard-rule, blacklist) are exempt — they're zero-hallucination facts that don't depend on CI, and the linked-issue rule already has its own flag-then-verify pass. Best-effort: a token-mint failure fails open, since this is a defense-in-depth check, not the primary gate — the freshness check immediately above it already fails closed on an unverifiable PR state.

Tests

  • Heuristic close is denied when live CI has since turned green; proceeds when still failing.
  • A non-heuristic close (linked-issue hard-rule) skips the CI re-check entirely (fetchLiveCiAggregate not called).
  • Merge is denied when live CI has since turned failing.
  • The CI re-check fails open on a token-mint error (merge still proceeds).

Full unsharded test:coverage green; typecheck green; npm audit clean.

Advances #1936. Closes #2128.

The freshness guard in executeAgentMaintenanceActions re-checks head SHA
and PR state before every live action, but not CI. The CI aggregate that
drove a heuristic close or a merge decision is read once in the planning
pass, seconds-to-tens-of-seconds before actuation, and never re-read at
the moment of mutation. GitHub's merge endpoint enforces branch-protection
required checks server-side only as a backstop when a repo configures
them, and a heuristic close has no server-side check at all — unlike the
deterministic linked-issue-hard-rule close, a heuristic CI-driven close
has no flag-then-verify pass either.

Add a new guard step that re-derives live CI via the existing
fetchLiveCiAggregate helper immediately before a merge or a heuristic
close (closeKind: "heuristic"), and denies the action if a merge's CI has
since turned failed, or a close's CI is no longer failed. Deterministic
closes (linked-issue hard-rule, blacklist) are exempt. Best-effort: a
token-mint failure fails open, since this is a defense-in-depth check,
not the primary gate (the freshness check above it already fails closed
on an unverifiable PR state).
@dosubot dosubot Bot added the size:M label Jul 1, 2026
@loopover-orb

loopover-orb Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Caution

🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥

🛑 Gittensory review result - fixes required

Review updated: 2026-07-01 20:27:51 UTC

5 files · 1 AI reviewer · no blockers · readiness 75/100 · CI failing · blocked

🛑 Suggested Action - Manual Review

  • Touches a guarded path — held for manual review

Review summary
The change correctly adds an actuation-time CI freshness check for merges and heuristic closes, and it also persists `closeKind` so queued heuristic closes retain the discriminator after replay. The core gating logic is in the right place after the head/state freshness check and before the mutation. The main maintainability issue in the visible diff is redundant `closeKind` serialization in `actionParams`, while the new live-CI call should be audited explicitly if its helper can reject.

Nits — 6 non-blocking
  • src/services/agent-action-executor.ts:270 serializes `closeKind` twice in `actionParams`, which is harmless at runtime but confusing and should be reduced to one spread plus one explanatory comment.
  • src/services/agent-action-executor.ts:142 should either wrap `fetchLiveCiAggregate` in the same audited error path as live mutations or document that the helper never rejects, because the new defense-in-depth check currently sits outside the existing `try` block.
  • src/services/agent-action-executor.ts:270 remove the duplicate `...(action.closeKind !== undefined ? { closeKind: action.closeKind } : {})` and keep the more specific round-trip comment.
  • src/services/agent-action-executor.ts:142 add a focused test for a rejected `fetchLiveCiAggregate` call if the intended policy is fail-open or audited denial on live-CI lookup errors.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.
  • Touches a guarded path — held for manual review — A maintainer must review and merge this change.

CI checks failing

  • validate
  • validate-code
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #2128
Related work ⚠️ 3 scoped overlaps Top overlaps are listed below; lower-confidence bulk is hidden.
Change scope ❌ 8/20 High review scope from cached public metadata (size label size:M; 1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 67 registered-repo PR(s), 57 merged, 589 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 67 PR(s), 589 issue(s).
Gate result ⚠️ Not blocking Advisory; not blocking this PR.
Review context
Contributor next steps
  • Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Review top overlaps.
  • Add a concise scope and risk note.
  • Triage stale or unlinked PRs.
  • No action.
  • Check active issues and PRs before submitting.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.83%. Comparing base (b0c2c32) to head (7e1e1e8).
⚠️ Report is 3 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2364   +/-   ##
=======================================
  Coverage   95.82%   95.83%           
=======================================
  Files         224      224           
  Lines       24975    25006   +31     
  Branches     9076     9096   +20     
=======================================
+ Hits        23933    23964   +31     
  Misses        428      428           
  Partials      614      614           
Files with missing lines Coverage Δ
src/services/agent-action-executor.ts 89.81% <100.00%> (+1.03%) ⬆️
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…on-failed

The planner itself only ever stages a merge when ciState === "passed"
exactly (reviewGood in agent-actions.ts; "pending" short-circuits to no
actions at all upstream). The live re-check before actuation only denied
on ciState === "failed", so a check that regressed to pending or became
unreadable (unverified) between planning and actuation still let the
merge proceed on stale information -- exactly the class of gap this
guard exists to close. Require the same exact "passed" state the
planner itself requires.

Also fixes test/unit/routes-agent-approval.test.ts, which pre-dates this
PR's live-CI-recheck step entirely and never mocked
fetchLiveCiAggregate -- its accept-merge happy path was incidentally
passing only because the un-mocked call fell through to "unverified",
which the too-lenient original check treated as fine. Mock it to
"passed" like the executor's own test file already does.
JSONbored added 2 commits July 1, 2026 12:08
…ive-CI recheck survives replay

actionParams() didn't round-trip closeKind, so pendingActionToPlanned()
rebuilt an accepted approval-queue close with closeKind undefined --
silently skipping the actuation-time live CI re-check this PR adds, since
that check keys on action.closeKind === "heuristic".
# Conflicts:
#	test/unit/agent-approval-queue.test.ts
#	test/unit/routes-agent-approval.test.ts
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
gittensory-ui e0b9ebc Commit Preview URL

Branch Preview URL
Jul 01 2026, 08:21 PM

JSONbored added 4 commits July 1, 2026 13:18
A merge landed the same closeKind field twice in the same type literal —
once from #2127 (close-precision circuit-breaker scoping) and once from
this PR's own #2364 (actuation-time live-CI re-check) — causing
TS2300 "Duplicate identifier 'closeKind'" and failing validate-code.

Collapse to a single declaration with a merged comment explaining both
consumers.
Same merge-conflict-resolution artifact as the AgentPendingActionParams
type duplicate: closeKind was spread into the persisted params twice
(once bare, once with the #2127 explanatory comment). Both computed the
identical value, so this was harmless at runtime, but redundant and
confusing. Keep the single, commented copy and note the #2364 live-CI
re-check's dependency on it too.
@JSONbored
JSONbored merged commit f98f555 into main Jul 1, 2026
7 checks passed
@JSONbored
JSONbored deleted the claude/actuation-live-ci-recheck branch July 1, 2026 20:38
@github-project-automation github-project-automation Bot moved this from Todo to Done in gittensory - v1 roadmap Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

fix(agent-actions): actuation freshness guard never re-verifies CI/mergeable state before merge or close

1 participant