openworkproof 1.0.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.
Files changed (39) hide show
  1. openworkproof/__init__.py +1 -0
  2. openworkproof/acceptance.py +3006 -0
  3. openworkproof/cli.py +164 -0
  4. openworkproof/composition.py +832 -0
  5. openworkproof/evidence.py +8281 -0
  6. openworkproof/execution_adapter.py +256 -0
  7. openworkproof/external_acceptor.py +211 -0
  8. openworkproof/mcp_server.py +2939 -0
  9. openworkproof/mcp_transport.py +72 -0
  10. openworkproof/models.py +3380 -0
  11. openworkproof/policy.py +2494 -0
  12. openworkproof/predicates.py +333 -0
  13. openworkproof/repo_pipeline/__init__.py +74 -0
  14. openworkproof/repo_pipeline/analysis.py +152 -0
  15. openworkproof/repo_pipeline/errors.py +64 -0
  16. openworkproof/repo_pipeline/models.py +80 -0
  17. openworkproof/repo_pipeline/output.py +68 -0
  18. openworkproof/repo_pipeline/reader.py +47 -0
  19. openworkproof/repo_pipeline/sources.py +120 -0
  20. openworkproof/repo_pipeline/traversal.py +253 -0
  21. openworkproof/repo_tools.py +8382 -0
  22. openworkproof/runtime_context.py +189 -0
  23. openworkproof/schema_registry.py +623 -0
  24. openworkproof/schemas/v0.1/acceptance-receipt.schema.json +1 -0
  25. openworkproof/schemas/v0.1/acceptance-rejection-receipt.schema.json +1 -0
  26. openworkproof/schemas/v0.1/action-receipt.schema.json +1 -0
  27. openworkproof/schemas/v0.1/capability-grant.schema.json +1 -0
  28. openworkproof/schemas/v0.1/schema-registry.json +1 -0
  29. openworkproof/schemas/v0.1/work-order.schema.json +1 -0
  30. openworkproof/signing.py +421 -0
  31. openworkproof/state.py +765 -0
  32. openworkproof/team_network_client.py +419 -0
  33. openworkproof/trusted_helper.py +269 -0
  34. openworkproof-1.0.0.dist-info/METADATA +578 -0
  35. openworkproof-1.0.0.dist-info/RECORD +39 -0
  36. openworkproof-1.0.0.dist-info/WHEEL +5 -0
  37. openworkproof-1.0.0.dist-info/entry_points.txt +2 -0
  38. openworkproof-1.0.0.dist-info/licenses/LICENSE +202 -0
  39. openworkproof-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,832 @@
