@iowarp/clio-coder 0.3.2 → 0.3.4

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 (259) hide show
  1. package/CHANGELOG.md +269 -458
  2. package/CONTRIBUTING.md +1 -1
  3. package/README.md +3 -3
  4. package/dist/{acp-BIYHVZIM.js → acp-S5R4RR5B.js} +7 -6
  5. package/dist/{agents-YT6SSRIT.js → agents-P6DMMVZY.js} +24 -21
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-2XCZLPKS.js} +12 -8
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-WMSVI4G2.js → chunk-2LZI5CAG.js} +133 -13
  10. package/dist/{chunk-OAO4GE4M.js → chunk-2TZWSW76.js} +2 -2
  11. package/dist/{chunk-OOJYHWRB.js → chunk-34475P3I.js} +2 -2
  12. package/dist/{chunk-WVO7V2QY.js → chunk-35MKKU5R.js} +4 -4
  13. package/dist/{chunk-LBNRH5WM.js → chunk-3HZ5RWN2.js} +5 -5
  14. package/dist/{chunk-AGYYIBLL.js → chunk-3JLKSKD7.js} +2 -2
  15. package/dist/{chunk-MBS4V7ZP.js → chunk-4JUF2NNX.js} +7 -7
  16. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  17. package/dist/chunk-5M54SPOL.js +926 -0
  18. package/dist/{chunk-STBPMHSX.js → chunk-7RXG6QRZ.js} +51 -11
  19. package/dist/{chunk-77VKQEHF.js → chunk-A2GZF7DC.js} +5 -5
  20. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  21. package/dist/chunk-AOCYTWAV.js +449 -0
  22. package/dist/chunk-BEY543CS.js +258 -0
  23. package/dist/{chunk-6N5PTWMY.js → chunk-BP4OYD6A.js} +32 -13
  24. package/dist/chunk-BPGS2WCQ.js +612 -0
  25. package/dist/{chunk-J5HN4RYU.js → chunk-BRXQQJFP.js} +8 -8
  26. package/dist/chunk-CFGTUFWB.js +67 -0
  27. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  28. package/dist/{chunk-G2DE3C7R.js → chunk-EDRHSCIE.js} +4 -4
  29. package/dist/{chunk-4KLWL3UC.js → chunk-EFADSJET.js} +2 -2
  30. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  31. package/dist/chunk-FYYLNIL5.js +313 -0
  32. package/dist/{chunk-EPVUXGXG.js → chunk-HV5X7OR2.js} +14 -12
  33. package/dist/{chunk-TZTZS7QK.js → chunk-HXG4IURW.js} +5 -3
  34. package/dist/{chunk-IGLFWIYI.js → chunk-K6WL7QZT.js} +3 -3
  35. package/dist/chunk-K7VKOLQQ.js +15 -0
  36. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  37. package/dist/{chunk-V4RXGQ5Q.js → chunk-KRPY7NTG.js} +10 -7
  38. package/dist/chunk-LL4KHSZI.js +22 -0
  39. package/dist/{chunk-KJ5LWLOE.js → chunk-MEQ45TQ4.js} +15 -9
  40. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  41. package/dist/{chunk-AO4RKG4M.js → chunk-N4CZJQRK.js} +5 -5
  42. package/dist/{chunk-ARBGF5F7.js → chunk-NILBFAPG.js} +14 -8
  43. package/dist/chunk-OZNBF4L3.js +23 -0
  44. package/dist/{verify-G6V4D2G7.js → chunk-PCZJO5TI.js} +127 -42
  45. package/dist/chunk-QQK64KLB.js +1360 -0
  46. package/dist/{chunk-6EJV5X2W.js → chunk-QQL5RT5M.js} +979 -1619
  47. package/dist/{chunk-LZSJBIVT.js → chunk-QWU7ZBO7.js} +70 -720
  48. package/dist/{chunk-2EHAIA3X.js → chunk-RD5U66HV.js} +3 -3
  49. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  50. package/dist/{chunk-OQ33BKR3.js → chunk-TTNYS3EA.js} +3 -60
  51. package/dist/chunk-TW3WDMVS.js +677 -0
  52. package/dist/chunk-TZSKNMZG.js +434 -0
  53. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  54. package/dist/{chunk-7EYHLWU7.js → chunk-UZHIZC5S.js} +7 -7
  55. package/dist/{chunk-QTYWRVRA.js → chunk-VAWWTKDP.js} +8 -8
  56. package/dist/{chunk-X75S7HFS.js → chunk-VEZEGCGW.js} +214 -20
  57. package/dist/{chunk-OHHN2SO4.js → chunk-VMNQ6OZA.js} +98 -202
  58. package/dist/chunk-VSNATDE6.js +122 -0
  59. package/dist/chunk-W6GROXXM.js +69 -0
  60. package/dist/chunk-WPQLXFOZ.js +375 -0
  61. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  62. package/dist/{chunk-3ZXDFGR5.js → chunk-X6COSD2O.js} +5 -5
  63. package/dist/chunk-ZGVHUX3M.js +66 -0
  64. package/dist/{chunk-MAW544W2.js → chunk-ZWMF7253.js} +4 -4
  65. package/dist/{chunk-MQSRRFWA.js → chunk-ZYKPLLNQ.js} +563 -546
  66. package/dist/cli/index.js +27 -23
  67. package/dist/{clio-4LY5K2AC.js → clio-J5JIOIDS.js} +7 -6
  68. package/dist/{code-nav-7AX6FYE6.js → code-nav-AXCXSBHX.js} +5 -3
  69. package/dist/{config-GTLUW2PR.js → config-OEBMIN2U.js} +37 -27
  70. package/dist/{configure-R6A64DHX.js → configure-PUQOSIXQ.js} +16 -13
  71. package/dist/{context-5VKGUVJJ.js → context-EKDCKUUZ.js} +82 -7
  72. package/dist/{context-RW5HC47S.js → context-MGSE4Z2T.js} +33 -23
  73. package/dist/{context-JFZEJ7W5.js → context-URSXPBCK.js} +17 -9
  74. package/dist/{context-clear-6ZHBAZZT.js → context-clear-KDAJRNUK.js} +33 -23
  75. package/dist/context-working-set-SBKMPPI2.js +1552 -0
  76. package/dist/{dispatch-runner-VKBRCWQC.js → dispatch-runner-MSWN72NK.js} +43 -29
  77. package/dist/{doctor-KI767GSN.js → doctor-7BSE27PJ.js} +10 -10
  78. package/dist/{eval-XSSNATB4.js → eval-IZGDOO4H.js} +9 -8
  79. package/dist/{evidence-UA6AWDQQ.js → evidence-SR7WXB5B.js} +51 -23
  80. package/dist/{evolve-QNTFGV6Z.js → evolve-K7VE2CBX.js} +30 -20
  81. package/dist/{fleet-Q7UOMUSG.js → fleet-7XMJNQNF.js} +48 -38
  82. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-AQNAH644.js} +3 -3
  83. package/dist/{init-WBB65ZHQ.js → init-JGNPAYXT.js} +41 -31
  84. package/dist/{memory-MD3O64RI.js → memory-4ALKDJ4Q.js} +32 -22
  85. package/dist/{models-BZU34YWD.js → models-ZMMLFJNN.js} +22 -19
  86. package/dist/{monitor-MEQA5C3I.js → monitor-2F3T5KHP.js} +55 -43
  87. package/dist/{orchestrator-CGFKEP27.js → orchestrator-ORHT43JB.js} +2507 -1896
  88. package/dist/{reset-L2FQEE3E.js → reset-NXGTYNUO.js} +4 -3
  89. package/dist/{run-IV4Q6RLN.js → run-RF4WJGMT.js} +51 -41
  90. package/dist/{share-S5BZQC5I.js → share-UT3W6E4M.js} +5 -4
  91. package/dist/{skills-LQEKRDTN.js → skills-PSACKC5Q.js} +2 -2
  92. package/dist/{skills-eval-3DC4HEWS.js → skills-eval-WJSI55RZ.js} +34 -24
  93. package/dist/{targets-C4SSGQOB.js → targets-PIIRAOYS.js} +23 -20
  94. package/dist/{terminal-lease-IT5JW2NR.js → terminal-lease-ULWXWNVY.js} +5 -4
  95. package/dist/{upgrade-7TT7SQ3G.js → upgrade-346TZ6AV.js} +18 -17
  96. package/dist/{usage-GV4PKT3M.js → usage-6KKXR32N.js} +34 -24
  97. package/dist/verifiers-4UUM6TEE.js +1214 -0
  98. package/dist/verify-X5HDROLA.js +25 -0
  99. package/dist/{wiki-generate-DQF6Z66B.js → wiki-generate-7STOCIFZ.js} +42 -31
  100. package/dist/worker/entry.js +33 -24
  101. package/docs/README.md +8 -7
  102. package/docs/acp.md +1 -1
  103. package/docs/alcf-provider.md +1 -1
  104. package/docs/architecture.md +2 -2
  105. package/docs/artifact-versions.md +1 -1
  106. package/docs/built-in-agents.md +1 -1
  107. package/docs/capacity-and-scheduling.md +1 -1
  108. package/docs/commands-and-modes.md +53 -21
  109. package/docs/config-knobs-audit.md +1 -2
  110. package/docs/configuration-and-targets.md +15 -1
  111. package/docs/context-engine.md +64 -12
  112. package/docs/context-working-set.md +194 -0
  113. package/docs/development-pipeline.md +1 -1
  114. package/docs/documentation-coverage.md +5 -5
  115. package/docs/documentation-guide.md +6 -5
  116. package/docs/environment-variables.md +2 -1
  117. package/docs/eval-runner.md +1 -1
  118. package/docs/evals-internal.md +14 -1
  119. package/docs/evidence-and-memory.md +74 -2
  120. package/docs/evolution.md +1 -1
  121. package/docs/exit-codes-and-output.md +1 -1
  122. package/docs/extensions-and-sharing.md +2 -2
  123. package/docs/fleet-dispatch.md +22 -7
  124. package/docs/glossary.md +21 -1
  125. package/docs/installation-and-lifecycle.md +6 -6
  126. package/docs/middleware-and-components.md +1 -1
  127. package/docs/model-catalog.md +7 -9
  128. package/docs/observability.md +4 -4
  129. package/docs/performance-methodology.md +2 -2
  130. package/docs/proactive-memory.md +1 -1
  131. package/docs/prompt-envelope-and-tools.md +4 -4
  132. package/docs/provider-adapter-cookbook.md +1 -1
  133. package/docs/release-cut-checklist.md +35 -35
  134. package/docs/safety-model.md +23 -4
  135. package/docs/scientific-validation.md +21 -3
  136. package/docs/session-lifecycle.md +3 -3
  137. package/docs/skills-marketplace.md +1 -1
  138. package/docs/tool-usage.md +79 -12
  139. package/docs/trace-store.md +1 -1
  140. package/docs/troubleshooting.md +1 -1
  141. package/docs/tui-design.md +2 -2
  142. package/docs/worker-dispatch-mechanics.md +11 -1
  143. package/package.json +8 -11
  144. package/skills/meta/clio-test/SKILL.md +20 -17
  145. package/skills/meta/clio-test/evals.md +3 -3
  146. package/skills/meta/clio-test/references/harness.md +35 -6
  147. package/skills/meta/clio-test/references/test-map.md +20 -10
  148. package/skills/registry.yaml +2 -2
  149. package/skills/skill-marketplace.json +1 -1
  150. package/src/cli/context-working-set.ts +513 -0
  151. package/src/cli/context.ts +8 -0
  152. package/src/cli/evidence.ts +20 -2
  153. package/src/cli/index.ts +4 -0
  154. package/src/cli/verifiers.ts +325 -0
  155. package/src/core/bash-exec.ts +39 -14
  156. package/src/core/bus-events.ts +19 -4
  157. package/src/core/config.ts +54 -0
  158. package/src/core/defaults.ts +50 -3
  159. package/src/core/git-commit-attribution.ts +46 -21
  160. package/src/core/verification-scripts.ts +6 -0
  161. package/src/domains/agents/builtins/verifier.md +3 -0
  162. package/src/domains/config/classify.ts +1 -0
  163. package/src/domains/config/keybindings.ts +3 -3
  164. package/src/domains/context/working-set/contract.ts +161 -0
  165. package/src/domains/context/working-set/defaults.ts +28 -0
  166. package/src/domains/context/working-set/engine.ts +203 -0
  167. package/src/domains/context/working-set/fold.ts +62 -0
  168. package/src/domains/context/working-set/horizon.ts +38 -0
  169. package/src/domains/context/working-set/marker.ts +103 -0
  170. package/src/domains/context/working-set/path-index.ts +436 -0
  171. package/src/domains/context/working-set/payload.ts +152 -0
  172. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  173. package/src/domains/context/working-set/policies/index.ts +21 -0
  174. package/src/domains/context/working-set/policies/structural.ts +160 -0
  175. package/src/domains/context/working-set/project.ts +132 -0
  176. package/src/domains/context/working-set/protect.ts +109 -0
  177. package/src/domains/context/working-set/recall.ts +177 -0
  178. package/src/domains/context/working-set/replay/controls.ts +112 -0
  179. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  180. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  181. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  182. package/src/domains/context/working-set/replay/report.ts +139 -0
  183. package/src/domains/context/working-set/replay/runner.ts +325 -0
  184. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  185. package/src/domains/context/working-set/replay/trace.ts +21 -0
  186. package/src/domains/context/working-set/visible.ts +54 -0
  187. package/src/domains/evidence/build.ts +112 -45
  188. package/src/domains/evidence/eval.ts +24 -7
  189. package/src/domains/evidence/index.ts +53 -0
  190. package/src/domains/evidence/ordering.ts +12 -0
  191. package/src/domains/evidence/run-trust.ts +221 -0
  192. package/src/domains/evidence/store.ts +46 -6
  193. package/src/domains/evidence/trust-status.ts +854 -0
  194. package/src/domains/evidence/types.ts +26 -0
  195. package/src/domains/middleware/memory-intervention.ts +3 -0
  196. package/src/domains/middleware/stalled-turn.ts +165 -4
  197. package/src/domains/safety/autonomy.ts +1 -1
  198. package/src/domains/safety/default-path-policy.ts +8 -0
  199. package/src/domains/safety/finish-contract.ts +4 -3
  200. package/src/domains/safety/policy-engine.ts +48 -6
  201. package/src/domains/session/compaction/compact.ts +23 -1
  202. package/src/domains/session/compaction/cut-point.ts +2 -0
  203. package/src/domains/session/compaction/tokens.ts +16 -1
  204. package/src/domains/session/context-ledger.ts +2 -0
  205. package/src/domains/session/entries.ts +107 -1
  206. package/src/domains/session/manager.ts +9 -2
  207. package/src/domains/session/migrations/index.ts +22 -3
  208. package/src/engine/acp/server.ts +3 -0
  209. package/src/engine/agent.ts +18 -1
  210. package/src/engine/session.ts +9 -3
  211. package/src/entry/orchestrator.ts +16 -4
  212. package/src/interactive/chat-loop-messages.ts +18 -6
  213. package/src/interactive/chat-panel.ts +571 -244
  214. package/src/interactive/chat-renderer.ts +79 -39
  215. package/src/interactive/context-meter.ts +10 -0
  216. package/src/interactive/context-overlay.ts +81 -6
  217. package/src/interactive/context-recall-command.ts +110 -0
  218. package/src/interactive/editor-submit.ts +26 -1
  219. package/src/interactive/footer/widgets.ts +22 -20
  220. package/src/interactive/footer-panel.ts +6 -1
  221. package/src/interactive/interactive-application.ts +2 -0
  222. package/src/interactive/interactive-event-projection.ts +12 -0
  223. package/src/interactive/interactive-slash-runtime.ts +49 -8
  224. package/src/interactive/model-session-replay.ts +21 -0
  225. package/src/interactive/overlay-general-openers.ts +6 -0
  226. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  227. package/src/interactive/overlays/ask-user.ts +146 -24
  228. package/src/interactive/renderers/tool-execution.ts +167 -56
  229. package/src/interactive/session-transcript.ts +2 -2
  230. package/src/interactive/slash-commands.ts +29 -2
  231. package/src/interactive/status/index.ts +12 -1
  232. package/src/interactive/status/reasoning.ts +87 -0
  233. package/src/interactive/status/summary.ts +13 -2
  234. package/src/interactive/transcript-detail.ts +120 -0
  235. package/src/interactive/turn-context.ts +238 -88
  236. package/src/interactive/turn-middleware.ts +6 -6
  237. package/src/tools/agent-tools.ts +11 -4
  238. package/src/tools/bash.ts +144 -82
  239. package/src/tools/builtin-tool-catalog.ts +18 -6
  240. package/src/tools/context/index.ts +105 -3
  241. package/src/tools/context/surface.ts +3 -2
  242. package/src/tools/core-bootstrap.ts +21 -0
  243. package/src/tools/dispatch-runner.ts +9 -7
  244. package/src/tools/monitor.ts +28 -20
  245. package/src/tools/presentation.ts +107 -0
  246. package/src/tools/registry.ts +65 -7
  247. package/src/tools/result-disposition.ts +550 -0
  248. package/src/tools/result-shaping.ts +262 -19
  249. package/src/tools/safe-exec.ts +2 -0
  250. package/src/tools/verify/authoring.ts +1119 -0
  251. package/src/tools/verify/catalog.ts +346 -0
  252. package/src/tools/verify/index.ts +13 -3
  253. package/src/tools/verify/scripts.ts +135 -37
  254. package/src/tools/verify/surface.ts +9 -5
  255. package/src/tools/worker-evidence.ts +35 -12
  256. package/dist/chunk-MNA4JGU4.js +0 -255
  257. package/dist/chunk-SRF2PJNW.js +0 -184
  258. package/dist/chunk-T6YILFSB.js +0 -80
  259. package/dist/chunk-VAKQQHWR.js +0 -434
