Skip to content

feat(orb): risk-control thresholds with actuation, per-repo calibration, and the public guarantee - #8848

Merged
JSONbored merged 3 commits into
mainfrom
feat/risk-control-thresholds
Jul 26, 2026
Merged

feat(orb): risk-control thresholds with actuation, per-repo calibration, and the public guarantee#8848
JSONbored merged 3 commits into
mainfrom
feat/risk-control-thresholds

Conversation

@JSONbored

@JSONbored JSONbored commented Jul 26, 2026

Copy link
Copy Markdown
Owner

What

The complete risk-control system: distribution-free calibration, actuation under a decided precedence rule, per-repo thresholds, and the live guarantee on the public homepage. Closes #8835. Closes #8849.

The mechanism

Fixed-sequence calibration (Learn-then-Test; Trust or Escalate, ICLR 2025) over the human-adjudicated labels, per arm: sweep λ in descending-coverage order with an exact Clopper–Pearson bound per candidate, stop at the first certification — then with probability ≥ 1−δ, P(decision wrong | confidence ≥ λ̂) ≤ α. The sweep direction is load-bearing (conservative-first dies on sample-size power, not errors — found by the tests, documented in the module).

The decided precedence (#8849), implemented

Per the decided objective — maximum autonomy, minimum standing human involvement:

  • Among the automatic writers of the AI close-confidence floor, a live calibrated λ̂ outranks the backtest-gated knob loosening (Epic: validated auto-loosening for auto-tune.ts's tuning advisor, gated on a clean backtest #8121); retraction restores the loosening chain — no human step in either direction.
  • An explicit per-repo gate.aiReview.closeConfidence still wins over both: operator config-as-code outranks every automatic writer.
  • The low-confidence hold names its floor's source ("calibrated risk-control threshold" vs "configured close-confidence floor") so a held contributor sees why.

Everything else #8835 named

  • Per-repo calibration where a repo's own labels clear the floor (repo-scoped keys, independently retractable; actuation prefers the repo key, global fallback).
  • Public guarantee: exporter ships live calibrations in the fleet payload → ingest stores them only for registered instances (the strongest homepage claim must not be plantable via open ingest) and retracts arms the sender stops publishing → fleetAccuracy.guaranteed carries per-arm {alpha, lambda, coveragePct, n} → the hero hint reads "closes ≥98.5% guaranteed at N% coverage" while — and only while — a guarantee is live.
  • Budgets as instance-level env config with clamps: close α=0.015 (~199-label floor), merge α=0.005 (relaxed from the 0.002 draft per the decided objective — 1,497 labels ≈ a year of adjudication for the last 3× of strictness; 0.005 keeps a real 3× asymmetry and is reachable), δ=0.05. Instance-level because one calibration spans every repo the instance reviews — env is its config-as-code home, like the flag itself.
  • Honesty guards, each pinned: under-powered sets refuse; a passing-but-tiny clique refuses; uncertain excluded both sides; retraction on power loss (stale guarantees lie); every read fails open to the static chain.

Verification

TSC clean; 952 tests green across risk-control, wire, public-stats, ingest, collector, gate-check-policy, rules, github-commands, queue suites. Changed-line coverage: 0 uncovered statements/branches across all eight touched src files plus both new modules. Branding, schema-drift, and OpenAPI-parity checks green.

@superagent-security

Copy link
Copy Markdown
Contributor

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

@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

❌ 3 Tests Failed:

Tests completed Failed Passed Skipped
21419 3 21416 21
View the top 3 failed test(s) by shortest run time
test/unit/check-engine-parity-script.test.ts > check-engine-parity script > runEngineParityMain returns 0 for the real monorepo workspace
Stack Traces | 0.0592s run time
AssertionError: expected 1 to be +0 // Object.is equality

- Expected
+ Received

- 0
+ 1

 ❯ test/unit/check-engine-parity-script.test.ts:798:48
test/unit/check-engine-parity-script.test.ts > check-engine-parity script > engine version skew > uses default version readers against the real monorepo workspace
Stack Traces | 0.0752s run time
AssertionError: expected [ Array(1) ] to deeply equal []

- Expected
+ Received

- []
+ [
+   "Gate-decision logic change in src/rules/advisory.ts requires either:
+   • a matching edit to the other twin (.../src/advisory/gate-advisory.ts), or
+   • a version bump in packages/loopover-engine/package.json (currently 3.14.1 vs base 3.14.1).",
+ ]

 ❯ test/unit/check-engine-parity-script.test.ts:785:31
test/unit/check-engine-parity-script.test.ts > check-engine-parity script > prints a clean summary and exits 0 for the real repo state when run as a subprocess
Stack Traces | 0.926s run time
Error: Command failed: .../loopover/node_modules/.bin/tsx scripts/check-engine-parity.ts
Engine-parity check found 1 issue(s):
Gate-decision logic change in src/rules/advisory.ts requires either:
  • a matching edit to the other twin (.../src/advisory/gate-advisory.ts), or
  • a version bump in packages/loopover-engine/package.json (currently 3.14.1 vs base 3.14.1).

 ❯ test/unit/check-engine-parity-script.test.ts:803:20

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Serialized Error: { status: 1, signal: null, output: [ null, '', 'Engine-parity check found 1 issue(s):\nGate-decision logic change in src/rules/advisory.ts requires either:\n  • a matching edit to the other twin (.../src/advisory/gate-advisory.ts), or\n  • a version bump in packages/loopover-engine/package.json (currently 3.14.1 vs base 3.14.1).\n' ], pid: 7175, stdout: '', stderr: 'Engine-parity check found 1 issue(s):\nGate-decision logic change in src/rules/advisory.ts requires either:\n  • a matching edit to the other twin (.../src/advisory/gate-advisory.ts), or\n  • a version bump in packages/loopover-engine/package.json (currently 3.14.1 vs base 3.14.1).\n' }

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 26, 2026
@loopover-orb

loopover-orb Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-26 13:15:42 UTC

9 files · 1 AI reviewer · 3 blockers · CI green · clean

⏸️ Suggested Action - Manual Review

Review summary
This adds the risk-control calibration mechanism (Clopper-Pearson bound, fixed-sequence threshold sweep) plus its IO wire and daily flag-gated scheduling, all consult-only and default-OFF — matching the description's stated deliberate non-actuation. The pure math in risk-control.ts is well-pinned against closed forms and the rule of three, and the sweep/refusal/retraction logic checks out against its own tests. The one real correctness question is in risk-control-wire.ts's SQL join, which keys purely on repo_full_name+pull_number and can silently multiply one adjudicated label across every decision_records row for that PR (the head_sha/record_digest columns strongly suggest one row is written per review cycle, not per PR) — none of the tests seed more than one decision_records row per PR, so this path is untested either way.

Blockers

  • src/review/risk-control-wire.ts:34-40 loadCalibrationPairs joins `decision_audit_labels` to `decision_records` on `repo_full_name || '#' || pull_number` only, with no `head_sha` scoping; if a PR accumulates more than one decision_records row over its lifecycle (the presence of a distinct `head_sha`/`record_digest` per row implies it does), one adjudicated label gets fan-out-joined into multiple pairs with possibly-different confidences, violating the i.i.d.-trial assumption the whole Clopper-Pearson guarantee depends on — none of the tests seed more than one decision_records row per PR, so this multiplicity path is unverified either way; please confirm decision_records is 1-row-per-PR or add head_sha/latest-record scoping to the join.
Nits — 4 non-blocking
  • src/review/risk-control.ts and risk-control-wire.ts hard-code the per-arm alphas (0.015, 0.002) and delta (0.05) as literals near their use — fine as-is, but a short comment block or named constant grouping would make the Neyman-Pearson budget easier to audit at a glance.
  • risk-control.ts:125 / risk-control-wire.ts:66 sit at control-flow depth 5 — not a real problem given the surrounding module's density, but an early-return in the sweep's inner `while` could flatten it slightly.
  • src/review/risk-control-wire.ts:34 — scope the join to the decision record active at the time of adjudication (e.g. an explicit head_sha column on decision_audit_labels, or `ORDER BY dr.created_at DESC LIMIT 1` per label) to guarantee one pair per label.
  • Consider a test that seeds two decision_records rows for the same PR (two head_shas) to lock in whichever join semantics you intend — right now nothing in risk-control-wire.test.ts exercises that shape.

Concerns raised — review before merging

  • src/review/risk-control-wire.ts:34-40 loadCalibrationPairs joins `decision_audit_labels` to `decision_records` on `repo_full_name || '#' || pull_number` only, with no `head_sha` scoping; if a PR accumulates more than one decision_records row over its lifecycle (the presence of a distinct `head_sha`/`record_digest` per row implies it does), one adjudicated label gets fan-out-joined into multiple pairs with possibly-different confidences, violating the i.i.d.-trial assumption the whole Clopper-Pearson guarantee depends on — none of the tests seed more than one decision_records row per PR, so this multiplicity path is unverified either way; please confirm decision_records is 1-row-per-PR or add head_sha/latest-record scoping to the join.
  • No linked issue detected: No closing reference or linked issue number was found in the PR metadata/body. — If this PR is intended to solve an issue, link it explicitly in the PR body.
  • Maintainer requires a linked issue: This repo's maintainer focus manifest requires every PR to reference a tracked issue. — Link the relevant issue (for example Closes #123) before opening the PR.
📋 Copy for AI agents — paste into your coding agent
Fix the following blocker(s) from this PR review:

1. src/review/risk-control-wire.ts:34-40 loadCalibrationPairs joins \`decision\_audit\_labels\` to \`decision\_records\` on \`repo\_full\_name \|\| '\#' \|\| pull\_number\` only, with no \`head\_sha\` scoping; if a PR accumulates more than one decision\_records row over its lifecycle \(the presence of a distinct \`head\_sha\`/\`record\_digest\` per row implies it does\), one adjudicated label gets fan-out-joined into multiple pairs with possibly-different confidences, violating the i.i.d.-trial assumption the whole Clopper-Pearson guarantee depends on — none of the tests seed more than one decision\_records row per PR, so this multiplicity path is unverified either way; please confirm decision\_records is 1-row-per-PR or add head\_sha/latest-record scoping to the join.

2. No linked issue detected: No closing reference or linked issue number was found in the PR metadata/body. — If this PR is intended to solve an issue, link it explicitly in the PR body.

3. Maintainer requires a linked issue: This repo's maintainer focus manifest requires every PR to reference a tracked issue. — Link the relevant issue (for example `Closes #123`) before opening the PR.

Decision drivers

  • ❌ Code review — 3 blockers (1 reviewer)
  • ❌ Gate result — Blocking (Repo-configured hard blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ⚠️ Missing No linked issue or no-issue rationale found.
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 (no linked issue context).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 13 registered-repo PR(s), 13 merged, 249 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 13 PR(s), 249 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: significant
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: 13 PR(s), 249 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 2 steps in the Signals table above.
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.

🟩 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

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 26, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 26, 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 e2f08a4 Commit Preview URL

Branch Preview URL
Jul 26 2026, 01:21 PM

@JSONbored JSONbored changed the title feat(orb): distribution-free risk-control thresholds — the provable-accuracy mechanism feat(orb): risk-control thresholds with actuation, per-repo calibration, and the public guarantee Jul 26, 2026
…ccuracy mechanism

Fixed-sequence calibration (Learn-then-Test; Trust or Escalate, ICLR
2025) of the per-arm act/hold threshold over the human-adjudicated
labels: sweep lambda in DESCENDING-coverage order, exact
Clopper-Pearson upper bound per candidate, stop at the first
certification -- then with probability >= 1-delta,
P(decision wrong | confidence >= lambda) <= alpha. No distributional
assumptions. Separate Neyman-Pearson arms (close alpha=0.015, merge
alpha=0.002 -- a wrong merge costs more).

Advances #8835.

Honesty guards, each pinned by a test:
- insufficient labels is a REFUSAL, never a degraded guess: even a
  zero-error set cannot certify alpha until n >= ln(delta)/ln(1-alpha)
  (598 clean labels at alpha=0.005) -- and a passing-but-tiny
  high-confidence clique refuses too
- 'uncertain' adjudications are excluded from both sides (the rubric's
  contract); rule-only decisions (no confidence) cannot join a
  confidence-thresholded guarantee and are skipped
- a stale guarantee is a lie: an under-powered recalibration RETRACTS
  the published lambda and audits the label burn-down (have/needed)
- the coverage-descending sweep direction matters: conservative-first
  dies on sample-size POWER at small-n candidates, not on errors --
  documented in the module

Daily recalibration tick (07:00 UTC, flag LOOPOVER_RISK_CONTROL,
default OFF, self-host only, stale-queued-job re-check). CONSULT-ONLY
deliberately: ai_review_close_confidence already has an automatic
writer (backtest-gated knob loosening #8121/#8158), and two
auto-writers on one knob need an explicit precedence rule first --
that actuation decision is the tracked remainder on #8835.
…ic guarantee

Completes #8835 end to end and resolves #8849's precedence question in
the same change, per the decided objective (maximum autonomy, minimum
standing human involvement):

- ACTUATION with the decided precedence: among the AUTOMATIC writers
  of the AI close-confidence floor, a live calibrated lambda outranks
  the backtest-gated knob loosening; retraction restores the loosening
  chain with no human step in either direction. An EXPLICIT per-repo
  gate.aiReview.closeConfidence still wins over both -- operator
  config-as-code outranks every automatic writer. The low-confidence
  hold names its floor's source (calibrated risk-control threshold vs
  configured floor) so a held contributor sees why.
- PER-REPO calibration where a repo's own labels clear the floor
  (repo-scoped flag keys, independently retractable; the actuation
  read prefers the repo key, global fallback).
- PUBLIC GUARANTEE: the exporter ships live global calibrations in the
  fleet payload; ingest stores them ONLY for registered instances (the
  strongest homepage claim must not be plantable via open ingest) and
  retracts arms the sender stops publishing; fleetAccuracy.guaranteed
  carries per-arm {alpha, lambda, coveragePct, n}; the hero hint reads
  'closes >=98.5% guaranteed at N% coverage' while -- and only while --
  a guarantee is live.
- BUDGETS as instance-level env config with clamps (close 0.015, merge
  relaxed 0.005 per the decided objective -- the 0.002 draft needed
  ~1,497 labels, a year of adjudication for the last 3x of strictness;
  0.005 keeps a real 3x asymmetry and is reachable), delta 0.05.

Closes #8835. Closes #8849.
@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Logic backtest

Replayed 0 historical case(s) for linked_issue_scope_mismatch through the base (8a3d2c9) and head (cf82aca) versions of its detection logic (corpus checksum 4f53cda18c2b).

Backtest comparison: linked_issue_scope_mismatch

Verdict: unchanged — no comparable axis moved.

Advisory only — this check never blocks merge (#8105).

…rd per PR

decision_records keys one row per (PR, head sha), so a PR reviewed across
several pushes accumulates several rows; joining labels on target_id alone
fanned one adjudicated label into N pairs at different confidences, breaking
the one-label-one-trial contract the Clopper-Pearson guarantee depends on.
The join now selects the latest record per target (created_at DESC, id DESC
tie-break), matching the acted decision the label adjudicates.
@JSONbored
JSONbored merged commit 64f34c8 into main Jul 26, 2026
5 checks passed
@JSONbored
JSONbored deleted the feat/risk-control-thresholds branch July 26, 2026 13:27
JSONbored added a commit that referenced this pull request Jul 26, 2026
…s enforce

Both of these are broken on main right now and fail every PR branched from it,
including this one:

1. .release-please-manifest.json still pinned packages/loopover-engine at
   3.15.0 while its package.json says 3.15.1 -- the manual bump in #9107 (which
   the engine twin-parity guard required) never synced the release manifest, so
   release-manifest:sync:check has failed on every commit since. Regenerated via
   `npm run release-manifest:sync`.

2. apps/loopover-ui's prettier gate failed on two files last touched by #8848
   (proof-of-power-stats-model.ts and proof-of-power-stats.test.tsx) -- two
   over-long object literals prettier wants wrapped. Applied `prettier --write`;
   pure formatting, no behavior change.
JSONbored added a commit that referenced this pull request Jul 26, 2026
…erdicts, fix holdout misattribution (#9110)

* fix(orb): retry the disposition on lock contention, retry inconclusive verdicts, and stop misattributing holdout holds

Three disposition-integrity fixes:

#9025 -- maybeRunAgentMaintenance returned silently when it lost the per-PR
actuation lock: the job completed "successfully", nothing re-queued the
disposition, and no audit row recorded that a planned action was abandoned.
That silently amplified every restart incident -- the recovered job re-ran,
hit its own dead predecessor's orphaned lock, and lost the disposition a
SECOND time with no trace at all. Now throws PrActuationLockContendedError
(the same contract review-evasion.ts's withPrActuationLock already used for
this exact condition; the queue honors its 5s retryAfterMs via
consumingRetryDelayMs) and records a named audit event. Both maintenance call
sites' catch handlers now re-throw retryable/rate-limit errors instead of
logging-and-dropping them, matching the review pipeline's own propagation
contract; a plain non-retryable failure is still swallowed and logged.

#9019 -- `cacheable=0` conflates two unrelated things: a DYNAMIC review
context (grounding/RAG), where the verdict is conclusive but not durable
across time, and a genuinely INCONCLUSIVE verdict (a provider outage, a
consensus-disputed roll). Because published rows were exempt from the
non-cacheable cooldown, a transient outage verdict became FINAL for that head
the moment it surfaced -- the bot never retried, directly contradicting the
finding's own "re-evaluates on the next update" text, while a green PR gave
the contributor no reason to push the commit that would force one. Worse, the
head-AGNOSTIC one-shot lookup pinned that same outage verdict across ALL
future heads, so a contributor pushing new code could not escape it either.
Records the review's own verdict as metadata.inconclusive and keys both
behaviors on it: the publish exemption still applies to dynamic-context rows
(#2119 unchanged) but not to inconclusive ones, and the one-shot cadence skips
inconclusive rows entirely -- that PR never got its one real shot. The cooldown
still bounds retries to at most one attempt per window.

#9040 -- every "auto-action held by precision circuit breaker" audit row was
wrong. agentHoldAuditDetail inferred the breaker purely from "a terminal action
was planned but is not in the final plan", but the call site passes the
POST-HOLDOUT plan, so every ε-holdout adjudication hold (#8831) was attributed
to a breaker that had never engaged -- 6 of 6 live rows paired 1:1 (within
20ms) with decision_audit_holdout events while system_flags contained no
engaged breaker at all. Each transform now REPORTS its own engagement, derived
from its own before/after pair, and the holdout gets its own reason string; the
residual set-difference case returns an honest generic reason instead of a
false specific attribution.

Closes #9019
Closes #9025
Closes #9040

* fix(ci): repair two pre-existing main breakages the drift/format gates enforce

Both of these are broken on main right now and fail every PR branched from it,
including this one:

1. .release-please-manifest.json still pinned packages/loopover-engine at
   3.15.0 while its package.json says 3.15.1 -- the manual bump in #9107 (which
   the engine twin-parity guard required) never synced the release manifest, so
   release-manifest:sync:check has failed on every commit since. Regenerated via
   `npm run release-manifest:sync`.

2. apps/loopover-ui's prettier gate failed on two files last touched by #8848
   (proof-of-power-stats-model.ts and proof-of-power-stats.test.tsx) -- two
   over-long object literals prettier wants wrapped. Applied `prettier --write`;
   pure formatting, no behavior change.
JSONbored added a commit that referenced this pull request Jul 26, 2026
…ses (#9111)

* fix(orb): retry the disposition on lock contention, retry inconclusive verdicts, and stop misattributing holdout holds

Three disposition-integrity fixes:

#9025 -- maybeRunAgentMaintenance returned silently when it lost the per-PR
actuation lock: the job completed "successfully", nothing re-queued the
disposition, and no audit row recorded that a planned action was abandoned.
That silently amplified every restart incident -- the recovered job re-ran,
hit its own dead predecessor's orphaned lock, and lost the disposition a
SECOND time with no trace at all. Now throws PrActuationLockContendedError
(the same contract review-evasion.ts's withPrActuationLock already used for
this exact condition; the queue honors its 5s retryAfterMs via
consumingRetryDelayMs) and records a named audit event. Both maintenance call
sites' catch handlers now re-throw retryable/rate-limit errors instead of
logging-and-dropping them, matching the review pipeline's own propagation
contract; a plain non-retryable failure is still swallowed and logged.

#9019 -- `cacheable=0` conflates two unrelated things: a DYNAMIC review
context (grounding/RAG), where the verdict is conclusive but not durable
across time, and a genuinely INCONCLUSIVE verdict (a provider outage, a
consensus-disputed roll). Because published rows were exempt from the
non-cacheable cooldown, a transient outage verdict became FINAL for that head
the moment it surfaced -- the bot never retried, directly contradicting the
finding's own "re-evaluates on the next update" text, while a green PR gave
the contributor no reason to push the commit that would force one. Worse, the
head-AGNOSTIC one-shot lookup pinned that same outage verdict across ALL
future heads, so a contributor pushing new code could not escape it either.
Records the review's own verdict as metadata.inconclusive and keys both
behaviors on it: the publish exemption still applies to dynamic-context rows
(#2119 unchanged) but not to inconclusive ones, and the one-shot cadence skips
inconclusive rows entirely -- that PR never got its one real shot. The cooldown
still bounds retries to at most one attempt per window.

#9040 -- every "auto-action held by precision circuit breaker" audit row was
wrong. agentHoldAuditDetail inferred the breaker purely from "a terminal action
was planned but is not in the final plan", but the call site passes the
POST-HOLDOUT plan, so every ε-holdout adjudication hold (#8831) was attributed
to a breaker that had never engaged -- 6 of 6 live rows paired 1:1 (within
20ms) with decision_audit_holdout events while system_flags contained no
engaged breaker at all. Each transform now REPORTS its own engagement, derived
from its own before/after pair, and the holdout gets its own reason string; the
residual set-difference case returns an honest generic reason instead of a
false specific attribution.

Closes #9019
Closes #9025
Closes #9040

* fix(ci): repair two pre-existing main breakages the drift/format gates enforce

Both of these are broken on main right now and fail every PR branched from it,
including this one:

1. .release-please-manifest.json still pinned packages/loopover-engine at
   3.15.0 while its package.json says 3.15.1 -- the manual bump in #9107 (which
   the engine twin-parity guard required) never synced the release manifest, so
   release-manifest:sync:check has failed on every commit since. Regenerated via
   `npm run release-manifest:sync`.

2. apps/loopover-ui's prettier gate failed on two files last touched by #8848
   (proof-of-power-stats-model.ts and proof-of-power-stats.test.tsx) -- two
   over-long object literals prettier wants wrapped. Applied `prettier --write`;
   pure formatting, no behavior change.

* fix(ci): fail closed on truncated CI reads and partial GraphQL responses

Two silent-failure classes on the wrong-merge path, both in the live CI/review
readers that gate every merge decision.

#9051 -- a FAILED check-runs page fetch already set checkRunsIncomplete, but
EXHAUSTING the 10-page cap with `rel="next"` still present did not: the loop
just exited and reduceLiveCiAggregate treated a truncated set as complete. A red
check on page 11+ was therefore invisible -> ciState "passed" -> planner
reviewGood -> MERGE. The executor's act-boundary recheck calls the same function
so it reproduced the wrong verdict rather than catching it, and the false
"passed" was persisted into the durable cross-job CI cache. Fixed for both the
check-runs and classic-status loops. Separately, the check-suites backstop --
the LAST gate before a commit is certified settled -- read page 1 only with no
Link follow, so a first-party suite still running on page 2 never set anyPending;
it now paginates and returns null (which the reducer already fails closed on)
when its own cap is exhausted. The GraphQL twin's `checkSuites` selection had no
hasNextPage guard either, unlike its `contexts` sibling one line above; added.

#9052 -- fetchLiveReviewThreadBlockers read `connection?.nodes` and returned []
without ever checking the GraphQL top-level `errors` array. GitHub's standard
partial-failure shape under load is HTTP 200 with `reviewThreads: null` plus
`errors`, which yielded [] -- indistinguishable from a genuinely thread-free PR
-- so a maintainer's unresolved blocking thread was dropped from the findings and
the gate could conclude success and merge over the open objection. Unlike a
transport error (nothing read at all -> fail open, unchanged), a partial result
means the answer is known-unreliable, so it now fails CLOSED with a synthetic
blocker. The sibling readers in this file already guarded this; this one was the
outlier. Same class, second instance: fetchLivePullRequestReviewDecision also had
no errors check and returned undefined, which let the caller's
`liveReviewDecision ?? pr.reviewDecision` substitute a STALE stored APPROVED for
a read that failed -- so a PR later flipped to CHANGES_REQUESTED still merged. It
now returns an explicit REVIEW_DECISION_UNREADABLE sentinel that survives the ??
fallback, matches no real enum value (so every === comparison is correctly
false), and is checked by name at the one approval-queue site that would
otherwise have read it as "confirmed no changes requested".

Closes #9051
Closes #9052

Tests: 3 cap-exhaustion regressions (check-runs, statuses, check-suites), a
GraphQL checkSuites-truncation guard, a 200-with-errors review-threads
fail-closed test, two review-decision sentinel tests, and an approval-queue test
proving an unreadable decision no longer clears a conflict-justified close. 100%
coverage on all 88 added lines; 1368/1368 across the 12 affected suites.
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. manual-review Gittensor contributor context

Projects

None yet

1 participant