Skip to content

orb(observability): hold reason is misattributed — 100% of 'precision circuit breaker' holds are actually adjudication holdouts #9040

Description

@JSONbored

Every agent.action.hold that reports "auto-action held by precision circuit breaker" is actually the ε=20% close-audit adjudication holdout (#8831). The precision circuit breaker has never engaged. The ledger names the wrong cause.

The bug

agentHoldAuditDetail (src/queue/processors.ts ~2277-2280) infers the breaker purely from "a terminal action was planned but is not in the final plan":

const plannedTerminalAction = args.planned.some(a => a.actionClass === "merge" || a.actionClass === "close");
const finalTerminalAction  = args.breakerOnPlan.some(a => a.actionClass === "merge" || a.actionClass === "close");
if (plannedTerminalAction && !finalTerminalAction)
  return "auto-action held by precision circuit breaker";   // <-- assumes the breaker did it

But the call site at ~3391 passes breakerOnPlan: holdoutOnPlan — i.e. the plan after maybeApplyCloseAuditHoldout (~3266), not after applyPrecisionBreakers (~3237). So when the holdout removes the close, this first branch matches and attributes it to the breaker. Being the first branch, it also shadows every more-specific reason below it.

Empirical proof (live ledger, edge-nl-01, since 2026-07-20)

So the correlation is 100% and the claimed cause is provably absent.

Why this matters

A wrong reason is worse than no reason: an operator investigating a stalled PR chases a circuit breaker that was never engaged, while the real cause (this PR was deliberately sampled for human adjudication) is one line above in the ledger and gets ignored. It also corrupts any analysis of breaker behavior — the breaker looks active when it has never fired.

Fix

  1. Pass the genuinely post-breaker plan for the breaker comparison, and check the holdout separately — or better, have each transform (breaker, holdout) report why it removed an action instead of the audit function guessing from set difference.
  2. Add a distinct reason string for the holdout: "auto-action held for close-audit adjudication (ε-holdout)".
  3. Order the branches so a specific, known cause always beats the inferred one.

This is a concrete instance of the invariant in #9003: a decision reason must be recorded by the code that made the decision, never reconstructed by comparing before/after states.

Acceptance

  • A holdout-held PR reports the holdout as its reason; a breaker-held PR reports the breaker; a ledger query can distinguish them.

Refs #9003, #8831.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.orbGittensory Orb related - maintainer self-hosting analytics.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions