Contents

Fixed-Point Store-Position Wakes

This note owns the implementation cut for restarting an open interlace after local durable store progress. The mechanism is deliberately broad:

FixedPointBoundary + Lace-owned retained position-or-terminal-failure signal

Stores remain policy-neutral. Hosts do not classify commits, replay records, or predict whether policy output will change.

Purpose

An open endpoint at fixed point must notice a commit newer than the terminal round’s local record-fact boundary without moving interlace policy into the store or duplicating selection logic in each runtime.

The endpoint reports the terminal round’s shared local StorePosition read-through. Any later position published by the owning Lace makes another advertisement evaluation eligible. The evaluation, not the wake signal, determines whether the selected set changed. It updates the endpoint’s session state with the records admitted since that boundary, so a wake costs work in proportion to those records and the selections they change, not to the store (interlace-policy-lowering.md).

Ownership

Endpoint machine

On fixed-point entry the machine reports:

FixedPointBoundary {
  round: InterlaceRoundId,
  wake_boundaries: [FixedPointWakeBoundary],
}

FixedPointWakeBoundary {
  machine: MachineId,
  fixed_point: FixedPointId,
  position: StorePosition,
}

A connected machine has one wake boundary. A direct pair has one independently tokened wake boundary per protocol side, including same-Lace composition.

The fixed-point identity is an opaque ownership token for one exact settled state. Every logical session and direct replacement creates fresh identities. It prevents an asynchronous position result from being applied after peer input, policy replacement, or a newer fixed point has retired the old state.

The endpoint owns protocol state and the transition from a current boundary to Round.Advertising. It does not own a store, watch, callback, or task.

Host Lace

Each runtime-owned Lace owns one retained position-or-terminal-failure signal. Before failure it contains the latest confirmed monotonic StorePosition, so a subscriber can read current state even when it missed the change edge. On the first Lace-terminal failure it permanently contains that typed Store or Integration error. Local mutation completion and every authoritative refresh publish through this one signal and the same mutation/publication gate.

At store adoption the Lace also retains the immutable position_may_advance_externally boolean. When true, the Lace owns the shared next_poll_at and poll_in_flight state, physical probe lifetime, and polling fanout. Concrete open operations own their subscriptions, endpoint boundary registrations, transport and cancellation waits, and token validation. Their fixed-point drivers consult the Lace-owned polling state; they do not own per-operation cadence or another operation’s machine.

Store

The store owns durable records, StoreRecordId, StorePosition, load, search, and store execution. CurrentStorePosition is the authoritative external refresh probe. The store does not know the adoption boolean, endpoints, compiled plans, exposure views, protocol sides, host lifecycle, timers, subscriptions, or callbacks.

Rust and the shared binding layer

Rust owns scalar StorePosition comparison, FixedPointBoundary, FixedPointWakeBoundary, and the endpoint transition that returns Accepted only for an advance on the exact current token and Stale otherwise. Native Rust drivers inspect that result. C/WASM projects the boundary and a safe transition operation that treats stale delivery as a no-op. PyO3 keeps the boundary in the machine wrapper, exposing its per-side positions and a delivery that returns whether the advance was accepted. They expose no policy-interest object, classifier key, candidate hint, committed-record feed, or replay API.

Lace position publication and terminal failure

The runtime-owned Lace owns a mutating store operation through publication:

execute StoreOp
-> classify durable outcome
-> refresh CurrentStorePosition after mutating success or error
-> publish any position advance to retained Lace state
-> submit the active StoreCall response if its machine remains active

Publication occurs before completion becomes available to code that could put an endpoint to sleep. Durable progress discovered while returning StoreError is still published; the error remains an error. A failed StoreRecords remains operation-local when its mandatory refresh and publication succeed. Failure to refresh after ordinary operation work is Store for that operation; failure to publish a confirmed position is Lace-terminal Integration. Neither failure permits successful mutation submission. A position retained before publication fails remains confirmed progress.

A Lace-owned external refresh performs CurrentStorePosition under the same publication gate without manufacturing a machine StoreCall. A successful refresh publishes the greatest confirmed position even if the initiating fixed-point token or operation became stale. External-probe failure is Lace-terminal Store; failure to publish a confirmed position is Lace-terminal Integration. The first Lace-terminal failure atomically replaces the retained signal state, clears polling state, wakes every subscriber, rejects all later store execution and participant claims, and is returned by Lace close after active work drains. A poisoned Lace never retries; recovery constructs a fresh Lace and store object.

Operation retirement does not suppress publication or the terminal transition. Already-started non-cancellable work retains the Lace through durable classification but never submits to a retired machine. An ordinary operation-local store failure does not poison the Lace. Record observations never update position state. This one retained publication path keeps direct and connected routes identical. Stores have no delete operation; position is monotonic, and duplicate admission advances neither position nor the signal.

Fixed-point registration race

An open operation establishes its retained Lace-state subscriptions before it can install any fixed-point boundary; current runtimes do this when constructing the operation, or when a selecting connected operation adopts its selected Lace, which precedes its first session, and reuse the subscriptions until operation close. When an endpoint enters fixed point, the host closes the evaluation-to-sleep race in this order:

  1. ensure that the owning Lace subscription already exists;
  2. select and install the endpoint’s complete FixedPointWakeBoundary from the reported FixedPointBoundary;
  3. read the retained Lace state;
  4. if it is terminal failure, end the operation with that exact retained error;
  5. if its position is greater than boundary.position, validate the token and report the advance;
  6. otherwise wait for retained state to change, the Lace polling deadline when enabled, legal peer input, cancellation, or closure.

