blun-king-cli 9.1.587 → 9.1.588

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 (436) hide show
  1. package/CHANGELOG.md +11 -185
  2. package/LIESMICH.txt +51 -13
  3. package/README.md +44 -47
  4. package/agent-spine-plugin/.codex-plugin/plugin.json +16 -4
  5. package/agent-spine-plugin/CHANGELOG.md +37 -5
  6. package/agent-spine-plugin/README.md +3 -3
  7. package/agent-spine-plugin/blun.plugin.json +45 -10
  8. package/agent-spine-plugin/docs/artifact-evaluation.md +93 -0
  9. package/agent-spine-plugin/docs/host-integration.md +42 -27
  10. package/agent-spine-plugin/docs/preflight-recall.md +4 -2
  11. package/agent-spine-plugin/docs/session-timeline.md +97 -236
  12. package/agent-spine-plugin/docs/world-model.md +25 -0
  13. package/agent-spine-plugin/hooks/codex.json +1 -1
  14. package/agent-spine-plugin/hooks/hooks.json +1 -1
  15. package/agent-spine-plugin/package.json +1 -3
  16. package/agent-spine-plugin/scripts/check-hosts.js +3 -3
  17. package/agent-spine-plugin/scripts/release-check.js +10 -5
  18. package/agent-spine-plugin/scripts/run-checks.js +4 -1
  19. package/agent-spine-plugin/scripts/run-tests-hermetic.js +32 -6
  20. package/agent-spine-plugin/src/cli-learning.js +15 -0
  21. package/agent-spine-plugin/src/cli.js +2 -0
  22. package/agent-spine-plugin/src/hook.js +32 -32
  23. package/agent-spine-plugin/src/lib/action-lesson-recall.js +73 -8
  24. package/agent-spine-plugin/src/lib/briefing.js +146 -36
  25. package/agent-spine-plugin/src/lib/channel-continuity.js +19 -0
  26. package/agent-spine-plugin/src/lib/delivery-agent-usage.js +14 -7
  27. package/agent-spine-plugin/src/lib/gateway-group-response.js +128 -0
  28. package/agent-spine-plugin/src/lib/gateway-runs.js +24 -15
  29. package/agent-spine-plugin/src/lib/hook-briefing-use.js +13 -3
  30. package/agent-spine-plugin/src/lib/hook-context.js +16 -3
  31. package/agent-spine-plugin/src/lib/hook-output.js +129 -5
  32. package/agent-spine-plugin/src/lib/hook-timeline.js +5 -3
  33. package/agent-spine-plugin/src/lib/indexed-memory.js +2 -2
  34. package/agent-spine-plugin/src/lib/learning-artifact-evaluator.js +114 -0
  35. package/agent-spine-plugin/src/lib/learning-context.js +11 -4
  36. package/agent-spine-plugin/src/lib/learning-measurements.js +2 -2
  37. package/agent-spine-plugin/src/lib/mcp-runtime.js +89 -3
  38. package/agent-spine-plugin/src/lib/mcp-source-context.js +12 -2
  39. package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +91 -8
  40. package/agent-spine-plugin/src/lib/mcp-world-tools.js +2 -2
  41. package/agent-spine-plugin/src/lib/owned-file-lock.js +20 -1
  42. package/agent-spine-plugin/src/lib/persona-runtime.js +2 -2
  43. package/agent-spine-plugin/src/lib/preflight-delivery-id.js +27 -0
  44. package/agent-spine-plugin/src/lib/preflight.js +4 -4
  45. package/agent-spine-plugin/src/lib/session-timeline-codex.js +15 -0
  46. package/agent-spine-plugin/src/lib/session-timeline-contract.js +12 -4
  47. package/agent-spine-plugin/src/lib/session-timeline-event-extract.js +36 -7
  48. package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +13 -10
  49. package/agent-spine-plugin/src/lib/session-timeline-invocation.js +1 -1
  50. package/agent-spine-plugin/src/lib/session-timeline-king.js +14 -0
  51. package/agent-spine-plugin/src/lib/session-timeline-prior.js +18 -12
  52. package/agent-spine-plugin/src/lib/session-timeline-provider.js +5 -0
  53. package/agent-spine-plugin/src/lib/session-timeline-query.js +2 -0
  54. package/agent-spine-plugin/src/lib/session-timeline-results.js +35 -10
  55. package/agent-spine-plugin/src/lib/session-timeline-source-open.js +30 -0
  56. package/agent-spine-plugin/src/lib/session-timeline.js +122 -75
  57. package/agent-spine-plugin/src/lib/source-roots.js +3 -2
  58. package/agent-spine-plugin/src/lib/task-knowledge-context.js +22 -1
  59. package/agent-spine-plugin/src/lib/timeline-continuation-update.js +100 -0
  60. package/agent-spine-plugin/src/lib/timeline-tool-guard.js +30 -7
  61. package/agent-spine-plugin/src/lib/timeline-user-feedback.js +217 -0
  62. package/agent-spine-plugin/src/lib/timeline-world-capture.js +233 -0
  63. package/agent-spine-plugin/src/lib/world-knowledge.js +59 -2
  64. package/agent-spine-plugin/src/lib/world-model.js +64 -9
  65. package/agent-spine-plugin/src/worker.js +13 -1
  66. package/bin/blun.js +43 -28
  67. package/bin/core-bootstrap.js +5 -4
  68. package/bin/king.js +43 -28
  69. package/bin/launcher-mode.js +1 -10
  70. package/bin/launcher-runtime.js +128 -295
  71. package/bin/managed-node.js +0 -0
  72. package/bin/managed-plugin-selection.cjs +0 -1
  73. package/bin/native-module-repair.js +0 -0
  74. package/bin/node-runtime.js +0 -0
  75. package/bin/node-version.js +0 -0
  76. package/bin/plugin-bootstrap.js +56 -120
  77. package/bin/private-paths.js +11 -34
  78. package/bin/standard-tools-bootstrap.js +34 -114
  79. package/bin/turn-thinking-policy.cjs +3 -11
  80. package/bin/update-copy.js +200 -0
  81. package/bin/update-lease.js +0 -0
  82. package/bin/update-notice.js +136 -289
  83. package/bin/verify-agent-behavior.cjs +122 -0
  84. package/bin/verify-agent-components.cjs +104 -0
  85. package/bin/verify-bundled-agent-sources.cjs +57 -0
  86. package/blun.mjs +143076 -135288
  87. package/bundled-agent-sources.json +701 -0
  88. package/package.json +12 -15
  89. package/standard-skills/translate-native/README.md +1293 -0
  90. package/standard-skills/translate-native/SKILL.md +172 -22
  91. package/standard-skills/translate-native/VERSION +1 -1
  92. package/standard-skills/translate-native/agents/openai.yaml +18 -0
  93. package/standard-skills/translate-native/assets/icon.svg +8 -0
  94. package/standard-skills/translate-native/docs/BLUN_CODE_INTEGRATION.md +76 -0
  95. package/standard-skills/translate-native/docs/PREMORTEM.md +489 -0
  96. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +2035 -0
  97. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1302 -0
  98. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +136 -0
  99. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HEALTH_HTTP.md +130 -0
  100. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +175 -0
  101. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +86 -0
  102. package/standard-skills/translate-native/integrations/AGENT_RULES.md +32 -0
  103. package/standard-skills/translate-native/integrations/adapters/blun-code-language-guard.js +514 -0
  104. package/standard-skills/translate-native/integrations/adapters/node-language-guard.js +230 -0
  105. package/standard-skills/translate-native/integrations/audit_log.py +327 -0
  106. package/standard-skills/translate-native/integrations/claude_language_hook.js +1536 -0
  107. package/standard-skills/translate-native/integrations/commercial_localization_profile.py +42 -0
  108. package/standard-skills/translate-native/integrations/delivery-policy.example.json +28 -0
  109. package/standard-skills/translate-native/integrations/enforced_delivery.py +543 -0
  110. package/standard-skills/translate-native/integrations/guard_service.py +435 -0
  111. package/standard-skills/translate-native/integrations/language_gateway.py +67 -0
  112. package/standard-skills/translate-native/integrations/mcp_auth_headers.py +198 -0
  113. package/standard-skills/translate-native/integrations/mcp_http_gateway.py +429 -0
  114. package/standard-skills/translate-native/integrations/non_language_html_entities.js +1485 -0
  115. package/standard-skills/translate-native/integrations/pre_output_guard.py +65 -0
  116. package/standard-skills/translate-native/integrations/task_router.py +101 -0
  117. package/standard-skills/translate-native/integrations/website_localization.py +401 -0
  118. package/standard-skills/translate-native/integrations/website_localization_api.py +581 -0
  119. package/standard-skills/translate-native/integrations/website_localization_benchmark.py +1885 -0
  120. package/standard-skills/translate-native/integrations/website_localization_benchmark_campaign.py +1772 -0
  121. package/standard-skills/translate-native/integrations/website_localization_benchmark_candidate.py +506 -0
  122. package/standard-skills/translate-native/integrations/website_localization_benchmark_http.py +400 -0
  123. package/standard-skills/translate-native/integrations/website_localization_benchmark_review_store.py +781 -0
  124. package/standard-skills/translate-native/integrations/website_localization_benchmark_reviewer_http.py +500 -0
  125. package/standard-skills/translate-native/integrations/website_localization_benchmark_runtime.py +1107 -0
  126. package/standard-skills/translate-native/integrations/website_localization_benchmark_suite.py +463 -0
  127. package/standard-skills/translate-native/integrations/website_localization_cms.py +2835 -0
  128. package/standard-skills/translate-native/integrations/website_localization_cms_client.py +875 -0
  129. package/standard-skills/translate-native/integrations/website_localization_cms_dispatch.py +805 -0
  130. package/standard-skills/translate-native/integrations/website_localization_cms_http.py +588 -0
  131. package/standard-skills/translate-native/integrations/website_localization_cms_lifecycle_monitor.py +991 -0
  132. package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +1441 -0
  133. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +414 -0
  134. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +1073 -0
  135. package/standard-skills/translate-native/integrations/website_localization_cms_removal_dispatch.py +865 -0
  136. package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +583 -0
  137. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +964 -0
  138. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +665 -0
  139. package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +1153 -0
  140. package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +675 -0
  141. package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +1125 -0
  142. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification.py +674 -0
  143. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +444 -0
  144. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +1469 -0
  145. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +1142 -0
  146. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +634 -0
  147. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +804 -0
  148. package/standard-skills/translate-native/integrations/website_localization_deepl_baseline.py +922 -0
  149. package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +482 -0
  150. package/standard-skills/translate-native/integrations/website_localization_health.py +1541 -0
  151. package/standard-skills/translate-native/integrations/website_localization_health_http.py +372 -0
  152. package/standard-skills/translate-native/integrations/website_localization_http_provider.py +297 -0
  153. package/standard-skills/translate-native/integrations/website_localization_native_reference_http.py +479 -0
  154. package/standard-skills/translate-native/integrations/website_localization_native_reference_intake.py +363 -0
  155. package/standard-skills/translate-native/integrations/website_localization_native_reference_queue.py +1449 -0
  156. package/standard-skills/translate-native/integrations/website_localization_native_reference_store.py +420 -0
  157. package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +235 -0
  158. package/standard-skills/translate-native/integrations/website_localization_queue.py +671 -0
  159. package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +516 -0
  160. package/standard-skills/translate-native/integrations/website_localization_release.py +928 -0
  161. package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +1008 -0
  162. package/standard-skills/translate-native/integrations/website_localization_runner.py +276 -0
  163. package/standard-skills/translate-native/integrations/website_localization_runtime.py +862 -0
  164. package/standard-skills/translate-native/integrations/website_localization_service.py +350 -0
  165. package/standard-skills/translate-native/integrations/website_localization_supervisor.py +511 -0
  166. package/standard-skills/translate-native/integrations/website_localization_worker.py +663 -0
  167. package/standard-skills/translate-native/provenance.json +3 -4
  168. package/standard-skills/translate-native/references/commercial-localization.md +177 -0
  169. package/standard-skills/translate-native/scripts/blun_language_guard.py +7 -1
  170. package/standard-skills/translate-native/scripts/check_commercial_review.py +80 -0
  171. package/standard-skills/translate-native/scripts/commercial_localization_profile.py +333 -0
  172. package/standard-tools/language-guard/LICENSE +21 -0
  173. package/standard-tools/language-guard/VERSION +1 -0
  174. package/standard-tools/language-guard/blun_language_guard.py +7 -1
  175. package/standard-tools/language-guard/check_commercial_review.py +80 -0
  176. package/standard-tools/language-guard/commercial_localization_profile.py +333 -0
  177. package/standard-tools/language-guard/language_gateway.py +62 -0
  178. package/standard-tools/language-guard/pre_output_guard.py +64 -0
  179. package/standard-tools/language-guard/provenance.json +4 -11
  180. package/standard-tools/manifest.json +34 -11
  181. package/telegram-plugin/commands/access.md +2 -10
  182. package/telegram-plugin/dist/bridge.mjs +64041 -687
  183. package/telegram-plugin/dist/mcp-server.mjs +72810 -9027
  184. package/telegram-plugin/dist/noise.mjs +28 -63511
  185. package/agent-spine-plugin/CONTRIBUTING.md +0 -52
  186. package/agent-spine-plugin/SECURITY.md +0 -47
  187. package/agent-spine-plugin/docs/assignment-continuation.md +0 -48
  188. package/agent-spine-plugin/docs/releasing.md +0 -85
  189. package/agent-spine-plugin/docs/structured-completion.md +0 -67
  190. package/bin/abort-listener-policy.cjs +0 -43
  191. package/bin/active-steer-priority-policy.cjs +0 -24
  192. package/bin/agent-api-http-adapter.mjs +0 -446
  193. package/bin/agent-api-private-http-server.mjs +0 -288
  194. package/bin/agent-api-runtime.mjs +0 -252
  195. package/bin/agent-api-service-environment.mjs +0 -236
  196. package/bin/agent-api-service-host.mjs +0 -209
  197. package/bin/agent-api-service-process.mjs +0 -171
  198. package/bin/agent-api-session-registry.mjs +0 -428
  199. package/bin/agent-api-tool-broker.cjs +0 -248
  200. package/bin/agent-api-turn-controller.mjs +0 -461
  201. package/bin/agent-api-usage-journal.cjs +0 -259
  202. package/bin/agent-resume-snapshot.cjs +0 -241
  203. package/bin/agentspine-king-goal-inbox.mjs +0 -111
  204. package/bin/agentspine-king-goal-intake.mjs +0 -106
  205. package/bin/approval-rejection-stop.cjs +0 -15
  206. package/bin/assistant-message-offload-policy.cjs +0 -284
  207. package/bin/baseline-skill-performance-policy.cjs +0 -39
  208. package/bin/bash-search-scope-policy.cjs +0 -49
  209. package/bin/codebase-search-runtime.cjs +0 -23
  210. package/bin/cognitive-action-checkpoint.cjs +0 -1104
  211. package/bin/cognitive-attention-delivery.cjs +0 -76
  212. package/bin/cognitive-attention-policy.cjs +0 -143
  213. package/bin/cognitive-attention-runtime.cjs +0 -91
  214. package/bin/cognitive-context-projection.cjs +0 -73
  215. package/bin/cognitive-cross-portal-acceptance.cjs +0 -443
  216. package/bin/cognitive-effective-view.cjs +0 -77
  217. package/bin/cognitive-focus-projection.cjs +0 -206
  218. package/bin/cognitive-focus-scope.cjs +0 -37
  219. package/bin/cognitive-goal-autostart-policy.cjs +0 -72
  220. package/bin/cognitive-goal-time-trigger-controller.cjs +0 -146
  221. package/bin/cognitive-memory-adapter.cjs +0 -282
  222. package/bin/cognitive-memory-command.cjs +0 -293
  223. package/bin/cognitive-memory-provider.cjs +0 -92
  224. package/bin/cognitive-salience-policy.cjs +0 -159
  225. package/bin/cognitive-state-store.cjs +0 -508
  226. package/bin/cognitive-turn-lifecycle.cjs +0 -624
  227. package/bin/cognitive-work-focus.cjs +0 -180
  228. package/bin/compaction-history-archive.cjs +0 -166
  229. package/bin/compaction-history-startup.cjs +0 -50
  230. package/bin/compaction-model-policy.cjs +0 -31
  231. package/bin/compaction-stage-policy.cjs +0 -21
  232. package/bin/compaction-transaction-policy.cjs +0 -122
  233. package/bin/config-write-dedup-policy.cjs +0 -27
  234. package/bin/context-budget-ledger.cjs +0 -31
  235. package/bin/context-doctor-policy.cjs +0 -70
  236. package/bin/context-insight-policy.cjs +0 -36
  237. package/bin/context-performance-policy.cjs +0 -19
  238. package/bin/context-pressure-policy.cjs +0 -20
  239. package/bin/cron-run-output.cjs +0 -45
  240. package/bin/cron-run-store.cjs +0 -145
  241. package/bin/curiosity-scout-policy.cjs +0 -49
  242. package/bin/default-model-output-budget-policy.cjs +0 -28
  243. package/bin/durable-task-resume-policy.cjs +0 -130
  244. package/bin/durable-task-resume-runtime.cjs +0 -117
  245. package/bin/durable-task-resume-store.cjs +0 -88
  246. package/bin/editable-tool-approval-policy.cjs +0 -540
  247. package/bin/editable-tool-approval-runtime.cjs +0 -99
  248. package/bin/effective-system-prompt-cache-policy.cjs +0 -33
  249. package/bin/error-memory-performance-policy.cjs +0 -113
  250. package/bin/file-observation-policy.cjs +0 -133
  251. package/bin/foreground-output-capture-policy.cjs +0 -41
  252. package/bin/generated-source-health.cjs +0 -142
  253. package/bin/glob-pattern-policy.cjs +0 -13
  254. package/bin/goal-completion-evidence-policy.cjs +0 -120
  255. package/bin/grep-output-limit-policy.cjs +0 -39
  256. package/bin/historical-media-projection-policy.cjs +0 -48
  257. package/bin/history-offload-pressure-policy.cjs +0 -33
  258. package/bin/html-to-research-markdown.cjs +0 -147
  259. package/bin/identity-context-policy.cjs +0 -764
  260. package/bin/identity-journal-policy.cjs +0 -107
  261. package/bin/input-draft-persistence.cjs +0 -77
  262. package/bin/king-tui-function-contract.json +0 -33
  263. package/bin/launcher-restart-policy.cjs +0 -150
  264. package/bin/live-response-repetition-guard.cjs +0 -196
  265. package/bin/llm-config-log-dedup-policy.cjs +0 -76
  266. package/bin/loop-event-record-policy.cjs +0 -174
  267. package/bin/managed-context-startup-policy.cjs +0 -27
  268. package/bin/media-activity-layout-policy.cjs +0 -34
  269. package/bin/media-auto-retrieval-policy.cjs +0 -90
  270. package/bin/media-result-policy.cjs +0 -59
  271. package/bin/micro-compaction-policy.cjs +0 -145
  272. package/bin/mistake-relevance-policy.cjs +0 -319
  273. package/bin/model-retry-progress-policy.cjs +0 -46
  274. package/bin/native-large-file-io.cjs +0 -42
  275. package/bin/native-runtime-cache.cjs +0 -76
  276. package/bin/natural-presence-policy.cjs +0 -28
  277. package/bin/noninteractive-shell-env-policy.cjs +0 -19
  278. package/bin/observer-hooks.cjs +0 -14
  279. package/bin/outbound-claim-provenance.cjs +0 -150
  280. package/bin/oversized-context-offload-policy.cjs +0 -86
  281. package/bin/pending-media-policy.cjs +0 -182
  282. package/bin/pending-token-estimate-policy.cjs +0 -41
  283. package/bin/personal-memory-consent-policy.cjs +0 -72
  284. package/bin/personal-memory-performance-policy.cjs +0 -12
  285. package/bin/personality-choice-policy.cjs +0 -101
  286. package/bin/personality-memory-adapter.cjs +0 -379
  287. package/bin/personality-mode.cjs +0 -46
  288. package/bin/personality-setup-policy.cjs +0 -197
  289. package/bin/proactive-compaction-policy.cjs +0 -25
  290. package/bin/profile-identity-resolution.cjs +0 -136
  291. package/bin/profile-runtime.cjs +0 -318
  292. package/bin/profile-tool-exclusion-policy.cjs +0 -37
  293. package/bin/programmatic-context-isolation.cjs +0 -25
  294. package/bin/programmatic-tool-runtime.mjs +0 -627
  295. package/bin/provider-idle-timeout-policy.cjs +0 -14
  296. package/bin/provider-model-refresh-deadline.cjs +0 -53
  297. package/bin/provider-model-refresh-policy.cjs +0 -107
  298. package/bin/rate-limit-recovery-policy.cjs +0 -47
  299. package/bin/read-batch-policy.cjs +0 -32
  300. package/bin/read-continuation-policy.cjs +0 -59
  301. package/bin/recurring-cron-history-policy.cjs +0 -124
  302. package/bin/relationship-continuity-policy.cjs +0 -143
  303. package/bin/relationship-curiosity-policy.cjs +0 -107
  304. package/bin/relationship-learning-policy.cjs +0 -168
  305. package/bin/release-artifact-freeze-policy.cjs +0 -30
  306. package/bin/reload-plugin-bootstrap.cjs +0 -18
  307. package/bin/reload-queue-policy.cjs +0 -38
  308. package/bin/repeated-assistant-response-policy.cjs +0 -232
  309. package/bin/repeated-injection-projection.cjs +0 -107
  310. package/bin/repeated-user-message-projection.cjs +0 -8
  311. package/bin/research-page-result.cjs +0 -74
  312. package/bin/retry-checkpoint-policy.cjs +0 -13
  313. package/bin/runtime-exit-ledger.cjs +0 -144
  314. package/bin/scoped-cron-run-policy.cjs +0 -358
  315. package/bin/session-checkpoint-policy.cjs +0 -25
  316. package/bin/session-compaction-policy.cjs +0 -84
  317. package/bin/session-replay-policy.cjs +0 -20
  318. package/bin/session-replay-window-policy.cjs +0 -40
  319. package/bin/session-resume-checkpoint.cjs +0 -254
  320. package/bin/session-scrollback-archive.cjs +0 -229
  321. package/bin/skill-activation-performance-policy.cjs +0 -69
  322. package/bin/skill-listing-performance-policy.cjs +0 -92
  323. package/bin/soul-organization-policy.cjs +0 -78
  324. package/bin/soul-preservation-policy.cjs +0 -20
  325. package/bin/startup-preferences.cjs +0 -131
  326. package/bin/streaming-flush-performance-policy.cjs +0 -28
  327. package/bin/structured-agent-swarm-output.cjs +0 -325
  328. package/bin/structured-subagent-output.cjs +0 -252
  329. package/bin/subagent-context-fork-policy.cjs +0 -155
  330. package/bin/subagent-max-tokens-handoff-policy.cjs +0 -69
  331. package/bin/subagent-parent-responsiveness.cjs +0 -19
  332. package/bin/subagent-skill-policy.cjs +0 -206
  333. package/bin/subagent-timeout-policy.cjs +0 -182
  334. package/bin/subagent-tool-policy.cjs +0 -60
  335. package/bin/subagent-usage-rollup-policy.cjs +0 -29
  336. package/bin/system-prompt-context-policy.cjs +0 -124
  337. package/bin/system-prompt-token-cache-policy.cjs +0 -60
  338. package/bin/telegram-addressed-focus.cjs +0 -55
  339. package/bin/telegram-addressed-priority.cjs +0 -12
  340. package/bin/telegram-approval-relay.cjs +0 -290
  341. package/bin/telegram-bot-priority.cjs +0 -17
  342. package/bin/telegram-console-status-policy.cjs +0 -174
  343. package/bin/telegram-context-projection-policy.cjs +0 -141
  344. package/bin/telegram-delivery-lifecycle.cjs +0 -125
  345. package/bin/telegram-direct-focus-policy.cjs +0 -273
  346. package/bin/telegram-mcp-compatibility.cjs +0 -49
  347. package/bin/telegram-media-delivery-policy.cjs +0 -42
  348. package/bin/telegram-private-conversation-policy.cjs +0 -185
  349. package/bin/telegram-queue-handoff-policy.cjs +0 -73
  350. package/bin/telegram-remote-status-policy.cjs +0 -120
  351. package/bin/telegram-session-queue-runtime.mjs +0 -306
  352. package/bin/telegram-text-chunk-policy.cjs +0 -63
  353. package/bin/telegram-truncated-reply-policy.cjs +0 -37
  354. package/bin/telegram-urgent-policy.cjs +0 -45
  355. package/bin/telemetry-spool-policy.cjs +0 -57
  356. package/bin/thinking-activity-status-policy.cjs +0 -132
  357. package/bin/thinking-only-guard.cjs +0 -80
  358. package/bin/todo-list-turn-policy.cjs +0 -131
  359. package/bin/tool-call-loop-policy.cjs +0 -51
  360. package/bin/tool-file-persistence.cjs +0 -141
  361. package/bin/tool-result-offload-policy.cjs +0 -359
  362. package/bin/tool-result-offload-telemetry.cjs +0 -12
  363. package/bin/tool-schema-token-cache-policy.cjs +0 -41
  364. package/bin/tool-stream-preview-policy.cjs +0 -9
  365. package/bin/tui-functional-contract.cjs +0 -55
  366. package/bin/turn-tool-performance-policy.cjs +0 -486
  367. package/bin/usage-cache-efficiency-policy.cjs +0 -26
  368. package/bin/user-home-path-policy.cjs +0 -13
  369. package/bin/user-message-offload-policy.cjs +0 -103
  370. package/bin/user-prompt-hook-origin-policy.cjs +0 -34
  371. package/bin/user-tool-record-policy.cjs +0 -7
  372. package/bin/validated-learning-insight-policy.cjs +0 -58
  373. package/bin/validated-learning-outcome-trace.cjs +0 -107
  374. package/bin/validated-learning-performance-policy.cjs +0 -53
  375. package/bin/validated-learning-signal.cjs +0 -463
  376. package/bin/windows-bash-dialect-policy.cjs +0 -25
  377. package/bin/windows-node-crash-dump.cjs +0 -110
  378. package/bin/write-continuation-policy.cjs +0 -69
  379. package/codebase-index/README.md +0 -82
  380. package/codebase-index/codebase_index.py +0 -470
  381. package/standard-skills/agent-browser/SKILL.md +0 -19
  382. package/standard-skills/agent-browser/references/runtime.md +0 -8
  383. package/standard-skills/blun-session-inspector/SKILL.md +0 -41
  384. package/standard-skills/blun-session-inspector/scripts/inspect-session.cjs +0 -437
  385. package/standard-skills/design-taste-frontend/SKILL.md +0 -1206
  386. package/standard-skills/full-output-enforcement/SKILL.md +0 -49
  387. package/standard-skills/high-end-visual-design/SKILL.md +0 -98
  388. package/standard-skills/image-to-code/SKILL.md +0 -1228
  389. package/standard-skills/industrial-brutalist-ui/SKILL.md +0 -92
  390. package/standard-skills/minimalist-ui/SKILL.md +0 -85
  391. package/standard-skills/motion-design-taste/SKILL.md +0 -74
  392. package/standard-skills/playwright-testing/SKILL.md +0 -19
  393. package/standard-skills/playwright-testing/references/runtime.md +0 -7
  394. package/standard-skills/premortem/SKILL.md +0 -148
  395. package/standard-skills/redesign-existing-projects/SKILL.md +0 -178
  396. package/standard-skills/research-evidence/SKILL.md +0 -39
  397. package/standard-skills/research-evidence/references/evidence-format.md +0 -104
  398. package/standard-skills/research-evidence/scripts/evidence-collection.cjs +0 -260
  399. package/standard-skills/research-evidence/scripts/score-report.cjs +0 -130
  400. package/standard-skills/screenshot-lesen/SKILL.md +0 -52
  401. package/standard-skills/stitch-design-taste/DESIGN.md +0 -121
  402. package/standard-skills/stitch-design-taste/SKILL.md +0 -184
  403. package/standard-skills/telegram-channel/SKILL.md +0 -18
  404. package/standard-skills/telegram-channel/references/runtime.md +0 -7
  405. package/standard-skills/venture-flywheel/SKILL.md +0 -32
  406. package/standard-skills/venture-flywheel/identity/project-identity.cjs +0 -146
  407. package/standard-skills/venture-flywheel/policy/capability-engine.cjs +0 -114
  408. package/standard-skills/venture-flywheel/policy/repository-trust.cjs +0 -229
  409. package/standard-skills/venture-flywheel/references/BEISPIELE-phase0.md +0 -146
  410. package/standard-skills/venture-flywheel/references/CAPABILITY-MAP.md +0 -34
  411. package/standard-skills/venture-flywheel/references/SPEC-phase0-identity-trust.md +0 -77
  412. package/standard-skills/venture-flywheel/references/SPEC-phase0-state-events.md +0 -93
  413. package/standard-skills/venture-flywheel/schemas/capability-decision.schema.json +0 -13
  414. package/standard-skills/venture-flywheel/schemas/execution-event.schema.json +0 -44
  415. package/standard-skills/venture-flywheel/schemas/project-identity.schema.json +0 -32
  416. package/standard-skills/venture-flywheel/schemas/repository-trust.schema.json +0 -57
  417. package/standard-skills/venture-flywheel/schemas/run-transition.schema.json +0 -59
  418. package/standard-skills/venture-flywheel/state/execution-event.cjs +0 -191
  419. package/standard-skills/venture-flywheel/state/task-state-machine.cjs +0 -190
  420. package/standard-skills/web-lesen/SKILL.md +0 -73
  421. package/standard-skills/web-lesen/scripts/crawl_public.py +0 -379
  422. package/standard-skills/windows-mcp/SKILL.md +0 -19
  423. package/standard-skills/windows-mcp/references/runtime.md +0 -9
  424. package/telegram-plugin/DELIVERY.md +0 -36
  425. package/telegram-plugin/bin/telegram-approval-relay.cjs +0 -290
  426. package/telegram-plugin/bin/telegram-console-status-policy.cjs +0 -175
  427. package/telegram-plugin/bin/telegram-delivery-lifecycle.cjs +0 -125
  428. package/telegram-plugin/bin/telegram-direct-reply-policy.cjs +0 -48
  429. package/telegram-plugin/bin/telegram-launcher-status-queue.cjs +0 -122
  430. package/telegram-plugin/bin/telegram-private-conversation-policy.cjs +0 -186
  431. package/telegram-plugin/bin/telegram-remote-status-policy.cjs +0 -121
  432. package/telegram-plugin/bin/telegram-reply-parts.cjs +0 -149
  433. package/telegram-plugin/bin/telegram-text-chunk-policy.cjs +0 -63
  434. package/telegram-plugin/bin/telegram-typing-keepalive.cjs +0 -89
  435. package/telegram-plugin/compat/mcp-server-fa511cd1.mjs +0 -73825
  436. /package/{bin → scripts}/fix-node-pty-perms.js +0 -0
