/** * Associating one document execution with a workflow run. * * An installation is a value, not an installation act. It creates no workflow * run: a run comes into being when a document execution reaches its first * durable operation, which allocates the run once, records one immutable value, * and only then lets the root document be imported. * * What a run *is* belongs to the host that states it. `@executablemd/git` * supplies one that resolves a base through Git; a workflow host supplies one * for a run its storage already created. Both arrive as a * `WorkflowRunPreparation`, and everything below holds either of them to the * same journal on the same terms. * * A journal can be in three states, and two of them are held to the run. * * - **Live** — no record yet. The installation's `prepare` hook asks the * preparation to allocate, and records the value — inside the durable root, * before any public document policy and before the root is imported. * - **Truncated** — the record is there but the root never closed. The durable * operation replays the stored value, so the preparation is not asked to * allocate a second time, and the journal cursor still advances past its own * entry. * - **Completed** — the root `Close` is recorded, and `durableRun` returns the * stored result without entering the durable body at all, so preparation is * never reached and the admission is what restores the run. * * `retainedWorkflowInstallation(run)` is the same three states under a run that already * exists. A workflow host has created the storage record before anything * executes, so the live path records exactly the value it was given rather than * allocating an id and resolving a base, and every state requires the journal to * agree with that value in full. * * ## Where identity is decided * * In no middleware at all. `ReplayGuard` is composable policy — a handler * installed further out may decline to call `next` — and so is `Execution`: a * handler registered at the same position can rebuild the options a later one * produced, stream included. A journal held to its run from either place would * be held to it by registration order. * * So this is an *installation* the trusted host hands to `executeInstalled()`, * and core owns the read. The admission is captured before any installation, * middleware or document code exists, and applied inside the same trusted * `readAll` that already holds a resumed run to its recorded root selection. That read happens before any middleware runs, on the retained * snapshot every later phase consumes — ahead of public guard policy, of any * retained Yield reaching execution, of a retained `Close` being reused, of * authored work, and of any append. Public `ReplayGuard` handlers still observe * and may still reject the history this admits; none of them can widen it. * * The two installations differ in what they require, not in how strictly it is * enforced. A base that would not resolve is recorded as a failed effect (§6), * so a programmatic run replays that failure rather than demanding a successful * record it never wrote. * * All of it is operation-scoped. The value is installed in the scope that owns * the document execution, so every descendant of the expansion reads it, the * output emitted after the durable run still sees it, and ordinary teardown * takes it away. Nothing lives at module scope. */ import type { Operation } from "effection"; import type { EffectDescription } from "@executablemd/durable-streams"; import type { ExecutionInstallation } from "@executablemd/core/host"; import type { WorkflowRun } from "./journal.js"; export type { WorkflowRun } from "./journal.js"; /** The frozen run of the current document execution; throws outside one. */ export declare function getWorkflowRun(): Operation; /** * How one installation decides what the run is, and what the journal is held to. * * Two hosts need different answers to both questions. A caller that resolves a * base lets the first live execution allocate an id and resolve that base, so * the only thing a record can disagree about is the base it was made from. A * workflow host has already created the storage record, so the run is not the * execution's to allocate: it arrives whole, and a journal that records a * different one is not this run's journal. * * Both answers are the host's, and neither is this package's to invent. What * stays here is everything underneath them: the installation slot, when root * admission happens, the durable record's parser, and where the current run is * published. A host that resolves a repository supplies the resolution; it does * not supply the journal. */ export interface WorkflowRunPreparation { /** * How the durable record identifies itself. * * Carried rather than derived from a base, because a version-2 run has none: * its description says which version it is and what bundle it retains. */ readonly description: EffectDescription; /** Whether a non-empty history must carry a successful record. */ readonly required: boolean; /** The recorded run, or a refusal naming what it disagrees about. */ agree(recorded: WorkflowRun): WorkflowRun; /** The run this execution is of, reached only when nothing is recorded yet. */ allocate(): Operation; } /** * What a trusted host attaches to one execution to make it this run's. * * An installation rather than something installed into an ambient scope: the * admission is a value the host hands to `executeInstalled()`, so canonical * core captures it before any middleware or document code exists, and a second * loaded copy of this package composes by handing over its own closure rather * than by agreeing on a name. * * The preparation is the host's half and the only half. Everything the run is * held to — the admission captured before any installation, the durable record * inside the root, the parser that reads it back, the slot the execution * publishes into — stays here, so a host that decides what its run is decides * nothing about when or how strictly that decision is enforced. */ export declare function createWorkflowRunInstallation(preparation: WorkflowRunPreparation): ExecutionInstallation; /** * Associate the document execution this scope owns with a run that already * exists. * * A workflow host creates the run's storage record before it executes anything, * so by the time a document runs there is nothing left to allocate or resolve: * the run id is the one storage answered with, and the pinned commit is the one * the definition was established from. This installation records exactly that * value and requires a journal to agree with it in every field, so a resumed * execution can never continue under a run the storage record does not describe. * * Git is not consulted, and no identifier is generated. */ export declare function retainedWorkflowInstallation(run: WorkflowRun): ExecutionInstallation;