/**
 * artifacts/types — the claim-check shapes and the five-verb port.
 *
 * A tool stores its result under a REFERENCE and hands the model a claim
 * ticket; the model routes tickets instead of hauling data. These are the
 * shapes that make that sentence true: the ref (an opaque minted string),
 * the metadata a consumer decides from (never the bytes), and the store
 * port every backend implements.
 *
 * ── The constitution this port inherits (from `MemoryStore`) ────────────────
 *   1. **Scope is always the first argument.** Every call takes an
 *      {@link ArtifactScope} — the same tenant/principal/conversation tuple
 *      memory scopes on — so stores enforce isolation at the boundary. A ref
 *      alone opens NOTHING; a wrong scope surfaces as "no data", never as a
 *      cross-tenant read.
 *   2. **`get` returns `null` for missing OR expired.** Deliberate ambiguity:
 *      "no data" is the only actionable fact, and distinguishing the two would
 *      let a caller reason about another scope's contents.
 *   3. **Reads return cursors, not unbounded arrays.** `list` pages.
 *   4. **Methods return Promises uniformly**, so sync adapters can become
 *      async ones without breaking a caller.
 *
 * ── Five verbs, no more ─────────────────────────────────────────────────────
 * `put · head · get · delete · list`. The moment this port grows `query()` or
 * `transform()` we are building a database — compute belongs to the code leg,
 * and that refusal is written here so a future round can be refused by
 * citation.
 *
 * `head` earns its place because it IS the render-by-ref decision: a consumer
 * picks what to do from `kind` and `bytes` without paying for the payload.
 *
 * ── …and two OPTIONAL ones (9.25.0) ─────────────────────────────────────────
 * `putStream?` / `getStream?` are feature-detected members, not a sixth and
 * seventh verb: a store that cannot move a payload without holding it whole
 * LEAVES THEM ABSENT, and a consumer that calls one it did not detect gets a
 * type error rather than a runtime surprise. An adapter must never fake a
 * stream over bytes it already holds — a fake stream is an accepted-and-
 * silently-wrong promise about memory. See {@link ArtifactStreamPutInput} for
 * the two things streaming costs you (a stated `bytes`, and no digest).
 */
import type { MemoryIdentity } from '../memory/identity/types.js';
import type { DatasetTimeAxis } from '../time/axis.js';
/**
 * The isolation tuple every artifact call presents — the SAME tuple memory
 * scopes on (`{ tenant?, principal?, conversationId }`), under a name that
 * says what it does here. One type, not a structural twin: two spellings of
 * one scoping rule could disagree, and this one cannot.
 *
 * The framework composes it from the run's identity/session (an anonymous run
 * scopes to its own runId; a session-bound run to its sessionId; an
 * identity-carrying run to the caller's tenant/principal tuple). A tool never
 * supplies it — `ctx.artifacts` is already bound.
 */
export type ArtifactScope = MemoryIdentity;
/**
 * The ref the model speaks — an opaque MINTED string (`art_` + 22 random
 * chars, ~26 total). Never content-addressed: the digest is metadata, never
 * the key (content-as-key would collide two tenants' identical bytes into one
 * object and could never name two generations of "the current dataset").
 * The grammar has ONE owner: `naming.ts`.
 */
export type ArtifactRef = string;
/** Where an artifact came from — the join to the trace. Facts, never invented:
 *  absent fields mean the minting door genuinely did not have them. */
export interface ArtifactOrigin {
    readonly runId?: string;
    readonly toolCallId?: string;
}
/**
 * The claim ticket's description — what a consumer needs to DECIDE, never the
 * bytes. This is what `head` returns, what `list` rows are, and what every
 * `artifacts.*` event carries (events never carry payloads).
 */
export interface ArtifactMeta {
    readonly ref: ArtifactRef;
    /** Consumer vocabulary — what this IS to whoever redeems it:
     *  `'dataset/rows'`, `'chart/spec'`, `'report/csv'`. Declared by the
     *  producer, never inferred. */
    readonly kind: string;
    /** MIME type of the payload: `'application/json'`, `'text/csv'`, … */
    readonly mediaType: string;
    /** Payload size in bytes (UTF-8 for text/JSON, byteLength for binary). */
    readonly bytes: number;
    /** The human name: `"Q3 sales by region"`. */
    readonly label?: string;
    /** `sha-256:<hex>` — integrity + idempotent re-put detection, computed at
     *  `put` when asked. Metadata, NEVER the key. Verified on `get`; a mismatch
     *  is a teaching refusal, never silent corruption. */
    readonly digest?: string;
    /** Unix ms when this artifact stops resolving — STATED at mint (from the
     *  store's ttl or the caller's own value, whichever is sooner), so consumers
     *  can reason about expiry instead of discovering it. Absent = no expiry. */
    readonly expiresAt?: number;
    /** The join to the causal record. */
    readonly origin?: ArtifactOrigin;
    /**
     * Derivation FACTS — the refs this artifact was computed from. Validated at
     * mint: naming a parent that does not resolve in the same scope is a
     * refusal (a foreign key that cannot dangle at birth). Deliberately NOT a
     * lineage-graph engine: walking parents is the consumer's fold over
     * `head()`, and causation stays the trace's job.
     */
    readonly parentRefs?: readonly ArtifactRef[];
    /** The rows' TIME AXIS as the producer declared it — which column is time,
     *  how its values are written, and how each row summarises its interval.
     *  Validated at mint (a malformed one is refused, never repaired); absent =
     *  undeclared, and a consumer keeps its own heuristic. See `time/axis.ts`. */
    readonly timeAxis?: DatasetTimeAxis;
    /** Unix ms when the artifact was stored. */
    readonly createdAt: number;
}
/** What `put` takes — everything on {@link ArtifactMeta} the CALLER owns.
 *  `ref`, `bytes`, `digest` and `createdAt` are the store's to stamp. */