@@ -0,0 +1,128 @@
1
+ import { channelRuntimeFindings, claimChannelEvent, completeChannelEvent, loadChannelPolicy, loadChannelRuntime } from "./channel-runtime.js";
2
+ import { loadGraph } from "./graph.js";
3
+ import { emptyPolicy, emptyRuntime, exactId, sha256, timestamp } from "./gateway-common.js";
4
+ import { assertActivePersona, exactReplyBinding } from "./gateway-runtime-identity.js";
5
+ import { appendReceipt } from "./gateway-runtime-records.js";
6
+ import { normalizePolicy, normalizeRuntime, pathsFor, readJson, withLock } from "./gateway-state.js";
7
+ import { loadPersonaRuntime } from "./persona-runtime.js";
8
+
9
+ const SCHEMA = "agentspine.group-response/v1";
10
+ const CONTRIBUTIONS = new Set(["idea", "error", "improvement"]);
11
+
12
+ // This is a host result contract, not a permission or an objective evaluation.
13
+ export function groupResponseContract(event) {
14
+ if (!event?.groupId) return null;
15
+ return { schema: SCHEMA, defaultKind: "silence", kinds: ["silence", "answer", ...CONTRIBUTIONS],
16
+ eventId: event.eventId, sessionKey: event.sessionKey, groupId: event.groupId,
17
+ authority: "context-only", directAddressVerified: false,
18
+ instruction: "Without a direct request, stay silent unless contributing a relevant idea, concrete error, or improvement. Return groupResponse with this schema and kind; silence has no text. Contributions need a stable subjectId. Answer direct requests normally. Suggestions are not verified facts. Do not echo bot status messages." };
19
+ }
20
+
21
+ export function reviewGroupResponse({ result, text, event, item, runtime, current }) {
22
+ if (result?.groupResponse === undefined) return null; // Preserve the legacy reply contract.
23
+ const response = result.groupResponse;
24
+ if (!event?.groupId || event.privacy !== "group" || event.groupId !== item.groupId
25
+ || event.projectId !== item.projectId || event.agentId !== item.agentId) {
26
+ throw new Error("group response requires the exact group channel work item");
27
+ }
28
+ if (!response || Array.isArray(response) || response.schema !== SCHEMA
29
+ || !["silence", "answer", ...CONTRIBUTIONS].includes(response.kind)) {
30
+ throw new Error("unknown group response contract or kind");
31
+ }
32
+ const contribution = CONTRIBUTIONS.has(response.kind);
33
+ const keys = contribution ? ["schema", "kind", "subjectId"] : ["schema", "kind"];
34
+ if (Object.keys(response).length !== keys.length || Object.keys(response).some((key) => !keys.includes(key))) {
35
+ throw new Error("group response fields do not match its kind");
36
+ }
37
+ if (response.kind === "silence" && result.text !== undefined && result.text !== null && result.text !== "") {
38
+ throw new Error("silent group response must not contain text or a visible placeholder");
39
+ }
40
+ if (response.kind !== "silence" && !text) throw new Error("group contribution or answer requires text");
41
+ let contributionDigest = null;
42
+ let duplicate = false;
43
+ if (contribution) {
44
+ const subjectId = exactId(response.subjectId, "groupResponse.subjectId");
45
+ // The gateway derives the digest. Changing an event ID cannot repeat the same
46
+ // contribution; different private routes and sessions never share dedupe state.
47
+ contributionDigest = sha256(JSON.stringify([event.provider, event.tenantId, event.accountId,
48
+ event.bindingId, event.agentId, event.projectId, event.groupId, event.chatId, event.threadId,
49
+ event.sessionKey, subjectId, text]));
50
+ duplicate = runtime.receipts.some((receipt) => receipt.kind === "group-contribution-prepared"
51
+ && receipt.details.schema === SCHEMA && receipt.details.contributionDigest === contributionDigest);
52
+ }
53
+ const suppressed = response.kind === "silence" || duplicate;
54
+ if (suppressed || contribution) appendReceipt(runtime,
55
+ suppressed ? "group-response-suppressed" : "group-contribution-prepared", item.queueId, current,
56
+ { schema: SCHEMA, eventId: event.eventId, bindingId: event.bindingId,
57
+ kind: response.kind, reason: duplicate ? "duplicate" : response.kind,
58
+ contributionDigest, deliveryConfirmed: false, completionVerified: false });
59
+ return { schema: SCHEMA, kind: response.kind, suppressed, duplicate,
60
+ deliveryConfirmed: false, completionVerified: false };
61
+ }
62
+
63
+ // Recover the local acknowledgement after the gateway transaction commits.
64
+ // No adapter, outbox or delivery receipt is involved. A crash between claim and
65
+ // completion resumes the same lease, or reacquires it after its original expiry.
66
+ export async function settleSuppressedGroupEvents({ root = process.cwd(), now = new Date() } = {}) {
67
+ const paths = await pathsFor(root);
68
+ return withLock(paths, async () => {
69
+ const [policy, runtime, channelPolicy, channel, personas] = await Promise.all([
70
+ readJson(paths.gatewayPolicyPath, paths.catalog.root, normalizePolicy, emptyPolicy),
71
+ readJson(paths.gatewayRuntimePath, paths.catalog.root, normalizeRuntime, emptyRuntime),
72
+ loadChannelPolicy(paths.catalog.root, paths.catalog), loadChannelRuntime(paths.catalog.root, paths.catalog),
73
+ loadPersonaRuntime(paths.catalog.root, paths.catalog)
74
+ ]);
75
+ if (!policy.enabled || policy.killSwitch) return { settled: 0 };
76
+ const current = timestamp(now);
77
+ let settled = 0; let deferred = 0;
78
+ const pending = runtime.receipts.filter((receipt) => receipt.kind === "group-response-suppressed"
79
+ && channel.runtime.events.some((event) => event.eventId === receipt.details.eventId
80
+ && !["completed", "cancelled"].includes(event.status)));
81
+ if (pending.length) {
82
+ const { graph } = await loadGraph(paths.catalog.root, paths.catalog);
83
+ if (channelRuntimeFindings(channel.runtime, channelPolicy.policy, graph).length) {
84
+ throw new Error("suppressed channel event integrity mismatch");
85
+ }
86
+ }
87
+ for (const receipt of pending) {
88
+ if (settled >= 20) break;
89
+ if (receipt.details.schema !== SCHEMA) throw new Error("unknown group response receipt version");
90
+ const item = runtime.queue.find((entry) => entry.queueId === receipt.objectId);
91
+ const event = channel.runtime.events.find((entry) => entry.eventId === receipt.details.eventId);
92
+ if (!item || item.status !== "completed" || item.channelEventId !== event.eventId
93
+ || item.groupId !== event.groupId || item.agentId !== event.agentId || item.projectId !== event.projectId
94
+ || !event.groupId || receipt.details.bindingId !== event.bindingId
95
+ || runtime.outbox.some((entry) => entry.queueId === item.queueId)) {
96
+ throw new Error("suppressed group response lost its exact no-delivery binding");
97
+ }
98
+ try {
99
+ assertActivePersona(personas.policy, personas.runtime, item.agentId, item.projectId, item.groupId);
100
+ exactReplyBinding(channelPolicy.policy, event);
101
+ } catch {
102
+ // Revocation keeps this event untouched, without stopping other work.
103
+ deferred += 1;
104
+ continue;
105
+ }
106
+ const workerId = "group-silence:" + sha256(item.queueId).slice(0, 32);
107
+ try {
108
+ if (event.status === "leased" && new Date(event.lease.expiresAt) > new Date(current)) {
109
+ if (event.lease.workerId !== workerId) { deferred += 1; continue; }
110
+ } else {
111
+ const claim = await claimChannelEvent({ root: paths.catalog.root, agentId: event.agentId,
112
+ projectId: event.projectId, groupId: event.groupId, provider: event.provider,
113
+ eventId: event.eventId, workerId, now: current, catalog: paths.catalog });
114
+ if (!claim.event) { deferred += 1; continue; }
115
+ }
116
+ await completeChannelEvent({ root: paths.catalog.root, eventId: event.eventId,
117
+ workerId, status: "completed", now: current });
118
+ settled += 1;
119
+ } catch {
120
+ // Local acknowledgement is recoverable bookkeeping, not a new work gate.
121
+ // Keep the durable suppression and do not claim acknowledgement succeeded.
122
+ deferred += 1;
123
+ break; // Do not repeat the same unavailable channel service in this tick.
124
+ }
125
+ }
126
+ return { settled, deferred };
127
+ });
128
+ }
@@ -1,4 +1,5 @@
1
1
  import { loadChannelPolicy, loadChannelRuntime } from "./channel-runtime.js";
2
+ import { reviewGroupResponse } from "./gateway-group-response.js";
2
3
  import {
3
4
  assertGatewayCompletionMode, exactGatewayLeaseGeneration, failGatewayLane,
4
5
  markHostStarted, newGatewayLease, normalizeGatewayExecutionMode,
@@ -156,26 +157,35 @@ export async function completeGatewayRun({ root = process.cwd(), queueId, worker
156
157
  executionReview = { passed: false, outcome: null, reason: "Execution outcome history is full." };
157
158
  }
158
159
  const text = result?.text ? safeText(result.text, "result.text", 16000) : null;
160
+ if (result?.groupResponse !== undefined && !item.channelEventId) {
161
+ throw new Error("group response requires channel work");
162
+ }
163
+ let communication = null;
159
164
  let clarification = null; let exploration = null; let selfHelp = null; let selfHelpRequired = null;
160
165
  preserve(runtime, "queue", item, "run-completed", current);
161
166
  if (item.channelEventId) {
162
- if (!text) throw new Error("a channel obligation requires a non-empty response");
163
- const voice = evaluateVoiceOutput(text);
164
- if (!voice.ok) throw new Error("channel response contains a prohibited attachment or consciousness claim");
165
167
  const event = channelRuntime.runtime.events.find((entry) => entry.eventId === item.channelEventId);
166
168
  if (!event) throw new Error("channel event disappeared before delivery preparation");
167
169
  const binding = exactReplyBinding(channelPolicy.policy, event);
168
- const idempotencyKey = "delivery:" + sha256([event.eventId, binding.id, event.chatId, event.threadId || "", event.replyTo || ""].join("\0")).slice(0, 32);
169
- let outbox = runtime.outbox.find((entry) => entry.idempotencyKey === idempotencyKey);
170
- if (!outbox) {
171
- outbox = { outboxId: "gateway-outbox:" + sha256(idempotencyKey).slice(0, 32), queueId: item.queueId,
172
- idempotencyKey, bindingId: binding.id, eventId: event.eventId, provider: event.provider, tenantId: event.tenantId,
173
- accountId: event.accountId, chatId: event.chatId, threadId: event.threadId, replyTo: event.replyTo,
174
- text, status: "prepared", attempts: 0, nextAttemptAt: current, createdAt: current, updatedAt: current,
175
- deliveredAt: null, adapterReceipt: null, lastError: null, authority: "delivery-state-only" };
176
- runtime.outbox.push(outbox);
170
+ communication = reviewGroupResponse({ result, text, event, item, runtime, current });
171
+ if (communication?.suppressed) {
172
+ item.status = "completed"; item.completedAt = current;
173
+ } else {
174
+ if (!text) throw new Error("a channel obligation requires a non-empty response");
175
+ const voice = evaluateVoiceOutput(text);
176
+ if (!voice.ok) throw new Error("channel response contains a prohibited attachment or consciousness claim");
177
+ const idempotencyKey = "delivery:" + sha256([event.eventId, binding.id, event.chatId, event.threadId || "", event.replyTo || ""].join("\0")).slice(0, 32);
178
+ let outbox = runtime.outbox.find((entry) => entry.idempotencyKey === idempotencyKey);
179
+ if (!outbox) {
180
+ outbox = { outboxId: "gateway-outbox:" + sha256(idempotencyKey).slice(0, 32), queueId: item.queueId,
181
+ idempotencyKey, bindingId: binding.id, eventId: event.eventId, provider: event.provider, tenantId: event.tenantId,
182
+ accountId: event.accountId, chatId: event.chatId, threadId: event.threadId, replyTo: event.replyTo,
183
+ text, status: "prepared", attempts: 0, nextAttemptAt: current, createdAt: current, updatedAt: current,
184
+ deliveredAt: null, adapterReceipt: null, lastError: null, authority: "delivery-state-only" };
185
+ runtime.outbox.push(outbox);
186
+ }
187
+ item.status = "awaiting-delivery";
177
188
  }
178
- item.status = "awaiting-delivery";
179
189
  } else {
180
190
  item.status = result?.blocked || knowledgeGapRequest || premortemReview?.blocked || (executionReview && !executionReview.passed)
181
191
  ? "blocked" : "completed"; item.completedAt = current;
@@ -270,7 +280,7 @@ export async function completeGatewayRun({ root = process.cwd(), queueId, worker
270
280
  appendReceipt(runtime, "run-terminal", item.queueId, current, { status: item.status, goalStepId: item.goalStepId || null }); runtime.revision += 1;
271
281
  await writeGatewayStatePair(policy, runtime);
272
282
  return { item, outbox: runtime.outbox.find((entry) => entry.queueId === item.queueId) || null,
273
- clarification, exploration, selfHelp, selfHelpRequired, executionReview, premortemReview };
283
+ clarification, exploration, selfHelp, selfHelpRequired, executionReview, premortemReview, communication };
274
284
  });
275
285
  }
276
286
 
@@ -297,4 +307,3 @@ export async function failGatewayRun({ root = process.cwd(), queueId, workerId,
297
307
  return { item, receipt: failure.receipt, policyEnabled: policy.enabled && !policy.killSwitch };
298
308
  });
299
309
  }
300
-
@@ -29,7 +29,16 @@ function unverified(reason) {
29
29
  automaticRetry: false, completionVerified: false, authority: "context-only" };
30
30
  }