Subscribing before boundary installation ensures that a commit between output evaluation and boundary installation is either already represented by the retained position or observed afterward. No contiguous commit stream, recent-record ring, overflow marker, or record rescan is required.

A bounded operation does not install this registration or request external polling. A new fixed point replaces the previous token and position. Leaving fixed point, logical-session or direct replacement, closure, failure, or drop clears the tokened boundary registration; the operation-lifetime subscription remains until operation close. Poll cadence is Lace state and is not cleared or reset by one operation’s phase transition.

Stale boundary tokens

A position wait captures the complete boundary value. Before delivery, the driver first processes any synchronously staged replacement, then submits that value to the endpoint. Native Rust drivers follow the authoritative Accepted or Stale result. C/WASM hosts submit only a matching projected token, and the safe binding transition treats any stale delivery as a no-op; PyO3 delivers to the retained boundary for a side and reports acceptance.

Discarding a stale position result neither fails the active round nor schedules another round. Refresh and confirmed-position publication are Lace-scoped and still complete when delivery becomes stale; only submission of an advance to the endpoint is token-gated. A retained terminal Lace failure is not endpoint input and is not discarded as stale: it terminates every still-subscribed operation that uses that Lace. A commit already visible at the active round’s local record boundary is covered by both output evaluations. A newer commit remains newer than the round boundary at the next fixed point and is found by the next registration race.

Starting an open round

There is one round-start mechanism: an advertisement listing, carried as one Lace-060 ::offers-changed item on a connected carrier.

No side coordinates round start and neither side has priority after fixed point. The advertisement is ordinary policy output, not evidence that a particular record changed or that the round will transfer anything.

Externally advancing store polling

Polling is enabled by the immutable adoption metadata position_may_advance_externally, never by inspecting a concrete store type. false schedules no external probe. true selects one fixed internal one-second interval. Polling is requested only while at least one relevant open operation is waiting at fixed point; bounded operations and active rounds do not request it. CurrentStorePosition, not the timer or metadata, supplies position authority.

Each Lace retains only:

next_poll_at
poll_in_flight

Every fixed-point driver consults that shared state. The first driver at or after next_poll_at marks one probe in flight and provisionally moves next_poll_at to one interval after the start. Other drivers observe the in-flight flag or later time and continue waiting on retained Lace state, legal transport, cancellation, or that time. They do not join the probe, create a completion generation, or queue another probe. If a driver’s observed deadline expires while the probe remains active, that driver uses one local interval as a retry bound instead of spinning.

Successful completion clears poll_in_flight and sets next_poll_at to one interval after completion, including when position did not advance. This update belongs to the Lace and does not depend on the initiating operation remaining alive or receiving a result. An advance follows ordinary monotonic publication and wakes all subscribers; no advance publishes nothing. Failure instead clears polling state and follows the Lace-wide poisoning path above. A same-Lace direct pair and any number of staggered open operations therefore cause at most one physical probe per shared interval. Separate Lace objects remain separate refresh owners. Native filesystem Laces have exclusive root ownership and do not request external polling; cooperating LMDB processes each refresh through their own Lace.

lace-rt bounds its Mio wait and starts Lace-owned blocking refresh work. lace-tokio selects the shared deadline alongside retained state and connected IO and executes the refresh inline or through spawn_blocking, as the adopted backend’s execution marker requires. Python bounds both direct condition waits and connected transport waits, executes a blocking refresh on its owned store worker, and publishes from an operation driving that Lace. All three continue legal transport, phase-deadline, and cancellation driving while refresh is in flight.

There is no public interval option, persistent watcher thread or task, external notification ABI, callback, notification socket, process-wide scheduler, or store registry. Poll state and initiating operations do not process another operation’s machine. A future notification can only prompt the same authoritative refresh and retained publication path.

Fanout and same-Lace composition

A position advance makes every open endpoint on that Lace whose current boundary is older eligible. A terminal Lace failure wakes and terminates every subscribed operation using that Lace. Broad fanout is intentional. Hosts do not inspect plans, fields, operation roles, or Datalog dependencies to narrow it.

A direct pair may use the same Lace for both endpoints through two handles. That Lace’s one retained position-or-terminal-failure signal serves both independently captured boundary tokens. Atomic direct replacement drops both old tokens before either fresh endpoint runs. The driver makes both current endpoints eligible, lets both start Advertising, and routes their crossed listings normally. No owner-identity rejection or special same-Lace protocol path is needed.

Multiple commits before one endpoint runs require only the latest retained position. Once the endpoint leaves fixed point, later commits are covered by active output boundaries or the next registration. There is no per-record host work item.

Output scope and closure

The boundary comes from the machine’s actual round-local record snapshot, not from the Lace’s latest position when the host processes fixed-point entry. This preserves output scope: a commit after the round boundary freezes cannot alter either output in that round.

A bounded host returns only after the final accepted output batch is flushed to the adopted IO and its route is closed or released. An open host accepts clean item-boundary EOF at fixed point from a bounded peer and transitions to clean closure. Operation close settles an already-started authoritative refresh. Its retirement never suppresses confirmed-position publication or Lace-wide poisoning. External-probe or publication failure wakes every remaining subscriber with the retained typed Store or Integration error, rejects later work and participant claims, and is returned by Lace close after active work drains. No result is submitted to a retired machine. Local work not exchanged before closure remains eligible in a later fresh Lace or session when the Lace was not poisoned.

Boundary tests

Tests for this ownership cut cover: