Skip to content

feat(gate): guardrailEscalation.onCleanReview — release the guardrail hold when the escalated review is clean - #9869

Open
JSONbored wants to merge 3 commits into
mainfrom
feat/guardrail-mode
Open

feat(gate): guardrailEscalation.onCleanReview — release the guardrail hold when the escalated review is clean#9869
JSONbored wants to merge 3 commits into
mainfrom
feat/guardrail-mode

Conversation

@JSONbored

@JSONbored JSONbored commented Jul 29, 2026

Copy link
Copy Markdown
Owner

The second half of #9808, as a mode

#9821 shipped the escalation knobs — a guarded PR now gets a high-effort review — but the disposition still held it unconditionally: guardrailHit sat in heldForManualReview regardless of what the escalated review found. The 74 held PRs / 14 days kept landing on the maintainer, just with better reviews attached.

gate:
  guardrailEscalation:
    effort: high
    onCleanReview: proceed   # NEW — full-autonomy mode
    # hold (default) = today's behavior exactly, human-in-the-loop

proceed: a clean escalated review (gate success + green CI) releases the guardrail hold and the normal approve/merge path continues — the guarded path is protected by the escalated review instead of a human queue. Because it's a manifest field it layers global → per-repo like everything else: repos flip one at a time, and the mode is reversible with a config edit, no deploy.

Fail-closed on every axis

  • proceed is inert unless at least one escalation knob is actually set. The release is justified by extra scrutiny; absent scrutiny, nothing vouches for the guarded path. A config that sets the mode but forgets the escalation changes nothing.
  • The disposition re-checks reviewGood independently of the caller's flag — a red gate or CI still blocks even if cleared were mis-set upstream. Pinned by a test.
  • Only the guardrail term is released. Migration collisions, unlinked-issue holds, advisory-check holds, unstable merge states all still hold — each pinned individually.
  • The manual-hold reason no longer claims "guarded path → manual review" on a cleared PR, so the audit trail matches the action.

Note reviewGood already folds in the AI verdict: a consensus blocker fails the gate itself, so "clean escalated review" is not a separate, bypassable signal — it's the same gate every other merge decision trusts.

Tests

4 disposition cases (release, default-hold byte-identical, only-the-guardrail-term, red-gate-cannot-merge-despite-flag) + engine parse/round-trip/presence/junk-rejection for the new field. Full suite 25,455 passed; docs-drift (both example configs), openapi, contract schemas, dead-source-files green.

Activation

On merge + image: set onCleanReview: proceed in the three repos' private configs (server-side, no code). Every hold family is then either eliminated, one-shot-closed, or maintainer-only — the full-autonomy target, with hold mode one config edit away if precision degrades.

Closes #9808.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 29, 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
loopover-ui 5ae2ba9 Commit Preview URL

Branch Preview URL
Jul 29 2026, 10:13 PM

@loopover-orb

loopover-orb Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-29 23:46:20 UTC

17 files · 1 AI reviewer · no blockers · CI green · clean

⏸️ Suggested Action - Manual Review

Review summary
This PR adds `guardrailEscalation.onCleanReview: proceed` as a full-autonomy mode that releases the guardrail hold when a clean escalated review (gate success + green CI) has run, threading the field through the manifest parser, settings types, OpenAPI schema, and disposition logic. The core logic is correct and fail-closed as claimed: `guardrailEscalationCleared` requires guardrailHit, reviewGood, at least one escalation knob set, and the explicit opt-in, and the disposition change only affects the guardrail term while leaving migration/unlinked-issue/advisory holds untouched, backed by dedicated invariant tests. The manual-hold-reason fix (`guardrailHit && !guardrailEscalationCleared`) correctly keeps the audit trail accurate on a cleared PR.

