kenaz 0.3.3 → 0.3.6

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 (451) hide show
  1. package/core/.agents/skills/typesafe-ai/LICENSE +21 -21
  2. package/core/.agents/skills/typesafe-ai/SKILL.md +149 -149
  3. package/core/.claude/commands/Ansuz.md +15 -2
  4. package/core/.claude/hooks/__tests__/task-2395-project-registration.test.js +84 -0
  5. package/core/.claude/hooks/handoff-staleness.js +2 -2
  6. package/core/.claude/hooks/session-init.ps1 +49 -49
  7. package/core/.claude/hooks/turn-context.js +50 -2
  8. package/core/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -26
  9. package/core/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -97
  10. package/core/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -101
  11. package/core/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -31
  12. package/core/.claude/skills/ui-ux-pro-max/data/products.csv +96 -96
  13. package/core/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -45
  14. package/core/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -54
  15. package/core/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
  16. package/core/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
  17. package/core/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
  18. package/core/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
  19. package/core/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
  20. package/core/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
  21. package/core/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
  22. package/core/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -54
  23. package/core/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
  24. package/core/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
  25. package/core/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
  26. package/core/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -50
  27. package/core/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -68
  28. package/core/.claude/skills/ui-ux-pro-max/data/typography.csv +57 -57
  29. package/core/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
  30. package/core/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
  31. package/core/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -31
  32. package/core/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -253
  33. package/core/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -1067
  34. package/core/.claude/skills/ui-ux-pro-max/scripts/search.py +106 -106
  35. package/core/.collaboration/core/task-api.js +1 -4
  36. package/core/.formation/README.md +21 -146
  37. package/core/.formation/bifrost/codex-doctor.js +37 -2
  38. package/core/.formation/bifrost/codex-doctor.test.js +18 -0
  39. package/core/.formation/bifrost/launch.js +1 -1
  40. package/core/.formation/bifrost/openai/codex-hook-shim.js +6 -0
  41. package/core/.formation/bifrost/openai/codex-hook-shim.test.js +11 -1
  42. package/core/.formation/bifrost/setup-codex.js +3 -0
  43. package/core/.formation/native/claude/README.md +1 -1
  44. package/core/.formation/role-map.yaml +3 -3
  45. package/core/.formation/spec/task_operations.parity.test.js +0 -1
  46. package/core/.formation/spec/task_operations.yaml +3 -3
  47. package/core/.formation/tests/hello.txt +2 -2
  48. package/core/.formation/tools/__tests__/subagent-bifrost-guard.test.js +4 -4
  49. package/core/.formation/tools/dashboard-models-chain.test.js +0 -6
  50. package/core/.formation/tools/dispatch-detail/cross-project-worktree.md +1 -9
  51. package/core/.formation/tools/dispatch-detail/worktree-subagent-mode.md +2 -2
  52. package/core/.formation/tools/dispatch.js +33 -554
  53. package/core/.formation/tools/mcp-allowlist.test.js +0 -1
  54. package/core/.formation/tools/post-complete/task2345.test.js +0 -5
  55. package/core/.formation/tools/pre-dispatch-snapshot.test.js +0 -100
  56. package/core/.formation/tools/prompt.js +33 -1623
  57. package/core/.formation/tools/prompt.test.js +26 -594
  58. package/core/.formation/unit/do.yaml +2 -4
  59. package/core/.kenaz/knowledge/ladybug_2c51da1e_shadow_file_frame_group.patch +163 -163
  60. package/core/.kenaz/knowledge/ladybug_30cf85690e_shadow_page_read_during_checkpoint.patch +393 -393
  61. package/core/.kenaz/knowledge/ladybug_7a17858d3a_node_group_delete_lock.patch +102 -102
  62. package/core/.kenaz/knowledge/ladybug_926a0ba1_column_checkpoint.patch +412 -412
  63. package/core/.kenaz/knowledge/ladybug_a346c4c4b6_pk_index_header_pages.patch +144 -144
  64. package/core/.kenaz/knowledge/ladybug_ba5f38815b_csr_node_group.patch +86 -86
  65. package/core/.kenaz/muninn_episode_write.ps1 +17 -17
  66. package/core/.kenaz/specialist/field_report_watermark.json +1 -1
  67. package/core/.kenaz/specialist/memory_guard_fired.json +1 -1
  68. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +1 -1
  69. package/core/.kenaz/specialist/t1777_probe.txt +1 -1
  70. package/core/.matrix/index.matrix +5 -5
  71. package/core/.rule/general/agent-workflow.yaml +4 -4
  72. package/core/.rule/general/file-size-threshold.yaml +16 -4
  73. package/core/.rule/general/rust-verify-target.yaml +0 -1
  74. package/core/.rule/general/system-invariants.yaml +8 -25
  75. package/core/.specialist/Ansuz/SYSTEM_DOC.md +17 -42
  76. package/core/.specialist/Ansuz/capability.yaml +7 -14
  77. package/core/.specialist/Ansuz/concepts/formation_quick_ref.yaml +4 -11
  78. package/core/.specialist/Ansuz/elixir.yaml +3 -4
  79. package/core/.specialist/Ansuz/identity_contract.yaml +1 -1
  80. package/core/.specialist/Ansuz/knowledge.yaml +7 -10
  81. package/core/.specialist/Ansuz/rule.yaml +2 -2
  82. package/core/.specialist/Ansuz/tools/verify-and-land.js +22 -0
  83. package/core/.specialist/Ansuz/tools/verify-and-land.test.js +59 -5
  84. package/core/.specialist/Ansuz/workflow.yaml +7 -11
  85. package/core/.specialist/Forseti/core.yaml +1 -1
  86. package/core/.specialist/Heimdall/SKILL.md +1 -1
  87. package/core/.specialist/Heimdall/core.yaml +2 -2
  88. package/core/.specialist/Huginn/rule.yaml +1 -1
  89. package/core/.specialist/tools/README.md +2 -2
  90. package/core/.specialist/tools/__tests__/freya-cli-contract.test.js +0 -1
  91. package/core/.system/collaboration/README.md +1 -1
  92. package/core/.system/formation/LEGACY_SKILLS.md +2 -0
  93. package/core/.system/formation/POST_COMPLETE.md +2 -0
  94. package/core/.system/formation/README.md +2 -0
  95. package/core/KENAZ_CORE_VERSION +1 -1
  96. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +355 -355
  97. package/core/dev/JEV_INTEGRATION_PLAN.md +189 -189
  98. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +13 -13
  99. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +9 -9
  100. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +14 -14
  101. package/core/dev/design/matrix_v2_EXAMPLE.matrix +67 -67
  102. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +52 -52
  103. package/core/dev/jev-eval/CONTEXT_REVIEW.md +31 -31
  104. package/core/dev/jev-eval/EVALUATION_STATUS.md +39 -39
  105. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +33 -33
  106. package/core/dev/jev-eval/README.md +99 -99
  107. package/core/dev/jev-eval/THALAMUS_RANKING.md +58 -58
  108. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +32 -32
  109. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +48 -48
  110. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +52 -52
  111. package/core/dev/pipeline/SELF_ENHANCEMENT_STATUS.json.bak +47 -47
  112. package/core/dev/pipeline/tasks/.gitkeep +1 -1
  113. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +27 -27
  114. package/core/dev/scripts/check-file-size.js +44 -17
  115. package/core/dev/scripts/init_git.sh +0 -0
  116. package/core/dev/scripts/init_project.sh +0 -0
  117. package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +536 -536
  118. package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +1978 -1978
  119. package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +140 -140
  120. package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +173 -173
  121. package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +168 -168
  122. package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +126 -126
  123. package/core/dev/scripts/multi_agent_scheduler.sh +0 -0
  124. package/core/dev/scripts/run_once.sh +0 -0
  125. package/core/dev/scripts/setup_mcp.sh +0 -0
  126. package/core/dev/scripts/setup_rag.sh +0 -0
  127. package/core/dev/scripts/start_dev_agent.sh +0 -0
  128. package/core/dev/scripts/start_multi_agent.sh +0 -0
  129. package/core/dev/scripts/sync_task_queue.sh +0 -0
  130. package/core/k-cli/README.md +1 -94
  131. package/core/k-cli/test/TEST_SPEC.md +5 -22
  132. package/core/k-cli/test/run.sh +1 -67
  133. package/core/plugins/kenaz/commands/Amelia.md +1 -1
  134. package/core/plugins/kenaz/commands/Ansuz.md +16 -3
  135. package/core/plugins/kenaz/scripts/kenaz-mode.js +11 -1
  136. package/core/plugins/kenaz/scripts/sync.js +6 -2
  137. package/core/plugins/kenaz/scripts/ygg.js +13 -1
  138. package/core/plugins/kenaz/skills/product_manager/SKILL.md +12 -12
  139. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/charts.csv +26 -26
  140. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/colors.csv +97 -97
  141. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/icons.csv +101 -101
  142. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/landing.csv +31 -31
  143. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/products.csv +96 -96
  144. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/react-performance.csv +45 -45
  145. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -54
  146. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
  147. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
  148. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
  149. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
  150. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
  151. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
  152. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
  153. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react.csv +54 -54
  154. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
  155. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
  156. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
  157. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -50
  158. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/styles.csv +68 -68
  159. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/typography.csv +57 -57
  160. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
  161. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
  162. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/web-interface.csv +31 -31
  163. package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/core.py +253 -253
  164. package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/design_system.py +1067 -1067
  165. package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/search.py +106 -106
  166. package/lib/cli.js +11 -4
  167. package/package.json +11 -7
  168. package/vendor/install-kenaz-cli.js +18 -7
  169. package/core/.formation/legion/forge.yaml +0 -299
  170. package/core/.formation/legion/hive.yaml +0 -238
  171. package/core/.formation/squad/blitz.yaml +0 -192
  172. package/core/.formation/squad/strategy-tribunal.yaml +0 -354
  173. package/core/.formation/squad/strategy.yaml +0 -349
  174. package/core/.formation/squad/sweep.yaml +0 -208
  175. package/core/.formation/tools/broadcast.js +0 -103
  176. package/core/.formation/tools/dispatch-dryrun.test.js +0 -54
  177. package/core/.formation/tools/dispatch-notifier.js +0 -84
  178. package/core/.formation/tools/formations.js +0 -1203
  179. package/core/.formation/tools/headless-branch-recovery.test.js +0 -64
  180. package/core/.formation/tools/headless-dryrun.test.js +0 -79
  181. package/core/.formation/tools/headless-v2.js +0 -659
  182. package/core/.formation/tools/headless.js +0 -1071
  183. package/core/.formation/tools/legacy-scheduler.js +0 -1994
  184. package/core/.formation/tools/logger.js +0 -273
  185. package/core/.formation/tools/memory-loader.js +0 -422
  186. package/core/.formation/tools/process-state.js +0 -33
  187. package/core/.formation/tools/remote-conflict.js +0 -98
  188. package/core/.formation/tools/runner.js +0 -1332
  189. package/core/.formation/tools/task-utils.js +0 -344
  190. package/core/.formation/tools/task2028-headless-worktree.test.js +0 -112
  191. package/core/.formation/tools/tests/headless-mcp-args-plumbing.test.js +0 -123
  192. package/core/.formation/tools/worktree-leak.test.js +0 -162
  193. package/core/k-cli/dist/alaya/run.js +0 -91
  194. package/core/k-cli/dist/core/output.js +0 -24
  195. package/core/k-cli/dist/core/process.js +0 -38
  196. package/core/k-cli/dist/core/project.js +0 -80
  197. package/core/k-cli/dist/core/spawn.js +0 -268
  198. package/core/k-cli/dist/core/types.js +0 -2
  199. package/core/k-cli/dist/dashboard/update.js +0 -53
  200. package/core/k-cli/dist/dashboard/version.js +0 -20
  201. package/core/k-cli/dist/dispatch/run.js +0 -241
  202. package/core/k-cli/dist/dispatch/status.js +0 -103
  203. package/core/k-cli/dist/index.js +0 -283
  204. package/core/k-cli/dist/project/initialize.js +0 -301
  205. package/core/k-cli/dist/project/install.js +0 -89
  206. package/core/k-cli/dist/project/status.js +0 -138
  207. package/core/k-cli/dist/specialist/list.js +0 -100
  208. package/core/k-cli/dist/specialist/run.js +0 -93
  209. package/core/k-cli/dist/task/create.js +0 -194
  210. package/core/k-cli/dist/task/delete.js +0 -98
  211. package/core/k-cli/dist/task/get.js +0 -55
  212. package/core/k-cli/dist/task/list.js +0 -58
  213. package/core/k-cli/dist/task/submit.js +0 -156
  214. package/core/k-cli/dist/ygg/run.js +0 -51
  215. package/core/k-cli/node_modules/.bin/yaml +0 -16
  216. package/core/k-cli/node_modules/.bin/yaml.cmd +0 -17
  217. package/core/k-cli/node_modules/.bin/yaml.ps1 +0 -28
  218. package/core/k-cli/node_modules/.package-lock.json +0 -23
  219. package/core/k-cli/node_modules/yaml/LICENSE +0 -13
  220. package/core/k-cli/node_modules/yaml/README.md +0 -172
  221. package/core/k-cli/node_modules/yaml/bin.mjs +0 -11
  222. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-collection.js +0 -88
  223. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-doc.js +0 -43
  224. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-node.js +0 -109
  225. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-scalar.js +0 -86
  226. package/core/k-cli/node_modules/yaml/browser/dist/compose/composer.js +0 -217
  227. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-map.js +0 -115
  228. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +0 -198
  229. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +0 -49
  230. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-end.js +0 -37
  231. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +0 -207
  232. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +0 -223
  233. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-props.js +0 -146
  234. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-contains-newline.js +0 -34
  235. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +0 -26
  236. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +0 -15
  237. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-map-includes.js +0 -13
  238. package/core/k-cli/node_modules/yaml/browser/dist/doc/Document.js +0 -335
  239. package/core/k-cli/node_modules/yaml/browser/dist/doc/anchors.js +0 -71
  240. package/core/k-cli/node_modules/yaml/browser/dist/doc/applyReviver.js +0 -55
  241. package/core/k-cli/node_modules/yaml/browser/dist/doc/createNode.js +0 -88
  242. package/core/k-cli/node_modules/yaml/browser/dist/doc/directives.js +0 -176
  243. package/core/k-cli/node_modules/yaml/browser/dist/errors.js +0 -57
  244. package/core/k-cli/node_modules/yaml/browser/dist/index.js +0 -17
  245. package/core/k-cli/node_modules/yaml/browser/dist/log.js +0 -11
  246. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Alias.js +0 -114
  247. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Collection.js +0 -147
  248. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Node.js +0 -38
  249. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Pair.js +0 -36
  250. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Scalar.js +0 -24
  251. package/core/k-cli/node_modules/yaml/browser/dist/nodes/YAMLMap.js +0 -144
  252. package/core/k-cli/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +0 -113
  253. package/core/k-cli/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +0 -63
  254. package/core/k-cli/node_modules/yaml/browser/dist/nodes/identity.js +0 -36
  255. package/core/k-cli/node_modules/yaml/browser/dist/nodes/toJS.js +0 -37
  256. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-scalar.js +0 -214
  257. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-stringify.js +0 -61
  258. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-visit.js +0 -97
  259. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst.js +0 -98
  260. package/core/k-cli/node_modules/yaml/browser/dist/parse/lexer.js +0 -717
  261. package/core/k-cli/node_modules/yaml/browser/dist/parse/line-counter.js +0 -39
  262. package/core/k-cli/node_modules/yaml/browser/dist/parse/parser.js +0 -967
  263. package/core/k-cli/node_modules/yaml/browser/dist/public-api.js +0 -102
  264. package/core/k-cli/node_modules/yaml/browser/dist/schema/Schema.js +0 -37
  265. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/map.js +0 -17
  266. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/null.js +0 -15
  267. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/seq.js +0 -17
  268. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/string.js +0 -14
  269. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/bool.js +0 -19
  270. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/float.js +0 -43
  271. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/int.js +0 -38
  272. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/schema.js +0 -23
  273. package/core/k-cli/node_modules/yaml/browser/dist/schema/json/schema.js +0 -62
  274. package/core/k-cli/node_modules/yaml/browser/dist/schema/tags.js +0 -96
  275. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +0 -58
  276. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +0 -26
  277. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +0 -46
  278. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +0 -71
  279. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +0 -64
  280. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +0 -74
  281. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +0 -78
  282. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +0 -39
  283. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +0 -93
  284. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +0 -101
  285. package/core/k-cli/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +0 -146
  286. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringify.js +0 -129
  287. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +0 -153
  288. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyComment.js +0 -20
  289. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +0 -85
  290. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +0 -24
  291. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyPair.js +0 -150
  292. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyString.js +0 -336
  293. package/core/k-cli/node_modules/yaml/browser/dist/util.js +0 -11
  294. package/core/k-cli/node_modules/yaml/browser/dist/visit.js +0 -233
  295. package/core/k-cli/node_modules/yaml/browser/index.js +0 -5
  296. package/core/k-cli/node_modules/yaml/browser/package.json +0 -3
  297. package/core/k-cli/node_modules/yaml/dist/cli.d.ts +0 -8
  298. package/core/k-cli/node_modules/yaml/dist/cli.mjs +0 -201
  299. package/core/k-cli/node_modules/yaml/dist/compose/compose-collection.d.ts +0 -11
  300. package/core/k-cli/node_modules/yaml/dist/compose/compose-collection.js +0 -90
  301. package/core/k-cli/node_modules/yaml/dist/compose/compose-doc.d.ts +0 -7
  302. package/core/k-cli/node_modules/yaml/dist/compose/compose-doc.js +0 -45
  303. package/core/k-cli/node_modules/yaml/dist/compose/compose-node.d.ts +0 -29
  304. package/core/k-cli/node_modules/yaml/dist/compose/compose-node.js +0 -112
  305. package/core/k-cli/node_modules/yaml/dist/compose/compose-scalar.d.ts +0 -5
  306. package/core/k-cli/node_modules/yaml/dist/compose/compose-scalar.js +0 -88
  307. package/core/k-cli/node_modules/yaml/dist/compose/composer.d.ts +0 -63
  308. package/core/k-cli/node_modules/yaml/dist/compose/composer.js +0 -222
  309. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-map.d.ts +0 -6
  310. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-map.js +0 -117
  311. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +0 -11
  312. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-scalar.js +0 -200
  313. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +0 -6
  314. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-seq.js +0 -51
  315. package/core/k-cli/node_modules/yaml/dist/compose/resolve-end.d.ts +0 -6
  316. package/core/k-cli/node_modules/yaml/dist/compose/resolve-end.js +0 -39
  317. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +0 -7
  318. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-collection.js +0 -209
  319. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +0 -10
  320. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-scalar.js +0 -225
  321. package/core/k-cli/node_modules/yaml/dist/compose/resolve-props.d.ts +0 -23
  322. package/core/k-cli/node_modules/yaml/dist/compose/resolve-props.js +0 -148
  323. package/core/k-cli/node_modules/yaml/dist/compose/util-contains-newline.d.ts +0 -2
  324. package/core/k-cli/node_modules/yaml/dist/compose/util-contains-newline.js +0 -36
  325. package/core/k-cli/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +0 -2
  326. package/core/k-cli/node_modules/yaml/dist/compose/util-empty-scalar-position.js +0 -28
  327. package/core/k-cli/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +0 -3
  328. package/core/k-cli/node_modules/yaml/dist/compose/util-flow-indent-check.js +0 -17
  329. package/core/k-cli/node_modules/yaml/dist/compose/util-map-includes.d.ts +0 -4
  330. package/core/k-cli/node_modules/yaml/dist/compose/util-map-includes.js +0 -15
  331. package/core/k-cli/node_modules/yaml/dist/doc/Document.d.ts +0 -141
  332. package/core/k-cli/node_modules/yaml/dist/doc/Document.js +0 -337
  333. package/core/k-cli/node_modules/yaml/dist/doc/anchors.d.ts +0 -24
  334. package/core/k-cli/node_modules/yaml/dist/doc/anchors.js +0 -76
  335. package/core/k-cli/node_modules/yaml/dist/doc/applyReviver.d.ts +0 -9
  336. package/core/k-cli/node_modules/yaml/dist/doc/applyReviver.js +0 -57
  337. package/core/k-cli/node_modules/yaml/dist/doc/createNode.d.ts +0 -17
  338. package/core/k-cli/node_modules/yaml/dist/doc/createNode.js +0 -90
  339. package/core/k-cli/node_modules/yaml/dist/doc/directives.d.ts +0 -49
  340. package/core/k-cli/node_modules/yaml/dist/doc/directives.js +0 -178
  341. package/core/k-cli/node_modules/yaml/dist/errors.d.ts +0 -21
  342. package/core/k-cli/node_modules/yaml/dist/errors.js +0 -62
  343. package/core/k-cli/node_modules/yaml/dist/index.d.ts +0 -25
  344. package/core/k-cli/node_modules/yaml/dist/index.js +0 -50
  345. package/core/k-cli/node_modules/yaml/dist/log.d.ts +0 -3
  346. package/core/k-cli/node_modules/yaml/dist/log.js +0 -19
  347. package/core/k-cli/node_modules/yaml/dist/nodes/Alias.d.ts +0 -29
  348. package/core/k-cli/node_modules/yaml/dist/nodes/Alias.js +0 -116
  349. package/core/k-cli/node_modules/yaml/dist/nodes/Collection.d.ts +0 -73
  350. package/core/k-cli/node_modules/yaml/dist/nodes/Collection.js +0 -151
  351. package/core/k-cli/node_modules/yaml/dist/nodes/Node.d.ts +0 -53
  352. package/core/k-cli/node_modules/yaml/dist/nodes/Node.js +0 -40
  353. package/core/k-cli/node_modules/yaml/dist/nodes/Pair.d.ts +0 -22
  354. package/core/k-cli/node_modules/yaml/dist/nodes/Pair.js +0 -39
  355. package/core/k-cli/node_modules/yaml/dist/nodes/Scalar.d.ts +0 -43
  356. package/core/k-cli/node_modules/yaml/dist/nodes/Scalar.js +0 -27
  357. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLMap.d.ts +0 -53
  358. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLMap.js +0 -147
  359. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +0 -60
  360. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLSeq.js +0 -115
  361. package/core/k-cli/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +0 -4
  362. package/core/k-cli/node_modules/yaml/dist/nodes/addPairToJSMap.js +0 -65
  363. package/core/k-cli/node_modules/yaml/dist/nodes/identity.d.ts +0 -23
  364. package/core/k-cli/node_modules/yaml/dist/nodes/identity.js +0 -53
  365. package/core/k-cli/node_modules/yaml/dist/nodes/toJS.d.ts +0 -29
  366. package/core/k-cli/node_modules/yaml/dist/nodes/toJS.js +0 -39
  367. package/core/k-cli/node_modules/yaml/dist/options.d.ts +0 -350
  368. package/core/k-cli/node_modules/yaml/dist/parse/cst-scalar.d.ts +0 -64
  369. package/core/k-cli/node_modules/yaml/dist/parse/cst-scalar.js +0 -218
  370. package/core/k-cli/node_modules/yaml/dist/parse/cst-stringify.d.ts +0 -8
  371. package/core/k-cli/node_modules/yaml/dist/parse/cst-stringify.js +0 -63
  372. package/core/k-cli/node_modules/yaml/dist/parse/cst-visit.d.ts +0 -39
  373. package/core/k-cli/node_modules/yaml/dist/parse/cst-visit.js +0 -99
  374. package/core/k-cli/node_modules/yaml/dist/parse/cst.d.ts +0 -109
  375. package/core/k-cli/node_modules/yaml/dist/parse/cst.js +0 -112
  376. package/core/k-cli/node_modules/yaml/dist/parse/lexer.d.ts +0 -87
  377. package/core/k-cli/node_modules/yaml/dist/parse/lexer.js +0 -719
  378. package/core/k-cli/node_modules/yaml/dist/parse/line-counter.d.ts +0 -22
  379. package/core/k-cli/node_modules/yaml/dist/parse/line-counter.js +0 -41
  380. package/core/k-cli/node_modules/yaml/dist/parse/parser.d.ts +0 -84
  381. package/core/k-cli/node_modules/yaml/dist/parse/parser.js +0 -972
  382. package/core/k-cli/node_modules/yaml/dist/public-api.d.ts +0 -44
  383. package/core/k-cli/node_modules/yaml/dist/public-api.js +0 -107
  384. package/core/k-cli/node_modules/yaml/dist/schema/Schema.d.ts +0 -17
  385. package/core/k-cli/node_modules/yaml/dist/schema/Schema.js +0 -39
  386. package/core/k-cli/node_modules/yaml/dist/schema/common/map.d.ts +0 -2
  387. package/core/k-cli/node_modules/yaml/dist/schema/common/map.js +0 -19
  388. package/core/k-cli/node_modules/yaml/dist/schema/common/null.d.ts +0 -4
  389. package/core/k-cli/node_modules/yaml/dist/schema/common/null.js +0 -17
  390. package/core/k-cli/node_modules/yaml/dist/schema/common/seq.d.ts +0 -2
  391. package/core/k-cli/node_modules/yaml/dist/schema/common/seq.js +0 -19
  392. package/core/k-cli/node_modules/yaml/dist/schema/common/string.d.ts +0 -2
  393. package/core/k-cli/node_modules/yaml/dist/schema/common/string.js +0 -16
  394. package/core/k-cli/node_modules/yaml/dist/schema/core/bool.d.ts +0 -4
  395. package/core/k-cli/node_modules/yaml/dist/schema/core/bool.js +0 -21
  396. package/core/k-cli/node_modules/yaml/dist/schema/core/float.d.ts +0 -4
  397. package/core/k-cli/node_modules/yaml/dist/schema/core/float.js +0 -47
  398. package/core/k-cli/node_modules/yaml/dist/schema/core/int.d.ts +0 -4
  399. package/core/k-cli/node_modules/yaml/dist/schema/core/int.js +0 -42
  400. package/core/k-cli/node_modules/yaml/dist/schema/core/schema.d.ts +0 -1
  401. package/core/k-cli/node_modules/yaml/dist/schema/core/schema.js +0 -25
  402. package/core/k-cli/node_modules/yaml/dist/schema/json/schema.d.ts +0 -2
  403. package/core/k-cli/node_modules/yaml/dist/schema/json/schema.js +0 -64
  404. package/core/k-cli/node_modules/yaml/dist/schema/json-schema.d.ts +0 -69
  405. package/core/k-cli/node_modules/yaml/dist/schema/tags.d.ts +0 -48
  406. package/core/k-cli/node_modules/yaml/dist/schema/tags.js +0 -99
  407. package/core/k-cli/node_modules/yaml/dist/schema/types.d.ts +0 -92
  408. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +0 -2
  409. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/binary.js +0 -70
  410. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +0 -7
  411. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/bool.js +0 -29
  412. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +0 -4
  413. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/float.js +0 -50
  414. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +0 -5
  415. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/int.js +0 -76
  416. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +0 -9
  417. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/merge.js +0 -68
  418. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +0 -22
  419. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/omap.js +0 -77
  420. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +0 -10
  421. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +0 -82
  422. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +0 -1
  423. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/schema.js +0 -41
  424. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +0 -28
  425. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/set.js +0 -96
  426. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +0 -6
  427. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +0 -105
  428. package/core/k-cli/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +0 -34
  429. package/core/k-cli/node_modules/yaml/dist/stringify/foldFlowLines.js +0 -151
  430. package/core/k-cli/node_modules/yaml/dist/stringify/stringify.d.ts +0 -21
  431. package/core/k-cli/node_modules/yaml/dist/stringify/stringify.js +0 -132
  432. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +0 -17
  433. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyCollection.js +0 -155
  434. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyComment.d.ts +0 -10
  435. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyComment.js +0 -24
  436. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +0 -4
  437. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyDocument.js +0 -87
  438. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +0 -2
  439. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyNumber.js +0 -26
  440. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyPair.d.ts +0 -3
  441. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyPair.js +0 -152
  442. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyString.d.ts +0 -9
  443. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyString.js +0 -338
  444. package/core/k-cli/node_modules/yaml/dist/test-events.d.ts +0 -4
  445. package/core/k-cli/node_modules/yaml/dist/test-events.js +0 -134
  446. package/core/k-cli/node_modules/yaml/dist/util.d.ts +0 -16
  447. package/core/k-cli/node_modules/yaml/dist/util.js +0 -28
  448. package/core/k-cli/node_modules/yaml/dist/visit.d.ts +0 -102
  449. package/core/k-cli/node_modules/yaml/dist/visit.js +0 -236
  450. package/core/k-cli/node_modules/yaml/package.json +0 -97
  451. package/core/k-cli/node_modules/yaml/util.js +0 -2
