1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
//! Public wire DTO for the deterministic repo-fact report (`shipshape facts`).
//!
//! This is the versioned surface `/shipshape-init` (config generation) and the
//! readiness `audit` both read, so they never disagree on maturity or the gated
//! core (ADR-0001 §3). Its field names and shape are a faithful port of
//! homebase's `infer-repo-facts.py` JSON — `ecosystems`, `packages`, `has_ci`,
//! `tags`, `committers_total`/`committers_recent_year`, `inferred_maturity`, and
//! the rest — because the prose `/shipshape-init` skill already relies on those exact
//! names (SCHEMA.md §4 "maturity inference signals").
//!
//! Consumers read this document under the CLI's canonical `data` envelope:
//! `{schema_version, data: <this shape>, warnings}` — the same envelope every
//! `shipshape --json` command shares (`crate::SCHEMA_VERSION` versions that wire
//! envelope). Unlike the contract document, the facts report has no
//! source-level document version of its own (it is *derived*, never authored),
//! so the envelope's `schema_version` is the single version consumers gate on.
//!
//! The report **reuses** [`Ecosystem`] and [`Maturity`] from the canonical
//! contract model rather than restating their wire strings: facts and the
//! contract must agree on `"rust"` / `"mvp"` down to the byte, and sharing the
//! one enum is how that agreement is made structural instead of coincidental.
use Serialize;
use crate;
/// Distribution infrastructure discovered in the repository tree.
/// What one Cargo manifest says about publishing to crates.io.
///
/// This is deliberately tri-state: collapsing [`Self::Unknown`] into either
/// other value would turn an inconclusive read into a confident wrong statement.
/// These serialized variant names are part of the additive `facts` wire contract;
/// renaming one is a breaking change that requires a `schema_version` bump.
/// The resolved crates.io publish evidence read from one Cargo manifest.
/// The complete `shipshape facts --json` data payload.
///
/// [`Self::cargo_publish`] is additive to the original flat facts shape. It is
/// collected by the same detector function the contract normalizer calls for
/// its Cargo publish hard floor, preventing the inspectable report and the
/// enforcing decision from drifting apart.
/// The established base repo facts, flattened into [`FactsReport`] for
/// `shipshape facts` and consumed directly by internal release and audit logic.
///
/// Every field is always present (an empty/unborn repo still gets a defined
/// value for each), mirroring the Python detector's "exit 0 even for an empty
/// repo" contract.
// The report mirrors the Python detector's flat boolean signals; grouping them
// into sub-structs purely to satisfy the bool-count lint would diverge the wire
// shape from `infer-repo-facts.py` for no consumer benefit.
/// A Rust Cargo workspace's crates.io-**publishable** members and the
/// intra-workspace dependency edges among them — the graph the release planner
/// derives a dependency-ordered publish set from (`release-rust-workspace-multicrate`).
///
/// Off-wire plumbing carried on [`Facts::rust_workspace`]; see that field for why it
/// is not serialized. Members are listed in workspace declaration order (the planner
/// applies the topological ordering — a dependency before its dependents); only
/// members publishable to crates.io are included (a `publish = false` member, or one
/// restricted to a non-crates.io registry, is dropped, matching the cargo adapter's
/// cut-time `cargo metadata` filter).
/// One crates.io-publishable Cargo workspace member and its intra-workspace
/// (publishable) dependency crate names — a node in [`RustWorkspace`].
/// One detected package manifest and the name/version parsed from it.
// `package` is the field name `/shipshape-init` reads (SCHEMA.md §4); the
// struct-name-echo lint does not apply to a fixed wire contract.
/// The two maturity truth-table outputs (SCHEMA.md §4). Both can be `false`
/// (the tie case), which resolves to `mvp`; they are never both `true`
/// (`production` is checked first).