@cohortapp/agent-sdk 2.17.0 → 2.18.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/.claude/settings.json +18 -0
  2. package/.env.example +18 -5
  3. package/README.md +1 -0
  4. package/bin/maestro.mjs +62 -0
  5. package/docs/guides/billing-console-keys.md +60 -0
  6. package/docs/guides/front-door-session.md +54 -9
  7. package/docs/guides/mac-mini.md +20 -25
  8. package/docs/guides/setup-wizard.md +1 -1
  9. package/docs/runbooks/fleet-rollout.md +156 -0
  10. package/docs/runbooks/mac-mini-bootstrap.md +12 -14
  11. package/lib/action-executor.js +19 -3
  12. package/lib/budget-guard.mjs +279 -3
  13. package/lib/channels/base-adapter.mjs +3 -1
  14. package/lib/channels/contract.mjs +2 -1
  15. package/lib/channels/inbox-item.mjs +8 -0
  16. package/lib/claude-bin.mjs +5 -6
  17. package/lib/cli/doctor-checks.mjs +141 -10
  18. package/lib/cli/global-setup-extras.mjs +5 -1
  19. package/lib/cli/inbox.mjs +100 -15
  20. package/lib/cli/seat-auth.mjs +463 -0
  21. package/lib/cli/session.mjs +80 -12
  22. package/lib/collective/capture.mjs +8 -6
  23. package/lib/collective/global-config.mjs +63 -1
  24. package/lib/collective/presence.mjs +142 -5
  25. package/lib/comms/send-gate.mjs +559 -1
  26. package/lib/diagnostics/alerts.mjs +49 -0
  27. package/lib/diagnostics/cadence-output-freshness.mjs +288 -0
  28. package/lib/engine/agents/definitions.mjs +343 -0
  29. package/lib/engine/agents/persist.mjs +275 -0
  30. package/lib/engine/agents/runtime.mjs +748 -0
  31. package/lib/engine/agents/usage.mjs +95 -0
  32. package/lib/engine/auth-status.mjs +139 -0
  33. package/lib/engine/budget.mjs +194 -0
  34. package/lib/engine/cli.mjs +1204 -0
  35. package/lib/engine/commands/index.mjs +269 -0
  36. package/lib/engine/context/budget.mjs +219 -0
  37. package/lib/engine/context/cache.mjs +125 -0
  38. package/lib/engine/context/child-env.mjs +215 -0
  39. package/lib/engine/context/compaction.mjs +342 -0
  40. package/lib/engine/context/images.mjs +90 -0
  41. package/lib/engine/context/instructions.mjs +327 -0
  42. package/lib/engine/context/lazy-instructions.mjs +169 -0
  43. package/lib/engine/context/manager.mjs +182 -0
  44. package/lib/engine/context/real-path.mjs +91 -0
  45. package/lib/engine/context/secret-values.mjs +163 -0
  46. package/lib/engine/context/settings.mjs +274 -0
  47. package/lib/engine/context/stream-input.mjs +159 -0
  48. package/lib/engine/guard.mjs +152 -0
  49. package/lib/engine/hooks.mjs +713 -0
  50. package/lib/engine/loop.mjs +560 -0
  51. package/lib/engine/mcp/client.mjs +254 -0
  52. package/lib/engine/mcp/config.mjs +301 -0
  53. package/lib/engine/mcp/http.mjs +201 -0
  54. package/lib/engine/mcp/index.mjs +146 -0
  55. package/lib/engine/mcp/jsonrpc.mjs +147 -0
  56. package/lib/engine/mcp/naming.mjs +66 -0
  57. package/lib/engine/mcp/resources.mjs +89 -0
  58. package/lib/engine/mcp/results.mjs +133 -0
  59. package/lib/engine/mcp/stdio.mjs +137 -0
  60. package/lib/engine/mcp/supervisor.mjs +116 -0
  61. package/lib/engine/messages.mjs +104 -0
  62. package/lib/engine/output/json.mjs +164 -0
  63. package/lib/engine/output/stream-json.mjs +266 -0
  64. package/lib/engine/permissions.mjs +845 -0
  65. package/lib/engine/process-identity.mjs +164 -0
  66. package/lib/engine/process-tree.mjs +551 -0
  67. package/lib/engine/prompt.mjs +60 -0
  68. package/lib/engine/session/store.mjs +299 -0
  69. package/lib/engine/session-runtime/args.mjs +97 -0
  70. package/lib/engine/session-runtime/host.mjs +143 -0
  71. package/lib/engine/session-runtime/inbox.mjs +122 -0
  72. package/lib/engine/session-runtime/notifications.mjs +129 -0
  73. package/lib/engine/session-runtime/registry.mjs +328 -0
  74. package/lib/engine/session-runtime/runner.mjs +344 -0
  75. package/lib/engine/session-runtime/socket.mjs +212 -0
  76. package/lib/engine/session-runtime/wakeup.mjs +115 -0
  77. package/lib/engine/skills/index.mjs +321 -0
  78. package/lib/engine/tools/bash-background.mjs +533 -0
  79. package/lib/engine/tools/bash.mjs +216 -0
  80. package/lib/engine/tools/edit.mjs +97 -0
  81. package/lib/engine/tools/glob.mjs +81 -0
  82. package/lib/engine/tools/grep.mjs +224 -0
  83. package/lib/engine/tools/index.mjs +84 -0
  84. package/lib/engine/tools/list-agents.mjs +32 -0
  85. package/lib/engine/tools/ls.mjs +127 -0
  86. package/lib/engine/tools/monitor.mjs +82 -0
  87. package/lib/engine/tools/notebook-edit.mjs +218 -0
  88. package/lib/engine/tools/read.mjs +103 -0
  89. package/lib/engine/tools/schedule-wakeup.mjs +45 -0
  90. package/lib/engine/tools/schema.mjs +144 -0
  91. package/lib/engine/tools/send-message.mjs +77 -0
  92. package/lib/engine/tools/session.mjs +70 -0
  93. package/lib/engine/tools/todo.mjs +144 -0
  94. package/lib/engine/tools/toolsearch.mjs +217 -0
  95. package/lib/engine/tools/walk.mjs +193 -0
  96. package/lib/engine/tools/web-switch.mjs +31 -0
  97. package/lib/engine/tools/webfetch-html.mjs +387 -0
  98. package/lib/engine/tools/webfetch-net.mjs +340 -0
  99. package/lib/engine/tools/webfetch.mjs +198 -0
  100. package/lib/engine/tools/websearch.mjs +91 -0
  101. package/lib/engine/tools/workflow.mjs +95 -0
  102. package/lib/engine/tools/write.mjs +76 -0
  103. package/lib/engine/tui/line-editor.mjs +137 -0
  104. package/lib/engine/tui/render.mjs +86 -0
  105. package/lib/engine/tui/tui.mjs +274 -0
  106. package/lib/engine/wire/anthropic-messages.mjs +263 -0
  107. package/lib/engine/wire/effort.mjs +36 -0
  108. package/lib/engine/wire/errors.mjs +496 -0
  109. package/lib/engine/wire/http.mjs +441 -0
  110. package/lib/engine/wire/index.mjs +76 -0
  111. package/lib/engine/wire/openai-chat.mjs +332 -0
  112. package/lib/engine/wire/prompt-cache.mjs +79 -0
  113. package/lib/engine/wire/search.mjs +140 -0
  114. package/lib/engine/wire/sse.mjs +114 -0
  115. package/lib/engine/wire/stall.mjs +349 -0
  116. package/lib/engine/wire/token-provider.mjs +175 -0
  117. package/lib/engine/wire/usage.mjs +192 -0
  118. package/lib/engine/workflow/host.mjs +524 -0
  119. package/lib/engine/workflow/journal.mjs +188 -0
  120. package/lib/engine/workflow/json-schema.mjs +171 -0
  121. package/lib/engine/workflow/meta.mjs +329 -0
  122. package/lib/engine/workflow/notifications.mjs +52 -0
  123. package/lib/engine/workflow/runtime.mjs +447 -0
  124. package/lib/engine/workflow/sandbox.mjs +534 -0
  125. package/lib/engine/workflow/worker.mjs +141 -0
  126. package/lib/engine/workflow/worktree.mjs +74 -0
  127. package/lib/execution/disposition.mjs +1 -1
  128. package/lib/execution/intake.mjs +10 -0
  129. package/lib/execution/surface-policy.mjs +15 -0
  130. package/lib/learning/curator.mjs +8 -6
  131. package/lib/learning/reflect.mjs +8 -6
  132. package/lib/model-router/catalog/cohort.yaml +137 -0
  133. package/lib/model-router/catalog.mjs +118 -1
  134. package/lib/model-router/failover.mjs +67 -16
  135. package/lib/model-router/llm-task.mjs +39 -3
  136. package/lib/model-router/resolve.mjs +89 -3
  137. package/lib/model-router/spawn.mjs +46 -47
  138. package/lib/model-router/taxonomy.mjs +126 -4
  139. package/lib/org/cost-sync.mjs +141 -11
  140. package/lib/org/inbound/broadcast.mjs +289 -0
  141. package/lib/org/inbound/collective.mjs +375 -0
  142. package/lib/org/inbound/directedness.mjs +96 -8
  143. package/lib/org/inbound/facts.mjs +78 -2
  144. package/lib/org/inbound/project.mjs +22 -0
  145. package/lib/org/inbound/surfaces.mjs +14 -0
  146. package/lib/org/llm-token.mjs +879 -0
  147. package/lib/org/mesh.mjs +61 -0
  148. package/lib/org/messaging.mjs +3 -1
  149. package/lib/org/protocol.checksum +1 -1
  150. package/lib/org/protocol.mjs +15 -0
  151. package/lib/org/quota.mjs +520 -0
  152. package/lib/org/tool-surface.mjs +104 -16
  153. package/lib/org/ui-parity.mjs +16 -1
  154. package/lib/org/work-ledger.mjs +37 -6
  155. package/lib/rate-guard.mjs +114 -1
  156. package/lib/resource-governor.mjs +41 -6
  157. package/lib/runtime/adapter.mjs +823 -0
  158. package/lib/runtime/child-env.mjs +191 -0
  159. package/lib/runtime/legacy-shell-guard.mjs +97 -0
  160. package/lib/runtime/seat-engine.mjs +162 -0
  161. package/lib/session/ask-ledger.mjs +271 -0
  162. package/lib/session/current-work.mjs +676 -0
  163. package/lib/session/feed-core.mjs +40 -3
  164. package/lib/session/launch-args.mjs +56 -4
  165. package/lib/session/status-summary.mjs +26 -9
  166. package/lib/session/upgrade-notice.mjs +42 -0
  167. package/lib/setup/claude-probe.mjs +117 -13
  168. package/lib/setup/enrich.mjs +13 -10
  169. package/lib/setup/sections/model.mjs +39 -13
  170. package/lib/telemetry/collect.mjs +208 -9
  171. package/lib/upgrade/ignored-drift.mjs +105 -0
  172. package/lib/voice/post-call-brief.mjs +30 -17
  173. package/package.json +13 -3
  174. package/plugins/maestro-skills/skills/board-work.md +5 -0
  175. package/plugins/maestro-skills/skills/inbound-triage.md +56 -15
  176. package/plugins/maestro-skills/skills/main-session.md +18 -7
  177. package/scripts/ci/check-tarball-fidelity.mjs +126 -2
  178. package/scripts/ci/run-tests.mjs +47 -19
  179. package/scripts/cohort-llm/api-key-helper.mjs +92 -0
  180. package/scripts/collective/hook-runner.mjs +29 -2
  181. package/scripts/continuous-monitor.sh +13 -0
  182. package/scripts/cost/track-claude-usage.mjs +15 -0
  183. package/scripts/daemon/agent-daemon.mjs +408 -20
  184. package/scripts/daemon/assurance.mjs +48 -12
  185. package/scripts/daemon/cadence-consumer.mjs +218 -68
  186. package/scripts/daemon/cadence-handlers.mjs +73 -4
  187. package/scripts/daemon/classifier.mjs +75 -26
  188. package/scripts/daemon/context-compiler.mjs +51 -37
  189. package/scripts/daemon/deliver.mjs +30 -1
  190. package/scripts/daemon/dispatcher.mjs +595 -149
  191. package/scripts/daemon/health.mjs +14 -1
  192. package/scripts/daemon/maestro-daemon.mjs +11 -0
  193. package/scripts/daemon/prompt-builder.mjs +24 -0
  194. package/scripts/daemon/responder.mjs +246 -79
  195. package/scripts/daemon/sdk-version.mjs +98 -16
  196. package/scripts/eval/probe-gateway.mjs +635 -0
  197. package/scripts/eval/replay/extract.mjs +270 -0
  198. package/scripts/eval/replay/grade.mjs +260 -0
  199. package/scripts/eval/replay/lib/config.mjs +50 -0
  200. package/scripts/eval/replay/lib/effects.mjs +65 -0
  201. package/scripts/eval/replay/lib/fixture.mjs +188 -0
  202. package/scripts/eval/replay/lib/judge.mjs +72 -0
  203. package/scripts/eval/replay/lib/redact.mjs +136 -0
  204. package/scripts/eval/replay/lib/sandbox.mjs +170 -0
  205. package/scripts/eval/replay/lib/schema-check.mjs +63 -0
  206. package/scripts/eval/replay/lib/transcript.mjs +76 -0
  207. package/scripts/eval/replay/mcp-replay-stub.mjs +101 -0
  208. package/scripts/eval/replay/report.mjs +185 -0
  209. package/scripts/eval/replay/run.mjs +404 -0
  210. package/scripts/fleet/rollout.mjs +1094 -0
  211. package/scripts/hooks/pre-send-audit.sh +36 -245
  212. package/scripts/hooks/pre-write-yaml-validate.mjs +275 -0
  213. package/scripts/hooks/validate-state-yaml.sh +190 -0
  214. package/scripts/huddle/huddle-llm.mjs +361 -0
  215. package/scripts/huddle/huddle-server.mjs +46 -121
  216. package/scripts/local-triggers/autoupdate.sh +448 -78
  217. package/scripts/local-triggers/run-trigger.sh +13 -0
  218. package/scripts/maintenance/pin-integrity.mjs +364 -0
  219. package/scripts/poll-slack-events.sh +41 -9
  220. package/scripts/poller/slack-socket-mode.mjs +28 -3
  221. package/scripts/session/supervisor.mjs +80 -13
  222. package/scripts/spawn-session.sh +13 -0
  223. package/bin/maestro.test.mjs +0 -1574
  224. package/lib/action-executor.test.mjs +0 -871
  225. package/lib/archetype.test.mjs +0 -132
  226. package/lib/assurance/plan-note.test.mjs +0 -234
  227. package/lib/assurance/room-budget.test.mjs +0 -486
  228. package/lib/assurance/tier.test.mjs +0 -174
  229. package/lib/autonomy.test.mjs +0 -66
  230. package/lib/backlog.test.mjs +0 -302
  231. package/lib/backup/policy.test.mjs +0 -305
  232. package/lib/budget-escalate.test.mjs +0 -232
  233. package/lib/budget-guard.envelope.test.mjs +0 -476
  234. package/lib/budget-guard.test.mjs +0 -427
  235. package/lib/cadence-bus-requeue.test.mjs +0 -83
  236. package/lib/cadence-bus-schedule.test.mjs +0 -194
  237. package/lib/cadence-bus.test.mjs +0 -720
  238. package/lib/cadences.test.mjs +0 -230
  239. package/lib/capability/inventory.test.mjs +0 -232
  240. package/lib/capability.test.mjs +0 -78
  241. package/lib/channels/base-adapter.test.mjs +0 -590
  242. package/lib/channels/channels.test.mjs +0 -371
  243. package/lib/channels/contract.test.mjs +0 -162
  244. package/lib/channels/inbox-item.test.mjs +0 -368
  245. package/lib/channels/orgmail/adapter.test.mjs +0 -448
  246. package/lib/channels/pairing.test.mjs +0 -270
  247. package/lib/channels/repeat-suppressor.test.mjs +0 -134
  248. package/lib/channels/slack-adapter.test.mjs +0 -212
  249. package/lib/channels/telegram-adapter.test.mjs +0 -306
  250. package/lib/channels/voice/adapter.test.mjs +0 -278
  251. package/lib/channels/whatsapp/adapter-baileys.test.mjs +0 -359
  252. package/lib/channels/whatsapp/baileys-typing.test.mjs +0 -154
  253. package/lib/charter.test.mjs +0 -89
  254. package/lib/claude-bin.test.mjs +0 -131
  255. package/lib/cli/board.test.mjs +0 -227
  256. package/lib/cli/design.test.mjs +0 -270
  257. package/lib/cli/doctor-checks.test.mjs +0 -336
  258. package/lib/cli/global-setup-extras.test.mjs +0 -462
  259. package/lib/cli/inbox.test.mjs +0 -230
  260. package/lib/cli/session-ack.test.mjs +0 -63
  261. package/lib/cli/session.test.mjs +0 -613
  262. package/lib/collective/capture.test.mjs +0 -121
  263. package/lib/collective/cards.test.mjs +0 -114
  264. package/lib/collective/config.test.mjs +0 -123
  265. package/lib/collective/global-config.test.mjs +0 -220
  266. package/lib/collective/global-skills.test.mjs +0 -126
  267. package/lib/collective/presence.test.mjs +0 -95
  268. package/lib/collective/recall.test.mjs +0 -116
  269. package/lib/collective/vendor-skills.test.mjs +0 -306
  270. package/lib/comms/send-gate.test.mjs +0 -770
  271. package/lib/comms.test.mjs +0 -41
  272. package/lib/context/budget.test.mjs +0 -252
  273. package/lib/context/history-scope.test.mjs +0 -79
  274. package/lib/cost/ledger-row.test.mjs +0 -183
  275. package/lib/design/design-md.test.mjs +0 -318
  276. package/lib/design/fixtures/DESIGN.golden.md +0 -238
  277. package/lib/design/fixtures/PRODUCT.golden.md +0 -67
  278. package/lib/design/fixtures/foundation.json +0 -133
  279. package/lib/design/refresh-gate.test.mjs +0 -144
  280. package/lib/design/write.test.mjs +0 -241
  281. package/lib/diagnostics/alerts.test.mjs +0 -318
  282. package/lib/diagnostics/backup-freshness.test.mjs +0 -185
  283. package/lib/diagnostics/counters.test.mjs +0 -206
  284. package/lib/diagnostics/events.test.mjs +0 -290
  285. package/lib/diagnostics/otel.test.mjs +0 -196
  286. package/lib/diagnostics/trace.test.mjs +0 -251
  287. package/lib/env-compat.test.mjs +0 -104
  288. package/lib/execution/disposition.test.mjs +0 -553
  289. package/lib/execution/drive.test.mjs +0 -270
  290. package/lib/execution/effects.test.mjs +0 -344
  291. package/lib/execution/intake.test.mjs +0 -389
  292. package/lib/execution/journal.test.mjs +0 -261
  293. package/lib/execution/match.test.mjs +0 -235
  294. package/lib/execution/pipeline.test.mjs +0 -392
  295. package/lib/execution/route.test.mjs +0 -186
  296. package/lib/execution/surface-policy.test.mjs +0 -162
  297. package/lib/fs-atomic.test.mjs +0 -72
  298. package/lib/fs-ownership.test.mjs +0 -158
  299. package/lib/goals/admission.test.mjs +0 -164
  300. package/lib/goals/classify.test.mjs +0 -167
  301. package/lib/goals/collaborate.test.mjs +0 -336
  302. package/lib/goals/gaps.test.mjs +0 -284
  303. package/lib/goals/loop.test.mjs +0 -845
  304. package/lib/hooks/bus.test.mjs +0 -387
  305. package/lib/identity/persona.test.mjs +0 -142
  306. package/lib/kpi-sensors.test.mjs +0 -278
  307. package/lib/kpi.test.mjs +0 -244
  308. package/lib/learning/config.test.mjs +0 -75
  309. package/lib/learning/counters.test.mjs +0 -69
  310. package/lib/learning/curator-consolidate.test.mjs +0 -238
  311. package/lib/learning/curator.test.mjs +0 -106
  312. package/lib/learning/reflect.test.mjs +0 -0
  313. package/lib/learning/session-index.test.mjs +0 -125
  314. package/lib/learning/skill-writer.test.mjs +0 -210
  315. package/lib/mandate/audit.test.mjs +0 -195
  316. package/lib/mandate/contract.test.mjs +0 -185
  317. package/lib/mandate/derive.test.mjs +0 -274
  318. package/lib/mandate/model.test.mjs +0 -164
  319. package/lib/mandate/refresh.test.mjs +0 -389
  320. package/lib/mcp/server.test.mjs +0 -426
  321. package/lib/model-router/auth-profiles.test.mjs +0 -580
  322. package/lib/model-router/catalog.test.mjs +0 -385
  323. package/lib/model-router/economics.test.mjs +0 -438
  324. package/lib/model-router/failover.test.mjs +0 -439
  325. package/lib/model-router/health.test.mjs +0 -338
  326. package/lib/model-router/integration-coverage.test.mjs +0 -831
  327. package/lib/model-router/integration.test.mjs +0 -564
  328. package/lib/model-router/ledger.test.mjs +0 -415
  329. package/lib/model-router/llm-task.test.mjs +0 -392
  330. package/lib/model-router/org-credentials.test.mjs +0 -265
  331. package/lib/model-router/pricing-refresh.test.mjs +0 -286
  332. package/lib/model-router/reconcile.test.mjs +0 -316
  333. package/lib/model-router/repair.test.mjs +0 -180
  334. package/lib/model-router/spawn.test.mjs +0 -446
  335. package/lib/model-router/taxonomy.test.mjs +0 -410
  336. package/lib/model-router.test.mjs +0 -1207
  337. package/lib/org/activity.test.mjs +0 -134
  338. package/lib/org/approvals.test.mjs +0 -216
  339. package/lib/org/awareness.test.mjs +0 -159
  340. package/lib/org/board-mine-cache.test.mjs +0 -53
  341. package/lib/org/board.test.mjs +0 -187
  342. package/lib/org/bootstrap-context.test.mjs +0 -153
  343. package/lib/org/client.test.mjs +0 -1206
  344. package/lib/org/cohort-client.test.mjs +0 -126
  345. package/lib/org/cost-sync.test.mjs +0 -153
  346. package/lib/org/doctor.test.mjs +0 -346
  347. package/lib/org/engagement-ledger.test.mjs +0 -112
  348. package/lib/org/engagement.test.mjs +0 -739
  349. package/lib/org/handoff.test.mjs +0 -269
  350. package/lib/org/inbound/directedness.test.mjs +0 -668
  351. package/lib/org/inbound/facts.test.mjs +0 -471
  352. package/lib/org/inbound/hydrate.test.mjs +0 -908
  353. package/lib/org/inbound/index.test.mjs +0 -429
  354. package/lib/org/inbound/project.test.mjs +0 -287
  355. package/lib/org/integration-tools.test.mjs +0 -160
  356. package/lib/org/keys.test.mjs +0 -92
  357. package/lib/org/knowledge.test.mjs +0 -326
  358. package/lib/org/leases.test.mjs +0 -235
  359. package/lib/org/mesh-directives.test.mjs +0 -110
  360. package/lib/org/mesh-integration.test.mjs +0 -127
  361. package/lib/org/mesh.test.mjs +0 -400
  362. package/lib/org/messaging.test.mjs +0 -471
  363. package/lib/org/param-contract.test.mjs +0 -477
  364. package/lib/org/policy.test.mjs +0 -237
  365. package/lib/org/protocol.checksum.test.mjs +0 -90
  366. package/lib/org/protocol.test.mjs +0 -323
  367. package/lib/org/push.test.mjs +0 -792
  368. package/lib/org/registry.test.mjs +0 -100
  369. package/lib/org/resource-tools.test.mjs +0 -361
  370. package/lib/org/tool-access.test.mjs +0 -144
  371. package/lib/org/tool-surface-integration.test.mjs +0 -120
  372. package/lib/org/tool-surface.test.mjs +0 -1268
  373. package/lib/org/typing.test.mjs +0 -291
  374. package/lib/org/ui-parity.test.mjs +0 -560
  375. package/lib/org/verify.test.mjs +0 -194
  376. package/lib/org/work-ledger.test.mjs +0 -273
  377. package/lib/plan/adoption-e2e.test.mjs +0 -366
  378. package/lib/plan/budget-enforcement.test.mjs +0 -400
  379. package/lib/plan/compile.test.mjs +0 -382
  380. package/lib/plan/emit.test.mjs +0 -269
  381. package/lib/plan/explain.test.mjs +0 -188
  382. package/lib/prompts/parallelism.test.mjs +0 -177
  383. package/lib/rag/rag.test.mjs +0 -505
  384. package/lib/rate-guard.test.mjs +0 -272
  385. package/lib/reactive-gate.test.mjs +0 -57
  386. package/lib/render.test.mjs +0 -68
  387. package/lib/resource-governor.test.mjs +0 -488
  388. package/lib/scheduling/dynamic-jobs.test.mjs +0 -344
  389. package/lib/scheduling/jitter.test.mjs +0 -140
  390. package/lib/secrets/broker.test.mjs +0 -280
  391. package/lib/secrets/providers.test.mjs +0 -274
  392. package/lib/security/audit-engine.test.mjs +0 -424
  393. package/lib/security/coerce-args.test.mjs +0 -281
  394. package/lib/security/dangerous-tools.test.mjs +0 -68
  395. package/lib/security/external-content.test.mjs +0 -84
  396. package/lib/security/redact.test.mjs +0 -441
  397. package/lib/security/secret-equal.test.mjs +0 -55
  398. package/lib/session/config.test.mjs +0 -92
  399. package/lib/session/feed-core.test.mjs +0 -198
  400. package/lib/session/first-run.test.mjs +0 -121
  401. package/lib/session/frontdoor.test.mjs +0 -205
  402. package/lib/session/handoffs.test.mjs +0 -183
  403. package/lib/session/identity.test.mjs +0 -180
  404. package/lib/session/inbox-claims.test.mjs +0 -286
  405. package/lib/session/launch-args.test.mjs +0 -157
  406. package/lib/session/liveness.test.mjs +0 -100
  407. package/lib/session/status-summary.test.mjs +0 -118
  408. package/lib/session-permissions.test.mjs +0 -120
  409. package/lib/setup/claude-probe.test.mjs +0 -187
  410. package/lib/setup/completeness.test.mjs +0 -110
  411. package/lib/setup/context-pack.test.mjs +0 -89
  412. package/lib/setup/enrich.test.mjs +0 -115
  413. package/lib/setup/enroll-from-cohort.test.mjs +0 -300
  414. package/lib/setup/integration.test.mjs +0 -162
  415. package/lib/setup/io.test.mjs +0 -77
  416. package/lib/setup/runner.test.mjs +0 -132
  417. package/lib/setup/sections/identity.test.mjs +0 -234
  418. package/lib/setup/sections/inventory.test.mjs +0 -198
  419. package/lib/setup/sections/learning.test.mjs +0 -81
  420. package/lib/setup/sections/mandate.test.mjs +0 -388
  421. package/lib/setup/sections/messaging.test.mjs +0 -127
  422. package/lib/setup/sections/model.test.mjs +0 -240
  423. package/lib/setup/sections/org.test.mjs +0 -346
  424. package/lib/setup/sections/orgmail.test.mjs +0 -118
  425. package/lib/setup/sections/recovery.test.mjs +0 -98
  426. package/lib/setup/sections/subagents.test.mjs +0 -429
  427. package/lib/setup/sections/verify.test.mjs +0 -175
  428. package/lib/setup/sot.test.mjs +0 -81
  429. package/lib/setup/state.test.mjs +0 -115
  430. package/lib/singleton.test.mjs +0 -151
  431. package/lib/subagents/cli.test.mjs +0 -389
  432. package/lib/subagents/client.test.mjs +0 -309
  433. package/lib/subagents/gap.test.mjs +0 -234
  434. package/lib/subagents/lock.test.mjs +0 -248
  435. package/lib/subagents/manifest.test.mjs +0 -175
  436. package/lib/subagents/refs.test.mjs +0 -204
  437. package/lib/subagents/resolve.test.mjs +0 -422
  438. package/lib/subagents/schema.test.mjs +0 -328
  439. package/lib/telemetry/alerts.test.mjs +0 -109
  440. package/lib/telemetry/collect.test.mjs +0 -1274
  441. package/lib/tool-definitions-integration.test.mjs +0 -83
  442. package/lib/tool-definitions.test.mjs +0 -437
  443. package/lib/upgrade/global-refresh.test.mjs +0 -65
  444. package/lib/upgrade/launchd-reconcile.test.mjs +0 -272
  445. package/lib/upgrade/post-steps.test.mjs +0 -200
  446. package/lib/upgrade/verify.test.mjs +0 -164
  447. package/lib/util/fetch-timeout.test.mjs +0 -202
  448. package/lib/util/reconnect.test.mjs +0 -369
  449. package/lib/util/unhandled.test.mjs +0 -216
  450. package/lib/voice/outbound.test.mjs +0 -69
  451. package/lib/voice/session-rotation.test.mjs +0 -114
  452. package/lib/voice/stt.test.mjs +0 -226
  453. package/lib/voice/voice.test.mjs +0 -990
  454. package/scripts/cadence/enqueue-cadence-tick.test.mjs +0 -187
  455. package/scripts/ci/check-docs-accuracy.test.mjs +0 -409
  456. package/scripts/ci/check-durable-write-seam.test.mjs +0 -90
  457. package/scripts/ci/check-no-build-artifacts.test.mjs +0 -71
  458. package/scripts/ci/check-no-residual-identity.test.mjs +0 -202
  459. package/scripts/ci/check-skill-packs.test.mjs +0 -495
  460. package/scripts/ci/check-subagent-frontmatter.test.mjs +0 -124
  461. package/scripts/ci/check.test.mjs +0 -194
  462. package/scripts/ci/conformance-org-api.test.mjs +0 -425
  463. package/scripts/cloud-relay/voice/relay-identity.test.mjs +0 -96
  464. package/scripts/collective/hook-runner.test.mjs +0 -173
  465. package/scripts/cost/fleet-digest.test.mjs +0 -207
  466. package/scripts/cost/track-claude-usage-pricing.test.mjs +0 -183
  467. package/scripts/cost/track-claude-usage.test.mjs +0 -148
  468. package/scripts/daemon/agent-daemon-board-mine.test.mjs +0 -96
  469. package/scripts/daemon/agent-daemon-design.test.mjs +0 -238
  470. package/scripts/daemon/agent-daemon-frontdoor.test.mjs +0 -60
  471. package/scripts/daemon/agent-daemon.test.mjs +0 -995
  472. package/scripts/daemon/assurance-e2e.test.mjs +0 -613
  473. package/scripts/daemon/assurance.test.mjs +0 -1791
  474. package/scripts/daemon/board-mirror.test.mjs +0 -165
  475. package/scripts/daemon/cadence-consumer-frontdoor.test.mjs +0 -393
  476. package/scripts/daemon/cadence-consumer-governance.test.mjs +0 -276
  477. package/scripts/daemon/cadence-consumer.test.mjs +0 -776
  478. package/scripts/daemon/cadence-handlers.test.mjs +0 -837
  479. package/scripts/daemon/classifier-identity.test.mjs +0 -137
  480. package/scripts/daemon/classifier.test.mjs +0 -266
  481. package/scripts/daemon/classify-kind.test.mjs +0 -40
  482. package/scripts/daemon/context-compiler.test.mjs +0 -406
  483. package/scripts/daemon/deliver.test.mjs +0 -564
  484. package/scripts/daemon/dispatcher-cooldown.test.mjs +0 -122
  485. package/scripts/daemon/dispatcher-governance.test.mjs +0 -1013
  486. package/scripts/daemon/dispatcher-resume.test.mjs +0 -166
  487. package/scripts/daemon/dispatcher-session-continuity.test.mjs +0 -365
  488. package/scripts/daemon/execution-ladder.test.mjs +0 -470
  489. package/scripts/daemon/goal-steward-cadence.test.mjs +0 -312
  490. package/scripts/daemon/inbox-deferral-session.test.mjs +0 -49
  491. package/scripts/daemon/inbox-deferral.test.mjs +0 -336
  492. package/scripts/daemon/inbox-wake.test.mjs +0 -199
  493. package/scripts/daemon/integration.test.mjs +0 -149
  494. package/scripts/daemon/lib/self-echo.test.mjs +0 -153
  495. package/scripts/daemon/lib/session-router.test.mjs +0 -554
  496. package/scripts/daemon/prompt-builder-preamble.test.mjs +0 -210
  497. package/scripts/daemon/prompt-builder.test.mjs +0 -556
  498. package/scripts/daemon/responder-cost.test.mjs +0 -68
  499. package/scripts/daemon/responder-history.test.mjs +0 -221
  500. package/scripts/daemon/sdk-version.test.mjs +0 -31
  501. package/scripts/daemon/session-lock.test.mjs +0 -252
  502. package/scripts/daemon/session-outcomes.test.mjs +0 -533
  503. package/scripts/daemon/typing-registry.test.mjs +0 -102
  504. package/scripts/hooks/pre-send-audit.test.mjs +0 -354
  505. package/scripts/huddle/huddle-prompt.test.mjs +0 -176
  506. package/scripts/local-triggers/autoupdate.test.mjs +0 -518
  507. package/scripts/local-triggers/generate-plists.test.mjs +0 -456
  508. package/scripts/media-generation/brand-clause.test.mjs +0 -135
  509. package/scripts/org/send-orgmail.first-contact.test.mjs +0 -102
  510. package/scripts/poller/inbox-privilege-injection.test.mjs +0 -167
  511. package/scripts/poller/inbox-scan-poller.test.mjs +0 -295
  512. package/scripts/poller/lib/cloud-relay-dedup.test.mjs +0 -133
  513. package/scripts/poller/slack-socket-mode.test.mjs +0 -805
  514. package/scripts/poller-launchd/install.test.mjs +0 -243
  515. package/scripts/restore-from-backup.test.mjs +0 -181
  516. package/scripts/session/feed.test.mjs +0 -196
  517. package/scripts/session/supervisor-sh.test.mjs +0 -218
  518. package/scripts/session/supervisor.test.mjs +0 -482
  519. package/scripts/setup/configure-macos.test.mjs +0 -306
  520. package/scripts/setup/gen-subagent-manifest.test.mjs +0 -124
  521. package/scripts/setup/generate-agent-package-json.test.mjs +0 -143
  522. package/scripts/setup/generate-capability.test.mjs +0 -134
  523. package/scripts/setup/init-agent.test.mjs +0 -370
  524. package/scripts/setup/init-skill-marketplace.test.mjs +0 -193
  525. package/scripts/vendor/sync-skill-packs.test.mjs +0 -103
  526. package/scripts/watchdog/memory-watchdog.test.mjs +0 -64
