import { type SigningKey } from './keys.js'; import type { ActorAssurance } from './tokens.js'; export declare const RECEIPT_VERSION: 'conarium-receipt/0.4'; /** Single-source vocabulary. Order is the documented meaning order; new values are appended. */ export declare const META_SOURCES: readonly ['protocol', 'measured', 'operator-declared', 'undeclared']; export type ActorType = 'service' | 'user'; export type PolicyDecision = 'allow' | 'deny' | 'partial'; export type OutcomeStatus = 'complete' | 'error' | 'denied'; export interface ReceiptActor { type: ActorType; id: string; /** How the identity was established — the receipt carries not just who, but HOW they were known. */ assurance: ActorAssurance; } /** * WHERE a meta field's value came from. * * The receipt does not say "the model was X" — it says "declared as X" or * "not declared". Same discipline as `ReceiptActor.assurance`: next to the * value, an evidence level saying how seriously it can be taken. * * - `protocol` measured during the connection (MCP initialize → clientInfo) * - `measured` computed by Conarium itself (a hash, etc.) — no invention * - `operator-declared` operator declared it in config; Conarium did NOT verify * - `undeclared` not declared; fields are null, nothing was invented * * `verified` / `attested` do NOT exist TODAY. If attestation arrives, `attested` is added then. */ export type MetaSource = (typeof META_SOURCES)[number]; export interface ReceiptModel { source: MetaSource; provider: string | null; name: string | null; version: string | null; } export interface ReceiptClient { source: MetaSource; name: string | null; version: string | null; } /** * Commitment over the result that crossed the boundary. The hash is over the * UTF-8 bytes of the masked / row-capped text sent to the client — the * request hash (`request.argsHash`) does not bind the output; this field does. * * `measured`: Conarium computed those bytes. `undeclared`: error/deny path or * the result was not serialized; hash/bytes are null, nothing invented. */ export interface ReceiptDisclosure { hash: string | null; bytes: number | null; source: Extract; } /** * Destination declaration. MCP does not carry a model; the value comes from * operator config. Conarium does not verify it. The policy decision is NOT * bound to this field — binding an access decision to an unverifiable field * would make the declaration look like enforcement. */ export interface ReceiptDestination { value: string | null; source: Extract; } export interface ReceiptRequest { tool: string; target: string; argsHash: string; } export interface ReceiptDataRef { source: string; object: string; fieldsRequested: string[]; } export interface ReceiptPolicy { id: string; version: string; decision: PolicyDecision; rulesApplied: string[]; } export interface ReceiptMasking { maskedCount: number; byClass: Record; rowsReturned: number; rowCapApplied: boolean; } export interface ReceiptOutcome { status: OutcomeStatus; denied: boolean; } export interface ReceiptChain { seq: number; prevHash: string; hash: string; } export interface ReceiptSig { alg: 'Ed25519'; keyId: string; value: string; } /** Hash-exterior reference; OTS proof lives in `.anchors.jsonl`. */ export interface ReceiptAnchor { log: string; ref: string; state: 'pending' | 'bitcoin'; } export interface Receipt { v: typeof RECEIPT_VERSION; id: string; ts: string; period: { start: string; end: string; }; actor: ReceiptActor; model: ReceiptModel; client: ReceiptClient; destination: ReceiptDestination; request: ReceiptRequest; dataRefs: ReceiptDataRef[]; policy: ReceiptPolicy; flags: string[]; masking: ReceiptMasking; disclosure: ReceiptDisclosure; outcome: ReceiptOutcome; consentRef: null; chain: ReceiptChain; sig: ReceiptSig | null; anchor: ReceiptAnchor | null; } /** Input for buildReceipt — no chain/hash/sig/anchor. */ export interface ReceiptInput { id?: string; ts?: string; period: { start: string; end: string; }; actor: { id: string; type?: ActorType; assurance?: ActorAssurance; }; /** * If omitted, written as `undeclared`. Model identity is NOT in the MCP * protocol; if the operator did not declare it, the receipt says "not * declared" instead of hiding that. */ model?: { provider: string; name: string; version: string; }; /** * If `source` is omitted it counts as a declaration. A value measured from * MCP `initialize` must arrive with `source: 'protocol'` — measured and * declared must not be mixed. */ client?: { name: string; version: string; source?: MetaSource; }; /** Operator declaration (e.g. "openai/gpt-x"). Not verified. Undeclared if absent. */ destination?: string; request: ReceiptRequest; dataRefs: ReceiptDataRef[]; policy: ReceiptPolicy; flags: string[]; masking: ReceiptMasking; /** * The exact text sent to the client (MCP `content[0].text`). The raw * result is not written on the receipt — only hash and byte count. Do not * supply it on the deny/error path; even if supplied it is ignored (no * invention, `undeclared`). */ disclosurePayload?: string; outcome: ReceiptOutcome; } export interface ChainState { seq: number; prevHash: string; } export declare const RECEIPT_GENESIS_HASH = "sha256:0000000000000000000000000000000000000000000000000000000000000000"; /** Crockford Base32 ULID (26 chars). No dependency. */ export declare function ulid(now?: number): string; /** * RFC 8785 JCS subset: sorted object keys, no whitespace, omit undefined. * Sufficient for Receipt JSON (no exotic numbers / bigint). */ export declare function canonicalize(obj: unknown): string; export declare function receiptHash(r: unknown): string; /** * Build a signed (or explicitly unsigned) receipt. * consentRef is always null — reserved for consent binding (ISO/IEC TS 27560), * which is NOT part of v0.2. Naming it "v0.2" was wrong once v0.2 shipped. * seq must be provided via chain and is written as-is (caller owns monotonicity). */ export declare function buildReceipt(input: ReceiptInput, chain: ChainState, key: SigningKey | null): Receipt; /** Hash a request args object without retaining raw content. */ export declare function hashArgs(args: unknown): string; /** * Disclosure commitment: SHA-256 of the exact UTF-8 bytes that left the * boundary. Same string → same hash in any process. Not JCS — the wire * bytes are the fact, not a re-canonicalised object. */ export declare function hashDisclosure(payload: string): { hash: string; bytes: number; }; export declare function nextChainState(prev: Receipt | null): ChainState; export type ReceiptChainCheck = { ok: true; entries: number; } | { ok: false; brokenAt: number; reason: string; entries: number; }; /** * Hash + prevHash + seq, same rules as `conarium-verify` on a single file. * `brokenAt` is 1-based index in the array (line N). Does not hide a break. */ export declare function verifyReceiptChain(receipts: unknown[]): ReceiptChainCheck; //# sourceMappingURL=receipt.d.ts.map