@nullsquare/agent-authority 0.4.1 → 0.4.3

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 CHANGED
@@ -8,9 +8,9 @@
8
8
 
9
9
  **Agent Authority turns a human-approved task into temporary execution authority, then keeps that authority bounded as the agent discovers resources, crosses tools, and performs side effects.**
10
10
 
11
- [Task Leases](docs/task-leases.md) · [Validate](docs/validation.md) · [Integration contract](docs/integration-contract.md) · [CLI](docs/cli.md) · [Architecture](docs/architecture.md) · [Roadmap](ROADMAP.md) · [Contributing](CONTRIBUTING.md)
11
+ [Task Leases](docs/task-leases.md) · [Validate](docs/validation.md) · [Google proof](docs/live-google-validation.md) · [Integration contract](docs/integration-contract.md) · [CLI](docs/cli.md) · [Architecture](docs/architecture.md) · [Roadmap](ROADMAP.md) · [Contributing](CONTRIBUTING.md)
12
12
 
13
- > **Status: public pre-alpha / v0.4.0 Developer Preview.** Published on npm as `@nullsquare/agent-authority`. The repository has a working policy runtime, protocol-neutral guard, Task Lease prototype with provenance-bound derived facts, approvals, revocation, idempotency, credential isolation, MCP v2 gateway, GitHub brokered execution, CI and CodeQL. It is not production-ready yet.
13
+ > **Status: public pre-alpha / v0.4.2 Developer Preview.** Published on npm as `@nullsquare/agent-authority`. The repository has a working policy runtime, protocol-neutral guard, Task Lease prototype, execution-bound derived facts, approvals, revocation, idempotency, credential isolation, MCP v2 gateway, GitHub and Google provider integrations, CI and CodeQL. It is not production-ready yet.
14
14
 
15
15
  </div>
16
16
 
@@ -97,6 +97,12 @@ Human-approved task
97
97
  Gmail thread #91
98
98
  |
99
99
  authorized read
100
+ |
101
+ +--> ALLOW receipt
102
+ +--> exact output hash evidence
103
+ |
104
+ v
105
+ reviewed adapter extractor
100
106
  |
101
107
  v
102
108
  derived fact
@@ -152,12 +158,15 @@ The demo performs this flow without provider credentials:
152
158
 
153
159
  The side-effect callbacks for blocked actions never run.
154
160
 
161
+ The repository also includes a real Gmail → Calendar validation path and a reusable Google provider adapter. The stricter v0.4.2 path binds the derived sender to the exact guarded output before it becomes authority. See [Live Gmail → Calendar validation](docs/live-google-validation.md) and [Executable Evidence](docs/evidence.md).
162
+
155
163
  ## Minimal developer API
156
164
 
157
165
  ```js
158
166
  import { AuthorityRuntime } from '@nullsquare/agent-authority';
159
167
  import { createTaskLease } from '@nullsquare/agent-authority/task-lease';
160
168
  import { createTaskLeaseGuard } from '@nullsquare/agent-authority/guard';
169
+ import { gmailThreadSenderAuthorityExtractor } from '@nullsquare/agent-authority/providers/google';
161
170
 
162
171
  const lease = createTaskLease({
163
172
  mission,
@@ -169,7 +178,7 @@ const lease = createTaskLease({
169
178
  {
170
179
  service: 'calendar',
171
180
  action: 'event.create',
172
- context_field: 'attendee',
181
+ context_field: 'attendee_email',
173
182
  fact_id: 'fact:sender-email'
174
183
  }
175
184
  ]
@@ -183,25 +192,30 @@ const guard = createTaskLeaseGuard({
183
192
  const read = await guard.run({
184
193
  service: 'gmail',
185
194
  action: 'thread.read',
186
- context: { thread: 'thread:demo-91' }
195
+ context: { thread_id: 'thread:demo-91' }
187
196
  }, () => gmail.readThread('thread:demo-91'));
188
197
 
189
- lease.derive({
198
+ const senderFact = lease.deriveFromEvidence({
190
199
  fact_id: 'fact:sender-email',
191
200
  kind: 'email.address',
192
- value: read.output.sender,
193
201
  from: ['fact:thread'],
194
202
  receipt: read.receipt,
195
- selector: 'output.sender'
203
+ evidence: read.evidence,
204
+ output: read.output,
205
+ extractor: gmailThreadSenderAuthorityExtractor
196
206
  });
197
207
 
198
208
  await guard.run({
199
209
  service: 'calendar',
200
210
  action: 'event.create',
201
- context: { attendee: read.output.sender }
202
- }, () => calendar.createEvent({ attendee: read.output.sender }));
211
+ context: { attendee_email: senderFact.value }
212
+ }, () => calendar.createEvent({ attendee: senderFact.value }));
203
213
  ```