@@ -1,12 +1,9 @@
1
1
  /**
2
- * TASK_1978 — scaffold diet S2: dispatch prompt ceremony compression.
3
- *
4
- * Verifies the four compressed sub-agent/dispatch ceremony sections in
5
- * prompt.js stay within the ≤800-byte-per-section budget, that every hard
6
- * constraint that existed before the compression is still present (as a
7
- * substring), and that the corresponding dispatch-detail/*.md files (moved
8
- * explanatory prose) exist. Also checks the Shared Module: testing
9
- * injection (sourced from .formation/roles/_shared/modules/testing.yaml).
2
+ * TASK_1978 — scaffold diet S2: sub-agent dispatch prefixes stay within the
3
+ * byte budget and keep every hard constraint; the dispatch-detail files that
4
+ * hold the moved-out explanatory prose exist. Plus the live prompt.js pieces:
5
+ * promptProfile / extract* / splitPromptSections, the Rust check gate, and the
6
+ * TASK_2391 short subagent template.
10
7
  */
11
8
 
12
9
  const test = require('node:test');
@@ -18,24 +15,12 @@ const {
18
15
  buildPrompt,
19
16
  SUBAGENT_PREFIX,
20
17
  buildSubagentWorktreePrefix,
21
- appendCognitiveCheckpoint,
22
- buildTaskContextQuery,
23
- appendAlayaLessons,
24
- deriveTaskStack,
25
- deriveBijaStack,
26
- passesAlayaRelevanceGate,
27
- ALAYA_MIN_COSINE_DEFAULT,
28
- ALAYA_STACK_OVERRIDE_COSINE,
29
- ALAYA_CANDIDATE_POOL,
30
18
  promptProfile,
31
19
  extractRigor,
32
20
  extractComplexity,
33
21
  splitPromptSections,
34
- resolveModules,
35
- appendMemoryContext,
36
22
  hasRustScope,
37
23
  appendRustCheckReminder,
38
- appendWorkflow,
39
24
  applyRustCheckToPrefix,
40
25
  } = require('./prompt');
