import type { TaskResult } from "./types.js"; /** * design/97 CORE-7 — one recorded `ctx.agent` result in a workflow's RESUME journal. Unlike the observation-only * {@link WorkflowRunStore} (best-effort, swallowed on throw), the journal is LOAD-BEARING: a resume replays the * longest unchanged PREFIX of these (keyed by the deterministic {@link workflowAgentCallKey}) and runs only the * first changed/new call + everything after it live. Same script + same args → 100% cache hit. */ export interface WorkflowJournalEntry { /** The agent's deterministic call key (`ordinal:specIdentityHash`) — the replay match key. */ callKey: string; /** The agent's TaskResult, replayed verbatim when a resume's call key matches at the same ordinal. */ result: TaskResult; } /** * The seam a resume reads/writes its journal through. Core ships {@link InMemoryWorkflowJournalStore}; a durable * deployment provides a Postgres-backed one (service SVC-2) so a workflow survives a replica crash. The owner of * a run is the sole writer of its journal. * * 🔐 `scope` (the TENANT/principal of the resuming run) is LOAD-BEARING for multi-tenant isolation (CORE-9 audit * BLOCKER): an LLM controls the `resumeFromRunId`, so `load` MUST be constrained to the caller's scope — exactly * as {@link WorkflowRunStore} puts scope in the WHERE of every method. A store implementation MUST return ONLY a * run's journal whose recorded scope equals the requested `scope` (a cross-scope `resumeFromRunId` resolves to an * EMPTY journal → the resume safely diverges to a live re-run, never disclosing another tenant's results). */ export interface WorkflowJournalStore { /** Entries for `runId` IF its recorded scope === `scope`, ASCENDING by ordinal; otherwise EMPTY (cross-scope). */ load(runId: string, scope: string): Promise; /** Record one agent's result under `(runId, scope)`. MUST be idempotent per `(runId, ordinal)` — a resumed run * re-appends the cached results of its replayed prefix, so a second append for the same ordinal overwrites. */ append(runId: string, scope: string, entry: WorkflowJournalEntry): Promise; } /** The ordinal a callKey (`ordinal:hash`) was minted at — the journal's positional index. The sole producer * ({@link workflowAgentCallKey}) always emits a well-formed `:`; a MALFORMED key (no leading int) * falls back to `0` rather than throwing — callers must not feed it arbitrary strings (audit note). */ export declare function callKeyOrdinal(callKey: string): number; /** In-process journal store (core default). A single-replica run; durable resume across crashes needs the * service's Postgres store (SVC-2). Records each run's `scope` and enforces it on load (CORE-9 audit BLOCKER: * a cross-scope resumeFromRunId resolves to an empty journal — no cross-tenant disclosure). */ export declare class InMemoryWorkflowJournalStore implements WorkflowJournalStore { private readonly runs; load(runId: string, scope: string): Promise; append(runId: string, scope: string, entry: WorkflowJournalEntry): Promise; } //# sourceMappingURL=workflow-journal-store.d.ts.map