jonnify·bcs /bcs/cache/the-lane-that-remembers/the-bus-dies-the-lane-replays

B4.4 · dive 2 — the bus dies, the lane replays

The bus dies; the lane replays.

D-2 keeps the bus volatile on purpose, so a bus restart erases queued coherence jobs — Chapter 4.2 stated that ceiling in the open, and the TTL was the floor under the loss. This dive raises the ceiling without touching the decision. The H3 gate proves the applied memory outlives everything around it — a replayed old version answers :remembered_stale from the journal alone, no cache row consulted, none created — and the H4 gate stages D-2's loss itself: fifty obligations on the lane, twenty applied, the queue flushed, and the journal replaying back exactly 30 uncovered intents … in seq order under their recorded job ids.

Source: content/bcs4.4.md, quoting bcs_rung_4_4_check.out. This dive reads the memory derive, H3, the loss derive, and H4 — the derived expectation: a remembered count of 50.

The restart, stepped. The H3 drill over one file: the applied memory holds v5, the table and the journal stop, the same file reopens against an empty L1, and two versions arrive — one old, one genuinely newer. Step through; the readout quotes the record where it lands.
the full stop table and journal, down :remembered_stale no row appeared passes through journal-<group>.db applied: the name → v5 :limits · L1 empty after the reopen the same file applied still holds v5 a replayed old version older than v5 v6 genuinely newer · the new last word
readout · Press step to walk the H3 drill — the memory before the stop, the full stop, the reopen against an empty L1, the old version refused, the newer one applied.

Static walk — 1) the applied memory holds v5; the applied table lives in the file · 2) the full stop: table and journal, down · 3) the same file reopens against an empty L1 · 4) a replayed old version answers :remembered_stale from the journal alone — no cache row consulted, none created · 5) the verdict counters did not move and no row appeared · 6) the genuinely newer v6 passed through and became the new last word.

§1

The transcript

bcs_rung_4_4_check.out · verbatim · this dive reads the memory derive, H3, the loss derive, H4
content/echo_data/runtimes/elixir/bcs_rung_4_4_check.out · verbatim · the middle; the hub holds the record wholefrozen
… (the self-check, the header, H1, and H2 open the record -- frozen on the module hub)
derive (memory): the applied table lives in the file, so it survives the table, the node, and the bus; after a full restart with an empty L1, a replayed old version must answer :remembered_stale from the journal alone -- no cache row consulted, none created -- while a genuinely newer version passes through and updates the memory
H3 memory ok -- the journal remembered v5 across a full stop of table and journal; the replayed old version answered :remembered_stale without touching the cache -- the table's verdict counters did not move and no row appeared -- and the genuinely newer v6 passed through and became the new last word
derive (loss): D-2 keeps the bus volatile, so a bus restart erases queued coherence jobs; 50 intents recorded and enqueued, 20 applied before the loss, the lane's queue keys flushed -- replay must re-enqueue exactly the 30 uncovered intents in seq order, and a consumer must drain them to a remembered count of 50
H4 loss ok -- the bus restart erased the queue and the journal replayed the lane back: exactly 30 uncovered intents re-enqueued in seq order under their recorded job ids, the consumer drained them, and the applied memory closed at 50 of 50 names holding their final versions
… (the compaction and the price close the record -- frozen on the module hub)

Each derive line states the expectation before the gate asserts it: the H3 derive demands :remembered_stale with no cache involvement at all, and the H4 derive computes the replay set's size from the staging itself — 50 recorded, 20 applied, so exactly 30 uncovered.

§2

The memory across a restart

content/bcs4.4.md · What · Decisions

The applied table lives in the file, so it survives the table, the node, and the bus. Without this memory, an empty L1 makes every replayed message look fresh; with it, staleness is a fact about the lane, not about whichever rows happen to be resident. The drill stops the table and the journal, reopens the same file against an empty L1, and replays an old version — the gate's verbatim close: the table's verdict counters did not move and no row appeared -- and the genuinely newer v6 passed through and became the new last word.

The decision underneath: the memory check runs before the cache. apply_and_remember consults the journal first and answers :remembered_stale without an ETS lookup, because the journal's word outlives the cache's rows — the gate proves the counters do not move. This is newer-wins from B4.2 · Coherence by Mint Time given a durable floor: the comparison is the same, the version is still a name, and the only change is where the older side of the comparison survives.

§3

The loss drill — 50, 20, 30

content/bcs4.4.md · What · Who · Boundaries

D-2 keeps the bus volatile, so a bus restart erases queued coherence jobs. The rung stages exactly that — 50 intents recorded and enqueued, 20 applied before the loss, the lane's queue keys flushed — and replay selects by coverage: every intent whose name lacks an applied version at least as new. The twenty already-applied intents are not re-sent; the thirty lost ones are, in seq order, under their recorded job ids, with no acknowledgment bookkeeping anywhere on the hot path.

The ledger of the loss. The fixed 50/20/30 dataset of the H4 drill, drawn to scale. Step the stages; the ledger is recomputed from the staging — uncovered = 50 recorded − 20 applied.
recorded · 50 applied · 20 re-enqueued · 30 in seq order · under their recorded job ids
readout · Press stage to run the H4 drill over the fixed ledger — 50 recorded, 20 applied, the flush, the replay of exactly 30, the drain to 50 of 50.

Static ledger — recorded 50 · applied before the loss 20 · re-enqueued by replay 30, in seq order under their recorded job ids · the consumer drained them and the applied memory closed at 50 of 50 names holding their final versions.

Recovery, after the bus came back empty, is one idempotent verb — and retention is its sibling, both safe to run on a schedule:

{:ok, %{replayed: n, deduplicated: m}} = Journal.replay(:limits_journal, conn)
{:ok, retired} = Journal.compact(:limits_journal)

Boundaries, stated honestly: the journal is per-group and per-node — it restores its own lane's obligations and claims nothing about cross-group ordering, which the lanes never promised anyway. Replay is at-least-once by construction and harmless by comparison — the same two facts, in the same order, as everywhere else in this part. The lease, the reaper, and the volatile substrate under this drill are B3.3 · The State Machine in Lua's machine; the recorded job ids the replay reuses ride B3.2 · Jobs Are Entities's admission dedup. Application on the consumer side is the engine of the sibling module — B4.3 · The Single Writer and the Ring — and the compaction predicate and the price close the module in the next dive.

§4

References

sources · related

Sources

Related