capsule-engine 0.1.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 (288) hide show
  1. capsule_engine/__init__.py +17 -0
  2. capsule_engine/bundle_viewer/__init__.py +21 -0
  3. capsule_engine/bundle_viewer/static/offline_shell.html +1509 -0
  4. capsule_engine/bundle_viewer/viewer.py +57 -0
  5. capsule_engine/cli/__init__.py +5 -0
  6. capsule_engine/cli/bundle_cmd.py +269 -0
  7. capsule_engine/cli/console_cmd.py +70 -0
  8. capsule_engine/cli/constraints_cmd.py +74 -0
  9. capsule_engine/cli/format.py +173 -0
  10. capsule_engine/cli/guard_cmds.py +361 -0
  11. capsule_engine/cli/init_cmds.py +169 -0
  12. capsule_engine/cli/main.py +120 -0
  13. capsule_engine/cli/packs_cmds.py +96 -0
  14. capsule_engine/cli/telemetry_cmd.py +80 -0
  15. capsule_engine/cli/tenant_cmds.py +199 -0
  16. capsule_engine/cli/verify_cmd.py +110 -0
  17. capsule_engine/compiler/__init__.py +13 -0
  18. capsule_engine/compiler/effect_model.py +79 -0
  19. capsule_engine/compiler/vocabulary.py +253 -0
  20. capsule_engine/console/__init__.py +10 -0
  21. capsule_engine/console/api.py +251 -0
  22. capsule_engine/console/components.css +406 -0
  23. capsule_engine/console/console.css +130 -0
  24. capsule_engine/console/console.html +51 -0
  25. capsule_engine/console/console.js +330 -0
  26. capsule_engine/console/gallery.html +274 -0
  27. capsule_engine/console/server.py +137 -0
  28. capsule_engine/console/tokens.css +68 -0
  29. capsule_engine/conversation/__init__.py +88 -0
  30. capsule_engine/conversation/capsules.py +268 -0
  31. capsule_engine/conversation/exchange.py +279 -0
  32. capsule_engine/conversation/merkle.py +80 -0
  33. capsule_engine/conversation/session.py +101 -0
  34. capsule_engine/envcompat.py +15 -0
  35. capsule_engine/events/__init__.py +14 -0
  36. capsule_engine/events/capsule.py +133 -0
  37. capsule_engine/examples/__init__.py +9 -0
  38. capsule_engine/examples/data/tau2_airline/LICENSE-tau2-bench +21 -0
  39. capsule_engine/examples/data/tau2_airline/PROVENANCE.json +70 -0
  40. capsule_engine/examples/data/tau2_airline/hand_labels.json +893 -0
  41. capsule_engine/examples/data/tau2_airline/pilot1_live_gemini-2-5-flash_airline_shift1.jsonl +190 -0
  42. capsule_engine/examples/data/tau2_airline/tau2_committed_claude-3-7-sonnet_airline_trial0.jsonl +556 -0
  43. capsule_engine/examples/data/tau2_airline/tau2_committed_gpt-4-1-mini_airline_trial0.jsonl +480 -0
  44. capsule_engine/examples/data/tau2_airline/tau2_committed_gpt-4-1_airline_trial0.jsonl +496 -0
  45. capsule_engine/examples/data/tau2_airline/tau2_committed_o4-mini_airline_trial0.jsonl +392 -0
  46. capsule_engine/examples/data/tau2_airline/tau2_conversations_claude-3-7-sonnet_airline_4trials.jsonl +200 -0
  47. capsule_engine/examples/tau2_airline_reference.py +460 -0
  48. capsule_engine/examples/tau2_conversation_exchange.py +92 -0
  49. capsule_engine/folds/__init__.py +104 -0
  50. capsule_engine/folds/account_core.py +89 -0
  51. capsule_engine/folds/approval_latency.py +86 -0
  52. capsule_engine/folds/catalog.py +79 -0
  53. capsule_engine/folds/catalog_defs/actions.count_by_developer.yaml +10 -0
  54. capsule_engine/folds/catalog_defs/actions.executed_count.yaml +16 -0
  55. capsule_engine/folds/catalog_defs/actions.last_decision.yaml +12 -0
  56. capsule_engine/folds/catalog_defs/counterparty.seen_before.v2.yaml +34 -0
  57. capsule_engine/folds/catalog_defs/counterparty.seen_before.v3.yaml +38 -0
  58. capsule_engine/folds/catalog_defs/counterparty.seen_before.yaml +28 -0
  59. capsule_engine/folds/catalog_defs/disclosure.class_seen.yaml +29 -0
  60. capsule_engine/folds/catalog_defs/disclosure.statement_seen.yaml +32 -0
  61. capsule_engine/folds/catalog_defs/hold.active_exposure.yaml +44 -0
  62. capsule_engine/folds/catalog_defs/spend.weekly.v2.yaml +38 -0
  63. capsule_engine/folds/catalog_defs/spend.weekly.v3.1.yaml +71 -0
  64. capsule_engine/folds/catalog_defs/spend.weekly.v3.yaml +76 -0
  65. capsule_engine/folds/catalog_defs/spend.weekly.yaml +33 -0
  66. capsule_engine/folds/counterparty_signals.py +179 -0
  67. capsule_engine/folds/definition.py +421 -0
  68. capsule_engine/folds/duration.py +16 -0
  69. capsule_engine/folds/engine.py +436 -0
  70. capsule_engine/folds/errors.py +44 -0
  71. capsule_engine/folds/loader.py +24 -0
  72. capsule_engine/folds/ordering.py +143 -0
  73. capsule_engine/folds/paths.py +25 -0
  74. capsule_engine/folds/record_type_coverage.py +58 -0
  75. capsule_engine/folds/reducers.py +75 -0
  76. capsule_engine/folds/retention_continuity.py +117 -0
  77. capsule_engine/folds/set_membership.py +59 -0
  78. capsule_engine/folds/taxonomy.py +231 -0
  79. capsule_engine/guards/__init__.py +59 -0
  80. capsule_engine/guards/action.py +446 -0
  81. capsule_engine/guards/action_taxonomy.json +27 -0
  82. capsule_engine/guards/action_taxonomy_v2.json +27 -0
  83. capsule_engine/guards/action_taxonomy_v3.json +27 -0
  84. capsule_engine/guards/action_taxonomy_v4.json +27 -0
  85. capsule_engine/guards/action_taxonomy_v5.json +27 -0
  86. capsule_engine/guards/capsule.py +377 -0
  87. capsule_engine/guards/checks/__init__.py +268 -0
  88. capsule_engine/guards/checks/action_class_gate.py +199 -0
  89. capsule_engine/guards/checks/base.py +33 -0
  90. capsule_engine/guards/checks/caps.py +517 -0
  91. capsule_engine/guards/checks/channel_change.py +64 -0
  92. capsule_engine/guards/checks/commitment.py +41 -0
  93. capsule_engine/guards/checks/counterparty_identity_change.py +95 -0
  94. capsule_engine/guards/checks/counterparty_list.py +176 -0
  95. capsule_engine/guards/checks/counterparty_seen_before.py +160 -0
  96. capsule_engine/guards/checks/credential_pattern.py +73 -0
  97. capsule_engine/guards/checks/dedupe.py +259 -0
  98. capsule_engine/guards/checks/destination_rail.py +120 -0
  99. capsule_engine/guards/checks/field_change_count.py +100 -0
  100. capsule_engine/guards/checks/offer_expiry.py +134 -0
  101. capsule_engine/guards/checks/plan_containment.py +180 -0
  102. capsule_engine/guards/checks/price_floor.py +211 -0
  103. capsule_engine/guards/checks/promise_never.py +236 -0
  104. capsule_engine/guards/checks/promise_requires_approval.py +214 -0
  105. capsule_engine/guards/checks/recipient_role.py +117 -0
  106. capsule_engine/guards/checks/recurring_charge.py +49 -0
  107. capsule_engine/guards/checks/refundability.py +46 -0
  108. capsule_engine/guards/checks/release_on_acceptance.py +286 -0
  109. capsule_engine/guards/checks/required_disclosure.py +233 -0
  110. capsule_engine/guards/checks/single_commitment.py +221 -0
  111. capsule_engine/guards/checks/task_authority.py +182 -0
  112. capsule_engine/guards/checks/upfront_amount.py +71 -0
  113. capsule_engine/guards/checks/verify_before_dispatch.py +75 -0
  114. capsule_engine/guards/classes.py +393 -0
  115. capsule_engine/guards/engine.py +926 -0
  116. capsule_engine/guards/history_state.py +127 -0
  117. capsule_engine/guards/plan.py +237 -0
  118. capsule_engine/guards/revocation.py +120 -0
  119. capsule_engine/guards/signing.py +60 -0
  120. capsule_engine/guards/statements.py +62 -0
  121. capsule_engine/guards/tool_call.py +83 -0
  122. capsule_engine/guards/wickets/__init__.py +23 -0
  123. capsule_engine/guards/wickets/catalog.py +75 -0
  124. capsule_engine/guards/wickets/catalog_defs/action_class_gate.v1.1.yaml +38 -0
  125. capsule_engine/guards/wickets/catalog_defs/action_class_gate.v1.2.yaml +52 -0
  126. capsule_engine/guards/wickets/catalog_defs/action_class_gate.yaml +34 -0
  127. capsule_engine/guards/wickets/catalog_defs/caps.v2.yaml +30 -0
  128. capsule_engine/guards/wickets/catalog_defs/caps.v3.yaml +49 -0
  129. capsule_engine/guards/wickets/catalog_defs/caps.v4.yaml +45 -0
  130. capsule_engine/guards/wickets/catalog_defs/caps.v5.1.yaml +53 -0
  131. capsule_engine/guards/wickets/catalog_defs/caps.v5.yaml +43 -0
  132. capsule_engine/guards/wickets/catalog_defs/caps.yaml +17 -0
  133. capsule_engine/guards/wickets/catalog_defs/caps_holds.yaml +18 -0
  134. capsule_engine/guards/wickets/catalog_defs/channel_change.v1.1.yaml +18 -0
  135. capsule_engine/guards/wickets/catalog_defs/channel_change.yaml +10 -0
  136. capsule_engine/guards/wickets/catalog_defs/counterparty_identity_change.yaml +9 -0
  137. capsule_engine/guards/wickets/catalog_defs/counterparty_list.yaml +20 -0
  138. capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.v2.yaml +15 -0
  139. capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.v3.yaml +23 -0
  140. capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.v4.yaml +26 -0
  141. capsule_engine/guards/wickets/catalog_defs/counterparty_seen_before.yaml +14 -0
  142. capsule_engine/guards/wickets/catalog_defs/credential_pattern.yaml +14 -0
  143. capsule_engine/guards/wickets/catalog_defs/dedupe.yaml +19 -0
  144. capsule_engine/guards/wickets/catalog_defs/destination_rail.seller.v1.1.yaml +32 -0
  145. capsule_engine/guards/wickets/catalog_defs/destination_rail.seller.yaml +10 -0
  146. capsule_engine/guards/wickets/catalog_defs/destination_rail.yaml +9 -0
  147. capsule_engine/guards/wickets/catalog_defs/hold_reconcile.yaml +14 -0
  148. capsule_engine/guards/wickets/catalog_defs/material_fields_changed.v1.1.yaml +22 -0
  149. capsule_engine/guards/wickets/catalog_defs/material_fields_changed.yaml +14 -0
  150. capsule_engine/guards/wickets/catalog_defs/offer_expiry.v1.1.yaml +31 -0
  151. capsule_engine/guards/wickets/catalog_defs/offer_expiry.yaml +24 -0
  152. capsule_engine/guards/wickets/catalog_defs/offer_fields_changed.v1.1.yaml +22 -0
  153. capsule_engine/guards/wickets/catalog_defs/offer_fields_changed.yaml +10 -0
  154. capsule_engine/guards/wickets/catalog_defs/price_floor.yaml +32 -0
  155. capsule_engine/guards/wickets/catalog_defs/promise_never.v1.1.yaml +64 -0
  156. capsule_engine/guards/wickets/catalog_defs/promise_never.yaml +16 -0
  157. capsule_engine/guards/wickets/catalog_defs/promise_requires_approval.v1.1.yaml +26 -0
  158. capsule_engine/guards/wickets/catalog_defs/promise_requires_approval.yaml +21 -0
  159. capsule_engine/guards/wickets/catalog_defs/recipient_role.seller.v1.1.yaml +23 -0
  160. capsule_engine/guards/wickets/catalog_defs/recipient_role.seller.v1.2.yaml +24 -0
  161. capsule_engine/guards/wickets/catalog_defs/recipient_role.seller.yaml +10 -0
  162. capsule_engine/guards/wickets/catalog_defs/recipient_role.v1.1.yaml +26 -0
  163. capsule_engine/guards/wickets/catalog_defs/recipient_role.yaml +11 -0
  164. capsule_engine/guards/wickets/catalog_defs/recipient_seen_before.yaml +16 -0
  165. capsule_engine/guards/wickets/catalog_defs/recurring_charge.yaml +9 -0
  166. capsule_engine/guards/wickets/catalog_defs/refundability.v1.1.yaml +15 -0
  167. capsule_engine/guards/wickets/catalog_defs/refundability.yaml +7 -0
  168. capsule_engine/guards/wickets/catalog_defs/release_on_acceptance.seller.v1.1.yaml +44 -0
  169. capsule_engine/guards/wickets/catalog_defs/release_on_acceptance.seller.v1.2.yaml +63 -0
  170. capsule_engine/guards/wickets/catalog_defs/release_on_acceptance.seller.yaml +36 -0
  171. capsule_engine/guards/wickets/catalog_defs/required_disclosure.v1.1.yaml +36 -0
  172. capsule_engine/guards/wickets/catalog_defs/required_disclosure.v1.2.yaml +42 -0
  173. capsule_engine/guards/wickets/catalog_defs/required_disclosure.yaml +25 -0
  174. capsule_engine/guards/wickets/catalog_defs/single_commitment.seller.yaml +14 -0
  175. capsule_engine/guards/wickets/catalog_defs/task_authority.v1.1.yaml +20 -0
  176. capsule_engine/guards/wickets/catalog_defs/task_authority.yaml +8 -0
  177. capsule_engine/guards/wickets/catalog_defs/upfront_amount.v1.1.yaml +19 -0
  178. capsule_engine/guards/wickets/catalog_defs/upfront_amount.yaml +11 -0
  179. capsule_engine/guards/wickets/catalog_defs/verify_before_dispatch.yaml +9 -0
  180. capsule_engine/guards/wickets/definition.py +164 -0
  181. capsule_engine/guards/wickets/errors.py +18 -0
  182. capsule_engine/guards/wickets/loader.py +26 -0
  183. capsule_engine/guards/wickets/retired.py +62 -0
  184. capsule_engine/holds/__init__.py +35 -0
  185. capsule_engine/holds/capsules.py +266 -0
  186. capsule_engine/holds/engine.py +476 -0
  187. capsule_engine/holds/errors.py +29 -0
  188. capsule_engine/holds/policy.py +62 -0
  189. capsule_engine/holds/scope.py +47 -0
  190. capsule_engine/mcp/__init__.py +16 -0
  191. capsule_engine/mcp/config.py +117 -0
  192. capsule_engine/mcp/server.py +338 -0
  193. capsule_engine/mcp/tools.py +424 -0
  194. capsule_engine/packaging.py +60 -0
  195. capsule_engine/packs/__init__.py +45 -0
  196. capsule_engine/packs/backfill_coverage.py +238 -0
  197. capsule_engine/packs/catalog/airline-engagement/AI-BOOTSTRAP.md +53 -0
  198. capsule_engine/packs/catalog/airline-engagement/folds/session_close.yaml +8 -0
  199. capsule_engine/packs/catalog/airline-engagement/pack.yaml +146 -0
  200. capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/good_execution.json +36 -0
  201. capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/oversight_declared.json +36 -0
  202. capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/tampered_execution.json +36 -0
  203. capsule_engine/packs/catalog/eu-ai-act/fixtures/trace/trusted_issuer.jwk.json +5 -0
  204. capsule_engine/packs/catalog/eu-ai-act/obligations-pack-note.md +68 -0
  205. capsule_engine/packs/catalog/eu-ai-act/obligations-register.yaml +761 -0
  206. capsule_engine/packs/catalog/eu-ai-act/pack.yaml +88 -0
  207. capsule_engine/packs/catalog/eu-ai-act/register.yaml +96 -0
  208. capsule_engine/packs/catalog/eu-ai-act-deterministic/fixtures/synthetic_internal_assist_sample.jsonl +6 -0
  209. capsule_engine/packs/catalog/eu-ai-act-deterministic/pack.yaml +580 -0
  210. capsule_engine/packs/catalog/everyday/AI-BOOTSTRAP.md +194 -0
  211. capsule_engine/packs/catalog/everyday/fixtures/mini_ledger.jsonl +45 -0
  212. capsule_engine/packs/catalog/everyday/pack.yaml +480 -0
  213. capsule_engine/packs/catalog/payments-safety/AI-BOOTSTRAP.md +83 -0
  214. capsule_engine/packs/catalog/payments-safety/fixtures/mini_ledger.jsonl +8 -0
  215. capsule_engine/packs/catalog/payments-safety/folds/spend_weekly.yaml +29 -0
  216. capsule_engine/packs/catalog/payments-safety/pack.yaml +112 -0
  217. capsule_engine/packs/catalog/seller/fixtures/mini_ledger.jsonl +83 -0
  218. capsule_engine/packs/catalog/seller/pack.yaml +503 -0
  219. capsule_engine/packs/catalog/standard-vendor/AI-BOOTSTRAP.md +70 -0
  220. capsule_engine/packs/catalog/standard-vendor/folds/session_close.yaml +8 -0
  221. capsule_engine/packs/catalog/standard-vendor/pack.yaml +466 -0
  222. capsule_engine/packs/contract_diff.py +809 -0
  223. capsule_engine/packs/contract_validate.py +185 -0
  224. capsule_engine/packs/corpus_verify.py +126 -0
  225. capsule_engine/packs/enforce.py +81 -0
  226. capsule_engine/packs/errors.py +159 -0
  227. capsule_engine/packs/eu_ai_act_trace_field_map.py +46 -0
  228. capsule_engine/packs/install.py +266 -0
  229. capsule_engine/packs/loader.py +1462 -0
  230. capsule_engine/packs/measurability_report.py +280 -0
  231. capsule_engine/packs/obligation_results.py +72 -0
  232. capsule_engine/packs/pins.py +92 -0
  233. capsule_engine/packs/schema.py +1053 -0
  234. capsule_engine/packs/thresholds.py +146 -0
  235. capsule_engine/packs/trace_attainment.py +188 -0
  236. capsule_engine/packs/trace_reader.py +104 -0
  237. capsule_engine/policy/__init__.py +37 -0
  238. capsule_engine/policy/activation.py +87 -0
  239. capsule_engine/policy/catalog_defs/default.yaml +23 -0
  240. capsule_engine/policy/catalog_defs/holds.yaml +27 -0
  241. capsule_engine/policy/errors.py +46 -0
  242. capsule_engine/policy/limits.py +287 -0
  243. capsule_engine/policy/loader.py +26 -0
  244. capsule_engine/policy/manifest.py +289 -0
  245. capsule_engine/policy/profile.py +281 -0
  246. capsule_engine/policy/resolve.py +224 -0
  247. capsule_engine/register/__init__.py +39 -0
  248. capsule_engine/register/compiler.py +219 -0
  249. capsule_engine/register/errors.py +40 -0
  250. capsule_engine/register/loader.py +247 -0
  251. capsule_engine/register/schema.py +129 -0
  252. capsule_engine/registry/__init__.py +19 -0
  253. capsule_engine/registry/conventions.json +162 -0
  254. capsule_engine/registry/conventions.py +188 -0
  255. capsule_engine/registry/cpb_registry.json +78 -0
  256. capsule_engine/report/__init__.py +62 -0
  257. capsule_engine/report/build.py +267 -0
  258. capsule_engine/report/coverage.py +777 -0
  259. capsule_engine/report/errors.py +35 -0
  260. capsule_engine/report/live_check.py +126 -0
  261. capsule_engine/report/live_history.py +420 -0
  262. capsule_engine/report/model.py +95 -0
  263. capsule_engine/report/render.py +467 -0
  264. capsule_engine/report/replay.py +1677 -0
  265. capsule_engine/report/result.py +504 -0
  266. capsule_engine/report/result_from_folds.py +222 -0
  267. capsule_engine/report/result_from_layers.py +670 -0
  268. capsule_engine/report/sale_bundle.py +864 -0
  269. capsule_engine/report/static/verify.js +451 -0
  270. capsule_engine/schemas/evidence-contract-v0.json +383 -0
  271. capsule_engine/schemas/vendor/epistemic-types.json +21 -0
  272. capsule_engine/schemas/vendor/evidence-result-v0.json +463 -0
  273. capsule_engine/telemetry/__init__.py +9 -0
  274. capsule_engine/telemetry/consent.py +39 -0
  275. capsule_engine/telemetry/events.py +93 -0
  276. capsule_engine/telemetry/fixtures/synthetic_events.jsonl +45 -0
  277. capsule_engine/telemetry/funnel.py +147 -0
  278. capsule_engine/telemetry/record.py +106 -0
  279. capsule_engine/telemetry/sink.py +61 -0
  280. capsule_engine/telemetry/state.py +60 -0
  281. capsule_engine/tenants.py +327 -0
  282. capsule_engine-0.1.0.dist-info/METADATA +47 -0
  283. capsule_engine-0.1.0.dist-info/RECORD +288 -0
  284. capsule_engine-0.1.0.dist-info/WHEEL +5 -0
  285. capsule_engine-0.1.0.dist-info/entry_points.txt +2 -0
  286. capsule_engine-0.1.0.dist-info/licenses/LICENSE +202 -0
  287. capsule_engine-0.1.0.dist-info/licenses/capsule_engine/examples/data/tau2_airline/LICENSE-tau2-bench +21 -0
  288. capsule_engine-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,222 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ """Adapters: real deterministic-fold outputs -> Result v0 ``Claim``s.
3
+
4
+ Every adapter here reads ``tier``/``grade``/``evidence``/``proofs`` off REAL
5
+ objects the fold call already produced -- ``capsule_emit``'s own
6
+ ``CheckpointRecord.grade()`` (the two-rung ladder position: ``self-attested``
7
+ until a real, non-stub, offline-verified witness stamp lands, then
8
+ ``witnessed`` -- see that method's docstring) for ``grade``, and
9
+ ``CheckpointRecord.digest()`` / ``WitnessRecord.entry_hash`` for
10
+ ``evidence``/``proofs``. Nothing here asserts a grade or invents a digest;
11
+ that is the module's whole point -- "grade read from the bundle's
12
+ witness/countersign state, never asserted".
13
+
14
+ ``tier`` is always ``"recomputed"`` in this module: every fold in
15
+ ``capsule_engine/folds/`` is a deterministic recomputation over sealed
16
+ records (this repo's own report/build.py docstring: "nothing in this module
17
+ invents a number"), never a semantic judgment. A ``"judged"`` claim's source
18
+ is a ``capsule-judge`` verdict record -- a different subsystem this repo
19
+ does not import -- so no adapter in this module ever emits
20
+ ``tier="judged"``; ``result.py``'s ``Claim`` supports it for a caller that
21
+ has one.
22
+ """
23
+ from __future__ import annotations
24
+
25
+ from dataclasses import dataclass
26
+
27
+ from agent_action_capsule import json_digest
28
+ from capsule_emit.chain_segment import ChainSegment
29
+
30
+ from ..folds.record_type_coverage import RecordTypeCoverageResult
31
+ from ..folds.retention_continuity import RetentionContinuityResult
32
+ from .result import Claim, DigestRef, DisclosureCarrier, ProofRef
33
+
34
+ __all__ = [
35
+ "GuardProjection",
36
+ "claim_from_guard_constraint",
37
+ "claim_from_retention_continuity",
38
+ "is_excluded_not_applicable",
39
+ "project_guard_constraint",
40
+ ]
41
+
42
+ # spec/evidence-result-v0.md section 1's rule, restated: sufficiency SATISFIED
43
+ # only when the fold actually reached a met/not_met judgment; INSUFFICIENT
44
+ # otherwise. "insufficient_evidence" is the fold's retired spelling of
45
+ # not_evaluable, still read as an alias for results written before the
46
+ # rename and always projected under the one canonical spelling.
47
+ # Accepted alias, never emitted: removing it breaks reading older results.
48
+ _RETENTION_VERDICT_MAP = {
49
+ "met": ("SATISFIED", "met", "SATISFIED"),
50
+ "not_met": ("SATISFIED", "not_met", "SATISFIED"),
51
+ "not_evaluable": ("INSUFFICIENT", "not_evaluable", "INSUFFICIENT"),
52
+ "insufficient_evidence": ("INSUFFICIENT", "not_evaluable", "INSUFFICIENT"),
53
+ }
54
+
55
+
56
+ def claim_from_retention_continuity(
57
+ result: RetentionContinuityResult,
58
+ segment: ChainSegment,
59
+ *,
60
+ claim_id: str,
61
+ contract_ref: str,
62
+ requirement_ref: str,
63
+ ) -> Claim:
64
+ """Project one ``evaluate_retention_continuity`` call into a Result v0
65
+ claim. ``segment`` must be the SAME segment ``result`` was computed
66
+ over -- this function reads the segment's own last checkpoint for grade
67
+ and evidence/proof digests, it does not recompute the fold.
68
+ """
69
+ if result.verdict not in _RETENTION_VERDICT_MAP:
70
+ raise ValueError(f"unrecognized retention-continuity verdict {result.verdict!r}")
71
+ sufficiency, verdict, disclosure_status = _RETENTION_VERDICT_MAP[result.verdict]
72
+
73
+ checkpoint = segment.checkpoint
74
+ grade = checkpoint.grade().value
75
+ evidence = (DigestRef(digest=checkpoint.digest()),)
76
+ proofs = tuple(
77
+ ProofRef(kind="receipt", digest=w.entry_hash) for w in checkpoint.witnesses
78
+ ) or (ProofRef(kind="inclusion_proof", digest=checkpoint.digest()),)
79
+
80
+ return Claim(
81
+ id=claim_id,
82
+ contract_ref=contract_ref,
83
+ requirement_ref=requirement_ref,
84
+ tier="recomputed",
85
+ grade=grade,
86
+ sufficiency=sufficiency,
87
+ verdict=verdict,
88
+ evidence=evidence,
89
+ proofs=proofs,
90
+ presentation=DisclosureCarrier(status=disclosure_status, evidence=evidence),
91
+ )
92
+
93
+
94
+ def is_excluded_not_applicable(result: RecordTypeCoverageResult) -> bool:
95
+ """spec section 3: a requirement excluded as NOT_APPLICABLE never
96
+ becomes a claim at all -- it only contributes to
97
+ ``aggregate.coverage.excluded_not_applicable`` (``build_result``'s
98
+ ``excluded_not_applicable`` count). This fold's own ``applicable`` flag
99
+ already carries that exclusion (an empty ``registered_kinds`` declaration,
100
+ per ``record_type_coverage.py``'s docstring: "nothing was declared to
101
+ check coverage against"), so this is a pure read, not a second judgment.
102
+ """
103
+ return not result.applicable
104
+
105
+
106
+ # A guard constraint record's result (pass | fail | n/a) projected onto the
107
+ # registered (EvidenceStatus, Sufficiency, Verdict) triple, beside the fold
108
+ # map above. pass/fail are settled; an n/a is read through the facts object
109
+ # guards/capsule.py's not_applicable_evidence() digests into evidence_digest.
110
+ _GUARD_SETTLED = {
111
+ "pass": ("SATISFIED", "SATISFIED", "met"),
112
+ "fail": ("SATISFIED", "SATISFIED", "not_met"),
113
+ }
114
+
115
+
116
+ _GRADE_BY_ATTESTATION_MODE = {"self_attested": "self-attested"}
117
+
118
+
119
+ @dataclass(frozen=True)
120
+ class GuardProjection:
121
+ """One guard constraint record, projected. ``excluded`` means the rule did
122
+ not apply: the record contributes to ``excluded_not_applicable`` and never
123
+ becomes a claim. ``recording_defect`` marks an n/a whose cause cannot be
124
+ read off the record (population b); it is counted on its own and kept out
125
+ of every rate."""
126
+
127
+ evidence_status: str
128
+ sufficiency: str | None
129
+ verdict: str | None
130
+ excluded: bool = False
131
+ recording_defect: bool = False
132
+
133
+
134
+ # `record` is one raw constraint object of a sealed capsule's JSON, possibly
135
+ # from a producer other than this engine; it is decoded field by field here.
136
+ def project_guard_constraint(record: dict, *, candidate_fields: frozenset[str]) -> GuardProjection:
137
+ """Project one sealed guard constraint record (``capsule["constraints"][i]``).
138
+
139
+ ``candidate_fields`` are the normalized action fields an in-scope n/a may
140
+ name as missing; the record's ``evidence_digest`` is matched against the
141
+ facts object for each, so nothing beyond the sealed record is read.
142
+
143
+ | record | status | sufficiency | verdict |
144
+ |-----------------------------------------|----------------|-------------|---------------|
145
+ | pass / fail | SATISFIED | SATISFIED | met / not_met |
146
+ | n/a, in_scope false | NOT_APPLICABLE | (excluded, never a claim) |
147
+ | n/a, in_scope true, missing_field named | NOT_FOUND | GAP | not_evaluable |
148
+ | n/a with no readable cause | UNKNOWN | UNKNOWN | not_evaluable |
149
+ """
150
+ result = record["result"]
151
+ if result in _GUARD_SETTLED:
152
+ status, sufficiency, verdict = _GUARD_SETTLED[result]
153
+ return GuardProjection(evidence_status=status, sufficiency=sufficiency, verdict=verdict)
154
+ if result != "n/a":
155
+ raise ValueError(f"unrecognized guard constraint result {result!r}")
156
+
157
+ constraint_id = record["id"]
158
+ digest = record.get("evidence_digest")
159
+ if digest == json_digest({"constraint_id": constraint_id, "in_scope": False, "missing_field": None}):
160
+ return GuardProjection(evidence_status="NOT_APPLICABLE", sufficiency=None, verdict=None, excluded=True)
161
+ for field_name in sorted(candidate_fields):
162
+ if digest == json_digest({"constraint_id": constraint_id, "in_scope": True, "missing_field": field_name}):
163
+ # LOCAL CHOICE, declared here rather than derived: NOT_FOUND -> GAP.
164
+ # The donated spec does not define NOT_FOUND's sufficiency.
165
+ # agent-action-capsule spec/evidence-result-v0.md section 2
166
+ # ("Disclosure policy", at origin/main 3dfc70b) collapses
167
+ # WITHHELD and NOT_COMMITTED into GAP and names NOT_FOUND only as
168
+ # the contrast case; it leaves NOT_FOUND's projection open. We
169
+ # chose GAP: the claim is inside the evaluated population, in the
170
+ # not_evaluable bucket, and NOT in unknown_count. Choosing UNKNOWN
171
+ # instead would put this case in the published unknown_count,
172
+ # which section 3 ("What the sponsor sees first") and section 7
173
+ # ("Aggregate") define as the count of claims resolved UNKNOWN.
174
+ return GuardProjection(evidence_status="NOT_FOUND", sufficiency="GAP", verdict="not_evaluable")
175
+ # No digest, or one that matches no facts object: the record does not say
176
+ # why the rule did not settle. This engine cannot emit one
177
+ # (ConstraintOutcome refuses an n/a without evidence), so this is a
178
+ # foreign or pre-fix record -- a recording defect, not a decline.
179
+ return GuardProjection(
180
+ evidence_status="UNKNOWN", sufficiency="UNKNOWN", verdict="not_evaluable", recording_defect=True
181
+ )
182
+
183
+
184
+ # `capsule` and `record` are raw sealed-capsule JSON, as for
185
+ # project_guard_constraint; only capsule_id, assurance and the record's own
186
+ # fields are read.
187
+ def claim_from_guard_constraint(
188
+ capsule: dict,
189
+ record: dict,
190
+ *,
191
+ claim_id: str,
192
+ contract_ref: str,
193
+ requirement_ref: str,
194
+ candidate_fields: frozenset[str],
195
+ ) -> Claim | None:
196
+ """A Result v0 claim for one constraint record of a sealed guard decision
197
+ capsule, or ``None`` when the rule did not apply (the caller counts it in
198
+ ``build_result(excluded_not_applicable=...)``). Tier ``recomputed``: the
199
+ check is a deterministic predicate over the decision's recorded inputs.
200
+ Grade is read off the capsule's own ``assurance.attestation_mode``; only
201
+ ``self_attested`` maps today, and anything else is refused rather than
202
+ guessed. Evidence is the constraint's own ``evidence_digest``
203
+ when it has one; the proof is the decision capsule's ``capsule_id``."""
204
+ projected = project_guard_constraint(record, candidate_fields=candidate_fields)
205
+ if projected.excluded:
206
+ return None
207
+ attestation_mode = (capsule.get("assurance") or {}).get("attestation_mode")
208
+ if attestation_mode not in _GRADE_BY_ATTESTATION_MODE:
209
+ raise ValueError(f"no Result grade is defined for attestation_mode {attestation_mode!r}")
210
+ evidence = (DigestRef(digest=record["evidence_digest"]),) if record.get("evidence_digest") else ()
211
+ return Claim(
212
+ id=claim_id,
213
+ contract_ref=contract_ref,
214
+ requirement_ref=requirement_ref,
215
+ tier="recomputed",
216
+ grade=_GRADE_BY_ATTESTATION_MODE[attestation_mode],
217
+ sufficiency=projected.sufficiency,
218
+ verdict=projected.verdict,
219
+ evidence=evidence,
220
+ proofs=(ProofRef(kind="inclusion_proof", digest=capsule["capsule_id"]),),
221
+ presentation=DisclosureCarrier(status=projected.evidence_status, evidence=evidence),
222
+ )