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
Journalhandle wires the reducer to durable storage through the injectedJournalStore/Clock/IdGenports, 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:
- Watermark —
applyignores any event whoseseqis 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. - Structural — the projection is built from keyed sets/maps, so folding a
fact about target
cargomore 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 Failed→Ok 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.
- Journal
Paths - 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
pathinto events, in ascendingseq. - 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
RunStatestraight from its event log — the read-only pathrelease verifyreconciles from. - reduce
- Fold an ordered event stream into the materialized
RunState— the pure, I/O-free core of the journal.