Skip to main content

Module journal

Module journal 

Source
Expand description

Event-sourced release journal (ADR-0003).

Append-only JSONL events under git-common-dir/ossctl/releases/<run_id>/, with an idempotent reducer folding them into resumable RunState. The durable record release resume/verify/show read back.

§The two halves

  • The reducer (reduce / apply) is a pure fold of [JournalEvent] → RunState. It has no I/O and is the core testable unit: the same events always fold to the same state, and re-applying a seen event changes nothing.
  • The Journal handle wires the reducer to durable storage through the injected JournalStore / Clock / IdGen ports, enforcing the append-then-apply atomicity discipline and holding the single-active-cut lock for its lifetime.

§Append-then-apply (ADR-0003 §2, from octl-core)

Every mutation is: (1) fsync the event to journal.jsonl (durable), (2) apply it to the in-memory RunState, (3) atomically rewrite the manifest.json cache. The journal is the single source of truth; the manifest is disposable and is always rebuilt by reduce on Journal::open, so a crash anywhere in that sequence recovers cleanly — a durably-appended event is folded back in on the next open regardless of whether its manifest write landed.

§Idempotency

Replay idempotency — the property the crash-safety discipline needs — comes from two mechanisms working together:

  1. Watermarkapply ignores any event whose seq is at or below the already-applied high-water mark, so replaying the persisted log (or a seen event) is a no-op. This is the “re-applying a seen event changes nothing” guarantee.
  2. Structural — the projection is built from keyed sets/maps, so folding a fact about target cargo more than once yields the identical map.

The log is append-only facts: Journal::append does not deduplicate on crate::protocol::journal::JournalEvent::idempotency_key (an earlier design did, which silently swallowed a legitimate FailedOk phase retry after a resume). Whether to emit an event is the coordinator’s decision — and since the remote registry is ground truth (ADR-0003 §4), a resumed cut re-checks reality before re-emitting rather than trusting an append gate.

§Terminal states

Once the run reaches a terminal status (RunStatus::Completed or RunStatus::Abandoned) the reducer freezes: later events are ignored, so a corrupt or buggy log cannot un-abandon a run or resurrect a completed one.

Structs§

Journal
A live, exclusively-locked handle to one release run’s journal.
JournalPaths
Resolved on-disk locations for a repo’s release journals.

Functions§

apply
Apply a single event to state, in place.
list_runs
List the run ids present under the releases root — the enumeration behind release list.
load_state
Read a run’s current state without locking — the read-only path behind release show.
read_events
Parse the JSONL journal at path into events, in ascending seq.
read_run
Read a run’s event log and its reduced state, read-only — the read path behind release show.
read_run_state
Authoritatively rebuild a run’s RunState straight from its event log — the read-only path release verify reconciles from.
reduce
Fold an ordered event stream into the materialized RunState — the pure, I/O-free core of the journal.