import type { OwnershipScope } from "./contracts.js"; /** * Durable artifact co-work review types (Phase 9 / 0.0.14). Core exports types only; * the service + delivery-link signer live in `@arnilo/prism-server`. Prism persists bounded * metadata, revisions, approvals, and delivery references — never file bodies (hosts own blobs). */ /** Review state of an artifact's latest revision. */ export type ArtifactApprovalState = "pending" | "approved" | "rejected"; /** A resolved decision on one revision (pending is the absence of a decision). */ export type ArtifactDecisionState = Exclude; /** Optional host semantic verdict. Never treated as citation integrity or proof. */ export type CitationSupport = "unverified" | "supported" | "unsupported" | "uncertain"; /** Bounded citation / data-source reference. Host resolves the body; Prism stores the ref only. */ export interface ArtifactCitation { readonly uri: string; readonly title?: string; /** Data-source kind (e.g. "web", "database", "upload", "rag"); host-defined, bounded. */ readonly kind?: string; readonly sourceId?: string; readonly revision?: string; /** SHA-256 hex of the retrieved source snapshot (optional `sha256:` prefix). */ readonly contentHash?: string; readonly retrievedAt?: string; readonly excerpt?: string; readonly span?: { readonly start: number; readonly end: number; }; readonly tenantId?: string; readonly support?: CitationSupport; } /** One immutable revision of an artifact. `uri`/`hash` reference host-owned content. */ export interface ArtifactRevision { /** 1-based, monotonic within the artifact. */ readonly version: number; /** Host-owned blob reference (redacted; never a local filesystem path). */ readonly uri: string; readonly mime: string; /** Host-computed content hash for integrity compare. */ readonly hash: string; /** Expected body byte length; required when a blob store is wired for delivery. */ readonly size?: number; readonly changeNote?: string; /** Run that produced this revision, if any. */ readonly producerRunId?: string; readonly citations?: readonly ArtifactCitation[]; /** Preview metadata only; the host renders content. */ readonly preview?: Readonly>; readonly createdAt: string; } /** A reviewer decision on a specific revision. */ export interface ArtifactApproval { readonly version: number; readonly state: ArtifactDecisionState; /** Redacted reviewer actor reference. */ readonly reviewer: string; /** Change-request / rejection note. */ readonly note?: string; readonly decidedAt: string; /** SHA-256 of bound citation sourceId/revision/contentHash tuples at decision time. */ readonly evidenceDigest?: string; } /** * Durable artifact record. Stored as a versioned checkpoint value; the checkpoint version * is the CAS counter for concurrent reviewers, distinct from revision numbers. */ export interface ArtifactRecord extends OwnershipScope { readonly id: string; readonly threadId: string; readonly title?: string; readonly revisions: readonly ArtifactRevision[]; readonly approvals: readonly ArtifactApproval[]; /** Last approved revision; remains recoverable after a later rejection. */ readonly lastValidatedVersion?: number; readonly createdAt: string; readonly updatedAt: string; } /** Signed, expiring delivery authorization. Reauthorized per download; never a bearer secret. */ export interface ArtifactDeliveryToken extends OwnershipScope { readonly artifactId: string; readonly threadId: string; readonly version: number; readonly issuedAt: string; readonly expiresAt: string; } /** * Opaque, ownership-scoped reference to one artifact body revision. The store derives its * internal object key from these fields; hosts never see or store bucket/path/key internals. * `size` is the expected byte length and `hash` the expected SHA-256 hex; both are verified * on every put/get (fail closed on mismatch). */ export interface ArtifactBodyRef extends OwnershipScope { readonly artifactId: string; readonly threadId: string; readonly version: number; readonly mime: string; /** Expected body byte length; verified against the actual body on put and get. */ readonly size: number; /** Expected SHA-256 hex digest of the body; verified on put and get. */ readonly hash: string; } /** Transfer options shared by put/get/delete. */ export interface ArtifactBodyTransferOptions { readonly signal?: AbortSignal; } /** Presign options: bounded TTL for the returned delivery URL. */ export interface ArtifactBodyPresignOptions extends ArtifactBodyTransferOptions { /** Bounded by the store's presignTtlMs cap; defaults to the store default. */ readonly ttlMs?: number; } /** * Host-owned blob storage contract (Phase 11 / 0.0.28). Core exports the contract only; * the reference S3-compatible adapter lives in `@arnilo/prism-server/artifact-bodies`. * Implementations must verify ownership on every operation, verify hash/size/MIME on * put/get (fail closed), refuse delete under legal hold, and never disclose bucket/path/key * in errors, telemetry, or records. All failures surface typed errors, never silent success. */ export interface ArtifactBodyStore { /** Store a body; verifies size + SHA-256 hash against the ref before persisting. */ put(ref: ArtifactBodyRef, body: Uint8Array | ReadableStream, options?: ArtifactBodyTransferOptions): Promise; /** Retrieve a body; verifies size, MIME, and SHA-256 hash before returning bytes. */ get(ref: ArtifactBodyRef, options?: ArtifactBodyTransferOptions): Promise>; /** Delete a body; idempotent. Refuses while the resource is under legal hold. */ delete(ref: ArtifactBodyRef, options?: ArtifactBodyTransferOptions): Promise; /** Return a bounded-TTL, single-object delivery URL (never a bucket listing or wildcard). */ presign(ref: ArtifactBodyRef, options?: ArtifactBodyPresignOptions): Promise; } /** Frozen ArtifactBodyStore failure reasons (fail-closed posture). */ export type ArtifactBodyErrorCode = "OWNERSHIP" | "HASH_MISMATCH" | "SIZE_MISMATCH" | "MIME_MISMATCH" | "HELD" | "STORE"; /** Well-known error codes for ArtifactBodyStore failures. */ export declare const ARTIFACT_BODY_ERROR_CODES: Readonly>; /** Typed ArtifactBodyStore failure; `code` is one of the frozen ERR_PRISM_ARTIFACT_BODY_* codes. */ export declare class ArtifactBodyStoreError extends Error { readonly reason: ArtifactBodyErrorCode; readonly code: `ERR_PRISM_ARTIFACT_BODY_${ArtifactBodyErrorCode}`; constructor(message: string, reason: ArtifactBodyErrorCode); } /** Well-known checkpoint namespace for artifact records. */ export declare const ARTIFACT_CHECKPOINT_NAMESPACE = "prism.artifact"; export declare class ArtifactError extends Error { readonly reason: string; readonly code = "ERR_PRISM_ARTIFACT"; constructor(message: string, reason: string); } /** Checkpoint key for an artifact: thread-scoped so per-thread listing uses a key prefix. */ export declare function artifactCheckpointKey(threadId: string, artifactId: string): string; /** Current review state: the decision on the latest revision, or pending when undecided. */ export declare function artifactApprovalState(record: ArtifactRecord): ArtifactApprovalState; export declare const HARD_CITATION_EXCERPT_BYTES = 8192; export type CitationIntegrityReason = "ok" | "missing_source" | "hash_mismatch" | "span_mismatch" | "revoked_acl" | "revision_changed" | "excerpt_too_large" | "cross_tenant"; export interface CitationLiveSource { readonly contentHash: string; readonly revision: string; readonly body?: string; readonly tenantId?: string; readonly authorized?: boolean; } export interface CitationIntegrityResult { readonly ok: boolean; readonly reason: CitationIntegrityReason; } /** Deterministic source existence / hash / span / ACL check. Ignores `support`. */ export declare function checkCitationIntegrity(citation: ArtifactCitation, live?: CitationLiveSource, options?: { readonly boundRevision?: string; readonly maxExcerptBytes?: number; }): CitationIntegrityResult; /** Stable digest of citation identity tuples. Source body changes after approval fail this digest only when citations themselves change; live hash is `checkCitationIntegrity`. */ export declare function citationBindingDigest(citations: readonly ArtifactCitation[] | undefined): string; /** True when the approval digest still matches the revision and (if given) live sources pass integrity. */ export declare function approvalEvidenceIntact(approval: ArtifactApproval, revision: ArtifactRevision, liveSources?: Readonly>): CitationIntegrityResult;