import type { ExtractedTool, JudgmentFields, JudgmentsFile, PendingLoosening, ToolJudgment } from "./formats.js"; /** * The judgment layer's deterministic half: the direction rule that decides * which half of a model's proposal may land and which half waits for a human. * * The safety property is one-way and absolute. A judgment may make a tool MORE * restrictive on its own — raise risk, narrow audience, disable, mark confirmEach, * rewrite prose. It may never make one LESS restrictive: lowering risk, widening * audience, waking a disabled tool, or clearing a confirmEach mark is a human act. * Those do not get refused and forgotten (the old clamp's failure: a real * finding evaporated into a log line) — they are QUEUED as `pending` on the * judgment, each with its own evidence, and stay inert at runtime until a human * accepts them. Direction is computed against the tool's EFFECTIVE state * (skeleton ⊕ the standing judgment), so accepted judgments only ratchet * tighter and an over-tight call is undone by a human, never by the next model * run. Tool identity, bindings, and inputSchema are not expressible here: * `JudgmentFields` is the whole AI-writable surface. */ /** Restrictiveness order over the grades someone actually assigned. * `ungraded` is the ABSENCE of a grade, so it is not a rung here — * `classifyField` handles it directly. */ export declare const RISK_RANK: { readonly read: 0; readonly write: 1; readonly destructive: 2; }; /** Audience narrowing order: an ungraded tool behaves as end-user-visible, so * end-user is the widest grade and internal the narrowest (non-end-user * grades exclude the tool from the embedded agent by default). */ export declare const AUDIENCE_RANK: { readonly "end-user": 0; readonly operator: 1; readonly internal: 2; }; /** One tool's proposal from the judge: the writable fields plus the evidence * every queued loosening inherits. Evidence is required because a loosening * cannot exist without it. */ export interface JudgmentProposal extends JudgmentFields { evidence: string; reason?: string; } /** * Which way one proposed field moves the tool. "harden" = at least as * restrictive as the tool's current state (a restatement is a harmless no-op * the caller drops); "loosen" = strictly less restrictive, which never applies * itself. Prose and semantics route with the hardenings: there is no direction * to a description, and the AI is the sole author of one. */ export declare function classifyField(tool: ExtractedTool, field: keyof JudgmentFields, value: unknown): "harden" | "loosen"; /** * Split one proposal against the tool's EFFECTIVE current state — pass the * entry `applyJudgment` already returned, not the raw `tools.json` skeleton, or * a standing judgment's own grade reads as a fresh hardening. No-ops (a field * restating what already holds) drop from both sides. */ export declare function splitProposal(tool: ExtractedTool, proposal: JudgmentProposal): { hardenings: JudgmentFields; loosenings: PendingLoosening[]; }; /** * Apply a standing judgment to one tool. The judgment's `binding` is checked * against the tool's identity first: a judgment of a handler that moved is * INERT, never re-pointed at whatever now answers under that name. `pending` is * never applied — those wait for a human. */ export declare function applyJudgment(tool: ExtractedTool, judgment: ToolJudgment | undefined): ExtractedTool; /** * Why one host tool is off, named for the layer that turned it off, or * undefined when it is live. The human's override wins the merge, so it is * checked first; an audience grade is the fail-closed exclusion `applyJudgment` * adds above, and it is the only reason no file states outright — which is * exactly how a graded tool used to vanish in silence. */ export declare function disabledReason(tool: ExtractedTool, judgment: ToolJudgment | undefined, override: { disabled?: boolean; } | undefined): string | undefined; /** * Drop judgments that no longer describe anything: a name the current catalog * does not carry, or one whose binding moved. Keeps the file honest instead of * accumulating inert entries a human would have to read past. */ export declare function pruneJudgments(file: JudgmentsFile, tools: ExtractedTool[]): JudgmentsFile;