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
// SPDX-License-Identifier: Apache-2.0
//! The third check that reads a lifecycle regime, and the first that is about
//! a document the corpus no longer holds.
//!
//! [Spec 3](../../../../docs/spec/03-authoring-and-lifecycle.md#lifecycle)
//! rules that "terminal states marked `retain_terminal: true` may never be
//! deleted. Lineage is the point."
//! [Spec 2](../../../../docs/spec/02-taxonomy-model.md#shape)
//! declares the member on a lifecycle regime, the meta-schema types it
//! `boolean`, `taxonomy validate` refuses a value that is not one, and both
//! regimes of the base package have written `true` since 1.0.0. Nothing read
//! it. A member a corpus writes and no component reads is a promise the
//! taxonomy makes and cannot keep, and this is the component that keeps it.
//!
//! # A deletion is a fact about a change, so the grain is the corpus
//!
//! [`crate::transition`] reads one document against the version of itself that
//! stood before a change. That grain cannot reach this defect: a document the
//! change deleted has no row in the census, so no document-scoped instance is
//! generated over it, and the rule that would refuse the deletion is never
//! instantiated. So this check is corpus-grained and declares
//! `CorpusCheck::NEEDS_PRIOR`, which hands it every path the change named that
//! this corpus holds no row at, and the version of each one.
//!
//! One instance covers the whole change. A run that names no change skips it
//! with the reason spec 12 fixes, exactly as an instance of the two
//! document-scoped rules that declare the same input does.
//!
//! # A rename is not a deletion, and nothing here decides that
//!
//! The producer turns git's similarity detection on, so a renamed document
//! reaches the engine as one `prior` line naming the path the document arrived
//! at. The census holds a row there, so the entry binds, and it never reaches
//! [`crate::change::Change::departed`] at all. A document moved out of the
//! corpus root does reach it, and that is a departure by every reading this
//! engine has: no shelf places it, no rule runs over it, and no index names it.
//!
//! The trust boundary is the producer's, and [`crate::change`] states it: a
//! caller that turned similarity detection off would present a rename as a
//! deletion and an addition, and this rule would refuse the deletion. That is
//! the honest failure. The alternative is an engine that walks history, which
//! spec 12 rules out as an input.
//!
//! # What it reads out of the declaration, and the three answers
//!
//! The kind comes from the path and the prior front matter, through the same
//! resolver the census used, so a departed document is classified by the
//! declaration rather than by a guess. The kind binds a lifecycle regime, and
//! the regime answers three ways.
//!
//! - `retain_terminal: true` — a document standing at a terminal state of this
//! regime is kept, and a change that deletes one is refused.
//! - `retain_terminal: false` — the regime has ruled that the deletion is
//! permitted, and this reports nothing.
//! - the member is absent — the regime has said nothing, and this reports
//! nothing either.
//!
//! The last two produce one behavior and they are not one fact.
//! [`crate::shape::LifecycleRegime::retain_terminal`] keeps them apart at the
//! parse, so the day a rule has something different to say about silence, the
//! difference is still there to read. No regime in this repository declares
//! `false`; the fixture taxonomy under `engine/crates/check/fixtures/` does,
//! and it is what holds that arm to a behavior.
//!
//! # Terminal is the role and the machine, and they name one set
//!
//! A state is terminal when the regime names it and it reaches nothing, which
//! is [`crate::shape::LifecycleRegime::terminal`] and the same reading
//! [`crate::transition`] takes. [`crate::dependency`] takes the other reading:
//! the `terminal-` role that the state vocabulary gives the value, which is
//! [`crate::lifecycle_state::StateFacet::standing`].
//!
//! The two name one set over every taxonomy the resolver accepts. `lifecycle
//! soundness` refuses a regime that reaches a state with no exit and no such
//! role, and it refuses a regime that reaches a role-terminal state and gives
//! it an exit. [Spec
//! 3](../../../../docs/spec/03-authoring-and-lifecycle.md#lifecycle) states the
//! pair, and `regimes.lifecycle` declares no `terminal` member for a third way
//! to say it.
//!
//! A shape built from source rather than resolved still holds two readings that
//! differ, and `lifecycle_state.rs` carries the case that says so. This layer
//! re-runs no resolver rule over the lock it reads.
//!
//! # The severity is an error, and the finding carries no patch
//!
//! The remedy is mechanical and total: put the file back. That is the
//! [fixability](../../../../docs/spec/12-check-layer.md#fixability) bar, so the
//! rule is an error and the commit gate refuses the change. Nothing is written,
//! because this engine holds the prior front matter and not the prior body: a
//! patch that restored the file from what a check received would restore half
//! of it.
use crate;
use crateOutcome;
use crate;
use crate;
use crateShape;
use Taxonomy;
pub const RULE: &str = "lifecycle.deletion.not_permitted";
/// The check. It carries the taxonomy because a departed path has no census
/// row to read a kind off, and the shape because the regime it holds the
/// document to is declared rather than known.
/// The reason a corpus with no state facet carries. See [`Retention::evaluate`].
const NO_STATE_FACET: &str =
"this taxonomy declares no facet in the `state` role, so no document stands anywhere and no \
departure can be held to a terminal state";