> ## Documentation Index
> Fetch the complete documentation index at: https://docs.claw.boo/llms.txt
> Use this file to discover all available pages before exploring further.

# @clawboo/governance

> Pure verification (builder≠judge) and governance primitives: verdict schemas, severity policy, budget cent-math, caps, and circuit-breaker reducer.

* **Version** `0.1.0`
* **Purity** pure zero-dep (browser-safe; only external dep is `zod`, no `node:*` / DB / network)
* **Purpose** The shared typed vocabulary for verification (builder≠judge) and governance (budgets, caps, circuit breakers): pure functions + zod schemas the board, server libs, and SPA all consume identically.
* **Workspace deps** none
* **External deps** `zod` `^3.25.0`

DB-bound concerns (tables, atomic SQL, audit inserts) live in `@clawboo/db`; runtime I/O (spawning the verify command, the review worktree) lives server-side. This package is purely the decision layer.

The barrel re-exports four module groups: `./verify`, `./budget`, `./caps`, `./breaker`. The package exposes a single `.` entry point (no subpath exports).

## Public API

### Functions

**verify**

| Signature                                                                                  | Contract                                                                                                                                                                                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `classifySeverity(finding: Finding): 'block' \| 'warn'`                                    | Rationed blocking: `block` only for `security`/`crash`/`data_loss`/`wrong_algorithm`/`missing_ac`; everything else is `warn` (debt).                                                                                                                                                                                                                            |
| `blockingFindings(verdict: CriticVerdict): Finding[]`                                      | The verdict's findings filtered to blocking severities.                                                                                                                                                                                                                                                                                                         |
| `isBlocking(verdict: CriticVerdict): boolean`                                              | True when the verdict has ≥1 blocking finding.                                                                                                                                                                                                                                                                                                                  |
| `verificationStatusFor(det: DeterministicResult, critic: CriticVerdict): 'pass' \| 'fail'` | Compose one attempt's status: a red gate is always `fail`; a green gate + a blocking critic finding is `fail`; otherwise `pass`. Never produces `completed_with_debt`.                                                                                                                                                                                          |
| `nextCycleDecision({ attempt, maxCycles }: CycleInput): 'retry' \| 'mark_debt'`            | After a failing attempt, `mark_debt` once `attempt >= max(1, maxCycles)`, else `retry`. The retry budget is bounded; the evaluator is permanent.                                                                                                                                                                                                                |
| `isVerdictPromotable(verdict: PromotableVerdict \| null \| undefined): boolean`            | The `→done` gate rule the board state machine enforces, and the check the approval reaper uses to leave a verification-held task `blocked`: `pass` → yes; `completed_with_debt` → only if the latest attempt's deterministic gate passed; anything else / missing → no. The worktree completion path no longer calls it, since it promotes only a clean `pass`. |
| `parseVerifyCommand(initShText: string): string \| null`                                   | Parse `VERIFY_CMD='…'` (optional `export `) out of an `init.sh` body, reversing bash single-quote escaping. Returns `null` when absent or the placeholder.                                                                                                                                                                                                      |
| `parseVerifyCommandFromVerificationMd(md: string): string \| null`                         | Parse the `` - Verify: `<cmd>` `` line out of a `VERIFICATION.md` body. `null` when absent or the placeholder.                                                                                                                                                                                                                                                  |
| `shouldRunCritic(input: CriticTriggerInput): boolean`                                      | Run the read-only critic when `riskFlag`, `hasParent` (delegated work), or the diff exceeds the file/line thresholds (default 5 files / 300 lines).                                                                                                                                                                                                             |

**budget**