204
214
 
215
+ `deriveFromEvidence()` does not accept the authority value. The reviewed extractor selects a normalized output field, and Task Lease resolves that value only after verifying that the output still matches the exact allowed execution evidence.
216
+
217
+ The older `derive()` API remains available as the explicitly **host-trusted compatibility path**.
218
+
205
219
  The host keeps its existing SDK, connector and authentication. Agent Authority controls whether the effect may happen.
206
220
 
207
221
  ## Three integration modes, one authority model
@@ -247,7 +261,11 @@ The long-term validation target is the **same Task Lease and authority lineage a
247
261
  - Task Lease prototype
248
262
  - explicit authority roots
249
263
  - same-lease provenance-bound derived facts
250
- - required parent lineage and trusted extraction selector
264
+ - execution evidence binding an allowed receipt, request and exact output hash
265
+ - strict `deriveFromEvidence()` path where the caller cannot provide the authority value
266
+ - reviewed Gmail sender authority extractor bound to `gmail:thread.read`
267
+ - legacy host-trusted `derive()` compatibility path
268
+ - required parent lineage and extraction selector
251
269
  - exact context-field bindings
252
270
  - authority-delta step-up signal
253
271
  - immediate task completion/expiry enforcement
@@ -257,6 +275,7 @@ The long-term validation target is the **same Task Lease and authority lineage a
257
275
 
258
276
  - protocol-neutral `guard.run()` wrapper
259
277
  - blocked side effects never invoke their callback
278
+ - successful guarded effects return separate execution evidence
260
279
  - one-time human approvals bound to exact request
261
280
  - mutation idempotency
262
281
  - conservative uncertain-state handling
@@ -269,15 +288,19 @@ The long-term validation target is the **same Task Lease and authority lineage a
269
288
  - AES-256-GCM local encrypted secret store
270
289
  - safe reconnect cleanup
271
290
  - GitHub brokered execution without returning the token to the agent
291
+ - Google REST provider mappings for Gmail thread reads and Calendar event mutations
272
292
  - short-lived signed local agent-instance tokens
273
293
  - local CLI/daemon
274
294
 
275
295
  ### Engineering quality
276
296
 
277
297
  - adversarial authorization tests
298
+ - execution-evidence substitution, tampering, replay, cross-lease and selector tests
278
299
  - Node 20 and Node 22 CI
279
300
  - coverage run
280
301
  - package checks
302
+ - clean-consumer npm registry verification
303
+ - live GitHub read and mutation proofs
281
304
  - CodeQL
282
305
 
283
306
  ## What is different from OAuth, IAM and MCP authorization?
@@ -333,7 +356,7 @@ Allow a natural workflow across mail, calendar, CRM and internal systems without
333
356
  1. **Task before credential.** A provider token is not task authority.
334
357
  2. **Mission is the ceiling.** Task Leases cannot override explicit denies.
335
358
  3. **No side effect before authorization.** Denied and step-up actions never execute.
336
- 4. **Authority lineage matters.** Derived facts require an authorized receipt from the same Task Lease, at least one existing parent fact, and a recorded extraction selector.
359
+ 4. **Authority lineage matters.** Provider-derived authority should bind the exact allowed receipt and guarded output to a reviewed extractor; legacy host-trusted derivation remains identifiable in provenance.
337
360
  5. **No silent resource expansion.** A different concrete resource becomes an authority delta.
338
361
  6. **Task authority ends with the task.** Completion and expiry are independent from provider credential lifetime.
339
362
  7. **Authority may shrink, never silently grow.** Delegation and transport changes must preserve non-amplification.
@@ -348,7 +371,9 @@ See [SECURITY.md](SECURITY.md).
348
371
  This is still a validation implementation.