@@ -1,477 +0,0 @@
1
- /**
2
- * param-contract.test.mjs — the wire param contract (lib/org/param-contract.mjs).
3
- *
4
- * Three layers, all hermetic (no network, no disk):
5
- *
6
- * 1. NORMALISER MECHANICS — alias/mint/fold/strict/enum/transform, purity,
7
- * idempotence, and the fail-open guarantees.
8
- * 2. ONE REGRESSION PER DRIFT ROW — every row the 2026-08 wire audit found gets
9
- * a test that asserts the canonical name hq validates is on the wire. These
10
- * are the tests that would have gone red on the day each bug shipped.
11
- * 3. SURFACE GUARD — a static sweep of the curated LLM tool table asserting no
12
- * tool advertises a param name hq does not read. This is the CI half of
13
- * "impossible to ship again": it needs no credentials and no server.
14
- *
15
- * Run: node --test lib/org/param-contract.test.mjs
16
- */
17
-
18
- "use strict";
19
-
20
- import { test } from "node:test";
21
- import assert from "node:assert/strict";
22
-
23
- import {
24
- PARAM_CONTRACT,
25
- BOARD_COLS,
26
- TASK_PRIORITIES,
27
- MEMORY_CLASSES,
28
- ESCALATION_SEVERITIES,
29
- hasContract,
30
- contractFor,
31
- normalizeParams,
32
- missingRequired,
33
- formatReport,
34
- reportIsInteresting,
35
- logReportOnce,
36
- _resetLogOnce,
37
- toRegisterParams,
38
- } from "./param-contract.mjs";
39
- import { ORG_TOOLS } from "./tool-surface.mjs";
40
- import { methodDef } from "./protocol.mjs";
41
-
42
- /** Normalise with a deterministic id so wire bodies are comparable. */
43
- const norm = (method, params) =>
44
- normalizeParams(method, params, { mintId: () => "MINTED" });
45
- /** Just the wire body. */
46
- const wire = (method, params) => norm(method, params).params;
47
-
48
- // ═══════════════════════════════════════════════════════════════════════════
49
- // 1. normaliser mechanics
50
- // ═══════════════════════════════════════════════════════════════════════════
51
-
52
- test("a method with no contract entry passes through byte-for-byte", () => {
53
- const input = { anything: 1, nested: { a: [1, 2] } };
54
- const r = norm("presence.beat", input);
55
- assert.deepEqual(r.params, input);
56
- assert.deepEqual(r.renamed, []);
57
- assert.equal(hasContract("presence.beat"), false);
58
- assert.equal(contractFor("presence.beat"), null);
59
- });
60
-
61
- test("PURE: the caller's params object is never mutated", () => {
62
- const input = { channelId: "C1", body: "hi" };
63
- const snapshot = JSON.parse(JSON.stringify(input));
64
- norm("messaging.send", input);
65
- assert.deepEqual(input, snapshot, "input untouched");
66
- });
67
-
68
- test("TOTAL: null / non-object / unknown method never throw", () => {
69
- assert.deepEqual(norm("messaging.send", null).params.body, undefined);
70
- assert.doesNotThrow(() => norm(undefined, undefined));
71
- assert.doesNotThrow(() => norm("no.such.method", { a: 1 }));
72
- assert.deepEqual(norm("no.such.method", { a: 1 }).params, { a: 1 });
73
- });
74
-
75
- test("alias: an EXPLICIT canonical value always beats a legacy one", () => {
76
- const w = wire("decision.comment", { body: "legacy", text: "canonical" });
77
- assert.equal(w.text, "canonical");
78
- });
79
-
80
- test("alias: the legacy key rides along by default (an older server may read it)", () => {
81
- const w = wire("member.get", { memberId: "m-1" });
82
- assert.equal(w.slug, "m-1", "canonical name added");
83
- assert.equal(w.memberId, "m-1", "legacy name kept — hq's schema is not strict");
84
- });
85
-
86
- test("strict: hq's .strict() schemas drop every unknown key, legacy names included", () => {
87
- const r = norm("board.complete", { itemId: "i-1", note: "shipped", stray: 1 });
88
- assert.deepEqual(Object.keys(r.params).sort(), ["itemId", "proof"]);
89
- assert.deepEqual(r.params.proof, { note: "shipped" });
90
- assert.ok(r.dropped.includes("note") && r.dropped.includes("stray"));
91
- });
92
-
93
- test("mint: a required business-dedup id is auto-minted only when absent", () => {
94
- assert.equal(wire("messaging.send", { channelId: "C", body: "x" }).idempotencyId, "MINTED");
95
- assert.equal(
96
- wire("messaging.send", { channelId: "C", body: "x", idempotencyId: "keep" }).idempotencyId,
97
- "keep",
98
- );
99
- // An empty string is not an id — mint over it.
100
- assert.equal(wire("messaging.send", { channelId: "C", body: "x", idempotencyId: "" }).idempotencyId, "MINTED");
101
- });
102
-
103
- test("fold: enrichment hq only persists inside a container is moved there", () => {
104
- const r = norm("knowledge.append", {
105
- body: "note",
106
- kind: "call",
107
- participants: ["a"],
108
- links: ["u"],
109
- refs: ["r"],
110
- });
111
- assert.deepEqual(r.params.metadata, { kind: "call", participants: ["a"], links: ["u"], refs: ["r"] });
112
- assert.deepEqual(r.folded.sort(), ["kind", "links", "participants", "refs"]);
113
- // A pre-existing metadata bag is merged into, never clobbered.
114
- const merged = wire("knowledge.append", { body: "n", metadata: { keep: 1 }, kind: "call" });
115
- assert.deepEqual(merged.metadata, { keep: 1, kind: "call" });
116
- });
117
-
118
- test("enums: a case-variant value is coerced; an unmappable one is reported, not dropped", () => {
119
- const ok = norm("board.createTask", { title: "t", status: "TODO" });
120
- assert.equal(ok.params.col, "todo");
121
- const bad = norm("board.createTask", { title: "t", status: "in-progress" });
122
- assert.equal(bad.params.col, "in-progress", "left for the server to reject — we do not invent values");
123
- assert.ok(bad.notes.some((n) => n.includes("in-progress")));
124
- });
125
-
126
- test("fail-open: a throwing transform loses nothing", () => {
127
- const saved = PARAM_CONTRACT["member.get"].transform;
128
- PARAM_CONTRACT["member.get"].transform = () => {
129
- throw new Error("boom");
130
- };
131
- try {
132
- const w = wire("member.get", { memberId: "m-1" });
133
- assert.equal(w.slug, "m-1", "alias still applied after the transform faulted");
134
- } finally {
135
- if (saved === undefined) delete PARAM_CONTRACT["member.get"].transform;
136
- else PARAM_CONTRACT["member.get"].transform = saved;
137
- }
138
- });
139
-
140
- test("IDEMPOTENT: normalising twice is the same as normalising once", () => {
141
- for (const method of Object.keys(PARAM_CONTRACT)) {
142
- const seed = {
143
- itemId: "i", taskId: "t", decisionId: "d", channelId: "c", messageId: "msg",
144
- callId: "call", memberId: "m", scope: "work-claim", resourceId: "r",
145
- id: "x", title: "T", body: "B", text: "X", emoji: "+1", assignee: "a",
146
- actionClass: "external_comms", payload: { a: 1 }, decision: "approve",
147
- displayName: "D",
148
- };
149
- const once = normalizeParams(method, seed, { mintId: () => "M" }).params;
150
- const twice = normalizeParams(method, once, { mintId: () => "M" }).params;
151
- assert.deepEqual(twice, once, `${method} is not idempotent`);
152
- }
153
- });
154
-
155
- test("missingRequired: reports absent required names and unmet one-of groups", () => {
156
- assert.deepEqual(missingRequired("decision.comment", { decisionId: "d" }), ["text"]);
157
- assert.deepEqual(missingRequired("escalation.create", { title: "t" }), ["taskId|channelId"]);
158
- assert.deepEqual(missingRequired("escalation.create", { title: "t", channelId: "c" }), []);
159
- // An empty string / empty array is not "present".
160
- assert.deepEqual(missingRequired("calling.start", { participantIds: [] }), ["channelId|participantIds"]);
161
- assert.deepEqual(missingRequired("no.such.method", {}), []);
162
- });
163
-
164
- test("reporting: a rewrite is never silent, and never logged twice", () => {
165
- _resetLogOnce();
166
- const lines = [];
167
- const sink = (l) => lines.push(l);
168
- const r = norm("member.get", { memberId: "m-1" });
169
- assert.equal(reportIsInteresting(r), true);
170
- assert.match(formatReport("member.get", r), /renamed memberId→slug/);
171
- assert.equal(logReportOnce("member.get", r, sink), true);
172
- assert.equal(logReportOnce("member.get", r, sink), false, "one shot per distinct rewrite");
173
- assert.equal(lines.length, 1);
174
- // A clean call says nothing.
175
- const clean = norm("member.get", { slug: "agent-one" });
176
- assert.equal(reportIsInteresting(clean), false);
177
- assert.equal(formatReport("member.get", clean), "");
178
- assert.equal(logReportOnce("member.get", clean, sink), false);
179
- });
180
-
181
- // ═══════════════════════════════════════════════════════════════════════════
182
- // 2. one regression per DRIFT row (2026-08 wire audit)
183
- // ═══════════════════════════════════════════════════════════════════════════
184
-
185
- // ── P0: the feature was 100 % dead — every call returned BAD_REQUEST ────────
186
-
187
- test("P0/1 messaging.send: hq requires idempotencyId, NOT clientMsgId", () => {
188
- const w = wire("messaging.send", { channelId: "C1", body: "hello", clientMsgId: "cm-1" });
189
- assert.equal(w.idempotencyId, "cm-1", "the minted dedup id lands on the name hq reads");
190
- assert.deepEqual(missingRequired("messaging.send", w), []);
191
- });
192
-
193
- test("P0/2 registry.register: the raw self-entry is projected onto the .strict() schema", () => {
194
- // A persona-agnostic fixture: the framework must carry no instance identity.
195
- const entry = {
196
- id: "A001", name: "agent-one", fullName: "Agent One", title: "Engineer",
197
- email: "agent-one@example.test", repo: "example-org/agent-one",
198
- archetype: { function: "engineering", altitude: "specialist", label: "Specialist Engineer" },
199
- towers: ["eng"], focus: "wire contracts", principal: { fullName: "Sponsor Name" },
200
- presence: "online", status: "ACTIVE",
201
- };
202
- const r = norm("registry.register", entry);
203
- assert.deepEqual(Object.keys(r.params).sort(), ["archetype", "card", "displayName", "humanSponsor"]);
204
- assert.equal(r.params.displayName, "Agent One");
205
- assert.equal(r.params.archetype, "Specialist Engineer", "the archetype OBJECT is flattened to a string");
206
- assert.equal(r.params.humanSponsor, "Sponsor Name");
207
- assert.deepEqual(r.params.card, entry, "everything hq does not model is preserved under card");
208
- // …and every one of those raw top-level keys is gone from the wire.
209
- for (const k of ["id", "name", "fullName", "email", "repo", "towers", "focus", "presence", "status"]) {
210
- assert.equal(r.params[k], undefined, `${k} would have 400'd the strict schema`);
211
- }
212
- });
213
-
214
- test("P0/2b toRegisterParams is idempotent — an already-projected object is untouched", () => {
215
- const projected = { displayName: "D", archetype: "A", humanSponsor: "H", card: { x: 1 } };
216
- assert.deepEqual(toRegisterParams(projected), projected);
217
- assert.deepEqual(toRegisterParams(null), { card: {} });
218
- });
219
-
220
- test("P0/3 memory.author: hq requires {memoryClass (enum), title}", () => {
221
- const w = wire("memory.author", { content: "Q3 pricing moved to usage-based.\nDetail follows.", kind: "STRATEGY" });
222
- assert.equal(w.memoryClass, "strategy", "kind→memoryClass, case-folded into hq's enum");
223
- assert.equal(w.title, "Q3 pricing moved to usage-based.", "a title is derived from the first line");
224
- assert.equal(w.summary, "Q3 pricing moved to usage-based.\nDetail follows.");
225
- assert.deepEqual(missingRequired("memory.author", w), []);
226
- assert.ok(MEMORY_CLASSES.includes(w.memoryClass));
227
- });
228
-
229
- test("P0/3b memory.author: `tags` are NOT scopes — they are reported, never smuggled into the ACL", () => {
230
- const r = norm("memory.author", { memoryClass: "ledger", title: "t", tags: ["private", "finance"] });
231
- assert.equal(r.params.scopes, undefined, "tags must never become ACL scopes");
232
- assert.ok(r.unsupported.includes("tags"));
233
- });
234
-
235
- test("P0/4 escalation.create: hq requires a title AND a target", () => {
236
- const w = wire("escalation.create", { severity: "high", subject: "Deploy blocked", body: "CI is red" });
237
- assert.equal(w.title, "Deploy blocked");
238
- assert.equal(w.detail, "CI is red");
239
- assert.deepEqual(missingRequired("escalation.create", w), ["taskId|channelId"]);
240
- assert.deepEqual(missingRequired("escalation.create", { ...w, taskId: "t-1" }), []);
241
- assert.ok(ESCALATION_SEVERITIES.includes(w.severity));
242
- });
243
-
244
- test("P0/5 member.get: hq resolves by slug, not memberId", () => {
245
- assert.equal(wire("member.get", { memberId: "m-1" }).slug, "m-1");
246
- assert.equal(wire("member.get", { id: "m-2" }).slug, "m-2");
247
- });
248
-
249
- test("P0/6 decision.comment: hq reads `text`, and threw on `body`", () => {
250
- const w = wire("decision.comment", { decisionId: "d-1", body: "agreed" });
251
- assert.equal(w.text, "agreed");
252
- assert.deepEqual(missingRequired("decision.comment", w), []);
253
- });
254
-
255
- test("P0/7 approval.request: actionClass is REQUIRED; the hash and expiry are renamed", () => {
256
- const w = wire("approval.request", {
257
- id: "ap-1",
258
- kind: "external_comms",
259
- subject: "email to a new contact",
260
- payload_hash: "a".repeat(64),
261
- requester: "acme",
262
- expiresInMs: 3_600_000,
263
- });
264
- assert.equal(w.actionClass, "external_comms", 'hq threw "actionClass is required" on every call');
265
- assert.equal(w.payloadHash, "a".repeat(64));
266
- assert.ok(Date.parse(w.expiresAt) > Date.now(), "expiresInMs → an absolute expiresAt");
267
- assert.deepEqual(missingRequired("approval.request", w), []);
268
- });
269
-
270
- test("P0/7b approval.request: `requester` is server-derived and is reported as not-read", () => {
271
- const r = norm("approval.request", { actionClass: "x", payload: {}, requester: "acme" });
272
- assert.ok(r.unsupported.includes("requester"));
273
- });
274
-
275
- test("P0/8 calling.start: hq's refine demands channelId or a non-empty participantIds", () => {
276
- const w = wire("calling.start", { channel: "C1", invitees: ["m1", "m2"], topic: "standup", id: "i-1" });
277
- assert.equal(w.channelId, "C1");
278
- assert.deepEqual(w.participantIds, ["m1", "m2"]);
279
- assert.deepEqual(missingRequired("calling.start", w), []);
280
- // The topic has nowhere to go on hq's schema — say so rather than pretend.
281
- assert.ok(norm("calling.start", { channel: "C1", topic: "standup" }).unsupported.includes("topic"));
282
- });
283
-
284
- test("P0/9 board.complete: `note` 400'd the .strict() schema — it is wrapped as proof.note", () => {
285
- assert.deepEqual(wire("board.complete", { itemId: "i-1", note: "PR #42 merged" }), {
286
- itemId: "i-1",
287
- proof: { note: "PR #42 merged" },
288
- });
289
- // A caller that already speaks `proof` is left alone.
290
- assert.deepEqual(wire("board.complete", { itemId: "i-1", proof: { url: "u" } }), {
291
- itemId: "i-1",
292
- proof: { url: "u" },
293
- });
294
- });
295
-
296
- // ── P1: the call SUCCEEDED but silently discarded the caller's intent ───────
297
-
298
- test("P1/10 board.createTask: description/assignee/status were stripped by zod", () => {
299
- const r = norm("board.createTask", {
300
- title: "Ship the probe",
301
- description: "wire conformance",
302
- assignee: "m-1",
303
- status: "todo",
304
- priority: "P1",
305
- dueAt: "2026-09-01",
306
- });
307
- assert.equal(r.params.detail, "wire conformance");
308
- assert.equal(r.params.assigneeId, "m-1");
309
- assert.equal(r.params.col, "todo");
310
- assert.equal(r.params.priority, "P1");
311
- // createTaskSchema models no dueAt at all — the loss is reported, not hidden.
312
- assert.ok(r.unsupported.includes("dueAt"));
313
- assert.ok(r.notes.some((n) => n.includes("board.updateTask")));
314
- });
315
-
316
- test("P1/11 board.updateTask: editTaskSchema has NO assignee — reassignment needs board.assignTask", () => {
317
- const r = norm("board.updateTask", { taskId: "t-1", status: "review", description: "d", assignee: "m-9" });
318
- assert.equal(r.params.col, "review");
319
- assert.equal(r.params.detail, "d");
320
- assert.ok(r.unsupported.includes("assignee"), "an agent that thought it reassigned a task did not");
321
- // The verb that DOES work.
322
- assert.deepEqual(missingRequired("board.assignTask", wire("board.assignTask", { taskId: "t-1", assignee: "m-9" })), []);
323
- assert.equal(wire("board.assignTask", { taskId: "t-1", assignee: "m-9" }).assigneeId, "m-9");
324
- });
325
-
326
- test("P1/12 decision.propose: the rationale lives at why.reason, and `scope` is hq's `tag`", () => {
327
- const w = wire("decision.propose", { title: "Adopt usage pricing", rationale: "margin", scope: "pricing" });
328
- assert.deepEqual(w.why, { reason: "margin" });
329
- assert.equal(w.tag, "pricing");
330
- // An explicit why block is preserved and merged, not overwritten.
331
- const merged = wire("decision.propose", { title: "t", why: { options: ["a", "b"] }, rationale: "r" });
332
- assert.deepEqual(merged.why, { options: ["a", "b"], reason: "r" });
333
- });
334
-
335
- test("P1/13 messaging.history: hq paginates on before/after — since/cursor were dropped", () => {
336
- const w = wire("messaging.history", { channel: "C1", cursor: "m-100", since: "m-1", limit: 50 });
337
- assert.equal(w.channelId, "C1");
338
- assert.equal(w.before, "m-100");
339
- assert.equal(w.after, "m-1");
340
- assert.equal(w.limit, 50);
341
- });
342
-
343
- test("P1/14 approval_request: a hash-only request keeps the hash on the name hq binds", () => {
344
- const w = wire("approval.request", { actionClass: "external_comms", payload_hash: "b".repeat(64) });
345
- assert.equal(w.payloadHash, "b".repeat(64));
346
- assert.deepEqual(missingRequired("approval.request", w), [], "payload OR payloadHash satisfies the bind");
347
- });
348
-
349
- // ── P2: dropped enrichment ─────────────────────────────────────────────────
350
-
351
- test("P2/15 knowledge.append: kind/participants/links/refs now persist under metadata", () => {
352
- const r = norm("knowledge.append", { text: "call notes", kind: "note", participants: ["a", "b"] });
353
- assert.equal(r.params.body, "call notes", "hq reads body (text is its accepted alias)");
354
- assert.deepEqual(r.params.metadata, { kind: "note", participants: ["a", "b"] });
355
- });
356
-
357
- test("P2/16 knowledge.search: kind/includeInvalid/lexical are not read by hq — reported", () => {
358
- const r = norm("knowledge.search", { query: "pricing", kind: "note", includeInvalid: true, lexical: true });
359
- assert.equal(r.params.q, "pricing");
360
- assert.deepEqual(r.unsupported.sort(), ["includeInvalid", "kind", "lexical"]);
361
- });
362
-
363
- test("P2/17 contacts.upsert / meetings.record: the ACL `group` hint is not read", () => {
364
- assert.ok(norm("contacts.upsert", { displayName: "X", group: "org" }).unsupported.includes("group"));
365
- assert.ok(norm("meetings.record", { title: "T", group: "org" }).unsupported.includes("group"));
366
- });
367
-
368
- test("P2/18 leases: `holder` and `leaseToken` never round-trip — ownership is the actor", () => {
369
- assert.ok(norm("lease.claim", { scope: "work-claim", resourceId: "r", holder: "me" }).unsupported.includes("holder"));
370
- assert.ok(norm("lease.release", { scope: "work-claim", resourceId: "r", leaseToken: "t" }).unsupported.includes("leaseToken"));
371
- assert.equal(wire("lease.claim", { scope: "s", resourceId: "r", token: "hash" }).tokenHash, "hash");
372
- });
373
-
374
- // ═══════════════════════════════════════════════════════════════════════════
375
- // 3. surface guard — the offline CI half
376
- // ═══════════════════════════════════════════════════════════════════════════
377
-
378
- test("GUARD: every contracted method is a real protocol method", () => {
379
- for (const method of Object.keys(PARAM_CONTRACT)) {
380
- assert.ok(methodDef(method), `${method} is not in the vendored protocol table`);
381
- }
382
- });
383
-
384
- test("GUARD: no curated tool advertises a param name hq does not read", () => {
385
- const offenders = [];
386
- for (const t of ORG_TOOLS) {
387
- if (!t.binding || t.binding.kind !== "rpc") continue;
388
- const c = contractFor(t.binding.method);
389
- if (!c || !c.alias) continue;
390
- const stillRead = new Set(c.serverAccepts || []);
391
- const props = Object.keys((t.input_schema && t.input_schema.properties) || {});
392
- for (const p of props) {
393
- // A legacy alias key the server does NOT also accept is a name the model
394
- // would fill in and hq would ignore (or reject). That is the whole bug.
395
- if (Object.prototype.hasOwnProperty.call(c.alias, p) && !stillRead.has(p)) {
396
- offenders.push(`${t.name} (${t.binding.method}) advertises "${p}" — hq reads "${c.alias[p]}"`);
397
- }
398
- }
399
- }
400
- assert.deepEqual(offenders, [], `curated tools drifted from hq:\n ${offenders.join("\n ")}`);
401
- });
402
-
403
- test("GUARD: no curated tool advertises a param hq accepts but never reads", () => {
404
- const offenders = [];
405
- for (const t of ORG_TOOLS) {
406
- if (!t.binding || t.binding.kind !== "rpc") continue;
407
- const c = contractFor(t.binding.method);
408
- if (!c || !c.unsupported) continue;
409
- const props = Object.keys((t.input_schema && t.input_schema.properties) || {});
410
- for (const p of props) {
411
- if (c.unsupported.includes(p)) {
412
- offenders.push(`${t.name} (${t.binding.method}) offers "${p}" — hq discards it`);
413
- }
414
- }
415
- }
416
- assert.deepEqual(offenders, [], `tools promise the model things hq drops:\n ${offenders.join("\n ")}`);
417
- });
418
-
419
- test("GUARD: a curated tool's REQUIRED params cover everything hq requires", () => {
420
- const offenders = [];
421
- for (const t of ORG_TOOLS) {
422
- if (!t.binding || t.binding.kind !== "rpc") continue;
423
- const c = contractFor(t.binding.method);
424
- if (!c || !c.required) continue;
425
- const props = new Set(Object.keys((t.input_schema && t.input_schema.properties) || {}));
426
- for (const need of c.required) {
427
- // Minted ids are supplied by the executor, not the model.
428
- if ((c.mint || []).includes(need)) continue;
429
- if (!props.has(need)) {
430
- offenders.push(`${t.name} (${t.binding.method}) cannot supply required "${need}"`);
431
- }
432
- }
433
- }
434
- assert.deepEqual(offenders, [], `tools cannot satisfy hq:\n ${offenders.join("\n ")}`);
435
- });
436
-
437
- test("GUARD: enum-valued tool params list exactly hq's vocabulary", () => {
438
- const byTool = {
439
- task_create: { col: BOARD_COLS, priority: TASK_PRIORITIES },
440
- task_update: { col: BOARD_COLS, priority: TASK_PRIORITIES },
441
- memory_author: { memoryClass: MEMORY_CLASSES },
442
- escalation_raise: { severity: ESCALATION_SEVERITIES },
443
- };
444
- for (const [toolName, expect] of Object.entries(byTool)) {
445
- const t = ORG_TOOLS.find((x) => x.name === toolName);
446
- assert.ok(t, `${toolName} is in the table`);
447
- for (const [param, values] of Object.entries(expect)) {
448
- assert.deepEqual(t.input_schema.properties[param].enum, values, `${toolName}.${param}`);
449
- }
450
- }
451
- });
452
-
453
- test("messaging.send/edit: mentions are coerced to hq's object shape at the ONE chokepoint", () => {
454
- const sent = normalizeParams("messaging.send", {
455
- channelId: "C-1",
456
- body: "b",
457
- idempotencyId: "i",
458
- mentions: ["M-2", { memberId: "M-2" }, { id: "M-3" }, { memberId: "M-4", offset: 3 }, "", null],
459
- });
460
- assert.deepEqual(sent.params.mentions, [
461
- { memberId: "M-2" },
462
- { memberId: "M-3" },
463
- { memberId: "M-4", offset: 3 },
464
- ]);
465
-
466
- // Idempotent: applying the contract twice must not re-wrap.
467
- const twice = normalizeParams("messaging.send", sent.params);
468
- assert.deepEqual(twice.params.mentions, sent.params.mentions);
469
-
470
- // An empty list states nothing rather than asserting an empty relation.
471
- const none = normalizeParams("messaging.send", { channelId: "C", body: "b", idempotencyId: "i", mentions: [] });
472
- assert.equal("mentions" in none.params, false);
473
-
474
- // messaging.edit reuses hq's mentionSchema, so it gets the same coercion.
475
- const edited = normalizeParams("messaging.edit", { messageId: "m1", body: "b", mentions: ["M-9"] });
476
- assert.deepEqual(edited.params.mentions, [{ memberId: "M-9" }]);
477
- });