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
//! The **judgment fold** (VISION §4.11 items 4, 6, 7; DESIGN §8.6): a class, the
//! shipped default table, and the two kinds of operator answer the ops trail
//! already carries.
//!
//! The control writes nothing, ever — the seam re-adjudicates a held invocation
//! on every later drive, so a consult with a side effect would answer
//! differently the second time. Everything it needs therefore has a home
//! somewhere else already:
//!
//! - the **request** is litany's own hold mark, written by the seam;
//! - **standing policy** is the shipped [`Table`], overridden row by row by the
//! workspace's own [`Policy`](super::policy::Policy) when it declares one —
//! absence *is* the defaults, the `cadence.yaml` severability pattern;
//! - **answers** are `ops.jsonl` rows, which are at once the audit and this
//! fold's memory. No new durable artifact; I2 holds at three.
//!
//! Two answer kinds, and only two:
//!
//! 1. A **once-answer** scoped to one `tool_use` id. The id is provider-unique,
//! so the grant needs no consumption and cannot race: the same id is never
//! asked twice by two different invocations.
//! 2. A **floor** on a conversation — the alignment monitor's revoke rung
//! (bl-94b4) — under which every class above read adjudicates to a hold. It
//! matches by descent prefix, so revoking a conversation revokes its whole
//! subtree without enumerating one.
//!
//! Precedence is the operator's: a once-answer to *this exact* invocation wins
//! over the floor and over the table. The floor then raises whatever the table
//! said; it never lowers it, so a refusal stays a refusal.
//!
//! **Revocation binds at the next consult, never mid-window.** A verdict already
//! passed runs its one call; recalling it would mean stopping the agent, and a
//! stop mid-tool-window wedges the branch permanently.
use HashMap;
use Effect;
use Verdict;
use crate;
/// What the policy says about a class, before a reason is attached.
/// The class → ruling table: **everything passes except loss and credentials**.
/// An unattended drone is there to work, and a shipped hold on open-world made
/// the operator answer for every `python` and every fetch — approving what they
/// were always going to approve. So the four classes that are the job pass, and
/// only irreversible loss and credential access decline in band: those two are
/// what a drone must not decide for itself, and neither is answerable by
/// reflex.
///
/// **Hold is no longer standing policy; it is imposed.** Two mechanisms carry
/// the weight the shipped hold used to, and both aim it at the conversation
/// that earned it rather than at all of them:
///
/// - a workspace that wants the parked default writes one line of
/// `capability.yaml` — `table:` / ` open-world: hold` (see
/// [`Policy`](super::policy::Policy)); severability still runs the right way,
/// with absence the (now permissive) default and the file the override;
/// - the alignment monitor's revoke rung raises a per-conversation floor, under
/// which every class above read holds ([`Answers::floored`]).
///
/// **One exception, and it is not about a reach** (bl-72bd): the seventh class
/// [`Opaque`](Effect::Opaque) holds, because it is what the classifier says
/// when it could not read the invocation at all. bl-1ef1's argument does not
/// reach it — that argument was about parking effects the operator was always
/// going to approve, and this class is the one where nobody knows what is
/// being approved. A workspace that wants the old, open answer writes
/// `table:` / ` opaque: pass`, the same one line, the same way round.
;
/// The ops-row verb naming a once-answer to one held `tool_use`.
const ANSWER: &str = "answer";
/// The ops-row verb naming a per-conversation floor, raised or lowered.
const FLOOR: &str = "floor";
/// The floor's two states, as its row spells them.
const RAISE: &str = "raise";
const LOWER: &str = "lower";
/// The operator's answers, folded from the trail. Later rows supersede earlier
/// ones for the same key — the log is append-only, so the fold is the state.