Skip to main content

Module wal

Module wal 

Source
Expand description

WAL frame substrate (Phase 14.6 — DS-14-storage Q1+Q3+Q5 locks, M4.A 2026-05-10).

On-disk frame format consumed by Graph::restore_snapshot({ mode:"diff" }) (M4.E). Each frame decomposes a single graph diff into one DS-14 BaseChange<T> envelope per structural-or-value change, scoped by Lifecycle so callers can narrow rewinds.

The TS reference impl lives at packages/pure-ts/src/extra/storage/wal.ts. Field names + checksum algorithm are parity-locked — both impls produce byte-identical hex SHA-256 over the same canonical-JSON encoding of a frame body.

§Canonical-JSON parity

TS’s stableJsonString (packages/pure-ts/src/extra/storage/core.ts:22-39) is “recursively sort object keys, then JSON.stringify(_, undefined, 0)”. The Rust port mirrors this by routing the frame body through serde_json::to_value (lands in serde_json::Map which is BTreeMap by default — sorted iteration) then serde_json::to_string. Output is byte-identical to TS for the WAL frame schema: ASCII keys, integer numerics, no floats.

Parity caveats (lift when a real consumer surfaces):

  • String VALUES containing surrogate-pair code points (≥ U+10000): JS sorts keys by UTF-16 code-unit order; Rust BTreeMap sorts by UTF-8 byte order. For ASCII keys these agree; for non-BMP keys they don’t. The frame schema’s keys are ASCII so this can only bite if path or change.structure contains non-BMP code points — neither is expected for graph identifiers.
  • Float-typed user payloads: JS JSON.stringify uses IEEE 754 with shortest-decimal-round-trip; Rust’s serde_json uses ryu which agrees on finite f64 in safe range but may diverge on subnormals. WAL frames typically carry integer-only data; if a user puts a float in change.change, document the constraint.

§Checksum

SHA-256 over canonical-JSON of the frame body (everything except the checksum field itself), encoded as a 64-char lowercase hex string. Spec-locked at GRAPHREFLY-SPEC.md:1201-1206 — original BLAKE3 lock was revised to SHA-256 so the TS impl could stay zero-dep (no BLAKE3 in WebCrypto). Rust matches via sha2 + hex.

Structs§

WALFrame
On-disk WAL frame (DS-14-storage Q1 lock).
WalTag
Singleton-string discriminator for the bridge wire-format tag. Always serializes / deserializes as "c"; rejects any other value at parse time.

Enums§

ChecksumError
Errors surfaced by checksum compute / verify.

Constants§

REPLAY_ORDER
Cross-scope replay order (DS-14 PART 4 lock — Spec → Data → Ownership). Exported so the replay implementation and parity tests share one source of truth.
WAL_FRAME_SEQ_PAD
Pad width for frame_seq in WAL keys. 20 digits keeps lex-ASC string sort = numeric ASC up to frame_seq < 10^20 (well past u64::MAX).
WAL_KEY_SEGMENT
Default WAL prefix segment relative to a graph.name. Frames land at ${graph.name}/${WAL_KEY_SEGMENT}/${frame_seq:020}.

Functions§

graph_wal_prefix
Default WAL key prefix for a graph by its name.
verify_wal_frame_checksum
Verify a frame’s checksum field matches its body. Replay invokes this at the WAL tail (drop on mismatch by default) and mid-stream (abort on mismatch by default) per Q3.
wal_frame_checksum
Compute the SHA-256 checksum over a frame’s body (sans checksum), returning a 64-char lowercase hex string. Parity-locked with TS walFrameChecksum.
wal_frame_key
Build the canonical WAL frame key. prefix is the WAL-prefix portion (e.g. "my-graph/wal"); frame_seq is the per-frame cursor. Zero-padded so lex-ASC string sort equals numeric ASC sort.