apsimo-hostworker 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,1109 @@
1
+ """Executable store-adapter conformance suite.
2
+
3
+ Every case exercises one or more of the numbered invariants in
4
+ :mod:`apsimo_hostworker.store` through the public store API only, using a
5
+ fresh harness per case. The adversarial cases are constructed so that a
6
+ store which "merely implements the method signatures" — one that trusts the
7
+ caller's pre-check, caches receipts read at lease time, skips the
8
+ in-transaction gate validator, re-leases dispatched work, or honors a
9
+ retryable flag after a mutation — FAILS loudly here instead of dispatching
10
+ a second mutation or honoring dead authority in production.
11
+
12
+ A host must pass this suite with its own harness before running live:
13
+
14
+ from apsimo_hostworker.conformance import assert_store_conformance
15
+ assert_store_conformance(my_harness_factory)
16
+
17
+ or, for the bundled reference store::
18
+
19
+ python -m apsimo_hostworker.conformance
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import hashlib
25
+ from dataclasses import dataclass
26
+ from typing import Any, Callable, Mapping
27
+
28
+ from ..gate import (
29
+ GRANT_UNLIMITED_SENTINEL,
30
+ GateAuthorization,
31
+ assert_dispatchable,
32
+ validate_owner_gate,
33
+ )
34
+ from ..store import (
35
+ ActionStoreError,
36
+ GATE_RECEIPT_KIND,
37
+ RECOVERY_RECEIPT_KIND,
38
+ )
39
+ from ..worker import DEFAULT_ACTION_TYPE, DEFAULT_SOURCE_PREFIX, build_execution_request
40
+ from .harness import (
41
+ HarnessFactory,
42
+ StoreHarness,
43
+ build_envelope,
44
+ build_intent,
45
+ delivery_gate_evidence,
46
+ grant_gate_evidence,
47
+ )
48
+
49
+ SOURCE = DEFAULT_SOURCE_PREFIX + "conformance-host"
50
+ OWNER_A = "conformance-worker-a"
51
+ OWNER_B = "conformance-worker-b"
52
+ LEASE_SECONDS = 60.0
53
+
54
+
55
+ class ConformanceFailure(AssertionError):
56
+ """The store under test violated a documented invariant."""
57
+
58
+
59
+ @dataclass
60
+ class ConformanceResult:
61
+ name: str
62
+ passed: bool
63
+ detail: str = ""
64
+
65
+
66
+ @dataclass
67
+ class Scenario:
68
+ action: Mapping[str, Any]
69
+ intent: Any
70
+ evidence: Mapping[str, Any]
71
+ gate_receipt: Mapping[str, Any]
72
+
73
+
74
+ def _require(condition: bool, case: str, message: str) -> None:
75
+ if not condition:
76
+ raise ConformanceFailure("%s: %s" % (case, message))
77
+
78
+
79
+ def _expect_refusal(case: str, message: str, callable_: Callable[[], Any]) -> None:
80
+ try:
81
+ callable_()
82
+ except ActionStoreError:
83
+ return
84
+ except Exception as error:
85
+ raise ConformanceFailure(
86
+ "%s: %s — raised %r instead of an ActionStoreError" % (case, message, error)
87
+ )
88
+ raise ConformanceFailure("%s: %s — the store did not refuse" % (case, message))
89
+
90
+
91
+ def _gated(
92
+ harness: StoreHarness,
93
+ *,
94
+ tool_name: str = "colony_create_commitment",
95
+ args: Mapping[str, Any] | None = None,
96
+ grant: bool = False,
97
+ standing_grant: bool = False,
98
+ expires_in: float = 3600.0,
99
+ grant_expires_in: float = 3600.0,
100
+ ) -> Scenario:
101
+ intent = build_intent(tool_name=tool_name, args=args)
102
+ envelope = build_envelope(intent)
103
+ action = harness.propose(
104
+ idempotency_key=intent.idempotency_key,
105
+ source=SOURCE,
106
+ source_ref=intent.intent_id,
107
+ action_type=DEFAULT_ACTION_TYPE,
108
+ payload=envelope,
109
+ )
110
+ now = harness.now()
111
+ if grant:
112
+ evidence = grant_gate_evidence(
113
+ action,
114
+ decided_at=now,
115
+ expires_at=now + expires_in,
116
+ grant_expires_at=(
117
+ GRANT_UNLIMITED_SENTINEL
118
+ if standing_grant else now + grant_expires_in
119
+ ),
120
+ )
121
+ else:
122
+ evidence = delivery_gate_evidence(
123
+ action, decided_at=now, expires_at=now + expires_in
124
+ )
125
+ action, receipt = harness.add_gate(
126
+ action["action_id"], evidence, external_id=evidence["approval_id"]
127
+ )
128
+ return Scenario(action=action, intent=intent, evidence=evidence, gate_receipt=receipt)
129
+
130
+
131
+ def _lease_gated(harness: StoreHarness, owner: str = OWNER_A) -> Mapping[str, Any]:
132
+ leased = harness.store.lease_next(
133
+ owner, lease_seconds=LEASE_SECONDS, states=("gated",)
134
+ )
135
+ if leased is None:
136
+ raise ConformanceFailure("harness: gated action could not be leased")
137
+ return leased
138
+
139
+
140
+ def _real_validator(tool_name: str):
141
+ def validate(action, receipts, now):
142
+ return assert_dispatchable(
143
+ validate_owner_gate(action, receipts, tool_name=tool_name, now=now)
144
+ )
145
+
146
+ return validate
147
+
148
+
149
+ def _permissive_authorization(
150
+ scenario: Scenario, *, granted: bool = False, expired: bool = False
151
+ ) -> GateAuthorization:
152
+ """A fabricated always-yes authorization used to prove the STORE's own
153
+ checks refuse even when a (broken or malicious) validator would not."""
154
+
155
+ return GateAuthorization(
156
+ shape="bounded_grant" if granted else "message_delivery",
157
+ granted=granted,
158
+ receipt_key=scenario.gate_receipt["receipt_key"],
159
+ evidence_sha256=scenario.gate_receipt["evidence_sha256"],
160
+ approval_id=scenario.evidence["approval_id"],
161
+ decision_id=scenario.evidence["decision_id"],
162
+ revision=1,
163
+ decided_at=float(scenario.evidence["decided_at_epoch"]),
164
+ expires_at=float(scenario.evidence["expires_at_epoch"]),
165
+ expired=expired,
166
+ )
167
+
168
+
169
+ def _placeholder_digest(scenario: Scenario) -> str:
170
+ return hashlib.sha256(
171
+ ("conformance:" + scenario.action["action_id"]).encode("utf-8")
172
+ ).hexdigest()
173
+
174
+
175
+ def _dispatch(
176
+ harness: StoreHarness,
177
+ scenario: Scenario,
178
+ *,
179
+ owner: str = OWNER_A,
180
+ validator,
181
+ execution_digest: str | None = None,
182
+ window: float = 600.0,
183
+ max_observations: int = 5,
184
+ ):
185
+ return harness.store.begin_owner_authorized_dispatch(
186
+ scenario.action["action_id"],
187
+ owner,
188
+ gate_receipt_key=scenario.gate_receipt["receipt_key"],
189
+ expected_source=scenario.action["source"],
190
+ expected_source_ref=scenario.action["source_ref"],
191
+ expected_action_type=scenario.action["action_type"],
192
+ expected_payload=scenario.action["payload"],
193
+ expected_approval_id=scenario.evidence["approval_id"],
194
+ expected_decision_id=scenario.evidence["decision_id"],
195
+ expected_execution_digest=execution_digest or _placeholder_digest(scenario),
196
+ observation_window_seconds=window,
197
+ max_observations=max_observations,
198
+ gate_validator=validator,
199
+ )
200
+
201
+
202
+ def _require_unconsumed(harness: StoreHarness, scenario: Scenario, case: str) -> None:
203
+ action = harness.store.get_action(scenario.action["action_id"])
204
+ _require(action["state"] == "gated", case, "action left the gated state")
205
+ _require(
206
+ int(action["attempt_count"]) == 0, case, "an attempt was consumed"
207
+ )
208
+ recovery = [
209
+ receipt
210
+ for receipt in harness.store.list_receipts(scenario.action["action_id"])
211
+ if receipt["kind"] == RECOVERY_RECEIPT_KIND
212
+ ]
213
+ _require(not recovery, case, "a recovery contract was written despite refusal")
214
+
215
+
216
+ def _dispatch_ok(
217
+ harness: StoreHarness,
218
+ scenario: Scenario,
219
+ *,
220
+ owner: str = OWNER_A,
221
+ window: float = 600.0,
222
+ max_observations: int = 5,
223
+ ) -> tuple[Mapping[str, Any], dict[str, Any]]:
224
+ """Lease and dispatch a valid scenario the way the worker does."""
225
+
226
+ action = _lease_gated(harness, owner)
227
+ authorization = validate_owner_gate(
228
+ action,
229
+ harness.store.list_receipts(action["action_id"]),
230
+ tool_name=scenario.intent.tool_name,
231
+ now=harness.now(),
232
+ )
233
+ request = build_execution_request(action, scenario.intent, authorization)
234
+ dispatched = _dispatch(
235
+ harness,
236
+ scenario,
237
+ owner=owner,
238
+ validator=_real_validator(scenario.intent.tool_name),
239
+ execution_digest=request["execution_digest"],
240
+ window=window,
241
+ max_observations=max_observations,
242
+ )
243
+ return dispatched, request
244
+
245
+
246
+ # ----------------------------------------------------------------- cases
247
+
248
+
249
+ def check_happy_path_lifecycle(factory: HarnessFactory) -> None:
250
+ """I1/I2/I5/I8/I9: the full governed lifecycle, exactly once each."""
251
+
252
+ case = "happy_path_lifecycle"
253
+ harness = factory()
254
+ try:
255
+ scenario = _gated(harness)
256
+ # I1: idempotent re-propose returns the identical immutable action.
257
+ again = harness.propose(
258
+ idempotency_key=scenario.intent.idempotency_key,
259
+ source=SOURCE,
260
+ source_ref=scenario.intent.intent_id,
261
+ action_type=DEFAULT_ACTION_TYPE,
262
+ payload=build_envelope(scenario.intent),
263
+ )
264
+ _require(
265
+ again["action_id"] == scenario.action["action_id"],
266
+ case,
267
+ "idempotent propose minted a second action",
268
+ )
269
+ dispatched, request = _dispatch_ok(harness, scenario)
270
+ _require(dispatched["state"] == "dispatched", case, "dispatch did not commit")
271
+ _require(
272
+ int(dispatched["attempt_count"]) == 1,
273
+ case,
274
+ "attempt_count did not increment exactly once",
275
+ )
276
+ recovery = [
277
+ receipt
278
+ for receipt in harness.store.list_receipts(dispatched["action_id"])
279
+ if receipt["kind"] == RECOVERY_RECEIPT_KIND
280
+ ]
281
+ _require(
282
+ len(recovery) == 1
283
+ and recovery[0]["external_id"] == request["execution_digest"],
284
+ case,
285
+ "the GET-only recovery contract was not written atomically "
286
+ "with the dispatch transition",
287
+ )
288
+ acceptance_key = "governed-action-acceptance:" + request["execution_digest"]
289
+ endpoint_projection = {
290
+ "status": "completed",
291
+ "execution_digest": request["execution_digest"],
292
+ "observed": "conformance",
293
+ }
294
+ accepted, _receipt = harness.store.accept(
295
+ dispatched["action_id"],
296
+ OWNER_A,
297
+ acceptance_key,
298
+ "governed_action_acceptance",
299
+ endpoint_projection,
300
+ external_id=dispatched["action_id"],
301
+ )
302
+ _require(accepted["state"] == "accepted", case, "accept did not commit")
303
+ verified, _receipt = harness.store.verify(
304
+ accepted["action_id"],
305
+ OWNER_A,
306
+ "governed-action-verification:" + request["execution_digest"],
307
+ endpoint_projection,
308
+ qualifying_receipt_keys=(acceptance_key,),
309
+ )
310
+ _require(verified["state"] == "verified", case, "verify did not commit")
311
+ completed = harness.store.complete(
312
+ verified["action_id"], OWNER_A, {"status": "completed"}
313
+ )
314
+ _require(
315
+ completed["state"] == "completed"
316
+ and completed["lease_owner"] is None
317
+ and completed["terminal_at"] is not None,
318
+ case,
319
+ "complete did not terminalize cleanly",
320
+ )
321
+ # I8: terminal states are frozen.
322
+ _expect_refusal(
323
+ case,
324
+ "a completed action accepted another transition",
325
+ lambda: harness.store.fail_attempt(
326
+ completed["action_id"], OWNER_A, "late failure", False
327
+ ),
328
+ )
329
+ finally:
330
+ harness.close()
331
+
332
+
333
+ def check_gate_validator_runs_inside_dispatch(factory: HarnessFactory) -> None:
334
+ """I4: the store MUST invoke the supplied validator, against durable
335
+ receipts re-read in the transaction, with the store's own clock — and a
336
+ validator verdict of anything but a live authorization must abort.
337
+
338
+ Catches: a store that never calls the validator, calls it with the
339
+ caller's stale receipt view, or ignores its verdict."""
340
+
341
+ case = "gate_validator_runs_inside_dispatch"
342
+ harness = factory()
343
+ try:
344
+ scenario = _gated(harness)
345
+ _lease_gated(harness)
346
+ harness.advance(40.0) # the store's clock, not the pre-check's
347
+ seen: dict[str, Any] = {}
348
+
349
+ def sentinel(action, receipts, now):
350
+ seen["action_id"] = action.get("action_id")
351
+ seen["receipts"] = list(receipts)
352
+ seen["now"] = now
353
+ raise RuntimeError("sentinel refuses")
354
+
355
+ _expect_refusal(
356
+ case,
357
+ "a raising validator did not abort the dispatch",
358
+ lambda: _dispatch(harness, scenario, validator=sentinel),
359
+ )
360
+ _require(bool(seen), case, "the store never invoked the gate validator")
361
+ _require(
362
+ seen.get("action_id") == scenario.action["action_id"],
363
+ case,
364
+ "the validator saw a different action",
365
+ )
366
+ durable_gates = [
367
+ receipt
368
+ for receipt in seen.get("receipts", ())
369
+ if receipt.get("kind") == GATE_RECEIPT_KIND
370
+ ]
371
+ _require(
372
+ len(durable_gates) == 1
373
+ and durable_gates[0].get("evidence") == dict(scenario.evidence)
374
+ and durable_gates[0].get("evidence_sha256")
375
+ == scenario.gate_receipt["evidence_sha256"],
376
+ case,
377
+ "the validator was not given the durable gate receipt",
378
+ )
379
+ _require(
380
+ float(seen.get("now", -1.0)) == harness.now(),
381
+ case,
382
+ "the validator was not given the store's point-of-use clock",
383
+ )
384
+ _require_unconsumed(harness, scenario, case)
385
+
386
+ # A validator returning garbage must abort too.
387
+ _expect_refusal(
388
+ case,
389
+ "a non-authorization validator result was accepted",
390
+ lambda: _dispatch(
391
+ harness, scenario, validator=lambda *_: {"approved": True}
392
+ ),
393
+ )
394
+ # And so must an authorization the validator marked expired.
395
+ _expect_refusal(
396
+ case,
397
+ "an expired authorization was accepted",
398
+ lambda: _dispatch(
399
+ harness,
400
+ scenario,
401
+ validator=lambda *_: _permissive_authorization(
402
+ scenario, expired=True
403
+ ),
404
+ ),
405
+ )
406
+ _require_unconsumed(harness, scenario, case)
407
+ finally:
408
+ harness.close()
409
+
410
+
411
+ def check_evidence_mutated_between_precheck_and_dispatch(
412
+ factory: HarnessFactory,
413
+ ) -> None:
414
+ """ADVERSARIAL/TOCTOU: the gate evidence set changes after the caller's
415
+ pre-check (a second gate receipt lands post-lease). A conforming store
416
+ re-reads and re-validates inside the dispatch transaction and refuses.
417
+
418
+ Catches: a store that validates at lease time, caches the receipt list,
419
+ or otherwise trusts the caller's earlier look at the evidence."""
420
+
421
+ case = "evidence_mutated_between_precheck_and_dispatch"
422
+ harness = factory()
423
+ try:
424
+ scenario = _gated(harness)
425
+ leased = _lease_gated(harness)
426
+ # The caller's pre-check: passes against the receipts as they are NOW.
427
+ precheck = validate_owner_gate(
428
+ leased,
429
+ harness.store.list_receipts(leased["action_id"]),
430
+ tool_name=scenario.intent.tool_name,
431
+ now=harness.now(),
432
+ )
433
+ _require(not precheck.expired, case, "fixture pre-check unexpectedly failed")
434
+ # Between check and use, a second owner-gate receipt lands (an
435
+ # approval-router race or a forged duplicate approval).
436
+ second = delivery_gate_evidence(
437
+ scenario.action,
438
+ decided_at=harness.now(),
439
+ expires_at=harness.now() + 3600.0,
440
+ )
441
+ harness.add_gate(
442
+ scenario.action["action_id"],
443
+ second,
444
+ receipt_key="owner-gate-2",
445
+ external_id=second["approval_id"],
446
+ )
447
+ _expect_refusal(
448
+ case,
449
+ "the store dispatched on pre-check evidence after the durable "
450
+ "gate set changed",
451
+ lambda: _dispatch(
452
+ harness,
453
+ scenario,
454
+ validator=_real_validator(scenario.intent.tool_name),
455
+ ),
456
+ )
457
+ _require_unconsumed(harness, scenario, case)
458
+ finally:
459
+ harness.close()
460
+
461
+
462
+ def check_duplicate_gates_refused(factory: HarnessFactory) -> None:
463
+ """ADVERSARIAL: two gate receipts must never dispatch — even when the
464
+ validator (broken or malicious) says yes, the store's own exactly-one
465
+ check must hold.
466
+
467
+ Catches: a store that picks 'the first' or 'the matching' of several
468
+ gates instead of requiring exactly one."""
469
+
470
+ case = "duplicate_gates_refused"
471
+ harness = factory()
472
+ try:
473
+ scenario = _gated(harness)
474
+ second = delivery_gate_evidence(
475
+ scenario.action,
476
+ decided_at=harness.now(),
477
+ expires_at=harness.now() + 3600.0,
478
+ )
479
+ harness.add_gate(
480
+ scenario.action["action_id"],
481
+ second,
482
+ receipt_key="owner-gate-2",
483
+ external_id=second["approval_id"],
484
+ )
485
+ _lease_gated(harness)
486
+ _expect_refusal(
487
+ case,
488
+ "duplicate gates dispatched under the real validator",
489
+ lambda: _dispatch(
490
+ harness,
491
+ scenario,
492
+ validator=_real_validator(scenario.intent.tool_name),
493
+ ),
494
+ )
495
+ _expect_refusal(
496
+ case,
497
+ "duplicate gates dispatched under a permissive validator",
498
+ lambda: _dispatch(
499
+ harness,
500
+ scenario,
501
+ validator=lambda *_: _permissive_authorization(scenario),
502
+ ),
503
+ )
504
+ _require_unconsumed(harness, scenario, case)
505
+ finally:
506
+ harness.close()
507
+
508
+
509
+ def check_tampered_gate_binding_refused(factory: HarnessFactory) -> None:
510
+ """ADVERSARIAL: gate evidence whose action_digest binds a DIFFERENT
511
+ payload must refuse under both the validator and the store's own
512
+ structural binding check.
513
+
514
+ Catches: a store that binds the gate by action_id alone and lets an
515
+ approval for one payload authorize another."""
516
+
517
+ case = "tampered_gate_binding_refused"
518
+ harness = factory()
519
+ try:
520
+ intent = build_intent()
521
+ envelope = build_envelope(intent)
522
+ action = harness.propose(
523
+ idempotency_key=intent.idempotency_key,
524
+ source=SOURCE,
525
+ source_ref=intent.intent_id,
526
+ action_type=DEFAULT_ACTION_TYPE,
527
+ payload=envelope,
528
+ )
529
+ evidence = delivery_gate_evidence(
530
+ action,
531
+ decided_at=harness.now(),
532
+ expires_at=harness.now() + 3600.0,
533
+ action_digest="0" * 64, # someone else's payload
534
+ )
535
+ action, receipt = harness.add_gate(
536
+ action["action_id"], evidence, external_id=evidence["approval_id"]
537
+ )
538
+ scenario = Scenario(
539
+ action=action, intent=intent, evidence=evidence, gate_receipt=receipt
540
+ )
541
+ _lease_gated(harness)
542
+ _expect_refusal(
543
+ case,
544
+ "a mis-bound gate dispatched under the real validator",
545
+ lambda: _dispatch(
546
+ harness, scenario, validator=_real_validator(intent.tool_name)
547
+ ),
548
+ )
549
+ _expect_refusal(
550
+ case,
551
+ "a mis-bound gate dispatched under a permissive validator",
552
+ lambda: _dispatch(
553
+ harness,
554
+ scenario,
555
+ validator=lambda *_: _permissive_authorization(scenario),
556
+ ),
557
+ )
558
+ _require_unconsumed(harness, scenario, case)
559
+ finally:
560
+ harness.close()
561
+
562
+
563
+ def check_crash_between_dispatch_and_put(factory: HarnessFactory) -> None:
564
+ """I5/I6: after the dispatch transaction commits and the worker dies
565
+ before (or during) its one PUT, the action must be recoverable ONLY as
566
+ GET-only observation — never as a second mutation.
567
+
568
+ Catches: a store that returns dispatched work to gated, lets
569
+ ``lease_next`` hand it out again, or allows a second dispatch."""
570
+
571
+ case = "crash_between_dispatch_and_put"
572
+ harness = factory()
573
+ try:
574
+ scenario = _gated(harness)
575
+ dispatched, request = _dispatch_ok(harness, scenario)
576
+ _require(dispatched["state"] == "dispatched", case, "fixture dispatch failed")
577
+ # The worker crashes here; its lease expires.
578
+ harness.advance(LEASE_SECONDS * 2)
579
+ stolen = harness.store.lease_next(
580
+ OWNER_B,
581
+ lease_seconds=LEASE_SECONDS,
582
+ states=("gated", "accepted", "verified"),
583
+ )
584
+ _require(
585
+ stolen is None or stolen["action_id"] != dispatched["action_id"],
586
+ case,
587
+ "lease_next re-leased a dispatched action for mutation",
588
+ )
589
+ observed = harness.store.lease_dispatched_observation(
590
+ OWNER_B, lease_seconds=LEASE_SECONDS
591
+ )
592
+ _require(
593
+ observed is not None
594
+ and observed["action_id"] == dispatched["action_id"]
595
+ and observed["state"] == "dispatched",
596
+ case,
597
+ "the dispatched action was not recoverable as GET-only work",
598
+ )
599
+ _expect_refusal(
600
+ case,
601
+ "a second owner-authorized dispatch was permitted",
602
+ lambda: _dispatch(
603
+ harness,
604
+ scenario,
605
+ owner=OWNER_B,
606
+ validator=lambda *_: _permissive_authorization(scenario),
607
+ execution_digest=request["execution_digest"],
608
+ ),
609
+ )
610
+ recovery = [
611
+ receipt
612
+ for receipt in harness.store.list_receipts(dispatched["action_id"])
613
+ if receipt["kind"] == RECOVERY_RECEIPT_KIND
614
+ ]
615
+ _require(
616
+ len(recovery) == 1
617
+ and recovery[0]["external_id"] == request["execution_digest"],
618
+ case,
619
+ "the recovery contract is missing, duplicated, or unbound",
620
+ )
621
+ current = harness.store.get_action(dispatched["action_id"])
622
+ _require(
623
+ int(current["attempt_count"]) == 1,
624
+ case,
625
+ "the crash recovery consumed another attempt",
626
+ )
627
+ finally:
628
+ harness.close()
629
+
630
+
631
+ def check_lease_steal_during_observation(factory: HarnessFactory) -> None:
632
+ """I3: once worker B holds the observation lease, worker A's stale
633
+ handle must not be able to defer, accept, or otherwise mutate.
634
+
635
+ Catches: a store that checks lease ownership outside the transaction,
636
+ or not at all, letting two workers race the same observation."""
637
+
638
+ case = "lease_steal_during_observation"
639
+ harness = factory()
640
+ try:
641
+ scenario = _gated(harness)
642
+ dispatched, request = _dispatch_ok(harness, scenario)
643
+ action, attempt_one = harness.store.begin_dispatched_observation(
644
+ dispatched["action_id"], OWNER_A, request["execution_digest"]
645
+ )
646
+ _require(
647
+ attempt_one is not None and action["state"] == "dispatched",
648
+ case,
649
+ "fixture observation attempt failed",
650
+ )
651
+ harness.advance(LEASE_SECONDS * 2) # A's lease dies
652
+ stolen = harness.store.lease_dispatched_observation(
653
+ OWNER_B, lease_seconds=LEASE_SECONDS
654
+ )
655
+ _require(
656
+ stolen is not None and stolen["action_id"] == dispatched["action_id"],
657
+ case,
658
+ "worker B could not take over the expired observation",
659
+ )
660
+ _expect_refusal(
661
+ case,
662
+ "worker A deferred an observation it no longer leases",
663
+ lambda: harness.store.defer_dispatched_observation(
664
+ dispatched["action_id"],
665
+ OWNER_A,
666
+ request["execution_digest"],
667
+ attempt_one["receipt_key"],
668
+ "stale worker",
669
+ 1.0,
670
+ ),
671
+ )
672
+ _expect_refusal(
673
+ case,
674
+ "worker A accepted an action it no longer leases",
675
+ lambda: harness.store.accept(
676
+ dispatched["action_id"],
677
+ OWNER_A,
678
+ "governed-action-acceptance:" + request["execution_digest"],
679
+ "governed_action_acceptance",
680
+ {"status": "completed"},
681
+ ),
682
+ )
683
+ current = harness.store.get_action(dispatched["action_id"])
684
+ _require(
685
+ current["state"] == "dispatched"
686
+ and current["lease_owner"] == OWNER_B,
687
+ case,
688
+ "the stale worker mutated state despite losing the lease",
689
+ )
690
+ finally:
691
+ harness.close()
692
+
693
+
694
+ def check_expired_gate_at_point_of_use(factory: HarnessFactory) -> None:
695
+ """ADVERSARIAL: an approval that was live when written but is expired at
696
+ dispatch time must never dispatch — under the real validator AND under
697
+ a permissive one (the store re-checks expiry itself).
698
+
699
+ Catches: a store that trusts 'valid when the receipt was written'."""
700
+
701
+ case = "expired_gate_at_point_of_use"
702
+ harness = factory()
703
+ try:
704
+ scenario = _gated(harness, expires_in=50.0)
705
+ _lease_gated(harness)
706
+ harness.advance(55.0) # inside the lease, past the gate expiry
707
+ _expect_refusal(
708
+ case,
709
+ "an expired gate dispatched under the real validator",
710
+ lambda: _dispatch(
711
+ harness,
712
+ scenario,
713
+ validator=_real_validator(scenario.intent.tool_name),
714
+ ),
715
+ )
716
+ _expect_refusal(
717
+ case,
718
+ "an expired gate dispatched under a permissive validator",
719
+ lambda: _dispatch(
720
+ harness,
721
+ scenario,
722
+ validator=lambda *_: _permissive_authorization(scenario),
723
+ ),
724
+ )
725
+ _require_unconsumed(harness, scenario, case)
726
+ finally:
727
+ harness.close()
728
+
729
+
730
+ def check_expired_grant_at_point_of_use(factory: HarnessFactory) -> None:
731
+ """ADVERSARIAL: a bounded grant whose own expiry passed — while the gate
732
+ receipt's outer expiry is still live — must never dispatch. Only the
733
+ shape-aware validator knows the grant expiry field, so this case FAILS
734
+ on any store that does not actually run the supplied validator inside
735
+ the transaction (I4).
736
+
737
+ Catches: a store whose structural checks pass and which skips or
738
+ short-circuits the semantic validator."""
739
+
740
+ case = "expired_grant_at_point_of_use"
741
+ harness = factory()
742
+ try:
743
+ scenario = _gated(
744
+ harness,
745
+ tool_name="colony_task_complete",
746
+ args={"task_id": "task-conformance-1"},
747
+ grant=True,
748
+ expires_in=3600.0,
749
+ grant_expires_in=50.0,
750
+ )
751
+ _lease_gated(harness)
752
+ harness.advance(55.0) # grant dead, outer gate expiry still live
753
+ _expect_refusal(
754
+ case,
755
+ "an expired bounded grant dispatched",
756
+ lambda: _dispatch(
757
+ harness,
758
+ scenario,
759
+ validator=_real_validator(scenario.intent.tool_name),
760
+ ),
761
+ )
762
+ _require_unconsumed(harness, scenario, case)
763
+ finally:
764
+ harness.close()
765
+
766
+
767
+ def check_non_grantable_tool_with_grant_proof(factory: HarnessFactory) -> None:
768
+ """ADVERSARIAL: a syntactically perfect standing-grant receipt presented
769
+ for either ``non_grantable`` autonomy tool must never
770
+ dispatch — under the real validator AND under a permissive one (the
771
+ store's grant backstop must hold on its own).
772
+
773
+ Catches: a store or configuration that lets standing-grant authority
774
+ reach tools the catalog reserves for per-message owner approval."""
775
+
776
+ case = "non_grantable_tool_with_grant_proof"
777
+ for tool_name in ("colony_autonomy_enable", "colony_autonomy_disable"):
778
+ harness = factory()
779
+ try:
780
+ scenario = _gated(
781
+ harness,
782
+ tool_name=tool_name,
783
+ args={},
784
+ grant=True,
785
+ standing_grant=True,
786
+ )
787
+ _lease_gated(harness)
788
+ _expect_refusal(
789
+ case,
790
+ "%s dispatched under a standing grant and the real validator"
791
+ % tool_name,
792
+ lambda: _dispatch(
793
+ harness,
794
+ scenario,
795
+ validator=_real_validator(scenario.intent.tool_name),
796
+ ),
797
+ )
798
+ _expect_refusal(
799
+ case,
800
+ "%s dispatched under a standing grant and a permissive validator"
801
+ % tool_name,
802
+ lambda: _dispatch(
803
+ harness,
804
+ scenario,
805
+ validator=lambda *_: _permissive_authorization(
806
+ scenario, granted=True
807
+ ),
808
+ ),
809
+ )
810
+ _require_unconsumed(harness, scenario, case)
811
+ finally:
812
+ harness.close()
813
+
814
+
815
+ def check_observation_budget_exhaustion(factory: HarnessFactory) -> None:
816
+ """I7: the observation journal is consumed durably BEFORE each GET and
817
+ the action terminalizes as explicitly ambiguous when the budget runs
818
+ out — it never becomes retryable.
819
+
820
+ Catches: a store with unbounded reconciliation or one that converts an
821
+ exhausted observation into a fresh mutation attempt."""
822
+
823
+ case = "observation_budget_exhaustion"
824
+ harness = factory()
825
+ try:
826
+ scenario = _gated(harness)
827
+ dispatched, request = _dispatch_ok(
828
+ harness, scenario, max_observations=2
829
+ )
830
+ _action, first = harness.store.begin_dispatched_observation(
831
+ dispatched["action_id"], OWNER_A, request["execution_digest"]
832
+ )
833
+ _require(first is not None, case, "attempt 1 was not journaled")
834
+ harness.store.defer_dispatched_observation(
835
+ dispatched["action_id"],
836
+ OWNER_A,
837
+ request["execution_digest"],
838
+ first["receipt_key"],
839
+ "unresolved",
840
+ 1.0,
841
+ )
842
+ harness.advance(2.0)
843
+ released = harness.store.lease_dispatched_observation(
844
+ OWNER_A, lease_seconds=LEASE_SECONDS
845
+ )
846
+ _require(released is not None, case, "deferred observation never re-leased")
847
+ _action, second = harness.store.begin_dispatched_observation(
848
+ dispatched["action_id"], OWNER_A, request["execution_digest"]
849
+ )
850
+ _require(second is not None, case, "attempt 2 was not journaled")
851
+ final = harness.store.defer_dispatched_observation(
852
+ dispatched["action_id"],
853
+ OWNER_A,
854
+ request["execution_digest"],
855
+ second["receipt_key"],
856
+ "unresolved",
857
+ 1.0,
858
+ )
859
+ _require(
860
+ final["state"] == "failed"
861
+ and isinstance(final.get("result"), Mapping)
862
+ and final["result"].get("status") == "ambiguous",
863
+ case,
864
+ "an exhausted observation budget did not terminalize as "
865
+ "explicitly ambiguous",
866
+ )
867
+ _require(
868
+ int(final["attempt_count"]) == 1,
869
+ case,
870
+ "exhaustion consumed another mutation attempt",
871
+ )
872
+ finally:
873
+ harness.close()
874
+
875
+
876
+ def check_observation_deadline_exhaustion(factory: HarnessFactory) -> None:
877
+ """I7: once the observation deadline passes, the action terminalizes as
878
+ ambiguous instead of observing (or mutating) further."""
879
+
880
+ case = "observation_deadline_exhaustion"
881
+ harness = factory()
882
+ try:
883
+ scenario = _gated(harness)
884
+ dispatched, request = _dispatch_ok(
885
+ harness, scenario, window=100.0, max_observations=5
886
+ )
887
+ _action, first = harness.store.begin_dispatched_observation(
888
+ dispatched["action_id"], OWNER_A, request["execution_digest"]
889
+ )
890
+ _require(first is not None, case, "attempt 1 was not journaled")
891
+ harness.store.defer_dispatched_observation(
892
+ dispatched["action_id"],
893
+ OWNER_A,
894
+ request["execution_digest"],
895
+ first["receipt_key"],
896
+ "unresolved",
897
+ 1.0,
898
+ )
899
+ harness.advance(150.0) # past the observation deadline
900
+ leased = harness.store.lease_dispatched_observation(
901
+ OWNER_A, lease_seconds=LEASE_SECONDS
902
+ )
903
+ _require(
904
+ leased is None or leased["action_id"] != dispatched["action_id"],
905
+ case,
906
+ "an over-deadline observation contract was leased again",
907
+ )
908
+ final = harness.store.get_action(dispatched["action_id"])
909
+ _require(
910
+ final["state"] == "failed"
911
+ and isinstance(final.get("result"), Mapping)
912
+ and final["result"].get("status") == "ambiguous",
913
+ case,
914
+ "an over-deadline dispatch did not terminalize as ambiguous",
915
+ )
916
+ finally:
917
+ harness.close()
918
+
919
+
920
+ def check_dispatched_never_regates(factory: HarnessFactory) -> None:
921
+ """I6/I10: after the one mutation attempt, a failure — even one claimed
922
+ to be retryable — must terminalize, never return the action to gated.
923
+
924
+ Catches: a store carrying the general-purpose retry edge into the
925
+ governed subset, which would re-dispatch a possibly-performed effect."""
926
+
927
+ case = "dispatched_never_regates"
928
+ harness = factory()
929
+ try:
930
+ scenario = _gated(harness)
931
+ dispatched, _request = _dispatch_ok(harness, scenario)
932
+ failed = harness.store.fail_attempt(
933
+ dispatched["action_id"], OWNER_A, "provider timeout", True
934
+ )
935
+ _require(
936
+ failed["state"] == "failed",
937
+ case,
938
+ "a retryable failure re-opened a dispatched action "
939
+ "(state %r)" % failed["state"],
940
+ )
941
+ _require(
942
+ int(failed["attempt_count"]) == 1 and failed["lease_owner"] is None,
943
+ case,
944
+ "the terminal failure left attempt count or lease inconsistent",
945
+ )
946
+ finally:
947
+ harness.close()
948
+
949
+
950
+ def check_receipt_and_idempotency_immutability(factory: HarnessFactory) -> None:
951
+ """I1/I2: reusing an idempotency key or a receipt key with different
952
+ content must conflict; identical replays must be no-ops."""
953
+
954
+ case = "receipt_and_idempotency_immutability"
955
+ harness = factory()
956
+ try:
957
+ scenario = _gated(harness)
958
+ other_intent = build_intent()
959
+ _expect_refusal(
960
+ case,
961
+ "an idempotency key was reused with a different payload",
962
+ lambda: harness.propose(
963
+ idempotency_key=scenario.intent.idempotency_key,
964
+ source=SOURCE,
965
+ source_ref=other_intent.intent_id,
966
+ action_type=DEFAULT_ACTION_TYPE,
967
+ payload=build_envelope(other_intent),
968
+ ),
969
+ )
970
+ mutated = dict(scenario.evidence)
971
+ mutated["decision_id"] = "decision-tampered"
972
+ _expect_refusal(
973
+ case,
974
+ "a gate receipt key was reused with different evidence",
975
+ lambda: harness.add_gate(
976
+ scenario.action["action_id"],
977
+ mutated,
978
+ receipt_key=scenario.gate_receipt["receipt_key"],
979
+ external_id=mutated["approval_id"],
980
+ ),
981
+ )
982
+ # Identical replay is an idempotent no-op.
983
+ _action, replay = harness.add_gate(
984
+ scenario.action["action_id"],
985
+ scenario.evidence,
986
+ receipt_key=scenario.gate_receipt["receipt_key"],
987
+ external_id=scenario.evidence["approval_id"],
988
+ )
989
+ _require(
990
+ replay["evidence_sha256"] == scenario.gate_receipt["evidence_sha256"],
991
+ case,
992
+ "an identical gate replay was not idempotent",
993
+ )
994
+ gates = [
995
+ receipt
996
+ for receipt in harness.store.list_receipts(scenario.action["action_id"])
997
+ if receipt["kind"] == GATE_RECEIPT_KIND
998
+ ]
999
+ _require(len(gates) == 1, case, "the idempotent replay duplicated the gate")
1000
+ finally:
1001
+ harness.close()
1002
+
1003
+
1004
+ def check_verify_requires_durable_acceptance(factory: HarnessFactory) -> None:
1005
+ """I9: an action cannot reach verified without its durable acceptance
1006
+ receipt existing in the same store."""
1007
+
1008
+ case = "verify_requires_durable_acceptance"
1009
+ harness = factory()
1010
+ try:
1011
+ scenario = _gated(harness)
1012
+ dispatched, request = _dispatch_ok(harness, scenario)
1013
+ acceptance_key = "governed-action-acceptance:" + request["execution_digest"]
1014
+ accepted, _receipt = harness.store.accept(
1015
+ dispatched["action_id"],
1016
+ OWNER_A,
1017
+ acceptance_key,
1018
+ "governed_action_acceptance",
1019
+ {"status": "completed"},
1020
+ )
1021
+ _expect_refusal(
1022
+ case,
1023
+ "verify passed without its qualifying acceptance receipt",
1024
+ lambda: harness.store.verify(
1025
+ accepted["action_id"],
1026
+ OWNER_A,
1027
+ "governed-action-verification:" + request["execution_digest"],
1028
+ {"status": "completed"},
1029
+ qualifying_receipt_keys=("no-such-receipt-key",),
1030
+ ),
1031
+ )
1032
+ current = harness.store.get_action(accepted["action_id"])
1033
+ _require(
1034
+ current["state"] == "accepted",
1035
+ case,
1036
+ "the refused verification changed lifecycle state",
1037
+ )
1038
+ finally:
1039
+ harness.close()
1040
+
1041
+
1042
+ CASES: tuple[Callable[[HarnessFactory], None], ...] = (
1043
+ check_happy_path_lifecycle,
1044
+ check_gate_validator_runs_inside_dispatch,
1045
+ check_evidence_mutated_between_precheck_and_dispatch,
1046
+ check_duplicate_gates_refused,
1047
+ check_tampered_gate_binding_refused,
1048
+ check_crash_between_dispatch_and_put,
1049
+ check_lease_steal_during_observation,
1050
+ check_expired_gate_at_point_of_use,
1051
+ check_expired_grant_at_point_of_use,
1052
+ check_non_grantable_tool_with_grant_proof,
1053
+ check_observation_budget_exhaustion,
1054
+ check_observation_deadline_exhaustion,
1055
+ check_dispatched_never_regates,
1056
+ check_receipt_and_idempotency_immutability,
1057
+ check_verify_requires_durable_acceptance,
1058
+ )
1059
+
1060
+
1061
+ def run_store_conformance(factory: HarnessFactory) -> list[ConformanceResult]:
1062
+ """Run every case against fresh harnesses; a crash is a failure too."""
1063
+
1064
+ results = []
1065
+ for case in CASES:
1066
+ name = case.__name__
1067
+ try:
1068
+ case(factory)
1069
+ except ConformanceFailure as failure:
1070
+ results.append(ConformanceResult(name=name, passed=False, detail=str(failure)))
1071
+ except Exception as error: # a store crashing mid-case is a failure
1072
+ results.append(
1073
+ ConformanceResult(
1074
+ name=name,
1075
+ passed=False,
1076
+ detail="store raised %r" % (error,),
1077
+ )
1078
+ )
1079
+ else:
1080
+ results.append(ConformanceResult(name=name, passed=True))
1081
+ return results
1082
+
1083
+
1084
+ def assert_store_conformance(factory: HarnessFactory) -> list[ConformanceResult]:
1085
+ """Raise :class:`ConformanceFailure` unless EVERY case passes."""
1086
+
1087
+ results = run_store_conformance(factory)
1088
+ failures = [result for result in results if not result.passed]
1089
+ if failures:
1090
+ raise ConformanceFailure(
1091
+ "store adapter failed %d/%d conformance cases:\n%s"
1092
+ % (
1093
+ len(failures),
1094
+ len(results),
1095
+ "\n".join(
1096
+ " - %s: %s" % (item.name, item.detail) for item in failures
1097
+ ),
1098
+ )
1099
+ )
1100
+ return results
1101
+
1102
+
1103
+ __all__ = (
1104
+ "CASES",
1105
+ "ConformanceFailure",
1106
+ "ConformanceResult",
1107
+ "assert_store_conformance",
1108
+ "run_store_conformance",
1109
+ )