/** * Extracted, testable pieces of the Stage-2 per-kind completion hooks * (plan S2-T3; extraction demanded by implementation review round 1 - the * hook bodies lived in registerApiRoutes closures where nothing could prove * them, which is the green-test-trap class the plan bans). * * - buildWorkerTraceQueries: the G1 re-keyed verifier trace queries. Worker * runs log gateway_tool_call rows with the worker's identity, NOT * agent_id='dashboard-agent'; the ONLY schema-supported key is the details * JSON (agent_activity has no channel_id column) - hence json_extract. * - buildPromotionAfterHook: the PROMOTED parse + event re-emission that * keeps the memory:promoted -> wiki ingress chain alive (plan E4/R7). * - buildWikiAfterHook: outcome reading only. */ import type { SQLiteDatabase } from '../sqlite.js'; import type { BoardCandidateAttemptState, WorkOrderRecord } from './task-ledger.js'; import { type TemporalVerifierDeps } from './action-verifier.js'; import type { WorkOrderEffectVerdict, WorkOrderHook } from './workorder-consumer.js'; export interface BoardCandidateReceiptInspector { inspectBoardCandidateAttempt(attemptId: number): BoardCandidateAttemptState; } /** Candidate completion is established by receipts, never verifier telemetry. */ export declare function boardCandidateReceiptVerdict(workOrder: WorkOrderRecord, inspector: BoardCandidateReceiptInspector | null | undefined): WorkOrderEffectVerdict; /** * The tools whose execution proves a lane did its job, per lane. * * The board lane already verified this way: a run counts as verified when a NEW * gateway_tool_call trace row appears past the snapshot, naming an obligated tool. That is * a measurement - the trace row is written by the executor when the call runs, so an agent * cannot produce one by describing a call it never made. * * The wiki and promotion lanes were reading the agent's PROSE instead, and the gap that * opened is measurable: 59 wiki work orders reached 'done' while wiki_page_index last moved * on 2026-07-04. The tools themselves are honest - wiki_publish writes the page and index * synchronously and throws on failure - but nothing downstream required the call to have * happened. * * `contract_no_update` is obligated everywhere: a run that legitimately found nothing must * still say so through a tool, or "nothing to do" and "did nothing" stay indistinguishable. */ export declare const LANE_OBLIGATED_TOOLS: { readonly board: readonly ["report_publish", "task_create", "task_update", "contract_no_update"]; readonly wiki: readonly ["obsidian", "wiki_publish", "contract_no_update"]; readonly 'memory-curation': readonly ["mama_save", "contract_no_update"]; }; /** * The subset that proves the lane WROTE, as opposed to merely acting. * * `contract_no_update` is obligated so an empty run has a way to say so - but counting it as * a write is how the first version of this hook reported "promotion run: 1 saved" for a run * that honestly saved nothing, and woke the wiki compiler on it. Found in review. Two * questions, two counts: did the lane act, and did it write. */ export declare const LANE_WRITE_TOOLS: { readonly wiki: readonly ["obsidian", "wiki_publish"]; readonly 'memory-curation': readonly ["mama_save"]; }; export interface WorkerTraceQueries { getTraceMaxId: () => number; countObligatedTraceRowsSince: (maxId: number) => number; } export declare function buildWorkerTraceQueries(sessionsDb: SQLiteDatabase | undefined, workerChannelId: string, obligatedTools?: readonly string[]): WorkerTraceQueries; export interface PromotionHookEvents { emitAgentAction: (action: 'promoted' | 'no_update', target: string) => void; emitMemoryPromoted: (saved: number) => void; log?: (line: string) => void; } /** * What the run SAID, kept apart from what it DID. * * The claim is still parsed, because the promotion count feeds the memory:promoted -> * wiki ingress chain and nothing else carries it. It is no longer trusted on its own: the * trace count is the measurement, and when the two disagree the disagreement is the finding. */ export interface LaneClaim { /** What the response asserts it wrote (0 when it asserts nothing). */ claimed: number; /** Whether the response asserts there was nothing to do. */ noUpdate: boolean; } export declare function readLaneClaim(response: string): LaneClaim; /** * Compare a lane's claim against its obligated-tool traces. * * Observe, never block - the same rule the board verifier states, and for the same reason: * a run that overstates has still done whatever it did, and failing it here would retry work * that may have partly landed. The falsehood becomes visible instead of authoritative. */ export declare function reconcileClaimAgainstTraces(claim: LaneClaim, traceCount: number): { verified: boolean; note: string; }; export interface LaneAfterHookDeps { /** Counts the lane's obligated tools: proves the run ACTED. */ traces: WorkerTraceQueries; /** * Counts only the lane's write tools: proves the run WROTE. Separate from `traces` because * `contract_no_update` is honest evidence of acting and no evidence at all of writing. */ writeTraces?: WorkerTraceQueries; log: (line: string) => void; /** Raised when the run cannot be shown to have done what it reported. */ onUnverified?: (note: string) => void; } /** * The wiki ingress chain's second link: losing the parse severs memory:promoted, so the * claim is still read - but `emitMemoryPromoted` now carries the measured count, not the * asserted one, so a lane that writes nothing can no longer wake the wiki compiler. */ export declare function buildPromotionAfterHook(events: PromotionHookEvents, deps?: LaneAfterHookDeps): (wo: WorkOrderRecord, response: string, before?: unknown) => void; export declare function buildWikiAfterHook(log: (line: string) => void, deps?: Omit): (wo: WorkOrderRecord, response: string, before?: unknown) => void; export declare function buildTemporalWorkOrderHook(deps: TemporalVerifierDeps): WorkOrderHook; //# sourceMappingURL=workorder-hooks.d.ts.map