/** * The acceptance view's CONFORMANCE section (AW-14 / arch-R13a + arch-R16). * * `GET /runs/:id/acceptance` used to resolve ONLY the QE ledger verdict, while * governance conformance claims were served on a separate route * (`/governance/claims`) nobody stands in front of — so a wiki-rule violation * never appeared where humans actually look at a run's "is it done?". This * module derives the missing half and `buildAcceptanceView` serves it BESIDE * the QE gate: two verdicts, one page, deny-dominates on both. * * Three honesty rules, all deny-dominant: * * 1. **Run-scoped claims, cited.** Claims are filtered to THIS run's scope * (`wicked-agent//shared` | `wicked-agent//unit/`, the * engine's `scope.rs` grammar) and each `conform:` obligation is parsed * back into the wiki/conformance rule it cites (severity, rule id, * statement — the `attach_recalled_rules` format), so a denial names the * rule that was violated instead of an opaque string. * * 2. **"Guardrailed" is a verified claim, never a default.** A run whose * workflow declared governed units but whose CLI has no gate-hook adapter * runs with UNCHECKED tool calls and only leaves a `governanceUnenforced` (or an * `evaluatorMutatedWorktree` — an evaluator that rewrote the code it was reviewing, F-036) * event behind (gate-hook injection is claude-only — FINDING-063, * `execute_wrapped.rs`). This section reads the run's durable event log and * reports `enforcement.status` accordingly; `guardrailed` is true ONLY when * enforcement was positively observed armed and nothing reported unenforced. * An unreadable event log is `unverifiable` — unknown is never guardrailed. * * 3. **Unreadable is not clean.** A claims wire that cannot be read yields * `claimsAvailable: false` plus the error — never an empty list wearing a * "no denials" face. * * COVERAGE BOUNDARY (write-it-down half of arch-R16): deterministic per-tool- * call input governance exists for claude only. Units routed to any other CLI * (Antigravity, Codex, local, …) get phase-boundary coverage only — the * in-process `apply_unit` output gate and the deliverable floor — which * evaluates the unit's OUTPUT after the fact and cannot block a tool call * mid-flight. A governed unit on a non-claude CLI is therefore reported here * as `unenforced`, not silently folded into "guardrailed". The same boundary * is documented in the README's acceptance section. * * Coordinates crew#311 (vacuous unit completion passes gates): same * gate-honesty seam, different defect — #311 is about "done" being asserted * from an empty turn; this section is about governance claims/enforcement * being invisible or overclaimed. Neither fix closes the other. */ import type { GovernanceClaim, RecordedEvent } from '../core/types.js'; import { type GovernanceModeKind, type GovernanceModeSource, type GovernanceSeatInput, type SeatGovernanceFence } from '../api/seat-governance.js'; /** A wiki/conformance rule cited by a claim's `conform:` obligation. */ export interface ConformanceRuleCitation { /** `Critical` | `Error` | `Warn` | `Info` — the rule's `ConfSeverity`, as serialized. */ severity: string; /** The conformance-rule id (`PAT-*` / `POL-*`) — the wiki rule the claim cites. */ ruleId: string; /** The rule's prescriptive statement. */ statement: string; } /** One of this run's governance decisions, run-scoped and with its rule citations parsed. */ export interface RunConformanceClaimView { claimId: string; scope: string; phase: string; decision: 'allow' | 'deny' | 'allow_with_conditions'; policyIds: string[]; /** Wiki/conformance rules cited by `conform:` obligations — the ruleset the output had to meet. */ rules: ConformanceRuleCitation[]; /** Every obligation, verbatim (includes the unparsed originals of `rules`). */ obligations: string[]; evaluator: string; /** Unix-seconds timestamp of evaluation. */ evaluatedAt: number; /** * True for an ADVISORY boundary READ deny: the tool call WAS blocked, but a blocked read leaks * nothing, so it is audit-only and not unit-fatal (core#219). Mirrors the engine's * `is_advisory_boundary_read_deny` exactly — evaluator identity AND claim-id prefix, so a policy * deny can never be downgraded to advisory. */ advisory: boolean; } /** A unit the workflow declared governed that ran with UNCHECKED tool calls (FINDING-063). */ export interface UnenforcedUnit { ord: number; attempt: number; cli: string; reason: string; /** * Which enforcement failure this is: `unchecked_tool_calls` — a governed unit ran on a seat with * no input-governance adapter (`governanceUnenforced`); `worktree_mutation` — an * `executes_code: false` unit changed the worktree it was reviewing (`evaluatorMutatedWorktree` * with a denying `changed`/`headMoved`, wicked-core F-036). Classification rides here, never on * the reason text (Copilot on #507). */ kind: 'unchecked_tool_calls' | 'worktree_mutation'; } /** What the run's durable event log says about whether governance was actually IN FORCE. */ export interface GovernanceEnforcementView { /** * - `enforced` — enforcement positively observed armed; nothing reported unenforced. * - `contained` — (IG1-crew-2) no unit ran unchecked, but ≥1 unit was held by an OS-sandbox * floor (or, on a bound run, the repository boundary) rather than a per-call * gate: its writes were fenced to the roots `units[].fence` names. Between * `enforced` and `unenforced`; never "guardrailed". * - `unenforced` — ≥1 governed unit ran with unchecked tool calls (`governanceUnenforced` on * a run bound to no repository) or an evaluator mutated the worktree. * - `ungoverned` — the log is readable and carries no governance signal at all: the run never * asked for governance. Not a failure — but never "guardrailed" either. * - `unverifiable` — the event log could not be read; unknown is never guardrailed. */ status: 'enforced' | 'contained' | 'unenforced' | 'ungoverned' | 'unverifiable'; /** The governed-but-unchecked units, verbatim from their events. Empty unless `unenforced`. */ unenforced: UnenforcedUnit[]; /** Ords of units whose governance context was confirmed armed (`governanceContextArmed`). */ armedUnits: number[]; /** Why the status is what it is — always populated. */ reason: string; /** (IG1-crew-2) What fenced each governed unit's tool calls, per attempt, oldest first. */ units: GovernedUnitRecord[]; } /** (IG1-crew-2) One governed unit attempt's governance record, derived from frames only. */ export interface GovernedUnitRecord { ord: number; attempt: number; cli: string; mode: GovernanceModeKind; source: GovernanceModeSource; fence: SeatGovernanceFence; reason: string; /** `undisclosed`: the unit reported `governanceUnenforced` on a bound run — the repository * boundary held its writes, but no armed floor was disclosed for it. */ enforced?: 'undisclosed'; } /** What the per-unit record needs beyond the log: the run's binding and the seats' records. */ export interface EnforcementContext { /** The run is bound to one repository (a worktree). */ bound: boolean; /** The bound run's worktree (`AgentSession.workdir`). */ worktree?: string | null; extraWriteRoots?: readonly string[]; /** The roster's record for a seat key (its `governance_class`, `acp`, `trust_flags`). */ seatOf?: (cli: string) => GovernanceSeatInput | undefined; } /** The conformance half of the acceptance view — served beside the QE gate. */ export interface RunConformance { /** Whether the claims wire could be read at all. False is NOT "no denials". */ claimsAvailable: boolean; /** The read failure, when `claimsAvailable` is false for a reason other than a missing binding. */ claimsError?: string; /** This run's claims (run-scope filtered), oldest first. */ claims: RunConformanceClaimView[]; /** Non-advisory deny claims — the ones that stand against the run. */ denials: number; /** Advisory boundary-read denies — blocked, audited, not unit-fatal. */ advisoryDenials: number; /** Deny-dominates over the run's READ claims: true when any non-advisory deny stands. */ denied: boolean; enforcement: GovernanceEnforcementView; /** * The ONE headline, deny-dominates across everything above: true ONLY when the claims wire was * readable, no non-advisory denial stands, AND enforcement was positively verified. An * unenforced, ungoverned, or unverifiable run is NEVER guardrailed (arch-R16). */ guardrailed: boolean; /** One honest sentence for the surface beside the QE verdict. */ summary: string; } /** Whether `scope` belongs to run `runId` under the engine's scope grammar. */ export declare function isRunScope(scope: string, runId: string): boolean; /** * Parse one `conform:::` obligation (the `attach_recalled_rules` format) * into its rule citation. Statements may contain `:` freely — only the first three separators * split. Returns null for any obligation that is not a rule citation (boundary reasons, policy * obligations, free text): those stay visible verbatim in `obligations`. */ export declare function parseRuleCitation(obligation: string): ConformanceRuleCitation | null; /** Mirror of the engine's `is_advisory_boundary_read_deny` (`gate_hook.rs`). */ export declare function isAdvisoryBoundaryReadDeny(claim: GovernanceClaim): boolean; /** * Derive the enforcement view from the run's durable event log. * * `events === null` means the log could NOT be read (no binding, or the loader was not wired) — * which is `unverifiable`, never a quiet "enforced". An empty log is a real answer: no governance * signal ⇒ `ungoverned`. */ export declare function resolveEnforcement(events: RecordedEvent[] | null, ctx?: EnforcementContext): GovernanceEnforcementView; /** * Assemble the conformance section: run-scoped claims + enforcement, resolved deny-dominates. * * `claims === null` means the claims wire could not be read (`claimsError` says why when known) — * reported as unavailable, never as an empty clean list. */ export declare function resolveConformance(opts: { runId: string; claims: GovernanceClaim[] | null; claimsError?: string; events: RecordedEvent[] | null; /** IG1-crew-2: the run's binding and seat records for the per-unit record. */ enforcementContext?: EnforcementContext; }): RunConformance; //# sourceMappingURL=conformance.d.ts.map