Skip to content

@source-repo/continuity

What a component keeps when the process implementing it is replaced: versioned state snapshots, adjacent forward migrations with reviewed defaults, the work a running activation was holding, a record of every value that moved — and the replacement itself, under a fence.

npm install @source-repo/continuity
  • Held state is explicit, and the rule is enforced — state is structure-cloned before every step, so state living in a language's object layout is refused with the reason rather than discovered at a handoff.
  • One reviewed transform per adjacent version — vK to vN walks the chain, which is one place per version where somebody had to decide what a new field means.
  • Three outcomes, not three degrees of successtotal, defaulted with the field, value and grounds recorded, and impossible, which refuses rather than inventing a value nothing downstream could tell from a measured one.
  • No separate dry run — migration is a pure function of an immutable snapshot, so the thing that was checked is the thing that runs.
  • Determinism is checked, not assumed — every step runs twice and its outputs are compared, which catches the two that actually happen: a clock and a random value.
  • A barrier, and one instantholdExecution queues arriving calls rather than rejecting them, and captureAtBarrier takes the values and the outstanding work in the same held breath or refuses.
  • Doing the work and recording it are one actRpcManagedRuntime arms the timer and registers the obligation in the same call, so there is no order of statements in which one happens and the other does not; a managed timer's callback runs on the component's own serial chain, where a barrier can hold it, rather than wherever the event loop delivers it.
  • Unmanaged writes are caught in the act — a component held at a barrier whose revision moves anyway is being changed by something the runtime never dispatched, and settleMs refuses unmanaged-mutation instead of sealing values from after the barrier under a position from before it.
  • Every obligation gets a disposition — a timer, a call in flight, a lease or a subscription the successor says nothing about is unhonourable, never assumed; a timer has no default policy because every policy is catastrophic somewhere.
  • The plan is proved twice — once while preparing, once against the snapshot actually taken at the barrier, because a component that took on work in between is owed a different set of things.
  • The commit point is the compare-and-swap and nothing else — before it, abandoning is free and no caller can tell; after it, the coordinator will not put the incumbent back, because the successor may already have touched the plant.
  • A fence has two halves — the local one is what the activation holds, and the one at the sink is the only one that survives a partition, because it does not require the stale activation to know anything.
  • A store says what it can guaranteelinearizable, durable, fencedAtTheSink, stated rather than implied; the in-memory reference store answers false to all three.
  • Callers address a name — a resolution carries the epoch it was taken under, and that is its shelf life; holding the address without it is a destination that stops being correct silently.
  • It crosses languages — a snapshot written here verifies to the same content hash in SourceRpc.Continuity, and a journal written here chains to the same hashes and yields the same replay plan there. Checked against fixtures both suites read verbatim rather than asserted; a chain is a stronger claim than a digest, because it is over every document and the order they are in.
  • Positions cross as decimal strings — JSON has one numeric type and it is a double, and a sequence position that rounds is a successor that reprocesses input or skips it. A position that arrived as a number is refused, never converted.
  • Portable is stronger than cloneable — a Date, a Uint8Array, a Map and a bigint all clone perfectly and none of them cross a language boundary as themselves.
  • A journal makes recover forward a procedurefailed-after-commit used to be an instruction; now a snapshot plus the inputs recorded after it can be replayed into a revision that can take them. A snapshot and a journal join at lastAppliedInputSequence, and a gap refuses rather than replaying what is left, because the state on the other side of a gap never existed.
  • Effects on replay are declaredsuppress-effects rebuilds state with outputs fenced, since re-applying a hundred inputs re-runs a hundred handlers; honour-idempotency is safe only where the sinks actually deduplicate, which is a claim about the plant.
  • Retention is what stays replayable — compaction takes a snapshot rather than a date, and refuses where it would leave a journal that looked whole and could no longer carry the snapshot it was kept for. The chain makes an altered or removed entry detectable rather than merely absent.
  • A manifest describes a revision and does not approve one — an artifact that could authorise itself by asserting its own capabilities would make the approval path decorative.

Full documentation: the package README. On npm: @source-repo/continuity.

MIT licensed