| Signature                                                              | Contract                                                                                                                                                                                                    |
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `usdToCents(usd: number): number`                                      | USD → non-negative ROUNDED cents (display + the integer-cent per-node cap). NOT for the ledger: sub-half-cent rounds to 0.                                                                                  |
| `usdToFractionalCents(usd: number): number`                            | USD → fractional cents (un-rounded) for the budget ledger, so sub-cent deltas accumulate losslessly.                                                                                                        |
| `centsToUsd(cents: number): number`                                    | `cents / 100`.                                                                                                                                                                                              |
| `softThresholdCents(limitCents: number): number`                       | `floor(limitCents * 80 / 100)`, same integer arithmetic as the SQL `CASE`.                                                                                                                                  |
| `statusForSpend(limitCents: number, spentCents: number): BudgetStatus` | `paused` at/over limit, `soft_capped` at/over the 80% threshold, `active` below. `limitCents <= 0` ⇒ `active` (uncapped).                                                                                   |
| `budgetStatusAfter(input: BudgetStatusInput): BudgetStatusResult`      | Apply a spend delta; reports the resulting status, the `crossed` threshold (`'soft'`/`'hard'`/`'none'`, non-`none` only on the tipping event), and `newSpentCents`. Mirrors the DB `recordSpend` authority. |

**caps**

| Signature                                          | Contract                                                                                                            |
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| `checkDepthCap({ depth, max }): CapResult`         | Reject (`ok: false`) once existing ancestor `depth >= max` (the new child would be `depth+1`).                      |
| `checkFanoutCap({ siblingCount, max }): CapResult` | Reject once a parent already has `siblingCount >= max` children.                                                    |
| `checkCostCap({ nodeCents, max }): CapResult`      | Reject once a single run's accrued `nodeCents >= max`; `>=` matches the budget hard cap's exact-boundary semantics. |

**breaker**

| Signature                                                                      | Contract                                                                                                                                                                                                                    |
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `createBreakerState(config?: Partial<BreakerConfig>): BreakerState`            | Fresh run-local breaker accumulator, merging overrides over `BREAKER_DEFAULTS`.                                                                                                                                             |
| `stepBreaker(state: BreakerState, signal: BreakerSignal): BreakerTrip \| null` | Deterministic step function (mutates `state`, no I/O, no clock read) over a typed signal; returns the FIRST trip seen, or `null`.                                                                                           |
| `toolSignature(name: string, input: unknown): string`                          | Stable identity `<name>:<fnv1a-hash-of-JSON(input)>`, computed from typed fields, never scraped prose. Falls back to name-only on unserializable input.                                                                     |
| `isPolicyDenialCode(code: string \| null \| undefined): boolean`               | True when `code` (case-insensitive) is in the typed denial allowlist (`policy_denied`/`permission_denied`/`denied`/`forbidden`/`unauthorized`/`eperm`/`eacces`). Keyed on the RuntimeEvent `error.code`, not message prose. |

### Types & interfaces

**verify**

