/** * Copyright (c) 2025 Elara AI Pty Ltd * Licensed under BSL 1.1. See LICENSE for details. */ /** * Record mutation execution — the write half of the function machinery. * * A mutation is a pure East reducer `(State, ...Args) => State` run via the * graph-free {@link runDetached} kernel in a compare-and-swap retry loop: * read state → reduce → write new state + commit objects → conditional ref * write; retry on conflict. A crash at any point leaves only unreferenced * objects (GC reclaims them) — never a torn record. The reducer's purity is * what makes re-running against fresher state safe. */ import { type EastTypeValue } from '@elaraai/east'; import { type RecordCommit } from '@elaraai/e3-types'; import type { StorageBackend, LockHandle } from './storage/interfaces.js'; import type { TaskRunner } from './execution/interfaces.js'; /** Mutations persist their (potentially large) new state, so the result cap is * far higher than the 1 MB inline-result default for function calls. */ export interface RecordMutateLimits { timeoutMs: number; maxResultBytes: number; maxLogBytes: number; } /** * The outcome of a mutation attempt. Only `committed` writes anything durable; * every other outcome leaves the repo byte-identical (bar unreferenced objects * GC reclaims). */ export type MutationOutcome = /** New state + commit written, record ref swung to the new commit. */ { kind: 'committed'; commitHash: string; stateHash: string; } /** Lookup/arity error — nothing ran. */ | { kind: 'invalid'; message: string; } /** The reducer process exited non-zero (incl. a reducer `$.error`). */ | { kind: 'failed'; exitCode: number; stderr: string; } /** The reducer exceeded its time budget. */ | { kind: 'timed_out'; ms: number; stderr: string; } /** The new state exceeded the result-size cap. */ | { kind: 'too_large'; bytes: number; limit: number; stderr: string; } /** The compare-and-swap lost the race `attempts` times. */ | { kind: 'conflict'; attempts: number; }; export interface RecordMutateOptions { /** Caller identity recorded on the commit (auth principal / `cli:`). */ actor: string; /** Execution limits; sensible record defaults applied when omitted. */ limits?: RecordMutateLimits; /** Wall-clock budget for CAS retries (default 30s); on expiry returns conflict. */ maxRetryMs?: number; /** Hard wall-clock budget for the WHOLE call (reducer runs included). When set, * the loop returns a typed `conflict`/`timed_out` before this deadline rather * than risking a caller's gateway timeout: each iteration is gated on the * deadline and each reducer run's `timeoutMs` is clamped to the time * remaining. Omit for the unbounded local behaviour. */ budgetMs?: number; /** Optional client idempotency key. When the record's last mutation carried * this same key, the reducer is NOT re-run and the prior commit is returned — * so a client retrying after a gateway timeout cannot double-apply. */ idempotencyKey?: string; /** Optional hard cap on CAS attempts (mainly for tests forcing a conflict). */ maxAttempts?: number; /** Cancellation — aborts the in-flight reducer execution (how is the runner's * concern: a local runner kills the process group, a remote one cancels the * invocation). */ signal?: AbortSignal; /** Externally-held shared workspace lock; acquired internally when omitted. */ lock?: LockHandle; /** Pass `-v` to the reducer's runner (known runtimes only) so it prints * timing/perf to stderr. Runtime-only; never affects hashing or caching. */ verbose?: boolean; } /** * Apply a named mutation to a record under optimistic concurrency. * * Resolves the mutation, then loops: read the current state + revision, run the * reducer against it, write the new state and a commit object, and conditionally * swing the record ref. On a concurrent commit the conditional write conflicts * and the loop retries against fresher state. Two mutations on the same record * serialize; mutations on different records never contend. */ export declare function recordMutate(storage: StorageBackend, runner: TaskRunner, repo: string, ws: string, recordName: string, mutationName: string, args: Uint8Array[], opts: RecordMutateOptions): Promise; /** A record's mutation surface: each mutation's name and EXTRA arg types. */ export interface RecordSignature { name: string; mutations: Array<{ name: string; argTypes: EastTypeValue[]; }>; } /** * Describe a record's mutations (name + extra arg types), so dynamic callers * can encode arguments. Returns null if the workspace has no such record. */ export declare function recordDescribe(storage: StorageBackend, repo: string, ws: string, recordName: string): Promise; /** * Compact a record's history: write a fresh `$compact` root commit * (`parent: none`) over the current state and swing the ref to it. The prior * commit chain becomes unreachable and is reclaimed by GC; the state itself is * unchanged. Returns `committed` / `invalid` / `conflict` like a mutation. */ export declare function recordCompact(storage: StorageBackend, repo: string, ws: string, recordName: string, opts: { actor: string; maxRetryMs?: number; maxAttempts?: number; lock?: LockHandle; }): Promise; /** A commit in a record's history, with its content hash. */ export interface RecordHistoryEntry { hash: string; commit: RecordCommit; } /** * Walk a record's commit chain newest-first. * * @param opts.limit - Maximum commits to return (default: the whole chain) * @param opts.from - Commit hash to start the walk at (a cursor for paging, * trusted to be a hash this endpoint previously returned for this record); * defaults to the record's head commit. A missing/undecodable cursor (or a * corrupt link mid-walk) terminates the walk rather than throwing. */ export declare function recordHistory(storage: StorageBackend, repo: string, ws: string, recordName: string, opts?: { limit?: number; from?: string; }): Promise; //# sourceMappingURL=records.d.ts.map