31
31
 
32
- export async function recordHookBriefingUse({ origin, root, now = new Date() }) {
32
+ function validHandoff(value) {
33
+ return value?.schema === "agentspine.host-context-handoff/v1"
34
+ && ["additionalContext", "message"].includes(value.field)
35
+ && ["claude", "codex", "generic", "king"].includes(value.host)
36
+ && Number.isSafeInteger(value.bytes) && value.bytes > 0
37
+ && /^[a-f0-9]{64}$/.test(value.digest || "");
38
+ }
39
+
40
+ export async function recordHookBriefingUse({ origin, root, handoff, now = new Date() }) {
41
+ if (!validHandoff(handoff)) return unverified("host-context-handoff-unavailable");
33
42
  const proof = verified.get(origin);
34
43
  if (!verified.delete(origin)) return unverified("host-briefing-origin-unavailable");
35
44
  try {
@@ -51,10 +60,11 @@ export async function recordHookBriefingUse({ origin, root, now = new Date() })
51
60
  return unverified("host-briefing-binding-mismatch");
52
61
  }
53
62
  const usage = await recordDeliveryBriefingUse({ root, requirementId,
54
- preserveConsumed: true, verifiedHostBriefing: true,
63
+ preserveConsumed: true, verifiedHostHandoff: true,
55
64
  input: { origin: "verified-host-preflight", receiptId: receipt.id,
56
65
  promptDigest: receipt.promptDigest, requirementId },
57
- result: { briefingDigest: receipt.briefingDigest, sourceSnapshotDigest: receipt.bodyDigest }, now });
66
+ result: { briefingDigest: receipt.briefingDigest, sourceSnapshotDigest: receipt.bodyDigest,
67
+ handoff: structuredClone(handoff) }, now });
58
68
  return { ...usage, verified: ["recorded", "duplicate"].includes(usage.status),
59
69
  automaticRetry: false, completionVerified: false };
