/** * Resolve a claim's support back to the events it came from. * * This is the capability the whole "traceable judgment" idea rests on, and until now it * did not exist in any form the agent could reach. Memory records carried model run, * envelope, gateway call and source refs; recall stripped every one of them, so an agent * could read a memory and then had no way to say which memory a statement rested on. A * handle was added upstream; this turns the handle into an answer. * * Two rules shape everything here. * * POSSESSION IS NOT AUTHORIZATION. Holding a memory id proves only that recall returned * it once, under some scope, at some time. Every event is re-checked against the scope * active NOW, and content is withheld when that check fails. A resolver that trusted the * handle would turn recall into a capability leak: read once, cite forever. * * ABSENCE GETS A REASON. Silence is what made the original problem invisible - a report * asserted things with nothing behind them and looked identical to one that was * grounded. Every failure here names itself, so "I cannot support this" is a statement * the agent can make instead of a gap it cannot see. */ /** Why a claim, or one of its supports, could not be resolved. */ export type ResolutionFailure = /** The memory carries no source refs at all. */ 'missing_ref' /** Provenance exists but predates scoped writes - nothing to re-check against. */ | 'legacy_unscoped' /** The referenced event is no longer in the index. */ | 'event_deleted' /** The event exists but is not visible under the scope active now. */ | 'outside_scope' /** The ref shape is not one this resolver knows how to dereference. */ | 'unsupported_ref' /** * The claim records provenance, but none of it points at an observed event. * Measured, not hypothetical: of the source refs stored on this machine, 13,403 are * `memory:`, 1,748 are `envelope:`, 9 are `message:` and ZERO are `raw:`. Folding this * into `unsupported_ref` would have reported a parser limitation where the real answer * is that the claim rests on other claims rather than on anything observed. */ | 'no_event_refs' /** No memory with that id. */ | 'unknown_memory'; export interface ResolvedEvent { connector: string; eventIndexId: string; sourceId: string; channel: string | null; observedAt: string | null; /** Bounded excerpt. Never the whole record: this answers "where from", not "give me". */ excerpt: string; } /** * One support that could not be dereferenced, and why. * * `kind` exists because the other two fields collapse three different situations into * one shape: an unparseable ref, a withheld observation, and a withheld claim all render * as roughly `{null, reason}`. "A supporting observation was withheld" and "a supporting * claim was withheld" are different statements about grounding, and an agent that cannot * tell them apart cannot make either one. */ export interface UnresolvedSupport { kind: 'event' | 'memory' | 'message' | 'unknown'; /** Present only for events. A memory id is withheld deliberately - see below. */ eventIndexId: string | null; reason: ResolutionFailure; } /** * Provenance that was recorded but does not point at an observed event: the memory a * claim was built from, the envelope that authorized the write, the message that * prompted it. Reported rather than discarded - "this rests on three earlier memories * and no observation" is a true and useful answer, and it is the answer for almost * every memory that exists today. */ export interface RecordedSupport { kind: 'memory' | 'envelope' | 'message'; id: string; } /** A parsed source ref. `raw` is the only kind this resolver dereferences to an event. */ export type ParsedSourceRef = { kind: 'raw'; connector: string; eventIndexId: string; } | RecordedSupport | { kind: 'unsupported'; }; export interface ProvenanceResolution { memoryId: string; /** * The stored record's own status, and whether the system has retired it. * * Carried because every read path filters these out and this one did not: 65% of the * live corpus is `superseded`, and without this the tool would report `resolved` for a * retired claim in output identical to a current one. Grounding a statement in a record * the system has explicitly replaced, confidently and invisibly, is the failure this * whole tool exists to prevent. */ memoryStatus: string | null; retired: boolean; /** * `resolved` - every support dereferenced and visible. * `partial` - at least one resolved, at least one not. * `unresolved` - nothing could be shown, and `reason` says why. */ status: 'resolved' | 'partial' | 'unresolved'; modelRunId: string | null; contextPacketId: string | null; events: ResolvedEvent[]; unresolved: UnresolvedSupport[]; /** Recorded provenance that is not an observed event. Never a failure. */ supports: RecordedSupport[]; /** Present only when nothing resolved, so a caller never has to infer the cause. */ reason?: ResolutionFailure; } /** A memory's recorded provenance, reduced to what resolution needs. */ export interface MemoryProvenanceRecord { /** Raw status column, e.g. `active`, `superseded`. */ status?: string | null; /** True when the reader's status filter, or a supersede link, would exclude it. */ retired?: boolean; modelRunId: string | null; contextPacketId: string | null; /** Canonical source refs; empty when the write was not evidence-backed. */ sourceRefs: ReadonlyArray; /** True when the record predates scoped provenance and cannot be re-checked. */ legacyUnscoped?: boolean; } export interface IndexedEvent { connector: string; eventIndexId: string; sourceId: string; channel: string | null; observedAt: string | null; content: string; /** * The scope recorded on the event, or null when it was indexed before scoped * indexing existed. Carried on the event so visibility is a pure function of it - * a caller cannot re-check what it was not given. */ memoryScope?: { kind: string; id: string; } | null; /** Project and tenant the event was indexed under; null when it carries neither. */ projectId?: string | null; tenantId?: string | null; } export interface ProvenanceResolverDeps { lookupMemoryProvenance(memoryId: string): MemoryProvenanceRecord | null; lookupEvent(connector: string, eventIndexId: string): IndexedEvent | null; /** * Whether this event is visible under the scope active NOW - not the scope that was * active when the memory was written. This is the check that keeps a handle from * becoming a standing capability. */ isVisible(event: IndexedEvent): boolean; /** * Whether a recorded support may be named under the authority active now. * * Applies to every non-event support, not just memories. The first version checked * nothing here and the second checked only `memory:`, which left `message:` refs - * built as `source:channelId:turnId` - handing a channel identifier to any caller that * could read the memory. Naming a support is disclosure whatever its kind. * * Optional so the pure module stays usable without a store; when absent, supports are * withheld rather than assumed visible. A check that fails open is not a check. */ isSupportVisible?(support: RecordedSupport): boolean; /** * Redaction applied to an excerpt before it leaves. Recall runs its text through a * pattern list (URLs, emails, tokens, key shapes, raw refs); an excerpt path that * skipped it would send connector content out through a surface whose sibling scrubs * it. Optional, and identity when absent - the pure module holds no pattern list. */ redact?(text: string): string; /** Excerpt bound in characters. */ excerptChars?: number; } /** * Resolve one memory's support. Never throws for missing or invisible evidence - those * are answers, not errors, and an agent needs to be able to report them. */ export declare function resolveMemoryProvenance(memoryId: string, deps: ProvenanceResolverDeps): ProvenanceResolution; //# sourceMappingURL=provenance-resolver.d.ts.map