wire/answer/building.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 one building says about itself: the rows of its plan, what is
7//! stuck and how much waits behind it, the goal it works towards, the
8//! documents it keeps and what it has filed. Read shapes only, cut out of
9//! `answer` so that file stays inside its budget; every name is
10//! re-exported from there and the public spelling is unchanged.
11
12use kernel::{
13 Address, McpServer, NodeId, Progress, PursuitState, PursuitVerdict, RoadmapStatus,
14 SandboxLimits,
15};
16use serde::{Deserialize, Serialize};
17
18/// A building's plan, as its own `Roadmap.md` states it.
19///
20/// `problems` carries the rows the table could not state — a row with a
21/// status outside the five words, a column count that is not six, or a
22/// dependency that runs in a circle. The interface shows them: a plan
23/// that quietly drops the lines it could not parse would report progress
24/// against a denominator nobody chose.
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
27pub struct BuildingProgress {
28 pub addr: Address,
29 pub progress: Progress,
30 pub problems: Vec<String>,
31 /// What is stuck, one line per cause. Never one per symptom: a plan
32 /// with one real problem sends one line, and the seventeen nodes
33 /// waiting behind it are a count on that line rather than seventeen
34 /// more of them.
35 pub blocked: Vec<BlockedLine>,
36 /// How many nodes could be started right now. The number that says
37 /// whether a city with a standing goal has anything left to do.
38 pub ready: u32,
39}
40
41/// One cause, and how much is waiting behind it.
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
44pub struct BlockedLine {
45 /// The node it is stuck at.
46 pub source: NodeId,
47 /// The whole sentence: which branch, which node, and why.
48 pub line: String,
49 /// How many other nodes cannot move until this one does.
50 pub waiting: u32,
51}
52
53/// One node of a building's plan, flattened for a renderer.
54///
55/// The tree travels as rows in reading order rather than as nested
56/// objects: every face the client draws — the list, the board, a branch
57/// summary — wants a different grouping, and a shape that favoured one
58/// of them would make the others re-flatten it.
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
61pub struct PlanRow {
62 pub node: NodeId,
63 pub item: String,
64 pub status: RoadmapStatus,
65 /// This node's share of the whole plan, in billionths.
66 pub share_ppb: u64,
67 pub needs: Vec<NodeId>,
68 /// Whether a run could take it right now.
69 pub ready: bool,
70 /// Whether it carries work of its own. Only leaves are counted, so a
71 /// renderer that showed branches in the same column as leaves would
72 /// be showing the same work twice.
73 pub leaf: bool,
74 pub evidence: Option<String>,
75}
76
77/// A city's standing goal, if it has one.
78///
79/// `verdict` is the city's own reading of whether there is anything left
80/// to do, so a page never has to work out the stop condition for itself
81/// — which is what would give the condition a second authority.
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
84pub struct PursuitLine {
85 pub addr: Address,
86 pub goal: String,
87 pub state: PursuitState,
88 /// The kind, never a sentence: a page takes the words for it from its
89 /// own language table.
90 pub verdict: PursuitVerdict,
91}
92
93/// One document of a building, as it stands on disk.
94///
95/// The text is bounded: these files are written by agents over months,
96/// and a page that ships an unbounded file has no answer for the day one
97/// of them reaches a hundred megabytes. When it is cut, it says so -
98/// silence about a cut is the difference between a view and a lie.
99#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
100#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
101pub struct BuildingDoc {
102 pub name: String,
103 pub text: String,
104 pub bytes: u64,
105 pub truncated: bool,
106}
107
108/// One line of a building's archive index.
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
111pub struct ArchiveLine {
112 pub kind: String,
113 /// Whole days since the epoch, as the archive files them.
114 pub day: u64,
115 pub subject: String,
116}
117
118/// What one building is: its plan, its own documents, its rooms and what
119/// it has filed. The answer a person reads when they ask "what happened
120/// in there".
121#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
122#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
123pub struct BuildingAnswer {
124 pub addr: Address,
125 pub progress: Progress,
126 /// Rows of the plan this build could not read. Shown, never dropped.
127 pub problems: Vec<String>,
128 /// The plan tree, in reading order. Empty when the plan does not
129 /// parse, which `problems` then explains.
130 pub plan: Vec<PlanRow>,
131 /// What is stuck, one line per cause.
132 pub blocked: Vec<BlockedLine>,
133 pub rooms: Vec<String>,
134 pub docs: Vec<BuildingDoc>,
135 pub archive: Vec<ArchiveLine>,
136 /// What this building's own layer states its runs may reach. The
137 /// resolved value is the ladder's; this is the rung a person edits,
138 /// so a form that showed the resolved value would silently rewrite
139 /// what a city-wide setting had said.
140 pub sandbox: Option<SandboxLimits>,
141 pub mcp: Vec<McpServer>,
142}