60
70
  } catch { return unverified("host-briefing-service-unavailable"); }
@@ -58,6 +58,9 @@ export function hostFromInput(input) {
58
58
 
59
59
  export function gatewayEnvironmentContext(env = process.env) {
60
60
  if (env.AGENTSPINE_GATEWAY_CONTEXT !== "agentspine.gateway-start/v1") return null;
61
+ const portalRef = boundedId(env.AGENTSPINE_PORTAL_REF, "AGENTSPINE_PORTAL_REF");
62
+ const threadRef = boundedId(env.AGENTSPINE_THREAD_REF, "AGENTSPINE_THREAD_REF");
63
+ if (Boolean(portalRef) !== Boolean(threadRef)) throw new Error("gateway portal and thread references must be paired");
61
64
  return {
62
65
  host: boundedId(env.AGENTSPINE_HOST, "AGENTSPINE_HOST"),
63
66
  entityId: boundedId(env.AGENTSPINE_ENTITY_ID, "AGENTSPINE_ENTITY_ID"),
@@ -71,7 +74,8 @@ export function gatewayEnvironmentContext(env = process.env) {
71
74
  "AGENTSPINE_PLAN_DEFINITIONS_DIGEST"),
72
75
  gatewayAttempt: positiveInteger(env.AGENTSPINE_GATEWAY_ATTEMPT, "AGENTSPINE_GATEWAY_ATTEMPT"),
73
76
  eventId: boundedId(env.AGENTSPINE_CHANNEL_EVENT_ID, "AGENTSPINE_CHANNEL_EVENT_ID"),
74
- provider: boundedId(env.AGENTSPINE_CHANNEL_PROVIDER, "AGENTSPINE_CHANNEL_PROVIDER")
77
+ provider: boundedId(env.AGENTSPINE_CHANNEL_PROVIDER, "AGENTSPINE_CHANNEL_PROVIDER"),
78
+ portalRef, threadRef
75
79
  };
76
80
  }
77
81
 
@@ -116,6 +120,11 @@ export async function runtimeScope(input, root, userStateRoot = null, catalog) {
116
120
  const gateway = gatewayEnvironmentContext();
117
121
  const suppliedAttempt = positiveInteger(supplied.gateway_attempt ?? supplied.gatewayAttempt,
118
122
  "gatewayAttempt");
123
+ const suppliedPortalRef = supplied.portal_ref ?? supplied.portalRef;
124
+ const suppliedThreadRef = supplied.thread_ref ?? supplied.threadRef;
125
+ if (!gateway && [suppliedPortalRef, suppliedThreadRef].some((value) => value !== undefined && value !== null && value !== "")) {
126
+ throw new Error("portal timeline scope requires an authenticated gateway binding");
127
+ }
119
128
  return {
120
129
  entityId: boundedId(gatewayBound(gateway, "entityId",
121
130
  supplied.entity_id ?? supplied.entityId, "entityId")
@@ -139,6 +148,8 @@ export async function runtimeScope(input, root, userStateRoot = null, catalog) {
139
148
  supplied.plan_definitions_digest ?? supplied.planDefinitionsDigest,
140
149
  "planDefinitionsDigest"), "planDefinitionsDigest"),
141
150
  gatewayAttempt: gatewayBound(gateway, "gatewayAttempt", suppliedAttempt, "gatewayAttempt"),
151
+ portalRef: boundedId(gatewayBound(gateway, "portalRef", suppliedPortalRef, "portalRef"), "portalRef"),
152
+ threadRef: boundedId(gatewayBound(gateway, "threadRef", suppliedThreadRef, "threadRef"), "threadRef"),
142
153
  host: gateway
143
154
  ? gatewayBound(gateway, "host", input.host ?? input.provider, "host")
144
155
  : hostFromInput(input),
@@ -214,7 +225,8 @@ export function renderContext(event, catalog, briefing, signal = null, attention
214
225
  sourceResolution: sourceDiagnostics,
215
226
  lessonRecall: lessonRecall?.status === "recalled" ? {
216
227
  status: "recalled", schema: lessonRecall.schema, receiptDigest: lessonRecall.receiptDigest,
217
- items: lessonRecall.items, omitted: lessonRecall.omitted,
228
+ items: lessonRecall.items, learning: lessonRecall.learning || [],
229
+ learningDiagnostics: lessonRecall.learningDiagnostics || null, omitted: lessonRecall.omitted,
218
230
  instruction: lessonRecall.instruction, authority: "context-only"
219
231
  } : lessonRecall?.status === "group-suppressed" ? {
220
232
  status: "group-suppressed", items: [], authority: "context-only"
@@ -260,7 +272,8 @@ export function selfstarterInput(input) {
260
272
 
261
273
  function channelEventInput(input) {
262
274
  const gateway = gatewayEnvironmentContext();
263
- const value = input.agent_spine_channel_event ?? (gateway?.eventId && gateway?.provider
275
+ const value = input.agent_spine_channel_event ?? (input.hook_event_name === "SessionStart"
276
+ && gateway?.eventId && gateway?.provider
264
277
  ? { event_id: gateway.eventId, provider: gateway.provider } : null);
265
278
  if (value === undefined || value === null) return null;
266
279
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("agent_spine_channel_event must be one object");
@@ -1,6 +1,116 @@
1
1
  const BLUN_MESSAGE_MAX_BYTES = 1200;
2
2
  const BLUN_BOUND_MARKER = "\n[optional runtime detail omitted: 1200-byte bound]";
3
3
 
4
+ function byteSize(value) {
5
+ return Buffer.byteLength(JSON.stringify(value));
6
+ }
7
+
8
+ function addRecallField(packet, key, value, maximum = 1020) {
9
+ if (value === undefined || value === null) return;
10
+ packet[key] = value;
11
+ if (byteSize(packet) <= maximum) return true;
12
+ delete packet[key];
13
+ return false;
14
+ }
15
+
16
+ function sharedPrefix(values) {
17
+ let prefix = values[0] || "";
18
+ for (const value of values.slice(1)) {
19
+ while (prefix && !value.startsWith(prefix)) prefix = prefix.slice(0, -1);
20
+ }
21
+ return prefix.length >= 4 ? prefix : "";
22
+ }
23
+
24
+ function compactCandidateRows(packet, candidates) {
25
+ if (candidates.rows.length < 2) return;
26
+ if (!candidates.prefixes) {
27
+ const digest = candidates.fields.indexOf("digest");
28
+ if (digest >= 0 && candidates.rows.every((row) => row[digest] === candidates.rows[0][digest])) {
29
+ candidates.common = { ...(candidates.common || {}), digest: candidates.rows[0][digest] };
30
+ candidates.fields.splice(digest, 1);
31
+ for (const row of candidates.rows) row.splice(digest, 1);
32
+ }
33
+ candidates.prefixes = candidates.fields.map((field, index) => {
34
+ const values = candidates.rows.map((row) => row[index]);
35
+ const prefix = ["id", "message", "session"].includes(field) ? sharedPrefix(values)
36
+ : field === "at" && values.every((value) => /^\d{4}-\d{2}-\d{2}T\d{2}:/.test(value))
37
+ ? values[0].slice(0, 14) : "";
38
+ if (!prefix || !values.every((value) => value.startsWith(prefix))) return "";
39
+ for (const row of candidates.rows) row[index] = row[index].slice(prefix.length);
40
+ return prefix;
41
+ });
42
+ }
43
+ if (packet.task) {
44
+ delete packet.task.status;
45
+ if (packet.task.lastVerifiedStep) delete packet.task.lastVerifiedStep.result;
46
+ }
47
+ const review = packet.feedbackReview;
48
+ if (review?.modelClarification) packet.feedbackReview = {
49
+ status: review.status, completionVerified: false, target: review.targetAssertionId,
50
+ question: review.modelClarification.question, model: true
51
+ };
52
+ }
53
+
54
+ function compactFeedbackCandidates(packet) {
55
+ const candidates = packet.feedbackCandidates;
56
+ const proposal = packet.feedbackReview?.modelClarification;
57
+ if (proposal) for (const key of ["completionVerified", "provider", "replaces"]) delete proposal[key];
58
+ if (candidates && !Array.isArray(candidates)
59
+ && Array.isArray(candidates.fields) && Array.isArray(candidates.rows)) {
60
+ compactCandidateRows(packet, candidates);
61
+ return true;
62
+ }
63
+ if (!Array.isArray(candidates) || candidates.length < 2) return false;
64
+ const origins = ["provider", "session"];
65
+ const sharedKeys = origins.filter((key) =>
66
+ candidates.every((item) => item?.[key] === candidates[0]?.[key]));
67
+ const fields = ["id", "text", "digest", "message", "at",
68
+ ...origins.filter((key) => !sharedKeys.includes(key))];
69
+ packet.feedbackCandidates = {
70
+ fields,
71
+ ...(sharedKeys.length ? { common: Object.fromEntries(sharedKeys.map((key) =>
72
+ [key, candidates[0][key]])) } : {}),
73
+ rows: candidates.map((item) => fields.map((key) => item[key]))
74
+ };
75
+ compactCandidateRows(packet, packet.feedbackCandidates);
76
+ return true;
77
+ }
78
+
79
+ export function preAnswerRecallCapsule(detailed) {
80
+ if (detailed?.event !== "UserPromptSubmit" || !detailed.loaded) return null;
81
+ const briefing = detailed.briefing;
82
+ const preflight = detailed.preflight?.briefing;
83
+ if (!briefing || !preflight) return null;
84
+ if (briefing.scope?.groupId !== null && briefing.scope?.groupId !== undefined) return null;
85
+ const omitted = [];
86
+ const packet = briefing.preAnswerRecall ? { ...briefing.preAnswerRecall } : {
87
+ schema: "agentspine.pre-answer-recall/v1",
88
+ order: "review-before-claims-and-actions",
89
+ authority: "context-only"
90
+ };
91
+ const mustRemember = (preflight.mustRemember || []).map((item) => ({
92
+ id: item.id, claim: item.claim, checksum: item.checksum
93
+ }));
94
+ if (mustRemember.length && !addRecallField(packet, "mustRemember", mustRemember)) {
95
+ if (!compactFeedbackCandidates(packet)
96
+ || !addRecallField(packet, "mustRemember", mustRemember, BLUN_MESSAGE_MAX_BYTES)) {
97
+ omitted.push("mustRemember");
98
+ }
99
+ }
100
+ const retrieval = (preflight.retrieval || []).flatMap((provider) =>
101
+ (provider.items || []).map((item) => ({ providerId: provider.providerId,
102
+ id: item.id, revision: item.revision, claim: item.claim, source: item.source }))).slice(0, 3);
103
+ if (retrieval.length && !addRecallField(packet, "retrieval", retrieval)) {
104
+ if (!compactFeedbackCandidates(packet)
105
+ || !addRecallField(packet, "retrieval", retrieval, BLUN_MESSAGE_MAX_BYTES)) {
106
+ omitted.push("retrieval");
107
+ }
108
+ }
109
+ compactFeedbackCandidates(packet);
110
+ if (omitted.length && byteSize({ ...packet, omitted }) <= BLUN_MESSAGE_MAX_BYTES) packet.omitted = omitted;
111
+ return Object.keys(packet).length > 3 ? packet : null;
112
+ }
113
+
4
114
  function compactPremortemRegistration(premortem, includeRoot = true) {
5
115
  const root = premortem?.registration?.root;
6
116
  const requirementId = premortem?.requirementId || premortem?.registration?.requirementId;
@@ -37,6 +147,8 @@ export function blunRuntimeContext(context) {
37
147
  : detailed.instruction,
38
148
  authority: "context-only"
39
149
  };
150
+ const recall = preAnswerRecallCapsule(detailed);
151
+ if (recall) runtime.preAnswerRecall = recall;
40
152
  if (detailed.signal && (detailed.signal.captured || detailed.signal.accepted || detailed.signal.reason)) {
41
153
  runtime.signal = detailed.signal;
42
154
  }
@@ -56,7 +168,9 @@ export function blunRuntimeMessage(context) {
56
168
  const runtime = JSON.parse(blunRuntimeContext(context));
57
169
  const warning = runtime.sourceResolution?.incomplete ? ` Warning: ${runtime.sourceResolution.warning}` : "";
58
170
  const base = runtime.loaded
59
- ? `AgentSpine ready: ${runtime.indexedSources} sources indexed. Load detailed continuity only on demand through session_briefing.${warning}`
171
+ ? runtime.preAnswerRecall
172
+ ? `AgentSpine ready: ${runtime.indexedSources} sources indexed.${warning}`
173
+ : `AgentSpine ready: ${runtime.indexedSources} sources indexed. Load detailed continuity only on demand through session_briefing.${warning}`
60
174
  : `AgentSpine unavailable${runtime.sourceResolution?.reason ? `: ${runtime.sourceResolution.reason}` : ""}. ${runtime.instruction}`;
61
175
  const active = {};
62
176
  if (runtime.signal && (runtime.signal.captured || runtime.signal.accepted
@@ -72,16 +186,24 @@ export function blunRuntimeMessage(context) {
72
186
  const details = Object.keys(active).length === 0
73
187
  ? ""
74
188
  : `\nActive AgentSpine runtime data: ${JSON.stringify(active)}`;
189
+ const recall = runtime.preAnswerRecall
190
+ ? `\n${JSON.stringify(runtime.preAnswerRecall)}`
191
+ : "";
75
192
  const root = runtime.premortem?.registration?.root;
76
193
  const instruction = typeof root === "string"
77
194
  ? runtime.premortem?.instruction?.replace("registration.root", () => `root ${JSON.stringify(root)}`)
78
195
  : runtime.premortem?.instruction;
79
196
  const premortem = instruction ? `\n${instruction}` : "";
80
- const message = `${base}${details}${premortem}`;
197
+ const message = `${base}${recall}${details}${premortem}`;
81
198
  if (Buffer.byteLength(message) <= BLUN_MESSAGE_MAX_BYTES) return message;
82
- const compact = `${base}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem)}`;
199
+ const compact = `${base}${recall}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem)}`;
83
200
  if (Buffer.byteLength(compact) <= BLUN_MESSAGE_MAX_BYTES) return compact;
84
- return `${base}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem, false)}`;
201
+ if (!runtime.preAnswerRecall) {
202
+ return `${base}${BLUN_BOUND_MARKER}\n${compactPremortemRegistration(runtime.premortem, false)}`;
203
+ }
204
+ const recallOnly = `${base}${recall}${BLUN_BOUND_MARKER}`;
205
+ if (Buffer.byteLength(recallOnly) <= BLUN_MESSAGE_MAX_BYTES) return recallOnly;
206
+ return Buffer.byteLength(recall)<=BLUN_MESSAGE_MAX_BYTES+1?recall.slice(1):`${base}\nRecall unavailable.`;
85
207
  }
86
208
 
87
209
  export function hookOutput(event, context, env = process.env) {
@@ -130,7 +252,9 @@ export function lifecycleOutput(event, artifactGuard, premortem, deliveryVerific
130
252
  if (lessonRecall?.status === "recalled") {
131
253
  messages.push(JSON.stringify({
132
254
  schema: lessonRecall.schema, receiptDigest: lessonRecall.receiptDigest,
133
- instruction: lessonRecall.instruction, items: lessonRecall.items, omitted: lessonRecall.omitted,
255
+ instruction: lessonRecall.instruction, items: lessonRecall.items,
256
+ learning: lessonRecall.learning || [], learningDiagnostics: lessonRecall.learningDiagnostics || null,
257
+ omitted: lessonRecall.omitted,
134
258
  authority: "context-only"
135
259
  }));
136
260
  }
@@ -77,14 +77,16 @@ export async function finalizeUserPromptSessionTimeline({
77
77
  }) {
78
78
  const consumed = await consumeTimelineHostOrigin({ event: "UserPromptSubmit", input, scope, resolvedSources,
79
79
  preflight, prompt, environment: process.env, now });
80
- if (!consumed?.consumed) return { preflightConsumed: false, timeline: unavailable("preflight-receipt-unavailable") };
80
+ if (!consumed?.consumed) return { preflightConsumed: false, briefingOrigin: null,
81
+ timeline: unavailable("preflight-receipt-unavailable") };
81
82
  try {
82
- return { preflightConsumed: true, timeline: await captureSessionTimelineLifecycle({
83
+ return { preflightConsumed: true, briefingOrigin: consumed.briefingOrigin,
84
+ timeline: await captureSessionTimelineLifecycle({
83
85
  root, event: "UserPromptSubmit", input, scope, hostHome: resolvedSources.hostHome,
84
86
  hostOrigin: consumed.origin, clock: () => new Date(now)
85
87
  }) };
86
88
  } catch (error) {
87
- return { preflightConsumed: true, timeline: {
89
+ return { preflightConsumed: true, briefingOrigin: consumed.briefingOrigin, timeline: {
88
90
  schema: "agentspine.session-timeline/v1", status: "degraded", reason: error.message, authority: AUTHORITY
89
91
  } };
90
92
  }
@@ -247,7 +247,7 @@ export async function resolveIndexedMemory({ root, scope = {}, env = process.env
247
247
  diagnostics.cacheHits += Number(index.cacheHit);
248
248
  diagnostics.cacheMisses += Number(!index.cacheHit);
249
249
  const entries = parseMemoryIndex(index.buffer.toString("utf8"), index.path, canonicalRoot);
250
- if (entries.length > MAX_INDEXED_LINKS) throw new Error(`Claude MEMORY.md indexes more than ${MAX_INDEXED_LINKS} direct files`);
250
+ if (entries.length > MAX_INDEXED_LINKS) throw new Error(`MEMORY.md indexes more than ${MAX_INDEXED_LINKS} direct files`);
251
251
  diagnostics.indexed = entries.length;
252
252
  const sources = [{ path: index.path, relativePath: "MEMORY.md", snapshot: index, relevance: "index" }];
253
253
  const selected = [];
@@ -279,7 +279,7 @@ export async function resolveIndexedMemory({ root, scope = {}, env = process.env
279
279
  }
280
280
  checkDeadline();
281
281
  const finalIndex = await safeIndexedSnapshot(canonicalRoot, "MEMORY.md", index.record, hooks);
282
- if (finalIndex.rejected || finalIndex.metadata.sha256 !== index.metadata.sha256) throw new Error("Claude MEMORY.md changed during indexed resolution; retry the hook");
282
+ if (finalIndex.rejected || finalIndex.metadata.sha256 !== index.metadata.sha256) throw new Error("MEMORY.md changed during indexed resolution; retry the hook");
283
283
  await mutateCache(env, (value) => {
284
284
  const records = { "MEMORY.md": index.record };
285
285
  for (const source of sources.slice(1)) records[source.relativePath] = source.snapshot.record;
@@ -0,0 +1,114 @@
1
+ import { realpath } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { performance } from "node:perf_hooks";
4
+ import { randomUUID } from "node:crypto";
5
+ import { targetSnapshot } from "./delivery-target.js";
6
+ import { loadLearning } from "./learning-storage.js";
7
+ import { digest, exactScope, normalizeScope, activeEvaluationBinding } from "./learning-scope-targets.js";
8
+ import { recordLearningMeasurement } from "./learning-measurements.js";
9
+ import { CATALOG_SCHEMA, catalogScanPolicy } from "./catalog.js";
10
+
11
+ const SCHEMA = "agentspine.artifact-checks/v1";
12
+ const PROTOCOL = "agentspine.artifact-evaluator/v1:sha256-or-absent:two-pass:16-cases:2-mib-per-file";
13
+ const PROTOCOL_DIGEST = digest(PROTOCOL);
14
+ // One implementation is ONE principal, even under different aliases or paths.
15
+ const PRINCIPAL_DIGEST = digest({ implementation: PROTOCOL });
16
+ const METRIC = { name: "artifact-check-pass-rate", direction: "higher" };
17
+
18
+ export function artifactEvaluationPlan(spec) {
19
+ if (!spec || spec.schema !== SCHEMA || Object.keys(spec).some((key) => !["schema", "checks"].includes(key))
20
+ || !Array.isArray(spec.checks) || spec.checks.length < 1 || spec.checks.length > 16) {
21
+ throw new Error("artifact evaluation requires a known schema and 1 to 16 explicit checks");
22
+ }
23
+ const seen = new Set();
24
+ const checks = spec.checks.map((check) => {
25
+ if (!check || Object.keys(check).some((key) => !["path", "sha256", "blocking"].includes(key))
26
+ || typeof check.path !== "string" || check.path.length > 240
27
+ || !/^[A-Za-z0-9_-][A-Za-z0-9_./-]*$/.test(check.path)
28
+ || check.path.split("/").some((part) => !part || part === "." || part === "..")
29
+ || !(check.sha256 === null || /^[a-f0-9]{64}$/.test(check.sha256 || ""))
30
+ || typeof check.blocking !== "boolean") {
31
+ throw new Error("artifact checks require unique project-relative paths, SHA-256 or null, and explicit blocking flags");
32
+ }
33
+ const key = check.path.toLowerCase();
34
+ if (seen.has(key)) throw new Error("artifact check paths must be unique across platforms");
35
+ seen.add(key);
36
+ return { path: check.path, sha256: check.sha256, blocking: check.blocking };
37
+ }).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
38
+ const normalized = { schema: SCHEMA, checks };
39
+ return { spec: normalized, datasetDigest: digest(normalized), protocolDigest: PROTOCOL_DIGEST,
40
+ principalDigest: PRINCIPAL_DIGEST, metric: { ...METRIC }, minCases: checks.length,
41
+ authority: "context-only" };
42
+ }
43
+
44
+ // Local evaluator only. No shell, model scores, automatic registration, source
45
+ // discovery, outcome consumption, promotion or configuration changes.
46
+ export async function measureLearningArtifacts({ root = process.cwd(), spec, id, learningId, evaluationId,
47
+ phase, scope, evaluatorId, runId, confirmLocalMeasurement = false } = {}) {
48
+ if (confirmLocalMeasurement !== true) throw new Error("artifact measurement requires explicit local confirmation");
49
+ const started = performance.now();
50
+ const plan = artifactEvaluationPlan(spec);
51
+ const canonical = await realpath(root);
52
+ if (canonical !== resolve(root)) throw new Error("artifact project root must be canonical and non-symbolic");
53
+ // State-only catalog: measurement contracts need no document discovery.
54
+ // Never take this catalog from the caller; its root is resolved above.
55
+ const catalog = { schema: CATALOG_SCHEMA, root: canonical, generatedAt: new Date().toISOString(),
56
+ scanPolicy: catalogScanPolicy(canonical), preservation: "source-files-are-read-only",
57
+ documents: [], conflicts: [], summary: { total: 0, protected: 0, conflicts: 0, byLayer: {} } };
58
+ const { learning } = await loadLearning(canonical, catalog);
59
+ const evaluation = learning.evaluations.find((entry) => entry.id === evaluationId && entry.learningId === learningId);
60
+ const binding = normalizeScope(scope);
61
+ if (!evaluation || !exactScope(evaluation.scope, binding) || !activeEvaluationBinding(learning, evaluation)) {
62
+ throw new Error("artifact evaluation requires an active exact-scope local contract");
63
+ }
64
+ if (evaluation.benchmark.datasetDigest !== plan.datasetDigest
65
+ || evaluation.benchmark.protocolDigest !== plan.protocolDigest
66
+ || evaluation.benchmark.minCases !== plan.minCases
67
+ || evaluation.metric.name !== METRIC.name || evaluation.metric.direction !== METRIC.direction) {
68
+ throw new Error("artifact checks or measurement protocol differ from the frozen evaluation");
69
+ }
70
+ if (!evaluation.evaluatorRoots.some((entry) => entry.evaluatorId === evaluatorId
71
+ && entry.principalDigest === PRINCIPAL_DIGEST)) {
72
+ throw new Error("artifact evaluator must use its single locally registered implementation principal");
73
+ }
74
+ const trial = evaluation.initialTrials?.[phase]?.find((entry) => entry.evaluatorId === evaluatorId);
75
+ if (!trial || trial.runId !== runId) throw new Error("artifact measurement requires the precommitted initial trial");
76
+ if (learning.measurements.some((entry) => entry.id === id
77
+ || (entry.measurement.evaluatorId === evaluatorId && entry.measurement.runId === runId))) {
78
+ throw new Error("artifact trial was already measured; it cannot be rerun or replaced");
79
+ }
80
+ const snapshots = [];
81
+ for (const check of plan.spec.checks) {
82
+ const snapshot = await targetSnapshot(canonical, check.path);
83
+ if (snapshot.omitted) throw new Error("artifact exceeds the bounded measurement budget");
84
+ snapshots.push(snapshot);
85
+ }
86
+ // Recheck the complete bounded cohort, not just each file during its own read.
87
+ for (let index = 0; index < snapshots.length; index++) {
88
+ const current = await targetSnapshot(canonical, plan.spec.checks[index].path);
89
+ if (JSON.stringify(current) !== JSON.stringify(snapshots[index])) {
90
+ throw new Error("artifact cohort changed during measurement");
91
+ }
92
+ }
93
+ const checks = plan.spec.checks.map((check, index) => ({
94
+ path: check.path, expectedDigest: check.sha256,
95
+ observedDigest: snapshots[index].sha256, bytes: snapshots[index].bytes,
96
+ passed: snapshots[index].sha256 === check.sha256, blocking: check.blocking
97
+ }));
98
+ const metric = { ...METRIC, value: checks.filter((check) => check.passed).length / checks.length,
99
+ blockingDefects: checks.filter((check) => !check.passed && check.blocking).length };
100
+ const measuredAt = new Date().toISOString();
101
+ const report = { schema: "agentspine.artifact-measurement/v1", observationId: randomUUID(), evaluationId, learningId,
102
+ scope: binding, evaluatorId, runId, phase, datasetDigest: plan.datasetDigest,
103
+ protocolDigest: PROTOCOL_DIGEST, measuredAt, checks, metric, authority: "context-only" };
104
+ const sourceDigest = digest(report);
105
+ const recorded = await recordLearningMeasurement({ root: canonical, id, learningId, evaluationId, phase,
106
+ scope: binding, metric, measurement: { kind: "objective", evaluatorId, runId, sourceDigest },
107
+ coverage: { datasetDigest: plan.datasetDigest, caseCount: checks.length },
108
+ measuredAt, confirmLocalMeasurement: true, catalog });
109
+ return { ...recorded, report, sourceDigest,
110
+ diagnostics: { elapsedMs: performance.now() - started,
111
+ inspectedFiles: checks.length, inspectedBytes: snapshots.reduce((sum, item) => sum + item.bytes, 0) * 2,
112
+ broadScan: false, commandsExecuted: 0 },
113
+ completionVerified: false, automaticRetry: false, authority: "context-only" };
114
+ }