harnery 0.35.0 → 0.36.0

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 (616) hide show
  1. package/dist/commander.d.ts +30 -5
  2. package/dist/commander.d.ts.map +1 -1
  3. package/dist/commander.js +124 -96
  4. package/dist/commands/agents.d.ts +23 -3
  5. package/dist/commands/agents.d.ts.map +1 -1
  6. package/dist/commands/agents.js +379 -198
  7. package/dist/commands/backup.d.ts.map +1 -1
  8. package/dist/commands/backup.js +10 -10
  9. package/dist/commands/browse-session.d.ts.map +1 -1
  10. package/dist/commands/browse-session.js +12 -0
  11. package/dist/commands/browse.d.ts +1 -1
  12. package/dist/commands/browse.d.ts.map +1 -1
  13. package/dist/commands/browse.js +5 -4
  14. package/dist/commands/conversations.d.ts +10 -0
  15. package/dist/commands/conversations.d.ts.map +1 -0
  16. package/dist/commands/conversations.js +201 -0
  17. package/dist/commands/deinit.d.ts.map +1 -1
  18. package/dist/commands/deinit.js +5 -0
  19. package/dist/commands/docs.d.ts.map +1 -1
  20. package/dist/commands/docs.js +13 -2
  21. package/dist/commands/doctor.d.ts +5 -0
  22. package/dist/commands/doctor.d.ts.map +1 -1
  23. package/dist/commands/doctor.js +51 -7
  24. package/dist/commands/fetch.js +6 -5
  25. package/dist/commands/files.d.ts +22 -0
  26. package/dist/commands/files.d.ts.map +1 -0
  27. package/dist/commands/files.js +113 -0
  28. package/dist/commands/governor.js +14 -12
  29. package/dist/commands/inbox.d.ts +5 -0
  30. package/dist/commands/inbox.d.ts.map +1 -0
  31. package/dist/commands/inbox.js +57 -0
  32. package/dist/commands/init.d.ts +4 -5
  33. package/dist/commands/init.d.ts.map +1 -1
  34. package/dist/commands/init.js +63 -13
  35. package/dist/commands/ledger-v3.d.ts.map +1 -1
  36. package/dist/commands/ledger-v3.js +347 -1
  37. package/dist/commands/logs.d.ts +4 -0
  38. package/dist/commands/logs.d.ts.map +1 -0
  39. package/dist/commands/logs.js +169 -0
  40. package/dist/commands/messages.d.ts +5 -0
  41. package/dist/commands/messages.d.ts.map +1 -0
  42. package/dist/commands/messages.js +45 -0
  43. package/dist/commands/outline.d.ts +1 -1
  44. package/dist/commands/outline.d.ts.map +1 -1
  45. package/dist/commands/outline.js +2 -2
  46. package/dist/commands/read.d.ts +1 -1
  47. package/dist/commands/read.d.ts.map +1 -1
  48. package/dist/commands/read.js +2 -2
  49. package/dist/commands/semantic.d.ts.map +1 -1
  50. package/dist/commands/semantic.js +54 -2
  51. package/dist/commands/storage.d.ts +4 -0
  52. package/dist/commands/storage.d.ts.map +1 -0
  53. package/dist/commands/storage.js +238 -0
  54. package/dist/commands/tunnel.d.ts +5 -1
  55. package/dist/commands/tunnel.d.ts.map +1 -1
  56. package/dist/commands/tunnel.js +44 -31
  57. package/dist/commands/web.d.ts +3 -0
  58. package/dist/commands/web.d.ts.map +1 -1
  59. package/dist/commands/web.js +67 -7
  60. package/dist/commands/work.js +3 -3
  61. package/dist/commands/workflow.js +13 -13
  62. package/dist/core/adapters/profiles.d.ts +1 -1
  63. package/dist/core/agents/cli.js +209 -39
  64. package/dist/core/agents/live-authority-v3.d.ts +47 -1
  65. package/dist/core/agents/live-authority-v3.d.ts.map +1 -1
  66. package/dist/core/agents/live-authority-v3.js +244 -10
  67. package/dist/core/agents/live-lifecycle-v3.js +6 -1
  68. package/dist/core/agents/live-observation-v3.d.ts.map +1 -1
  69. package/dist/core/agents/live-observation-v3.js +6 -1
  70. package/dist/core/agents/render/prompt-context.d.ts +9 -3
  71. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  72. package/dist/core/agents/render/prompt-context.js +24 -7
  73. package/dist/core/agents/rules/stop-hook.d.ts +2 -0
  74. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  75. package/dist/core/agents/rules/stop-hook.js +94 -13
  76. package/dist/core/agents/rules/verdict.d.ts +1 -0
  77. package/dist/core/agents/rules/verdict.d.ts.map +1 -1
  78. package/dist/core/agents/session-events.d.ts.map +1 -1
  79. package/dist/core/agents/session-events.js +4 -0
  80. package/dist/core/agents/session-finalization-state-v3.js +1 -1
  81. package/dist/core/agents/session-finalizer-v3.js +5 -1
  82. package/dist/core/agents/state/activity-log.d.ts +3 -0
  83. package/dist/core/agents/state/activity-log.d.ts.map +1 -1
  84. package/dist/core/agents/state/activity-log.js +6 -3
  85. package/dist/core/agents/state/heartbeat-writer.d.ts +6 -0
  86. package/dist/core/agents/state/heartbeat-writer.d.ts.map +1 -1
  87. package/dist/core/agents/state/heartbeat-writer.js +18 -0
  88. package/dist/core/agents/state/live-coordination-view.d.ts +5 -7
  89. package/dist/core/agents/state/live-coordination-view.d.ts.map +1 -1
  90. package/dist/core/agents/state/live-coordination-view.js +15 -90
  91. package/dist/core/agents/state/live-coordination-writer.d.ts +12 -0
  92. package/dist/core/agents/state/live-coordination-writer.d.ts.map +1 -0
  93. package/dist/core/agents/state/live-coordination-writer.js +92 -0
  94. package/dist/core/artifacts/index.d.ts +21 -0
  95. package/dist/core/artifacts/index.d.ts.map +1 -1
  96. package/dist/core/artifacts/index.js +46 -1
  97. package/dist/core/config.d.ts +62 -4
  98. package/dist/core/config.d.ts.map +1 -1
  99. package/dist/core/config.js +98 -4
  100. package/dist/core/conversations/archive.d.ts +49 -0
  101. package/dist/core/conversations/archive.d.ts.map +1 -0
  102. package/dist/core/conversations/archive.js +136 -0
  103. package/dist/core/conversations/catalog.d.ts +10 -0
  104. package/dist/core/conversations/catalog.d.ts.map +1 -0
  105. package/dist/core/conversations/catalog.js +72 -0
  106. package/dist/core/conversations/context-pack.d.ts +6 -0
  107. package/dist/core/conversations/context-pack.d.ts.map +1 -0
  108. package/dist/core/conversations/context-pack.js +60 -0
  109. package/dist/core/conversations/contract.d.ts +155 -0
  110. package/dist/core/conversations/contract.d.ts.map +1 -0
  111. package/dist/core/conversations/contract.js +1 -0
  112. package/dist/core/conversations/evaluation.d.ts +16 -0
  113. package/dist/core/conversations/evaluation.d.ts.map +1 -0
  114. package/dist/core/conversations/evaluation.js +9 -0
  115. package/dist/core/conversations/index.d.ts +10 -0
  116. package/dist/core/conversations/index.d.ts.map +1 -0
  117. package/dist/core/conversations/index.js +9 -0
  118. package/dist/core/conversations/lifecycle.d.ts +28 -0
  119. package/dist/core/conversations/lifecycle.d.ts.map +1 -0
  120. package/dist/core/conversations/lifecycle.js +29 -0
  121. package/dist/core/conversations/normalize.d.ts +14 -0
  122. package/dist/core/conversations/normalize.d.ts.map +1 -0
  123. package/dist/core/conversations/normalize.js +82 -0
  124. package/dist/core/conversations/query.d.ts +8 -0
  125. package/dist/core/conversations/query.d.ts.map +1 -0
  126. package/dist/core/conversations/query.js +280 -0
  127. package/dist/core/conversations/search-index.d.ts +9 -0
  128. package/dist/core/conversations/search-index.d.ts.map +1 -0
  129. package/dist/core/conversations/search-index.js +29 -0
  130. package/dist/core/events/legacy-storage/canary.d.ts +18 -0
  131. package/dist/core/events/legacy-storage/canary.d.ts.map +1 -0
  132. package/dist/core/events/legacy-storage/canary.js +150 -0
  133. package/dist/core/events/legacy-storage/fence.d.ts +15 -0
  134. package/dist/core/events/legacy-storage/fence.d.ts.map +1 -0
  135. package/dist/core/events/legacy-storage/fence.js +115 -0
  136. package/dist/core/events/legacy-storage/index.d.ts +6 -0
  137. package/dist/core/events/legacy-storage/index.d.ts.map +1 -0
  138. package/dist/core/events/legacy-storage/index.js +5 -0
  139. package/dist/core/events/legacy-storage/inventory.d.ts +10 -0
  140. package/dist/core/events/legacy-storage/inventory.d.ts.map +1 -0
  141. package/dist/core/events/legacy-storage/inventory.js +40 -0
  142. package/dist/core/events/legacy-storage/manifest.d.ts +23 -0
  143. package/dist/core/events/legacy-storage/manifest.d.ts.map +1 -0
  144. package/dist/core/events/legacy-storage/manifest.js +108 -0
  145. package/dist/core/events/legacy-storage/reader.d.ts +15 -0
  146. package/dist/core/events/legacy-storage/reader.d.ts.map +1 -0
  147. package/dist/core/events/legacy-storage/reader.js +154 -0
  148. package/dist/core/events/v3/authority-outbox.d.ts +7 -2
  149. package/dist/core/events/v3/authority-outbox.d.ts.map +1 -1
  150. package/dist/core/events/v3/authority-outbox.js +16 -3
  151. package/dist/core/events/v3/base-contract.d.ts +81 -41
  152. package/dist/core/events/v3/base-contract.d.ts.map +1 -1
  153. package/dist/core/events/v3/base-contract.js +17 -7
  154. package/dist/core/events/v3/bootstrap.d.ts +39 -0
  155. package/dist/core/events/v3/bootstrap.d.ts.map +1 -1
  156. package/dist/core/events/v3/bootstrap.js +167 -3
  157. package/dist/core/events/v3/capabilities.js +3 -3
  158. package/dist/core/events/v3/control-witness.d.ts +44 -0
  159. package/dist/core/events/v3/control-witness.d.ts.map +1 -0
  160. package/dist/core/events/v3/control-witness.js +233 -0
  161. package/dist/core/events/v3/control-writer.d.ts +4 -0
  162. package/dist/core/events/v3/control-writer.d.ts.map +1 -0
  163. package/dist/core/events/v3/control-writer.js +16 -0
  164. package/dist/core/events/v3/control.d.ts +8 -2
  165. package/dist/core/events/v3/control.d.ts.map +1 -1
  166. package/dist/core/events/v3/control.js +46 -18
  167. package/dist/core/events/v3/coordination-transaction-recovery.d.ts +42 -0
  168. package/dist/core/events/v3/coordination-transaction-recovery.d.ts.map +1 -0
  169. package/dist/core/events/v3/coordination-transaction-recovery.js +342 -0
  170. package/dist/core/events/v3/coordination-view.d.ts.map +1 -1
  171. package/dist/core/events/v3/coordination-view.js +16 -1
  172. package/dist/core/events/v3/generated.d.ts +1 -1
  173. package/dist/core/events/v3/generated.js +1 -1
  174. package/dist/core/events/v3/index.d.ts +4 -2
  175. package/dist/core/events/v3/index.d.ts.map +1 -1
  176. package/dist/core/events/v3/index.js +3 -1
  177. package/dist/core/events/v3/live-route-observer.d.ts +31 -0
  178. package/dist/core/events/v3/live-route-observer.d.ts.map +1 -0
  179. package/dist/core/events/v3/live-route-observer.js +58 -0
  180. package/dist/core/events/v3/live-routing.d.ts +13 -21
  181. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  182. package/dist/core/events/v3/live-routing.js +45 -41
  183. package/dist/core/events/v3/producers/coordination-recorder.d.ts +11 -1
  184. package/dist/core/events/v3/producers/coordination-recorder.d.ts.map +1 -1
  185. package/dist/core/events/v3/producers/coordination-recorder.js +76 -10
  186. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts +129 -0
  187. package/dist/core/events/v3/producers/diagnostic-summaries.d.ts.map +1 -0
  188. package/dist/core/events/v3/producers/diagnostic-summaries.js +499 -0
  189. package/dist/core/events/v3/producers/hook-base.js +1 -1
  190. package/dist/core/events/v3/producers/intake.d.ts +7 -0
  191. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  192. package/dist/core/events/v3/producers/intake.js +25 -2
  193. package/dist/core/events/v3/producers/producer-state-observer.d.ts +8 -0
  194. package/dist/core/events/v3/producers/producer-state-observer.d.ts.map +1 -0
  195. package/dist/core/events/v3/producers/producer-state-observer.js +45 -0
  196. package/dist/core/events/v3/producers/recorder.d.ts +55 -1
  197. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  198. package/dist/core/events/v3/producers/recorder.js +353 -24
  199. package/dist/core/events/v3/reader.d.ts +51 -0
  200. package/dist/core/events/v3/reader.d.ts.map +1 -1
  201. package/dist/core/events/v3/reader.js +181 -1
  202. package/dist/core/events/v3/rotation-config.d.ts +9 -0
  203. package/dist/core/events/v3/rotation-config.d.ts.map +1 -0
  204. package/dist/core/events/v3/rotation-config.js +91 -0
  205. package/dist/core/events/v3/runtime-build.d.ts +11 -0
  206. package/dist/core/events/v3/runtime-build.d.ts.map +1 -0
  207. package/dist/core/events/v3/runtime-build.js +39 -0
  208. package/dist/core/events/v3/runtime-identity.d.ts +5 -0
  209. package/dist/core/events/v3/runtime-identity.d.ts.map +1 -0
  210. package/dist/core/events/v3/runtime-identity.js +18 -0
  211. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts +6 -5
  212. package/dist/core/events/v3/runtime-telemetry-capabilities.d.ts.map +1 -1
  213. package/dist/core/events/v3/runtime-telemetry-capabilities.js +1 -1
  214. package/dist/core/events/v3/support-storage/classify.d.ts +46 -0
  215. package/dist/core/events/v3/support-storage/classify.d.ts.map +1 -0
  216. package/dist/core/events/v3/support-storage/classify.js +149 -0
  217. package/dist/core/events/v3/support-storage/eligibility.d.ts +29 -0
  218. package/dist/core/events/v3/support-storage/eligibility.d.ts.map +1 -0
  219. package/dist/core/events/v3/support-storage/eligibility.js +35 -0
  220. package/dist/core/events/v3/support-storage/index.d.ts +10 -0
  221. package/dist/core/events/v3/support-storage/index.d.ts.map +1 -0
  222. package/dist/core/events/v3/support-storage/index.js +9 -0
  223. package/dist/core/events/v3/support-storage/inventory.d.ts +30 -0
  224. package/dist/core/events/v3/support-storage/inventory.d.ts.map +1 -0
  225. package/dist/core/events/v3/support-storage/inventory.js +94 -0
  226. package/dist/core/events/v3/support-storage/logical-authority.d.ts +14 -0
  227. package/dist/core/events/v3/support-storage/logical-authority.d.ts.map +1 -0
  228. package/dist/core/events/v3/support-storage/logical-authority.js +104 -0
  229. package/dist/core/events/v3/support-storage/maintenance.d.ts +98 -0
  230. package/dist/core/events/v3/support-storage/maintenance.d.ts.map +1 -0
  231. package/dist/core/events/v3/support-storage/maintenance.js +352 -0
  232. package/dist/core/events/v3/support-storage/pack-contract.d.ts +59 -0
  233. package/dist/core/events/v3/support-storage/pack-contract.d.ts.map +1 -0
  234. package/dist/core/events/v3/support-storage/pack-contract.js +249 -0
  235. package/dist/core/events/v3/support-storage/pack-reader.d.ts +34 -0
  236. package/dist/core/events/v3/support-storage/pack-reader.d.ts.map +1 -0
  237. package/dist/core/events/v3/support-storage/pack-reader.js +258 -0
  238. package/dist/core/events/v3/support-storage/pack-writer.d.ts +30 -0
  239. package/dist/core/events/v3/support-storage/pack-writer.d.ts.map +1 -0
  240. package/dist/core/events/v3/support-storage/pack-writer.js +268 -0
  241. package/dist/core/events/v3/support-storage/recovery.d.ts +15 -0
  242. package/dist/core/events/v3/support-storage/recovery.d.ts.map +1 -0
  243. package/dist/core/events/v3/support-storage/recovery.js +22 -0
  244. package/dist/core/events/v3/turn-telemetry.d.ts +14 -8
  245. package/dist/core/events/v3/turn-telemetry.d.ts.map +1 -1
  246. package/dist/core/events/v3/turn-telemetry.js +32 -2
  247. package/dist/core/events/v3/writer.d.ts +13 -1
  248. package/dist/core/events/v3/writer.d.ts.map +1 -1
  249. package/dist/core/events/v3/writer.js +126 -12
  250. package/dist/core/governor/plan-read.d.ts.map +1 -1
  251. package/dist/core/governor/plan-read.js +5 -21
  252. package/dist/core/governor/planning.js +6 -8
  253. package/dist/core/governor/service-read.d.ts +12 -0
  254. package/dist/core/governor/service-read.d.ts.map +1 -1
  255. package/dist/core/governor/service-read.js +266 -2
  256. package/dist/core/governor/service.d.ts +1 -0
  257. package/dist/core/governor/service.d.ts.map +1 -1
  258. package/dist/core/governor/service.js +53 -18
  259. package/dist/core/guard/evidence-v3.d.ts.map +1 -1
  260. package/dist/core/guard/evidence-v3.js +2 -0
  261. package/dist/core/hooks/adapter/events.d.ts.map +1 -1
  262. package/dist/core/hooks/adapter/events.js +1 -0
  263. package/dist/core/hooks/adapter/output.d.ts +4 -2
  264. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  265. package/dist/core/hooks/adapter/output.js +13 -5
  266. package/dist/core/hooks/adapter/runtime-telemetry.d.ts +27 -4
  267. package/dist/core/hooks/adapter/runtime-telemetry.d.ts.map +1 -1
  268. package/dist/core/hooks/adapter/runtime-telemetry.js +307 -6
  269. package/dist/core/hooks/cli.js +212 -30
  270. package/dist/core/hooks/effects/image-capture.d.ts +1 -1
  271. package/dist/core/hooks/effects/image-capture.d.ts.map +1 -1
  272. package/dist/core/hooks/effects/image-capture.js +4 -2
  273. package/dist/core/hooks/remediation-cap.d.ts +8 -3
  274. package/dist/core/hooks/remediation-cap.d.ts.map +1 -1
  275. package/dist/core/hooks/remediation-cap.js +3 -11
  276. package/dist/core/hooks/resolve/coord-root.d.ts +22 -9
  277. package/dist/core/hooks/resolve/coord-root.d.ts.map +1 -1
  278. package/dist/core/hooks/resolve/coord-root.js +92 -11
  279. package/dist/core/hooks/resolve/owner.d.ts.map +1 -1
  280. package/dist/core/hooks/resolve/owner.js +5 -0
  281. package/dist/core/hooks/resolve/transcript.d.ts +8 -0
  282. package/dist/core/hooks/resolve/transcript.d.ts.map +1 -1
  283. package/dist/core/hooks/resolve/transcript.js +11 -0
  284. package/dist/core/inbox/contract.d.ts +64 -0
  285. package/dist/core/inbox/contract.d.ts.map +1 -0
  286. package/dist/core/inbox/contract.js +13 -0
  287. package/dist/core/inbox/index.d.ts +5 -0
  288. package/dist/core/inbox/index.d.ts.map +1 -0
  289. package/dist/core/inbox/index.js +4 -0
  290. package/dist/core/inbox/lifecycle.d.ts +22 -0
  291. package/dist/core/inbox/lifecycle.d.ts.map +1 -0
  292. package/dist/core/inbox/lifecycle.js +41 -0
  293. package/dist/core/inbox/service.d.ts +36 -0
  294. package/dist/core/inbox/service.d.ts.map +1 -0
  295. package/dist/core/inbox/service.js +210 -0
  296. package/dist/core/inbox/watcher.d.ts +7 -0
  297. package/dist/core/inbox/watcher.d.ts.map +1 -0
  298. package/dist/core/inbox/watcher.js +26 -0
  299. package/dist/core/presence/codec-digest.d.ts.map +1 -1
  300. package/dist/core/presence/codec-digest.js +14 -3
  301. package/dist/core/presence/relay-client.d.ts +1 -0
  302. package/dist/core/presence/relay-client.d.ts.map +1 -1
  303. package/dist/core/presence/relay-client.js +52 -8
  304. package/dist/core/semantic/adapters.d.ts +11 -8
  305. package/dist/core/semantic/adapters.d.ts.map +1 -1
  306. package/dist/core/semantic/adapters.js +169 -31
  307. package/dist/core/semantic/contract.d.ts +532 -48
  308. package/dist/core/semantic/contract.d.ts.map +1 -1
  309. package/dist/core/semantic/contract.js +104 -3
  310. package/dist/core/semantic/index.d.ts +7 -3
  311. package/dist/core/semantic/index.d.ts.map +1 -1
  312. package/dist/core/semantic/index.js +7 -3
  313. package/dist/core/semantic/once.d.ts +6 -1
  314. package/dist/core/semantic/once.d.ts.map +1 -1
  315. package/dist/core/semantic/once.js +80 -9
  316. package/dist/core/semantic/prompt.d.ts.map +1 -1
  317. package/dist/core/semantic/prompt.js +14 -1
  318. package/dist/core/semantic/review.d.ts +144 -0
  319. package/dist/core/semantic/review.d.ts.map +1 -0
  320. package/dist/core/semantic/review.js +544 -0
  321. package/dist/core/semantic/routes.d.ts +10 -0
  322. package/dist/core/semantic/routes.d.ts.map +1 -0
  323. package/dist/core/semantic/routes.js +21 -0
  324. package/dist/core/semantic/scheduler.d.ts +14 -3
  325. package/dist/core/semantic/scheduler.d.ts.map +1 -1
  326. package/dist/core/semantic/scheduler.js +30 -6
  327. package/dist/core/semantic/service-status.d.ts +20 -0
  328. package/dist/core/semantic/service-status.d.ts.map +1 -1
  329. package/dist/core/semantic/service-status.js +60 -4
  330. package/dist/core/semantic/service.d.ts +1 -0
  331. package/dist/core/semantic/service.d.ts.map +1 -1
  332. package/dist/core/semantic/service.js +104 -15
  333. package/dist/core/semantic/soak.d.ts +75 -0
  334. package/dist/core/semantic/soak.d.ts.map +1 -0
  335. package/dist/core/semantic/soak.js +476 -0
  336. package/dist/core/semantic/storage.d.ts +11 -1
  337. package/dist/core/semantic/storage.d.ts.map +1 -1
  338. package/dist/core/semantic/storage.js +4 -3
  339. package/dist/core/semantic/usage.d.ts +43 -0
  340. package/dist/core/semantic/usage.d.ts.map +1 -0
  341. package/dist/core/semantic/usage.js +193 -0
  342. package/dist/core/semantic/validate.d.ts +3 -1
  343. package/dist/core/semantic/validate.d.ts.map +1 -1
  344. package/dist/core/semantic/validate.js +34 -1
  345. package/dist/core/storage/buffer.d.ts +28 -0
  346. package/dist/core/storage/buffer.d.ts.map +1 -0
  347. package/dist/core/storage/buffer.js +101 -0
  348. package/dist/core/storage/builtins.d.ts +3 -0
  349. package/dist/core/storage/builtins.d.ts.map +1 -0
  350. package/dist/core/storage/builtins.js +683 -0
  351. package/dist/core/storage/catalog.d.ts +19 -0
  352. package/dist/core/storage/catalog.d.ts.map +1 -0
  353. package/dist/core/storage/catalog.js +365 -0
  354. package/dist/core/storage/config.d.ts +16 -0
  355. package/dist/core/storage/config.d.ts.map +1 -0
  356. package/dist/core/storage/config.js +311 -0
  357. package/dist/core/storage/contract.d.ts +275 -0
  358. package/dist/core/storage/contract.d.ts.map +1 -0
  359. package/dist/core/storage/contract.js +3 -0
  360. package/dist/core/storage/durable-history.d.ts +36 -0
  361. package/dist/core/storage/durable-history.d.ts.map +1 -0
  362. package/dist/core/storage/durable-history.js +606 -0
  363. package/dist/core/storage/health.d.ts +4 -0
  364. package/dist/core/storage/health.d.ts.map +1 -0
  365. package/dist/core/storage/health.js +65 -0
  366. package/dist/core/storage/index.d.ts +16 -0
  367. package/dist/core/storage/index.d.ts.map +1 -0
  368. package/dist/core/storage/index.js +15 -0
  369. package/dist/core/storage/inventory.d.ts +25 -0
  370. package/dist/core/storage/inventory.d.ts.map +1 -0
  371. package/dist/core/storage/inventory.js +666 -0
  372. package/dist/core/storage/jsonl.d.ts +52 -0
  373. package/dist/core/storage/jsonl.d.ts.map +1 -0
  374. package/dist/core/storage/jsonl.js +156 -0
  375. package/dist/core/storage/log-retention.d.ts +52 -0
  376. package/dist/core/storage/log-retention.d.ts.map +1 -0
  377. package/dist/core/storage/log-retention.js +419 -0
  378. package/dist/core/storage/logger.d.ts +82 -0
  379. package/dist/core/storage/logger.d.ts.map +1 -0
  380. package/dist/core/storage/logger.js +411 -0
  381. package/dist/core/storage/maintenance-providers.d.ts +26 -0
  382. package/dist/core/storage/maintenance-providers.d.ts.map +1 -0
  383. package/dist/core/storage/maintenance-providers.js +141 -0
  384. package/dist/core/storage/maintenance.d.ts +125 -0
  385. package/dist/core/storage/maintenance.d.ts.map +1 -0
  386. package/dist/core/storage/maintenance.js +609 -0
  387. package/dist/core/storage/metrics.d.ts +60 -0
  388. package/dist/core/storage/metrics.d.ts.map +1 -0
  389. package/dist/core/storage/metrics.js +134 -0
  390. package/dist/core/storage/policy.d.ts +7 -0
  391. package/dist/core/storage/policy.d.ts.map +1 -0
  392. package/dist/core/storage/policy.js +110 -0
  393. package/dist/core/storage/process-log.d.ts +38 -0
  394. package/dist/core/storage/process-log.d.ts.map +1 -0
  395. package/dist/core/storage/process-log.js +165 -0
  396. package/dist/core/storage/query.d.ts +34 -0
  397. package/dist/core/storage/query.d.ts.map +1 -0
  398. package/dist/core/storage/query.js +295 -0
  399. package/dist/core/storage/receipts.d.ts +23 -0
  400. package/dist/core/storage/receipts.d.ts.map +1 -0
  401. package/dist/core/storage/receipts.js +117 -0
  402. package/dist/core/storage/segments.d.ts +84 -0
  403. package/dist/core/storage/segments.d.ts.map +1 -0
  404. package/dist/core/storage/segments.js +542 -0
  405. package/dist/core/storage/sink-graph.d.ts +65 -0
  406. package/dist/core/storage/sink-graph.d.ts.map +1 -0
  407. package/dist/core/storage/sink-graph.js +213 -0
  408. package/dist/core/storage/storm-control.d.ts +23 -0
  409. package/dist/core/storage/storm-control.d.ts.map +1 -0
  410. package/dist/core/storage/storm-control.js +59 -0
  411. package/dist/core/work/state.d.ts.map +1 -1
  412. package/dist/core/work/state.js +10 -14
  413. package/dist/core/workflow/live-session-v3.d.ts.map +1 -1
  414. package/dist/core/workflow/live-session-v3.js +2 -1
  415. package/dist/index.d.ts +2 -0
  416. package/dist/index.d.ts.map +1 -1
  417. package/dist/index.js +2 -0
  418. package/dist/lazy-commands.d.ts +26 -0
  419. package/dist/lazy-commands.d.ts.map +1 -0
  420. package/dist/lazy-commands.js +210 -0
  421. package/dist/lib/docs-lint.d.ts +2 -0
  422. package/dist/lib/docs-lint.d.ts.map +1 -1
  423. package/dist/lib/docs-lint.js +45 -80
  424. package/dist/lib/docs-metadata-audit.d.ts +3 -0
  425. package/dist/lib/docs-metadata-audit.d.ts.map +1 -1
  426. package/dist/lib/docs-metadata-audit.js +13 -23
  427. package/dist/lib/docs-metadata-sync.d.ts +1 -0
  428. package/dist/lib/docs-metadata-sync.d.ts.map +1 -1
  429. package/dist/lib/docs-metadata-sync.js +28 -10
  430. package/dist/lib/docs-repository-view.d.ts +22 -0
  431. package/dist/lib/docs-repository-view.d.ts.map +1 -0
  432. package/dist/lib/docs-repository-view.js +185 -0
  433. package/dist/lib/http/client.d.ts +11 -5
  434. package/dist/lib/http/client.d.ts.map +1 -1
  435. package/dist/lib/http/client.js +22 -4
  436. package/dist/lib/http/index.d.ts +1 -1
  437. package/dist/lib/http/index.d.ts.map +1 -1
  438. package/dist/lib/http/index.js +1 -1
  439. package/dist/lib/indexer-exclusions.d.ts +27 -0
  440. package/dist/lib/indexer-exclusions.d.ts.map +1 -0
  441. package/dist/lib/indexer-exclusions.js +176 -0
  442. package/dist/lib/instructions/templates.d.ts.map +1 -1
  443. package/dist/lib/instructions/templates.js +5 -0
  444. package/dist/lib/local-file-url.d.ts +9 -0
  445. package/dist/lib/local-file-url.d.ts.map +1 -0
  446. package/dist/lib/local-file-url.js +20 -0
  447. package/dist/lib/web-performance.d.ts +118 -0
  448. package/dist/lib/web-performance.d.ts.map +1 -0
  449. package/dist/lib/web-performance.js +192 -0
  450. package/package.json +29 -2
  451. package/schemas/config.schema.json +58 -0
  452. package/schemas/event-v3.schema.json +324 -112
  453. package/src/commander.ts +462 -95
  454. package/src/commands/agents.ts +517 -190
  455. package/src/commands/backup.ts +18 -14
  456. package/src/commands/browse-session.ts +12 -0
  457. package/src/commands/browse.ts +6 -7
  458. package/src/commands/conversations.ts +279 -0
  459. package/src/commands/deinit.ts +6 -0
  460. package/src/commands/docs.ts +25 -6
  461. package/src/commands/doctor.ts +75 -9
  462. package/src/commands/fetch.ts +7 -6
  463. package/src/commands/files.ts +143 -0
  464. package/src/commands/governor.ts +13 -12
  465. package/src/commands/inbox.ts +61 -0
  466. package/src/commands/init.ts +78 -16
  467. package/src/commands/ledger-v3.ts +421 -1
  468. package/src/commands/logs.ts +224 -0
  469. package/src/commands/messages.ts +61 -0
  470. package/src/commands/outline.ts +6 -2
  471. package/src/commands/read.ts +6 -2
  472. package/src/commands/semantic.ts +66 -1
  473. package/src/commands/storage.ts +310 -0
  474. package/src/commands/tunnel.ts +66 -52
  475. package/src/commands/web.ts +77 -7
  476. package/src/commands/work.ts +3 -3
  477. package/src/commands/workflow.ts +13 -13
  478. package/src/core/agents/cli.ts +259 -53
  479. package/src/core/agents/live-authority-v3.ts +341 -10
  480. package/src/core/agents/live-lifecycle-v3.ts +6 -1
  481. package/src/core/agents/live-observation-v3.ts +6 -1
  482. package/src/core/agents/render/prompt-context.ts +27 -6
  483. package/src/core/agents/rules/stop-hook.ts +107 -16
  484. package/src/core/agents/rules/verdict.ts +1 -0
  485. package/src/core/agents/session-events.ts +4 -0
  486. package/src/core/agents/session-finalization-state-v3.ts +1 -1
  487. package/src/core/agents/session-finalizer-v3.ts +4 -1
  488. package/src/core/agents/state/activity-log.ts +7 -2
  489. package/src/core/agents/state/heartbeat-writer.ts +27 -0
  490. package/src/core/agents/state/live-coordination-view.ts +16 -105
  491. package/src/core/agents/state/live-coordination-writer.ts +141 -0
  492. package/src/core/artifacts/index.ts +64 -1
  493. package/src/core/config.ts +126 -5
  494. package/src/core/conversations/archive.ts +237 -0
  495. package/src/core/conversations/catalog.ts +79 -0
  496. package/src/core/conversations/context-pack.ts +72 -0
  497. package/src/core/conversations/contract.ts +178 -0
  498. package/src/core/conversations/evaluation.ts +30 -0
  499. package/src/core/conversations/index.ts +9 -0
  500. package/src/core/conversations/lifecycle.ts +63 -0
  501. package/src/core/conversations/normalize.ts +105 -0
  502. package/src/core/conversations/query.ts +318 -0
  503. package/src/core/conversations/search-index.ts +48 -0
  504. package/src/core/events/legacy-storage/canary.ts +177 -0
  505. package/src/core/events/legacy-storage/fence.ts +129 -0
  506. package/src/core/events/legacy-storage/index.ts +5 -0
  507. package/src/core/events/legacy-storage/inventory.ts +51 -0
  508. package/src/core/events/legacy-storage/manifest.ts +136 -0
  509. package/src/core/events/legacy-storage/reader.ts +178 -0
  510. package/src/core/events/v3/authority-outbox.ts +22 -1
  511. package/src/core/events/v3/base-contract.ts +17 -7
  512. package/src/core/events/v3/bootstrap.ts +195 -2
  513. package/src/core/events/v3/capabilities.ts +3 -3
  514. package/src/core/events/v3/control-witness.ts +339 -0
  515. package/src/core/events/v3/control-writer.ts +16 -0
  516. package/src/core/events/v3/control.ts +54 -18
  517. package/src/core/events/v3/coordination-transaction-recovery.ts +477 -0
  518. package/src/core/events/v3/coordination-view.ts +17 -1
  519. package/src/core/events/v3/generated.ts +1 -1
  520. package/src/core/events/v3/index.ts +5 -2
  521. package/src/core/events/v3/live-route-observer.ts +80 -0
  522. package/src/core/events/v3/live-routing.ts +64 -46
  523. package/src/core/events/v3/producers/coordination-recorder.ts +95 -10
  524. package/src/core/events/v3/producers/diagnostic-summaries.ts +593 -0
  525. package/src/core/events/v3/producers/hook-base.ts +1 -1
  526. package/src/core/events/v3/producers/intake.ts +30 -2
  527. package/src/core/events/v3/producers/producer-state-observer.ts +52 -0
  528. package/src/core/events/v3/producers/recorder.ts +571 -33
  529. package/src/core/events/v3/reader.ts +243 -2
  530. package/src/core/events/v3/rotation-config.ts +98 -0
  531. package/src/core/events/v3/runtime-build.ts +41 -0
  532. package/src/core/events/v3/runtime-identity.ts +16 -0
  533. package/src/core/events/v3/runtime-telemetry-capabilities.ts +14 -8
  534. package/src/core/events/v3/support-storage/classify.ts +209 -0
  535. package/src/core/events/v3/support-storage/eligibility.ts +58 -0
  536. package/src/core/events/v3/support-storage/index.ts +9 -0
  537. package/src/core/events/v3/support-storage/inventory.ts +135 -0
  538. package/src/core/events/v3/support-storage/logical-authority.ts +117 -0
  539. package/src/core/events/v3/support-storage/maintenance.ts +501 -0
  540. package/src/core/events/v3/support-storage/pack-contract.ts +337 -0
  541. package/src/core/events/v3/support-storage/pack-reader.ts +346 -0
  542. package/src/core/events/v3/support-storage/pack-writer.ts +352 -0
  543. package/src/core/events/v3/support-storage/recovery.ts +43 -0
  544. package/src/core/events/v3/turn-telemetry.ts +58 -7
  545. package/src/core/events/v3/writer.ts +168 -16
  546. package/src/core/governor/plan-read.ts +5 -18
  547. package/src/core/governor/planning.ts +5 -8
  548. package/src/core/governor/service-read.ts +320 -2
  549. package/src/core/governor/service.ts +49 -22
  550. package/src/core/guard/evidence-v3.ts +1 -0
  551. package/src/core/hooks/adapter/events.ts +1 -0
  552. package/src/core/hooks/adapter/output.ts +12 -5
  553. package/src/core/hooks/adapter/runtime-telemetry.ts +408 -13
  554. package/src/core/hooks/cli.ts +226 -32
  555. package/src/core/hooks/effects/image-capture.ts +4 -1
  556. package/src/core/hooks/remediation-cap.ts +12 -6
  557. package/src/core/hooks/resolve/coord-root.ts +91 -11
  558. package/src/core/hooks/resolve/owner.ts +4 -0
  559. package/src/core/hooks/resolve/transcript.ts +18 -0
  560. package/src/core/inbox/contract.ts +81 -0
  561. package/src/core/inbox/index.ts +4 -0
  562. package/src/core/inbox/lifecycle.ts +104 -0
  563. package/src/core/inbox/service.ts +305 -0
  564. package/src/core/inbox/watcher.ts +36 -0
  565. package/src/core/presence/codec-digest.ts +15 -9
  566. package/src/core/presence/relay-client.ts +55 -7
  567. package/src/core/semantic/adapters.ts +200 -41
  568. package/src/core/semantic/contract.ts +135 -3
  569. package/src/core/semantic/index.ts +76 -2
  570. package/src/core/semantic/once.ts +93 -7
  571. package/src/core/semantic/prompt.ts +13 -1
  572. package/src/core/semantic/review.ts +803 -0
  573. package/src/core/semantic/routes.ts +30 -0
  574. package/src/core/semantic/scheduler.ts +49 -5
  575. package/src/core/semantic/service-status.ts +99 -5
  576. package/src/core/semantic/service.ts +116 -15
  577. package/src/core/semantic/soak.ts +638 -0
  578. package/src/core/semantic/storage.ts +20 -6
  579. package/src/core/semantic/usage.ts +272 -0
  580. package/src/core/semantic/validate.ts +31 -0
  581. package/src/core/storage/buffer.ts +124 -0
  582. package/src/core/storage/builtins.ts +916 -0
  583. package/src/core/storage/catalog.ts +467 -0
  584. package/src/core/storage/config.ts +423 -0
  585. package/src/core/storage/contract.ts +342 -0
  586. package/src/core/storage/durable-history.ts +738 -0
  587. package/src/core/storage/health.ts +76 -0
  588. package/src/core/storage/index.ts +15 -0
  589. package/src/core/storage/inventory.ts +859 -0
  590. package/src/core/storage/jsonl.ts +213 -0
  591. package/src/core/storage/log-retention.ts +555 -0
  592. package/src/core/storage/logger.ts +546 -0
  593. package/src/core/storage/maintenance-providers.ts +200 -0
  594. package/src/core/storage/maintenance.ts +929 -0
  595. package/src/core/storage/metrics.ts +199 -0
  596. package/src/core/storage/policy.ts +141 -0
  597. package/src/core/storage/process-log.ts +203 -0
  598. package/src/core/storage/query.ts +360 -0
  599. package/src/core/storage/receipts.ts +162 -0
  600. package/src/core/storage/segments.ts +721 -0
  601. package/src/core/storage/sink-graph.ts +343 -0
  602. package/src/core/storage/storm-control.ts +91 -0
  603. package/src/core/work/state.ts +12 -21
  604. package/src/core/workflow/live-session-v3.ts +2 -4
  605. package/src/index.ts +2 -0
  606. package/src/lazy-commands.ts +294 -0
  607. package/src/lib/docs-lint.ts +58 -77
  608. package/src/lib/docs-metadata-audit.ts +26 -21
  609. package/src/lib/docs-metadata-sync.ts +32 -9
  610. package/src/lib/docs-repository-view.ts +220 -0
  611. package/src/lib/http/client.ts +44 -8
  612. package/src/lib/http/index.ts +6 -1
  613. package/src/lib/indexer-exclusions.ts +173 -0
  614. package/src/lib/instructions/templates.ts +5 -0
  615. package/src/lib/local-file-url.ts +31 -0
  616. package/src/lib/web-performance.ts +335 -0