Nits — 6 non-blocking
  • src/settings/agent-actions.ts: `escalationConfigured` checks only effort/selfConsistencyRuns/model/provider, not `guardrailEscalationOnCleanReview` itself — worth a one-line comment confirming that's intentional (the mode field shouldn't count as its own justification) since it's easy to misread as an oversight.
  • The PR bundles a large, mostly-mechanical field-threading diff across ~13 files (manifest parser, types, OpenAPI x2, docs-drift script, queue processor) for one small piece of new logic in pr-disposition.ts — consider noting in the description that most files are boilerplate wiring, to help reviewers focus on the actual logic change.
  • config/examples/loopover.full.yml and .loopover.yml.example duplicate the same lengthy comment block verbatim — same as the existing pattern for other guardrailEscalation fields, so consistent, but worth flagging if these ever drift out of sync.
  • Confirm in the PR description or a code comment why `guardrailEscalationOnCleanReview` itself isn't part of `escalationConfigured`'s check in src/settings/agent-actions.ts, since a reviewer's first instinct is to ask why setting the mode alone doesn't count as configuration.
  • The Workers Builds (loopover-ui) CI failure has no detail provided in what was given here — worth checking separately whether it's related to the openapi.json regen in this diff or an unrelated infra issue.
  • 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.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #9808
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 14 registered-repo PR(s), 13 merged, 306 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 14 PR(s), 306 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Linked issue satisfaction

