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
//! BP-10 (COMPOSABLE-HARNESS-DESIGN.md §2 module 14 `trust`, catalog row
//! "Project/workspace trust gate"): the workspace-trust DECISION — the
//! prompt, its per-project persistence, and the three surfaces it gates.
//!
//! # What was missing, and what this is
//! `[capabilities.trust]` already existed and already bit: config-declared
//! plugin code was refused unless `default = "always"`, and a project-local
//! config file was stripped of the forbidden capability tables. What did not
//! exist was the PROMPT the row is named for — both parity presets ship
//! `default = "ask"`, and with nothing anywhere consuming
//! [`crate::plugins::TrustDecision::Ask`] that value resolved exactly like
//! `never`. This module is that consumer.
//!
//! # One engine, one door
//! A trust question is an [`crate::permissions::ApprovalRequest`] on the
//! SAME [`crate::permissions::PermissionsApprovalHandler`] every other `Ask`
//! in this crate is answered on — tool `"trust"`, subject the project root,
//! `raw_args` naming what is about to be loaded. There is no second prompt
//! type, no second handler trait, and no second cache.
//!
//! The door is installed on [`crate::Config::trust_handler`] rather than on
//! `Agent` (where [`crate::Agent::set_permissions_approval_handler`] puts
//! the tool-dispatch door), for one structural reason: every surface trust
//! gates — the system prompt's project instruction tier, plugin
//! registration, the CLI's `[hooks]` wiring — is decided BEFORE or DURING
//! `Agent` construction, so a handler installed after construction would
//! always arrive too late to be asked. `Config` is the artifact that exists
//! first.
//!
//! # Persisted, per project, and reversible
//! An answer of "yes, and don't ask again" is written to
//! `$SUPERCODE_HOME/trust/<project_tag>.json` — the same
//! `$SUPERCODE_HOME`-derived, `crate::checkpoint::project_tag`-keyed layout
//! `crate::checkpoint`'s shadow store and
//! `crate::permissions::default_approval_store` both use, so a project's
//! records sit together. Deleting that file (or calling [`revoke`]) forgets
//! the decision and the next load asks again. The file IS the state; there
//! is no second copy.
//!
//! # What happens with NO door installed, stated per surface
//! Fail-closed means different things for code and for text, and this
//! module does not pretend otherwise:
//!
//! The rule is one sentence: with no door, every surface resolves to its
//! PRE-BP-10 outcome. Plugin code is refused (`crate::plugins::is_trusted`
//! has always demanded an explicit `always`); lifecycle hooks are installed
//! and project instruction files are loaded (neither was ever gated). A new
//! gate must not change what an existing configuration does when there is
//! nobody to ask — it must change what happens when there IS. An explicit
//! `default = "never"` refuses all three regardless.
//!
//! That per-surface answer is the point of [`TrustSurface`]: the gate is
//! one decision, but each surface declares what "nobody answered" means for
//! it, instead of one blanket answer quietly being wrong for two thirds of
//! the callers.
use ;
use crate;
use crateTrustDecision;
/// What is being loaded, and therefore what an unanswerable trust question
/// means for it — see this module's doc comment.
/// The persisted per-project trust record. Deliberately one boolean in a
/// JSON object rather than a bare `true`: a future field (a manifest hash,
/// cx§7's "hash-trust") has somewhere to go without a format break.
/// The default per-project trust store for `cwd` —
/// `$SUPERCODE_HOME/trust/<project_tag>.json`. Transcribes
/// `crate::permissions::default_approval_store`, which itself transcribes
/// `crate::checkpoint`'s `default_shadow_root`: one layout for a project's
/// records, not three.
/// The store this config's trust decision is read from and written to.
/// A previously recorded decision for this project, if any. Any failure
/// (absent, unreadable, corrupt) is "no decision recorded" — which re-asks,
/// the safe direction.
/// Record a decision so the next process does not re-ask.
/// BP-10: forget this project's recorded trust decision — the reversibility
/// half. The next load asks again.
/// BP-10: is this workspace trusted to load `surface`?
///
/// Order, first answer wins:
///
/// 1. `[capabilities.trust] enabled = false` ⇒ there is NO trust gate, so
/// [`TrustSurface::undecided`] answers: config-declared code is still
/// refused (`plugins → trust` is a hard resolver dependency — plugins
/// cannot even be enabled without this module), project instruction
/// text is still loaded. Both are the pre-BP-10 behavior exactly; a
/// module nobody turned on must not silently acquire a new refusal.
/// 2. `default = "always"` ⇒ `true`; `default = "never"` ⇒ `false`. An
/// explicit answer is never overridden by a stale recorded one.
/// 3. A recorded per-project decision ⇒ that answer, without prompting.
/// 4. `default = "ask"` with a door installed ⇒ ASK, on the one engine's
/// handler. `AllowForSession` ("don't ask again") records the answer;
/// a one-shot `Allow` does not. A refusal records nothing, so a later
/// run asks again rather than remembering a "no" the user may have
/// meant only for that moment.
/// 5. `default = "ask"` with no door ⇒ [`TrustSurface::undecided`] — see
/// this module's doc comment for why that differs by surface.
/// Put the trust question to the door and act on the answer.