wire/answer/commits.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 the city says about a commit it made: one, by oid, or a page of
7//! them, newest first.
8//!
9//! Its own file so that the two questions share one vocabulary in one
10//! place: a commit is the same eight facts whether it was looked up or
11//! listed, and a second shape for the list would be a second authority
12//! on what a commit is.
13
14use kernel::{Address, B3Hash, Effort, GitOid, RunId, Seq, SessionName, TimeMs, UsdMicros};
15use serde::{Deserialize, Serialize};
16
17/// Which run wrote one commit, in the words the commit's own git
18/// trailers use.
19///
20/// Four of the five trailers appear here; `Sprawling-City` does not,
21/// because whoever asked this question already holds the city. `seq` is
22/// what the trailers cannot carry: where in the one history the line
23/// announcing this commit sits, so a reader can go on from there.
24#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
25#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
26pub struct CommitAnswer {
27 pub oid: GitOid,
28 pub run: RunId,
29 /// `Sprawling-Actor`: the address the run worked at.
30 pub actor: Address,
31 /// `Sprawling-Model`. Empty when the record predates the city
32 /// writing the model down: an absent id beats an invented one.
33 pub model: String,
34 /// `Sprawling-Effort`. Absent leaves the choice to the provider,
35 /// which is not the same fact as `Effort::None`.
36 pub effort: Option<Effort>,
37 /// Where the line announcing this commit sits in the one history.
38 pub seq: Seq,
39 /// When that line was written: the record's own clock, so a list
40 /// of commits reads as a day rather than as a column of numbers.
41 pub at: TimeMs,
42 /// What a person called this line of work, read off the room the
43 /// actor worked in. Absent when the run worked at a building's own
44 /// address, which is a run nobody opened a session for.
45 pub session: Option<SessionName>,
46 /// This run first, then each run it replaced by succession, back to
47 /// the first. One entry for a run that replaced nobody.
48 pub lineage: Vec<RunId>,
49 /// What the run that wrote this commit has been billed, whole.
50 ///
51 /// The run's total rather than this commit's share: a commit is a
52 /// checkpoint and nothing prices a checkpoint, so dividing the run's spend
53 /// between its checkpoints would be a number nobody measured. Zero for
54 /// a run no priced call is attributed to.
55 pub spent: UsdMicros,
56 /// The commit the same run announced last before this one; `None`
57 /// for the run's first. The two bound what this commit is the
58 /// result of: `Query::Changes` from `previous.oid` to `oid` says
59 /// which files moved, and `Query::RunHistory` read back from `seq`
60 /// to `previous.seq` says which calls the run made meanwhile - as
61 /// candidates, since another run in the same building may have
62 /// written in that span too.
63 pub previous: Option<CommitAt>,
64 /// The commit object's own parents, in git's order: an empty list
65 /// is a root commit. `None` when the city has no repository beside
66 /// it, the repository does not hold this object, or it could not be
67 /// read - the other facts still stand without it.
68 pub parents: Option<Vec<GitOid>>,
69 /// The commit object's own message, trailers included, read when
70 /// the parents are and absent for the same reasons, or when it is
71 /// not UTF-8 (`crates/wire/spec/Answer/Commits.lean` §8-54).
72 pub message: Option<String>,
73 /// The BLAKE3 of the canonical bytes of the line that announced this
74 /// commit - the digest the next line of the chain carries as `prev`,
75 /// not this line's own `prev`. A person finds the line by it and
76 /// checks it was not altered. `None` only in a frame from a city
77 /// written before it was answered (`crates/wire/Spec.lean` §8-78).
78 #[serde(default)]
79 pub b3: Option<B3Hash>,
80}
81
82/// A commit, and where in the one history the line announcing it sits.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
84#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
85pub struct CommitAt {
86 pub oid: GitOid,
87 pub seq: Seq,
88}
89
90/// One page of the commits a city made, newest first.
91///
92/// `building` and `before` are the question handed back: the wire
93/// carries no request id, so a page matches an answer to what it asked
94/// by content, the way `ChangesAnswer` carries `base` and `head`. `more`
95/// rather than a cursor: the next page begins before the last `seq`
96/// here, which the reader already holds.
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
99pub struct CommitsAnswer {
100 pub building: Option<Address>,
101 pub before: Option<Seq>,
102 pub commits: Vec<CommitAnswer>,
103 pub more: bool,
104}