Partially addressed
The PR wires up the guardrail-release path (onCleanReview: proceed clears the hold when gate+CI pass and an escalation knob is set), which matches the issue's core ask to escalate instead of hold, but it doesn't visibly implement the issue's specific unanimity/confidence-floor criteria (requireUnanimous, minConfidence) as distinct gating logic — it relies on generic reviewGood rather than the expl

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 14 PR(s), 306 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
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.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Decision record
  • action: merge · clause: success
  • config: bc050ad6d5a99fa39e3057a6d47ecc248e91d316722cefb5720a042791729f8e · pack: oss-anti-slop · ci: passed
  • record: 71c464a80d1be1a8edf9485f041db31469a40d1cef7d15fb16a5f5202fcad470 (schema v5, head 5ae2ba9)
Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/ desktop before /
before /
after /
after /
/ mobile before / (mobile)
before / (mobile)
after / (mobile)
after / (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

Scroll preview
Route Before (production) After (this PR's preview)
/ before / (scroll)
before / (scroll)
after / (scroll)
after / (scroll)

A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show.

🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@JSONbored JSONbored self-assigned this Jul 29, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 361 bytes (0.0%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
loopover-ui 7.82MB 361 bytes (0.0%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: loopover-ui

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/add-scalar-classes-Bp8cJ6LF.js (New) 2.16MB 2.16MB 100.0% 🚀
assets/tanstack-vendor-B5Ij-9Ml.js (New) 930.74kB 930.74kB 100.0% 🚀
openapi.json 223 bytes 750.34kB 0.03%
assets/docs.fumadocs-spike-api-reference-BBY6WcBC.js (New) 443.45kB 443.45kB 100.0% 🚀
assets/AgentScalarChatInterface.vue-BgTY9c1D.js (New) 201.7kB 201.7kB 100.0% 🚀
assets/modal-DbBNyhzT.js (New) 184.5kB 184.5kB 100.0% 🚀
assets/client-C3xSI6Ou.js (New) 151.47kB 151.47kB 100.0% 🚀
assets/maintainer-panel-CMzdeK-9.js (New) 78.96kB 78.96kB 100.0% 🚀
assets/routes-Dlv1edB7.js (New) 36.41kB 36.41kB 100.0% 🚀
assets/owner-panel-CF0lF9AM.js (New) 28.26kB 28.26kB 100.0% 🚀
assets/app-C40KhfB-.js (New) 25.82kB 25.82kB 100.0% 🚀
assets/ui-vendor-VmR4oGg6.js (New) 24.57kB 24.57kB 100.0% 🚀
assets/miner-panel-Ck2kB5X6.js (New) 20.24kB 20.24kB 100.0% 🚀
assets/app.runs-C5YVFQrS.js (New) 20.22kB 20.22kB 100.0% 🚀
assets/api._op-DWOfM9ZD.js (New) 17.54kB 17.54kB 100.0% 🚀
assets/self-hosting-docs-audit-DfEwEM4Z.js (New) 16.6kB 16.6kB 100.0% 🚀
assets/docs._slug-BiOeTZ6z.js (New) 15.63kB 15.63kB 100.0% 🚀
assets/playground-panel-BTdBB0dO.js (New) 14.42kB 14.42kB 100.0% 🚀
assets/fairness-BlXU8Not.js (New) 13.98kB 13.98kB 100.0% 🚀
assets/app.audit-BUwuGXLb.js (New) 10.22kB 10.22kB 100.0% 🚀
assets/app.config-generator-ImrXbWQl.js (New) 10.06kB 10.06kB 100.0% 🚀
assets/maintainers-Cn5rvWF6.js (New) 8.06kB 8.06kB 100.0% 🚀
assets/miners-t1WvPAPq.js (New) 7.91kB 7.91kB 100.0% 🚀
assets/agents-C-UmLzOn.js (New) 7.74kB 7.74kB 100.0% 🚀
assets/commands-panel-DNLSXKpS.js (New) 6.74kB 6.74kB 100.0% 🚀
assets/maintainer-workflow-W8Mycl2j.js (New) 6.52kB 6.52kB 100.0% 🚀
assets/digest-panel-BproAl5Q.js (New) 6.15kB 6.15kB 100.0% 🚀
assets/repos._owner._repo.quality-CRLV4FUJ.js (New) 6.14kB 6.14kB 100.0% 🚀
assets/docs-nav-CiSil6Iq.js (New) 6.06kB 6.06kB 100.0% 🚀
assets/docs.index-F7re2WL5.js (New) 5.95kB 5.95kB 100.0% 🚀
assets/api.index-a8i5O_5I.js (New) 4.7kB 4.7kB 100.0% 🚀
assets/docs-DZJhY5aO.js (New) 2.93kB 2.93kB 100.0% 🚀
assets/api-cWmm5Ff2.js (New) 2.69kB 2.69kB 100.0% 🚀
assets/docs-page-DwSvcOic.js (New) 2.1kB 2.1kB 100.0% 🚀
assets/table-CbRSq6m_.js (New) 1.75kB 1.75kB 100.0% 🚀
assets/app.workbench-Bvrf0zXB.js (New) 1.58kB 1.58kB 100.0% 🚀
assets/tabs-C187V6h1.js (New) 1.39kB 1.39kB 100.0% 🚀
assets/app.repos-BP67iuus.js (New) 1.07kB 1.07kB 100.0% 🚀
assets/input-BcywM_Xp.js (New) 796 bytes 796 bytes 100.0% 🚀
assets/file-cog-jnkmO1r9.js (New) 758 bytes 758 bytes 100.0% 🚀
assets/app.maintainer-1HNLLjcl.js (New) 502 bytes 502 bytes 100.0% 🚀
assets/app.owner-Bx1zG4iq.js (New) 474 bytes 474 bytes 100.0% 🚀
assets/app.commands-DYwNL7KO.js (New) 455 bytes 455 bytes 100.0% 🚀
assets/app.playground-C7q1gYNy.js (New) 442 bytes 442 bytes 100.0% 🚀
assets/index-Cubdwx8u.js (New) 438 bytes 438 bytes 100.0% 🚀
assets/app.digest-ocR45zfU.js (New) 430 bytes 430 bytes 100.0% 🚀
assets/eye-off-DB2Qx5k-.js (New) 430 bytes 430 bytes 100.0% 🚀
assets/app.miner-CnlMhorE.js (New) 422 bytes 422 bytes 100.0% 🚀
assets/key-round-CiOImw0f.js (New) 355 bytes 355 bytes 100.0% 🚀
assets/bot-BvjmdBt-.js (New) 328 bytes 328 bytes 100.0% 🚀
assets/trash-2-BfK97oZP.js (New) 328 bytes 328 bytes 100.0% 🚀
assets/save-D1siH_ot.js (New) 327 bytes 327 bytes 100.0% 🚀
assets/git-pull-request-arrow-BhZTnEUF.js (New) 321 bytes 321 bytes 100.0% 🚀
assets/list-checks-CIrKXrx_.js (New) 279 bytes 279 bytes 100.0% 🚀
assets/compass-BeEt3DxV.js (New) 251 bytes 251 bytes 100.0% 🚀
assets/history-BbCXqGYu.js (New) 237 bytes 237 bytes 100.0% 🚀
assets/message-square-Cu6LhHVv.js (New) 233 bytes 233 bytes 100.0% 🚀
assets/lock-CQu-NVKz.js (New) 206 bytes 206 bytes 100.0% 🚀
assets/rotate-cw-CKHGeqsL.js (New) 201 bytes 201 bytes 100.0% 🚀
assets/play-DayjAleI.js (New) 190 bytes 190 bytes 100.0% 🚀
assets/circle-check-E1K4T4Z3.js (New) 178 bytes 178 bytes 100.0% 🚀
assets/search-GZPsUhBt.js (New) 174 bytes 174 bytes 100.0% 🚀
assets/add-scalar-classes-CepxXuDy.js (Deleted) -2.16MB 0 bytes -100.0% 🗑️
assets/tanstack-vendor-AwjN6nKq.js (Deleted) -930.64kB 0 bytes -100.0% 🗑️
assets/docs.fumadocs-spike-api-reference-yrtF2yG2.js (Deleted) -443.45kB 0 bytes -100.0% 🗑️
assets/AgentScalarChatInterface.vue-DpxZdr4p.js (Deleted) -201.7kB 0 bytes -100.0% 🗑️
assets/modal-BZsvE1y5.js (Deleted) -184.5kB 0 bytes -100.0% 🗑️
assets/client-COX_GLVr.js (Deleted) -151.47kB 0 bytes -100.0% 🗑️
assets/maintainer-panel-DOJ5zlPL.js (Deleted) -78.96kB 0 bytes -100.0% 🗑️
assets/routes-Cy1A0Rh0.js (Deleted) -36.41kB 0 bytes -100.0% 🗑️
assets/owner-panel-DR-WkbD2.js (Deleted) -28.22kB 0 bytes -100.0% 🗑️
assets/app-ChJbfLCb.js (Deleted) -25.82kB 0 bytes -100.0% 🗑️
assets/ui-vendor-DMhklvhg.js (Deleted) -24.57kB 0 bytes -100.0% 🗑️
assets/miner-panel-BUjifE2k.js (Deleted) -20.24kB 0 bytes -100.0% 🗑️
assets/app.runs-oro2kiGh.js (Deleted) -20.22kB 0 bytes -100.0% 🗑️
assets/api._op-FAsUFfkA.js (Deleted) -17.54kB 0 bytes -100.0% 🗑️
assets/self-hosting-docs-audit-1VxZHCSg.js (Deleted) -16.6kB 0 bytes -100.0% 🗑️
assets/docs._slug-DTstgoEh.js (Deleted) -15.63kB 0 bytes -100.0% 🗑️
assets/playground-panel-DoR5208S.js (Deleted) -14.42kB 0 bytes -100.0% 🗑️
assets/fairness-DDsxDFvD.js (Deleted) -13.98kB 0 bytes -100.0% 🗑️
assets/app.audit-PPe_-k2I.js (Deleted) -10.22kB 0 bytes -100.0% 🗑️
assets/app.config-generator-CD8EbFqg.js (Deleted) -10.06kB 0 bytes -100.0% 🗑️
assets/maintainers-BPsG3NI-.js (Deleted) -8.06kB 0 bytes -100.0% 🗑️
assets/miners-_yugMxF4.js (Deleted) -7.91kB 0 bytes -100.0% 🗑️
assets/agents-DZInFXYk.js (Deleted) -7.74kB 0 bytes -100.0% 🗑️
assets/commands-panel-C4XgA2SB.js (Deleted) -6.74kB 0 bytes -100.0% 🗑️
assets/maintainer-workflow-TYeSYWhi.js (Deleted) -6.52kB 0 bytes -100.0% 🗑️
assets/digest-panel-pa2sM7Aw.js (Deleted) -6.15kB 0 bytes -100.0% 🗑️
assets/repos._owner._repo.quality-DW47d8zs.js (Deleted) -6.14kB 0 bytes -100.0% 🗑️
assets/docs-nav-CaHfOrgH.js (Deleted) -6.06kB 0 bytes -100.0% 🗑️
assets/docs.index-CkfaheGH.js (Deleted) -5.95kB 0 bytes -100.0% 🗑️
assets/api.index-Ckg1gC3E.js (Deleted) -4.7kB 0 bytes -100.0% 🗑️
assets/docs-7ima7Aq2.js (Deleted) -2.93kB 0 bytes -100.0% 🗑️
assets/api-CoeevdYE.js (Deleted) -2.69kB 0 bytes -100.0% 🗑️
assets/docs-page-lt63N7xs.js (Deleted) -2.1kB 0 bytes -100.0% 🗑️
assets/table-oIj3aNct.js (Deleted) -1.75kB 0 bytes -100.0% 🗑️
assets/app.workbench-sPiCHKS8.js (Deleted) -1.58kB 0 bytes -100.0% 🗑️
assets/tabs-ibA9-M6P.js (Deleted) -1.39kB 0 bytes -100.0% 🗑️
assets/app.repos-BE89HZTy.js (Deleted) -1.07kB 0 bytes -100.0% 🗑️
assets/input-ZiI6IT0X.js (Deleted) -796 bytes 0 bytes -100.0% 🗑️
assets/file-cog-z9n0uxio.js (Deleted) -758 bytes 0 bytes -100.0% 🗑️
assets/app.maintainer-BoQwmeTx.js (Deleted) -502 bytes 0 bytes -100.0% 🗑️
assets/app.owner-DuBluKDb.js (Deleted) -474 bytes 0 bytes -100.0% 🗑️
assets/app.commands-DhptOC8r.js (Deleted) -455 bytes 0 bytes -100.0% 🗑️
assets/app.playground-CeO1KpiV.js (Deleted) -442 bytes 0 bytes -100.0% 🗑️
assets/index-DIWCSuER.js (Deleted) -438 bytes 0 bytes -100.0% 🗑️
assets/app.digest-_lTLVrqf.js (Deleted) -430 bytes 0 bytes -100.0% 🗑️
assets/eye-off-Gw5ZDj3v.js (Deleted) -430 bytes 0 bytes -100.0% 🗑️
assets/app.miner-WD9haHN-.js (Deleted) -422 bytes 0 bytes -100.0% 🗑️
assets/key-round-BbcWnC5k.js (Deleted) -355 bytes 0 bytes -100.0% 🗑️
assets/bot-DZBlDl7F.js (Deleted) -328 bytes 0 bytes -100.0% 🗑️
assets/trash-2-PdGAXEaH.js (Deleted) -328 bytes 0 bytes -100.0% 🗑️
assets/save-FZ5viRKr.js (Deleted) -327 bytes 0 bytes -100.0% 🗑️
assets/git-pull-request-arrow-CwFAEqHL.js (Deleted) -321 bytes 0 bytes -100.0% 🗑️
assets/list-checks-BxSljzj4.js (Deleted) -279 bytes 0 bytes -100.0% 🗑️
assets/compass-DEaQMQ7G.js (Deleted) -251 bytes 0 bytes -100.0% 🗑️
assets/history-xItiYNz_.js (Deleted) -237 bytes 0 bytes -100.0% 🗑️
assets/message-square-Dp6zYKsI.js (Deleted) -233 bytes 0 bytes -100.0% 🗑️
assets/lock-B_yC31cr.js (Deleted) -206 bytes 0 bytes -100.0% 🗑️
assets/rotate-cw-BHvWflKw.js (Deleted) -201 bytes 0 bytes -100.0% 🗑️
assets/play-5ne5Q6nV.js (Deleted) -190 bytes 0 bytes -100.0% 🗑️
assets/circle-check-BfjsYT4U.js (Deleted) -178 bytes 0 bytes -100.0% 🗑️
assets/search-tGyBe_6N.js (Deleted) -174 bytes 0 bytes -100.0% 🗑️

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.86%. Comparing base (84553fc) to head (5ae2ba9).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #9869   +/-   ##
=======================================
  Coverage   91.86%   91.86%           
=======================================
  Files         921      921           
  Lines      113256   113278   +22     
  Branches    27300    27312   +12     
=======================================
+ Hits       104039   104061   +22     
  Misses       7929     7929           
  Partials     1288     1288           
Flag Coverage Δ
backend 95.68% <100.00%> (+<0.01%) ⬆️
engine 72.25% <100.00%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-contract/src/api-schemas.ts 100.00% <ø> (ø)
packages/loopover-engine/src/focus-manifest.ts 82.33% <100.00%> (+0.04%) ⬆️
src/openapi/schemas.ts 100.00% <ø> (ø)
src/queue/processors.ts 94.81% <100.00%> (+<0.01%) ⬆️
src/settings/agent-actions.ts 98.26% <100.00%> (+0.01%) ⬆️
src/settings/pr-disposition.ts 100.00% <100.00%> (ø)
src/signals/focus-manifest.ts 99.61% <100.00%> (+<0.01%) ⬆️
src/types.ts 100.00% <ø> (ø)

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 29, 2026
@JSONbored
JSONbored force-pushed the feat/guardrail-mode branch 2 times, most recently from a1367ff to f970cea Compare July 29, 2026 19:29
… hold when the escalated review is clean

The second half of #9808, as an explicit MODE rather than a policy flip.

review -- but the disposition still held it unconditionally: guardrailHit sat
in heldForManualReview regardless of what the escalated review found. The 74
held PRs / 14 days kept landing on the maintainer, just with better reviews
attached.

gate.guardrailEscalation.onCleanReview:
  hold     (default) today's behavior exactly -- human-in-the-loop
  proceed  a clean escalated review releases the guardrail hold and the normal
           approve/merge path continues -- full-autonomy mode

Because it is a manifest field it layers global -> per-repo like everything
else, so repos can be flipped one at a time and the mode is reversible without
a deploy.

Fail-closed on every axis:
 - `proceed` is inert unless at least one escalation knob is actually SET: the
   release is justified by extra scrutiny, so absent scrutiny nothing vouches.
 - the release requires reviewGood -- gate success (which folds in the AI
   verdict's blockers) AND green CI -- and the disposition re-checks that
   independently of the caller's flag.
 - only the guardrail term is released: migration collisions, unlinked-issue
   holds, advisory-check holds, and unstable merge states all still hold.
 - the manual-hold reason no longer claims "guarded path -> manual review" for
   a cleared PR.
…t merges it

The manual-review label announces a HOLD. Its emit condition checked
`guardrailHit` alone, so once a clean escalated review released that hold
(guardrailEscalationCleared), the planner emitted both in one pass: the merge
AND the label telling a human to come look at it. Self-contradictory, and it
leaves a manual-review label sitting on merged PRs in precisely the
full-autonomy mode the feature exists to enable.

Also closes the two patch-coverage gaps this PR still carried, both of them
the "test both sides" class:

- agent-actions: no test made guardrailHit, reviewGood and escalationConfigured
  true at once, so the fourth conjunct -- `onCleanReview === "proceed"`, the
  term the whole feature turns on -- was never evaluated at all. Now asserted
  in both directions against identical input, plus the case where "proceed" is
  set with NO escalation configured, which must NOT release (that promise is
  about an escalated review; honouring it without one would leave guarded paths
  weaker than before the feature).

- focus-manifest: onCleanReview was covered through parse but not through
  resolveEffectiveSettings. Parsing it and dropping it during resolution would
  silently restore always-hold while the manifest still read as configured for
  full autonomy.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(gate): guardrail escalation — guarded paths get a stronger, multi-run AI review instead of a manual hold

1 participant