349
372
 
350
373
  - Task Lease state is currently process-local.
351
- - Derived-value extraction is trusted to the host/adapter; v0.4 records the source receipt and selector but does not yet cryptographically prove extraction from the provider response.
374
+ - `deriveFromEvidence()` proves consistency with the exact output returned through the trusted Agent Authority guard, but the output is not cryptographically attested by Gmail, GitHub, or another remote provider.
375
+ - The legacy `derive()` API remains host-trusted for compatibility; audit provenance distinguishes it from `execution-evidence-v1` derivation.
376
+ - Source-data changes do not yet automatically invalidate already-derived authority facts.
352
377
  - Bindings currently target top-level request context fields.
353
378
  - Approved authority deltas are surfaced but not automatically applied back into a live lease.
354
379
  - GitHub token-stdin is a developer bridge, not final browser OAuth onboarding.
package/ROADMAP.md CHANGED
@@ -77,19 +77,25 @@ Build only what the real M1 workflow proves necessary.
77
77
 
78
78
  **Success criterion:** a Task Lease survives daemon/process restarts without gaining authority or losing its provenance lineage.
79
79
 
80
- ## M3 — Trustworthy derived facts
80
+ ## M3 — Trustworthy derived facts — two-provider proof established
81
81
 
82
- Today the trusted host/adapter supplies the derived value and selector. This is an explicit v0.4 limitation.
82
+ The first real Gmail -> Calendar integration showed that recording a host-supplied value plus selector was too weak for the strongest derived-authority claim. The compatibility `derive()` path remains host-trusted; new provider work should prefer execution-bound evidence and reviewed adapter extractors.
83
83
 
84
- - [ ] define a small adapter contract for extracting authority-relevant fields from provider results
85
- - [ ] bind derived fact records to provider/result evidence where practical
86
- - [ ] adversarial tests for forged extraction, confused-deputy mappings and stale facts
87
- - [ ] conformance fixture for operation -> resource-context mappings
88
- - [ ] define invalidation rules when a source resource changes
84
+ - [x] define a small trusted-adapter extractor contract for authority-relevant normalized provider fields
85
+ - [x] bind successful guarded outputs to the exact ALLOW receipt, request and output hash
86
+ - [x] add `TaskLease.deriveFromEvidence()` so the caller cannot provide the authority value
87
+ - [x] migrate Gmail sender -> Calendar attendee derivation to the evidence-verified path
88
+ - [x] migrate the real GitHub issue discovery -> comment mutation proof to the same evidence-verified path
89
+ - [x] adversarial tests for value substitution, output/evidence tampering, receipt replay, cross-lease reuse, wrong-operation extraction and dangerous selectors
90
+ - [x] shared conformance fixtures for reviewed operation -> authority-field mappings across Google and GitHub
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.
89
95
 
90
96
  Do **not** build a general semantic policy language unless real integrations require it.
91
97
 
92
- **Success criterion:** an adapter cannot claim a value was derived from an authorized operation without satisfying the documented extraction/evidence contract.
98
+ **Success criterion:** provider-derived authority cannot be established through the strict path unless the exact guarded output, ALLOW receipt and reviewed extractor contract agree on the selected value. This behavior is now exercised across two provider mappings. Stronger provider attestation and source invalidation remain separate follow-on problems.
93
99
 
94
100
  ## M4 — Same task, multiple transports
95
101
 
@@ -147,7 +153,7 @@ Only after operational evidence.
147
153
 
148
154
  ## Research questions
149
155
 
150
- 1. What is the smallest trustworthy representation of an authority-relevant derived fact?
156
+ 1. What provider-side or transport-side evidence can strengthen output integrity without turning Agent Authority into an attestation protocol?
151
157
  2. How should an approved authority delta update a running task without opening a broader wildcard permission?
152
158
  3. How should source-data changes invalidate downstream derived authority?
153
159
  4. What provider/tool metadata is required to map operations to resource context reliably?