1
+ """Bounded causal replay for authorization receipt histories."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from dataclasses import dataclass
7
+ from itertools import islice
8
+
9
+ from openworkproof.models import (
10
+ ActionReceiptEnvelope,
11
+ ApprovalDecisionReceipt,
12
+ ApprovalRequestedReceipt,
13
+ ComposeProofArguments,
14
+ CreatePrProposalArguments,
15
+ GrantConsumedReceipt,
16
+ GrantIssuedReceipt,
17
+ GrantRevokedReceipt,
18
+ RollbackReceipt,
19
+ SystemEventReceipt,
20
+ TerminationDecisionReceipt,
21
+ ToolCallReceipt,
22
+ WorkOrder,
23
+ )
24
+
25
+
26
+ MAX_AUTHORIZATION_RECEIPTS = 64
27
+
28
+
29
+ class AuthorizationCausalityError(RuntimeError):
30
+ """Authorization receipt causality could not be replayed exactly."""
31
+
32
+
33
+ @dataclass(frozen=True)
34
+ class AuthorizationCausalSnapshot:
35
+ """Immutable causal facts visible at one signed receipt."""
36
+
37
+ active_patch_receipt_id: str | None
38
+ failure_receipt_id: str | None
39
+ rollback_receipt_id: str | None
40
+ latest_composition_trigger_id: str | None
41
+ independent_result_receipt_id: str | None
42
+ approval_decision_by_request: tuple[tuple[str, str], ...]
43
+
44
+
45
+ @dataclass(frozen=True)
46
+ class AuthorizationCausalState(AuthorizationCausalSnapshot):
47
+ """Immutable final facts and bounded per-receipt causal snapshots."""
48
+
49
+ independent_failure_terminal: bool
50
+ snapshots_by_receipt: tuple[
51
+ tuple[str, AuthorizationCausalSnapshot],
52
+ ...,
53
+ ]
54
+
55
+ def snapshot_for(self, receipt_id: str) -> AuthorizationCausalSnapshot:
56
+ for candidate_id, snapshot in self.snapshots_by_receipt:
57
+ if candidate_id == receipt_id:
58
+ return snapshot
59
+ raise _fail("receipt causal snapshot is unavailable")
60
+
61
+
62
+ @dataclass(frozen=True)
63
+ class _CausalIndex:
64
+ by_id: dict[str, ActionReceiptEnvelope]
65
+ by_digest: dict[str, ActionReceiptEnvelope]
66
+ by_sequence: dict[int, ActionReceiptEnvelope]
67
+ issuance_by_grant: dict[str, GrantIssuedReceipt]
68
+
69
+
70
+ def _fail(message: str) -> AuthorizationCausalityError:
71
+ return AuthorizationCausalityError(message)
72
+
73
+
74
+ def _bounded_receipts(
75
+ receipts: Iterable[ActionReceiptEnvelope],
76
+ ) -> tuple[ActionReceiptEnvelope, ...]:
77
+ try:
78
+ bounded = tuple(
79
+ islice(receipts, MAX_AUTHORIZATION_RECEIPTS + 1)
80
+ )
81
+ except AuthorizationCausalityError:
82
+ raise
83
+ except Exception as error:
84
+ raise _fail(
85
+ "receipt history input is unavailable"
86
+ ) from error
87
+ if len(bounded) > MAX_AUTHORIZATION_RECEIPTS:
88
+ raise _fail("receipt history exceeds its bounded input capacity")
89
+ return bounded
90
+
91
+
92
+ def _build_index(
93
+ receipts: tuple[ActionReceiptEnvelope, ...],
94
+ ) -> _CausalIndex:
95
+ by_id: dict[str, ActionReceiptEnvelope] = {}
96
+ by_digest: dict[str, ActionReceiptEnvelope] = {}
97
+ by_sequence: dict[int, ActionReceiptEnvelope] = {}
98
+ issuance_by_grant: dict[str, GrantIssuedReceipt] = {}
99
+ for receipt in receipts:
100
+ if (
101
+ receipt.receipt_id in by_id
102
+ or receipt.digest in by_digest
103
+ or receipt.sequence in by_sequence
104
+ ):
105
+ raise _fail("receipt history index is not unique")
106
+ by_id[receipt.receipt_id] = receipt
107
+ by_digest[receipt.digest] = receipt
108
+ by_sequence[receipt.sequence] = receipt
109
+ if (
110
+ isinstance(receipt, GrantIssuedReceipt)
111
+ and receipt.policy_decision == "allow"
112
+ and receipt.execution_status == "succeeded"
113
+ and receipt.issued_grant_id is not None
114
+ ):
115
+ if receipt.issued_grant_id in issuance_by_grant:
116
+ raise _fail("Grant issuance index is not unique")
117
+ issuance_by_grant[receipt.issued_grant_id] = receipt
118
+ return _CausalIndex(
119
+ by_id=by_id,
120
+ by_digest=by_digest,
121
+ by_sequence=by_sequence,
122
+ issuance_by_grant=issuance_by_grant,
123
+ )
124
+
125
+
126
+ def validate_authorization_causal_bindings(
127
+ work_order: WorkOrder,
128
+ receipts: tuple[ActionReceiptEnvelope, ...],
129
+ causal_state: AuthorizationCausalState,
130
+ ) -> None:
131
+ """Compare caller state with canonical replay of its bounded snapshot."""
132
+
133
+ canonical = replay_authorization_causality(work_order, receipts)
134
+ if canonical != causal_state:
135
+ raise _fail(
136
+ "canonical causal state rejects the supplied causal binding"
137
+ )
138
+
139
+
140
+ def replay_authorization_causality(
141
+ work_order: WorkOrder,
142
+ receipts: Iterable[ActionReceiptEnvelope],
143
+ ) -> AuthorizationCausalState:
144
+ """Replay exact semantic parents and return the frozen causal state."""
145
+
146
+ if not isinstance(work_order, WorkOrder):
147
+ raise _fail("WorkOrder is unavailable for causal replay")
148
+ bounded = _bounded_receipts(receipts)
149
+ if any(
150
+ not isinstance(receipt, ActionReceiptEnvelope)
151
+ for receipt in bounded
152
+ ):
153
+ raise _fail("receipt history contains a malformed receipt")
154
+ index = _build_index(bounded)
155
+ ordered = bounded
156
+ roles_by_key = {
157
+ binding.key_id: binding.role
158
+ for binding in work_order.key_bindings
159
+ }
160
+ roles_by_actor = {
161
+ (binding.subject_id, binding.key_id): binding.role
162
+ for binding in work_order.key_bindings
163
+ }
164
+ previous: ActionReceiptEnvelope | None = None
165
+ for expected_sequence, receipt in enumerate(ordered, start=1):
166
+ if (
167
+ receipt.work_order_digest != work_order.digest
168
+ or receipt.sequence != expected_sequence
169
+ or receipt.previous_receipt_digest
170
+ != (previous.digest if previous is not None else None)
171
+ ):
172
+ raise _fail(
173
+ "receipt chain origin or adjacency is invalid"
174
+ )
175
+ previous = receipt
176
+ if ordered:
177
+ first = ordered[0]
178
+ root_grant_id = work_order.root_grant_template.grant_id
179
+ root_activation = (
180
+ isinstance(first, GrantIssuedReceipt)
181
+ and first.parent_grant_id is None
182
+ and first.authorizing_grant_id == root_grant_id
183
+ and first.issued_grant_id == root_grant_id
184
+ and first.policy_decision == "allow"
185
+ and first.execution_status == "succeeded"
186
+ and first.state_before == "issued"
187
+ and first.state_after == "running"
188
+ and first.parent_receipt_ids == ()
189
+ and roles_by_actor.get(
190
+ (first.actor_id, first.actor_key_id)
191
+ )
192
+ == "Manager"
193
+ )
194
+ cause = (
195
+ first.cause
196
+ if isinstance(first, SystemEventReceipt)
197
+ else None
198
+ )
199
+ contract_expiry = (
200
+ isinstance(first, SystemEventReceipt)
201
+ and first.system_event_name == "contract_expired"
202
+ and first.error_code == "CONTRACT_EXPIRED"
203
+ and first.policy_decision == "not_applicable"
204
+ and first.execution_status == "succeeded"
205
+ and first.state_before == "issued"
206
+ and first.state_after == "frozen"
207
+ and first.parent_receipt_ids == ()
208
+ and roles_by_actor.get(
209
+ (first.actor_id, first.actor_key_id)
210
+ )
211
+ == "Sidecar"
212
+ and getattr(cause, "deadline", None)
213
+ == work_order.deadline
214
+ and getattr(cause, "observed_at", None)
215
+ == first.occurred_at
216
+ and getattr(cause, "tip_receipt_digest", None) is None
217
+ and first.occurred_at > work_order.deadline
218
+ )
219
+ maintainer_termination = (
220
+ isinstance(first, TerminationDecisionReceipt)
221
+ and first.policy_decision == "allow"
222
+ and first.execution_status == "succeeded"
223
+ and first.state_before == "issued"
224
+ and first.state_after == "rejected"
225
+ and first.parent_receipt_ids == ()
226
+ and first.target_work_order_digest == work_order.digest
227
+ and roles_by_actor.get(
228
+ (first.actor_id, first.actor_key_id)
229
+ )
230
+ == "Maintainer"
231
+ and first.decided_at >= work_order.issued_at
232
+ and first.occurred_at >= first.decided_at
233
+ and (
234
+ first.occurred_at - first.decided_at
235
+ ).total_seconds()
236
+ <= 300
237
+ and first.occurred_at <= work_order.deadline
238
+ )
239
+ if sum(
240
+ (root_activation, contract_expiry, maintainer_termination)
241
+ ) != 1:
242
+ raise _fail("receipt chain has no valid genesis event")
243
+ prior: list[ActionReceiptEnvelope] = []
244
+ active_patch: ToolCallReceipt | None = None
245
+ current_failure: ToolCallReceipt | None = None
246
+ current_rollback: RollbackReceipt | None = None
247
+ latest_passing_result: ToolCallReceipt | None = None
248
+ latest_composition_trigger: SystemEventReceipt | None = None
249
+ independent_result: ToolCallReceipt | None = None
250
+ independent_failure_terminal = False
251
+ last_independent_attempt: ToolCallReceipt | None = None
252
+ sealed_tail_appended = False
253
+ started_execution_context_ids: set[str] = set()
254
+ started_container_instance_digests: set[str] = set()
255
+ latest_revocation: dict[str, GrantRevokedReceipt] = {}
256
+ decision_by_request: dict[str, ApprovalDecisionReceipt] = {}
257
+ snapshots_by_receipt: list[
258
+ tuple[str, AuthorizationCausalSnapshot]
259
+ ] = []
260
+
261
+ def verifier_result_passed(receipt: ToolCallReceipt) -> bool:
262
+ results = tuple(
263
+ result
264
+ for result in receipt.predicate_results
265
+ if result.name == "tests_passed"
266
+ )
267
+ return bool(results) and all(
268
+ result.passed for result in results
269
+ )
270
+
271
+ def prior_receipt(
272
+ current: ActionReceiptEnvelope,
273
+ receipt_id: str,
274
+ *,
275
+ digest: str | None = None,
276
+ expected_type=None,
277
+ ) -> ActionReceiptEnvelope:
278
+ candidate = index.by_id.get(receipt_id)
279
+ if (
280
+ candidate is None
281
+ or candidate.sequence >= current.sequence
282
+ or (digest is not None and candidate.digest != digest)
283
+ or (
284
+ expected_type is not None
285
+ and not isinstance(candidate, expected_type)
286
+ )
287
+ ):
288
+ raise _fail("receipt causal reference is unavailable")
289
+ return candidate
290
+
291
+ def prior_digest(
292
+ current: ActionReceiptEnvelope,
293
+ digest: str,
294
+ *,
295
+ expected_type=None,
296
+ ) -> ActionReceiptEnvelope:
297
+ candidate = index.by_digest.get(digest)
298
+ if candidate is None:
299
+ raise _fail("receipt causal digest is unavailable")
300
+ return prior_receipt(
301
+ current,
302
+ candidate.receipt_id,
303
+ digest=digest,
304
+ expected_type=expected_type,
305
+ )
306
+
307
+ def grant_issuance(
308
+ current: ActionReceiptEnvelope,
309
+ grant_id: str,
310
+ ) -> GrantIssuedReceipt:
311
+ issuance = index.issuance_by_grant.get(grant_id)
312
+ if issuance is None:
313
+ raise _fail("receipt authorizing Grant issuance is unavailable")
314
+ candidate = prior_receipt(
315
+ current,
316
+ issuance.receipt_id,
317
+ expected_type=GrantIssuedReceipt,
318
+ )
319
+ assert isinstance(candidate, GrantIssuedReceipt)
320
+ return candidate
321
+
322
+ for receipt in ordered:
323
+ if independent_failure_terminal:
324
+ termination = (
325
+ isinstance(receipt, TerminationDecisionReceipt)
326
+ and receipt.state_before == "evidence_incomplete"
327
+ and receipt.state_after == "rejected"
328
+ and receipt.policy_decision == "allow"
329
+ and receipt.execution_status == "succeeded"
330
+ )
331
+ contract_expiry = (
332
+ isinstance(receipt, SystemEventReceipt)
333
+ and receipt.system_event_name == "contract_expired"
334
+ and receipt.error_code == "CONTRACT_EXPIRED"
335
+ and receipt.state_before == "evidence_incomplete"
336
+ and receipt.state_after == "frozen"
337
+ )
338
+ if sealed_tail_appended or not (termination or contract_expiry):
339
+ raise _fail(
340
+ "independent evidence failure sealed the episode"
341
+ )
342
+ sealed_tail_appended = True
343
+ root_activation = (
344
+ isinstance(receipt, GrantIssuedReceipt)
345
+ and receipt.parent_grant_id is None
346
+ and receipt.policy_decision == "allow"
347
+ and receipt.execution_status == "succeeded"
348
+ )
349
+ parents: dict[str, ActionReceiptEnvelope] = {}
350
+
351
+ def add_parent(parent: ActionReceiptEnvelope) -> None:
352
+ parents[parent.receipt_id] = parent
353
+
354
+ if root_activation:
355
+ if receipt.sequence != 1:
356
+ raise _fail("root activation is not the genesis receipt")
357
+ elif receipt.actor_type == "agent":
358
+ grant_id_value = (
359
+ receipt.authorizing_grant_id
360
+ if isinstance(
361
+ receipt,
362
+ (GrantIssuedReceipt, GrantRevokedReceipt),
363
+ )
364
+ else receipt.grant_id
365
+ )
366
+ add_parent(grant_issuance(receipt, grant_id_value))
367
+ if receipt.policy_decision == "deny":
368
+ revocation = latest_revocation.get(grant_id_value)
369
+ if revocation is not None:
370
+ add_parent(revocation)
371
+ if receipt.policy_error_code == "STATE_DENIED" and prior:
372
+ add_parent(prior[-1])
373
+
374
+ if isinstance(receipt, GrantConsumedReceipt):
375
+ if current_failure is not None and current_rollback is not None:
376
+ add_parent(current_failure)
377
+ add_parent(current_rollback)
378
+ if (
379
+ receipt.policy_decision == "allow"
380
+ and (
381
+ current_failure is None
382
+ or current_rollback is None
383
+ or current_rollback.sequence
384
+ <= current_failure.sequence
385
+ )
386
+ ):
387
+ raise _fail("retry causal episode is unavailable")
388
+ elif isinstance(receipt, GrantRevokedReceipt):
389
+ add_parent(
390
+ grant_issuance(receipt, receipt.revoked_grant_id)
391
+ )
392
+ elif isinstance(receipt, ToolCallReceipt):
393
+ if receipt.tool_name == "owp.repo_read":
394
+ if active_patch is not None:
395
+ add_parent(active_patch)
396
+ elif receipt.tool_name == "owp.apply_patch":
397
+ # A patch that follows a repo-read causally depends on the
398
+ # read: the exact historical replay must mirror the
399
+ # publication tip-parent rule (the latest repo-read on the
400
+ # same grant is a causal parent of the patch).
401
+ prior_read = next(
402
+ (
403
+ item
404
+ for item in reversed(prior)
405
+ if isinstance(item, ToolCallReceipt)
406
+ and item.tool_name == "owp.repo_read"
407
+ and item.grant_id == receipt.grant_id
408
+ ),
409
+ None,
410
+ )
411
+ if prior_read is not None:
412
+ add_parent(prior_read)
413
+ elif receipt.tool_name == "owp.run_tests":
414
+ # An independent episode is identified by its state pair and
415
+ # role alone: both succeeded and closed infrastructure-failed
416
+ # (TIMEOUT / OUTPUT_LIMIT / DISK_LIMIT) receipts carry the
417
+ # same proof_composed parent and the same fresh execution
418
+ # context requirements, so causal replay must accept either.
419
+ is_independent_attempt = (
420
+ receipt.state_before == "evidence_incomplete"
421
+ and receipt.state_after == "evidence_incomplete"
422
+ and receipt.policy_decision == "allow"
423
+ and roles_by_key.get(receipt.actor_key_id)
424
+ == "Verifier"
425
+ )
426
+ if active_patch is not None:
427
+ add_parent(active_patch)
428
+ elif receipt.policy_decision == "allow":
429
+ raise _fail("tested patch receipt is unavailable")
430
+ if is_independent_attempt:
431
+ if latest_composition_trigger is None:
432
+ raise _fail(
433
+ "independent result episode is unavailable"
434
+ )
435
+ add_parent(latest_composition_trigger)
436
+ # A retry after an infrastructure failure links to the
437
+ # previous closed failure receipt of the same episode.
438
+ if last_independent_attempt is not None:
439
+ add_parent(last_independent_attempt)
440
+ factors = receipt.correlation_factors
441
+ if (
442
+ factors.execution_context_id is None
443
+ or factors.container_instance_id_digest is None
444
+ or factors.execution_context_id
445
+ in started_execution_context_ids
446
+ or factors.container_instance_id_digest
447
+ in started_container_instance_digests
448
+ ):
449
+ raise _fail(
450
+ "independent result requires fresh execution context"
451
+ )
452
+ if (
453
+ verifier_result_passed(receipt)
454
+ and independent_result is not None
455
+ ):
456
+ raise _fail(
457
+ "independent result episode is unavailable"
458
+ )
459
+ elif receipt.tool_name == "owp.create_pr_proposal":
460
+ arguments = receipt.request_arguments
461
+ if not isinstance(arguments, CreatePrProposalArguments):
462
+ raise _fail("PR proposal arguments are unavailable")
463
+ patch = prior_digest(
464
+ receipt,
465
+ arguments.target_patch_digest,
466
+ expected_type=ToolCallReceipt,
467
+ )
468
+ if (
469
+ patch.tool_name != "owp.apply_patch"
470
+ or patch is not active_patch
471
+ ):
472
+ raise _fail("PR proposal target patch is not active")
473
+ decision = prior_receipt(
474
+ receipt,
475
+ receipt.approval_receipt_id,
476
+ digest=receipt.approval_receipt_digest,
477
+ expected_type=ApprovalDecisionReceipt,
478
+ )
479
+ assert isinstance(decision, ApprovalDecisionReceipt)
480
+ request = prior_receipt(
481
+ receipt,
482
+ decision.request_receipt_id,
483
+ digest=decision.request_receipt_digest,
484
+ expected_type=ApprovalRequestedReceipt,
485
+ )
486
+ assert isinstance(request, ApprovalRequestedReceipt)
487
+ scope = {
488
+ "work_order_digest": work_order.digest,
489
+ "operation": "create_local_pr_proposal",
490
+ "target_patch_digest": patch.digest,
491
+ }
492
+ if (
493
+ request.request_kind != "high_risk_action"
494
+ or dict(request.requested_scope) != scope
495
+ or dict(decision.approved_scope) != scope
496
+ or request.expires_at != decision.expires_at
497
+ or decision_by_request.get(request.receipt_id)
498
+ is not decision
499
+ ):
500
+ raise _fail("PR proposal approval binding is invalid")
501
+ add_parent(patch)
502
+ add_parent(decision)
503
+ elif receipt.tool_name == "owp.compose_proof":
504
+ arguments = receipt.request_arguments
505
+ if not isinstance(arguments, ComposeProofArguments):
506
+ raise _fail("composition arguments are unavailable")
507
+ if receipt.state_before == "evidence_incomplete":
508
+ if (
509
+ latest_composition_trigger is None
510
+ or independent_result is None
511
+ ):
512
+ raise _fail(
513
+ "recomposition causal inputs are unavailable"
514
+ )
515
+ add_parent(latest_composition_trigger)
516
+ add_parent(independent_result)
517
+ if (
518
+ arguments.previous_report_digest
519
+ != latest_composition_trigger.cause.composition_report_digest
520
+ ):
521
+ raise _fail(
522
+ "composition previous report digest is invalid"
523
+ )
524
+ else:
525
+ if (
526
+ receipt.state_before == "locally_verified"
527
+ and arguments.previous_report_digest is not None
528
+ ):
529
+ raise _fail(
530
+ "composition previous report digest is invalid"
531
+ )
532
+ if active_patch is not None:
533
+ add_parent(active_patch)
534
+ if latest_passing_result is not None:
535
+ add_parent(latest_passing_result)
536
+ if (
537
+ receipt.policy_decision == "allow"
538
+ and (
539
+ active_patch is None
540
+ or latest_passing_result is None
541
+ )
542
+ ):
543
+ raise _fail(
544
+ "composition causal inputs are unavailable"
545
+ )
546
+ elif isinstance(receipt, ApprovalRequestedReceipt):
547
+ scope = dict(receipt.requested_scope)
548
+ if receipt.request_kind == "high_risk_action":
549
+ patch = prior_digest(
550
+ receipt,
551
+ scope["target_patch_digest"],
552
+ expected_type=ToolCallReceipt,
553
+ )
554
+ if (
555
+ patch.tool_name != "owp.apply_patch"
556
+ or patch is not active_patch
557
+ ):
558
+ raise _fail("approval target patch is not active")
559
+ add_parent(patch)
560
+ else:
561
+ report_digest = scope["composition_report_digest"]
562
+ trigger = next(
563
+ (
564
+ item
565
+ for item in reversed(prior)
566
+ if (
567
+ isinstance(item, SystemEventReceipt)
568
+ and item.system_event_name
569
+ == "proof_composed"
570
+ and getattr(
571
+ item.cause,
572
+ "composition_report_digest",
573
+ None,
574
+ )
575
+ == report_digest
576
+ )
577
+ ),
578
+ None,
579
+ )
580
+ if trigger is None:
581
+ raise _fail(
582
+ "final approval trigger is unavailable"
583
+ )
584
+ add_parent(trigger)
585
+ elif isinstance(receipt, ApprovalDecisionReceipt):
586
+ request = prior_receipt(
587
+ receipt,
588
+ receipt.request_receipt_id,
589
+ digest=receipt.request_receipt_digest,
590
+ expected_type=ApprovalRequestedReceipt,
591
+ )
592
+ assert isinstance(request, ApprovalRequestedReceipt)
593
+ if receipt.request_receipt_id in decision_by_request:
594
+ raise _fail(
595
+ "approval request has more than one decision"
596
+ )
597
+ if (
598
+ receipt.approved_scope != request.requested_scope
599
+ or receipt.expires_at != request.expires_at
600
+ or receipt.decided_at < request.occurred_at
601
+ or receipt.decided_at > request.expires_at
602
+ or receipt.occurred_at < receipt.decided_at
603
+ or (
604
+ receipt.occurred_at - receipt.decided_at
605
+ ).total_seconds()
606
+ > 300
607
+ ):
608
+ raise _fail("approval decision is stale or mismatched")
609
+ decision_by_request[receipt.request_receipt_id] = receipt
610
+ add_parent(request)
611
+ elif isinstance(receipt, RollbackReceipt):
612
+ patch = prior_receipt(
613
+ receipt,
614
+ receipt.target_patch_receipt_id,
615
+ digest=receipt.target_patch_digest,
616
+ expected_type=ToolCallReceipt,
617
+ )
618
+ if (
619
+ patch.tool_name != "owp.apply_patch"
620
+ or patch is not active_patch
621
+ ):
622
+ raise _fail("rollback target is not the active patch")
623
+ add_parent(patch)
624
+ proactive_denial = (
625
+ receipt.policy_decision == "deny"
626
+ and receipt.policy_error_code == "STATE_DENIED"
627
+ and receipt.execution_status == "denied"
628
+ and receipt.state_before == receipt.state_after
629
+ and receipt.state_before in {"running", "retrying"}
630
+ )
631
+ if not proactive_denial:
632
+ failure = current_failure
633
+ if (
634
+ failure is None
635
+ or failure.sequence <= patch.sequence
636
+ or patch.receipt_id not in failure.parent_receipt_ids
637
+ ):
638
+ raise _fail(
639
+ "rollback failure receipt is unavailable"
640
+ )
641
+ add_parent(failure)
642
+ elif isinstance(receipt, SystemEventReceipt):
643
+ if receipt.system_event_name in {
644
+ "proof_composed",
645
+ "security_violation",
646
+ }:
647
+ initiator = prior_digest(
648
+ receipt,
649
+ receipt.cause.initiator_receipt_digest,
650
+ expected_type=ToolCallReceipt,
651
+ )
652
+ parents = {initiator.receipt_id: initiator}
653
+ elif prior:
654
+ parents = {prior[-1].receipt_id: prior[-1]}
655
+ elif isinstance(receipt, TerminationDecisionReceipt):
656
+ parents = (
657
+ {prior[-1].receipt_id: prior[-1]} if prior else {}
658
+ )
659
+
660
+ expected = tuple(
661
+ parent.receipt_id
662
+ for parent in sorted(
663
+ parents.values(),
664
+ key=lambda item: item.sequence,
665
+ )
666
+ )
667
+ if receipt.parent_receipt_ids != expected:
668
+ raise _fail(
669
+ "receipt causal parents failed exact historical replay"
670
+ )
671
+
672
+ if (
673
+ isinstance(receipt, ToolCallReceipt)
674
+ and receipt.tool_name == "owp.apply_patch"
675
+ and receipt.policy_decision == "allow"
676
+ and receipt.execution_status == "succeeded"
677
+ ):
678
+ if active_patch is not None:
679
+ raise _fail("a second active patch is not allowed")
680
+ active_patch = receipt
681
+ current_failure = None
682
+ current_rollback = None
683
+ latest_passing_result = None
684
+ elif (
685
+ isinstance(receipt, RollbackReceipt)
686
+ and receipt.policy_decision == "allow"
687
+ and receipt.execution_status == "succeeded"
688
+ ):
689
+ active_patch = None
690
+ current_rollback = receipt
691
+ if (
692
+ isinstance(receipt, ToolCallReceipt)
693
+ and receipt.tool_name == "owp.run_tests"
694
+ and receipt.policy_decision == "allow"
695
+ and receipt.execution_status == "succeeded"
696
+ ):
697
+ if receipt.state_after == "needs_rework":
698
+ current_failure = receipt
699
+ current_rollback = None
700
+ elif (
701
+ receipt.state_before == "evidence_incomplete"
702
+ and receipt.state_after == "evidence_incomplete"
703
+ and roles_by_key.get(receipt.actor_key_id)
704
+ == "Verifier"
705
+ and verifier_result_passed(receipt)
706
+ ):
707
+ independent_result = receipt
708
+ elif (
709
+ receipt.state_before == "evidence_incomplete"
710
+ and receipt.state_after == "evidence_incomplete"
711
+ and roles_by_key.get(receipt.actor_key_id)
712
+ == "Verifier"
713
+ ):
714
+ independent_failure_terminal = True
715
+ elif receipt.state_after == "locally_verified":
716
+ latest_passing_result = receipt
717
+ if (
718
+ isinstance(receipt, ToolCallReceipt)
719
+ and receipt.tool_name == "owp.run_tests"
720
+ and receipt.state_before == "evidence_incomplete"
721
+ and receipt.state_after == "evidence_incomplete"
722
+ and roles_by_key.get(receipt.actor_key_id) == "Verifier"
723
+ ):
724
+ last_independent_attempt = receipt
725
+ if (
726
+ isinstance(receipt, ToolCallReceipt)
727
+ and receipt.quota_charge is not None
728
+ and roles_by_key.get(receipt.actor_key_id)
729
+ in {"Developer", "Verifier"}
730
+ ):
731
+ factors = receipt.correlation_factors
732
+ if factors.execution_context_id is not None:
733
+ started_execution_context_ids.add(
734
+ factors.execution_context_id
735
+ )
736
+ if factors.container_instance_id_digest is not None:
737
+ started_container_instance_digests.add(
738
+ factors.container_instance_id_digest
739
+ )
740
+ if (
741
+ isinstance(receipt, SystemEventReceipt)
742
+ and receipt.system_event_name == "proof_composed"
743
+ ):
744
+ latest_composition_trigger = receipt
745
+ independent_result = None
746
+ if (
747
+ isinstance(receipt, GrantRevokedReceipt)
748
+ and receipt.policy_decision == "allow"
749
+ and receipt.execution_status == "succeeded"
750
+ ):
751
+ latest_revocation[receipt.revoked_grant_id] = receipt
752
+ snapshots_by_receipt.append(
753
+ (
754
+ receipt.receipt_id,
755
+ AuthorizationCausalSnapshot(
756
+ active_patch_receipt_id=(
757
+ active_patch.receipt_id
758
+ if active_patch is not None
759
+ else None
760
+ ),
761
+ failure_receipt_id=(
762
+ current_failure.receipt_id
763
+ if current_failure is not None
764
+ else None
765
+ ),
766
+ rollback_receipt_id=(
767
+ current_rollback.receipt_id
768
+ if current_rollback is not None
769
+ else None
770
+ ),
771
+ latest_composition_trigger_id=(
772
+ latest_composition_trigger.receipt_id
773
+ if latest_composition_trigger is not None
774
+ else None
775
+ ),
776
+ independent_result_receipt_id=(
777
+ independent_result.receipt_id
778
+ if independent_result is not None
779
+ else None
780
+ ),
781
+ approval_decision_by_request=tuple(
782
+ (request_id, decision.receipt_id)
783
+ for request_id, decision
784
+ in decision_by_request.items()
785
+ ),
786
+ ),
787
+ )
788
+ )
789
+ prior.append(receipt)
790
+
791
+ return AuthorizationCausalState(
792
+ active_patch_receipt_id=(
793
+ active_patch.receipt_id
794
+ if active_patch is not None
795
+ else None
796
+ ),
797
+ failure_receipt_id=(
798
+ current_failure.receipt_id
799
+ if current_failure is not None
800
+ else None
801
+ ),
802
+ rollback_receipt_id=(
803
+ current_rollback.receipt_id
804
+ if current_rollback is not None
805
+ else None
806
+ ),
807
+ latest_composition_trigger_id=(
808
+ latest_composition_trigger.receipt_id
809
+ if latest_composition_trigger is not None
810
+ else None
811
+ ),
812
+ independent_result_receipt_id=(
813
+ independent_result.receipt_id
814
+ if independent_result is not None
815
+ else None
816
+ ),
817
+ approval_decision_by_request=tuple(
818
+ (request_id, decision.receipt_id)
819
+ for request_id, decision in decision_by_request.items()
820
+ ),
821
+ independent_failure_terminal=independent_failure_terminal,
822
+ snapshots_by_receipt=tuple(snapshots_by_receipt),
823
+ )
824
+
825
+
826
+ __all__ = [
827
+ "AuthorizationCausalState",
828
+ "AuthorizationCausalSnapshot",
829
+ "AuthorizationCausalityError",
830
+ "replay_authorization_causality",
831
+ "validate_authorization_causal_bindings",
832
+ ]