kenaz 0.3.3 → 0.3.5

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 (413) 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 +14 -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/spec/task_operations.parity.test.js +0 -1
  44. package/core/.formation/tests/hello.txt +2 -2
  45. package/core/.formation/tools/dashboard-models-chain.test.js +0 -6
  46. package/core/.formation/tools/dispatch-detail/cross-project-worktree.md +1 -9
  47. package/core/.formation/tools/dispatch-detail/worktree-subagent-mode.md +2 -2
  48. package/core/.formation/tools/dispatch.js +28 -549
  49. package/core/.formation/tools/mcp-allowlist.test.js +0 -1
  50. package/core/.formation/tools/post-complete/task2345.test.js +0 -5
  51. package/core/.formation/tools/pre-dispatch-snapshot.test.js +0 -100
  52. package/core/.formation/tools/prompt.js +29 -1623
  53. package/core/.formation/tools/prompt.test.js +26 -594
  54. package/core/.kenaz/knowledge/ladybug_2c51da1e_shadow_file_frame_group.patch +163 -163
  55. package/core/.kenaz/knowledge/ladybug_30cf85690e_shadow_page_read_during_checkpoint.patch +393 -393
  56. package/core/.kenaz/knowledge/ladybug_7a17858d3a_node_group_delete_lock.patch +102 -102
  57. package/core/.kenaz/knowledge/ladybug_926a0ba1_column_checkpoint.patch +412 -412
  58. package/core/.kenaz/knowledge/ladybug_a346c4c4b6_pk_index_header_pages.patch +144 -144
  59. package/core/.kenaz/knowledge/ladybug_ba5f38815b_csr_node_group.patch +86 -86
  60. package/core/.kenaz/muninn_episode_write.ps1 +17 -17
  61. package/core/.kenaz/specialist/field_report_watermark.json +1 -1
  62. package/core/.kenaz/specialist/memory_guard_fired.json +1 -1
  63. package/core/.kenaz/specialist/memory_guard_trigger_cache.json +1 -1
  64. package/core/.kenaz/specialist/t1777_probe.txt +1 -1
  65. package/core/.matrix/index.matrix +5 -5
  66. package/core/.specialist/tools/__tests__/freya-cli-contract.test.js +0 -1
  67. package/core/KENAZ_CORE_VERSION +1 -1
  68. package/core/dev/ANSUZ_STARTUP_INJECTION_REVIEW.md +355 -355
  69. package/core/dev/JEV_INTEGRATION_PLAN.md +189 -189
  70. package/core/dev/design/matrix_format_EXAMPLE_memory.matrix +13 -13
  71. package/core/dev/design/matrix_format_EXAMPLE_project_status.matrix +9 -9
  72. package/core/dev/design/matrix_format_EXAMPLE_tasks.matrix +14 -14
  73. package/core/dev/design/matrix_v2_EXAMPLE.matrix +67 -67
  74. package/core/dev/jev-eval/ACTIVE_CORRECTION.md +52 -52
  75. package/core/dev/jev-eval/CONTEXT_REVIEW.md +31 -31
  76. package/core/dev/jev-eval/EVALUATION_STATUS.md +39 -39
  77. package/core/dev/jev-eval/HISTORICAL_CORPUS.md +33 -33
  78. package/core/dev/jev-eval/README.md +99 -99
  79. package/core/dev/jev-eval/THALAMUS_RANKING.md +58 -58
  80. package/core/dev/jev-eval/reports/annotation-pilot-2026-09-20.json +32 -32
  81. package/core/dev/jev-eval/reports/context-review-2026-09-20.json +48 -48
  82. package/core/dev/jev-eval/reports/history-corpus-2026-09-20.json +52 -52
  83. package/core/dev/pipeline/SELF_ENHANCEMENT_STATUS.json.bak +47 -47
  84. package/core/dev/pipeline/tasks/.gitkeep +1 -1
  85. package/core/dev/pipeline/test_results/TASK_TEST_PARALLEL_002_result.txt +27 -27
  86. package/core/dev/scripts/init_git.sh +0 -0
  87. package/core/dev/scripts/init_project.sh +0 -0
  88. package/core/dev/scripts/legacy/dev_agent_scheduler.ps1.bak +536 -536
  89. package/core/dev/scripts/legacy/multi_agent_scheduler.ps1.bak +1978 -1978
  90. package/core/dev/scripts/matrix/src/cli/commands/list-tags.ts.wip +140 -140
  91. package/core/dev/scripts/matrix/src/cli/commands/manage-tags.ts.wip +173 -173
  92. package/core/dev/scripts/matrix/src/cli/commands/stats.ts.wip +168 -168
  93. package/core/dev/scripts/matrix/src/cli/commands/tokens.ts.wip +126 -126
  94. package/core/dev/scripts/multi_agent_scheduler.sh +0 -0
  95. package/core/dev/scripts/run_once.sh +0 -0
  96. package/core/dev/scripts/setup_mcp.sh +0 -0
  97. package/core/dev/scripts/setup_rag.sh +0 -0
  98. package/core/dev/scripts/start_dev_agent.sh +0 -0
  99. package/core/dev/scripts/start_multi_agent.sh +0 -0
  100. package/core/dev/scripts/sync_task_queue.sh +0 -0
  101. package/core/plugins/kenaz/commands/Amelia.md +1 -1
  102. package/core/plugins/kenaz/commands/Ansuz.md +15 -3
  103. package/core/plugins/kenaz/scripts/kenaz-mode.js +11 -1
  104. package/core/plugins/kenaz/scripts/sync.js +6 -2
  105. package/core/plugins/kenaz/scripts/ygg.js +13 -1
  106. package/core/plugins/kenaz/skills/product_manager/SKILL.md +12 -12
  107. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/charts.csv +26 -26
  108. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/colors.csv +97 -97
  109. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/icons.csv +101 -101
  110. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/landing.csv +31 -31
  111. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/products.csv +96 -96
  112. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/react-performance.csv +45 -45
  113. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -54
  114. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -53
  115. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -56
  116. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -53
  117. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -53
  118. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -51
  119. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -59
  120. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -52
  121. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/react.csv +54 -54
  122. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -61
  123. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -54
  124. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -51
  125. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -50
  126. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/styles.csv +68 -68
  127. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/typography.csv +57 -57
  128. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -101
  129. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/ux-guidelines.csv +99 -99
  130. package/core/plugins/kenaz/skills/ui-ux-pro-max/data/web-interface.csv +31 -31
  131. package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/core.py +253 -253
  132. package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/design_system.py +1067 -1067
  133. package/core/plugins/kenaz/skills/ui-ux-pro-max/scripts/search.py +106 -106
  134. package/lib/cli.js +11 -4
  135. package/package.json +11 -7
  136. package/vendor/install-kenaz-cli.js +18 -7
  137. package/core/.formation/tools/broadcast.js +0 -103
  138. package/core/.formation/tools/dispatch-dryrun.test.js +0 -54
  139. package/core/.formation/tools/dispatch-notifier.js +0 -84
  140. package/core/.formation/tools/formations.js +0 -1203
  141. package/core/.formation/tools/headless-branch-recovery.test.js +0 -64
  142. package/core/.formation/tools/headless-dryrun.test.js +0 -79
  143. package/core/.formation/tools/headless-v2.js +0 -659
  144. package/core/.formation/tools/headless.js +0 -1071
  145. package/core/.formation/tools/legacy-scheduler.js +0 -1994
  146. package/core/.formation/tools/logger.js +0 -273
  147. package/core/.formation/tools/memory-loader.js +0 -422
  148. package/core/.formation/tools/process-state.js +0 -33
  149. package/core/.formation/tools/remote-conflict.js +0 -98
  150. package/core/.formation/tools/runner.js +0 -1332
  151. package/core/.formation/tools/task-utils.js +0 -344
  152. package/core/.formation/tools/task2028-headless-worktree.test.js +0 -112
  153. package/core/.formation/tools/tests/headless-mcp-args-plumbing.test.js +0 -123
  154. package/core/.formation/tools/worktree-leak.test.js +0 -162
  155. package/core/k-cli/dist/alaya/run.js +0 -91
  156. package/core/k-cli/dist/core/output.js +0 -24
  157. package/core/k-cli/dist/core/process.js +0 -38
  158. package/core/k-cli/dist/core/project.js +0 -80
  159. package/core/k-cli/dist/core/spawn.js +0 -268
  160. package/core/k-cli/dist/core/types.js +0 -2
  161. package/core/k-cli/dist/dashboard/update.js +0 -53
  162. package/core/k-cli/dist/dashboard/version.js +0 -20
  163. package/core/k-cli/dist/dispatch/run.js +0 -241
  164. package/core/k-cli/dist/dispatch/status.js +0 -103
  165. package/core/k-cli/dist/index.js +0 -283
  166. package/core/k-cli/dist/project/initialize.js +0 -301
  167. package/core/k-cli/dist/project/install.js +0 -89
  168. package/core/k-cli/dist/project/status.js +0 -138
  169. package/core/k-cli/dist/specialist/list.js +0 -100
  170. package/core/k-cli/dist/specialist/run.js +0 -93
  171. package/core/k-cli/dist/task/create.js +0 -194
  172. package/core/k-cli/dist/task/delete.js +0 -98
  173. package/core/k-cli/dist/task/get.js +0 -55
  174. package/core/k-cli/dist/task/list.js +0 -58
  175. package/core/k-cli/dist/task/submit.js +0 -156
  176. package/core/k-cli/dist/ygg/run.js +0 -51
  177. package/core/k-cli/node_modules/.bin/yaml +0 -16
  178. package/core/k-cli/node_modules/.bin/yaml.cmd +0 -17
  179. package/core/k-cli/node_modules/.bin/yaml.ps1 +0 -28
  180. package/core/k-cli/node_modules/.package-lock.json +0 -23
  181. package/core/k-cli/node_modules/yaml/LICENSE +0 -13
  182. package/core/k-cli/node_modules/yaml/README.md +0 -172
  183. package/core/k-cli/node_modules/yaml/bin.mjs +0 -11
  184. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-collection.js +0 -88
  185. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-doc.js +0 -43
  186. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-node.js +0 -109
  187. package/core/k-cli/node_modules/yaml/browser/dist/compose/compose-scalar.js +0 -86
  188. package/core/k-cli/node_modules/yaml/browser/dist/compose/composer.js +0 -217
  189. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-map.js +0 -115
  190. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-scalar.js +0 -198
  191. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-block-seq.js +0 -49
  192. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-end.js +0 -37
  193. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-flow-collection.js +0 -207
  194. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-flow-scalar.js +0 -223
  195. package/core/k-cli/node_modules/yaml/browser/dist/compose/resolve-props.js +0 -146
  196. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-contains-newline.js +0 -34
  197. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-empty-scalar-position.js +0 -26
  198. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-flow-indent-check.js +0 -15
  199. package/core/k-cli/node_modules/yaml/browser/dist/compose/util-map-includes.js +0 -13
  200. package/core/k-cli/node_modules/yaml/browser/dist/doc/Document.js +0 -335
  201. package/core/k-cli/node_modules/yaml/browser/dist/doc/anchors.js +0 -71
  202. package/core/k-cli/node_modules/yaml/browser/dist/doc/applyReviver.js +0 -55
  203. package/core/k-cli/node_modules/yaml/browser/dist/doc/createNode.js +0 -88
  204. package/core/k-cli/node_modules/yaml/browser/dist/doc/directives.js +0 -176
  205. package/core/k-cli/node_modules/yaml/browser/dist/errors.js +0 -57
  206. package/core/k-cli/node_modules/yaml/browser/dist/index.js +0 -17
  207. package/core/k-cli/node_modules/yaml/browser/dist/log.js +0 -11
  208. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Alias.js +0 -114
  209. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Collection.js +0 -147
  210. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Node.js +0 -38
  211. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Pair.js +0 -36
  212. package/core/k-cli/node_modules/yaml/browser/dist/nodes/Scalar.js +0 -24
  213. package/core/k-cli/node_modules/yaml/browser/dist/nodes/YAMLMap.js +0 -144
  214. package/core/k-cli/node_modules/yaml/browser/dist/nodes/YAMLSeq.js +0 -113
  215. package/core/k-cli/node_modules/yaml/browser/dist/nodes/addPairToJSMap.js +0 -63
  216. package/core/k-cli/node_modules/yaml/browser/dist/nodes/identity.js +0 -36
  217. package/core/k-cli/node_modules/yaml/browser/dist/nodes/toJS.js +0 -37
  218. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-scalar.js +0 -214
  219. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-stringify.js +0 -61
  220. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst-visit.js +0 -97
  221. package/core/k-cli/node_modules/yaml/browser/dist/parse/cst.js +0 -98
  222. package/core/k-cli/node_modules/yaml/browser/dist/parse/lexer.js +0 -717
  223. package/core/k-cli/node_modules/yaml/browser/dist/parse/line-counter.js +0 -39
  224. package/core/k-cli/node_modules/yaml/browser/dist/parse/parser.js +0 -967
  225. package/core/k-cli/node_modules/yaml/browser/dist/public-api.js +0 -102
  226. package/core/k-cli/node_modules/yaml/browser/dist/schema/Schema.js +0 -37
  227. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/map.js +0 -17
  228. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/null.js +0 -15
  229. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/seq.js +0 -17
  230. package/core/k-cli/node_modules/yaml/browser/dist/schema/common/string.js +0 -14
  231. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/bool.js +0 -19
  232. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/float.js +0 -43
  233. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/int.js +0 -38
  234. package/core/k-cli/node_modules/yaml/browser/dist/schema/core/schema.js +0 -23
  235. package/core/k-cli/node_modules/yaml/browser/dist/schema/json/schema.js +0 -62
  236. package/core/k-cli/node_modules/yaml/browser/dist/schema/tags.js +0 -96
  237. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/binary.js +0 -58
  238. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/bool.js +0 -26
  239. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/float.js +0 -46
  240. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/int.js +0 -71
  241. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/merge.js +0 -64
  242. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/omap.js +0 -74
  243. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/pairs.js +0 -78
  244. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/schema.js +0 -39
  245. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/set.js +0 -93
  246. package/core/k-cli/node_modules/yaml/browser/dist/schema/yaml-1.1/timestamp.js +0 -101
  247. package/core/k-cli/node_modules/yaml/browser/dist/stringify/foldFlowLines.js +0 -146
  248. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringify.js +0 -129
  249. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyCollection.js +0 -153
  250. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyComment.js +0 -20
  251. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyDocument.js +0 -85
  252. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyNumber.js +0 -24
  253. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyPair.js +0 -150
  254. package/core/k-cli/node_modules/yaml/browser/dist/stringify/stringifyString.js +0 -336
  255. package/core/k-cli/node_modules/yaml/browser/dist/util.js +0 -11
  256. package/core/k-cli/node_modules/yaml/browser/dist/visit.js +0 -233
  257. package/core/k-cli/node_modules/yaml/browser/index.js +0 -5
  258. package/core/k-cli/node_modules/yaml/browser/package.json +0 -3
  259. package/core/k-cli/node_modules/yaml/dist/cli.d.ts +0 -8
  260. package/core/k-cli/node_modules/yaml/dist/cli.mjs +0 -201
  261. package/core/k-cli/node_modules/yaml/dist/compose/compose-collection.d.ts +0 -11
  262. package/core/k-cli/node_modules/yaml/dist/compose/compose-collection.js +0 -90
  263. package/core/k-cli/node_modules/yaml/dist/compose/compose-doc.d.ts +0 -7
  264. package/core/k-cli/node_modules/yaml/dist/compose/compose-doc.js +0 -45
  265. package/core/k-cli/node_modules/yaml/dist/compose/compose-node.d.ts +0 -29
  266. package/core/k-cli/node_modules/yaml/dist/compose/compose-node.js +0 -112
  267. package/core/k-cli/node_modules/yaml/dist/compose/compose-scalar.d.ts +0 -5
  268. package/core/k-cli/node_modules/yaml/dist/compose/compose-scalar.js +0 -88
  269. package/core/k-cli/node_modules/yaml/dist/compose/composer.d.ts +0 -63
  270. package/core/k-cli/node_modules/yaml/dist/compose/composer.js +0 -222
  271. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-map.d.ts +0 -6
  272. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-map.js +0 -117
  273. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-scalar.d.ts +0 -11
  274. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-scalar.js +0 -200
  275. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-seq.d.ts +0 -6
  276. package/core/k-cli/node_modules/yaml/dist/compose/resolve-block-seq.js +0 -51
  277. package/core/k-cli/node_modules/yaml/dist/compose/resolve-end.d.ts +0 -6
  278. package/core/k-cli/node_modules/yaml/dist/compose/resolve-end.js +0 -39
  279. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-collection.d.ts +0 -7
  280. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-collection.js +0 -209
  281. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-scalar.d.ts +0 -10
  282. package/core/k-cli/node_modules/yaml/dist/compose/resolve-flow-scalar.js +0 -225
  283. package/core/k-cli/node_modules/yaml/dist/compose/resolve-props.d.ts +0 -23
  284. package/core/k-cli/node_modules/yaml/dist/compose/resolve-props.js +0 -148
  285. package/core/k-cli/node_modules/yaml/dist/compose/util-contains-newline.d.ts +0 -2
  286. package/core/k-cli/node_modules/yaml/dist/compose/util-contains-newline.js +0 -36
  287. package/core/k-cli/node_modules/yaml/dist/compose/util-empty-scalar-position.d.ts +0 -2
  288. package/core/k-cli/node_modules/yaml/dist/compose/util-empty-scalar-position.js +0 -28
  289. package/core/k-cli/node_modules/yaml/dist/compose/util-flow-indent-check.d.ts +0 -3
  290. package/core/k-cli/node_modules/yaml/dist/compose/util-flow-indent-check.js +0 -17
  291. package/core/k-cli/node_modules/yaml/dist/compose/util-map-includes.d.ts +0 -4
  292. package/core/k-cli/node_modules/yaml/dist/compose/util-map-includes.js +0 -15
  293. package/core/k-cli/node_modules/yaml/dist/doc/Document.d.ts +0 -141
  294. package/core/k-cli/node_modules/yaml/dist/doc/Document.js +0 -337
  295. package/core/k-cli/node_modules/yaml/dist/doc/anchors.d.ts +0 -24
  296. package/core/k-cli/node_modules/yaml/dist/doc/anchors.js +0 -76
  297. package/core/k-cli/node_modules/yaml/dist/doc/applyReviver.d.ts +0 -9
  298. package/core/k-cli/node_modules/yaml/dist/doc/applyReviver.js +0 -57
  299. package/core/k-cli/node_modules/yaml/dist/doc/createNode.d.ts +0 -17
  300. package/core/k-cli/node_modules/yaml/dist/doc/createNode.js +0 -90
  301. package/core/k-cli/node_modules/yaml/dist/doc/directives.d.ts +0 -49
  302. package/core/k-cli/node_modules/yaml/dist/doc/directives.js +0 -178
  303. package/core/k-cli/node_modules/yaml/dist/errors.d.ts +0 -21
  304. package/core/k-cli/node_modules/yaml/dist/errors.js +0 -62
  305. package/core/k-cli/node_modules/yaml/dist/index.d.ts +0 -25
  306. package/core/k-cli/node_modules/yaml/dist/index.js +0 -50
  307. package/core/k-cli/node_modules/yaml/dist/log.d.ts +0 -3
  308. package/core/k-cli/node_modules/yaml/dist/log.js +0 -19
  309. package/core/k-cli/node_modules/yaml/dist/nodes/Alias.d.ts +0 -29
  310. package/core/k-cli/node_modules/yaml/dist/nodes/Alias.js +0 -116
  311. package/core/k-cli/node_modules/yaml/dist/nodes/Collection.d.ts +0 -73
  312. package/core/k-cli/node_modules/yaml/dist/nodes/Collection.js +0 -151
  313. package/core/k-cli/node_modules/yaml/dist/nodes/Node.d.ts +0 -53
  314. package/core/k-cli/node_modules/yaml/dist/nodes/Node.js +0 -40
  315. package/core/k-cli/node_modules/yaml/dist/nodes/Pair.d.ts +0 -22
  316. package/core/k-cli/node_modules/yaml/dist/nodes/Pair.js +0 -39
  317. package/core/k-cli/node_modules/yaml/dist/nodes/Scalar.d.ts +0 -43
  318. package/core/k-cli/node_modules/yaml/dist/nodes/Scalar.js +0 -27
  319. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLMap.d.ts +0 -53
  320. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLMap.js +0 -147
  321. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLSeq.d.ts +0 -60
  322. package/core/k-cli/node_modules/yaml/dist/nodes/YAMLSeq.js +0 -115
  323. package/core/k-cli/node_modules/yaml/dist/nodes/addPairToJSMap.d.ts +0 -4
  324. package/core/k-cli/node_modules/yaml/dist/nodes/addPairToJSMap.js +0 -65
  325. package/core/k-cli/node_modules/yaml/dist/nodes/identity.d.ts +0 -23
  326. package/core/k-cli/node_modules/yaml/dist/nodes/identity.js +0 -53
  327. package/core/k-cli/node_modules/yaml/dist/nodes/toJS.d.ts +0 -29
  328. package/core/k-cli/node_modules/yaml/dist/nodes/toJS.js +0 -39
  329. package/core/k-cli/node_modules/yaml/dist/options.d.ts +0 -350
  330. package/core/k-cli/node_modules/yaml/dist/parse/cst-scalar.d.ts +0 -64
  331. package/core/k-cli/node_modules/yaml/dist/parse/cst-scalar.js +0 -218
  332. package/core/k-cli/node_modules/yaml/dist/parse/cst-stringify.d.ts +0 -8
  333. package/core/k-cli/node_modules/yaml/dist/parse/cst-stringify.js +0 -63
  334. package/core/k-cli/node_modules/yaml/dist/parse/cst-visit.d.ts +0 -39
  335. package/core/k-cli/node_modules/yaml/dist/parse/cst-visit.js +0 -99
  336. package/core/k-cli/node_modules/yaml/dist/parse/cst.d.ts +0 -109
  337. package/core/k-cli/node_modules/yaml/dist/parse/cst.js +0 -112
  338. package/core/k-cli/node_modules/yaml/dist/parse/lexer.d.ts +0 -87
  339. package/core/k-cli/node_modules/yaml/dist/parse/lexer.js +0 -719
  340. package/core/k-cli/node_modules/yaml/dist/parse/line-counter.d.ts +0 -22
  341. package/core/k-cli/node_modules/yaml/dist/parse/line-counter.js +0 -41
  342. package/core/k-cli/node_modules/yaml/dist/parse/parser.d.ts +0 -84
  343. package/core/k-cli/node_modules/yaml/dist/parse/parser.js +0 -972
  344. package/core/k-cli/node_modules/yaml/dist/public-api.d.ts +0 -44
  345. package/core/k-cli/node_modules/yaml/dist/public-api.js +0 -107
  346. package/core/k-cli/node_modules/yaml/dist/schema/Schema.d.ts +0 -17
  347. package/core/k-cli/node_modules/yaml/dist/schema/Schema.js +0 -39
  348. package/core/k-cli/node_modules/yaml/dist/schema/common/map.d.ts +0 -2
  349. package/core/k-cli/node_modules/yaml/dist/schema/common/map.js +0 -19
  350. package/core/k-cli/node_modules/yaml/dist/schema/common/null.d.ts +0 -4
  351. package/core/k-cli/node_modules/yaml/dist/schema/common/null.js +0 -17
  352. package/core/k-cli/node_modules/yaml/dist/schema/common/seq.d.ts +0 -2
  353. package/core/k-cli/node_modules/yaml/dist/schema/common/seq.js +0 -19
  354. package/core/k-cli/node_modules/yaml/dist/schema/common/string.d.ts +0 -2
  355. package/core/k-cli/node_modules/yaml/dist/schema/common/string.js +0 -16
  356. package/core/k-cli/node_modules/yaml/dist/schema/core/bool.d.ts +0 -4
  357. package/core/k-cli/node_modules/yaml/dist/schema/core/bool.js +0 -21
  358. package/core/k-cli/node_modules/yaml/dist/schema/core/float.d.ts +0 -4
  359. package/core/k-cli/node_modules/yaml/dist/schema/core/float.js +0 -47
  360. package/core/k-cli/node_modules/yaml/dist/schema/core/int.d.ts +0 -4
  361. package/core/k-cli/node_modules/yaml/dist/schema/core/int.js +0 -42
  362. package/core/k-cli/node_modules/yaml/dist/schema/core/schema.d.ts +0 -1
  363. package/core/k-cli/node_modules/yaml/dist/schema/core/schema.js +0 -25
  364. package/core/k-cli/node_modules/yaml/dist/schema/json/schema.d.ts +0 -2
  365. package/core/k-cli/node_modules/yaml/dist/schema/json/schema.js +0 -64
  366. package/core/k-cli/node_modules/yaml/dist/schema/json-schema.d.ts +0 -69
  367. package/core/k-cli/node_modules/yaml/dist/schema/tags.d.ts +0 -48
  368. package/core/k-cli/node_modules/yaml/dist/schema/tags.js +0 -99
  369. package/core/k-cli/node_modules/yaml/dist/schema/types.d.ts +0 -92
  370. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/binary.d.ts +0 -2
  371. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/binary.js +0 -70
  372. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/bool.d.ts +0 -7
  373. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/bool.js +0 -29
  374. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/float.d.ts +0 -4
  375. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/float.js +0 -50
  376. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/int.d.ts +0 -5
  377. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/int.js +0 -76
  378. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/merge.d.ts +0 -9
  379. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/merge.js +0 -68
  380. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/omap.d.ts +0 -22
  381. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/omap.js +0 -77
  382. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/pairs.d.ts +0 -10
  383. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/pairs.js +0 -82
  384. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/schema.d.ts +0 -1
  385. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/schema.js +0 -41
  386. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/set.d.ts +0 -28
  387. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/set.js +0 -96
  388. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/timestamp.d.ts +0 -6
  389. package/core/k-cli/node_modules/yaml/dist/schema/yaml-1.1/timestamp.js +0 -105
  390. package/core/k-cli/node_modules/yaml/dist/stringify/foldFlowLines.d.ts +0 -34
  391. package/core/k-cli/node_modules/yaml/dist/stringify/foldFlowLines.js +0 -151
  392. package/core/k-cli/node_modules/yaml/dist/stringify/stringify.d.ts +0 -21
  393. package/core/k-cli/node_modules/yaml/dist/stringify/stringify.js +0 -132
  394. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyCollection.d.ts +0 -17
  395. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyCollection.js +0 -155
  396. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyComment.d.ts +0 -10
  397. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyComment.js +0 -24
  398. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyDocument.d.ts +0 -4
  399. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyDocument.js +0 -87
  400. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyNumber.d.ts +0 -2
  401. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyNumber.js +0 -26
  402. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyPair.d.ts +0 -3
  403. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyPair.js +0 -152
  404. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyString.d.ts +0 -9
  405. package/core/k-cli/node_modules/yaml/dist/stringify/stringifyString.js +0 -338
  406. package/core/k-cli/node_modules/yaml/dist/test-events.d.ts +0 -4
  407. package/core/k-cli/node_modules/yaml/dist/test-events.js +0 -134
  408. package/core/k-cli/node_modules/yaml/dist/util.d.ts +0 -16
  409. package/core/k-cli/node_modules/yaml/dist/util.js +0 -28
  410. package/core/k-cli/node_modules/yaml/dist/visit.d.ts +0 -102
  411. package/core/k-cli/node_modules/yaml/dist/visit.js +0 -236
  412. package/core/k-cli/node_modules/yaml/package.json +0 -97
  413. 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
  });