@@ -0,0 +1,95 @@
1
+ # Authority extractor conformance
2
+
3
+ Agent Authority treats provider-derived authority as a small adapter contract, not a general semantic policy language.
4
+
5
+ The strict path is:
6
+
7
+ ```text
8
+ authorized request
9
+ |
10
+ v
11
+ reviewed provider adapter
12
+ |
13
+ v
14
+ normalized provider output
15
+ |
16
+ +--> ALLOW receipt
17
+ +--> execution output hash
18
+ |
19
+ v
20
+ adapter.authorityExtractor(request, factKind)
21
+ |
22
+ v
23
+ { extractor_id, selector }
24
+ |
25
+ v
26
+ TaskLease.deriveFromEvidence()
27
+ |
28
+ v
29
+ derived authority fact
30
+ ```
31
+
32
+ ## Adapter requirements
33
+
34
+ A provider mapping intended to establish downstream authority SHOULD satisfy all of these:
35
+
36
+ 1. **Reviewed operation mapping.** The adapter owns the mapping from Agent Authority `service` + `action` to the external provider operation.
37
+ 2. **Normalized authority field.** Provider data is normalized into a small output shape before authority extraction. Credentials and unrelated raw payloads should not be copied into the authority result.
38
+ 3. **Fail-closed extractor advertisement.** `adapter.authorityExtractor(request, factKind)` returns an extractor only for an explicitly supported operation/fact-kind pair. Unsupported mappings return `null`.
39
+ 4. **Selector, never value.** The extractor returns `{ extractor_id, selector }`. It must not return the derived authority value itself.
40
+ 5. **Operation binding.** The extractor rejects receipts from another provider action.
41
+ 6. **Canonical output.** The extractor rejects malformed, ambiguous, or non-canonical normalized output.
42
+ 7. **Task lineage.** `TaskLease.deriveFromEvidence()` requires an ALLOW receipt from the same mission and Task Lease plus at least one existing parent fact.
43
+ 8. **Exact-output integrity.** The output passed to derivation must still hash to the output bound into the execution evidence.
44
+
45
+ This is an integrity contract inside the trusted Agent Authority host/adapter boundary. It is not provider-signed remote attestation.
46
+
47
+ ## Current fixtures
48
+
49
+ ### Google Gmail sender
50
+
51
+ ```text
52
+ gmail:thread.read
53
+ -> normalized sender_email
54
+ -> google.gmail.thread.sender-email.v1
55
+ -> email.address
56
+ ```
57
+
58
+ The Gmail extractor accepts only canonical normalized `sender_email` output and selects `output.sender_email`.
59
+
60
+ ### GitHub selected issue
61
+
62
+ ```text
63
+ github:issue.list
64
+ + root-bound repository
65
+ + root-bound fixture_marker
66
+ -> exactly one normalized marker match
67
+ -> github.issue.list.selected-number.v1
68
+ -> github.issue.number
69
+ ```
70
+
71
+ The GitHub adapter performs marker matching against the provider response, does not expose issue bodies in the normalized output, and the extractor selects only `output.selected_issue_number` when exactly one non-pull-request issue matched.
72
+
73
+ ## Shared adversarial conformance suite
74
+
75
+ `test/provider-authority-conformance.test.js` applies the same strict-path checks to both provider fixtures:
76
+
77
+ - positive derivation obtains the value from the evidence-bound output rather than caller input;
78
+ - modified output under unchanged evidence is rejected;
79
+ - execution evidence cannot be replayed under a second ALLOW receipt;
80
+ - receipt/evidence from one Task Lease cannot establish authority in another lease;
81
+ - an extractor cannot be reused with evidence from another provider operation.
82
+
83
+ Provider-specific tests additionally verify canonical normalization, exact REST mappings, extractor advertisement, and ambiguity failure.
84
+
85
+ ## What conformance does not prove
86
+
87
+ Passing this contract does not prove that:
88
+
89
+ - a provider cryptographically signed the normalized result;
90
+ - the trusted host itself is non-malicious;
91
+ - a source resource has not changed since the read;
92
+ - a derived fact is automatically invalidated when provider data changes;
93
+ - an agent cannot bypass Agent Authority through a separate credential or unguarded provider path.
94
+
95
+ Those are separate trust, freshness, and deployment-boundary problems and should not be hidden inside the extractor API.
package/docs/evidence.md CHANGED
@@ -10,9 +10,85 @@ This page records the strongest properties the repository currently demonstrates
10
10
 
11
11
  The guarantee applies to effects that actually pass through the Agent Authority enforcement boundary. A separate unguarded provider path is outside this guarantee.
