Buffered-commit flush coordinator for the WASM backend's batch path.

Bridges the per-commit WasmStateMirror updates onto a single commit_batch Rust call when either the count threshold (BatchedFlush.afterN) or the time threshold (BatchedFlush.intervalMs) trips.

ONE production mode, and one harness-only shadow (§18A.8 fail-safe-removal, causl/causl-core-rs#169):

  • 'rust-ssot' (the default, and since #280 the only value any production construction passes) — the Rust commit_batch post-state is applied to the mirror UNCONDITIONALLY and the last projected Commit of the window is exposed via lastPromotedCommit as the adopter-facing canonical result. There is no per-flush TS-vs-Rust byte-compare, no rollback, and no sticky-downgrade — the CI-blocking cross-backend determinism gate (§18A.1.1) is the sole guarantee the Rust engine matches the TS reference.
  • null — SHADOW-ONLY. The Rust post-state is still applied to the mirror, but lastPromotedCommit stays undefined, so the caller returns the wrapped TS-engine Commit. This was spelled 'js-ssot' before 0.5.0 and was reachable from the engine option; #280 removed the option and the literal, and kept the STATE because the C.5 shadow-only cell of the cross-backend determinism gate supplies no JS oracle and would otherwise arm the compare against an empty one. See the field doc on #engineMode for why it is null and not undefined.

https://github.com/iasbuilt/causl/issues/1501 — C.3 PR 2 (time-trigger introduction).

Constructors

  • Parameters

    • mirror: WasmStateMirror
    • bridge: BatchedFlushBridge
    • afterN: number = 1
    • intervalMs: number = 16
    • timer: FlushTimer = HOST_FLUSH_TIMER
    • engineMode: null | "rust-ssot" = RUST_SSOT

    Returns BatchedFlush

Properties

afterN: number

Count-based flush threshold. 1 = flush every commit (default).

intervalMs: number

C.3 PR 2 (#1501) — time-based flush threshold (ms). Default 16 ms = one animation frame at 60 Hz (option-c doc §2.2). 0 disables the time trigger (count / manual / implicit only). A flush is scheduled when the FIRST commit is buffered and fires after intervalMs unless the count threshold flushes first.

Accessors

  • get error(): undefined | Error

    Captured flush error, if the most recent flush threw. Cleared on the next successful flush. The cross-backend determinism gate asserts this stays undefined.

    Returns undefined | Error

  • get pending(): number

    Number of commits currently buffered (un-flushed).

    Returns number

  • get timerArmed(): boolean

    C.3 PR 2 — true when a time-based flush is currently armed. Exposed for tests and the C.3 PR 3 implicit-flush callers (which must cancel a pending timer when they force a synchronous flush).

    Returns boolean

Methods

  • C.3 PR 2 — release the interval timer without flushing. Called by the C.3 PR 3 dispose path; idempotent. Does NOT drain the buffer (a caller that needs the bytes on the wire calls flush first — the implicit-flush wiring in C.3 PR 3 does exactly that).

    Returns void

  • Buffer one commit's shadow input. The baseNow is the TS graph's PRE-commit clock for the FIRST buffered commit (the value the batch envelope's state.now must carry); subsequent commits in the same window do not move it (the Rust extern threads the post-state internally). Triggers a count-based flush when the buffer reaches afterN.

    Parameters

    • input: BatchCommitInput
    • baseNow: number

    Returns void

  • Flush the buffer as a single commit_batch envelope (or, if the bridge lacks the batched extern, as N sequential single-commit calls — byte-identical by construction, option-c doc §3.1). A no-op when the buffer is empty (so implicit/manual flushes are always safe to call). The projected Commit[] is returned for the C.3 PR 3 implicit-flush callers; the per-commit subscriber fire is the JS engine's job (Answer C — NOT batched here).

    Returns Commit[]