Commit 105f0c1
authored
docs(adr): amend ADR-130's approval-surface constraint and gate it (#800)
## Description
ADR-130 constraint 3 said `agent_approve` was "doubly unreachable for
non-admins today". It named two surfaces, both behind admin gates — and
**both still are**: `nrllm_runs` is `access => 'admin'`
(`Modules.php:299-301`) and the Playground is too (`:280-282`) with
`denyNonAdmin()` on its resume path.
**So the premise did not expire. A third surface arrived.**
`nrllm_aitasks` is `access => 'user'` and registers
`approve`/`submitInput` (`:342-344`, `:375-381`), so the enumeration
stopped being exhaustive against a module that did not exist when it was
written.
That distinction is the useful part. "The premise expired" reads as bad
luck. **"A constraint that enumerates surfaces is only as durable as the
enumeration"** is a failure mode a reviewer can guard against — and it
is the one that bit. The record even predicted its own trigger ("becomes
exercisable with the editing module") and the prediction left no mark
anywhere a change had to pass.
Which record made it reachable was **established, not assumed**: `git
log -S"nrllm_aitasks"` returns exactly one commit, `2ee16dfd feat:
editor-facing AI Tasks module (ADR-131)`; `git log
-S"AgentRunController::class"` returns that and the earlier admin-only
module; and ADR-131's own Consequences already said it in prose —
*"`agent_approve` through the shared approvals inbox (previously doubly
unreachable for non-admins)"*. The author saw the consequence and wrote
it down. Only the two lifecycle fields were missed. They are written
now, from both ends.
## What the constraint says instead
**Not module access alone.** Both the module tick in `be_groups` and the
grant are required, and neither substitutes for the other (ADR-131
decision 2).
Then three checks on the approve path, in the order `ResumeCoordinator`
evaluates them — which is not the order I first wrote, and the code was
allowed to decide:
1. `mayActOnRun()` (`:205`) — may this actor act on this run at all
2. ADR-172's `requiresSecondApprover` (`:222-226`) — optional, refuses
an approval from the run's own initiator
3. ADR-133's `approverRefusal()` (`:314`) — withholds the release of a
write the approver could not run themselves
Only the third releases the run, because only it had claimed anything.
`submitInput`'s own gates are recorded **beside** the list rather than
merged into it: it has no four-eyes check, and its `submitterRefusal`
examines every pending call rather than only those declaring a write.
## A prediction in prose is what failed, so the fix is a test
`ApprovalSurfaceInventoryTest` holds three lists: which modules register
the approval actions and under which `access`; which classes under
`Classes/Controller` reach `AgentRuntime::approve()`/`submitInput()`;
and that every AJAX route on
`resumeAction`/`submitInputAction`/`approveAction` opens with
`denyNonAdmin()`. It then requires ADR-130 to **name each module the
scan finds**, matched as a whole identifier.
That matching detail is not cosmetic. An earlier draft used
`assertStringContainsString`, and a module named `nrllm_run` satisfied
it through the existing `nrllm_runs` — a substring collision that let a
fourth surface through. A second control found worse: a fourth module
under a *different* controller was invisible to all three assertions and
the suite stayed fully green. Both holes are closed; each guard was then
seen to fail on the defect it exists for.
**The ADR states what the three lists do not cover**, because they do
not cover everything: a class outside `Classes/Controller`, exposed
under a fourth action name, still passes. That was tried and it stayed
green. Saying so is the point — the check exists to make this record's
enumeration falsifiable, not to become a second registry. An earlier
draft of this very paragraph also planted the literal `nrllm_run` into
the text as an example, which would itself have satisfied the naming
check for a module of that name; no example is given now, deliberately.
## Citation rot, found and fixed
Eleven line-anchored citations in ADR-169 and ADR-171 pointed at ranges
this amendment moved. One predated it: **ADR-171 cited
`ResumeCoordinator.php:204` for the `mayActOnRun` check, and that line
is blank** — the four-eyes commit inserted a guard above it four days
ago. The personas record rotted within a day of merging.
All eleven are recomputed. The general problem is filed as #793: 74 such
citations exist and `AdrLifecycleTest` checks `:ref:` targets but not
these.
## Related Issue
Closes #787 — whose own framing this change corrects; the correction is
a comment on the issue.
Also filed while sweeping: #791 (ADR-119 counts twelve submodules, there
are fourteen plus one outside), #792 (ADR-108/094 count 40/41 builtins,
there are 46), #793 (line-anchored citations rot unchecked).
## Type of Change
- [x] Documentation update
- [x] New test (a mechanical gate for this defect class)
## Deliberately not done
ADR-130 **constraint 4** is expired too — `tasks_manage` "does not exist
yet", and the editing module shipped without it. Its amender is ADR-169,
which is `:Status: Proposed`. The lifecycle forbids a proposal writing
`:Amends:`, so that amendment is owed by whichever change accepts
ADR-169. Pre-empting it would break the same rule in the other
direction.
## Gates
`ApprovalSurfaceInventoryTest` OK (4 tests, 79 assertions),
`AdrLifecycleTest` OK (6 tests, 1187 assertions), all three repo checks
exit 0.
`rector -n` at the CI-pinned PHP 8.2 did not run — `.Build` here is
resolved at 8.4 and `platform_check.php` fatals before it starts. One
new PHP file reaches CI without that gate having run locally.
## Checklist
- [x] My code follows the project's coding standards
- [x] I have added a test that proves the gate works, and watched each
assertion fail
- [x] I have updated the documentation accordingly
- [x] `CHANGELOG.md` entry under the existing `### Changed`
- [x] Both ends of the amend link written, verified by
`AdrLifecycleTest`
- [x] My changes generate no new warnings6 files changed
Lines changed: 532 additions & 31 deletions
File tree
- Documentation/Adr
- Tests/Unit/Configuration
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
68 | 90 | | |
69 | 91 | | |
70 | 92 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
| 8 | + | |
8 | 9 | | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| |||
75 | 77 | | |
76 | 78 | | |
77 | 79 | | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
| 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 | + | |
84 | 210 | | |
85 | 211 | | |
86 | 212 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
| 9 | + | |
| 10 | + | |
9 | 11 | | |
10 | 12 | | |
11 | 13 | | |
| |||
Lines changed: 5 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
243 | 243 | | |
244 | 244 | | |
245 | 245 | | |
246 | | - | |
247 | | - | |
| 246 | + | |
| 247 | + | |
248 | 248 | | |
249 | 249 | | |
250 | 250 | | |
| |||
277 | 277 | | |
278 | 278 | | |
279 | 279 | | |
280 | | - | |
| 280 | + | |
281 | 281 | | |
282 | 282 | | |
283 | 283 | | |
| |||
287 | 287 | | |
288 | 288 | | |
289 | 289 | | |
290 | | - | |
| 290 | + | |
291 | 291 | | |
292 | 292 | | |
293 | 293 | | |
| |||
Lines changed: 27 additions & 19 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
114 | | - | |
115 | | - | |
| 114 | + | |
| 115 | + | |
116 | 116 | | |
117 | 117 | | |
118 | 118 | | |
| |||
216 | 216 | | |
217 | 217 | | |
218 | 218 | | |
219 | | - | |
| 219 | + | |
220 | 220 | | |
221 | 221 | | |
222 | 222 | | |
| |||
234 | 234 | | |
235 | 235 | | |
236 | 236 | | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
241 | | - | |
242 | | - | |
243 | | - | |
244 | | - | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
245 | 251 | | |
246 | 252 | | |
247 | 253 | | |
| |||
253 | 259 | | |
254 | 260 | | |
255 | 261 | | |
256 | | - | |
257 | | - | |
258 | | - | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
259 | 267 | | |
260 | 268 | | |
261 | 269 | | |
| |||
281 | 289 | | |
282 | 290 | | |
283 | 291 | | |
284 | | - | |
| 292 | + | |
285 | 293 | | |
286 | 294 | | |
287 | 295 | | |
| |||
292 | 300 | | |
293 | 301 | | |
294 | 302 | | |
295 | | - | |
| 303 | + | |
296 | 304 | | |
297 | 305 | | |
298 | 306 | | |
299 | | - | |
300 | | - | |
| 307 | + | |
| 308 | + | |
301 | 309 | | |
302 | 310 | | |
303 | 311 | | |
| |||
368 | 376 | | |
369 | 377 | | |
370 | 378 | | |
371 | | - | |
| 379 | + | |
372 | 380 | | |
373 | 381 | | |
374 | 382 | | |
| |||
0 commit comments