12
12
 
13
+ ## Execution-bound derived authority
14
+
15
+ The strict derived-authority path binds provider-derived authority to the exact output returned by an authorized `guard.run()` effect.
16
+
17
+ A successful guarded effect returns three relevant records:
18
+
19
+ ```text
20
+ ALLOW receipt
21
+ +
22
+ exact effect output
23
+ |
24
+ v
25
+ execution evidence
26
+ (receipt + request + output hash)
27
+ |
28
+ v
29
+ reviewed adapter extractor
30
+ (selector only, no value)
31
+ |
32
+ v
33
+ TaskLease.deriveFromEvidence()
34
+ |
35
+ v
36
+ derived authority fact
37
+ ```
38
+
39
+ `deriveFromEvidence()` does not accept the derived authority value. The trusted adapter extractor chooses a reviewed selector, and Task Lease resolves that selector itself only after verifying the execution evidence.
40
+
41
+ `test/authority-evidence.test.js` attacks this boundary directly and proves that:
42
+
43
+ - caller-supplied value substitution does not control the resulting fact;
44
+ - modified provider output is rejected with `evidence_output_mismatch`;
45
+ - modified execution-evidence contents are rejected;
46
+ - evidence cannot be replayed under a second ALLOW receipt;
47
+ - a receipt/evidence chain from another Task Lease is rejected;
48
+ - the Gmail sender extractor rejects the wrong provider operation;
49
+ - dangerous selector paths such as `__proto__` fail closed.
50
+
51
+ The legacy `TaskLease.derive()` API remains for compatibility and records `derivation_mode: host-trusted`. New provider-derived authority should prefer `deriveFromEvidence()`, which records `derivation_mode: execution-evidence-v1`, extractor ID, source output hash, and execution-evidence hash.
52
+
53
+ ### Boundary of this claim
54
+
55
+ Execution evidence is an integrity mechanism inside the trusted host/runtime boundary. It proves that the value selected for strict derivation came from the exact output object bound to that Agent Authority receipt.
56
+
57
+ It does **not** prove that Gmail, GitHub, or another provider cryptographically signed that output, and it does not protect a malicious host that bypasses or replaces the Agent Authority enforcement path. Stronger provider/transport attestation remains open M3 work.
58
+
59
+ ## Two-provider authority-extractor conformance
60
+
61
+ The same strict primitive is now exercised by two independent provider mappings:
62
+
63
+ ```text
64
+ Google Gmail
65
+ thread.read
66
+ -> sender_email
67
+ -> reviewed extractor
68
+ -> email.address authority
69
+
70
+ GitHub
71
+ issue.list
72
+ -> selected_issue_number
73
+ -> reviewed extractor
74
+ -> github.issue.number authority
75
+ ```
76
+
77
+ `test/provider-authority-conformance.test.js` applies the same contract to both mappings:
78
+
79
+ - positive derivation gets its value from the evidence-bound output rather than caller input;
80
+ - modifying the selected output under unchanged evidence is rejected;
81
+ - evidence replay under another ALLOW receipt is rejected;
82
+ - cross-Task-Lease receipt/evidence reuse is rejected;
83
+ - an extractor rejects evidence from another operation.
84
+
85
+ Provider-specific tests additionally verify canonical normalization and fail-closed extractor advertisement. The contract is documented in [Authority extractor conformance](authority-extractor-conformance.md).
86
+
87
+ This is the current evidence that execution-bound derived authority is a reusable provider primitive rather than a Gmail-only special case.
88
+
13
89
  ## Cross-provider derived authority — Gmail → Calendar
14
90
 
15
- Agent Authority now includes a real Google provider mapping, an adversarial cross-provider test, a live validation script, and an opt-in GitHub Actions workflow.
91
+ Agent Authority includes a real Google provider mapping, an adversarial cross-provider test, a live validation script, and an opt-in GitHub Actions workflow.
16
92
 
17
93
  The task shape is:
18
94
 
@@ -22,9 +98,11 @@ one Gmail thread
22
98
  |
23
99
  v
24
100
  ALLOW Gmail thread.read
101
+ |
102
+ +--> output-bound execution evidence
25
103
  |
26
104
  v
