Skip to main content

runtime/fork/
lineage.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! The `run_forked` line: written when a branch is frozen, and read back
7//! when a branch of that branch is rebuilt.
8
9use kernel::event::record::RunForked;
10use kernel::{
11    Address, AxCode, AxError, EventDraft, EventKind, EventRecord, Payload, RunId, Seq, TimeMs,
12};
13
14/// The `run_forked` draft for the city Ledger; the caller supplies the
15/// new run id, the room it lands in, and the clock reading.
16pub fn fork_draft(
17    origin: kernel::Origin,
18    new_run: RunId,
19    addr: Address,
20    t: TimeMs,
21    who: String,
22) -> Result<EventDraft, AxError> {
23    let data = Payload::of(&RunForked {
24        from: origin.run,
25        at_seq: origin.at_seq,
26    })?;
27    Ok(EventDraft {
28        run: new_run,
29        t,
30        who,
31        // The room is on the line because a fold that rebuilds what each
32        // room's session still owes reads it here: the new run's id says
33        // which run continues which, and the address says whose session
34        // has been served.
35        addr: Some(addr),
36        kind: EventKind::RunForked,
37        data,
38        ig: false,
39    })
40}
41
42/// Where `owner` was branched from, read off its `run_forked` line, when
43/// it was. The cut must lie before that line: a lineage that pointed at
44/// or past itself is a damaged history, refused rather than followed,
45/// which is also what makes the rebuild's recursion end.
46pub(super) fn forked_from(owner: RunId, records: &[EventRecord]) -> Result<Option<Seq>, AxError> {
47    let Some(line) = records
48        .iter()
49        .find(|record| record.kind() == EventKind::RunForked)
50    else {
51        return Ok(None);
52    };
53    let origin = line.data().read::<RunForked>()?.at_seq;
54    if origin >= line.seq() {
55        return Err(AxError::failure(
56            AxCode::InvalidArgs,
57            "fork",
58            format!(
59                "{owner} was branched at seq {}, which is not before its own run_forked at seq {}",
60                origin.value(),
61                line.seq().value()
62            ),
63        )
64        .with_recovery("branch from a run whose lineage this history holds in order"));
65    }
66    Ok(Some(origin))
67}