kernel/event/record/checkpoint.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//! What a checkpoint records: the job a dispatch pinned, or the commit
7//! a checkpoint raised.
8
9use serde::{Deserialize, Serialize};
10
11use crate::event::identity::RunId;
12use crate::locator::{GitOid, Locator};
13use crate::model::Effort;
14
15/// `checkpoint_committed` carries two facts that are not the same fact,
16/// and this enum states which one a line holds instead of leaving a
17/// reader to infer it from which keys are absent.
18///
19/// A dispatch opens a run by pinning the job it came out of; a checkpoint
20/// raises a git commit before a wave. Both were written under this one
21/// kind before these structs existed, and re-spelling a ledger already
22/// on disk is not available, so the two shapes stay under one kind and
23/// are told apart by their keys. The variants are untagged: each one
24/// writes exactly the object its hand-written predecessor wrote, with
25/// no discriminator added.
26///
27/// **The pin should be its own kind.** It answers "which job is this
28/// run for", which no commit answers, and every reader of this kind
29/// starts by discarding it. Splitting it needs a new `EventKind` and a
30/// ledger version, so it is recorded here rather than done here.
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32#[serde(untagged)]
33#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
34pub enum CheckpointCommitted {
35 /// The dispatch pin: the job a run was opened for, and no commit.
36 JobPinned {
37 #[cfg_attr(feature = "schema", schemars(with = "String"))]
38 job: Locator,
39 },
40 /// A checkpoint or a landing: the commit, and the facts the record
41 /// cannot state for itself.
42 Committed(Commit),
43}
44
45/// Which session made a commit, as the ledger states it.
46///
47/// One fact with one home, carried by both kinds of record that name a
48/// commit: `checkpoint_committed` from a checkpoint and `pr_merged` from a
49/// review. The run and the actor are the record's own identity and are
50/// not repeated here; the model and the effort are, because until they
51/// are written here they exist only on the git commit's trailers, and
52/// the trailers are the projection rather than the authority.
53#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
54#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
55pub struct CommitAttribution {
56 /// The endpoint's own model id, empty when the caller did not know
57 /// it. Absent in every record written before the key existed, which
58 /// reads back the same as unknown.
59 #[serde(default)]
60 pub model: String,
61 /// Absent leaves the choice to the provider, which is not the same
62 /// fact as [`Effort::None`] asking it not to think. A checkpoint writes
63 /// `Effort::None` for both, because that is the word its git
64 /// trailer has always carried.
65 #[serde(default, skip_serializing_if = "Option::is_none")]
66 pub effort: Option<Effort>,
67 /// The run this one replaced, when it is a successor.
68 #[serde(default, skip_serializing_if = "Option::is_none")]
69 pub predecessor: Option<RunId>,
70}
71
72/// The commit a checkpoint raised, and what it staged.
73#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
75pub struct Commit {
76 /// The commit object this checkpoint wrote.
77 #[cfg_attr(feature = "schema", schemars(with = "String"))]
78 pub oid: GitOid,
79 #[serde(flatten)]
80 pub by: CommitAttribution,
81 /// Which parts of the city the checkpoint staged, empty for the whole of
82 /// it. Written even when empty, as the hand-written writer did.
83 #[serde(default)]
84 pub scope: Vec<String>,
85 /// The paths this commit touched.
86 #[serde(default)]
87 pub files: Vec<String>,
88}
89
90#[cfg(test)]
91#[allow(
92 clippy::unwrap_used,
93 clippy::expect_used,
94 clippy::panic,
95 clippy::indexing_slicing,
96 reason = "test code"
97)]
98mod tests;