27
- discover sender email
105
+ trusted Gmail sender extractor
28
106
  |
29
107
  v
30
108
  derive fact: sender_email
@@ -57,19 +135,21 @@ A controlled self-test was exercised against the connected NullSquare Gmail and
57
135
 
58
136
  No unrelated external person was invited. The smoke test establishes that the concrete Gmail and Calendar operations used by the validation are available and compatible with the intended data shape.
59
137
 
60
- The live connected-account smoke is not presented as a public CI proof of the repository script. The Task Lease zero-call assertions are separately executable in `test/google-cross-provider.test.js`, and `.github/workflows/live-google-validation.yml` is provided for a rerunnable provider-backed proof once repository Google OAuth secrets are configured.
138
+ The live connected-account smoke is not presented as a public CI proof of the repository script. The Task Lease zero-call and execution-evidence assertions are separately executable in `test/google-cross-provider.test.js` and `test/authority-evidence.test.js`, and `.github/workflows/live-google-validation.yml` is provided for a rerunnable provider-backed proof once repository Google OAuth secrets are configured.
61
139
 
62
140
  ### Executable local/CI assertions
63
141
 
64
142
  `test/google-cross-provider.test.js` proves deterministically that:
65
143
 
66
144
  - the approved Gmail thread callback runs exactly once;
67
- - its sender becomes a same-lease derived authority fact;
145
+ - its sender becomes a same-lease `execution-evidence-v1` authority fact;
68
146
  - one Calendar mutation for that sender runs exactly once;
69
147
  - a different attendee produces `authority_delta_required` and the Calendar callback is not invoked;
70
148
  - after lease completion, the previously valid attendee produces `task_lease_completed` and the Calendar callback is not invoked again.
71
149
 
72
- `test/google-provider.test.js` separately validates the Google REST mappings, metadata-only Gmail sender extraction, Calendar attendee body, default `sendUpdates=none`, credential redaction, unsupported-action failure, and mutation classification.
150
+ `test/google-provider.test.js` validates the Google REST mappings, metadata-only Gmail sender extraction, Calendar attendee body, default `sendUpdates=none`, credential redaction, unsupported-action failure, and mutation classification.
151
+
152
+ `test/google-authority-extractor.test.js` separately verifies that the reviewed Gmail extractor only accepts canonical `gmail:thread.read` sender output and that the Google adapter advertises it only for the supported authority mapping.
73
153
 
74
154
  ### Public workflow
75
155
 
@@ -89,9 +169,10 @@ The connected GitHub tool does not expose repository Actions-secret management,
89
169
 
90
170
  ### What this proves
91
171
 
92
- Taken together, the deterministic Task Lease test plus the controlled provider smoke show that:
172
+ Taken together, the deterministic Task Lease tests plus the controlled provider smoke show that:
93
173
 
94
174
  - the Gmail → Calendar derived-authority shape is implemented, not just diagrammed;
175
+ - strict derivation binds the sender to the exact guarded Gmail output before it becomes authority;
95
176
  - the exact attendee binding is enforced before the Calendar mutation callback;
96
177
  - provider operations exist and work against real Gmail and Calendar accounts;
97
178
  - cleanup can keep the live proof reversible and self-contained.
@@ -99,20 +180,21 @@ Taken together, the deterministic Task Lease test plus the controlled provider s
99
180
  ### What this does not prove yet
100
181
 
101
182
  - a public GitHub Actions run has executed the full repository live script;
102
- - host-side extraction of `sender_email` is cryptographically attested by Gmail;
183
+ - `sender_email` is cryptographically attested by Gmail rather than integrity-bound to the trusted host's guarded output;
103
184
  - the agent cannot bypass Agent Authority if it independently holds a Google credential;
104
185
  - Task Lease state is durable across process failure;
186
+ - source-data changes automatically invalidate downstream facts;
105
187
  - the refresh-token setup is production credential onboarding.
106
188
 
107
189
  See [Live Gmail → Calendar validation](live-google-validation.md).
108
190
 
109
- ## Live derived-authority mutation — GitHub
191
+ ## Live evidence-derived mutation — GitHub
110
192
 