export interface PutArtifactInput {
    readonly kind: string;
    readonly mediaType: string;
    /**
     * The payload. Strings and `Uint8Array` are stored byte-for-byte; any other
     * value must be JSON-serializable (it is measured, digested and — in the
     * durable adapters — persisted via JSON). A value JSON cannot carry is
     * refused at `put` by name, never stored as an approximation.
     */
    readonly data: unknown;
    readonly label?: string;
    /** Ask for an integrity digest, computed by the store at put. */
    readonly digest?: 'sha-256';
    /** Caller-stated expiry (unix ms). The store's own ttl may only TIGHTEN it. */
    readonly expiresAt?: number;
    readonly origin?: ArtifactOrigin;
    readonly parentRefs?: readonly ArtifactRef[];
    /** Declare the rows' time axis (see {@link ArtifactMeta.timeAxis}). */
    readonly timeAxis?: DatasetTimeAxis;
}
/** Why an artifact left the store without its owner asking. */
export type ArtifactSweepReason = 'ttl' | 'max-bytes' | 'max-count';
/** One swept artifact — the fact a retention pass leaves behind. */
export interface SweptArtifact {
    readonly ref: ArtifactRef;
    readonly reason: ArtifactSweepReason;
    readonly kind: string;
    readonly bytes: number;
}
/**
 * What `put` hands back: the ticket, plus everything retention swept to admit
 * it. Sweeps ride the RESULT (collect during traversal, never post-process) so
 * the capability layer can put each one on the record as it happens — a store
 * that evicted silently would be a store that lies by omission.
 */
export interface ArtifactPutResult {
    readonly meta: ArtifactMeta;
    readonly swept: readonly SweptArtifact[];
}
/** What `get` returns when the ref resolves: the ticket and the payload. */
export interface ArtifactRecord {
    readonly meta: ArtifactMeta;
    readonly data: unknown;
}
/** Options for `list` — the cursor convention `MemoryStore.list` set. */
export interface ArtifactListOptions {
    /** Continuation token from a previous page. Omit for the first page. */
    readonly cursor?: string;
    /** Maximum rows this page. Adapters may cap it lower. */
    readonly limit?: number;
}
/** One page of tickets. Bytes never ride a listing. */
export interface ArtifactListResult {
    readonly artifacts: readonly ArtifactMeta[];
    /** Present iff more pages exist. */
    readonly cursor?: string;
}
/**
 * What a STREAMED put declares. Everything on {@link PutArtifactInput} the
 * caller owns, minus the two things a store cannot honor without holding the
 * payload whole:
 *
 *   • **`bytes` is REQUIRED here** (it is stamped, not measured). Retention
 *     has to plan an eviction BEFORE the bytes arrive, and an object store
 *     has to declare a content length before it opens the upload — neither
 *     can wait for a stream to end. A store that can see the true count
 *     verifies it and refuses a mismatch by name rather than storing a meta
 *     that lies about its own payload.
 *   • **there is no `digest`.** A digest is computed over the whole canonical
 *     payload with the same primitive every adapter shares; a store that
 *     never holds the payload cannot produce one, and an incremental hash
 *     computed a second way would be a different promise wearing the same
 *     field name. Digest the source yourself, or use `put`.
 */
export interface ArtifactStreamPutInput {
    readonly kind: string;
    readonly mediaType: string;
    /** The payload's exact byte length — stated by the producer, not measured. */
    readonly bytes: number;
    readonly label?: string;
    /** Caller-stated expiry (unix ms). The store's own ttl may only TIGHTEN it. */
    readonly expiresAt?: number;
    readonly origin?: ArtifactOrigin;
    readonly parentRefs?: readonly ArtifactRef[];
}
/** What `getStream` returns when the ref resolves: the ticket, and the
 *  payload's CANONICAL BYTES as a stream — the same bytes `meta.bytes` counts
 *  and a digest would cover, never a re-encoding.
 *
 *  `meta.digest` (when the artifact carries one) describes these bytes but has
 *  NOT been checked against them: verification needs the whole payload, which
 *  is what this shape exists to avoid holding. It rides anyway so a caller who
 *  needs the guarantee can hash what it collected and compare — the loss is
 *  named, never silently traded. `get` remains the verifying read. */