@@ -0,0 +1,854 @@
1
+ import type { GateDecisionArtifact, GateDecisionVerification } from "../dispatch/gate-decisions.js";
2
+ import { type ReceiptIntegrityResult, verifyReceiptIntegrity } from "../dispatch/receipt-integrity.js";
3
+ import type {
4
+ RunBriefingProvenance,
5
+ RunEnvelope,
6
+ RunProjectContextProvenance,
7
+ RunReceipt,
8
+ RunReceiptQuality,
9
+ RunReceiptVerification,
10
+ } from "../dispatch/types.js";
11
+ import type { FinishContractAssessment } from "../safety/finish-contract.js";
12
+
13
+ /** Persisted version of the canonical, deliberately non-scalar trust model. */
14
+ export const TRUST_STATUS_VERSION = 1 as const;
15
+
16
+ /** Hard bounds keep references useful as pointers without turning them into embedded artifacts. */
17
+ export const TRUST_STATUS_MAX_ARTIFACT_REFERENCES = 16;
18
+ export const TRUST_STATUS_MAX_IDENTIFIER_LENGTH = 512;
19
+
20
+ export const TRUST_STATUS_AXES = [
21
+ "artifactIntegrity",
22
+ "validationGrounding",
23
+ "independentReview",
24
+ "contextProvenance",
25
+ "autonomyEnforcement",
26
+ "completionEvidence",
27
+ ] as const;
28
+
29
+ export type TrustStatusAxis = (typeof TRUST_STATUS_AXES)[number];
30
+
31
+ /** Runtime vocabularies and the source of the corresponding closed state unions. */
32
+ export const TRUST_STATUS_STATES = {
33
+ artifactIntegrity: ["verified", "failed", "absent", "unknown", "not_applicable"],
34
+ validationGrounding: ["validated", "failed", "ungrounded", "absent", "unknown", "not_applicable"],
35
+ independentReview: ["passed", "failed", "inconclusive", "not_independent", "absent", "unknown", "not_applicable"],
36
+ contextProvenance: ["recorded", "invalid", "absent", "unknown", "not_applicable"],
37
+ autonomyEnforcement: ["enforced", "approximated", "bypassed", "absent", "unknown", "not_applicable"],
38
+ completionEvidence: ["evidenced", "incomplete", "limited", "absent", "unknown", "not_applicable"],
39
+ } as const satisfies Record<TrustStatusAxis, ReadonlyArray<string>>;
40
+
41
+ export type TrustStatusSourceKind =
42
+ | "receipt_integrity_verification"
43
+ | "run_receipt"
44
+ | "gate_decision"
45
+ | "evidence_bundle"
46
+ | "finish_contract"
47
+ | "compatibility";
48
+
49
+ export interface TrustStatusSource {
50
+ kind: TrustStatusSourceKind;
51
+ id: string;
52
+ }
53
+
54
+ export type TrustStatusAuthorityKind =
55
+ | "clio"
56
+ | "validator"
57
+ | "reviewer"
58
+ | "operator"
59
+ | "runtime"
60
+ | "external_system"
61
+ | "unknown";
62
+
63
+ /** The actor or subsystem entitled to make the attributed observation. */
64
+ export interface TrustStatusAuthority {
65
+ kind: TrustStatusAuthorityKind;
66
+ id: string;
67
+ }
68
+
69
+ export type TrustArtifactKind =
70
+ | "run_receipt"
71
+ | "validation_result"
72
+ | "gate_decision"
73
+ | "briefing"
74
+ | "project_context"
75
+ | "autonomy_policy"
76
+ | "finish_contract_evidence"
77
+ | "evidence_bundle"
78
+ | "session_entry";
79
+
80
+ export interface TrustArtifactReference {
81
+ kind: TrustArtifactKind;
82
+ id: string;
83
+ digest?: {
84
+ algorithm: "sha256";
85
+ value: string;
86
+ };
87
+ }
88
+
89
+ /** Every observed fact, including unknown and not applicable, is attributable. */
90
+ export interface AttributedTrustStatus {
91
+ source: TrustStatusSource;
92
+ authority: TrustStatusAuthority;
93
+ artifacts: ReadonlyArray<TrustArtifactReference>;
94
+ }
95
+
96
+ export type TrustAbsenceReason = "not_recorded" | "not_observed" | "artifact_missing" | "historical_format";
97
+
98
+ export interface AbsentTrustStatus {
99
+ state: "absent";
100
+ reason: TrustAbsenceReason;
101
+ }
102
+
103
+ type AttributedState<State extends string> = { state: State } & AttributedTrustStatus;
104
+
105
+ type NonAbsentAxisState<Axis extends TrustStatusAxis> = Exclude<(typeof TRUST_STATUS_STATES)[Axis][number], "absent">;
106
+
107
+ export type ArtifactIntegrityStatus = AttributedState<NonAbsentAxisState<"artifactIntegrity">> | AbsentTrustStatus;
108
+
109
+ export type ValidationGroundingStatus = AttributedState<NonAbsentAxisState<"validationGrounding">> | AbsentTrustStatus;
110
+
111
+ export type IndependentReviewStatus = AttributedState<NonAbsentAxisState<"independentReview">> | AbsentTrustStatus;
112
+
113
+ export type ContextProvenanceStatus = AttributedState<NonAbsentAxisState<"contextProvenance">> | AbsentTrustStatus;
114
+
115
+ export type AutonomyEnforcementStatus = AttributedState<NonAbsentAxisState<"autonomyEnforcement">> | AbsentTrustStatus;
116
+
117
+ export type CompletionEvidenceStatus = AttributedState<NonAbsentAxisState<"completionEvidence">> | AbsentTrustStatus;
118
+
119
+ export interface TrustStatusAxes {
120
+ artifactIntegrity: ArtifactIntegrityStatus;
121
+ validationGrounding: ValidationGroundingStatus;
122
+ independentReview: IndependentReviewStatus;
123
+ contextProvenance: ContextProvenanceStatus;
124
+ autonomyEnforcement: AutonomyEnforcementStatus;
125
+ completionEvidence: CompletionEvidenceStatus;
126
+ }
127
+
128
+ /**
129
+ * One canonical aggregate. It has no confidence score or overall verdict;
130
+ * callers consume only the axes relevant to their decision.
131
+ */
132
+ export interface CanonicalTrustStatus extends TrustStatusAxes {
133
+ version: typeof TRUST_STATUS_VERSION;
134
+ }
135
+
136
+ export type TrustStatusProjection = Partial<TrustStatusAxes>;
137
+
138
+ export type TrustStatusValidation = { ok: true; status: CanonicalTrustStatus } | { ok: false; reason: string };
139
+
140
+ /**
141
+ * Artifact kinds that are self-reports of the run under inspection. They can
142
+ * establish `completionEvidence`, the axis they authentically own, and can
143
+ * never be read as independently observed validation.
144
+ */
145
+ const SELF_REPORTED_ARTIFACT_KINDS: ReadonlySet<TrustArtifactKind> = new Set([
146
+ "finish_contract_evidence",
147
+ "run_receipt",
148
+ ]);
149
+
150
+ const AXIS_STATES: Record<TrustStatusAxis, ReadonlySet<string>> = {
151
+ artifactIntegrity: new Set(TRUST_STATUS_STATES.artifactIntegrity),
152
+ validationGrounding: new Set(TRUST_STATUS_STATES.validationGrounding),
153
+ independentReview: new Set(TRUST_STATUS_STATES.independentReview),
154
+ contextProvenance: new Set(TRUST_STATUS_STATES.contextProvenance),
155
+ autonomyEnforcement: new Set(TRUST_STATUS_STATES.autonomyEnforcement),
156
+ completionEvidence: new Set(TRUST_STATUS_STATES.completionEvidence),
157
+ };
158
+
159
+ const AXIS_SOURCES: Record<TrustStatusAxis, ReadonlySet<TrustStatusSourceKind>> = {
160
+ artifactIntegrity: new Set(["receipt_integrity_verification", "compatibility"]),
161
+ validationGrounding: new Set(["run_receipt", "evidence_bundle", "compatibility"]),
162
+ independentReview: new Set(["gate_decision", "compatibility"]),
163
+ contextProvenance: new Set(["run_receipt", "evidence_bundle", "compatibility"]),
164
+ autonomyEnforcement: new Set(["run_receipt", "compatibility"]),
165
+ completionEvidence: new Set(["finish_contract", "compatibility"]),
166
+ };
167
+
168
+ const SOURCE_AUTHORITIES: Record<TrustStatusSourceKind, ReadonlySet<TrustStatusAuthorityKind>> = {
169
+ receipt_integrity_verification: new Set(["clio"]),
170
+ run_receipt: new Set(["clio", "validator", "runtime", "external_system", "unknown"]),
171
+ gate_decision: new Set(["clio", "reviewer", "operator", "unknown"]),
172
+ evidence_bundle: new Set(["clio"]),
173
+ finish_contract: new Set(["clio"]),
174
+ compatibility: new Set(["clio", "unknown"]),
175
+ };
176
+
177
+ const ABSENCE_REASONS: ReadonlySet<string> = new Set([
178
+ "not_recorded",
179
+ "not_observed",
180
+ "artifact_missing",
181
+ "historical_format",
182
+ ]);
183
+
184
+ const SOURCE_KINDS: ReadonlySet<string> = new Set([
185
+ "receipt_integrity_verification",
186
+ "run_receipt",
187
+ "gate_decision",
188
+ "evidence_bundle",
189
+ "finish_contract",
190
+ "compatibility",
191
+ ]);
192
+
193
+ const AUTHORITY_KINDS: ReadonlySet<string> = new Set([
194
+ "clio",
195
+ "validator",
196
+ "reviewer",
197
+ "operator",
198
+ "runtime",
199
+ "external_system",
200
+ "unknown",
201
+ ]);
202
+
203
+ const ARTIFACT_KINDS: ReadonlySet<string> = new Set([
204
+ "run_receipt",
205
+ "validation_result",
206
+ "gate_decision",
207
+ "briefing",
208
+ "project_context",
209
+ "autonomy_policy",
210
+ "finish_contract_evidence",
211
+ "evidence_bundle",
212
+ "session_entry",
213
+ ]);
214
+
215
+ function isRecord(value: unknown): value is Record<string, unknown> {
216
+ return typeof value === "object" && value !== null && !Array.isArray(value);
217
+ }
218
+
219
+ function hasExactKeys(value: Record<string, unknown>, keys: ReadonlyArray<string>): boolean {
220
+ const expected = new Set(keys);
221
+ return Object.keys(value).length === expected.size && Object.keys(value).every((key) => expected.has(key));
222
+ }
223
+
224
+ /**
225
+ * The identifier rule every source, authority, and artifact reference is held
226
+ * to. Exported so derivation boundaries can drop an unusable identifier from a
227
+ * malformed input row instead of throwing at normalization time.
228
+ */
229
+ export function isTrustStatusIdentifier(value: unknown): value is string {
230
+ if (typeof value !== "string" || value.trim().length === 0 || value.length > TRUST_STATUS_MAX_IDENTIFIER_LENGTH) {
231
+ return false;
232
+ }
233
+ for (const character of value) {
234
+ const codePoint = character.codePointAt(0);
235
+ if (codePoint !== undefined && (codePoint < 32 || codePoint === 127)) return false;
236
+ }
237
+ return true;
238
+ }
239
+
240
+ function compareArtifactReferences(left: TrustArtifactReference, right: TrustArtifactReference): number {
241
+ const leftKey = `${left.kind}\u0000${left.id}\u0000${left.digest?.value ?? ""}`;
242
+ const rightKey = `${right.kind}\u0000${right.id}\u0000${right.digest?.value ?? ""}`;
243
+ return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : 0;
244
+ }
245
+
246
+ function normalizeArtifactReference(value: unknown, path: string): TrustArtifactReference {
247
+ if (!isRecord(value)) throw new Error(`${path} must be an object`);
248
+ if (!hasExactKeys(value, value.digest === undefined ? ["kind", "id"] : ["kind", "id", "digest"])) {
249
+ throw new Error(`${path} has unknown or missing fields`);
250
+ }
251
+ if (typeof value.kind !== "string" || !ARTIFACT_KINDS.has(value.kind)) {
252
+ throw new Error(`${path}.kind is invalid`);
253
+ }
254
+ if (!isTrustStatusIdentifier(value.id)) throw new Error(`${path}.id is invalid`);
255
+ const reference: TrustArtifactReference = { kind: value.kind as TrustArtifactKind, id: value.id };
256
+ if (value.digest !== undefined) {
257
+ if (
258
+ !isRecord(value.digest) ||
259
+ !hasExactKeys(value.digest, ["algorithm", "value"]) ||
260
+ value.digest.algorithm !== "sha256" ||
261
+ typeof value.digest.value !== "string" ||
262
+ !/^[a-f0-9]{64}$/u.test(value.digest.value)
263
+ ) {
264
+ throw new Error(`${path}.digest is invalid`);
265
+ }
266
+ reference.digest = { algorithm: "sha256", value: value.digest.value };
267
+ }
268
+ return reference;
269
+ }
270
+
271
+ function normalizeAttributedStatus(axis: TrustStatusAxis, value: Record<string, unknown>): AttributedState<string> {
272
+ if (!hasExactKeys(value, ["state", "source", "authority", "artifacts"])) {
273
+ throw new Error(`${axis} has unknown or missing fields`);
274
+ }
275
+ if (!isRecord(value.source) || !hasExactKeys(value.source, ["kind", "id"])) {
276
+ throw new Error(`${axis}.source is invalid`);
277
+ }
278
+ if (
279
+ typeof value.source.kind !== "string" ||
280
+ !SOURCE_KINDS.has(value.source.kind) ||
281
+ !AXIS_SOURCES[axis].has(value.source.kind as TrustStatusSourceKind) ||
282
+ !isTrustStatusIdentifier(value.source.id)
283
+ ) {
284
+ throw new Error(`${axis}.source is invalid`);
285
+ }
286
+ if (!isRecord(value.authority) || !hasExactKeys(value.authority, ["kind", "id"])) {
287
+ throw new Error(`${axis}.authority is invalid`);
288
+ }
289
+ if (
290
+ typeof value.authority.kind !== "string" ||
291
+ !AUTHORITY_KINDS.has(value.authority.kind) ||
292
+ !SOURCE_AUTHORITIES[value.source.kind as TrustStatusSourceKind].has(
293
+ value.authority.kind as TrustStatusAuthorityKind,
294
+ ) ||
295
+ !isTrustStatusIdentifier(value.authority.id)
296
+ ) {
297
+ throw new Error(`${axis}.authority is invalid`);
298
+ }
299
+ if (value.source.kind === "compatibility" && value.state !== "unknown" && value.state !== "not_applicable") {
300
+ throw new Error(`${axis} compatibility source cannot establish ${value.state}`);
301
+ }
302
+ if (!Array.isArray(value.artifacts) || value.artifacts.length > TRUST_STATUS_MAX_ARTIFACT_REFERENCES) {
303
+ throw new Error(`${axis}.artifacts exceeds the bounded reference list`);
304
+ }
305
+ const artifacts = value.artifacts.map((entry, index) =>
306
+ normalizeArtifactReference(entry, `${axis}.artifacts[${index}]`),
307
+ );
308
+ artifacts.sort(compareArtifactReferences);
309
+ for (let index = 1; index < artifacts.length; index += 1) {
310
+ if (
311
+ compareArtifactReferences(
312
+ artifacts[index - 1] as TrustArtifactReference,
313
+ artifacts[index] as TrustArtifactReference,
314
+ ) === 0
315
+ ) {
316
+ throw new Error(`${axis}.artifacts contains a duplicate reference`);
317
+ }
318
+ }
319
+ return {
320
+ state: value.state as string,
321
+ source: { kind: value.source.kind as TrustStatusSourceKind, id: value.source.id },
322
+ authority: { kind: value.authority.kind as TrustStatusAuthorityKind, id: value.authority.id },
323
+ artifacts,
324
+ };
325
+ }
326
+
327
+ function normalizeAxis(axis: TrustStatusAxis, value: unknown): TrustStatusAxes[TrustStatusAxis] {
328
+ if (!isRecord(value) || typeof value.state !== "string" || !AXIS_STATES[axis].has(value.state)) {
329
+ throw new Error(`${axis}.state is invalid`);
330
+ }
331
+ if (value.state === "absent") {
332
+ if (
333
+ !hasExactKeys(value, ["state", "reason"]) ||
334
+ typeof value.reason !== "string" ||
335
+ !ABSENCE_REASONS.has(value.reason)
336
+ ) {
337
+ throw new Error(`${axis} absent state is invalid`);
338
+ }
339
+ return { state: "absent", reason: value.reason as TrustAbsenceReason };
340
+ }
341
+ return normalizeAttributedStatus(axis, value) as TrustStatusAxes[TrustStatusAxis];
342
+ }
343
+
344
+ /** Validate, defensively copy, and deterministically order a canonical aggregate. */
345
+ export function normalizeTrustStatus(value: unknown): CanonicalTrustStatus {
346
+ if (!isRecord(value) || !hasExactKeys(value, ["version", ...TRUST_STATUS_AXES])) {
347
+ throw new Error("trust status has unknown or missing fields");
348
+ }
349
+ if (value.version !== TRUST_STATUS_VERSION) throw new Error("trust status version is invalid");
350
+ return {
351
+ version: TRUST_STATUS_VERSION,
352
+ artifactIntegrity: normalizeAxis("artifactIntegrity", value.artifactIntegrity) as ArtifactIntegrityStatus,
353
+ validationGrounding: normalizeAxis("validationGrounding", value.validationGrounding) as ValidationGroundingStatus,
354
+ independentReview: normalizeAxis("independentReview", value.independentReview) as IndependentReviewStatus,
355
+ contextProvenance: normalizeAxis("contextProvenance", value.contextProvenance) as ContextProvenanceStatus,
356
+ autonomyEnforcement: normalizeAxis("autonomyEnforcement", value.autonomyEnforcement) as AutonomyEnforcementStatus,
357
+ completionEvidence: normalizeAxis("completionEvidence", value.completionEvidence) as CompletionEvidenceStatus,
358
+ };
359
+ }
360
+
361
+ /** Non-throwing boundary for persisted JSON and extension inputs. */
362
+ export function validateTrustStatus(value: unknown): TrustStatusValidation {
363
+ try {
364
+ return { ok: true, status: normalizeTrustStatus(value) };
365
+ } catch (error) {
366
+ return { ok: false, reason: error instanceof Error ? error.message : String(error) };
367
+ }
368
+ }
369
+
370
+ export function absentTrustStatus(reason: TrustAbsenceReason): AbsentTrustStatus {
371
+ return { state: "absent", reason };
372
+ }
373
+
374
+ /**
375
+ * Compose exact axis projections. Later projections replace the same axis;
376
+ * no state on one axis can fill or promote another axis.
377
+ */
378
+ export function composeTrustStatus(...projections: ReadonlyArray<TrustStatusProjection>): CanonicalTrustStatus {
379
+ const axes: TrustStatusAxes = {
380
+ artifactIntegrity: absentTrustStatus("not_recorded"),
381
+ validationGrounding: absentTrustStatus("not_recorded"),
382
+ independentReview: absentTrustStatus("not_recorded"),
383
+ contextProvenance: absentTrustStatus("not_recorded"),
384
+ autonomyEnforcement: absentTrustStatus("not_recorded"),
385
+ completionEvidence: absentTrustStatus("not_recorded"),
386
+ };
387
+ for (const projection of projections) {
388
+ if (projection.artifactIntegrity !== undefined) axes.artifactIntegrity = projection.artifactIntegrity;
389
+ if (projection.validationGrounding !== undefined) axes.validationGrounding = projection.validationGrounding;
390
+ if (projection.independentReview !== undefined) axes.independentReview = projection.independentReview;
391
+ if (projection.contextProvenance !== undefined) axes.contextProvenance = projection.contextProvenance;
392
+ if (projection.autonomyEnforcement !== undefined) axes.autonomyEnforcement = projection.autonomyEnforcement;
393
+ if (projection.completionEvidence !== undefined) axes.completionEvidence = projection.completionEvidence;
394
+ }
395
+ return normalizeTrustStatus({ version: TRUST_STATUS_VERSION, ...axes });
396
+ }
397
+
398
+ /** Project only explicitly requested axes and preserve their exact states. */
399
+ export function projectTrustStatus(
400
+ status: CanonicalTrustStatus,
401
+ axes: ReadonlyArray<TrustStatusAxis>,
402
+ ): TrustStatusProjection {
403
+ const normalized = normalizeTrustStatus(status);
404
+ const projection: TrustStatusProjection = {};
405
+ const requested = new Set(axes);
406
+ if (requested.has("artifactIntegrity")) projection.artifactIntegrity = normalized.artifactIntegrity;
407
+ if (requested.has("validationGrounding")) projection.validationGrounding = normalized.validationGrounding;
408
+ if (requested.has("independentReview")) projection.independentReview = normalized.independentReview;
409
+ if (requested.has("contextProvenance")) projection.contextProvenance = normalized.contextProvenance;
410
+ if (requested.has("autonomyEnforcement")) projection.autonomyEnforcement = normalized.autonomyEnforcement;
411
+ if (requested.has("completionEvidence")) projection.completionEvidence = normalized.completionEvidence;
412
+ return projection;
413
+ }
414
+
415
+ export type PersistedRunReceiptTrustFacts = Pick<RunReceipt, "runId"> &
416
+ Partial<
417
+ Pick<
418
+ RunReceipt,
419
+ | "integrity"
420
+ | "verification"
421
+ | "quality"
422
+ | "validationGrounding"
423
+ | "briefing"
424
+ | "projectContext"
425
+ | "autonomyEnforcement"
426
+ >
427
+ >;
428
+
429
+ function sha256Reference(kind: TrustArtifactKind, id: string, digest: string | undefined): TrustArtifactReference {
430
+ const reference: TrustArtifactReference = { kind, id };
431
+ if (digest !== undefined && /^[a-f0-9]{64}$/u.test(digest)) {
432
+ reference.digest = { algorithm: "sha256", value: digest };
433
+ }
434
+ return reference;
435
+ }
436
+
437
+ function receiptReference(receipt: PersistedRunReceiptTrustFacts): TrustArtifactReference {
438
+ return sha256Reference("run_receipt", receipt.runId, receipt.integrity?.digest);
439
+ }
440
+
441
+ function attributed<State extends string>(
442
+ state: State,
443
+ source: TrustStatusSource,
444
+ authority: TrustStatusAuthority,
445
+ artifacts: ReadonlyArray<TrustArtifactReference>,
446
+ ): AttributedState<State> {
447
+ return { state, source, authority, artifacts: [...artifacts].sort(compareArtifactReferences) };
448
+ }
449
+
450
+ function receiptSource(receipt: PersistedRunReceiptTrustFacts): TrustStatusSource {
451
+ return { kind: "run_receipt", id: receipt.runId };
452
+ }
453
+
454
+ function compatibilitySource(receipt: PersistedRunReceiptTrustFacts, field: string): TrustStatusSource {
455
+ return { kind: "compatibility", id: `run_receipt:${receipt.runId}:${field}` };
456
+ }
457
+
458
+ const DISPATCH_AUTHORITY: TrustStatusAuthority = { kind: "clio", id: "dispatch" };
459
+ const COMPATIBILITY_AUTHORITY: TrustStatusAuthority = { kind: "unknown", id: "historical-persisted-format" };
460
+
461
+ /** Adapt receipt integrity verification without reading any receipt claim as self-authenticating. */
462
+ export function adaptReceiptIntegrityStatus(
463
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
464
+ verification?: ReceiptIntegrityResult,
465
+ ): ArtifactIntegrityStatus {
466
+ if (receipt === null || receipt === undefined) return absentTrustStatus("artifact_missing");
467
+ const artifacts = [receiptReference(receipt)];
468
+ if (verification === undefined || (verification.ok && receipt.integrity === undefined)) {
469
+ return attributed(
470
+ "unknown",
471
+ {
472
+ kind: "compatibility",
473
+ id: `run_receipt:${receipt.runId}:${receipt.integrity === undefined ? "integrity-missing" : "integrity-unchecked"}`,
474
+ },
475
+ COMPATIBILITY_AUTHORITY,
476
+ artifacts,
477
+ );
478
+ }
479
+ return attributed(
480
+ verification.ok ? "verified" : "failed",
481
+ { kind: "receipt_integrity_verification", id: receipt.runId },
482
+ { kind: "clio", id: "receipt-integrity" },
483
+ artifacts,
484
+ );
485
+ }
486
+
487
+ function validationArtifacts(receipt: PersistedRunReceiptTrustFacts): TrustArtifactReference[] {
488
+ const artifacts = [receiptReference(receipt)];
489
+ for (const fact of receipt.quality?.typedValidations ?? []) {
490
+ artifacts.push(sha256Reference("validation_result", fact.sourceId, fact.validatorDigest));
491
+ }
492
+ const resultContract = receipt.quality?.resultContract;
493
+ if (resultContract !== null && resultContract !== undefined) {
494
+ artifacts.push(sha256Reference("validation_result", resultContract.sourceId, resultContract.validatorDigest));
495
+ }
496
+ return uniqueBoundedReferences(artifacts);
497
+ }
498
+
499
+ function qualityHasFailure(quality: RunReceiptQuality | undefined): boolean {
500
+ if (quality === undefined) return false;
501
+ if (quality.typedValidations.some((fact) => !fact.passed)) return true;
502
+ return quality.resultContract?.conformance === "fail" || quality.resultContract?.quality === "fail";
503
+ }
504
+
505
+ function qualityHasValidation(quality: RunReceiptQuality | undefined): boolean {
506
+ if (quality === undefined) return false;
507
+ if (quality.typedValidations.some((fact) => fact.passed)) return true;
508
+ return quality.resultContract?.quality === "pass";
509
+ }
510
+
511
+ function verificationStatus(
512
+ verification: RunReceiptVerification,
513
+ receipt: PersistedRunReceiptTrustFacts,
514
+ artifacts: TrustArtifactReference[],
515
+ ): ValidationGroundingStatus {
516
+ if (verification.state === "verified") {
517
+ return attributed("validated", receiptSource(receipt), { kind: "validator", id: verification.basis }, artifacts);
518
+ }
519
+ if (verification.state === "unverified") return absentTrustStatus("not_observed");
520
+ if (verification.state === "not_applicable") {
521
+ return attributed("not_applicable", receiptSource(receipt), DISPATCH_AUTHORITY, artifacts);
522
+ }
523
+ return attributed(
524
+ "unknown",
525
+ receiptSource(receipt),
526
+ verification.basis === "acp-external-unobserved"
527
+ ? { kind: "external_system", id: "acp-delegation" }
528
+ : COMPATIBILITY_AUTHORITY,
529
+ artifacts,
530
+ );
531
+ }
532
+
533
+ /** Adapt correctness-bearing receipt facts before the older descriptive marker. */
534
+ export function adaptRunReceiptValidationStatus(
535
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
536
+ ): ValidationGroundingStatus {
537
+ if (receipt === null || receipt === undefined) return absentTrustStatus("artifact_missing");
538
+ const artifacts = validationArtifacts(receipt);
539
+ if (qualityHasFailure(receipt.quality)) {
540
+ return attributed("failed", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
541
+ }
542
+ if (
543
+ (receipt.validationGrounding?.ungrounded.length ?? 0) > 0 ||
544
+ (receipt.validationGrounding !== undefined &&
545
+ receipt.validationGrounding.claimed > receipt.validationGrounding.grounded)
546
+ ) {
547
+ return attributed("ungrounded", receiptSource(receipt), { kind: "validator", id: "command-grounding" }, artifacts);
548
+ }
549
+ if (qualityHasValidation(receipt.quality)) {
550
+ return attributed("validated", receiptSource(receipt), { kind: "validator", id: "receipt-quality" }, artifacts);
551
+ }
552
+ if (receipt.verification !== undefined) return verificationStatus(receipt.verification, receipt, artifacts);
553
+ return attributed("unknown", compatibilitySource(receipt, "verification"), COMPATIBILITY_AUTHORITY, artifacts);
554
+ }
555
+
556
+ function validBriefing(briefing: RunBriefingProvenance): boolean {
557
+ return Number.isSafeInteger(briefing.bytes) && briefing.bytes >= 0 && /^[a-f0-9]{64}$/u.test(briefing.contentHash);
558
+ }
559
+
560
+ function validBoundedProjectContext(context: RunProjectContextProvenance): boolean {
561
+ return (
562
+ context.tier === "bounded" &&
563
+ Number.isSafeInteger(context.chars) &&
564
+ (context.chars ?? -1) >= 0 &&
565
+ typeof context.contentHash === "string" &&
566
+ /^[a-f0-9]{64}$/u.test(context.contentHash)
567
+ );
568
+ }
569
+
570
+ function contextArtifacts(receipt: PersistedRunReceiptTrustFacts): TrustArtifactReference[] {
571
+ const artifacts = [receiptReference(receipt)];
572
+ if (receipt.briefing !== undefined && validBriefing(receipt.briefing)) {
573
+ artifacts.push(sha256Reference("briefing", `${receipt.runId}:briefing`, receipt.briefing.contentHash));
574
+ }
575
+ if (receipt.projectContext?.tier === "bounded" && validBoundedProjectContext(receipt.projectContext)) {
576
+ artifacts.push(
577
+ sha256Reference("project_context", `${receipt.runId}:project-context`, receipt.projectContext.contentHash),
578
+ );
579
+ }
580
+ return uniqueBoundedReferences(artifacts);
581
+ }
582
+
583
+ /** Adapt briefing and project-context provenance without treating either hash as correctness evidence. */
584
+ export function adaptRunReceiptContextStatus(
585
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
586
+ ): ContextProvenanceStatus {
587
+ if (receipt === null || receipt === undefined) return absentTrustStatus("artifact_missing");
588
+ const artifacts = contextArtifacts(receipt);
589
+ const source = receiptSource(receipt);
590
+ const briefingInvalid = receipt.briefing !== undefined && !validBriefing(receipt.briefing);
591
+ if (briefingInvalid) return attributed("invalid", source, DISPATCH_AUTHORITY, artifacts);
592
+ const context = receipt.projectContext;
593
+ if (context === undefined) {
594
+ if (receipt.briefing !== undefined) return attributed("recorded", source, DISPATCH_AUTHORITY, artifacts);
595
+ return attributed("unknown", compatibilitySource(receipt, "projectContext"), COMPATIBILITY_AUTHORITY, artifacts);
596
+ }
597
+ if (context.tier === "none") {
598
+ if (context.chars !== undefined || context.contentHash !== undefined || context.sections !== undefined) {
599
+ return attributed("invalid", source, DISPATCH_AUTHORITY, artifacts);
600
+ }
601
+ return receipt.briefing === undefined
602
+ ? attributed("not_applicable", source, DISPATCH_AUTHORITY, artifacts)
603
+ : attributed("recorded", source, DISPATCH_AUTHORITY, artifacts);
604
+ }
605
+ return attributed(validBoundedProjectContext(context) ? "recorded" : "invalid", source, DISPATCH_AUTHORITY, artifacts);
606
+ }
607
+
608
+ /** Adapt the recorded runtime grade and conservatively recover inconsistent bypass flags. */
609
+ export function adaptRunReceiptAutonomyStatus(
610
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
611
+ ): AutonomyEnforcementStatus {
612
+ if (receipt === null || receipt === undefined) return absentTrustStatus("artifact_missing");
613
+ const enforcement = receipt.autonomyEnforcement;
614
+ const artifacts = [receiptReference(receipt)];
615
+ if (enforcement === undefined) {
616
+ return attributed("unknown", compatibilitySource(receipt, "autonomyEnforcement"), COMPATIBILITY_AUTHORITY, artifacts);
617
+ }
618
+ artifacts.push({ kind: "autonomy_policy", id: `${receipt.runId}:${enforcement.autonomy}` });
619
+ const authority: TrustStatusAuthority =
620
+ enforcement.grade === "mediated"
621
+ ? { kind: "clio", id: "safety-autonomy" }
622
+ : { kind: "runtime", id: enforcement.externalMode ?? "external-runtime" };
623
+ const state =
624
+ enforcement.dangerousBypass === true || enforcement.grade === "bypassed"
625
+ ? "bypassed"
626
+ : enforcement.grade === "approximated"
627
+ ? "approximated"
628
+ : "enforced";
629
+ return attributed(state, receiptSource(receipt), authority, artifacts);
630
+ }
631
+
632
+ export interface AdaptRunReceiptTrustOptions {
633
+ integrity?: ReceiptIntegrityResult;
634
+ }
635
+
636
+ function receiptClaimsAreAuthenticated(
637
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
638
+ integrity: ReceiptIntegrityResult | undefined,
639
+ ): boolean {
640
+ return receipt?.integrity !== undefined && integrity?.ok === true;
641
+ }
642
+
643
+ function unauthenticatedReceiptProjection(
644
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
645
+ ): TrustStatusProjection {
646
+ if (receipt === null || receipt === undefined) {
647
+ return {
648
+ validationGrounding: absentTrustStatus("artifact_missing"),
649
+ contextProvenance: absentTrustStatus("artifact_missing"),
650
+ autonomyEnforcement: absentTrustStatus("artifact_missing"),
651
+ };
652
+ }
653
+ if (receipt.integrity === undefined) {
654
+ const artifacts = [receiptReference(receipt)];
655
+ return {
656
+ validationGrounding: attributed(
657
+ "unknown",
658
+ compatibilitySource(receipt, "canonical-projection"),
659
+ COMPATIBILITY_AUTHORITY,
660
+ artifacts,
661
+ ),
662
+ contextProvenance: attributed(
663
+ "unknown",
664
+ compatibilitySource(receipt, "canonical-projection"),
665
+ COMPATIBILITY_AUTHORITY,
666
+ artifacts,
667
+ ),
668
+ autonomyEnforcement: attributed(
669
+ "unknown",
670
+ compatibilitySource(receipt, "canonical-projection"),
671
+ COMPATIBILITY_AUTHORITY,
672
+ artifacts,
673
+ ),
674
+ };
675
+ }
676
+ // The artifact-integrity axis retains the failure diagnostic. No other
677
+ // axis reads a field from a receipt that failed authentication.
678
+ return {
679
+ validationGrounding: absentTrustStatus("not_observed"),
680
+ contextProvenance: absentTrustStatus("not_observed"),
681
+ autonomyEnforcement: absentTrustStatus("not_observed"),
682
+ };
683
+ }
684
+
685
+ /** Build the receipt-owned projection. Gate and finish facts remain absent until explicitly composed. */
686
+ export function adaptRunReceiptTrustStatus(
687
+ receipt: PersistedRunReceiptTrustFacts | null | undefined,
688
+ options: AdaptRunReceiptTrustOptions = {},
689
+ ): CanonicalTrustStatus {
690
+ const authenticated = receiptClaimsAreAuthenticated(receipt, options.integrity);
691
+ const receiptProjection = authenticated
692
+ ? {
693
+ validationGrounding: adaptRunReceiptValidationStatus(receipt),
694
+ contextProvenance: adaptRunReceiptContextStatus(receipt),
695
+ autonomyEnforcement: adaptRunReceiptAutonomyStatus(receipt),
696
+ }
697
+ : unauthenticatedReceiptProjection(receipt);
698
+ return composeTrustStatus({
699
+ artifactIntegrity: adaptReceiptIntegrityStatus(receipt, options.integrity),
700
+ ...receiptProjection,
701
+ independentReview: absentTrustStatus(receipt === null || receipt === undefined ? "artifact_missing" : "not_recorded"),
702
+ completionEvidence: absentTrustStatus(
703
+ receipt === null || receipt === undefined ? "artifact_missing" : "not_recorded",
704
+ ),
705
+ });
706
+ }
707
+
708
+ export interface RunReceiptTrustInspection {
709
+ integrity: ReceiptIntegrityResult;
710
+ status: CanonicalTrustStatus;
711
+ }
712
+
713
+ /**
714
+ * Inspect a receipt and ledger envelope through one pure authentication and
715
+ * projection boundary. Callers retain the integrity result as the diagnostic
716
+ * and consume `status` for every trust-bearing presentation.
717
+ */
718
+ export function inspectRunReceiptTrustStatus(
719
+ receipt: RunReceipt | null | undefined,
720
+ envelope: RunEnvelope | null | undefined,
721
+ ): RunReceiptTrustInspection {
722
+ let integrity: ReceiptIntegrityResult;
723
+ if (receipt === null || receipt === undefined) {
724
+ integrity = { ok: false, reason: "receipt unavailable" };
725
+ } else if (envelope === null || envelope === undefined) {
726
+ integrity = { ok: false, reason: "run ledger envelope unavailable" };
727
+ } else {
728
+ try {
729
+ integrity = verifyReceiptIntegrity(receipt, envelope);
730
+ } catch (error) {
731
+ integrity = {
732
+ ok: false,
733
+ reason: `receipt invalid: ${error instanceof Error ? error.message : String(error)}`,
734
+ };
735
+ }
736
+ }
737
+ return {
738
+ integrity,
739
+ status: adaptRunReceiptTrustStatus(receipt, { integrity }),
740
+ };
741
+ }
742
+
743
+ function gateReference(artifact: GateDecisionArtifact): TrustArtifactReference {
744
+ return sha256Reference("gate_decision", artifact.id, artifact.integrity.digest);
745
+ }
746
+
747
+ function gateAuthority(artifact: GateDecisionArtifact): TrustStatusAuthority {
748
+ if (artifact.outcome === "operator-confirmed") return { kind: "operator", id: "gate-confirmation" };
749
+ if (artifact.outcome === "full-auto-applied") return { kind: "clio", id: "full-auto-gate-policy" };
750
+ return { kind: "reviewer", id: artifact.decider?.runId ?? "unavailable-decider" };
751
+ }
752
+
753
+ /**
754
+ * Adapt one authenticated decision for one subject. Missing authentication is
755
+ * unknown review, never a positive verdict inherited from artifact presence.
756
+ */
757
+ export function adaptGateDecisionReviewStatus(
758
+ artifact: GateDecisionArtifact | null | undefined,
759
+ subjectRunId: string,
760
+ verification?: GateDecisionVerification,
761
+ ): IndependentReviewStatus {
762
+ if (artifact === null || artifact === undefined) return absentTrustStatus("artifact_missing");
763
+ const source: TrustStatusSource = { kind: "gate_decision", id: artifact.id };
764
+ const artifacts = [gateReference(artifact)];
765
+ const authority = gateAuthority(artifact);
766
+ if (!artifact.subjects.some((subject) => subject.runId === subjectRunId)) return absentTrustStatus("not_recorded");
767
+ if (verification === undefined || !verification.ok) {
768
+ return attributed(
769
+ "unknown",
770
+ source,
771
+ verification === undefined ? COMPATIBILITY_AUTHORITY : { kind: "unknown", id: "unauthenticated-gate-artifact" },
772
+ artifacts,
773
+ );
774
+ }
775
+ if (artifact.decider === undefined || artifact.correlation === undefined) {
776
+ if (artifact.outcome === "operator-confirmed" || artifact.outcome === "full-auto-applied") {
777
+ return attributed("not_applicable", source, authority, artifacts);
778
+ }
779
+ return attributed("inconclusive", source, authority, artifacts);
780
+ }
781
+ if (!artifact.correlation.independent) return attributed("not_independent", source, authority, artifacts);
782
+ if (artifact.outcome === "pass") return attributed("passed", source, authority, artifacts);
783
+ if (artifact.outcome === "fail") return attributed("failed", source, authority, artifacts);
784
+ if (artifact.outcome === "winner") {
785
+ return attributed(
786
+ artifact.winner?.subject.runId === subjectRunId ? "passed" : "failed",
787
+ source,
788
+ authority,
789
+ artifacts,
790
+ );
791
+ }
792
+ return attributed("inconclusive", source, authority, artifacts);
793
+ }
794
+
795
+ export interface GroundedEvidenceValidationInput {
796
+ evidenceId: string;
797
+ runId: string;
798
+ artifacts?: ReadonlyArray<TrustArtifactReference>;
799
+ }
800
+
801
+ /**
802
+ * Project validation that the evidence linker grounded in an executed
803
+ * artifact. Grounding requires at least one independently observed artifact:
804
+ * a self-report of the run under inspection cannot ground its own validation
805
+ * (docs/evidence-and-memory.md, "composition rules"), and an empty reference
806
+ * list grounds
807
+ * nothing at all.
808
+ */
809
+ export function adaptGroundedEvidenceValidationStatus(
810
+ input: GroundedEvidenceValidationInput,
811
+ ): ValidationGroundingStatus {
812
+ const observed = (input.artifacts ?? []).filter((artifact) => !SELF_REPORTED_ARTIFACT_KINDS.has(artifact.kind));
813
+ if (observed.length === 0) return absentTrustStatus("not_observed");
814
+ return attributed(
815
+ "validated",
816
+ { kind: "evidence_bundle", id: `${input.evidenceId}:${input.runId}` },
817
+ { kind: "clio", id: "evidence-grounding" },
818
+ uniqueBoundedReferences([{ kind: "evidence_bundle", id: input.evidenceId }, ...observed]),
819
+ );
820
+ }
821
+
822
+ export interface AdaptFinishContractTrustOptions {
823
+ sourceId?: string;
824
+ artifacts?: ReadonlyArray<TrustArtifactReference>;
825
+ }
826
+
827
+ /** Map the live finish contract onto completion evidence without inferring completion from autonomy. */
828
+ export function adaptFinishContractCompletionStatus(
829
+ assessment: FinishContractAssessment,
830
+ options: AdaptFinishContractTrustOptions = {},
831
+ ): CompletionEvidenceStatus {
832
+ const artifacts = uniqueBoundedReferences(
833
+ options.artifacts ??
834
+ assessment.evidence.map((evidence, index) => ({
835
+ kind: evidence.turnId === undefined ? "finish_contract_evidence" : "session_entry",
836
+ id: evidence.turnId ?? `${evidence.kind}:${index + 1}`,
837
+ })),
838
+ );
839
+ const source: TrustStatusSource = { kind: "finish_contract", id: options.sourceId ?? assessment.reason };
840
+ const authority: TrustStatusAuthority = { kind: "clio", id: "finish-contract" };
841
+ if (assessment.reason === "no_mutation") return attributed("not_applicable", source, authority, artifacts);
842
+ if (assessment.reason === "validation_evidence") return attributed("evidenced", source, authority, artifacts);
843
+ if (assessment.reason === "explicit_limitation") return attributed("limited", source, authority, artifacts);
844
+ return attributed("incomplete", source, authority, artifacts);
845
+ }
846
+
847
+ function uniqueBoundedReferences(references: ReadonlyArray<TrustArtifactReference>): TrustArtifactReference[] {
848
+ const sorted = [...references].sort(compareArtifactReferences);
849
+ const unique = sorted.filter(
850
+ (reference, index) =>
851
+ index === 0 || compareArtifactReferences(sorted[index - 1] as TrustArtifactReference, reference) !== 0,
852
+ );
853
+ return unique.slice(0, TRUST_STATUS_MAX_ARTIFACT_REFERENCES);
854
+ }