111
193
  Public fixture: [issue #9](https://github.com/Null-Square/agent-authority/issues/9)
112
194
 
113
195
  Validation workflow: CI job `live-derived-github-mutation`
114
196
 
115
- Passing run: [CI run 136](https://github.com/Null-Square/agent-authority/actions/runs/32517381668)
197
+ Passing evidence-derived run: [CI run 262](https://github.com/Null-Square/agent-authority/actions/runs/32600963479)
116
198
 
117
199
  The job uses a GitHub Actions token with:
118
200
 
@@ -121,25 +203,40 @@ contents: read
121
203
  issues: write
122
204
  ```
123
205
 
124
- The Task Lease itself starts with only the repository as an authority root.
206
+ The Task Lease begins with two explicit authority roots:
207
+
208
+ ```text
209
+ repository = Null-Square/agent-authority
210
+ fixture_marker = agent-authority-live-fixture-v1
211
+ ```
212
+
213
+ Both values are bound to the `issue.list` request. The brokered GitHub provider adapter owns the external issue-list operation and normalizes the provider response. Issue bodies are used internally for marker matching but are not copied into the normalized authority output.
125
214
 
126
215
  ### Executed path
127
216
 
128
217
  ```text
129
- Task root
130
- Null-Square/agent-authority
218
+ Task roots
219
+ repository + fixture marker
220
+ |
221
+ v
222
+ ALLOW github:issue.list
223
+ through reviewed provider adapter
224
+ |
225
+ +--> exact output-bound execution evidence
131
226
  |
132
227
  v
133
- ALLOW live issue-list request
228
+ adapter selects exactly one marker match
229
+ selected_issue_number = 9
134
230
  |
135
231
  v
136
- discover issue #9 from GitHub response
232
+ reviewed GitHub issue-number extractor
137
233
  |
138
234
  v
139
- derive fact: issue_number = 9
235
+ TaskLease.deriveFromEvidence()
236
+ issue_number = 9
140
237
  |
141
238
  v
142
- ALLOW one real comment mutation on #9
239
+ ALLOW one real github:issue.comment on #9
143
240
  |
144
241
  +--> attempt comment on #1
145
242
  | -> authority_delta_required
@@ -156,38 +253,41 @@ complete Task Lease
156
253
  The passing job recorded:
157
254
 
158
255
  ```text
159
- ALLOW -> discovered issue #9
160
- Derived authority -> issue #9
256
+ ALLOW -> selected issue #9: Agent Authority live validation fixture — do not close
257
+ Evidence-verified authority -> issue #9
161
258
  ALLOW -> real GitHub comment mutation executed
162
259
  STEP-UP -> unrelated issue #1 blocked before provider mutation
163
260
  DENY -> post-completion mutation blocked for issue #9
261
+ PASS -> GitHub provider output became downstream authority only through execution evidence and a reviewed extractor
164
262
  Provider calls observed before cleanup: reads=1, task_mutations=1
165
263
  ```
166
264
 
167
- The temporary validation comment is deleted by test-harness cleanup after the proof. Cleanup is intentionally outside the agent authority path and counted separately.
265
+ The temporary validation comment was deleted by harness cleanup after the proof. Cleanup remains intentionally outside the Task Lease authority path and is counted separately.
168
266
 
169
267
  ### What this proves
170
268
 
171
- - a concrete resource can be discovered from a real provider response during authorized execution;
172
- - that resource can become same-lease derived authority;
173
- - a real provider mutation can be limited to the derived resource;
174
- - asking for another resource does not silently inherit the same authority;
175
- - a blocked resource causes zero additional task-side provider mutation calls;
176
- - completing the Task Lease prevents reuse of the previously authorized resource;
177
- - the provider credential can still exist after task authority disappears.
269
+ - the same execution-evidence + reviewed-extractor primitive used for Gmail works against a second real provider;
270
+ - the brokered GitHub adapter, rather than arbitrary host extraction code, owns provider response normalization;
271
+ - the caller does not provide the issue number to `deriveFromEvidence()`;
272
+ - repository and discovery marker are explicit Task Lease roots;
273
+ - a real provider mutation is limited to the issue selected from the authorized provider result;
274
+ - another issue causes zero additional task-side provider mutation calls;
275
+ - completing the Task Lease prevents reuse of the previously authorized issue;
276
+ - the provider credential can remain valid after task authority disappears.
178
277
 
179
278
  ### What this does not prove
180
279
 
181
- - the host/adapter's extraction of `output.number` is cryptographically verified;
280
+ - GitHub cryptographically attests the normalized Agent Authority output;
281
+ - source issue changes automatically invalidate a derived fact;
182
282
  - an agent cannot bypass Agent Authority if it independently possesses the provider credential or another unguarded provider path;
183
283
  - Task Lease state is durable across process failure;
184
284
  - the current prototype is ready for adversarial production use.
185
285
 
186
286
  ## Live provider read boundary — GitHub
187
287
 
188
- CI also runs `demo:live-github` against the public GitHub API.
288
+ CI also runs `demo:live-github` against the GitHub API.
189
289
 
190
- It proves that one repository permitted by the Task Lease causes one live `fetch()` while another repository produces `authority_delta_required` before a second fetch occurs.
290
+ It proves that one repository permitted by the Task Lease causes one live provider read while another repository produces `authority_delta_required` before a second provider request occurs.
191
291
 
192
292
  ## Network-boundary integration test
193
293
 
@@ -209,7 +309,9 @@ The test suite also covers:
209
309
  - receipts from another mission are rejected;
210
310
  - receipts from another Task Lease are rejected;
211
311
  - parent lineage is required;
212
- - a trusted extraction selector must be recorded;
312
+ - legacy host-trusted derivation records its extraction selector;
313
+ - strict execution-evidence derivation rejects substitution/replay/tampering cases;
314
+ - the shared provider conformance suite applies the same attacks to Google and GitHub mappings;
213
315
  - explicit mission deny rules remain the ceiling;
214
316
  - lease expiry and mission expiry are enforced against a consistent evaluation clock.
215
317
 
@@ -224,8 +326,8 @@ Current pull requests run:
224
326
  - package checks;
225
327
  - coverage;
226
328
  - live GitHub read validation;
227
- - live derived GitHub mutation validation for trusted in-repository branches;
228
- - Google provider and cross-provider adversarial tests;
329
+ - live evidence-derived GitHub mutation validation for trusted in-repository branches;
330
+ - Google and GitHub provider/extractor conformance and execution-evidence adversarial tests;
229
331
  - CodeQL.
230
332
 
231
333
  The live Google provider mutation workflow is manual because it requires repository-owned Google OAuth secrets. It should be added to the public evidence list after its first successful run.
@@ -13,17 +13,19 @@ Before any publication:
13
13
  After publication, verify from a fresh project with:
14
14
 
15
15
  ```bash
16
- npm install @nullsquare/agent-authority@0.4.0
16
+ npm install @nullsquare/agent-authority@0.4.2
17
17
  ```
18
18
 
19
19
  Then run the same consumer smoke flow through the registry-installed package. Registry verification is part of the release gate; a successful `npm publish` command alone is not sufficient.
20
20
 
21
+ The repository also includes `.github/workflows/verify-npm-registry.yml`, which verifies registry visibility and a clean consumer install. For v0.4.2 it additionally verifies the public `@nullsquare/agent-authority/authority-evidence` export plus the Google provider and Gmail authority-extractor exports.
22
+
21
23
  ## npm vs GitHub release surfaces
22
24
 
23
25
  Publishing to the public npm registry does not automatically create either a GitHub Release or a GitHub Packages entry.
24
26
 
25
27
  - **npm registry** — `npm publish --access public` publishes `@nullsquare/agent-authority` to `registry.npmjs.org` / npmjs.com. This is the package users install with `npm install`.
26
- - **GitHub Releases** — a separate GitHub object, normally backed by a Git tag such as `v0.4.0`. A release must be created explicitly or by release automation.
28
+ - **GitHub Releases** — a separate GitHub object, normally backed by a Git tag such as `v0.4.2`. A release must be created explicitly or by release automation.
27
29
  - **GitHub Packages** — a separate package registry. It only appears when the package is published to GitHub's npm registry (`npm.pkg.github.com`); publishing to npmjs.com does not populate it.
28
30
 
29
31
  Agent Authority currently uses npmjs.com as its public package registry. Therefore an empty GitHub **Packages** section is expected unless the project intentionally adopts dual publication. A GitHub **Release** is still useful for source-release discoverability and should track published versions, but it is independent from npm publication.