export interface ArtifactStreamRecord {
    readonly meta: ArtifactMeta;
    readonly body: ReadableStream<Uint8Array>;
}
/**
 * The port — five verbs, scope first, vendor-neutral, plus two optional
 * streaming members. Adapters are the vendor layer; every backend
 * (in-process, on-disk, embedded database, remote object storage) implements
 * exactly this.
 */
export interface ArtifactStore {
    /**
     * Store a payload; mint and return the ticket. Validates the input (a
     * malformed put is refused by name), validates `parentRefs` resolve in the
     * SAME scope, measures, optionally digests, stamps `expiresAt` from the
     * store's retention — and reports what retention swept to make room.
     */
    put(scope: ArtifactScope, input: PutArtifactInput): Promise<ArtifactPutResult>;
    /**
     * The ticket without the payload — the render-by-ref decision. `null` for
     * missing-or-expired (the deliberate ambiguity; both mean "no data").
     */
    head(scope: ArtifactScope, ref: ArtifactRef): Promise<ArtifactMeta | null>;
    /**
     * The ticket and the payload. `null` for missing-or-expired. When the meta
     * carries a `digest`, the payload is re-verified here — a mismatch throws
     * {@link ArtifactIntegrityError}, never returns corrupt bytes as if whole.
     */
    get(scope: ArtifactScope, ref: ArtifactRef): Promise<ArtifactRecord | null>;
    /** Remove one artifact. No-op when it does not exist — deleting an absence
     *  is not an error, it is agreement. */
    delete(scope: ArtifactScope, ref: ArtifactRef): Promise<void>;
    /** Page through this scope's tickets, newest first. */
    list(scope: ArtifactScope, options?: ArtifactListOptions): Promise<ArtifactListResult>;
    /**
     * OPTIONAL — store a payload the caller streams, without either side
     * holding it whole. Absent on stores that cannot honor that promise; detect
     * with `canPutArtifactStream(store)` before calling.
     *
     * The stream is consumed exactly once. Everything else is `put`'s law:
     * `parentRefs` are proven first, retention plans against the DECLARED
     * `bytes`, and the sweep rides the result.
     */
    putStream?(scope: ArtifactScope, input: ArtifactStreamPutInput, body: ReadableStream<Uint8Array>): Promise<ArtifactPutResult>;
    /**
     * OPTIONAL — read a payload as a stream of its canonical bytes. `null` for
     * missing-or-expired, exactly like `get`. Absent on stores that would have
     * to read the payload whole to answer; detect with
     * `canGetArtifactStream(store)`.
     *
     * A `digest` on the meta is NOT re-verified here — verification needs the
     * whole payload, which is the thing this member exists to avoid. `get`
     * remains the verifying read, and the difference is stated rather than
     * silently traded.
     */
    getStream?(scope: ArtifactScope, ref: ArtifactRef): Promise<ArtifactStreamRecord | null>;
}
/**
 * A `put` named a parent that does not resolve in the same scope — a foreign
 * key that would dangle at birth. Refused at mint, because a derivation fact
 * that points at nothing is worse than no fact: every later consumer would
 * inherit the lie.
 */
export declare class UnknownParentRefError extends Error {
    readonly code: "ERR_UNKNOWN_PARENT_REF";
    /** The parents that failed to resolve. */
    readonly unresolved: readonly ArtifactRef[];
    constructor(unresolved: readonly ArtifactRef[]);
}
/**
 * A stored payload no longer matches the digest minted with it. Thrown by
 * `get` instead of returning the bytes — corrupt data delivered as whole data
 * is the accepted-and-silently-wrong failure, and the one thing a claim check
 * must never do is honor a ticket with someone else's parcel.
 */
export declare class ArtifactIntegrityError extends Error {
    readonly code: "ERR_ARTIFACT_INTEGRITY";
    readonly ref: ArtifactRef;
    /** The digest minted at put. */
    readonly expected: string;
    /** The digest of what the store actually holds now. */
    readonly actual: string;
    constructor(ref: ArtifactRef, expected: string, actual: string);
}
/**
 * A `put` this store cannot honor as stated — a payload JSON cannot carry, a
 * blank `kind`, a payload larger than the whole scope budget. Refused by name
 * at the door: storing an approximation would be accepted-and-silently-wrong.
 */
export declare class InvalidArtifactError extends Error {
    readonly code: "ERR_INVALID_ARTIFACT";
    constructor(detail: string);
}