@@ -0,0 +1,803 @@
1
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
2
+ import {
3
+ chmodSync,
4
+ existsSync,
5
+ mkdirSync,
6
+ readdirSync,
7
+ readFileSync,
8
+ renameSync,
9
+ rmSync,
10
+ statSync,
11
+ writeFileSync,
12
+ } from "node:fs";
13
+ import { dirname, join, resolve } from "node:path";
14
+ import type {
15
+ SemanticAcceptedReadModelV2,
16
+ SemanticConfiguredModel,
17
+ SemanticEvidenceObservationV1,
18
+ SemanticEvidenceV1,
19
+ SemanticExpressionCue,
20
+ SemanticHarness,
21
+ SemanticMeaningV2,
22
+ SemanticPhase,
23
+ SemanticTag,
24
+ } from "./contract.ts";
25
+ import {
26
+ SEMANTIC_EXPRESSION_CUES,
27
+ SEMANTIC_HARNESSES,
28
+ SEMANTIC_PHASES,
29
+ SEMANTIC_TAGS,
30
+ } from "./contract.ts";
31
+ import { buildSemanticEvidenceV1 } from "./evidence.ts";
32
+ import { listSemanticAgentDocuments } from "./storage.ts";
33
+
34
+ export const SEMANTIC_REVIEW_SCHEMA_VERSION = 1 as const;
35
+ export const SEMANTIC_REVIEW_OVERALL_VERDICTS = ["correct", "close", "wrong", "unsure"] as const;
36
+ export const SEMANTIC_REVIEW_FIELD_VERDICTS = ["correct", "wrong", "unsure"] as const;
37
+ export const SEMANTIC_REVIEW_PORTRAIT_VERDICTS = ["helpful", "neutral", "misleading"] as const;
38
+ export const SEMANTIC_REVIEW_TRANSITION_VERDICTS = ["real-change", "flicker", "unsure"] as const;
39
+ export const SEMANTIC_REVIEW_CONFIDENCE = ["low", "medium", "high"] as const;
40
+ export const SEMANTIC_REVIEW_NO_EXPRESSION = "none" as const;
41
+
42
+ export type SemanticReviewOverallVerdict = (typeof SEMANTIC_REVIEW_OVERALL_VERDICTS)[number];
43
+ export type SemanticReviewFieldVerdict = (typeof SEMANTIC_REVIEW_FIELD_VERDICTS)[number];
44
+ export type SemanticReviewPortraitVerdict = (typeof SEMANTIC_REVIEW_PORTRAIT_VERDICTS)[number];
45
+ export type SemanticReviewTransitionVerdict = (typeof SEMANTIC_REVIEW_TRANSITION_VERDICTS)[number];
46
+ export type SemanticReviewConfidence = (typeof SEMANTIC_REVIEW_CONFIDENCE)[number];
47
+ export type SemanticReviewExpression = SemanticExpressionCue | typeof SEMANTIC_REVIEW_NO_EXPRESSION;
48
+
49
+ export interface SemanticReviewObservationV1 {
50
+ kind: string;
51
+ observed_at: string;
52
+ label?: string;
53
+ outcome?: string;
54
+ error_class?: string;
55
+ }
56
+
57
+ export interface SemanticReviewEvidenceSnapshotV1 {
58
+ observed_through_ts: string;
59
+ task?: string;
60
+ lifecycle?: string;
61
+ intent?: string;
62
+ operation?: { category: string; label: string };
63
+ waits: Array<{ kind: string; started_at: string }>;
64
+ recent: SemanticReviewObservationV1[];
65
+ attention?: SemanticReviewObservationV1;
66
+ }
67
+
68
+ export interface SemanticReviewProposalFieldV1<T> {
69
+ value: T;
70
+ confidence: "high" | "medium" | "low";
71
+ }
72
+
73
+ export interface SemanticReviewProposalV1 {
74
+ headline: SemanticReviewProposalFieldV1<string>;
75
+ summary: SemanticReviewProposalFieldV1<string>;
76
+ phase: SemanticReviewProposalFieldV1<SemanticPhase>;
77
+ expression_cue?: SemanticReviewProposalFieldV1<SemanticExpressionCue>;
78
+ purpose?: SemanticReviewProposalFieldV1<string>;
79
+ recent_result?: SemanticReviewProposalFieldV1<string>;
80
+ attention?: SemanticReviewProposalFieldV1<string>;
81
+ next_step?: SemanticReviewProposalFieldV1<string>;
82
+ tags?: SemanticReviewProposalFieldV1<SemanticTag[]>;
83
+ }
84
+
85
+ export interface SemanticReviewCandidateV1 {
86
+ schema_version: typeof SEMANTIC_REVIEW_SCHEMA_VERSION;
87
+ candidate_id: string;
88
+ subject_id: string;
89
+ captured_at: string;
90
+ source: {
91
+ evidence_digest: `sha256:${string}`;
92
+ observed_through_ts: string;
93
+ generated_at: string;
94
+ harness: SemanticHarness;
95
+ configured_model: SemanticConfiguredModel;
96
+ resolved_model_id: string;
97
+ model_attestation: "verified" | "requested-only";
98
+ };
99
+ evidence: SemanticReviewEvidenceSnapshotV1;
100
+ proposal: SemanticReviewProposalV1;
101
+ }
102
+
103
+ export interface SemanticReviewStudyCandidateV1 {
104
+ candidate: SemanticReviewCandidateV1;
105
+ previous?: SemanticReviewCandidateV1;
106
+ transition_required: boolean;
107
+ }
108
+
109
+ export interface SemanticReviewStudyV1 {
110
+ schema_version: typeof SEMANTIC_REVIEW_SCHEMA_VERSION;
111
+ study_id: string;
112
+ prepared_at: string;
113
+ total_candidate_count: number;
114
+ reviewed_candidate_count: number;
115
+ pending_candidate_count: number;
116
+ candidates: SemanticReviewStudyCandidateV1[];
117
+ }
118
+
119
+ export interface SemanticReviewResponseV1 {
120
+ candidate_id: string;
121
+ overall: SemanticReviewOverallVerdict;
122
+ phase: SemanticReviewFieldVerdict;
123
+ expected_phase?: SemanticPhase;
124
+ expression: SemanticReviewFieldVerdict;
125
+ expected_expression?: SemanticReviewExpression;
126
+ portrait_usefulness: SemanticReviewPortraitVerdict;
127
+ transition?: SemanticReviewTransitionVerdict;
128
+ confidence: SemanticReviewConfidence;
129
+ response_ms: number;
130
+ }
131
+
132
+ export interface SemanticReviewSubmissionV1 {
133
+ schema_version: typeof SEMANTIC_REVIEW_SCHEMA_VERSION;
134
+ study_id: string;
135
+ total_duration_ms: number;
136
+ responses: SemanticReviewResponseV1[];
137
+ }
138
+
139
+ export interface SemanticReviewReceiptRowV1 extends SemanticReviewResponseV1 {
140
+ subject_id: string;
141
+ candidate_generated_at: string;
142
+ source_harness: SemanticHarness;
143
+ configured_model: SemanticConfiguredModel;
144
+ resolved_model_id: string;
145
+ model_attestation: "verified" | "requested-only";
146
+ proposed_phase: SemanticPhase;
147
+ proposed_expression: SemanticReviewExpression;
148
+ }
149
+
150
+ export interface SemanticReviewReceiptV1 {
151
+ schema_version: typeof SEMANTIC_REVIEW_SCHEMA_VERSION;
152
+ receipt_id: string;
153
+ study_id: string;
154
+ completed_at: string;
155
+ total_duration_ms: number;
156
+ responses: SemanticReviewReceiptRowV1[];
157
+ summary: {
158
+ reviewed: number;
159
+ overall: Record<SemanticReviewOverallVerdict, number>;
160
+ phase: Record<SemanticReviewFieldVerdict, number>;
161
+ expression: Record<SemanticReviewFieldVerdict, number>;
162
+ portrait_usefulness: Record<SemanticReviewPortraitVerdict, number>;
163
+ transitions: Record<SemanticReviewTransitionVerdict, number>;
164
+ };
165
+ }
166
+
167
+ const MAX_JSON_BYTES = 512 * 1024;
168
+ const MAX_CANDIDATES = 100;
169
+ const MAX_CANDIDATE_AGE_MS = 7 * 24 * 60 * 60 * 1_000;
170
+ const MAX_RECEIPTS = 1_000;
171
+ const MAX_RECEIPT_AGE_MS = 365 * 24 * 60 * 60 * 1_000;
172
+ const DEFAULT_STUDY_SIZE = 12;
173
+ const MAX_STUDY_SIZE = 24;
174
+ const MAX_RESPONSE_MS = 10 * 60_000;
175
+ const MAX_TOTAL_DURATION_MS = 2 * 60 * 60_000;
176
+ const CANDIDATE_ID = /^candidate_[a-f0-9]{16}$/;
177
+ const SUBJECT_ID = /^subject_[a-f0-9]{16}$/;
178
+ const STUDY_ID = /^study_[a-f0-9]{16}$/;
179
+ const RECEIPT_ID = /^review_[a-f0-9]{16}$/;
180
+ const DIGEST = /^sha256:[a-f0-9]{64}$/;
181
+ const configuredModels = new Set<SemanticConfiguredModel>([
182
+ "haiku-4.5",
183
+ "gpt-5.6-luna",
184
+ "composer-2.5",
185
+ ]);
186
+ const phases = new Set<SemanticPhase>(SEMANTIC_PHASES);
187
+ const expressions = new Set<SemanticExpressionCue>(SEMANTIC_EXPRESSION_CUES);
188
+ const tags = new Set<SemanticTag>(SEMANTIC_TAGS);
189
+
190
+ export function semanticReviewPaths(coordRootRaw: string) {
191
+ const root = join(resolve(coordRootRaw), ".harnery", "semantic", "evaluations", "meaning");
192
+ return {
193
+ root,
194
+ candidates: join(root, "candidates"),
195
+ receipts: join(root, "receipts"),
196
+ };
197
+ }
198
+
199
+ export function captureSemanticReviewCandidate(
200
+ coordRootRaw: string,
201
+ evidence: SemanticEvidenceV1,
202
+ document: SemanticAcceptedReadModelV2,
203
+ ): SemanticReviewCandidateV1 {
204
+ if (
205
+ document.reader_outcome !== "accepted" ||
206
+ document.source.evidence_digest !== evidence.evidence_digest ||
207
+ document.generation_id !== evidence.generation_id ||
208
+ document.instance_id !== evidence.instance_id
209
+ ) {
210
+ throw new Error("semantic review candidate does not match accepted evidence");
211
+ }
212
+ const subjectId = opaqueId("subject", {
213
+ ledger_genesis_id: evidence.source.ledger_genesis_id,
214
+ instance_id: evidence.instance_id,
215
+ });
216
+ const candidateId = opaqueId("candidate", {
217
+ subject_id: subjectId,
218
+ evidence_digest: evidence.evidence_digest,
219
+ generated_at: document.generated_at,
220
+ reader: document.reader,
221
+ proposal: proposalSnapshot(document.meaning),
222
+ });
223
+ const candidate: SemanticReviewCandidateV1 = {
224
+ schema_version: SEMANTIC_REVIEW_SCHEMA_VERSION,
225
+ candidate_id: candidateId,
226
+ subject_id: subjectId,
227
+ captured_at: document.generated_at,
228
+ source: {
229
+ evidence_digest: evidence.evidence_digest as `sha256:${string}`,
230
+ observed_through_ts: evidence.source.observed_through_ts,
231
+ generated_at: document.generated_at,
232
+ harness: document.reader.harness,
233
+ configured_model: document.reader.configured_model,
234
+ resolved_model_id: document.reader.resolved_model_id,
235
+ model_attestation: document.reader.model_attestation,
236
+ },
237
+ evidence: evidenceSnapshot(evidence),
238
+ proposal: proposalSnapshot(document.meaning),
239
+ };
240
+ const target = join(semanticReviewPaths(coordRootRaw).candidates, `${candidateId}.json`);
241
+ if (!existsSync(target)) writePrivateJsonAtomic(target, candidate);
242
+ pruneSemanticReviewStorage(coordRootRaw);
243
+ return candidate;
244
+ }
245
+
246
+ export function backfillSemanticReviewCandidates(
247
+ coordRootRaw: string,
248
+ now = Date.now(),
249
+ ): SemanticReviewCandidateV1[] {
250
+ const evidenceByGeneration = new Map(
251
+ buildSemanticEvidenceV1(coordRootRaw, now).map((item) => [item.generation_id, item]),
252
+ );
253
+ const captured: SemanticReviewCandidateV1[] = [];
254
+ for (const document of listSemanticAgentDocuments(coordRootRaw)) {
255
+ if (document.reader_outcome !== "accepted") continue;
256
+ const evidence = evidenceByGeneration.get(document.generation_id);
257
+ if (!evidence || evidence.evidence_digest !== document.source.evidence_digest) continue;
258
+ captured.push(captureSemanticReviewCandidate(coordRootRaw, evidence, document));
259
+ }
260
+ return captured;
261
+ }
262
+
263
+ export function listSemanticReviewCandidates(coordRootRaw: string): SemanticReviewCandidateV1[] {
264
+ const dir = semanticReviewPaths(coordRootRaw).candidates;
265
+ if (!existsSync(dir)) return [];
266
+ return readdirSync(dir)
267
+ .filter((name) => /^candidate_[a-f0-9]{16}\.json$/.test(name))
268
+ .flatMap((name) => {
269
+ try {
270
+ const value = readBoundedJson<unknown>(join(dir, name), "semantic review candidate");
271
+ return isSemanticReviewCandidate(value) ? [value] : [];
272
+ } catch {
273
+ return [];
274
+ }
275
+ })
276
+ .sort(compareCandidates);
277
+ }
278
+
279
+ export function listSemanticReviewReceipts(coordRootRaw: string): SemanticReviewReceiptV1[] {
280
+ const dir = semanticReviewPaths(coordRootRaw).receipts;
281
+ if (!existsSync(dir)) return [];
282
+ return readdirSync(dir)
283
+ .filter((name) => /^review_[a-f0-9]{16}\.json$/.test(name))
284
+ .flatMap((name) => {
285
+ try {
286
+ const value = readBoundedJson<unknown>(join(dir, name), "semantic review receipt");
287
+ return isSemanticReviewReceipt(value) ? [value] : [];
288
+ } catch {
289
+ return [];
290
+ }
291
+ })
292
+ .sort((left, right) => right.completed_at.localeCompare(left.completed_at));
293
+ }
294
+
295
+ export function prepareSemanticReviewStudy(
296
+ coordRootRaw: string,
297
+ options: { limit?: number; now?: Date; backfill?: boolean } = {},
298
+ ): SemanticReviewStudyV1 {
299
+ const now = options.now ?? new Date();
300
+ if (options.backfill !== false) backfillSemanticReviewCandidates(coordRootRaw, now.getTime());
301
+ pruneSemanticReviewStorage(coordRootRaw, now.getTime());
302
+ const all = listSemanticReviewCandidates(coordRootRaw);
303
+ const reviewed = reviewedCandidateIds(listSemanticReviewReceipts(coordRootRaw));
304
+ const pending = all.filter((candidate) => !reviewed.has(candidate.candidate_id));
305
+ const limit = Math.min(MAX_STUDY_SIZE, Math.max(1, options.limit ?? DEFAULT_STUDY_SIZE));
306
+ const ranked = pending
307
+ .map((candidate) => {
308
+ const previous = previousCandidate(candidate, all);
309
+ return {
310
+ candidate,
311
+ ...(previous ? { previous } : {}),
312
+ transition_required: semanticTransitionChanged(candidate, previous),
313
+ } satisfies SemanticReviewStudyCandidateV1;
314
+ })
315
+ .sort((left, right) => {
316
+ if (left.transition_required !== right.transition_required) {
317
+ return left.transition_required ? -1 : 1;
318
+ }
319
+ const leftCue = left.candidate.proposal.expression_cue ? 1 : 0;
320
+ const rightCue = right.candidate.proposal.expression_cue ? 1 : 0;
321
+ return rightCue - leftCue || compareCandidates(left.candidate, right.candidate);
322
+ })
323
+ .slice(0, limit);
324
+ return {
325
+ schema_version: SEMANTIC_REVIEW_SCHEMA_VERSION,
326
+ study_id: studyId(ranked.map((item) => item.candidate.candidate_id)),
327
+ prepared_at: now.toISOString(),
328
+ total_candidate_count: all.length,
329
+ reviewed_candidate_count: reviewed.size,
330
+ pending_candidate_count: pending.length,
331
+ candidates: ranked,
332
+ };
333
+ }
334
+
335
+ export function storeSemanticReviewSubmission(
336
+ coordRootRaw: string,
337
+ value: unknown,
338
+ now = new Date(),
339
+ ): SemanticReviewReceiptV1 {
340
+ const all = listSemanticReviewCandidates(coordRootRaw);
341
+ const byId = new Map(all.map((candidate) => [candidate.candidate_id, candidate]));
342
+ const alreadyReviewed = reviewedCandidateIds(listSemanticReviewReceipts(coordRootRaw));
343
+ const submission = parseSubmission(value, byId, all, alreadyReviewed);
344
+ const completedAt = now.toISOString();
345
+ const rows = submission.responses.map((response): SemanticReviewReceiptRowV1 => {
346
+ const candidate = byId.get(response.candidate_id)!;
347
+ return {
348
+ ...response,
349
+ subject_id: candidate.subject_id,
350
+ candidate_generated_at: candidate.source.generated_at,
351
+ source_harness: candidate.source.harness,
352
+ configured_model: candidate.source.configured_model,
353
+ resolved_model_id: candidate.source.resolved_model_id,
354
+ model_attestation: candidate.source.model_attestation,
355
+ proposed_phase: candidate.proposal.phase.value,
356
+ proposed_expression:
357
+ candidate.proposal.expression_cue?.value ?? SEMANTIC_REVIEW_NO_EXPRESSION,
358
+ };
359
+ });
360
+ const receiptId = `review_${createHash("sha256")
361
+ .update(`${submission.study_id}:${completedAt}:${randomUUID()}`)
362
+ .digest("hex")
363
+ .slice(0, 16)}`;
364
+ const receipt: SemanticReviewReceiptV1 = {
365
+ schema_version: SEMANTIC_REVIEW_SCHEMA_VERSION,
366
+ receipt_id: receiptId,
367
+ study_id: submission.study_id,
368
+ completed_at: completedAt,
369
+ total_duration_ms: submission.total_duration_ms,
370
+ responses: rows,
371
+ summary: summarize(rows),
372
+ };
373
+ writePrivateJsonAtomic(
374
+ join(semanticReviewPaths(coordRootRaw).receipts, `${receiptId}.json`),
375
+ receipt,
376
+ );
377
+ pruneSemanticReviewStorage(coordRootRaw, now.getTime());
378
+ return receipt;
379
+ }
380
+
381
+ export function pruneSemanticReviewStorage(coordRootRaw: string, now = Date.now()): void {
382
+ const paths = semanticReviewPaths(coordRootRaw);
383
+ pruneFiles(paths.candidates, MAX_CANDIDATES, MAX_CANDIDATE_AGE_MS, now);
384
+ pruneFiles(paths.receipts, MAX_RECEIPTS, MAX_RECEIPT_AGE_MS, now);
385
+ }
386
+
387
+ function evidenceSnapshot(evidence: SemanticEvidenceV1): SemanticReviewEvidenceSnapshotV1 {
388
+ return {
389
+ observed_through_ts: evidence.source.observed_through_ts,
390
+ ...(evidence.task ? { task: evidence.task.value } : {}),
391
+ ...(evidence.lifecycle ? { lifecycle: evidence.lifecycle.state } : {}),
392
+ ...(evidence.intent ? { intent: evidence.intent.kind } : {}),
393
+ ...(evidence.operation
394
+ ? { operation: { category: evidence.operation.category, label: evidence.operation.label } }
395
+ : {}),
396
+ waits: evidence.waits.map((wait) => ({ kind: wait.kind, started_at: wait.started_at })),
397
+ recent: evidence.recent.map(observationSnapshot),
398
+ ...(evidence.attention ? { attention: observationSnapshot(evidence.attention) } : {}),
399
+ };
400
+ }
401
+
402
+ function observationSnapshot(
403
+ observation: SemanticEvidenceObservationV1,
404
+ ): SemanticReviewObservationV1 {
405
+ return {
406
+ kind: observation.kind,
407
+ observed_at: observation.observed_at,
408
+ ...(observation.label ? { label: observation.label } : {}),
409
+ ...(observation.outcome ? { outcome: observation.outcome } : {}),
410
+ ...(observation.error_class ? { error_class: observation.error_class } : {}),
411
+ };
412
+ }
413
+
414
+ function proposalSnapshot(meaning: SemanticMeaningV2): SemanticReviewProposalV1 {
415
+ return {
416
+ headline: reviewField(meaning.headline),
417
+ summary: reviewField(meaning.summary),
418
+ phase: reviewField(meaning.phase),
419
+ ...(meaning.expression_cue ? { expression_cue: reviewField(meaning.expression_cue) } : {}),
420
+ ...(meaning.purpose ? { purpose: reviewField(meaning.purpose) } : {}),
421
+ ...(meaning.recent_result ? { recent_result: reviewField(meaning.recent_result) } : {}),
422
+ ...(meaning.attention ? { attention: reviewField(meaning.attention) } : {}),
423
+ ...(meaning.next_step ? { next_step: reviewField(meaning.next_step) } : {}),
424
+ ...(meaning.tags ? { tags: reviewField(meaning.tags) } : {}),
425
+ };
426
+ }
427
+
428
+ function reviewField<T>(field: { value: T; confidence: "high" | "medium" | "low" }) {
429
+ return { value: field.value, confidence: field.confidence };
430
+ }
431
+
432
+ function previousCandidate(
433
+ candidate: SemanticReviewCandidateV1,
434
+ all: readonly SemanticReviewCandidateV1[],
435
+ ): SemanticReviewCandidateV1 | undefined {
436
+ return all
437
+ .filter(
438
+ (other) =>
439
+ other.subject_id === candidate.subject_id &&
440
+ other.candidate_id !== candidate.candidate_id &&
441
+ other.source.generated_at < candidate.source.generated_at,
442
+ )
443
+ .sort(compareCandidates)[0];
444
+ }
445
+
446
+ function semanticTransitionChanged(
447
+ candidate: SemanticReviewCandidateV1,
448
+ previous: SemanticReviewCandidateV1 | undefined,
449
+ ): boolean {
450
+ if (!previous) return false;
451
+ return (
452
+ candidate.proposal.phase.value !== previous.proposal.phase.value ||
453
+ (candidate.proposal.expression_cue?.value ?? SEMANTIC_REVIEW_NO_EXPRESSION) !==
454
+ (previous.proposal.expression_cue?.value ?? SEMANTIC_REVIEW_NO_EXPRESSION)
455
+ );
456
+ }
457
+
458
+ function parseSubmission(
459
+ value: unknown,
460
+ byId: ReadonlyMap<string, SemanticReviewCandidateV1>,
461
+ all: readonly SemanticReviewCandidateV1[],
462
+ alreadyReviewed: ReadonlySet<string>,
463
+ ): SemanticReviewSubmissionV1 {
464
+ if (!isRecord(value) || value.schema_version !== SEMANTIC_REVIEW_SCHEMA_VERSION) {
465
+ throw new Error("unsupported semantic review submission");
466
+ }
467
+ if (!isString(value.study_id) || !STUDY_ID.test(value.study_id)) {
468
+ throw new Error("invalid semantic review study");
469
+ }
470
+ if (!isBoundedInteger(value.total_duration_ms, 0, MAX_TOTAL_DURATION_MS)) {
471
+ throw new Error("invalid semantic review duration");
472
+ }
473
+ if (
474
+ !Array.isArray(value.responses) ||
475
+ value.responses.length < 1 ||
476
+ value.responses.length > MAX_STUDY_SIZE
477
+ ) {
478
+ throw new Error("invalid semantic review response count");
479
+ }
480
+ const seen = new Set<string>();
481
+ const responses = value.responses.map((raw): SemanticReviewResponseV1 => {
482
+ if (!isRecord(raw) || !isString(raw.candidate_id) || !CANDIDATE_ID.test(raw.candidate_id)) {
483
+ throw new Error("invalid semantic review response");
484
+ }
485
+ const candidate = byId.get(raw.candidate_id);
486
+ if (!candidate || seen.has(raw.candidate_id))
487
+ throw new Error("unexpected semantic review candidate");
488
+ if (alreadyReviewed.has(raw.candidate_id))
489
+ throw new Error("semantic review candidate already reviewed");
490
+ if (!includes(SEMANTIC_REVIEW_OVERALL_VERDICTS, raw.overall)) {
491
+ throw new Error("invalid semantic review overall verdict");
492
+ }
493
+ if (!includes(SEMANTIC_REVIEW_FIELD_VERDICTS, raw.phase)) {
494
+ throw new Error("invalid semantic review phase verdict");
495
+ }
496
+ const expectedPhase = raw.expected_phase;
497
+ if (raw.phase === "wrong") {
498
+ if (!isString(expectedPhase) || !phases.has(expectedPhase as SemanticPhase)) {
499
+ throw new Error("wrong phase verdict requires an expected phase");
500
+ }
501
+ } else if (expectedPhase !== undefined) {
502
+ throw new Error("expected phase is allowed only for a wrong verdict");
503
+ }
504
+ if (!includes(SEMANTIC_REVIEW_FIELD_VERDICTS, raw.expression)) {
505
+ throw new Error("invalid semantic review expression verdict");
506
+ }
507
+ const expectedExpression = raw.expected_expression;
508
+ if (raw.expression === "wrong") {
509
+ if (
510
+ !isString(expectedExpression) ||
511
+ (expectedExpression !== SEMANTIC_REVIEW_NO_EXPRESSION &&
512
+ !expressions.has(expectedExpression as SemanticExpressionCue))
513
+ ) {
514
+ throw new Error("wrong expression verdict requires an expected expression");
515
+ }
516
+ } else if (expectedExpression !== undefined) {
517
+ throw new Error("expected expression is allowed only for a wrong verdict");
518
+ }
519
+ if (!includes(SEMANTIC_REVIEW_PORTRAIT_VERDICTS, raw.portrait_usefulness)) {
520
+ throw new Error("invalid semantic review portrait verdict");
521
+ }
522
+ const transitionRequired = semanticTransitionChanged(
523
+ candidate,
524
+ previousCandidate(candidate, all),
525
+ );
526
+ if (transitionRequired) {
527
+ if (!includes(SEMANTIC_REVIEW_TRANSITION_VERDICTS, raw.transition)) {
528
+ throw new Error("changed semantic reading requires a transition verdict");
529
+ }
530
+ } else if (raw.transition !== undefined) {
531
+ throw new Error("transition verdict is not valid for this candidate");
532
+ }
533
+ if (!includes(SEMANTIC_REVIEW_CONFIDENCE, raw.confidence)) {
534
+ throw new Error("invalid semantic review confidence");
535
+ }
536
+ if (!isBoundedInteger(raw.response_ms, 0, MAX_RESPONSE_MS)) {
537
+ throw new Error("invalid semantic review response duration");
538
+ }
539
+ seen.add(raw.candidate_id);
540
+ return {
541
+ candidate_id: raw.candidate_id,
542
+ overall: raw.overall,
543
+ phase: raw.phase,
544
+ ...(raw.phase === "wrong" ? { expected_phase: expectedPhase as SemanticPhase } : {}),
545
+ expression: raw.expression,
546
+ ...(raw.expression === "wrong"
547
+ ? { expected_expression: expectedExpression as SemanticReviewExpression }
548
+ : {}),
549
+ portrait_usefulness: raw.portrait_usefulness,
550
+ ...(transitionRequired
551
+ ? { transition: raw.transition as SemanticReviewTransitionVerdict }
552
+ : {}),
553
+ confidence: raw.confidence,
554
+ response_ms: raw.response_ms,
555
+ };
556
+ });
557
+ if (value.study_id !== studyId(responses.map((response) => response.candidate_id))) {
558
+ throw new Error("semantic review study changed");
559
+ }
560
+ return {
561
+ schema_version: SEMANTIC_REVIEW_SCHEMA_VERSION,
562
+ study_id: value.study_id,
563
+ total_duration_ms: value.total_duration_ms,
564
+ responses,
565
+ };
566
+ }
567
+
568
+ function summarize(
569
+ rows: readonly SemanticReviewReceiptRowV1[],
570
+ ): SemanticReviewReceiptV1["summary"] {
571
+ const summary: SemanticReviewReceiptV1["summary"] = {
572
+ reviewed: rows.length,
573
+ overall: { correct: 0, close: 0, wrong: 0, unsure: 0 },
574
+ phase: { correct: 0, wrong: 0, unsure: 0 },
575
+ expression: { correct: 0, wrong: 0, unsure: 0 },
576
+ portrait_usefulness: { helpful: 0, neutral: 0, misleading: 0 },
577
+ transitions: { "real-change": 0, flicker: 0, unsure: 0 },
578
+ };
579
+ for (const row of rows) {
580
+ summary.overall[row.overall] += 1;
581
+ summary.phase[row.phase] += 1;
582
+ summary.expression[row.expression] += 1;
583
+ summary.portrait_usefulness[row.portrait_usefulness] += 1;
584
+ if (row.transition) summary.transitions[row.transition] += 1;
585
+ }
586
+ return summary;
587
+ }
588
+
589
+ function studyId(candidateIds: readonly string[]): string {
590
+ return opaqueId("study", { candidate_ids: candidateIds });
591
+ }
592
+
593
+ function opaqueId(prefix: "candidate" | "subject" | "study", value: unknown): string {
594
+ return `${prefix}_${createHash("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 16)}`;
595
+ }
596
+
597
+ function reviewedCandidateIds(receipts: readonly SemanticReviewReceiptV1[]): Set<string> {
598
+ return new Set(receipts.flatMap((receipt) => receipt.responses.map((row) => row.candidate_id)));
599
+ }
600
+
601
+ function compareCandidates(
602
+ left: SemanticReviewCandidateV1,
603
+ right: SemanticReviewCandidateV1,
604
+ ): number {
605
+ return (
606
+ right.source.generated_at.localeCompare(left.source.generated_at) ||
607
+ right.candidate_id.localeCompare(left.candidate_id)
608
+ );
609
+ }
610
+
611
+ function pruneFiles(dir: string, maxFiles: number, maxAgeMs: number, now: number): void {
612
+ if (!existsSync(dir)) return;
613
+ const entries = readdirSync(dir)
614
+ .filter((name) => name.endsWith(".json"))
615
+ .map((name) => ({ name, mtime: statSync(join(dir, name)).mtimeMs }))
616
+ .sort((left, right) => right.mtime - left.mtime);
617
+ for (const [index, entry] of entries.entries()) {
618
+ if (index >= maxFiles || now - entry.mtime > maxAgeMs)
619
+ rmSync(join(dir, entry.name), { force: true });
620
+ }
621
+ }
622
+
623
+ function readBoundedJson<T>(path: string, label: string): T {
624
+ const size = statSync(path).size;
625
+ if (size <= 0 || size > MAX_JSON_BYTES) throw new Error(`${label} has invalid size ${size}`);
626
+ return JSON.parse(readFileSync(path, "utf8")) as T;
627
+ }
628
+
629
+ function writePrivateJsonAtomic(path: string, value: unknown): void {
630
+ const body = `${JSON.stringify(value, null, 2)}\n`;
631
+ if (Buffer.byteLength(body) > MAX_JSON_BYTES)
632
+ throw new Error("semantic review file is too large");
633
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
634
+ chmodSync(dirname(path), 0o700);
635
+ const temporary = `${path}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
636
+ writeFileSync(temporary, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
637
+ renameSync(temporary, path);
638
+ chmodSync(path, 0o600);
639
+ }
640
+
641
+ function isSemanticReviewCandidate(value: unknown): value is SemanticReviewCandidateV1 {
642
+ if (!isRecord(value) || value.schema_version !== SEMANTIC_REVIEW_SCHEMA_VERSION) return false;
643
+ if (
644
+ !isString(value.candidate_id) ||
645
+ !CANDIDATE_ID.test(value.candidate_id) ||
646
+ !isString(value.subject_id) ||
647
+ !SUBJECT_ID.test(value.subject_id) ||
648
+ !isTimestamp(value.captured_at) ||
649
+ !isRecord(value.source) ||
650
+ !isString(value.source.evidence_digest) ||
651
+ !DIGEST.test(value.source.evidence_digest) ||
652
+ !isTimestamp(value.source.observed_through_ts) ||
653
+ !isTimestamp(value.source.generated_at) ||
654
+ !includes(SEMANTIC_HARNESSES, value.source.harness) ||
655
+ !configuredModels.has(value.source.configured_model as SemanticConfiguredModel) ||
656
+ !isBoundedString(value.source.resolved_model_id, 1, 160) ||
657
+ (value.source.model_attestation !== "verified" &&
658
+ value.source.model_attestation !== "requested-only") ||
659
+ !isReviewEvidence(value.evidence) ||
660
+ !isReviewProposal(value.proposal)
661
+ ) {
662
+ return false;
663
+ }
664
+ return true;
665
+ }
666
+
667
+ function isReviewEvidence(value: unknown): value is SemanticReviewEvidenceSnapshotV1 {
668
+ if (!isRecord(value) || !isTimestamp(value.observed_through_ts)) return false;
669
+ if (value.task !== undefined && !isBoundedString(value.task, 1, 200)) return false;
670
+ if (value.lifecycle !== undefined && !isBoundedString(value.lifecycle, 1, 128)) return false;
671
+ if (value.intent !== undefined && !isBoundedString(value.intent, 1, 128)) return false;
672
+ if (value.operation !== undefined) {
673
+ if (
674
+ !isRecord(value.operation) ||
675
+ !isBoundedString(value.operation.category, 1, 128) ||
676
+ !isBoundedString(value.operation.label, 1, 80)
677
+ )
678
+ return false;
679
+ }
680
+ if (!Array.isArray(value.waits) || value.waits.length > 8) return false;
681
+ if (
682
+ !value.waits.every(
683
+ (wait) =>
684
+ isRecord(wait) && isBoundedString(wait.kind, 1, 128) && isTimestamp(wait.started_at),
685
+ )
686
+ )
687
+ return false;
688
+ if (
689
+ !Array.isArray(value.recent) ||
690
+ value.recent.length > 8 ||
691
+ !value.recent.every(isReviewObservation)
692
+ )
693
+ return false;
694
+ return value.attention === undefined || isReviewObservation(value.attention);
695
+ }
696
+
697
+ function isReviewObservation(value: unknown): value is SemanticReviewObservationV1 {
698
+ return Boolean(
699
+ isRecord(value) &&
700
+ isBoundedString(value.kind, 1, 128) &&
701
+ isTimestamp(value.observed_at) &&
702
+ (value.label === undefined || isBoundedString(value.label, 1, 120)) &&
703
+ (value.outcome === undefined || isBoundedString(value.outcome, 1, 128)) &&
704
+ (value.error_class === undefined || isBoundedString(value.error_class, 1, 128)),
705
+ );
706
+ }
707
+
708
+ function isReviewProposal(value: unknown): value is SemanticReviewProposalV1 {
709
+ if (!isRecord(value)) return false;
710
+ if (!isProposalField(value.headline, (item) => isBoundedString(item, 1, 60))) return false;
711
+ if (!isProposalField(value.summary, (item) => isBoundedString(item, 1, 240))) return false;
712
+ if (
713
+ !isProposalField(
714
+ value.phase,
715
+ (item): item is SemanticPhase => isString(item) && phases.has(item as SemanticPhase),
716
+ )
717
+ )
718
+ return false;
719
+ if (
720
+ value.expression_cue !== undefined &&
721
+ !isProposalField(
722
+ value.expression_cue,
723
+ (item): item is SemanticExpressionCue =>
724
+ isString(item) && expressions.has(item as SemanticExpressionCue),
725
+ )
726
+ )
727
+ return false;
728
+ for (const key of ["purpose", "recent_result", "attention", "next_step"] as const) {
729
+ if (
730
+ value[key] !== undefined &&
731
+ !isProposalField(value[key], (item): item is string => isBoundedString(item, 1, 180))
732
+ )
733
+ return false;
734
+ }
735
+ if (
736
+ value.tags !== undefined &&
737
+ !isProposalField(
738
+ value.tags,
739
+ (item): item is SemanticTag[] =>
740
+ Array.isArray(item) &&
741
+ item.length <= 8 &&
742
+ item.every((tag) => isString(tag) && tags.has(tag as SemanticTag)),
743
+ )
744
+ )
745
+ return false;
746
+ return true;
747
+ }
748
+
749
+ function isProposalField<T>(
750
+ value: unknown,
751
+ valueCheck: (value: unknown) => value is T,
752
+ ): value is SemanticReviewProposalFieldV1<T> {
753
+ return Boolean(
754
+ isRecord(value) &&
755
+ valueCheck(value.value) &&
756
+ (value.confidence === "high" || value.confidence === "medium" || value.confidence === "low"),
757
+ );
758
+ }
759
+
760
+ function isSemanticReviewReceipt(value: unknown): value is SemanticReviewReceiptV1 {
761
+ if (
762
+ !isRecord(value) ||
763
+ value.schema_version !== SEMANTIC_REVIEW_SCHEMA_VERSION ||
764
+ !isString(value.receipt_id) ||
765
+ !RECEIPT_ID.test(value.receipt_id) ||
766
+ !isString(value.study_id) ||
767
+ !STUDY_ID.test(value.study_id) ||
768
+ !isTimestamp(value.completed_at) ||
769
+ !isBoundedInteger(value.total_duration_ms, 0, MAX_TOTAL_DURATION_MS) ||
770
+ !Array.isArray(value.responses) ||
771
+ value.responses.length < 1 ||
772
+ value.responses.length > MAX_STUDY_SIZE ||
773
+ !isRecord(value.summary)
774
+ )
775
+ return false;
776
+ return value.responses.every(
777
+ (row) => isRecord(row) && isString(row.candidate_id) && CANDIDATE_ID.test(row.candidate_id),
778
+ );
779
+ }
780
+
781
+ function includes<T extends readonly string[]>(values: T, value: unknown): value is T[number] {
782
+ return isString(value) && (values as readonly string[]).includes(value);
783
+ }
784
+
785
+ function isRecord(value: unknown): value is Record<string, unknown> {
786
+ return typeof value === "object" && value !== null && !Array.isArray(value);
787
+ }
788
+
789
+ function isString(value: unknown): value is string {
790
+ return typeof value === "string";
791
+ }
792
+
793
+ function isBoundedString(value: unknown, min: number, max: number): value is string {
794
+ return isString(value) && value.length >= min && value.length <= max;
795
+ }
796
+
797
+ function isTimestamp(value: unknown): value is string {
798
+ return isString(value) && Number.isFinite(Date.parse(value));
799
+ }
800
+
801
+ function isBoundedInteger(value: unknown, min: number, max: number): value is number {
802
+ return Number.isSafeInteger(value) && (value as number) >= min && (value as number) <= max;
803
+ }