/** * DiscreteStateTransition — the typed, attestation-checked authority record for a * discrete state crossing (#133). It REPLACES the dead-wrong * `discreteSignalPayloadsFromPatch`, which derived a runtime state VALUE from a * {@link SignalNode}'s content-address / axis. That was a category error: a * signal node's identity is not the runtime value the cell crossed to. * * A transition is a VALUE, never a closure: the crossing's next-state value * arrives IN the receipt payload (`next`/`generation`), minted by the authority * — nothing infers a value from patch ops. It reuses the ONE hash law * ({@link TypedRef.create} → {@link Receipt.createEnvelope} → sha256; Law 4), * mirroring {@link GraphPatch.receipt} byte-for-byte, so there is no second * hashing path. The subject law binds a receipt to exactly one `(base, cell)` * pair, so a receipt minted for `base#cellA` cannot be replayed against `cellB` * or another graph. * * Because a {@link DiscreteStateTransition} carries `kind: 'discrete'` BY * CONSTRUCTION and is only produced by the authority mint, there is no function * that turns a continuous cell / raw {@link SignalNode} into one — so "widen the * SSE replay payload with a signal" is UNCOMPILABLE (Law 16). See the * `@ts-expect-error` compile fixture in `state-transition.test.ts`. * * @module */ import { Effect } from 'effect'; import type { ContentAddress, HLC, StateName } from './brands.js'; import { type ReceiptEnvelope } from './receipt.js'; import { TypedRef } from './typed-ref.js'; import type { StateAuthority, StateCell, StateCellStoreShape } from './state-cell.js'; /** * A typed authority record for a single discrete state crossing. The * next-state VALUE lives in `next`/`generation` (minted by the authority), never * inferred from a graph node's content-address. `base`/`resultId` carry the * graph identity the crossing occurred against (and the recast result, when the * crossing recast the graph), so a composed chain can filter to the adopted * branch. `kind: 'discrete'` is the literal that makes the replay input * unrepresentable for continuous transients (Law 16). */ export interface DiscreteStateTransition { readonly _tag: 'DiscreteStateTransition'; readonly _version: 1; /** StateCellStore authority key (the cell name). */ readonly cell: string; /** Prior state when known (undefined at genesis). */ readonly previous?: StateName; /** Value-bearing next state — the crossing target. */ readonly next: StateName; /** Monotonic per-cell generation ({@link StateCell.generation}). */ readonly generation: number; /** Reuse the existing authority union. */ readonly authority: StateAuthority; /** Graph identity the crossing occurred against. */ readonly base: ContentAddress; /** Graph id after recast, when the crossing recast the graph. */ readonly resultId?: ContentAddress; /** Literal — the uncompilable-seam anchor. */ readonly kind: 'discrete'; } /** * The ONE `_version` this build's {@link DiscreteStateTransition} reader * understands. A transition stamped with a different `_version` is rejected * fail-closed by {@link decodeDiscreteStateTransition}. */ export declare const SUPPORTED_TRANSITION_VERSION: 1; /** * The receipt subject id for a transition — `${base}#${cell}`. The SINGLE source * of the subject law (Law 6): both the mint ({@link transitionReceipt}) and the * client-side attestation-check (`recordStreamPatchReceipt`) derive the expected * subject from HERE, so a receipt for `(base, cellA)` can never be replayed * against `cellB` or another graph. */ export declare function discreteTransitionSubjectId(transition: Pick): string; /** * The receipt PAYLOAD ref for a transition — a {@link TypedRef} over the crossing VALUE * (`cell`/`previous`/`next`/`generation`/`authority`/`base`/`resultId`/`kind`). The SINGLE * source of the payload law (Law 6): both the mint ({@link transitionReceipt}) AND the * client-side attestation-check (`recordStreamPatchReceipt`) derive the payload from HERE. * The subject law binds a receipt to a `(base, cell)` pair; THIS binds it to the exact * value, so a self-consistent receipt cannot be re-paired with a DIFFERENT `next`/ * `generation`/`resultId` on the same subject. */ export declare function discreteTransitionPayload(transition: DiscreteStateTransition): Effect.Effect; /** * Mint a receipt for a {@link DiscreteStateTransition}, mirroring * {@link GraphPatch.receipt} byte-for-byte: a single genesis-or-linked envelope * whose payload is a {@link TypedRef} over the transition, subject-keyed by the * `(base, cell)` law. Effect-returning because the receipt byte law hashes via * `crypto.subtle` (SHA-256) — the same async kernel `Receipt.createEnvelope` * rides on; folding it to a sync value would force a second, divergent hashing * path (Law 4). `timestamp`/`previous` default to a genesis stamp; pass them to * chain this transition onto a prior receipt. */ export declare function transitionReceipt(transition: DiscreteStateTransition, options?: { readonly timestamp?: HLC; readonly previous?: string | readonly string[]; }): Effect.Effect; /** * Companion mint the authority host calls AFTER a synchronous * {@link StateCellStoreShape.applyDiscrete} — builds the transition VALUE from * the crossing's `previous`/`next` cells plus the graph identity, then mints its * receipt via {@link transitionReceipt}. Kept separate so `applyDiscrete` stays * synchronous (no crypto in the hot path). */ export declare function mintTransition(previous: StateCell | undefined, next: StateCell, options: { readonly base: ContentAddress; readonly resultId?: ContentAddress; readonly previousHash?: string | readonly string[]; readonly timestamp?: HLC; }): Effect.Effect<{ readonly transition: DiscreteStateTransition; readonly receipt: ReceiptEnvelope; }>; /** * VERSION-AWARE, FAIL-CLOSED reader for an UNTRUSTED transition value (lowered * from an SSE frame / persisted JSON). Mirrors {@link GraphPatch.decode}: gates * `_tag`/`_version`/`kind` and rejects with ONE canonical tagged {@link ParseError} * — never silently misparsed. Scope is intentionally the tag/version/kind * ENVELOPE (the receipt hash + subject law are checked by the attestation seam). * * @throws `ParseError` (`source: 'DiscreteStateTransition'`) when the value is * not a record, carries the wrong `_tag`, an unsupported `_version`, or a * `kind` other than `'discrete'`. */ export declare function decodeDiscreteStateTransition(value: unknown): DiscreteStateTransition; /** * Apply a validated {@link DiscreteStateTransition} to a cell store. The typed * parameter is the uncompilable seam (Law 16): a `StateCell & { kind: 'continuous' }` * or a raw {@link SignalNode} is NOT a `DiscreteStateTransition`, so it cannot be * passed here — the wrong call does not compile. The store's generation-rollback * guard makes a stale/duplicate transition a byte-identical no-op (Law 15). */ export declare function applyTransition(cellStore: StateCellStoreShape, transition: DiscreteStateTransition): StateCell; //# sourceMappingURL=state-transition.d.ts.map