C.W.K.
Stream
Lesson 02 of 05 · published

The Journal Writes First

~12 min · journal, durability, write-before-mutate

Level 0Lost in Finder
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"If the power cuts one millisecond into a move, the only thing that saves you is a record written the millisecond before."

Ordering Is the Whole Guarantee

"Write before mutate" is not a slogan; it is a strict ordering. Before the engine makes the first change to the filesystem, it commits a durable journal row that says planned: here is the operation, here are the sources and destinations, here are the expected identities and the collision decision. Only after that row is safely on disk does a single byte move. The ordering is the guarantee — because a crash can happen at any instant, and the journal must always be at least one step ahead of the damage.

Why a Log After the Fact Is Useless

Contrast this with the ordinary instinct: do the operation, then log that you did it. If the app crashes mid-copy, that log was never written — you have a half-finished mutation and no record it was ever attempted. Recovery would be guesswork. The journal inverts the order precisely so that the record of intent outlives any crash, and recovery is reading, not guessing.

Every Barrier Leaves Evidence

The journal isn't just one row. At each barrier — validated, staged, verified, published, source-deleted — the engine appends timestamps, resolved identities, staging paths, byte and item progress, errors, and verification results. Ordinary console logs are secondary and disposable. The journal is the durable, transactional explanation of what happened, and it is backup-worthy runtime evidence, not debug noise.

The journal commits intent before the first mutation, and evidence at every barrier. Recovery reads the journal; it never guesses. A log written after an operation can't survive a crash during it — so the record of what was intended must come first, always one step ahead of the change on disk.
The same instinct runs cwkPippa. Pippa's conversation log is append-only JSONL, written before anything is shown to Dad — 'write before show,' the sibling of 'write before mutate.' In both apps the durable record precedes the visible or destructive act, so a crash can never destroy evidence of what was happening. One family, one instinct about durability.

Code

The journal: intent first, then evidence at each barrier·sql
-- Row 1 is committed BEFORE the first filesystem change:
INSERT INTO operation_journal (op_id, kind, state, source_ref, dest_ref,
                               expected_identity, collision_decision, planned_at)
VALUES ('op_7a3f', 'move', 'planned', :src, :dst, :ident, 'replace', :now);
-- ^ durable on disk. NOW, and only now, may a byte move.

-- Each barrier APPENDS evidence (never overwrites intent):
UPDATE operation_journal SET state='staged',   staged_path=:tmp,  staged_at=:t1  WHERE op_id='op_7a3f';
UPDATE operation_journal SET state='verified', verify_hash=:h,    verified_at=:t2 WHERE op_id='op_7a3f';
UPDATE operation_journal SET state='committed', committed_at=:t3               WHERE op_id='op_7a3f';
The ordering, enforced·swift
func execute(_ plan: OperationPlan) async throws {
    // 1. WRITE: durable 'planned' row, committed to disk.
    try await journal.commitPlanned(plan)
    // 2. Only after (1) is durable do we MUTATE:
    let staged = try await stage(plan)         // copy into staging
    try await journal.mark(plan.id, .staged, evidence: staged)
    try await verify(staged, against: plan)    // confirm bytes
    try await journal.mark(plan.id, .verified)
    try await publish(staged, plan)            // atomic rename into place
    try await journal.mark(plan.id, .committed)
}
// A crash between ANY two lines leaves a journal that names exactly
// where we were -- recovery reads it instead of guessing.

External links

Exercise

Design the journal row for a cross-volume move on paper. List every field recovery would need to answer, after a crash: 'was the copy finished? was it verified? was the source already deleted?' Then decide which fields must be written BEFORE the first byte moves, and which are appended as the operation progresses.
Hint
Before the first byte: op id, kind, source and destination identities, collision decision, and 'planned' — the intent. Appended per barrier: staging path, verification result, and the state transitions. The dividing line is simple — anything recovery needs to even KNOW an operation existed must be written first; everything else is evidence added as you go.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.