/** * artifacts/retention — the one owner of the eviction law. * * Three adapters, one rule for what leaves a scope and why. Each adapter * supplies its rows; this module decides — a pure plan over plain facts, so * the law is testable without a store and cannot fork into three dialects. * * The policy is three independent dials, all per scope: * • `ttlMs` — every artifact gets `expiresAt = createdAt + ttl` * stamped AT MINT (expiry is stated, never sprung), * and expired rows are swept when the scope is next * touched by a put. * • `maxBytesPerScope`— a byte budget; least-recently-ACCESSED leaves first * (an artifact under active render must not be the * next one evicted — the innerRunRecords recency law). * • `maxCountPerScope`— a row budget, same eviction order. * * Every eviction is a FACT the plan returns ({@link SweptArtifact}), because * the put that triggered it reports them upward and the capability layer puts * each one on the record. A store that made room silently would be lying by * omission. * * A payload bigger than the whole byte budget is REFUSED at the door (the * plan says so; the adapter throws by name) — evicting an entire scope to * admit one oversized object would trade everything for something that may * itself not fit. */ import type { SweptArtifact } from './types.js'; /** The three dials. All optional; absent means that dial does not bind. */ export interface ArtifactRetention { /** Lifetime stamped onto every mint as `expiresAt` (unix ms after createdAt). */ readonly ttlMs?: number; /** Byte budget per scope. */ readonly maxBytesPerScope?: number; /** Row budget per scope. */ readonly maxCountPerScope?: number; } /** The facts the planner needs about one held artifact. */ export interface RetainedRow { readonly ref: string; readonly kind: string; readonly bytes: number; readonly expiresAt?: number; /** Recency — refreshed by get/head, so eviction spares what is in use. */ readonly lastAccessedAt: number; } /** What a put must do to the scope before it may admit the incoming bytes. */ export interface RetentionPlan { /** Rows to remove, in order, each with its reason. */ readonly swept: readonly SweptArtifact[]; /** When defined, the put must be REFUSED with this sentence instead. */ readonly refusal?: string; } /** * Validate a retention policy at construction — a dial that cannot bind * (zero, negative, NaN) is refused where it was written, not discovered as * an always-empty store at the first put. */ export declare function assertRetention(adapter: string, retention: ArtifactRetention | undefined): void; /** * Plan what must leave a scope so that `incomingBytes` may enter. * * Pure: reads rows, returns facts, mutates nothing. Rows may arrive in any * order; eviction order here is least-recently-accessed first. */ export declare function planRetention(rows: readonly RetainedRow[], incomingBytes: number, retention: ArtifactRetention | undefined, now: number): RetentionPlan; /** * The `expiresAt` a mint gets: the caller's own statement and the store's * ttl, whichever comes SOONER. A store may tighten a promise, never extend * one — extending would overrule the only party who knows the data. */ export declare function resolveExpiresAt(callerExpiresAt: number | undefined, retention: ArtifactRetention | undefined, now: number): number | undefined; //# sourceMappingURL=retention.d.ts.map