Schema helpers are a thin layer over pi-schema's builders with the same JSON,
so fingerprints and stored data are unchanged (proven by schema-switch tests and
a store written by the TypeBox code). Checks through pi-schema; error messages
are pi-schema's; format is an annotation. v1 contracts take any JSON Schema.
map(bytes()) works.
- an awaited get or a ready hold has every state member of its variant, local or remote
- holds subscribe to their variant's state; per-member opt-out with state: false
- remote binding keys use canonical identity; client holds carry an opaque origin
- shape frames no longer carry codeVersion
- self.state(name, schema, { init }) loads before the object goes live
- the principal type is a parameter; createHost self, connect and route principals are required
- remote contracts declare their host (hostNamed, hostFamily); get no longer takes at
serve(Type, factory, { lifetime: "host" }) compiles only for a local type whose input has no required fields, and
not together with linger; the runtime check stays as a backstop. ServeOptions is a union (ReferencedServeOptions,
HostServeOptions), picked per contract by ServeOptionsFor<C>.
- A child that says hello during a cluster reload is fenced at once and reconciled after the reload ends, to the
committed code version (it was marked in sync without voting); a running reconciliation also waits for the reload.
- A child retires a code version only after its parent did (spec section 12): the coordinator retires before it
prepares, and children learn already retired versions at hello and before a reconciliation's prepare.
- Forced retirement aborts the leftover roots of the old code version, relayed calls included, before it closes the
resources only that code used.
- A task's replacement starts after the old run has ended, at most taskStopDeadline later.
- A kept resource adopts the newest declaration's close at commit.
- Disposed objects and old code generations are released: Ref bindings are weak, finished disposals leave the dying
table, stopped tasks are dropped, and contexts link abort signals without AbortSignal.any (which kept linked signals
and their listeners reachable).
- Facets get FacetApi.signal, aborted when their run is replaced, removed, aborted or the host closes.
- Regression tests for each, including a garbage-collection test of old code generations.
- self.state(name, schema, initial, { version?, migrate? }) returns the cell; the state version and migration live on
the cell (ServeOptions.state is gone). self.derive(sources, fn) has no name and is recomputed at commit.
self.resource(name, { version, deps?, exclusive?, open, close? }) (rev is version). self.task(fn). self.on(name,
source, [select,] handler) replaces listen/listener. cell(), derivation(), resource(), listener() and the
declaration maps are gone; a name declared twice in one factory run is an error.
- A listener on state receives the current value at start and after every reload: handlers must reconcile.
- method(args?, result?): an omitted result is void, omitted arguments make a no-argument method called as
ref.name(ctx) and implemented as (ctx) => ...; the wire omits both.
- References are Ref<C> (was Handle<C>), objects ObjectImpl (record.ts is object.ts), ImplementationOf<C> (was
BehaviorOf<C>), ResourceDeclaration (was ResourceSpec); epochs are code versions (codeVersion in Ctx, RootOptions,
Shape, Host, frames and reload reports). Docs say object and reference.
- A remote object's variant is named variant (was kind): factories return { variant }, references expose ref.variant.
- Links announce a protocol version (PROTOCOL_VERSION = 2) in hello; peers of different versions close the link with
reason protocol-version <n> and report it through LinkOptions.onProtocolMismatch.
- ServeOptions.lifetime ("referenced" | "host") replaces eager: a host-lifetime object is local, has an empty input,
exists once per host and lives until the host closes; awaitEager is awaitHostObjects. A reload that makes a type
referenced releases the host's own reference.
Peers acknowledge processed frames (ack, announced with acks in hello). While a window of frames is unacknowledged, state frames wait at the sender, coalesced per subscription, instead of queuing in front of call results; slots that outgrow their bound become resets, or a downstream resubscription on relays. AcceptOptions gains maxCalls, answering calls beyond it with unavailable/too_many_calls. Link.send returns the encoded frame size.
Chord: README rewritten for the new runtime; notes.md and requests.md removed, their open limits and
decisions folded into spec.md section 12; guide and spec status lines updated. Durable: drops the
pico-v5 handoff and delta findings, renames the Pico spec, and uses current Chord terms. Delta README,
issue categories, and PI_RADIUS_GATEWAY updated.
Moves chord2 (contracts, objects, cells, roots, plugins, hot reload, memory/IPC/WebSocket links)
from p2 into packages/chord, with its tests (now on vitest) and docs. The root export is the new
runtime plus the shared base (Context, JsonValue, JsonRepresentation, Draft, copyJson, isJsonValue,
replicatedState and its types). ./node now holds the host manager, child control, process locks,
and nodeLoader. ./context and ./delta are unchanged; ./bundler is removed.
replicatedState stays a standalone module with the same exports. It no longer exposes the exact-op
subscription the removed service provider used, so listener failures of mutable states are always
reported asynchronously. The package depends on typebox instead of esbuild. The wire format stays JSON.