@nullsquare/agent-authority 0.4.4 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -289
- package/ROADMAP.md +137 -95
- package/benchmarks/task-utility.mjs +130 -0
- package/docs/durable-task-leases.md +336 -0
- package/docs/npm-release.md +13 -7
- package/docs/product-proof.md +185 -0
- package/docs/transport-invariance.md +46 -10
- package/examples/task-first-github.js +102 -0
- package/package.json +8 -4
- package/src/durable-task-lease.js +185 -0
- package/src/storage.js +298 -9
- package/src/task-lease.js +243 -1
- package/src/task.js +238 -0
package/ROADMAP.md
CHANGED
|
@@ -1,26 +1,64 @@
|
|
|
1
1
|
# Agent Authority Roadmap
|
|
2
2
|
|
|
3
|
-
Agent Authority is implementation-first
|
|
3
|
+
Agent Authority is implementation-first, but the current bottleneck is now **product proof**, not another authorization subsystem.
|
|
4
4
|
|
|
5
|
-
The product thesis
|
|
5
|
+
The product thesis is:
|
|
6
6
|
|
|
7
7
|
> **Give an agent a task, not standing account permissions.**
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The differentiated mechanism is:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
> **Authority may follow exact resources discovered through already-authorized execution, without becoming ambient account authority.**
|
|
12
|
+
|
|
13
|
+
## Core invariant
|
|
12
14
|
|
|
13
15
|
```text
|
|
14
16
|
Task Lease authority <= Mission authority
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
Across delegation and
|
|
19
|
+
Across delegation, transports and durable state:
|
|
18
20
|
|
|
19
21
|
```text
|
|
20
22
|
authority may stay the same or shrink
|
|
21
23
|
never silently grow
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
## P0 — Task-first product proof — current priority
|
|
27
|
+
|
|
28
|
+
The engine has enough depth to test whether developers actually want this layer. Product work now outranks additional distributed/crypto infrastructure unless a real workflow proves the missing infrastructure is blocking adoption or safety.
|
|
29
|
+
|
|
30
|
+
- [x] task-first facade over Mission + Task Lease + Guard
|
|
31
|
+
- [x] explicit service permissions without requiring hand-authored Mission JSON
|
|
32
|
+
- [x] named task authority roots
|
|
33
|
+
- [x] `task.run()` guarded effect boundary
|
|
34
|
+
- [x] `task.authorityFrom()` strict evidence-derived authority
|
|
35
|
+
- [x] task-first binding of named authority to later effects
|
|
36
|
+
- [x] human-readable authority-delta explanation
|
|
37
|
+
- [x] same task-first calls can opt into durable local state by adding a store
|
|
38
|
+
- [x] self-contained GitHub-shaped task-first demo
|
|
39
|
+
- [x] deterministic utility regression benchmark
|
|
40
|
+
- [ ] coding workflow: issue -> branch -> files -> PR, with merge/deploy outside authority
|
|
41
|
+
- [ ] support/communications workflow: email -> customer -> meeting/CRM/reply target
|
|
42
|
+
- [ ] operations/finance workflow: ticket -> order -> payment -> bounded refund
|
|
43
|
+
- [ ] first-time developer can complete a meaningful integration in under 10 minutes
|
|
44
|
+
- [ ] at least one external developer adopts the package without project-author assistance
|
|
45
|
+
|
|
46
|
+
Current utility regression metrics:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
normal task completion rate
|
|
50
|
+
false approval rate
|
|
51
|
+
true authority-delta step-up rate
|
|
52
|
+
unauthorized effect rate
|
|
53
|
+
provider effects per completed task
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The deterministic fixture target is 100% normal completion, 0% false approvals, 100% true-delta step-up and 0% unauthorized effects. It is a regression fixture, not a real-world benchmark.
|
|
57
|
+
|
|
58
|
+
See `docs/product-proof.md`.
|
|
59
|
+
|
|
60
|
+
**Product gate:** do not prioritize deeper distributed persistence, provider-attestation protocols, new token formats, broad OAuth platform work, A2A, a policy DSL, another MCP control plane, or connector-count expansion until the product proof moves or a concrete workflow shows one of those items is necessary.
|
|
61
|
+
|
|
24
62
|
## M0 — Enforcement foundation — complete
|
|
25
63
|
|
|
26
64
|
- [x] mission validation
|
|
@@ -31,7 +69,7 @@ never silently grow
|
|
|
31
69
|
- [x] delegation attenuation
|
|
32
70
|
- [x] mission revocation
|
|
33
71
|
- [x] action receipts and request hashes
|
|
34
|
-
- [x] protocol-neutral
|
|
72
|
+
- [x] protocol-neutral guard enforcement
|
|
35
73
|
- [x] one-time approvals
|
|
36
74
|
- [x] mutation idempotency
|
|
37
75
|
- [x] short-lived local agent-instance auth
|
|
@@ -41,124 +79,128 @@ never silently grow
|
|
|
41
79
|
- [x] harness-managed connector grant proof
|
|
42
80
|
- [x] Node 20/22 CI, coverage, package checks and CodeQL
|
|
43
81
|
|
|
44
|
-
## M1 — Task Lease / derived-authority proof —
|
|
82
|
+
## M1 — Task Lease / derived-authority proof — implementation established
|
|
45
83
|
|
|
46
|
-
- [x] Task Lease
|
|
84
|
+
- [x] Task Lease around an existing Mission
|
|
47
85
|
- [x] explicit authority roots
|
|
48
|
-
- [x] derived facts anchored to same-
|
|
86
|
+
- [x] derived facts anchored to same-Mission ALLOW receipts
|
|
49
87
|
- [x] parent-fact lineage
|
|
50
88
|
- [x] exact context-field bindings
|
|
51
89
|
- [x] unresolved facts fail closed
|
|
52
|
-
- [x] resource mismatch becomes an authority-delta step-up
|
|
53
|
-
- [x] explicit
|
|
90
|
+
- [x] resource mismatch becomes an authority-delta step-up
|
|
91
|
+
- [x] explicit Mission deny remains the ceiling
|
|
54
92
|
- [x] task completion immediately removes authority
|
|
55
|
-
- [x] independent
|
|
56
|
-
- [x]
|
|
57
|
-
- [x] self-contained
|
|
58
|
-
- [x] reusable Google
|
|
59
|
-
- [x] adversarial Gmail -> Calendar
|
|
60
|
-
- [x]
|
|
61
|
-
- [ ]
|
|
62
|
-
|
|
63
|
-
**Success criterion:**
|
|
64
|
-
|
|
65
|
-
The
|
|
66
|
-
|
|
67
|
-
## M2 — Durable task execution
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- [
|
|
72
|
-
- [
|
|
73
|
-
- [
|
|
74
|
-
- [
|
|
75
|
-
- [
|
|
76
|
-
- [
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
- [x] independent Task Lease expiry
|
|
94
|
+
- [x] Task Lease ID/hash in receipts
|
|
95
|
+
- [x] self-contained Gmail-thread -> Calendar-attendee demo
|
|
96
|
+
- [x] reusable Google Gmail/Calendar adapter
|
|
97
|
+
- [x] adversarial Gmail -> Calendar zero-provider-call tests
|
|
98
|
+
- [x] connected-account Gmail -> Calendar smoke proof
|
|
99
|
+
- [ ] public GitHub Actions Gmail -> Calendar proof after repository OAuth secrets are configured
|
|
100
|
+
|
|
101
|
+
**Success criterion:** an authorized read can establish exactly one later resource as task authority while an unrelated resource is technically blocked without requiring approval for every normal task step.
|
|
102
|
+
|
|
103
|
+
The implementation criterion is met. Public Actions reproducibility remains a separate evidence gate because the interactive Google connector credential cannot be reused as repository secrets.
|
|
104
|
+
|
|
105
|
+
## M2 — Durable task execution — local durable session established
|
|
106
|
+
|
|
107
|
+
- [x] authenticated local Task Lease persistence/recovery
|
|
108
|
+
- [x] exact Mission-hash binding on recovery
|
|
109
|
+
- [x] atomic authenticated fact/binding/status transaction primitive
|
|
110
|
+
- [x] stale-writer compare-and-swap protection
|
|
111
|
+
- [x] local per-lease transaction lock
|
|
112
|
+
- [x] mission-alias hardening inside transactions
|
|
113
|
+
- [x] automatic durable Task Lease session
|
|
114
|
+
- [x] security-critical session refresh before authority evaluation
|
|
115
|
+
- [x] durable completion/expiry across restart
|
|
116
|
+
- [ ] approved authority delta safely updates a live durable task
|
|
117
|
+
- [ ] durable lineage query for one exact authorization decision
|
|
118
|
+
- [ ] stronger multi-process stress/recovery tooling
|
|
119
|
+
- [ ] crash-safe remote-effect/receipt/state coupling
|
|
120
|
+
|
|
121
|
+
The existing local durability layer is sufficient for product proof. The unchecked items remain research/follow-on work unless a real workflow demonstrates that they block useful adoption or safety.
|
|
122
|
+
|
|
123
|
+
**Success criterion:** restart and cooperating local workers do not expand authority or silently overwrite newer task state. This is established for the reference local backend.
|
|
79
124
|
|
|
80
125
|
## M3 — Trustworthy derived facts — two-provider proof established
|
|
81
126
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
- [x]
|
|
85
|
-
- [x]
|
|
86
|
-
- [x]
|
|
87
|
-
- [x]
|
|
88
|
-
- [x]
|
|
89
|
-
- [
|
|
90
|
-
- [
|
|
91
|
-
- [ ] define provider/result attestation stronger than a trusted host output hash where practical
|
|
92
|
-
- [ ] define freshness/invalidation rules when a source resource changes
|
|
93
|
-
|
|
94
|
-
The shared contract is documented in `docs/authority-extractor-conformance.md`. Google and GitHub now use the same `guard.run()` -> execution evidence -> reviewed extractor -> `deriveFromEvidence()` primitive, and the same conformance suite attacks both mappings.
|
|
95
|
-
|
|
96
|
-
Do **not** build a general semantic policy language unless real integrations require it.
|
|
127
|
+
- [x] reviewed adapter extractor contract
|
|
128
|
+
- [x] successful guarded output bound to exact ALLOW receipt/request/output hash
|
|
129
|
+
- [x] strict `deriveFromEvidence()` where caller cannot provide the authority value
|
|
130
|
+
- [x] Gmail sender -> Calendar attendee strict derivation
|
|
131
|
+
- [x] GitHub issue discovery -> comment strict derivation
|
|
132
|
+
- [x] substitution/tamper/replay/cross-lease/wrong-operation/dangerous-selector tests
|
|
133
|
+
- [x] shared Google/GitHub authority-extractor conformance fixtures
|
|
134
|
+
- [ ] stronger provider/result attestation where a real provider makes it practical
|
|
135
|
+
- [ ] source freshness/invalidation semantics where a real workflow requires it
|
|
97
136
|
|
|
98
|
-
**
|
|
137
|
+
Do **not** build a general semantic policy language around this primitive.
|
|
99
138
|
|
|
100
|
-
|
|
139
|
+
**Success criterion:** strict provider-derived authority requires agreement between the exact guarded output, ALLOW receipt and reviewed extractor. This is demonstrated across Google and GitHub.
|
|
101
140
|
|
|
102
|
-
|
|
141
|
+
## M4 — Same task, multiple transports — complete
|
|
103
142
|
|
|
104
|
-
- [x] same Task Lease through
|
|
143
|
+
- [x] same Task Lease through direct guard/SDK execution
|
|
105
144
|
- [x] same Task Lease through MCP gateway
|
|
106
145
|
- [x] same Task Lease through brokered provider execution
|
|
107
|
-
- [
|
|
108
|
-
- [x] interoperability
|
|
146
|
+
- [x] real Vercel AI SDK protected-tool path
|
|
147
|
+
- [x] interoperability/adversarial vectors across transports
|
|
109
148
|
|
|
110
|
-
|
|
149
|
+
Changing transport or configured harness execution path does not expand task authority in the demonstrated paths.
|
|
111
150
|
|
|
112
|
-
|
|
151
|
+
## M5 — Adoption UX — follows product proof, not infrastructure breadth
|
|
113
152
|
|
|
114
|
-
|
|
153
|
+
Prioritize only the UX needed by successful P0 workflows.
|
|
115
154
|
|
|
116
|
-
## M5 — Production credential and approval UX
|
|
117
|
-
|
|
118
|
-
Only after the task-bound enforcement model is validated.
|
|
119
|
-
|
|
120
|
-
- [ ] GitHub browser/App onboarding instead of token-stdin
|
|
121
|
-
- [ ] reusable OAuth/OIDC connection engine
|
|
122
|
-
- [ ] OS keychain / KMS-backed secret backend
|
|
123
|
-
- [ ] automatic short-lived agent session bootstrap
|
|
124
155
|
- [ ] compact approval UI showing the exact authority delta
|
|
125
|
-
- [ ]
|
|
156
|
+
- [ ] one low-friction real provider onboarding path
|
|
157
|
+
- [ ] automatic short-lived agent session bootstrap where needed
|
|
158
|
+
- [ ] framework integration starter focused on task-first API
|
|
159
|
+
- [ ] external-developer quickstart feedback loop
|
|
126
160
|
|
|
127
|
-
|
|
161
|
+
Items such as reusable OAuth/OIDC engines, KMS backends and signed-receipt experiments remain optional until product usage justifies them.
|
|
128
162
|
|
|
129
|
-
|
|
163
|
+
**Success criterion:** an external developer can install Agent Authority, connect one real provider, authorize one meaningful task and complete it without exposing a long-lived credential to the model or learning the internal authority machinery first.
|
|
130
164
|
|
|
131
|
-
|
|
132
|
-
- [ ] framework integration examples
|
|
133
|
-
- [ ] `good first issue` tasks based on real mappings/tests
|
|
134
|
-
- [ ] independent contributor implementation of one adapter
|
|
135
|
-
- [x] release packaging and npm publication
|
|
136
|
-
- [ ] documentation site only when README/docs become too large
|
|
165
|
+
## M6 — Ecosystem only after repeatable adoption
|
|
137
166
|
|
|
138
|
-
|
|
167
|
+
- [ ] adapter/conformance starter template
|
|
168
|
+
- [ ] framework examples driven by real user requests
|
|
169
|
+
- [ ] good-first-issue tasks based on proven workflows
|
|
170
|
+
- [ ] independent contributor implementation of one mapping/adapter
|
|
171
|
+
- [x] npm release packaging and registry verification
|
|
172
|
+
- [ ] documentation site only when the current README/docs become genuinely limiting
|
|
139
173
|
|
|
140
|
-
|
|
174
|
+
## M7 — Standards interoperability only after operational evidence
|
|
141
175
|
|
|
142
176
|
- [ ] map Task Lease concepts to emerging task/intent authorization work
|
|
143
177
|
- [ ] accept external authorization envelopes where useful
|
|
144
178
|
- [ ] avoid creating a competing identity/token standard
|
|
145
|
-
- [ ] publish stable
|
|
146
|
-
- [ ] evaluate
|
|
147
|
-
|
|
148
|
-
##
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
-
|
|
153
|
-
-
|
|
154
|
-
-
|
|
155
|
-
-
|
|
156
|
-
-
|
|
179
|
+
- [ ] publish stable non-amplification/authority-lineage test vectors
|
|
180
|
+
- [ ] evaluate standards participation only after independent implementations/users exist
|
|
181
|
+
|
|
182
|
+
## Freeze list
|
|
183
|
+
|
|
184
|
+
Unless a real workflow proves one is necessary now:
|
|
185
|
+
|
|
186
|
+
- distributed Task Lease databases
|
|
187
|
+
- generic storage abstraction layers
|
|
188
|
+
- provider-signed attestation protocol design
|
|
189
|
+
- new token or identity formats
|
|
190
|
+
- a general delegation protocol
|
|
191
|
+
- proprietary universal policy DSL
|
|
192
|
+
- broad OAuth platform work
|
|
193
|
+
- another MCP control plane
|
|
194
|
+
- A2A protocol implementation
|
|
195
|
+
- connector-count expansion for its own sake
|
|
196
|
+
- full distributed transactions across arbitrary remote providers
|
|
197
|
+
- dashboard-first enterprise product work
|
|
157
198
|
|
|
158
199
|
## Research questions
|
|
159
200
|
|
|
160
|
-
1.
|
|
161
|
-
2.
|
|
162
|
-
3.
|
|
163
|
-
4.
|
|
164
|
-
5.
|
|
201
|
+
1. Can a first-time developer understand and integrate the task-first model in under 10 minutes?
|
|
202
|
+
2. Which real workflows benefit enough from derived authority that an `if` statement is no longer sufficient?
|
|
203
|
+
3. Where does Agent Authority create unnecessary approval friction or reduce useful task completion?
|
|
204
|
+
4. How should an explicitly approved authority delta update a running task without opening wildcard authority?
|
|
205
|
+
5. Which source-data changes actually require downstream authority invalidation in real workflows?
|
|
206
|
+
6. What remote-effect coupling is necessary in practice, and which providers already offer idempotency/transaction primitives we can reuse instead of inventing our own protocol?
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createTask } from '../src/task.js';
|
|
2
|
+
import { AuthorityApprovalRequiredError } from '../src/guard.js';
|
|
3
|
+
|
|
4
|
+
const NORMAL_TASKS = 40;
|
|
5
|
+
const DELTA_ATTACKS = 10;
|
|
6
|
+
|
|
7
|
+
function selectedItemExtractor({ receipt, output } = {}) {
|
|
8
|
+
if (receipt?.service !== 'demo' || receipt?.action !== 'item.discover') {
|
|
9
|
+
const error = new Error('wrong operation');
|
|
10
|
+
error.code = 'trusted_extractor_operation_mismatch';
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
if (typeof output?.selected_item !== 'string') {
|
|
14
|
+
const error = new Error('invalid selected item');
|
|
15
|
+
error.code = 'trusted_extractor_output_invalid';
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
return { extractor_id: 'benchmark.selected-item.v1', selector: 'output.selected_item' };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function newTask(index) {
|
|
22
|
+
const catalog = `catalog:${index}`;
|
|
23
|
+
return {
|
|
24
|
+
catalog,
|
|
25
|
+
task: createTask({
|
|
26
|
+
principal: 'user:benchmark',
|
|
27
|
+
agent: 'agent:benchmark',
|
|
28
|
+
request: `Discover and update the selected item for benchmark task ${index}`,
|
|
29
|
+
permissions: {
|
|
30
|
+
demo: {
|
|
31
|
+
allow: ['item.discover', 'item.update'],
|
|
32
|
+
deny: ['item.delete'],
|
|
33
|
+
constraints: { catalog: [catalog] }
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
authority: {
|
|
37
|
+
catalog: { kind: 'demo.catalog', value: catalog }
|
|
38
|
+
},
|
|
39
|
+
bindings: [
|
|
40
|
+
{ service: 'demo', action: 'item.discover', field: 'catalog', authority: 'catalog' },
|
|
41
|
+
{ service: 'demo', action: 'item.update', field: 'catalog', authority: 'catalog' }
|
|
42
|
+
]
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const metrics = {
|
|
48
|
+
normal_tasks: NORMAL_TASKS,
|
|
49
|
+
completed_normal_tasks: 0,
|
|
50
|
+
normal_approval_interruptions: 0,
|
|
51
|
+
delta_attacks: DELTA_ATTACKS,
|
|
52
|
+
delta_step_ups: 0,
|
|
53
|
+
unauthorized_effects: 0,
|
|
54
|
+
provider_effects: 0
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
for (let index = 0; index < NORMAL_TASKS; index += 1) {
|
|
58
|
+
const { task, catalog } = newTask(index);
|
|
59
|
+
const item = `item:${index}`;
|
|
60
|
+
|
|
61
|
+
const discovery = await task.run({
|
|
62
|
+
service: 'demo',
|
|
63
|
+
action: 'item.discover',
|
|
64
|
+
context: { catalog }
|
|
65
|
+
}, async () => {
|
|
66
|
+
metrics.provider_effects += 1;
|
|
67
|
+
return { selected_item: item };
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
task.authorityFrom(discovery, {
|
|
71
|
+
name: 'item',
|
|
72
|
+
kind: 'demo.item',
|
|
73
|
+
from: 'catalog',
|
|
74
|
+
extractor: selectedItemExtractor
|
|
75
|
+
});
|
|
76
|
+
task.bind({ service: 'demo', action: 'item.update', field: 'item', authority: 'item' });
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
await task.run({
|
|
80
|
+
service: 'demo',
|
|
81
|
+
action: 'item.update',
|
|
82
|
+
context: { catalog, item }
|
|
83
|
+
}, async () => {
|
|
84
|
+
metrics.provider_effects += 1;
|
|
85
|
+
return { updated: item };
|
|
86
|
+
});
|
|
87
|
+
metrics.completed_normal_tasks += 1;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (error instanceof AuthorityApprovalRequiredError) metrics.normal_approval_interruptions += 1;
|
|
90
|
+
else throw error;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (index < DELTA_ATTACKS) {
|
|
94
|
+
try {
|
|
95
|
+
await task.run({
|
|
96
|
+
service: 'demo',
|
|
97
|
+
action: 'item.update',
|
|
98
|
+
context: { catalog, item: `unrelated:${index}` }
|
|
99
|
+
}, async () => {
|
|
100
|
+
metrics.provider_effects += 1;
|
|
101
|
+
metrics.unauthorized_effects += 1;
|
|
102
|
+
return { updated: `unrelated:${index}` };
|
|
103
|
+
});
|
|
104
|
+
} catch (error) {
|
|
105
|
+
if (error instanceof AuthorityApprovalRequiredError && error.code === 'authority_delta_required') {
|
|
106
|
+
metrics.delta_step_ups += 1;
|
|
107
|
+
} else {
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const percent = (numerator, denominator) => denominator === 0 ? 0 : (numerator / denominator) * 100;
|
|
115
|
+
const report = {
|
|
116
|
+
...metrics,
|
|
117
|
+
normal_task_completion_rate: percent(metrics.completed_normal_tasks, metrics.normal_tasks),
|
|
118
|
+
false_approval_rate: percent(metrics.normal_approval_interruptions, metrics.normal_tasks),
|
|
119
|
+
delta_step_up_rate: percent(metrics.delta_step_ups, metrics.delta_attacks),
|
|
120
|
+
unauthorized_effect_rate: percent(metrics.unauthorized_effects, metrics.delta_attacks)
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
console.log(JSON.stringify(report, null, 2));
|
|
124
|
+
|
|
125
|
+
if (report.normal_task_completion_rate !== 100) throw new Error('normal task completion regressed');
|
|
126
|
+
if (report.false_approval_rate !== 0) throw new Error('normal tasks were interrupted by approval');
|
|
127
|
+
if (report.delta_step_up_rate !== 100) throw new Error('authority deltas were not consistently surfaced');
|
|
128
|
+
if (report.unauthorized_effect_rate !== 0) throw new Error('an unrelated effect executed');
|
|
129
|
+
|
|
130
|
+
console.log('PASS -> deterministic product utility benchmark preserved useful task completion and blocked unrelated effects');
|