41
26
 
@@ -122,260 +107,12 @@ test('cross-project worktree prefix ends with a Details pointer to its detail fi
122
107
  );
123
108
  });
124
109
 
125
- // ── Shared Module: testing (sourced from _shared/modules/testing.yaml) ─
126
-
127
- function renderTestingModule() {
128
- const modPath = path.join(ROOT, '.formation', 'roles', '_shared', 'modules', 'testing.yaml');
129
- const raw = fs.readFileSync(modPath, 'utf-8');
130
- const nameMatch = raw.match(/^name:\s*(.+)$/m);
131
- const descMatch = raw.match(/^description:\s*(.+)$/m);
132
- const moduleName = nameMatch ? nameMatch[1].trim() : path.basename(modPath, '.yaml');
133
- const moduleDesc = descMatch ? descMatch[1].trim() : '';
134
- const lines = [`## Shared Module: ${moduleName}`];
135
- if (moduleDesc) { lines.push(moduleDesc); lines.push(''); }
136
- const contentMatch = raw.match(/^content:\n([\s\S]*)$/m);
137
- lines.push(contentMatch ? contentMatch[1].trimEnd() : raw.trimEnd());
138
- return lines.join('\n');
139
- }
140
-
141
- test('Shared Module: testing injection stays within the compressed-section byte budget', () => {
142
- const out = renderTestingModule();
143
- assert.ok(
144
- bytes(out) <= BYTE_BUDGET,
145
- `Shared Module: testing is ${bytes(out)} bytes, expected <= ${BYTE_BUDGET}`
146
- );
147
- });
148
-
149
- test('Shared Module: testing keeps coverage targets and defect-severity rules', () => {
150
- const out = renderTestingModule();
151
- const mustContain = ['>= 80%', '>= 70%', '100%', 'Critical=fix now', 'CI-integrated'];
152
- for (const needle of mustContain) {
153
- assert.ok(out.includes(needle), `Shared Module: testing missing: "${needle}"`);
154
- }
155
- });
156
-
157
- test('Shared Module: testing ends with a Details pointer to its detail file', () => {
158
- const out = renderTestingModule();
159
- assert.match(
160
- out,
161
- /Details: \.formation\/tools\/dispatch-detail\/testing-module\.md \(Read only if needed\)/
162
- );
163
- });
164
-
165
- // ── appendAlayaLessons (TASK_1992: Process lessons via alaya_recall;
166
- // TASK_2101: absolute relevance floor + stack match on top) ──
167
-
168
- const ALAYA_TASK = JSON.stringify({
169
- title: 'Fix appendCortexContext dedup bug',
170
- scope_paths: ['.formation/tools/prompt.js'],
171
- });
172
-
173
- function makeStubCaller(response) {
174
- // 2026-10-10: Alaya lessons are frozen by default; these tests keep covering the renderer.
175
- return Object.assign((toolName, toolArgs) => {
176
- assert.equal(toolName, 'alaya_recall');
177
- assert.equal(toolArgs.mode, 'hybrid');
178
- assert.deepEqual(toolArgs.seed_types, ['failure_seed', 'lesson_seed']);
179
- // TASK_2101: wider candidate pool (post-filtering needs real candidates
180
- // to keep) and the server-side cosine floor.
181
- assert.equal(toolArgs.limit, ALAYA_CANDIDATE_POOL);
182
- assert.equal(toolArgs.min_cosine, ALAYA_MIN_COSINE_DEFAULT);
183
- if (typeof response === 'function') return response(toolArgs);
184
- return response;
185
- }, { __forceAlaya: true });
186
- }
187
-
188
- // High enough to clear ALAYA_STACK_OVERRIDE_COSINE (0.8) — bypasses the
189
- // stack-match half of the gate so these fixtures only exercise the floor
190
- // and the pre-2101 rendering/dedup/cap behavior.
191
- const HIGH_COSINE = 0.95;
192
-
193
- test('appendAlayaLessons renders the section from a stubbed hybrid recall with 3 seeds', () => {
194
- const lines = [];
195
- const stub = makeStubCaller({
196
- mode_effective: 'hybrid',
197
- bijas: [
198
- { id: 'a1', seed_type: 'failure_seed', origin: 'local', content: 'Root cause one.', cosine: HIGH_COSINE },
199
- { id: 'a2', seed_type: 'lesson_seed', origin: 'remote', content: 'Lesson two.', cosine: HIGH_COSINE },
200
- { id: 'a3', seed_type: 'failure_seed', origin: 'remote', content: 'Failure three.', cosine: HIGH_COSINE },
201
- ],
202
- });
203
- appendAlayaLessons(lines, ALAYA_TASK, stub);
204
- const out = lines.join('\n');
205
- assert.ok(out.includes('## Process lessons (Alaya)'));
206
- assert.match(out, /Query: ".+" — 3 seeds \(mode=hybrid\)\./);
207
- assert.ok(out.includes('- **failure_seed** [local] Root cause one.'));
208
- assert.ok(out.includes('- **lesson_seed** [remote] Lesson two.'));
209
- assert.ok(out.includes('- **failure_seed** [remote] Failure three.'));
210
- });
211
-
212
- test('appendAlayaLessons omits the section when the recall is null, empty, or throws', () => {
213
- const nullCase = [];
214
- appendAlayaLessons(nullCase, ALAYA_TASK, makeStubCaller(null));
215
- assert.equal(nullCase.length, 0);
216
-
217
- const emptyCase = [];
218
- appendAlayaLessons(emptyCase, ALAYA_TASK, makeStubCaller({ mode_effective: 'hybrid', bijas: [] }));
219
- assert.equal(emptyCase.length, 0);
220
-
221
- const throwCase = [];
222
- appendAlayaLessons(throwCase, ALAYA_TASK, () => { throw new Error('MCP unavailable'); });
223
- assert.equal(throwCase.length, 0);
224
-
225
- const noQueryCase = [];
226
- appendAlayaLessons(noQueryCase, JSON.stringify({}), makeStubCaller({ bijas: [{ id: 'x', content: 'never called' }] }));
227
- assert.equal(noQueryCase.length, 0);
228
- });
229
-
230
- test('appendAlayaLessons caps the rendered section at 900 chars total', () => {
231
- const lines = [];
232
- // Per-line content is already capped at 220 chars inside appendAlayaLessons,
233
- // so 3 seeds alone stay well under 900 — push the total over budget via a
234
- // long `origin` field (rendered verbatim, uncapped) instead.
235
- const longOrigin = 'origin-'.repeat(60); // ~420 chars
236
- const longContent = 'y'.repeat(220);
237
- const stub = makeStubCaller({
238
- mode_effective: 'hybrid',
239
- bijas: [
240
- { id: 'b1', seed_type: 'failure_seed', origin: longOrigin, content: longContent, cosine: HIGH_COSINE },
241
- { id: 'b2', seed_type: 'lesson_seed', origin: longOrigin, content: longContent, cosine: HIGH_COSINE },
242
- { id: 'b3', seed_type: 'failure_seed', origin: longOrigin, content: longContent, cosine: HIGH_COSINE },
243
- ],
244
- });
245
- appendAlayaLessons(lines, ALAYA_TASK, stub);
246
- const start = lines.indexOf('## Process lessons (Alaya)');
247
- assert.ok(start >= 0, 'section header not found');
248
- const sectionLines = lines.slice(start, lines.length - 1); // drop trailing blank line
249
- const section = sectionLines.join('\n');
250
- assert.ok(section.length <= 900, `section is ${section.length} chars, expected <= 900`);
251
- assert.ok(section.endsWith('…'), 'over-budget section should end with an ellipsis');
252
- });
253
-
254
- test('appendAlayaLessons dedups seeds by id', () => {
255
- const lines = [];
256
- const stub = makeStubCaller({
257
- mode_effective: 'hybrid',
258
- bijas: [
259
- { id: 'dup', seed_type: 'failure_seed', origin: 'local', content: 'First copy.', cosine: HIGH_COSINE },
260
- { id: 'dup', seed_type: 'failure_seed', origin: 'local', content: 'Second copy (duplicate id).', cosine: HIGH_COSINE },
261
- ],
262
- });
263
- appendAlayaLessons(lines, ALAYA_TASK, stub);
264
- const out = lines.join('\n');
265
- assert.match(out, /1 seeds/);
266
- assert.ok(out.includes('First copy.'));
267
- assert.ok(!out.includes('Second copy'));
268
- });
269
-
270
- test('buildTaskContextQuery is the single query builder shared by Cortex and Alaya', () => {
271
- const q = buildTaskContextQuery(ALAYA_TASK);
272
- assert.ok(q && q.includes('prompt'));
273
- assert.equal(buildTaskContextQuery(JSON.stringify({})), null);
274
- });
275
-
276
- // ── TASK_2101: absolute relevance floor (cosine) + stack match ─────────
277
-
278
- test('deriveTaskStack extracts extensions and top path segments from scope_paths', () => {
279
- const stack = deriveTaskStack(['dashboard/src-tauri/src/features/cortex/bija_embedding.rs', '.formation/tools/prompt.js']);
280
- assert.ok(stack.has('rs'));
281
- assert.ok(stack.has('js'));
282
- assert.ok(stack.has('dashboard'));
283
- assert.ok(stack.has('dashboard/src-tauri'));
284
- assert.ok(stack.has('.formation'));
285
- assert.ok(stack.has('.formation/tools'));
286
- assert.equal(deriveTaskStack([]).size, 0);
287
- assert.equal(deriveTaskStack(undefined).size, 0);
288
- });
289
-
290
- test('deriveBijaStack reads tags and source_symbol (file_path:symbol:kind)', () => {
291
- const fromSourceSymbol = deriveBijaStack({
292
- tags: '', source_symbol: 'dashboard/src-tauri/src/features/cortex/bija_embedding.rs:recall_bijas_hybrid_with_vec:function',
293
- });
294
- assert.ok(fromSourceSymbol.has('rs'));
295
- assert.ok(fromSourceSymbol.has('dashboard'));
296
-
297
- const fromTags = deriveBijaStack({ tags: 'unity, csharp', source_symbol: '' });
298
- assert.ok(fromTags.has('unity'));
299
- assert.ok(fromTags.has('csharp'));
300
-
301
- // No signal at all (today's common case pre-hub-upgrade) -> empty, not an error.
302
- assert.equal(deriveBijaStack({}).size, 0);
303
- assert.equal(deriveBijaStack({ tags: '', source_symbol: '' }).size, 0);
304
- });
305
-
306
- test('passesAlayaRelevanceGate: cosine floor alone gates a null/low cosine out', () => {
307
- const taskStack = deriveTaskStack(['.formation/tools/prompt.js']);
308
- assert.equal(passesAlayaRelevanceGate({ cosine: null }, taskStack, ALAYA_MIN_COSINE_DEFAULT), false, 'null cosine (unscored) must fail the floor');
309
- assert.equal(passesAlayaRelevanceGate({ cosine: ALAYA_MIN_COSINE_DEFAULT - 0.01 }, taskStack, ALAYA_MIN_COSINE_DEFAULT), false, 'below-floor cosine must fail');
310
- assert.equal(
311
- passesAlayaRelevanceGate({ cosine: ALAYA_MIN_COSINE_DEFAULT, tags: 'js' }, taskStack, ALAYA_MIN_COSINE_DEFAULT),
312
- true,
313
- 'at-floor cosine with a stack match must pass'
314
- );
315
- });
316
-
317
- test('passesAlayaRelevanceGate: stack mismatch is dropped unless cosine clears the override', () => {
318
- const taskStack = deriveTaskStack(['.formation/tools/prompt.js']); // rs/js/.formation stack
319
- const csharpNoise = { cosine: 0.75, tags: '', source_symbol: 'Assets/Combat/CombatFeedback.cs:Play:method' };
320
- assert.equal(passesAlayaRelevanceGate(csharpNoise, taskStack, ALAYA_MIN_COSINE_DEFAULT), false, 'cross-stack .cs seed above the floor but below the override must be dropped');
321
-
322
- const csharpButVeryRelevant = { ...csharpNoise, cosine: ALAYA_STACK_OVERRIDE_COSINE };
323
- assert.equal(passesAlayaRelevanceGate(csharpButVeryRelevant, taskStack, ALAYA_MIN_COSINE_DEFAULT), true, 'cosine >= override clears a stack mismatch');
324
-
325
- const matchingStack = { cosine: 0.75, tags: 'js', source_symbol: '' };
326
- assert.equal(passesAlayaRelevanceGate(matchingStack, taskStack, ALAYA_MIN_COSINE_DEFAULT), true, 'a real stack overlap needs no override');
327
- });
328
-
329
- test('passesAlayaRelevanceGate: an empty task stack (no scope_paths) skips the stack half, floor still applies', () => {
330
- const emptyTaskStack = deriveTaskStack([]);
331
- assert.equal(passesAlayaRelevanceGate({ cosine: 0.75, tags: 'unrelated' }, emptyTaskStack, ALAYA_MIN_COSINE_DEFAULT), true);
332
- assert.equal(passesAlayaRelevanceGate({ cosine: 0.1, tags: 'unrelated' }, emptyTaskStack, ALAYA_MIN_COSINE_DEFAULT), false);
333
- });
334
-
335
- test('ALAYA_MIN_COSINE_DEFAULT rejects the measured live noise band (TASK_2101 R4: noise 0.656-0.697, on-topic >= 0.709)', () => {
336
- const emptyTaskStack = deriveTaskStack([]);
337
- assert.equal(passesAlayaRelevanceGate({ cosine: 0.697 }, emptyTaskStack, ALAYA_MIN_COSINE_DEFAULT), false, 'top of the measured noise band must fail');
338
- assert.equal(passesAlayaRelevanceGate({ cosine: 0.709 }, emptyTaskStack, ALAYA_MIN_COSINE_DEFAULT), true, 'bottom of the measured on-topic band must pass');
339
- });
340
-
341
- test('appendAlayaLessons drops candidates below the cosine floor or with a stack mismatch; renders nothing when none pass', () => {
342
- const lines = [];
343
- const stub = makeStubCaller({
344
- mode_effective: 'hybrid',
345
- bijas: [
346
- // Below the floor entirely (mirrors the RRF-rank-only noise this card fixes).
347
- { id: 'low_cosine', seed_type: 'failure_seed', origin: 'remote', content: 'TASK_396 combat feel seam: CombatFeedback.Play', cosine: 0.05 },
348
- // Cleared the floor but wrong stack (Unity C# seed on a Rust/JS card) at a cosine well under the override.
349
- { id: 'wrong_stack', seed_type: 'lesson_seed', origin: 'remote', content: 'dear-game-vm deployment is Docker-on-VM', cosine: 0.75, source_symbol: 'infra/game-vm/deploy.cs:Deploy:function' },
350
- // Never scored by the semantic arm at all (fts-only hit).
351
- { id: 'unscored', seed_type: 'failure_seed', origin: 'remote', content: 'Meta App Review requires Instagram OAuth', cosine: null },
352
- ],
353
- });
354
- appendAlayaLessons(lines, ALAYA_TASK, stub);
355
- assert.equal(lines.length, 0, 'zero passing candidates must render nothing, not an empty section');
356
- });
357
-
358
- test('appendAlayaLessons keeps a real stack match even at a moderate (non-override) cosine', () => {
359
- const lines = [];
360
- const stub = makeStubCaller({
361
- mode_effective: 'hybrid',
362
- bijas: [
363
- { id: 'relevant', seed_type: 'failure_seed', origin: 'remote', content: 'get_db_dir cross-boundary failure in synapse connection', cosine: 0.75, tags: 'js' },
364
- ],
365
- });
366
- appendAlayaLessons(lines, ALAYA_TASK, stub);
367
- const out = lines.join('\n');
368
- assert.ok(out.includes('## Process lessons (Alaya)'));
369
- assert.ok(out.includes('get_db_dir cross-boundary failure in synapse connection'));
370
- });
371
-
372
110
  // ── dispatch-detail files exist (the moved-out explanatory prose) ─────