| Name                  | Shape / contract                                                                                                                                      |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Severity`            | `z.infer` of `severitySchema`: `'security' \| 'crash' \| 'data_loss' \| 'wrong_algorithm' \| 'missing_ac' \| 'style' \| 'perf' \| 'other'`.           |
| `Finding`             | `{ severity, title, body, filePath \| null, startLine \| null, confidence }`, one critic finding; non-`severity`/`title` fields default.              |
| `DeterministicResult` | `{ command, exitCode \| null, passed, stdoutTail, stderrTail, durationMs, timedOut }`, the gate's exit-code truth + scrubbed tails.                   |
| `CriticOutput`        | `{ findings: Finding[] }`, exactly what a reviewer model emits.                                                                                       |
| `CriticVerdict`       | `{ ran, findings, reviewerRuntime \| null, reviewerModel \| null, reviewedSha \| null }`, stored critic verdict; `ran: false` ⇒ critic not triggered. |
| `StructuredError`     | `{ what, why, howToFix }`, an actionable failure routed back, not "FAIL".                                                                             |
| `VerificationStatus`  | `'pass' \| 'fail' \| 'completed_with_debt'`.                                                                                                          |
| `VerificationAttempt` | `{ attempt, at, deterministic, critic, status, structuredError \| null }`, one verify-fix attempt.                                                    |
| `DebtNote`            | `{ criterion, severity, justification }`, a signed-off gap carried at cycle exhaustion.                                                               |
| `VerificationResult`  | `{ status, attempts: VerificationAttempt[] (min 1), debtNotes, updatedAt }`, the full record stored on a task in one TEXT cell.                       |
| `CycleInput`          | `{ attempt: number; maxCycles: number }`, input to `nextCycleDecision`.                                                                               |
| `DiffStat`            | `{ filesChanged, insertions, deletions }`.                                                                                                            |
| `CriticTriggerInput`  | `{ diffStat, hasParent, riskFlag?, threshold?: { files?; lines? } }`.                                                                                 |

**budget**

| Name                 | Shape / contract                                                            |
| -------------------- | --------------------------------------------------------------------------- |
| `BudgetStatus`       | `'active' \| 'soft_capped' \| 'paused'`.                                    |
| `BudgetCrossing`     | `'none' \| 'soft' \| 'hard'`.                                               |
| `BudgetStatusInput`  | `{ limitCents; spentCents (before this delta); deltaCents }`.               |
| `BudgetStatusResult` | `{ status: BudgetStatus; crossed: BudgetCrossing; newSpentCents: number }`. |

**caps**

| Name        | Shape / contract                    |
| ----------- | ----------------------------------- |
| `CapResult` | `{ ok: boolean; reason?: string }`. |

**breaker**

| Name                 | Shape / contract                                                                                                                                                            |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BreakerConfig`      | `{ maxToolIterations, repeatFailureThreshold, noProgressThreshold, tokenVelocityCeiling, velocityMinWindowMs, repeatPolicyDeniedThreshold }`.                               |
| `BreakerConfigInput` | `z.infer` of `breakerConfigSchema`, partial `BreakerConfig` (each field optional) accepted from a REST body / run input.                                                    |
| `BreakerTripReason`  | `'iteration-cap' \| 'repeat-failure' \| 'no-progress' \| 'token-velocity' \| 'repeat-policy-denied'`.                                                                       |
| `BreakerTrip`        | `{ reason: BreakerTripReason; detail: string; counters: Record<string, number> }`.                                                                                          |
| `BreakerSignal`      | `{ kind: 'tool-call' \| 'tool-result' \| 'cost' \| 'policy-denied'; ts; signature?; ok?; tokens? }`, one observation derived from a typed RuntimeEvent.                     |
| `BreakerState`       | Run-local accumulator: `{ config, toolIterations, consecFailures, lastFailSig, productiveSigs, nonProductive, consecDenials, lastDenialSig, windowStartTs, windowTokens }`. |

### Constants

