/** * OperatorActionVerifier (M8 Phase 2) - verifies that a reconcile run actually * performed its obligated action. Ports Kagemusha's ContractActionVerifier * snapshot-diff mechanism, strengthened per plan review: signals must be BOUND * to the run, not to unrelated board activity. * * Verified iff, after the run: * (a) a NEW gateway tool-call trace row exists (rowid past the snapshot) * whose normalized tool name is one of the obligated tools, or * (b) a NEW no-update note exists with EXACTLY this run's scope. * Slot/ledger hash deltas are recorded as evidence detail only -- another * writer may have moved them (the board-writer queue makes in-queue runs * non-concurrent, which closes the remaining race). * * Observe, never block: the caller records the outcome and emits a notice; * an unverified run is a loud signal, not a rejection. */ import type { TaskRecord, TemporalGenerationRecord } from './task-ledger.js'; import { type TemporalEffectReceipt, type TemporalWorkContext } from './temporal-effect.js'; export declare const OBLIGATED_TOOLS: readonly ["report_publish", "task_create", "task_update", "contract_no_update"]; export interface VerifierDeps { /** Current report slots (id -> html). */ getSlots: () => Array<{ slotId: string; html: string; }>; /** Stable hash of the task ledger payload. */ getLedgerHash: () => string; /** Max no-update note id for a scope (0 when none). */ getScopedNoteMaxId: (scope: string) => number; /** * Count of gateway tool-call trace rows past a rowid whose normalized tool * name is in OBLIGATED_TOOLS (bound to the reconcile agent). */ countObligatedTraceRowsSince: (maxId: number) => number; /** Max gateway trace rowid right now (0 when none). */ getTraceMaxId: () => number; } export interface ActionSnapshot { slotHashes: Record; ledgerHash: string; scopedNoteMaxId: number; traceMaxId: number; } export interface VerifyResult { verified: boolean; /** Human-readable evidence lines for the activity record. */ effects: string[]; } export declare function captureSnapshot(deps: VerifierDeps, scope: string): ActionSnapshot; export declare function verifyAfterRun(deps: VerifierDeps, before: ActionSnapshot, scope: string): VerifyResult; export interface TemporalVerifierDeps { loadTemporalWorkContext: (attemptId: number) => TemporalWorkContext; getTemporalEffect: (attemptId: number) => TemporalEffectReceipt | null; getTask: (taskId: number) => TaskRecord | null; getTemporalGeneration: (generationKey: string) => TemporalGenerationRecord | null; getScopedNoteMaxId: (scope: string) => number; } export type TemporalEffectSnapshot = Readonly; export type TemporalVerifyResult = { verified: true; outcome: TemporalEffectReceipt['outcome'] | 'verified_superseded'; effects: string[]; } | { verified: false; reason: string; effects: string[]; }; export declare function captureTemporalEffectSnapshot(deps: TemporalVerifierDeps, attemptId: number): TemporalEffectSnapshot; export declare function verifyTemporalEffect(deps: TemporalVerifierDeps, before: TemporalEffectSnapshot): TemporalVerifyResult; //# sourceMappingURL=action-verifier.d.ts.map