373
111
 
374
112
  test('every dispatch-detail file referenced by a compressed section exists', () => {
375
113
  const files = [
376
114
  'worktree-subagent-mode.md',
377
115
  'cross-project-worktree.md',
378
- 'testing-module.md',
379
116
  ];
380
117
  for (const f of files) {
381
118
  assert.ok(fs.existsSync(detailPath(f)), `missing dispatch-detail file: ${f}`);
@@ -414,72 +151,22 @@ test('elixir.yaml no longer claims a 0-11 strict lifecycle', () => {
414
151
  assert.match(elixir, /dev\/archive\/ansuz\/BOOT_FULL\.md/);
415
152
  });
416
153
 
417
- // ── TASK_1998: two-axis prompt policy (2026-09-22 user decision) ───────
418
- // CONTEXT volume (Cross-Project Context caps, Related Files Preview, Known
419
- // Failures, Project Memory) is driven by `complexity`. PROCESS strictness
420
- // (Working contract vs full ritual) is driven by `rigor`. The two axes are
421
- // independent — a rigor:low/complexity:complex card gets the full Cortex
422
- // Context but only the compact Working contract, and vice versa.
423
-
424
- test('promptProfile: complexity gates Related Files Preview / Known Failures / Project Memory', () => {
425
- for (const rigor of ['low', 'medium', 'high']) {
426
- const p = promptProfile({ rigor, complexity: 'simple' });
427
- assert.equal(p.skipRelatedFilesPreview, true, `rigor=${rigor}`);
428
- assert.equal(p.skipKnownFailures, true, `rigor=${rigor}`);
429
- assert.equal(p.skipProjectMemory, true, `rigor=${rigor}`);
430
- }
154
+ // ── promptProfile: complexity gates the Related Files Preview (dispatch.js) ──
155
+
156
+ test('promptProfile: only a complex card gets the Related Files Preview', () => {
157
+ assert.equal(promptProfile({ complexity: 'simple' }).skipRelatedFilesPreview, true);
431
158
  for (const complexity of ['medium', null, undefined, 'bogus']) {
432
- const p = promptProfile({ rigor: 'medium', complexity });
159
+ const p = promptProfile({ complexity });
160
+ assert.equal(p.complexity, 'medium', `complexity=${complexity}`);
433
161
  assert.equal(p.skipRelatedFilesPreview, true, `complexity=${complexity}`);
434
- assert.equal(p.skipKnownFailures, false, `complexity=${complexity}`);
435
- assert.equal(p.skipProjectMemory, true, `complexity=${complexity}`);
436
- }
437
- const c = promptProfile({ rigor: 'medium', complexity: 'complex' });
438
- assert.equal(c.skipRelatedFilesPreview, false);
439
- assert.equal(c.skipKnownFailures, false);
440
- assert.equal(c.skipProjectMemory, false);
441
- });
442
-
443
- test('TASK_2371: promptProfile has no Cortex fields for any complexity', () => {
444
- for (const complexity of ['simple', 'medium', 'complex']) {
445
- const p = promptProfile({ rigor: 'medium', complexity });
446
- for (const k of Object.keys(p)) assert.ok(!/cortex|CrossProject/i.test(k), `unexpected profile key ${k}`);
447
- }
448
- });
449
-
450
- test('promptProfile: rigor=high uses the same compact ritual as medium (TASK_2371)', () => {
451
- for (const complexity of ['simple', 'medium', 'complex']) {
452
- const p = promptProfile({ rigor: 'high', complexity });
453
- assert.equal(p.rigor, 'high');
454
- assert.equal(p.compactRitual, true, `complexity=${complexity}`);
455
- assert.equal(p.ritualTier, 'medium', `complexity=${complexity}`);
456
- }
457
- });
458
-
459
- test('promptProfile: rigor=low/medium (incl. missing/unrecognized, default) get the compact ritual, with distinct tiers', () => {
460
- const low = promptProfile({ rigor: 'low', complexity: 'medium' });
461
- assert.equal(low.compactRitual, true);
462
- assert.equal(low.ritualTier, 'low');
463
-
464
- for (const rigor of ['medium', null, undefined, 'bogus']) {
465
- const p = promptProfile({ rigor, complexity: 'medium' });
466
- assert.equal(p.compactRitual, true, `rigor=${rigor}`);
467
- assert.equal(p.ritualTier, 'medium', `rigor=${rigor}`);
468
162
  }
163
+ assert.equal(promptProfile({ complexity: 'complex' }).skipRelatedFilesPreview, false);
469
164
  });
470
165
 
471
- test('promptProfile: backwards-compatible string call maps rigor to the given string and complexity to medium', () => {
472
- const viaString = promptProfile('high');
473
- const viaObject = promptProfile({ rigor: 'high', complexity: 'medium' });
474
- assert.deepEqual(viaString, viaObject);
475
- assert.equal(viaString.rigor, 'high');
476
- assert.equal(viaString.complexity, 'medium');
477
-
478
- for (const v of [null, undefined]) {
479
- const p = promptProfile(v);
480
- assert.equal(p.rigor, 'medium');
481
- assert.equal(p.complexity, 'medium');
482
- }
166
+ test('promptProfile: rigor is ignored; a bare string or missing arg is a complexity / the medium default', () => {
167
+ assert.deepEqual(promptProfile({ rigor: 'high', complexity: 'complex' }), promptProfile('complex'));
168
+ assert.deepEqual(promptProfile(), { complexity: 'medium', skipRelatedFilesPreview: true });
169
+ assert.deepEqual(Object.keys(promptProfile({ complexity: 'complex' })).sort(), ['complexity', 'skipRelatedFilesPreview']);
483
170
  });
484
171
 
485
172
  test('extractRigor reads taskData.rigor; null when missing, unparseable, or non-string', () => {
@@ -519,154 +206,6 @@ test('splitPromptSections splits on "## "/"# " headers only, not "### " sub-head
519
206
  assert.ok(sections[0].bytes > 0 && sections[1].bytes > 0);
520
207
  });
521
208
 
522
- // ── rigor tiers: Working contract / short progress note / full ritual ──
523
-
524
- test('rigor low: the six ritual sections collapse into "## Working contract"; Progress Note is dropped entirely', () => {
525
- const taskData = JSON.stringify({ id: 'TASK_TEST', rigor: 'low' });
526
-
527
- const ckLines = [];
528
- appendCognitiveCheckpoint(ckLines, taskData, {});
529
- const ck = ckLines.join('\n');
530
- assert.ok(ck.includes('## Working contract'));
531
- assert.ok(!ck.includes('synapse_inscribe'), 'memory system frozen 2026-10-10: no rune line');
532
- assert.ok(!ck.includes('## Progress Note (brief)'), 'rigor:low should not get the short progress note');
533
- const ritualNeedles = [
534
- 'Before You Start — Cognitive Recall',
535
- `Before You Finish — Don't Let Your Discovery Die`,
536
- '## Cognitive Checkpoint',
537
- ];
538
- for (const needle of ritualNeedles) {
539
- assert.ok(!ck.includes(needle), `rigor:low output should not contain "${needle}"`);
540
- }
541
-
542
- });
543
-
544
- test('rigor medium: "## Working contract" plus a short progress note, no rune-inscribe line (memory frozen)', () => {
545
- const taskData = JSON.stringify({ id: 'TASK_TEST', rigor: 'medium' });
546
-
547
- const ckLines = [];
548
- appendCognitiveCheckpoint(ckLines, taskData, {});
549
- const ck = ckLines.join('\n');
550
- assert.ok(ck.includes('## Working contract'));
551
- assert.ok(ck.includes('## Progress Note (brief)'), 'rigor:medium should get the short progress note');
552
- assert.ok(!ck.includes('synapse_inscribe'), 'memory system frozen 2026-10-10: no rune line');
553
- assert.ok(!ck.includes('## Progress Note (mandatory — write before finishing)'), 'rigor:medium should not get the full Progress Note');
554
- assert.ok(ck.includes('parallel tool calls in ONE turn'), 'rigor:medium should get the concrete parallel-reads batching rule');
555
- assert.ok(ck.includes('one bash command with separators'), 'rigor:medium should get the concrete shell-batching rule');
556
- assert.ok(ck.includes('one command over all N'), 'rigor:medium should get the concrete N-similar-items batching rule');
557
-
558
- });
559
-
560
- test('rigor high: same brief ritual as medium, no mandatory Before You Start / Before You Finish / Cognitive Checkpoint (TASK_2371)', () => {
561
- const taskData = JSON.stringify({ id: 'TASK_TEST', rigor: 'high' });
562
- const ckLines = [];
563
- appendCognitiveCheckpoint(ckLines, taskData, {});
564
- const ck = ckLines.join('\n');
565
- assert.ok(ck.includes('## Working contract'));
566
- assert.ok(ck.includes('## Progress Note (brief)'));
567
- assert.ok(!ck.includes('Cognitive Checkpoint'));
568
- assert.ok(!ck.includes('Before You Start'));
569
- assert.ok(!ck.includes('Before You Finish'));
570
- assert.ok(!ck.includes('Progress Note (mandatory'));
571
- });
572
-
573
- test('a rigor:low subagent prompt (SUBAGENT_PREFIX + Working contract) keeps the worktree hard rules', () => {
574
- const taskData = JSON.stringify({ id: 'TASK_TEST', rigor: 'low' });
575
- const lines = [];
576
- appendCognitiveCheckpoint(lines, taskData, {});
577
- const full = SUBAGENT_PREFIX + lines.join('\n');
578
- assert.ok(full.includes('禁 push'), 'worktree hard rule (no push) missing');
579
- assert.ok(full.includes('刪 worktree'), 'worktree hard rule (no delete worktree) missing');
580
- assert.ok(full.includes('## Working contract'));
581
- });
582
-
583
- // Functional check against the REAL .failure/.memory dirs (no mocking) —
584
- // confirms the section actually appears/disappears in an assembled prompt,
585
- // not just that the profile flag is set correctly.
586
- test('appendMemoryContext: complexity:medium prompt contains "## Known Failures", complexity:simple does not; neither carries "## Project Memory" except complexity:complex', () => {
587
- const mediumTaskData = JSON.stringify({ id: 'TASK_TEST', complexity: 'medium' });
588
- const mediumLines = [];
589
- appendMemoryContext(mediumLines, mediumTaskData, {});
590
- const mediumText = mediumLines.join('\n');
591
- assert.ok(mediumText.includes('## Known Failures'), 'complexity:medium prompt should contain "## Known Failures"');
592
- assert.ok(!mediumText.includes('## Project Memory'), 'complexity:medium prompt should NOT contain "## Project Memory"');
593
-
594
- const simpleTaskData = JSON.stringify({ id: 'TASK_TEST', complexity: 'simple' });
595
- const simpleLines = [];
596
- appendMemoryContext(simpleLines, simpleTaskData, {});
597
- const simpleText = simpleLines.join('\n');
598
- assert.ok(!simpleText.includes('## Known Failures'), 'complexity:simple prompt should NOT contain "## Known Failures"');
599
- assert.ok(!simpleText.includes('## Project Memory'), 'complexity:simple prompt should NOT contain "## Project Memory"');
600
- });
601
-
602
- // ── 3x3 matrix: simple/low, medium/medium, complex/high (task's minimum bar) ──
603
-
604
- test('two-axis matrix: simple/low has no Known Failures and has Working contract', () => {
605
- const taskData = JSON.stringify({ id: 'TASK_TEST', complexity: 'simple', rigor: 'low' });
606
- const memLines = [];
607
- appendMemoryContext(memLines, taskData, {});
608
- assert.ok(!memLines.join('\n').includes('## Known Failures'));
609
- const ckLines = [];
610
- appendCognitiveCheckpoint(ckLines, taskData, {});
611
- assert.ok(ckLines.join('\n').includes('## Working contract'));
612
- });
613
-
614
- test('two-axis matrix: medium/medium has Known Failures and the short progress note', () => {
615
- const taskData = JSON.stringify({ id: 'TASK_TEST', complexity: 'medium', rigor: 'medium' });
616
-
617
- const memLines = [];
618
- appendMemoryContext(memLines, taskData, {});
619
- assert.ok(memLines.join('\n').includes('## Known Failures'));
620
-
621
- const ckLines = [];
622
- appendCognitiveCheckpoint(ckLines, taskData, {});
623
- const ck = ckLines.join('\n');
624
- assert.ok(ck.includes('## Progress Note (brief)'), 'medium/medium should carry the short progress note');
625
- });
626
-
627
- test('two-axis matrix: complex/high has Related Files Preview enabled and the brief ritual', () => {
628
- const profile = promptProfile({ rigor: 'high', complexity: 'complex' });
629
- assert.equal(profile.skipRelatedFilesPreview, false);
630
- const ckLines = [];
631
- appendCognitiveCheckpoint(ckLines, JSON.stringify({ id: 'TASK_TEST', complexity: 'complex', rigor: 'high' }), {});
632
- const ck = ckLines.join('\n');
633
- assert.ok(ck.includes('## Progress Note (brief)'));
634
- assert.ok(!ck.includes('Cognitive Checkpoint'));
635
- });
636
-
637
- // ── TASK_2371: prompt diet ──
638
-
639
- test('TASK_2371: no Cortex / Episodic section can be produced (functions removed, builder output clean)', () => {
640
- const prompt = require('./prompt.js');
641
- assert.equal(prompt.appendCortexContext, undefined);
642
- assert.equal(prompt.appendEpisodicContext, undefined);
643
- const src = fs.readFileSync(path.join(__dirname, 'prompt.js'), 'utf-8');
644
- assert.ok(!src.includes('## Cross-Project Context'));
645
- assert.ok(!src.includes('## Episodic Memory'));
646
- });
647
-
648
- test('TASK_2371: Known Failures drop Heimdall REVERT / removed-system entries and cap at 3', () => {
649
- const lines = [];
650
- appendMemoryContext(lines, JSON.stringify({ id: 'TASK_TEST', complexity: 'complex' }), {});
651
- const text = lines.join('\n');
652
- assert.ok(!/Heimdall|\bREVERT\b|Kuzu|\bNorn\b|thalamus|\breflex\b|Formation squad/.test(text.split('## Project Memory')[0].split('## Known Failures')[1] || ''));
653
- const fail = (text.split('## Known Failures')[1] || '').split(/\n## /)[0];
654
- assert.ok((fail.match(/^- /gm) || []).length <= 3);
655
- });
656
-
657
- test('TASK_2371: loadFailures filter excludes Heimdall/REVERT entries', () => {
658
- const { loadFailures } = require('./memory-loader.js');
659
- const all = loadFailures({ tags: [] });
660
- for (const e of all) assert.ok(!/TASK_1413|TASK_1427|TASK_904/.test(e.id), e.id);
661
- });
662
-
663
- test('TASK_2371: Shared Modules inject only on explicit opt-in tags', () => {
664
- const noTag = resolveModules({ tags: ['auth', 'security', 'test', 'review'], scope_paths: ['src/auth/login.ts'] }, null, ROOT);
665
- assert.deepEqual(noTag, []);
666
- const optIn = resolveModules({ tags: ['security-review'] }, null, ROOT).map((p) => path.basename(p));
667
- assert.deepEqual(optIn, ['security.yaml']);
668
- });
669
-
670
209
  // ── TASK_2082: Rust check reminder for worktree subagents ──────────────
671
210
 
672
211
  test('hasRustScope: true for a .rs file, true for a dashboard/src-tauri/ path, false otherwise', () => {
@@ -727,57 +266,6 @@ test('appendRustCheckReminder: resolved core path is interpolated, no hard-coded
727
266
  assert.ok(!text.includes('C:\\'), 'template must not carry a hard-coded absolute path');
728
267
  });
729
268
 
730
- // Minimal do.yaml-shaped skillDef (real card structure per .formation/unit/do.yaml)
731
- // — enough to exercise appendWorkflow's commit-step branch without paying
732
- // for buildUnitPrompt's other live-project-dependent appends.
733
- const DO_LIKE_SKILL = {
734
- collaboration: {
735
- workflow: [
736
- {
737
- step: '提交變更',
738
- run: 'git add -A && (git commit --no-verify -m "[{task_id}] task completed" || true)',
739
- note: 'worktree 內顯式提交確保 post-complete 只需 merge 不需 recovery commit。',
740
- },
741
- ],
742
- },
743
- };
744
-
745
- test('appendWorkflow: a worktree-subagent card with Rust scope gets the Rust check section after the commit step', () => {
746
- const taskData = JSON.stringify({ id: 'TASK_TEST', scope_paths: ['dashboard/src-tauri/src/x.rs'] });
747
- const lines = [];
748
- appendWorkflow(lines, DO_LIKE_SKILL, { isSubagent: true, corePath: '/core', rustCoreCheck: () => true }, taskData);
749
- const text = lines.join('\n');
750
- assert.ok(text.includes('## Rust check (once, after commit)'));
751
- assert.ok(text.includes('node /core/dev/scripts/rust-verify-worktree.js run <your branch> <test filter>'));
752
- // Fixed by Ansuz review of eb7c3be5d: the section no longer tries to talk
753
- // over hard rule 4 with a "this overrides rule 4" note — that wording
754
- // fix now happens at the prefix+body composition point in dispatch.js
755
- // (applyRustCheckToPrefix), covered separately below.
756
- assert.ok(!text.includes('overrides'), 'section must not claim to override rule 4 by itself anymore');
757
- });
758
-
759
- test('appendWorkflow: a JS-only worktree-subagent card renders no Rust check section (byte-identical to before)', () => {
760
- const taskData = JSON.stringify({ id: 'TASK_TEST', scope_paths: ['dev/scripts/foo.js'] });
761
- const lines = [];
762
- appendWorkflow(lines, DO_LIKE_SKILL, { isSubagent: true, corePath: '/core' }, taskData);
763
- const text = lines.join('\n');
764
- assert.ok(!text.includes('## Rust check'), 'JS-only card must not gain the new section');
765
- // The commit-step block is unchanged: isolated staging note is still the last content.
766
- assert.ok(
767
- text.trimEnd().endsWith(
768
- 'Note: nothing to commit 時靜默跳過(不算失敗);git commit 失敗(如 index.lock 競爭)會自動退避重試兩次,仍失敗則以非零退出 — 此時大聲回報錯誤,不要吞掉。'
769
- )
770
- );
771
- });
772
-
773
- test('appendWorkflow: a shared-tree (non-subagent) Rust-scoped card renders no Rust check section', () => {
774
- const taskData = JSON.stringify({ id: 'TASK_TEST', scope_paths: ['dashboard/src-tauri/src/x.rs'] });
775
- const lines = [];
776
- appendWorkflow(lines, DO_LIKE_SKILL, { corePath: '/core' }, taskData);
777
- const text = lines.join('\n');
778
- assert.ok(!text.includes('## Rust check'), 'shared-tree mode has no isolated worktree to verify against');
779
- });
780
-
781
269
  // ── TASK_2082 defect fix (Ansuz review of eb7c3be5d): fix the contradictory
782
270
  // "Rust 交 Ansuz" hard rule 4 wording at the prefix+body COMPOSITION point
783
271
  // (dispatch.js) instead of relying on a later "overrides rule 4" note in
@@ -811,69 +299,6 @@ test('applyRustCheckToPrefix: also patches the cross-project worktree prefix var
811
299
  assert.ok(patched.includes('Rust 只准跑一次'));
812
300
  });
813
301
 
814
- // ── Role Expertise removal (TASK_2086) ──────────────────────────────────
815
- // appendRoleSkill/loadRoleSkill/ROLE_SKILL_MAP were removed: the extraction
816
- // regex was broken since it shipped (0a09fb2a5) and only ever injected a
817
- // one-line, wrong-stack (Python/FastAPI) role description + dangling
818
- // sub-heading. buildUnitPrompt (formation: unit) and buildLegacyPrompt
819
- // (formation: legacy) were the only two call sites.
820
-
821
- const MINIMAL_SKILL_DEF = { role: { identity: 'You are a developer.', priority: 'ship it' }, behavior: [] };
822
-
823
- function minimalTaskData(role) {
824
- return JSON.stringify({ id: 'TASK_9999', title: 'Test task', role, scope_paths: [] });
825
- }
826
-
827
- test('buildPrompt (unit formation): role=backend produces no "## Role Expertise" section', () => {
828
- const out = buildPrompt({ ...MINIMAL_SKILL_DEF, formation: 'unit' }, 'do it', minimalTaskData('backend'), {});
829
- assert.ok(!out.includes('## Role Expertise'), 'Role Expertise section should be removed');
830
- assert.ok(!out.includes('Python/FastAPI') && !out.includes('FastAPI'), 'wrong-stack Python/FastAPI text should not be injected');
831
- });
832
-
833
- test('buildPrompt (unit formation): role=frontend produces no "## Role Expertise" section', () => {
834
- const out = buildPrompt({ ...MINIMAL_SKILL_DEF, formation: 'unit' }, 'do it', minimalTaskData('frontend'), {});
835
- assert.ok(!out.includes('## Role Expertise'), 'Role Expertise section should be removed');
836
- });
837
-
838
- test('buildPrompt (legacy formation): role=backend produces no "## Role Expertise" section', () => {
839
- const out = buildPrompt({ ...MINIMAL_SKILL_DEF, formation: 'legacy' }, 'do it', minimalTaskData('backend'), {});
840
- assert.ok(!out.includes('## Role Expertise'), 'Role Expertise section should be removed');
841
- });
842
-
843
- // TASK_2252 — appendWorkflow rigor gate must accept taskData as JSON string OR object
844
- // (bare JSON.parse(object) threw, was swallowed, and the rigor:high gate failed open).
845
- const RIGOR_SKILL = { collaboration: { workflow: [{ step: 'Finish', run: 'node .collaboration/core/task-api.js complete {task_id}' }] } };
846
- test('TASK_2252 appendWorkflow rigor gate: string/object/invalid taskData', () => {
847
- const cases = [
848
- ['string rigor:high', JSON.stringify({ id: 'T', rigor: 'high' }), true],
849
- ['object rigor:high', { id: 'T', rigor: 'high' }, true],
850
- ['string rigor:medium (control)', JSON.stringify({ id: 'T', rigor: 'medium' }), false],
851
- ['object rigor:medium (control)', { id: 'T', rigor: 'medium' }, false],
852
- ['raw YAML (unparseable)', 'id: T\nrigor: high\n', false],
853
- ['null', null, false],
854
- ];
855
- for (const [name, td, gated] of cases) {
856
- const lines = [];
857
- appendWorkflow(lines, RIGOR_SKILL, { taskId: 'TASK_X' }, td);
858
- const out = lines.join('\n');
859
- assert.equal(out.includes('rigor: high — 禁止執行 task-api.js complete'), gated, name);
860
- if (!gated) assert.ok(out.includes('Command: node .collaboration/core/task-api.js complete TASK_X'), `${name}: complete step kept`);
861
- }
862
- });
863
- test('TASK_2252 appendWorkflow dispatch_overrides honoured for object taskData too', () => {
864
- const lines = [];
865
- appendWorkflow(lines, { collaboration: { workflow: [] } }, {}, { id: 'T', dispatch_overrides: 'DO NOT COMMIT' });
866
- assert.ok(lines.join('\n').includes('DO NOT COMMIT'));
867
- });
868
-
869
- test('memory frozen (2026-10-10): a caller without __forceAlaya renders no Alaya section and makes no MCP call', () => {
870
- const lines = [];
871
- let called = false;
872
- appendAlayaLessons(lines, ALAYA_TASK, () => { called = true; return { bijas: [{ id: 'x', content: 'y', cosine: 0.99 }] }; });
873
- assert.equal(called, false);
874
- assert.equal(lines.join('\n').includes('Process lessons (Alaya)'), false);
875
- });
876
-
877
302
  // ── TASK_2391: subagent dispatch prompt is a short template ─────────────
878
303
  function loadDoSkill() {
879
304
  return require('js-yaml').load(fs.readFileSync(path.join(__dirname, '..', 'unit', 'do.yaml'), 'utf8'));
@@ -895,10 +320,17 @@ test('TASK_2391: subagent prompt keeps card + commit rule + report, drops boiler
895
320
  assert.ok(body.length < 2500, `body too long: ${body.length}`);
896
321
  });
897
322
 
898
- test('TASK_2391: subagent prompt gets the Rust check only for a Rust-scoped card; non-subagent path unchanged', () => {
323
+ test('TASK_2391: subagent prompt gets the Rust check only for a Rust-scoped card', () => {
899
324
  const rustCard = JSON.stringify({ id: 'TASK_9002', title: 'R', scope_paths: ['dashboard/src-tauri/src/x.rs'] });
900
325
  const withRust = buildPrompt(loadDoSkill(), 'TASK_9002', rustCard, { isSubagent: true, taskId: 'TASK_9002', rustCoreCheck: () => true });
901
326
  assert.ok(withRust.includes('## Rust check (once, after commit)'));
902
- const formation = buildPrompt(loadDoSkill(), 'TASK_9002', rustCard, {});
903
- assert.ok(formation.includes('## Code Minimalism') && formation.includes('## Workflow'));
327
+ });
328
+
329
+ test('buildPrompt rejects squad/legion skills with a clear error instead of returning an empty prompt', () => {
330
+ for (const formation of ['squad', 'legion']) {
331
+ assert.throws(
332
+ () => buildPrompt({ formation, name: 'x' }, 'TASK_9003', null, { isSubagent: true }),
333
+ new RegExp(`Formation '${formation}'.*retired`)
334
+ );
335
+ }
904
336
  });