| Name                            | Value / contract                                                                                                                                                                                                          |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `severitySchema`                | zod enum of the 8 `Severity` values.                                                                                                                                                                                      |
| `findingSchema`                 | zod object for `Finding` (terse model output still parses via defaults).                                                                                                                                                  |
| `deterministicResultSchema`     | zod object for `DeterministicResult`.                                                                                                                                                                                     |
| `criticOutputSchema`            | zod object for `CriticOutput` (`findings` defaults to `[]`).                                                                                                                                                              |
| `criticVerdictSchema`           | zod object for `CriticVerdict`.                                                                                                                                                                                           |
| `structuredErrorSchema`         | zod object for `StructuredError`.                                                                                                                                                                                         |
| `verificationStatusSchema`      | zod enum for `VerificationStatus`.                                                                                                                                                                                        |
| `verificationAttemptSchema`     | zod object for `VerificationAttempt`.                                                                                                                                                                                     |
| `debtNoteSchema`                | zod object for `DebtNote`.                                                                                                                                                                                                |
| `verificationResultSchema`      | zod object for `VerificationResult` (`attempts` min 1).                                                                                                                                                                   |
| `DEFAULT_MAX_FIX_CYCLES`        | `3`, exported but no longer wired: the server's budget is `verifyMaxAttempts()` (`CLAWBOO_MAX_FIX_CYCLES` plus one, default 2 attempts). Two disagreeing defaults made the `mark_debt` exit unreachable.                  |
| `DEFAULT_CRITIC_THRESHOLD`      | `{ files: 5, lines: 300 }`, diff size above which the critic fires.                                                                                                                                                       |
| `SOFT_CAP_PERCENT`              | `80`, soft-cap threshold percent.                                                                                                                                                                                         |
| `MICRO_CENTS_PER_CENT`          | `10_000`, ledger micro-cent carry granularity.                                                                                                                                                                            |
| `DEFAULT_MAX_DEPTH`             | `2`, the SINGLE ancestor-chain depth ceiling. The board's capped create path, the team orchestrator, and the executor runner all derive from it (both `MAX_SPAWN_DEPTH` constants are now aliases), so they cannot drift. |
| `DEFAULT_MAX_CHILDREN`          | `24`, default per-parent LIFETIME live-child ceiling for the board's capped create path. Distinct from the per-turn fan-out cap (8).                                                                                      |
| `DEFAULT_MAX_ROOT_CREATES`      | `30`, default root-task creations allowed per rolling window (a RATE, not a total — a lifetime cap on roots would jam a long-lived board).                                                                                |
| `DEFAULT_ROOT_CREATE_WINDOW_MS` | `300_000` (5 min), the rolling window `DEFAULT_MAX_ROOT_CREATES` is measured over.                                                                                                                                        |
| `BREAKER_DEFAULTS`              | `{ maxToolIterations: 30, repeatFailureThreshold: 3, noProgressThreshold: 6, tokenVelocityCeiling: 200_000, velocityMinWindowMs: 15_000, repeatPolicyDeniedThreshold: 2 }`.                                               |
| `breakerConfigSchema`           | zod partial object for `BreakerConfigInput`.                                                                                                                                                                              |
| `breakerTripReasonSchema`       | zod enum for `BreakerTripReason`.                                                                                                                                                                                         |

### Classes

None: this package exports only functions, types, and constants.

## Used by

* **`@clawboo/db`**, `board/repository.ts`, `board/verification.ts` (state-machine gate via `isVerdictPromotable`), `governance/budgets.ts` (`recordSpend` mirrors `budgetStatusAfter`).
* **`@clawboo/evals`**, the ±verifier ablation scorecard.
* **`apps/web` (server)**, `lib/verification/{index,critic,deterministicGate}.ts` (the verify gate), `lib/executorRunner.ts` (budget kill-switch + breaker feed), `lib/routines/openclawDispatch.ts`, `lib/teamChat/dispatchChatTurn.ts`, `lib/worktrees.ts`, `lib/defaults.ts` (`SOFT_CAP_PERCENT`), `api/runtimes.ts` (`breakerConfigSchema` validation).
* **`@clawboo/team-orchestration`**, `boardOrchestration.ts` (`checkFanoutCap` for the per-turn delegation fan-out cap); the SPA reaches it through the re-export shim at `apps/web/src/features/group-chat/boardOrchestration.ts` and imports nothing from this package directly.
* **`@clawboo/db`** also uses the cap predicates: `board/repository.ts` calls `checkDepthCap` / `checkFanoutCap` in `createCappedSubtask` and re-exports `DEFAULT_MAX_CHILDREN` / `DEFAULT_MAX_DEPTH` by name, so `@clawboo/mcp` reads them without taking its own dependency on this package.

## Source

Barrel: [`packages/governance/src/index.ts`](https://github.com/clawboo/clawboo/blob/main/packages/governance/src/index.ts) (re-exports `./verify`, `./budget`, `./caps`, `./breaker`).

## See also

* [Verification (builder≠judge)](/concepts/verification)
* [Governance: budgets, breakers, caps](/concepts/governance)
* [Governance REST API](/reference/rest-api/governance)
* [`@clawboo/db`](/reference/packages/db), the DB authority for budgets/verification/audit
* [`@clawboo/executor`](/reference/packages/executor), the `RuntimeEvent` union the breaker signals derive from
* [Package overview](/reference/packages/index)
