@ngockhoale/ukit 3.0.0 → 3.0.2

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 (445) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/manifests/documentation.yaml +75 -64
  3. package/manifests/engineConformance.yaml +32 -0
  4. package/manifests/hostCapabilities.yaml +2 -2
  5. package/manifests/instructionRules.yaml +55 -55
  6. package/manifests/platform.full.yaml +30 -4
  7. package/manifests/platform.user.yaml +4 -4
  8. package/package.json +8 -7
  9. package/scripts/bench/v3-ceremony.mjs +214 -0
  10. package/scripts/install/sync-installed-mirror.mjs +3 -3
  11. package/scripts/perf/audit-perf.mjs +9 -9
  12. package/scripts/perf/perf-findings.json +4 -4
  13. package/scripts/perf/perf-measure.md +20 -20
  14. package/src/cli/commands/doctor.js +38 -2
  15. package/src/core/buildPlan.js +3 -3
  16. package/src/core/compact/contextBudget.js +2 -2
  17. package/src/core/compact/threshold.js +3 -3
  18. package/src/core/docContracts.js +17 -17
  19. package/src/core/ensureGitignore.js +1 -1
  20. package/src/core/executionContracts.js +42 -2
  21. package/src/core/fileOps.js +3 -3
  22. package/src/core/gatewayProbe.js +2 -2
  23. package/src/core/gatewayResilienceEnv.js +2 -2
  24. package/src/core/handoffDocValidator.js +152 -0
  25. package/src/core/output/index.js +1 -1
  26. package/src/core/paths.js +2 -1
  27. package/src/core/reviewPanelAggregate.js +120 -0
  28. package/src/core/runInstallPipeline.js +6 -4
  29. package/src/core/runtimeConfig.js +13 -6
  30. package/src/core/sensitiveValueScanner.js +1 -1
  31. package/src/core/taskBudgetValidator.js +1 -1
  32. package/src/core/unattendedDoctor.js +1 -1
  33. package/src/core/update.js +1 -1
  34. package/src/index/buildIndex.js +2 -2
  35. package/src/index/impactCatalog.js +12 -12
  36. package/src/index/taskRouting.js +263 -5
  37. package/src/render/instructionRenderer.js +7 -7
  38. package/src/skill/auditSkill.js +1 -1
  39. package/{templates → template_project}/.claude/agents/code-reviewer.md +25 -0
  40. package/{templates → template_project}/.claude/agents/handoff-planner.md +17 -2
  41. package/{templates → template_project}/.claude/commands/ukit/handoff-create.md +1 -1
  42. package/{templates → template_project}/.claude/commands/ukit/handoff-fullstack.md +26 -6
  43. package/{templates → template_project}/.claude/commands/ukit/handoff-review.md +31 -6
  44. package/{templates → template_project}/.claude/hooks/handoff-model-guard.sh +1 -1
  45. package/{templates → template_project}/.claude/hooks/skill-router.sh +3 -3
  46. package/{templates → template_project}/.claude/skills/skill-quality/SKILL.md +1 -1
  47. package/{templates → template_project}/.claude/skills/skill-quality/pressure-scenario-template.md +1 -1
  48. package/template_project/.claude/ukit/index/handoff-doc-validator.mjs +193 -0
  49. package/{templates → template_project}/.claude/ukit/index/lib/index-core.mjs +12 -12
  50. package/template_project/.claude/ukit/index/review-panel-aggregate.mjs +174 -0
  51. package/{templates → template_project}/.claude/ukit/index/route-task.mjs +408 -12
  52. package/{templates → template_project}/.claude/ukit/index/unic-gateway.mjs +1 -1
  53. package/{templates → template_project}/.claude/ukit/runtime/execution-ledger.mjs +14 -5
  54. package/{templates → template_project}/.claude/ukit/runtime/safe-patch-core.mjs +3 -3
  55. package/{templates → template_project}/.claude/ukit/runtime/sensitive-value-scanner.mjs +1 -1
  56. package/{templates → template_project}/.claude/ukit/runtime/stop-coordinator.mjs +187 -8
  57. package/{templates → template_project}/.claude/ukit/runtime/task-watchdog.mjs +1 -1
  58. package/{templates → template_project}/.gitignore +2 -2
  59. package/{templates → template_project}/.omp/RULES.md +1 -1
  60. package/{templates → template_project}/.omp/agents/code-reviewer.md +27 -0
  61. package/{templates → template_project}/.omp/agents/handoff-planner.md +17 -2
  62. package/{templates → template_project}/.omp/config.yml +3 -3
  63. package/{templates → template_project}/AGENTS.md +2 -2
  64. package/{templates → template_project}/CLAUDE.md +2 -2
  65. package/{templates → template_project}/docs/AI_HANDOFF/RULES.md +1 -1
  66. package/{templates → template_project}/docs/UKIT_INTERNALS.md +3 -3
  67. package/{templates → template_project}/instructions/core.md +1 -1
  68. package/{templates → template_project}/instructions/layout.yaml +8 -8
  69. package/{templates → template_project}/instructions/overlays/claude.md +1 -1
  70. package/{templates → template_project}/instructions/overlays/repo.md +1 -1
  71. package/{templates → template_project}/ukit/storage/config.json +4 -1
  72. package/template_project/ukit/storage/memory/projects/.gitkeep +2 -0
  73. package/templates/ukit/storage/memory/projects/.gitkeep +0 -2
  74. /package/{templates → template_project}/.claude/agents/bug-debugger.md +0 -0
  75. /package/{templates → template_project}/.claude/agents/feature-implementer.md +0 -0
  76. /package/{templates → template_project}/.claude/agents/ukit-small-task-maintainer.md +0 -0
  77. /package/{templates → template_project}/.claude/agents/ukit-vision-analyst.md +0 -0
  78. /package/{templates → template_project}/.claude/commands/ukit/handoff-clear.md +0 -0
  79. /package/{templates → template_project}/.claude/commands/ukit/handoff-implement.md +0 -0
  80. /package/{templates → template_project}/.claude/commands/ukit/handoff-status.md +0 -0
  81. /package/{templates → template_project}/.claude/config/providers.md +0 -0
  82. /package/{templates → template_project}/.claude/hooks/auto-allow-bash.sh +0 -0
  83. /package/{templates → template_project}/.claude/hooks/auto-prune-bash.sh +0 -0
  84. /package/{templates → template_project}/.claude/hooks/block-dangerous.mjs +0 -0
  85. /package/{templates → template_project}/.claude/hooks/block-dangerous.sh +0 -0
  86. /package/{templates → template_project}/.claude/hooks/completion-gate.sh +0 -0
  87. /package/{templates → template_project}/.claude/hooks/compress-output.sh +0 -0
  88. /package/{templates → template_project}/.claude/hooks/context-hardcap-gate.sh +0 -0
  89. /package/{templates → template_project}/.claude/hooks/context-window-guard.sh +0 -0
  90. /package/{templates → template_project}/.claude/hooks/handoff-resume.sh +0 -0
  91. /package/{templates → template_project}/.claude/hooks/post-edit-verify.sh +0 -0
  92. /package/{templates → template_project}/.claude/hooks/pre-edit-backup.sh +0 -0
  93. /package/{templates → template_project}/.claude/hooks/project-important.sh +0 -0
  94. /package/{templates → template_project}/.claude/hooks/protect-files.sh +0 -0
  95. /package/{templates → template_project}/.claude/hooks/record-execution.mjs +0 -0
  96. /package/{templates → template_project}/.claude/hooks/record-execution.sh +0 -0
  97. /package/{templates → template_project}/.claude/hooks/reinject-context.sh +0 -0
  98. /package/{templates → template_project}/.claude/hooks/reset-compact-pressure.sh +0 -0
  99. /package/{templates → template_project}/.claude/hooks/sensitive-data-guard.mjs +0 -0
  100. /package/{templates → template_project}/.claude/hooks/sensitive-data-guard.sh +0 -0
  101. /package/{templates → template_project}/.claude/hooks/session-episode.sh +0 -0
  102. /package/{templates → template_project}/.claude/hooks/session-start.md +0 -0
  103. /package/{templates → template_project}/.claude/hooks/stale-spec-guard.sh +0 -0
  104. /package/{templates → template_project}/.claude/hooks/task-watchdog.sh +0 -0
  105. /package/{templates → template_project}/.claude/hooks/verification-guard.sh +0 -0
  106. /package/{templates → template_project}/.claude/hooks/vision-router.sh +0 -0
  107. /package/{templates → template_project}/.claude/settings.json +0 -0
  108. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +0 -0
  109. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +0 -0
  110. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +0 -0
  111. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +0 -0
  112. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +0 -0
  113. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +0 -0
  114. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +0 -0
  115. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +0 -0
  116. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +0 -0
  117. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +0 -0
  118. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +0 -0
  119. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +0 -0
  120. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +0 -0
  121. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +0 -0
  122. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +0 -0
  123. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +0 -0
  124. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +0 -0
  125. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +0 -0
  126. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +0 -0
  127. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +0 -0
  128. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +0 -0
  129. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +0 -0
  130. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +0 -0
  131. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +0 -0
  132. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +0 -0
  133. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +0 -0
  134. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +0 -0
  135. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +0 -0
  136. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +0 -0
  137. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +0 -0
  138. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +0 -0
  139. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/mce/mc.xsd +0 -0
  140. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2010.xsd +0 -0
  141. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2012.xsd +0 -0
  142. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-2018.xsd +0 -0
  143. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cex-2018.xsd +0 -0
  144. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-cid-2016.xsd +0 -0
  145. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +0 -0
  146. /package/{templates → template_project}/.claude/skills/_shared/ooxml/schemas/microsoft/wml-symex-2015.xsd +0 -0
  147. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/pack.py +0 -0
  148. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/unpack.py +0 -0
  149. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/validate.py +0 -0
  150. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/validation/__init__.py +0 -0
  151. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/validation/base.py +0 -0
  152. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/validation/docx.py +0 -0
  153. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/validation/pptx.py +0 -0
  154. /package/{templates → template_project}/.claude/skills/_shared/ooxml/scripts/validation/redlining.py +0 -0
  155. /package/{templates → template_project}/.claude/skills/backend-api/SKILL.md +0 -0
  156. /package/{templates → template_project}/.claude/skills/canvas-design/LICENSE.txt +0 -0
  157. /package/{templates → template_project}/.claude/skills/canvas-design/SKILL.md +0 -0
  158. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  159. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +0 -0
  160. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  161. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  162. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  163. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  164. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +0 -0
  165. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  166. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  167. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  168. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  169. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +0 -0
  170. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  171. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  172. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  173. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  174. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Lora-OFL.txt +0 -0
  175. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  176. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +0 -0
  177. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  178. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  179. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +0 -0
  180. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  181. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  182. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +0 -0
  183. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  184. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +0 -0
  185. /package/{templates → template_project}/.claude/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  186. /package/{templates → template_project}/.claude/skills/canvas-design/philosophy-examples.md +0 -0
  187. /package/{templates → template_project}/.claude/skills/code-review/SKILL.md +0 -0
  188. /package/{templates → template_project}/.claude/skills/debugging-toolkit/SKILL.md +0 -0
  189. /package/{templates → template_project}/.claude/skills/debugging-toolkit/reference-tables.md +0 -0
  190. /package/{templates → template_project}/.claude/skills/delivery/SKILL.md +0 -0
  191. /package/{templates → template_project}/.claude/skills/discover-security/SKILL.md +0 -0
  192. /package/{templates → template_project}/.claude/skills/docker-packaging/SKILL.md +0 -0
  193. /package/{templates → template_project}/.claude/skills/docs-manager/SKILL.md +0 -0
  194. /package/{templates → template_project}/.claude/skills/docs-manager/conventions-and-examples.md +0 -0
  195. /package/{templates → template_project}/.claude/skills/docs-manager/init-project-docs.sh +0 -0
  196. /package/{templates → template_project}/.claude/skills/docs-manager/templates/README.md.template +0 -0
  197. /package/{templates → template_project}/.claude/skills/docs-manager/templates/agent-roles.md.template +0 -0
  198. /package/{templates → template_project}/.claude/skills/docs-manager/templates/coding-conventions.md.template +0 -0
  199. /package/{templates → template_project}/.claude/skills/docs-manager/templates/memory.md.template +0 -0
  200. /package/{templates → template_project}/.claude/skills/docs-manager/templates/onboarding.md.template +0 -0
  201. /package/{templates → template_project}/.claude/skills/docs-manager/templates/project.md.template +0 -0
  202. /package/{templates → template_project}/.claude/skills/docs-quality/SKILL.md +0 -0
  203. /package/{templates → template_project}/.claude/skills/docx/LICENSE.txt +0 -0
  204. /package/{templates → template_project}/.claude/skills/docx/SKILL.md +0 -0
  205. /package/{templates → template_project}/.claude/skills/docx/docx-js.md +0 -0
  206. /package/{templates → template_project}/.claude/skills/docx/ooxml.md +0 -0
  207. /package/{templates → template_project}/.claude/skills/docx/redlining-reference.md +0 -0
  208. /package/{templates → template_project}/.claude/skills/docx/scripts/__init__.py +0 -0
  209. /package/{templates → template_project}/.claude/skills/docx/scripts/document.py +0 -0
  210. /package/{templates → template_project}/.claude/skills/docx/scripts/templates/comments.xml +0 -0
  211. /package/{templates → template_project}/.claude/skills/docx/scripts/templates/commentsExtended.xml +0 -0
  212. /package/{templates → template_project}/.claude/skills/docx/scripts/templates/commentsExtensible.xml +0 -0
  213. /package/{templates → template_project}/.claude/skills/docx/scripts/templates/commentsIds.xml +0 -0
  214. /package/{templates → template_project}/.claude/skills/docx/scripts/templates/people.xml +0 -0
  215. /package/{templates → template_project}/.claude/skills/docx/scripts/utilities.py +0 -0
  216. /package/{templates → template_project}/.claude/skills/duraone/SKILL.md +0 -0
  217. /package/{templates → template_project}/.claude/skills/duraone/references/backend.md +0 -0
  218. /package/{templates → template_project}/.claude/skills/duraone/references/frontend.md +0 -0
  219. /package/{templates → template_project}/.claude/skills/duraone/references/sql.md +0 -0
  220. /package/{templates → template_project}/.claude/skills/duraone/references/workflow.md +0 -0
  221. /package/{templates → template_project}/.claude/skills/executing-plans/SKILL.md +0 -0
  222. /package/{templates → template_project}/.claude/skills/file-organizer/SKILL.md +0 -0
  223. /package/{templates → template_project}/.claude/skills/file-organizer/examples-and-practices.md +0 -0
  224. /package/{templates → template_project}/.claude/skills/frontend/SKILL.md +0 -0
  225. /package/{templates → template_project}/.claude/skills/frontend-design/LICENSE.txt +0 -0
  226. /package/{templates → template_project}/.claude/skills/frontend-design/SKILL.md +0 -0
  227. /package/{templates → template_project}/.claude/skills/frontend-vue/SKILL.md +0 -0
  228. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Box.vue +0 -0
  229. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Button.vue +0 -0
  230. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/ButtonBar.vue +0 -0
  231. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/ButtonFloat.vue +0 -0
  232. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/CheckButton.vue +0 -0
  233. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Checkbox.vue +0 -0
  234. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Datetime.vue +0 -0
  235. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Dropdownlist.vue +0 -0
  236. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Input.vue +0 -0
  237. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Label.vue +0 -0
  238. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Master/BoxColumn.vue +0 -0
  239. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Popup/Confirm.vue +0 -0
  240. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Popup/Info.vue +0 -0
  241. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Popup/ModalInfo.vue +0 -0
  242. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Popup/Reject.vue +0 -0
  243. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Tag.vue +0 -0
  244. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Control/Upload.vue +0 -0
  245. /package/{templates → template_project}/.claude/skills/frontend-vue/components/ControlMobile/Dropdownlist.vue +0 -0
  246. /package/{templates → template_project}/.claude/skills/frontend-vue/components/ControlMobile/PagingBar.vue +0 -0
  247. /package/{templates → template_project}/.claude/skills/frontend-vue/components/ControlMobile/UploadImage.vue +0 -0
  248. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Grid/AG.vue +0 -0
  249. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Grid/AntTable.vue +0 -0
  250. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditor.vue +0 -0
  251. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Grid/CustomDropdownEditorEnable.vue +0 -0
  252. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Grid/HtmlTable.vue +0 -0
  253. /package/{templates → template_project}/.claude/skills/frontend-vue/components/PDFViewer.vue +0 -0
  254. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Panel/FormView.vue +0 -0
  255. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Partial/Footer.vue +0 -0
  256. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Partial/Header.vue +0 -0
  257. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Partial/Sidebar.vue +0 -0
  258. /package/{templates → template_project}/.claude/skills/frontend-vue/components/Template.vue +0 -0
  259. /package/{templates → template_project}/.claude/skills/frontend-vue/components/View/Form.vue +0 -0
  260. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/indexDBStore.js +0 -0
  261. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/masterApi.js +0 -0
  262. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/state.js +0 -0
  263. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/useRequest.js +0 -0
  264. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/useSession.js +0 -0
  265. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/useTranslation.js +0 -0
  266. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/useWebSocket.js +0 -0
  267. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/userObj.js +0 -0
  268. /package/{templates → template_project}/.claude/skills/frontend-vue/composables/utils.js +0 -0
  269. /package/{templates → template_project}/.claude/skills/frontend-vue/reference/composables-example.vue +0 -0
  270. /package/{templates → template_project}/.claude/skills/frontend-vue/reference/form-example.vue +0 -0
  271. /package/{templates → template_project}/.claude/skills/frontend-vue/reference/grid-example.vue +0 -0
  272. /package/{templates → template_project}/.claude/skills/frontend-vue/reference/masterdata-example/[id].vue +0 -0
  273. /package/{templates → template_project}/.claude/skills/frontend-vue/reference/masterdata-example/index.vue +0 -0
  274. /package/{templates → template_project}/.claude/skills/frontend-vue/reference/popup-example.vue +0 -0
  275. /package/{templates → template_project}/.claude/skills/next-step/SKILL.md +0 -0
  276. /package/{templates → template_project}/.claude/skills/pdf/LICENSE.txt +0 -0
  277. /package/{templates → template_project}/.claude/skills/pdf/SKILL.md +0 -0
  278. /package/{templates → template_project}/.claude/skills/pdf/forms.md +0 -0
  279. /package/{templates → template_project}/.claude/skills/pdf/reference.md +0 -0
  280. /package/{templates → template_project}/.claude/skills/pdf/scripts/check_bounding_boxes.py +0 -0
  281. /package/{templates → template_project}/.claude/skills/pdf/scripts/check_bounding_boxes_test.py +0 -0
  282. /package/{templates → template_project}/.claude/skills/pdf/scripts/check_fillable_fields.py +0 -0
  283. /package/{templates → template_project}/.claude/skills/pdf/scripts/convert_pdf_to_images.py +0 -0
  284. /package/{templates → template_project}/.claude/skills/pdf/scripts/create_validation_image.py +0 -0
  285. /package/{templates → template_project}/.claude/skills/pdf/scripts/extract_form_field_info.py +0 -0
  286. /package/{templates → template_project}/.claude/skills/pdf/scripts/fill_fillable_fields.py +0 -0
  287. /package/{templates → template_project}/.claude/skills/pdf/scripts/fill_pdf_form_with_annotations.py +0 -0
  288. /package/{templates → template_project}/.claude/skills/pdf-processing/SKILL.md +0 -0
  289. /package/{templates → template_project}/.claude/skills/pdf-processing-pro/FORMS.md +0 -0
  290. /package/{templates → template_project}/.claude/skills/pdf-processing-pro/OCR.md +0 -0
  291. /package/{templates → template_project}/.claude/skills/pdf-processing-pro/SKILL.md +0 -0
  292. /package/{templates → template_project}/.claude/skills/pdf-processing-pro/TABLES.md +0 -0
  293. /package/{templates → template_project}/.claude/skills/pdf-processing-pro/scripts/analyze_form.py +0 -0
  294. /package/{templates → template_project}/.claude/skills/pdf-processing-pro/workflows-and-troubleshooting.md +0 -0
  295. /package/{templates → template_project}/.claude/skills/postgres/SKILL.md +0 -0
  296. /package/{templates → template_project}/.claude/skills/postgres/reference/fn_get_examples.sql +0 -0
  297. /package/{templates → template_project}/.claude/skills/postgres/reference/fn_rpt_examples.sql +0 -0
  298. /package/{templates → template_project}/.claude/skills/postgres/reference/utility_functions.sql +0 -0
  299. /package/{templates → template_project}/.claude/skills/pptx/LICENSE.txt +0 -0
  300. /package/{templates → template_project}/.claude/skills/pptx/SKILL.md +0 -0
  301. /package/{templates → template_project}/.claude/skills/pptx/design-references.md +0 -0
  302. /package/{templates → template_project}/.claude/skills/pptx/html2pptx.md +0 -0
  303. /package/{templates → template_project}/.claude/skills/pptx/ooxml.md +0 -0
  304. /package/{templates → template_project}/.claude/skills/pptx/scripts/html2pptx.js +0 -0
  305. /package/{templates → template_project}/.claude/skills/pptx/scripts/inventory.py +0 -0
  306. /package/{templates → template_project}/.claude/skills/pptx/scripts/rearrange.py +0 -0
  307. /package/{templates → template_project}/.claude/skills/pptx/scripts/replace.py +0 -0
  308. /package/{templates → template_project}/.claude/skills/pptx/scripts/thumbnail.py +0 -0
  309. /package/{templates → template_project}/.claude/skills/pptx/template-replacement-reference.md +0 -0
  310. /package/{templates → template_project}/.claude/skills/pptx/utilities.md +0 -0
  311. /package/{templates → template_project}/.claude/skills/principle-attack-the-premise/SKILL.md +0 -0
  312. /package/{templates → template_project}/.claude/skills/principle-boundary-discipline/SKILL.md +0 -0
  313. /package/{templates → template_project}/.claude/skills/principle-encode-lessons-in-structure/SKILL.md +0 -0
  314. /package/{templates → template_project}/.claude/skills/principle-fix-root-causes/SKILL.md +0 -0
  315. /package/{templates → template_project}/.claude/skills/principle-foundational-thinking/SKILL.md +0 -0
  316. /package/{templates → template_project}/.claude/skills/principle-guard-the-context-window/SKILL.md +0 -0
  317. /package/{templates → template_project}/.claude/skills/principle-laziness-protocol/SKILL.md +0 -0
  318. /package/{templates → template_project}/.claude/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +0 -0
  319. /package/{templates → template_project}/.claude/skills/principle-minimize-reader-load/SKILL.md +0 -0
  320. /package/{templates → template_project}/.claude/skills/principle-model-the-domain/SKILL.md +0 -0
  321. /package/{templates → template_project}/.claude/skills/principle-never-block-on-the-human/SKILL.md +0 -0
  322. /package/{templates → template_project}/.claude/skills/principle-prove-it-works/SKILL.md +0 -0
  323. /package/{templates → template_project}/.claude/skills/principle-sequence-verifiable-units/SKILL.md +0 -0
  324. /package/{templates → template_project}/.claude/skills/principle-subtract-before-you-add/SKILL.md +0 -0
  325. /package/{templates → template_project}/.claude/skills/principle-test-behavior-not-implementation/SKILL.md +0 -0
  326. /package/{templates → template_project}/.claude/skills/project-learning/SKILL.md +0 -0
  327. /package/{templates → template_project}/.claude/skills/repo-maintenance/SKILL.md +0 -0
  328. /package/{templates → template_project}/.claude/skills/research/EXAMPLES.md +0 -0
  329. /package/{templates → template_project}/.claude/skills/research/REFERENCE.md +0 -0
  330. /package/{templates → template_project}/.claude/skills/research/SKILL.md +0 -0
  331. /package/{templates → template_project}/.claude/skills/root-cause-tracing/SKILL.md +0 -0
  332. /package/{templates → template_project}/.claude/skills/root-cause-tracing/diagrams.md +0 -0
  333. /package/{templates → template_project}/.claude/skills/root-cause-tracing/find-polluter.sh +0 -0
  334. /package/{templates → template_project}/.claude/skills/sharing-skills/SKILL.md +0 -0
  335. /package/{templates → template_project}/.claude/skills/sharing-skills/complete-example.md +0 -0
  336. /package/{templates → template_project}/.claude/skills/skill-quality/rationalization-table-template.md +0 -0
  337. /package/{templates → template_project}/.claude/skills/skill-quality/trigger-accuracy-template.md +0 -0
  338. /package/{templates → template_project}/.claude/skills/sql-optimization-patterns/SKILL.md +0 -0
  339. /package/{templates → template_project}/.claude/skills/sql-optimization-patterns/references/advanced-techniques.md +0 -0
  340. /package/{templates → template_project}/.claude/skills/sql-optimization-patterns/references/core-concepts.md +0 -0
  341. /package/{templates → template_project}/.claude/skills/sql-optimization-patterns/references/query-patterns.md +0 -0
  342. /package/{templates → template_project}/.claude/skills/subagent-driven-development/SKILL.md +0 -0
  343. /package/{templates → template_project}/.claude/skills/subagent-driven-development/example-workflow.md +0 -0
  344. /package/{templates → template_project}/.claude/skills/systematic-debugging/CREATION-LOG.md +0 -0
  345. /package/{templates → template_project}/.claude/skills/systematic-debugging/SKILL.md +0 -0
  346. /package/{templates → template_project}/.claude/skills/systematic-debugging/reference-tables.md +0 -0
  347. /package/{templates → template_project}/.claude/skills/systematic-debugging/test-academic.md +0 -0
  348. /package/{templates → template_project}/.claude/skills/systematic-debugging/test-pressure-1.md +0 -0
  349. /package/{templates → template_project}/.claude/skills/systematic-debugging/test-pressure-2.md +0 -0
  350. /package/{templates → template_project}/.claude/skills/systematic-debugging/test-pressure-3.md +0 -0
  351. /package/{templates → template_project}/.claude/skills/test-driven-development/SKILL.md +0 -0
  352. /package/{templates → template_project}/.claude/skills/test-driven-development/reference-tables.md +0 -0
  353. /package/{templates → template_project}/.claude/skills/testing-anti-patterns/SKILL.md +0 -0
  354. /package/{templates → template_project}/.claude/skills/testing-anti-patterns/reference-tables.md +0 -0
  355. /package/{templates → template_project}/.claude/skills/testing-quality/SKILL.md +0 -0
  356. /package/{templates → template_project}/.claude/skills/update-status/SKILL.md +0 -0
  357. /package/{templates → template_project}/.claude/skills/verification-before-completion/SKILL.md +0 -0
  358. /package/{templates → template_project}/.claude/skills/verification-before-completion/key-patterns.md +0 -0
  359. /package/{templates → template_project}/.claude/skills/webapp-testing/LICENSE.txt +0 -0
  360. /package/{templates → template_project}/.claude/skills/webapp-testing/SKILL.md +0 -0
  361. /package/{templates → template_project}/.claude/skills/webapp-testing/examples/console_logging.py +0 -0
  362. /package/{templates → template_project}/.claude/skills/webapp-testing/examples/element_discovery.py +0 -0
  363. /package/{templates → template_project}/.claude/skills/webapp-testing/examples/static_html_automation.py +0 -0
  364. /package/{templates → template_project}/.claude/skills/webapp-testing/scripts/with_server.py +0 -0
  365. /package/{templates → template_project}/.claude/ukit/index/anchor-search.mjs +0 -0
  366. /package/{templates → template_project}/.claude/ukit/index/build-index.mjs +0 -0
  367. /package/{templates → template_project}/.claude/ukit/index/cache-utils.mjs +0 -0
  368. /package/{templates → template_project}/.claude/ukit/index/extract-image.mjs +0 -0
  369. /package/{templates → template_project}/.claude/ukit/index/impact-context.mjs +0 -0
  370. /package/{templates → template_project}/.claude/ukit/index/post-edit-verify.mjs +0 -0
  371. /package/{templates → template_project}/.claude/ukit/index/pre-edit-backup.mjs +0 -0
  372. /package/{templates → template_project}/.claude/ukit/index/provision-worktree.mjs +0 -0
  373. /package/{templates → template_project}/.claude/ukit/index/query-index.mjs +0 -0
  374. /package/{templates → template_project}/.claude/ukit/index/refresh-index.mjs +0 -0
  375. /package/{templates → template_project}/.claude/ukit/index/reset-auto-permissions.mjs +0 -0
  376. /package/{templates → template_project}/.claude/ukit/index/resolve-context.mjs +0 -0
  377. /package/{templates → template_project}/.claude/ukit/index/route-catalog.mjs +0 -0
  378. /package/{templates → template_project}/.claude/ukit/index/safe-patch.mjs +0 -0
  379. /package/{templates → template_project}/.claude/ukit/index/stale-spec-check.mjs +0 -0
  380. /package/{templates → template_project}/.claude/ukit/index/task-budget-validator.mjs +0 -0
  381. /package/{templates → template_project}/.claude/ukit/index/triage.mjs +0 -0
  382. /package/{templates → template_project}/.claude/ukit/index/verify-context.mjs +0 -0
  383. /package/{templates → template_project}/.claude/ukit/runtime/async-lock.mjs +0 -0
  384. /package/{templates → template_project}/.claude/ukit/runtime/compact-threshold.mjs +0 -0
  385. /package/{templates → template_project}/.claude/ukit/runtime/context-capacity.mjs +0 -0
  386. /package/{templates → template_project}/.claude/ukit/runtime/hook-chain-budget.mjs +0 -0
  387. /package/{templates → template_project}/.claude/ukit/runtime/hook-chain-runner.mjs +0 -0
  388. /package/{templates → template_project}/.claude/ukit/runtime/hook-field-salvage.mjs +0 -0
  389. /package/{templates → template_project}/.claude/ukit/runtime/hook-input.mjs +0 -0
  390. /package/{templates → template_project}/.claude/ukit/runtime/hook-input.sh +0 -0
  391. /package/{templates → template_project}/.claude/ukit/runtime/hook-payload-store.mjs +0 -0
  392. /package/{templates → template_project}/.claude/ukit/runtime/hook-process.mjs +0 -0
  393. /package/{templates → template_project}/.claude/ukit/runtime/hook-telemetry.mjs +0 -0
  394. /package/{templates → template_project}/.claude/ukit/runtime/hook-telemetry.sh +0 -0
  395. /package/{templates → template_project}/.claude/ukit/runtime/output-compression.mjs +0 -0
  396. /package/{templates → template_project}/.claude/ukit/runtime/project-important.mjs +0 -0
  397. /package/{templates → template_project}/.claude/ukit/runtime/reinject-context.mjs +0 -0
  398. /package/{templates → template_project}/.claude/ukit/runtime/text-profile.mjs +0 -0
  399. /package/{templates → template_project}/.claude/ukit/runtime/token-utils.mjs +0 -0
  400. /package/{templates → template_project}/.claude/ukit/runtime/transcript-tail.mjs +0 -0
  401. /package/{templates → template_project}/.claude/ukit/skill-router-state.json +0 -0
  402. /package/{templates → template_project}/.codex/README.md +0 -0
  403. /package/{templates → template_project}/.codex/settings.json +0 -0
  404. /package/{templates → template_project}/.omp/AGENTS.md +0 -0
  405. /package/{templates → template_project}/.omp/README.md +0 -0
  406. /package/{templates → template_project}/.omp/agents/bug-debugger.md +0 -0
  407. /package/{templates → template_project}/.omp/agents/feature-implementer.md +0 -0
  408. /package/{templates → template_project}/.omp/agents/ukit-small-task-maintainer.md +0 -0
  409. /package/{templates → template_project}/.omp/agents/ukit-vision-analyst.md +0 -0
  410. /package/{templates → template_project}/.omp/hooks/pre/ukit-bridge.js +0 -0
  411. /package/{templates → template_project}/.ukit/storage/cache/hook-latency/unknown.jsonl +0 -0
  412. /package/{templates → template_project}/PROJECT_IMPORTANT.md +0 -0
  413. /package/{templates → template_project}/adapter-presets/claude/settings.local.json +0 -0
  414. /package/{templates → template_project}/adapter-presets/codex/settings.local.json +0 -0
  415. /package/{templates → template_project}/docs/AI_HANDOFF/ACTIVE.md +0 -0
  416. /package/{templates → template_project}/docs/AI_HANDOFF/HISTORY.md +0 -0
  417. /package/{templates → template_project}/docs/AI_HANDOFF/INDEX.md +0 -0
  418. /package/{templates → template_project}/docs/AI_HANDOFF/PLAN.md +0 -0
  419. /package/{templates → template_project}/docs/AI_HANDOFF/SPEC.md +0 -0
  420. /package/{templates → template_project}/docs/AI_HANDOFF/archive/.gitkeep +0 -0
  421. /package/{templates → template_project}/docs/AI_HANDOFF/tasks/.gitkeep +0 -0
  422. /package/{templates → template_project}/docs/AI_HANDOFF/tasks/_TEMPLATE.md +0 -0
  423. /package/{templates → template_project}/docs/BUGFIX.md +0 -0
  424. /package/{templates → template_project}/docs/BUG_INDEX.md +0 -0
  425. /package/{templates → template_project}/docs/BUG_METRICS.md +0 -0
  426. /package/{templates → template_project}/docs/BUG_TEMPLATE.md +0 -0
  427. /package/{templates → template_project}/docs/CODE_MAP.md +0 -0
  428. /package/{templates → template_project}/docs/MEMORY.md +0 -0
  429. /package/{templates → template_project}/docs/PROJECT.md +0 -0
  430. /package/{templates → template_project}/docs/PROMPT_CACHING.md +0 -0
  431. /package/{templates → template_project}/docs/WORKLOG.md +0 -0
  432. /package/{templates → template_project}/instructions/overlays/agents.md +0 -0
  433. /package/{templates → template_project}/instructions/overlays/omp-rules.md +0 -0
  434. /package/{templates → template_project}/instructions/repo-vars.yaml +0 -0
  435. /package/{templates → template_project}/ukit/README.md +0 -0
  436. /package/{templates → template_project}/ukit/storage/cache/compact-history.json +0 -0
  437. /package/{templates → template_project}/ukit/storage/cache/compact-pressure.json +0 -0
  438. /package/{templates → template_project}/ukit/storage/cache/output-history.json +0 -0
  439. /package/{templates → template_project}/ukit/storage/cache/prompt-cache.json +0 -0
  440. /package/{templates → template_project}/ukit/storage/memory/sessions/.gitkeep +0 -0
  441. /package/{templates → template_project}/ukit/storage/memory/user.json +0 -0
  442. /package/{templates/user → template_user}/README.md +0 -0
  443. /package/{templates/user → template_user}/playbooks/bug-fix.md +0 -0
  444. /package/{templates/user → template_user}/playbooks/issue-implementation.md +0 -0
  445. /package/{templates/user → template_user}/storage/config.json +0 -0
@@ -69,6 +69,29 @@ export const ROUTE_INTENT_KINDS = new Set(['informational', 'delivery', 'mutatio
69
69
  export const ROUTE_MUTABILITIES = new Set(['read-only', 'mutating', 'mixed']);
70
70
  export const ROUTE_RIGOR_LEVELS = new Set(['R0', 'R1', 'R2', 'R3', 'R4']);
71
71
  export const ROUTE_MODEL_TIERS = new Set(['lite', 'code', 'smart']);
72
+ export const ROUTE_RISK_FLOORS = new Set(['none', 'high-risk']);
73
+ export const ROUTE_EFFORTS = new Set(['low', 'medium', 'high']);
74
+ // SPEC §5 FR-003: fixed table order — codes are emitted and printed in this order.
75
+ // The first six raise the floor to 'high-risk'; the last two are informational only.
76
+ export const ROUTE_RISK_REASON_CODES = Object.freeze([
77
+ 'security-sensitive',
78
+ 'shared-impact',
79
+ 'public-contract',
80
+ 'schema-change',
81
+ 'destructive-action',
82
+ 'cross-engine',
83
+ 'established-precedent',
84
+ 'explicit-local-target',
85
+ ]);
86
+ const ROUTE_RISK_FLOOR_RAISING_CODES = new Set(ROUTE_RISK_REASON_CODES.slice(0, 6));
87
+ const ROUTE_RISK_ENGINES = ['claude code', 'codex', 'omp'];
88
+
89
+ // FR-004 (M01.3'): Fast Path eligibility vocabulary. The suppressed list is fixed
90
+ // text per SPEC — deliberately not configurable. Reasons are the informational
91
+ // risk codes (the last two ROUTE_RISK_REASON_CODES entries) present on the route.
92
+ const FAST_PATH_MODES = new Set(['tiny-fix', 'local-fix']);
93
+ const FAST_PATH_SUPPRESSED = Object.freeze(['design', 'smart', 'subagents', 'broad-verify']);
94
+ const FAST_PATH_REASON_CODES = new Set(ROUTE_RISK_REASON_CODES.slice(6));
72
95
  // 'informational' is a real router emission (no completion contract) even though it is
73
96
  // not part of the seven-lane execution-mode ladder.
74
97
  export const ROUTE_EXECUTION_MODES = [
@@ -249,6 +272,162 @@ export function resolveRouteSchemaStage(config = null) {
249
272
  return ROUTE_SCHEMA_STAGES.has(stage) ? stage : 'off';
250
273
  }
251
274
 
275
+ // FR-002: generic stage resolver — every routing.<key>.stage shares the same
276
+ // absent/malformed → 'off' contract. resolveRouteSchemaStage stays as the
277
+ // routeSchema-specific spelling of this helper.
278
+ export function resolveRouteStage(config = null, key) {
279
+ const stage = config?.routing?.[key]?.stage;
280
+ return ROUTE_SCHEMA_STAGES.has(stage) ? stage : 'off';
281
+ }
282
+
283
+ // FR-003 (M01.2'): derive the additive riskFloor from hard signals. Codes are
284
+ // collected in ROUTE_RISK_REASON_CODES table order; the floor is 'high-risk' iff
285
+ // any of the first six (floor-raising) codes fired — informational codes never
286
+ // raise it. Detectors read the normalized signal text (same source the mode
287
+ // ladder uses) plus the raw target path and context preview.
288
+ export function deriveRiskFloor({
289
+ promptText = '',
290
+ commandText = '',
291
+ targetFile = null,
292
+ executionMode = null,
293
+ activeSkillIds = [],
294
+ contextPreview = null,
295
+ } = {}) {
296
+ const signalText = buildNormalizedRouteSignalText(promptText, commandText);
297
+ const target = String(targetFile || '');
298
+ const skillIds = Array.isArray(activeSkillIds) ? activeSkillIds : [];
299
+ const codes = [];
300
+ if (
301
+ /\b(auth|security|token|permission|secret|credential|password|vulnerab|exploit|xss|injection)\b/i.test(signalText)
302
+ || skillIds.includes('discover-security')
303
+ ) {
304
+ codes.push('security-sensitive');
305
+ }
306
+ if (isSharedImpactFile(targetFile) || executionMode === 'shared-edit' || executionMode === 'map-impact') {
307
+ codes.push('shared-impact');
308
+ }
309
+ if (
310
+ /(^|\/)(package\.json|manifests\/|.*\.d\.ts$|(^|\/)api\/|openapi|swagger)/i.test(target)
311
+ || /\b(public api|breaking change|api contract|semver)\b/i.test(signalText)
312
+ ) {
313
+ codes.push('public-contract');
314
+ }
315
+ if (
316
+ /(^|\/)(migrations?|db|database|prisma|schema)/i.test(target)
317
+ || /\b(migration|migrate|schema|alter table|add column|drop column)\b/i.test(signalText)
318
+ ) {
319
+ codes.push('schema-change');
320
+ }
321
+ if (/\b(delete|drop|truncate|destroy|wipe|uninstall|rm -rf|purge)\b/i.test(signalText)) {
322
+ codes.push('destructive-action');
323
+ }
324
+ const engineHits = ROUTE_RISK_ENGINES.filter(
325
+ (name) => new RegExp(`\\b${name}\\b`, 'i').test(signalText),
326
+ ).length;
327
+ if (
328
+ /\bcross[- ]engine\b|\ball engines\b/i.test(signalText)
329
+ || engineHits >= 2
330
+ || /^template_project\/\.(claude|codex|omp)\//i.test(target)
331
+ ) {
332
+ codes.push('cross-engine');
333
+ }
334
+ if ((contextPreview?.analogFiles?.length ?? 0) > 0 || (contextPreview?.styleFiles?.length ?? 0) > 0) {
335
+ codes.push('established-precedent');
336
+ }
337
+ if (target && !isSharedImpactFile(targetFile)) {
338
+ codes.push('explicit-local-target');
339
+ }
340
+ return {
341
+ floor: codes.some((code) => ROUTE_RISK_FLOOR_RAISING_CODES.has(code)) ? 'high-risk' : 'none',
342
+ codes,
343
+ };
344
+ }
345
+
346
+ // Route-line segment (FR-003): on 'high-risk' only the floor-raising codes print;
347
+ // on 'none' the informational codes do. Empty list → no segment at all.
348
+ function formatRiskFloorSegment(riskFloor = null) {
349
+ if (!riskFloor) {
350
+ return null;
351
+ }
352
+ const printed = riskFloor.floor === 'high-risk'
353
+ ? riskFloor.codes.filter((code) => ROUTE_RISK_FLOOR_RAISING_CODES.has(code))
354
+ : riskFloor.codes;
355
+ return printed.length > 0 ? `risk=${riskFloor.floor}(${printed.join(',')})` : null;
356
+ }
357
+
358
+ // FR-001 (M01.2' limits fragment): compile the contract's numeric budget keys
359
+ // into an advisory map. Only finite numbers survive — a non-numeric or missing
360
+ // key is simply absent. Zero is a real budget ("no read passes"), never
361
+ // filtered. Same key set as the ceremonyBudget.limits builder below.
362
+ export function deriveCeremonyLimits(executionContract = null) {
363
+ if (executionContract === null || typeof executionContract !== 'object') {
364
+ return {};
365
+ }
366
+ return Object.fromEntries(
367
+ ['maxReadPasses', 'maxContextPulls', 'maxReadPassesBeforeReassess']
368
+ .filter((key) => Number.isFinite(executionContract[key]))
369
+ .map((key) => [key, executionContract[key]]),
370
+ );
371
+ }
372
+
373
+ // Route-line segment (FR-002): fixed reads,ctx,reassess order; only present
374
+ // keys print. Empty/absent map → null so the segment never appears.
375
+ export function formatLimitsSegment(limits = null) {
376
+ if (limits === null || typeof limits !== 'object') {
377
+ return null;
378
+ }
379
+ const parts = [
380
+ ['reads', 'maxReadPasses'],
381
+ ['ctx', 'maxContextPulls'],
382
+ ['reassess', 'maxReadPassesBeforeReassess'],
383
+ ]
384
+ .filter(([, key]) => Number.isFinite(limits[key]))
385
+ .map(([label, key]) => `${label}:${limits[key]}`);
386
+ return parts.length > 0 ? `limits=${parts.join(',')}` : null;
387
+ }
388
+
389
+ // FR-004 (M01.3'): Fast Path eligibility predicate. Returns null when no riskFloor
390
+ // was supplied — eligibility must never be derived without the floor check, so a
391
+ // missing floor means "not computed", not "none". Eligible iff the lane is
392
+ // tiny-fix/local-fix, exactly one local target is known, the floor is 'none',
393
+ // a bounded verification path exists (targeted commands or the tiny-fix
394
+ // 'minimal-or-targeted' contract policy), and the target is not shared-impact.
395
+ export function deriveFastPath({
396
+ executionMode = null,
397
+ targetFile = null,
398
+ riskFloor = null,
399
+ verificationRecommendation = null,
400
+ contextPreview = null,
401
+ } = {}) {
402
+ if (!riskFloor) {
403
+ return null;
404
+ }
405
+ const reasons = (riskFloor.codes ?? []).filter((code) => FAST_PATH_REASON_CODES.has(code));
406
+ const hasLocalTarget = Boolean(targetFile) || contextPreview?.primaryTargets?.length === 1;
407
+ const hasBoundedVerification = (verificationRecommendation?.commands?.length ?? 0) > 0
408
+ || buildExecutionContract(executionMode)?.verificationPolicy === 'minimal-or-targeted';
409
+ const eligible = FAST_PATH_MODES.has(executionMode)
410
+ && hasLocalTarget
411
+ && riskFloor.floor === 'none'
412
+ && hasBoundedVerification
413
+ && !isSharedImpactFile(targetFile);
414
+ return {
415
+ eligible,
416
+ suppressed: eligible ? [...FAST_PATH_SUPPRESSED] : [],
417
+ reasons,
418
+ };
419
+ }
420
+
421
+ // Route-line segment (FR-004): emitted only for eligible routes — ineligible
422
+ // routes keep the routeSummary.fastPath field for telemetry but stay silent.
423
+ function formatFastPathSegment(fastPath = null) {
424
+ if (!fastPath?.eligible) {
425
+ return null;
426
+ }
427
+ const reasons = fastPath.reasons?.length ? ` (${fastPath.reasons.join(',')})` : '';
428
+ return `fastPath=on | suppress: ${FAST_PATH_SUPPRESSED.join(',')}${reasons}`;
429
+ }
430
+
252
431
  // A bare delivery command ("push this to git", "đẩy bộ này lên git") performs no
253
432
  // repository mutation the ledger could ever receipt. With no edit/review/debug/build
254
433
  // signal present, routing it to an investigation lane fabricates write debt and the
@@ -311,7 +490,12 @@ function buildResolvedRouteFields({
311
490
  executionMode = null,
312
491
  executionContract = null,
313
492
  completionState = null,
493
+ riskFloor = null,
314
494
  } = {}) {
495
+ // Decision table v2 (FR-001/FR-002): tier + effort resolve together from the
496
+ // contract lane and the additive riskFloor. The router cannot observe host
497
+ // binding capabilities, so the emitted pair is advisory text by definition.
498
+ const tierDecision = resolveModelTier({ executionMode, riskFloor });
315
499
  const signalText = buildNormalizedRouteSignalText(routingContext.promptText, routingContext.commandText);
316
500
  const deliveryOnly = isDeliveryOnlyRequest({
317
501
  signalText,
@@ -333,13 +517,15 @@ function buildResolvedRouteFields({
333
517
  execution: {
334
518
  mode: executionMode,
335
519
  rigor: null,
520
+ riskFloor: riskFloor?.floor ?? null,
336
521
  phase: null,
337
522
  contractVersion: ROUTE_CONTRACT_VERSION,
338
- modelTier: executionContract?.modelTier ?? null,
523
+ modelTier: tierDecision.tier,
524
+ effort: tierDecision.effort,
339
525
  },
340
526
  evidence: {
341
527
  observations: [],
342
- riskSignals: [],
528
+ riskSignals: riskFloor?.codes ?? [],
343
529
  activationReasons: [],
344
530
  suppressionReasons: [],
345
531
  completionRequirements: unique(completionState?.missingEvidence ?? []),
@@ -347,7 +533,13 @@ function buildResolvedRouteFields({
347
533
  ceremonyBudget: {
348
534
  policyVersion: ROUTE_CONTRACT_VERSION,
349
535
  rigor: null,
350
- limits: {},
536
+ limits: riskFloor
537
+ ? Object.fromEntries(
538
+ ['maxReadPasses', 'maxContextPulls', 'maxReadPassesBeforeReassess']
539
+ .filter((key) => typeof executionContract?.[key] === 'number')
540
+ .map((key) => [key, executionContract[key]]),
541
+ )
542
+ : {},
351
543
  consumed: {},
352
544
  exceptions: [],
353
545
  },
@@ -403,12 +595,19 @@ export function validateResolvedRoute(route = null) {
403
595
  if (route.execution.rigor !== null && !ROUTE_RIGOR_LEVELS.has(route.execution.rigor)) {
404
596
  errors.push(`execution.rigor must be null or one of: ${[...ROUTE_RIGOR_LEVELS].join(', ')}.`);
405
597
  }
598
+ if (route.execution.riskFloor !== null && !ROUTE_RISK_FLOORS.has(route.execution.riskFloor)) {
599
+ errors.push(`execution.riskFloor must be null or one of: ${[...ROUTE_RISK_FLOORS].join(', ')}.`);
600
+ }
406
601
  if (route.execution.contractVersion !== ROUTE_CONTRACT_VERSION) {
407
602
  errors.push(`execution.contractVersion must be ${ROUTE_CONTRACT_VERSION}.`);
408
603
  }
409
604
  if (route.execution.modelTier !== null && !ROUTE_MODEL_TIERS.has(route.execution.modelTier)) {
410
605
  errors.push(`execution.modelTier must be null or one of: ${[...ROUTE_MODEL_TIERS].join(', ')}.`);
411
606
  }
607
+ if (route.execution.effort !== null && route.execution.effort !== undefined
608
+ && !ROUTE_EFFORTS.has(route.execution.effort)) {
609
+ errors.push(`execution.effort must be null or one of: ${[...ROUTE_EFFORTS].join(', ')}.`);
610
+ }
412
611
  }
413
612
  if (!isObject(route.evidence)) {
414
613
  errors.push('evidence must be an object.');
@@ -418,6 +617,12 @@ export function validateResolvedRoute(route = null) {
418
617
  errors.push(`evidence.${key} must be an array.`);
419
618
  }
420
619
  }
620
+ if (Array.isArray(route.evidence.riskSignals)
621
+ && route.evidence.riskSignals.some(
622
+ (code) => typeof code !== 'string' || !ROUTE_RISK_REASON_CODES.includes(code),
623
+ )) {
624
+ errors.push(`evidence.riskSignals entries must be one of: ${ROUTE_RISK_REASON_CODES.join(', ')}.`);
625
+ }
421
626
  }
422
627
  if (!isObject(route.ceremonyBudget)) {
423
628
  errors.push('ceremonyBudget must be an object.');
@@ -1379,11 +1584,24 @@ async function main() {
1379
1584
  }
1380
1585
  : null;
1381
1586
  if (rescuedRouteSummary) {
1587
+ // FR-005: the rescued summary IS the previous route state — merge its
1588
+ // persisted riskEscalation with current evidence (monotonic, idempotent).
1589
+ const riskEscalation = computeRiskEscalation({
1590
+ routeSummary: rescuedRouteSummary,
1591
+ previousRouteSummary: cachedRouteState.routeSummary,
1592
+ config: escalationConfig,
1593
+ });
1594
+ if (riskEscalation) {
1595
+ rescuedRouteSummary.riskEscalation = riskEscalation;
1596
+ } else {
1597
+ delete rescuedRouteSummary.riskEscalation;
1598
+ }
1382
1599
  applyRescueBiasToRouteSummary(rescuedRouteSummary);
1383
1600
  applyEscalationToRouteSummary(rescuedRouteSummary, {
1384
1601
  config: escalationConfig,
1385
1602
  targetFile: cachedRouteState.routingContext?.targetFile ?? null,
1386
1603
  });
1604
+ appendRiskEscalationSegment(rescuedRouteSummary);
1387
1605
  }
1388
1606
  const sharedState = {
1389
1607
  ...cachedRouteState,
@@ -1673,11 +1891,25 @@ async function finalizeTaskRoute({
1673
1891
  previousRouteSummary?.continuationState ?? null,
1674
1892
  resolveEscalationSettings(escalationConfig),
1675
1893
  );
1894
+ // FR-005: merge risk evidence with the persisted previous riskEscalation AFTER
1895
+ // advanceContinuationState (stuckRisk is already advanced). Stage 'off'
1896
+ // returns null → the field is dropped, not carried forward.
1897
+ const riskEscalation = computeRiskEscalation({
1898
+ routeSummary,
1899
+ previousRouteSummary,
1900
+ config: escalationConfig,
1901
+ });
1902
+ if (riskEscalation) {
1903
+ routeSummary.riskEscalation = riskEscalation;
1904
+ } else {
1905
+ delete routeSummary.riskEscalation;
1906
+ }
1676
1907
  applyRescueBiasToRouteSummary(routeSummary);
1677
1908
  applyEscalationToRouteSummary(routeSummary, {
1678
1909
  config: escalationConfig,
1679
1910
  targetFile: routingContext.targetFile ?? null,
1680
1911
  });
1912
+ appendRiskEscalationSegment(routeSummary);
1681
1913
  const approachSelector = routeSummary?.approachSelector ?? null;
1682
1914
 
1683
1915
  return {
@@ -2672,6 +2904,48 @@ function buildRouteSummary({
2672
2904
  nextActionType: nextAction?.type ?? null,
2673
2905
  completionState,
2674
2906
  });
2907
+ // FR-003 (M01.2'): riskFloor is a top-level additive field emitted whenever ANY
2908
+ // of rigor/fastPath/escalation stages is on — fastPath/escalation consumers read
2909
+ // it even when routeSchema is off. All three off → absent, byte-identical route.
2910
+ const riskStageOn = ['rigor', 'fastPath', 'escalation']
2911
+ .some((key) => resolveRouteStage(runtimeConfig, key) !== 'off');
2912
+ const riskFloor = riskStageOn
2913
+ ? deriveRiskFloor({
2914
+ promptText: routingContext.promptText,
2915
+ commandText: routingContext.commandText,
2916
+ targetFile: routingContext.targetFile ?? null,
2917
+ executionMode,
2918
+ activeSkillIds: activeSkills.map((entry) => entry.id),
2919
+ contextPreview: contextRecommendation?.preview ?? null,
2920
+ })
2921
+ : null;
2922
+ const riskSegment = formatRiskFloorSegment(riskFloor);
2923
+ // FR-003 (M01.2' limits fragment): the rigor advisory — emitted whenever
2924
+ // rigor.stage is on, independent of fastPath/escalation. Stage off → no
2925
+ // segment, byte-identical route.
2926
+ const limitsSegment = resolveRouteStage(runtimeConfig, 'rigor') !== 'off'
2927
+ ? formatLimitsSegment(deriveCeremonyLimits(executionContract))
2928
+ : null;
2929
+ // FR-004 (M01.3'): fastPath is emitted whenever its own stage is on — the field
2930
+ // is always set then (eligible or not) so telemetry/harness can read it; the
2931
+ // route-line segment prints only for eligible routes.
2932
+ const fastPathStage = resolveRouteStage(runtimeConfig, 'fastPath');
2933
+ const fastPath = fastPathStage !== 'off'
2934
+ ? {
2935
+ eligible: false,
2936
+ suppressed: [],
2937
+ reasons: [],
2938
+ ...deriveFastPath({
2939
+ executionMode,
2940
+ targetFile: routingContext.targetFile ?? null,
2941
+ riskFloor,
2942
+ verificationRecommendation,
2943
+ contextPreview: contextRecommendation?.preview ?? null,
2944
+ }),
2945
+ stage: fastPathStage,
2946
+ }
2947
+ : null;
2948
+ const fastPathSegment = formatFastPathSegment(fastPath);
2675
2949
  const resolvedRouteFields = routeSchemaStage !== 'off'
2676
2950
  ? buildResolvedRouteFields({
2677
2951
  routingContext,
@@ -2679,6 +2953,7 @@ function buildRouteSummary({
2679
2953
  executionMode,
2680
2954
  executionContract,
2681
2955
  completionState,
2956
+ riskFloor,
2682
2957
  })
2683
2958
  : null;
2684
2959
  const helperHint = compactHelperHint(
@@ -2722,6 +2997,9 @@ function buildRouteSummary({
2722
2997
  formatCompactSegment('tests', relatedTests),
2723
2998
  formatCompactSegment('styles', styleFiles),
2724
2999
  editGuardHint ? `editGuard=${editGuardHint}` : null,
3000
+ riskSegment,
3001
+ limitsSegment,
3002
+ fastPathSegment,
2725
3003
  delegationRecommendation?.hint ? `delegate=${delegationRecommendation.hint}` : null,
2726
3004
  policyMode ? `policy=${policyMode}` : null,
2727
3005
  workflowPolicyName ? `workflow=${workflowPolicyName}` : null,
@@ -2742,6 +3020,10 @@ function buildRouteSummary({
2742
3020
  completionState,
2743
3021
  // M01.1 additive C01 groups — present only when routing.routeSchema.stage != "off".
2744
3022
  ...(resolvedRouteFields ?? {}),
3023
+ // FR-003 additive top-level field — present only when a risk stage is on.
3024
+ ...(riskFloor ? { riskFloor } : {}),
3025
+ // FR-004 additive top-level field — present only when fastPath stage is on.
3026
+ ...(fastPath ? { fastPath } : {}),
2745
3027
  continuationState,
2746
3028
  autonomyLevel,
2747
3029
  continuousExecution,
@@ -3208,6 +3490,45 @@ function buildExecutionContract(executionMode = null) {
3208
3490
  return contracts[executionMode] ? { ...contracts[executionMode] } : null;
3209
3491
  }
3210
3492
 
3493
+ // Decision table v2 (V3_RESHAPE §5): the contracts table's modelTier column is the
3494
+ // base row; resolveModelTier adds the (riskFloor, hostCapabilities) columns.
3495
+ // Deterministic — no registry, no leases, no outbound capability calls.
3496
+ // Literal mirror of src/core/executionContracts.js resolveModelTier; parity is
3497
+ // locked by tests/consistency/executionContractSync.test.js.
3498
+ const MODEL_TIER_ORDER = ['lite', 'code', 'smart'];
3499
+ const MODEL_TIER_EFFORT = {
3500
+ lite: 'low',
3501
+ code: 'medium',
3502
+ smart: 'high',
3503
+ };
3504
+
3505
+ /**
3506
+ * Resolves {tier, effort, advisoryOnly} for a route. A 'high-risk' floor escalates
3507
+ * the tier one band (lite→code→smart, capped at smart) and forces effort 'high'.
3508
+ * Unknown mode → {tier:null, effort:null, advisoryOnly:true}. Missing/unknown
3509
+ * riskFloor → 'none'. Missing hostCapabilities → advisoryOnly:true (the route text
3510
+ * is all the host gets when it cannot bind model and effort).
3511
+ */
3512
+ export function resolveModelTier({
3513
+ executionMode = null,
3514
+ riskFloor = null,
3515
+ hostCapabilities = null,
3516
+ } = {}) {
3517
+ const baseTier = buildExecutionContract(executionMode)?.modelTier ?? null;
3518
+ if (!baseTier) {
3519
+ return { tier: null, effort: null, advisoryOnly: true };
3520
+ }
3521
+ const highRisk = riskFloor?.floor === 'high-risk';
3522
+ const tier = highRisk
3523
+ ? MODEL_TIER_ORDER[Math.min(MODEL_TIER_ORDER.indexOf(baseTier) + 1, MODEL_TIER_ORDER.length - 1)]
3524
+ : baseTier;
3525
+ return {
3526
+ tier,
3527
+ effort: highRisk ? 'high' : MODEL_TIER_EFFORT[tier],
3528
+ advisoryOnly: !(hostCapabilities?.canBindModel === true && hostCapabilities?.canBindEffort === true),
3529
+ };
3530
+ }
3531
+
3211
3532
  function buildApproachSelectorResult({
3212
3533
  executionMode = null,
3213
3534
  executionScores = null,
@@ -3403,18 +3724,24 @@ function resolveEscalationSettings(config = null) {
3403
3724
  * Escalates exactly one rung above `modelTier` on `tierOrder`, capped at `cap`. Returns null when
3404
3725
  * escalation is disabled, `repeatCount` hasn't reached `debugLoopThreshold`, or `modelTier` isn't
3405
3726
  * on the cost ladder (e.g. no contract selected). Never returns 'vision'.
3727
+ * FR-005: when `riskEscalation.level === 'high'` the repeat-count threshold is treated as
3728
+ * satisfied (immediate one-rung escalation) and the effective cap rises to 'smart', overriding
3729
+ * the configured cap; the reason is prefixed `risk-floor:` so consumers can tell risk-driven
3730
+ * escalation from repeat-count escalation.
3406
3731
  */
3407
3732
  function computeEscalation({
3408
3733
  modelTier = null,
3409
3734
  repeatCount = null,
3410
3735
  config = null,
3411
3736
  targetFile = null,
3737
+ riskEscalation = null,
3412
3738
  } = {}) {
3413
- if (!modelTier || !Number.isFinite(repeatCount)) {
3739
+ if (!modelTier) {
3414
3740
  return null;
3415
3741
  }
3416
3742
  const settings = resolveEscalationSettings(config);
3417
- if (!settings.enabled || repeatCount < settings.debugLoopThreshold) {
3743
+ const riskDriven = riskEscalation?.level === 'high';
3744
+ if (!settings.enabled || (!riskDriven && (!Number.isFinite(repeatCount) || repeatCount < settings.debugLoopThreshold))) {
3418
3745
  return null;
3419
3746
  }
3420
3747
  const currentIndex = settings.tierOrder.indexOf(modelTier);
@@ -3422,18 +3749,23 @@ function computeEscalation({
3422
3749
  return null;
3423
3750
  }
3424
3751
  const capIndex = settings.tierOrder.indexOf(settings.cap);
3425
- const effectiveCapIndex = capIndex === -1 ? settings.tierOrder.length - 1 : capIndex;
3752
+ const smartIndex = settings.tierOrder.indexOf('smart');
3753
+ const effectiveCapIndex = riskDriven
3754
+ ? (smartIndex === -1 ? settings.tierOrder.length - 1 : smartIndex)
3755
+ : (capIndex === -1 ? settings.tierOrder.length - 1 : capIndex);
3426
3756
  const escalatedIndex = Math.min(currentIndex + 1, effectiveCapIndex);
3427
3757
  const escalatedTier = settings.tierOrder[escalatedIndex];
3428
3758
 
3429
3759
  return {
3430
3760
  escalatedTier,
3431
- escalationReason: `repeat-count=${repeatCount} threshold=${settings.debugLoopThreshold} file=${targetFile ?? 'null'}`,
3761
+ escalationReason: riskDriven
3762
+ ? `risk-floor: level=${riskEscalation.level} sources=${(riskEscalation.sources ?? []).join(',')} file=${targetFile ?? 'null'}`
3763
+ : `repeat-count=${repeatCount} threshold=${settings.debugLoopThreshold} file=${targetFile ?? 'null'}`,
3432
3764
  };
3433
3765
  }
3434
3766
 
3435
3767
  /** Attaches escalatedTier/escalationReason to routeSummary, additive alongside modelTier. */
3436
- function applyEscalationToRouteSummary(routeSummary = null, { config = null, targetFile = null } = {}) {
3768
+ export function applyEscalationToRouteSummary(routeSummary = null, { config = null, targetFile = null } = {}) {
3437
3769
  if (!routeSummary || typeof routeSummary !== 'object') {
3438
3770
  return routeSummary;
3439
3771
  }
@@ -3443,6 +3775,7 @@ function applyEscalationToRouteSummary(routeSummary = null, { config = null, tar
3443
3775
  repeatCount: routeSummary.continuationState?.repeatCount ?? null,
3444
3776
  config,
3445
3777
  targetFile,
3778
+ riskEscalation: routeSummary.riskEscalation ?? null,
3446
3779
  });
3447
3780
 
3448
3781
  if (escalation) {
@@ -3462,6 +3795,65 @@ function applyEscalationToRouteSummary(routeSummary = null, { config = null, tar
3462
3795
  return routeSummary;
3463
3796
  }
3464
3797
 
3798
+ // FR-005 (M01.4'): monotonic risk-evidence escalation. Sources are `risk-floor`
3799
+ // (routeSummary.riskFloor.floor === 'high-risk') and `stuck-risk`
3800
+ // (routeSummary.continuationState.stuckRisk === 'high' — read off the CURRENT
3801
+ // summary, which finalizeTaskRoute has already advanced). Sources merge as the
3802
+ // sorted union of current evidence and the persisted previous
3803
+ // riskEscalation.sources, so replaying the same evidence is a no-op and the
3804
+ // level can never decrease within a run (none < elevated < high). Stage 'off'
3805
+ // returns null unconditionally — a mid-run stage flip drops the field entirely
3806
+ // so the Stop gate sees nothing and the stage-off byte-identity contract holds.
3807
+ // Per-source flags: routing.escalation.sources.<source>: false disables that
3808
+ // source's current detection (absent = all sources on).
3809
+ const RISK_ESCALATION_LEVELS = { none: 0, elevated: 1, high: 2 };
3810
+
3811
+ export function computeRiskEscalation({
3812
+ routeSummary = null,
3813
+ previousRouteSummary = null,
3814
+ config = null,
3815
+ } = {}) {
3816
+ const stage = resolveRouteStage(config, 'escalation');
3817
+ if (stage === 'off') {
3818
+ return null;
3819
+ }
3820
+ const sourceFlags = config?.routing?.escalation?.sources ?? {};
3821
+ const isSourceEnabled = (source) => sourceFlags[source] !== false;
3822
+ const currentSources = [];
3823
+ if (isSourceEnabled('risk-floor') && routeSummary?.riskFloor?.floor === 'high-risk') {
3824
+ currentSources.push('risk-floor');
3825
+ }
3826
+ if (isSourceEnabled('stuck-risk') && routeSummary?.continuationState?.stuckRisk === 'high') {
3827
+ currentSources.push('stuck-risk');
3828
+ }
3829
+ const previous = previousRouteSummary?.riskEscalation ?? null;
3830
+ const sources = unique([...(previous?.sources ?? []), ...currentSources]).sort();
3831
+ const derivedLevel = sources.some((source) => source === 'risk-floor' || source === 'stuck-risk')
3832
+ ? 'high'
3833
+ : (sources.length > 0 ? 'elevated' : 'none');
3834
+ const previousLevel = RISK_ESCALATION_LEVELS[previous?.level] ?? 0;
3835
+ const level = RISK_ESCALATION_LEVELS[derivedLevel] >= previousLevel
3836
+ ? derivedLevel
3837
+ : previous.level;
3838
+ return { level, sources, stage };
3839
+ }
3840
+
3841
+ // FR-005: buildRouteSummary runs before riskEscalation exists, so the
3842
+ // `escalate=<level>(<sources>)` segment is appended here, where the merge
3843
+ // happens. Any previously emitted segment is stripped first — replay on a
3844
+ // rescued compacted summary must not double-append (idempotent).
3845
+ function appendRiskEscalationSegment(routeSummary = null) {
3846
+ if (!routeSummary || typeof routeSummary.line !== 'string') {
3847
+ return routeSummary;
3848
+ }
3849
+ const baseLine = routeSummary.line.replace(/(?: \| )?escalate=\S+$/, '');
3850
+ const riskEscalation = routeSummary.riskEscalation;
3851
+ routeSummary.line = riskEscalation && riskEscalation.level !== 'none'
3852
+ ? `${baseLine} | escalate=${riskEscalation.level}(${(riskEscalation.sources ?? []).join(',')})`
3853
+ : baseLine;
3854
+ return routeSummary;
3855
+ }
3856
+
3465
3857
  // WS-E tier-role wiring: a contract tier only takes effect when the executing session hands
3466
3858
  // the work to an agent whose definition binds that tier — otherwise every session behaves as
3467
3859
  // if it only had one model. `code` is the DEFAULT implementation lane, so a code-tier contract
@@ -3690,10 +4082,10 @@ const SHARED_IMPACT_PATTERNS = [
3690
4082
  /^src\/index\//,
3691
4083
  /^src\/core\/(runInstallPipeline|applyPlan|buildPlan|diffPlan|metadata|migrateLegacy|uninstall|runtimeConfig|runtimePaths)\.js$/,
3692
4084
  /^src\/core\/(output|token|compact)\//,
3693
- /^templates\/\.claude\/hooks\//,
3694
- /^templates\/\.claude\/ukit\//,
4085
+ /^template_project\/\.claude\/hooks\//,
4086
+ /^template_project\/\.claude\/ukit\//,
3695
4087
  /^manifests\/platform\.full\.yaml$/,
3696
- /^templates\//,
4088
+ /^template_project\//,
3697
4089
  ];
3698
4090
 
3699
4091
  function isSharedImpactFile(filePath) {
@@ -4179,7 +4571,7 @@ function compactRecentOutput(recentOutput = null) {
4179
4571
  };
4180
4572
  }
4181
4573
 
4182
- function compactRouteSummary(routeSummary = null) {
4574
+ export function compactRouteSummary(routeSummary = null) {
4183
4575
  if (!routeSummary) {
4184
4576
  return null;
4185
4577
  }
@@ -4221,6 +4613,10 @@ function compactRouteSummary(routeSummary = null) {
4221
4613
  escalatedTier: routeSummary.escalatedTier,
4222
4614
  escalationReason: routeSummary.escalationReason ?? null,
4223
4615
  } : {}),
4616
+ // FR-005: riskEscalation is the Stop-gate carrier (FR-006) — it must survive
4617
+ // skill-router-state.json compaction. Conditional spread keeps stage-off
4618
+ // output byte-identical (no key emitted when the field is absent).
4619
+ ...(routeSummary.riskEscalation ? { riskEscalation: routeSummary.riskEscalation } : {}),
4224
4620
  // M01.1 compact whitelist (C01): grouped fields survive compaction minus verbose
4225
4621
  // evidence; absent entirely when the route schema stage is off.
4226
4622
  ...(compactResolvedRoute(routeSummary) ?? {}),
@@ -35,7 +35,7 @@
35
35
  * Fail-safe direction (do not re-flip this): `unicMode` keeps BINARY semantics on every runtime
36
36
  * — `unicMode = sources.length > 0`, default `false`. Inconclusive detection never resolves to
37
37
  * `true`. The "assume UNIC when ambiguous" fail-safe some tools want belongs ONLY to the static
38
- * `modelRoles` values TASK-003 writes unconditionally into `templates/.omp/config.yml`
38
+ * `modelRoles` values TASK-003 writes unconditionally into `template_project/.omp/config.yml`
39
39
  * (`@vision: unic-vision`, no probe involved) — never to this module's boolean, because this
40
40
  * module is shared by every runtime and flipping its default would make Codex/Kilo/OPENAI_BASE_URL
41
41
  * sessions with zero omp/Claude signal start false-positively reporting UNIC mode.
@@ -1588,7 +1588,7 @@ export async function recordExecutionReceipt({
1588
1588
  }
1589
1589
 
1590
1590
  // F-15: mirror of isExplicitBroadVerificationRequest in
1591
- // templates/.claude/hooks/verification-guard.sh — the guard uses this prompt signal to
1591
+ // template_project/.claude/hooks/verification-guard.sh — the guard uses this prompt signal to
1592
1592
  // let a broad suite run under a targeted policy, so the completion gate must honor the
1593
1593
  // same signal when it classifies the resulting broad receipt. Keep both lists in sync.
1594
1594
  function isExplicitBroadVerificationRequest(promptText) {
@@ -1628,10 +1628,19 @@ function explicitBroadVerificationRequested(state = {}) {
1628
1628
  function requiredEvidence(state = {}) {
1629
1629
  const routeSummary = state?.routeSummary || {};
1630
1630
  const contractEvidence = routeSummary.executionContract?.completionEvidence;
1631
- if (Array.isArray(contractEvidence) && contractEvidence.length > 0) {
1632
- return [...new Set(contractEvidence)];
1633
- }
1634
- return [...new Set(routeSummary.completionState?.missingEvidence || [])];
1631
+ const required = Array.isArray(contractEvidence) && contractEvidence.length > 0
1632
+ ? [...contractEvidence]
1633
+ : [...(routeSummary.completionState?.missingEvidence || [])];
1634
+ // FR-006 (M01.4' tail): a route persisted with a high riskEscalation must re-verify at
1635
+ // Stop even when its own contract only demands write evidence. The route state is the
1636
+ // carrier — no config read here; absent/malformed/non-high fields are a no-op.
1637
+ // C48 FR-004: a record stamped `stage: 'shadow'` is advisory-only and does not demand
1638
+ // verification-evidence; a missing or malformed stage fails closed (enforcing) so
1639
+ // pre-C48 persisted records keep re-verifying until re-stamped.
1640
+ if (routeSummary.riskEscalation?.level === 'high' && routeSummary.riskEscalation?.stage !== 'shadow') {
1641
+ required.push('verification-evidence');
1642
+ }
1643
+ return [...new Set(required)];
1635
1644
  }
1636
1645
 
1637
1646
  function evidenceSatisfied(evidence, ledger = {}, state = {}, { cwd } = {}) {
@@ -27,15 +27,15 @@ const SHARED_RISK_PATTERNS = [
27
27
  /^\.claude\/hooks\//,
28
28
  /^\.claude\/ukit\//,
29
29
  /^\.codex\//,
30
- /^templates\/\.claude\/hooks\//,
31
- /^templates\/\.claude\/ukit\//,
30
+ /^template_project\/\.claude\/hooks\//,
31
+ /^template_project\/\.claude\/ukit\//,
32
32
  /^src\/index\//,
33
33
  /^src\/core\/(runInstallPipeline|applyPlan|buildPlan|diffPlan|metadata|migrateLegacy|uninstall|runtimeConfig|runtimePaths)\.js$/,
34
34
  /^src\/core\/(output|token|compact)\//,
35
35
  /^manifests\/platform\.full\.yaml$/,
36
36
  // Intentional for UKit development: template edits become installed runtime behavior after `ukit install`,
37
37
  // so templates stay in the strict shared-risk lane rather than being treated as ordinary docs/assets.
38
- /^templates\//,
38
+ /^template_project\//,
39
39
  /^scripts\//,
40
40
  /(^|\/)(AGENTS|CLAUDE)\.md$/,
41
41
  ];
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Installed-runtime mirror of src/core/sensitiveValueScanner.js — the
5
5
  * high-confidence secret *value* scanner shared with
6
- * templates/.claude/hooks/sensitive-data-guard.sh. Deliberate mirror: the
6
+ * template_project/.claude/hooks/sensitive-data-guard.sh. Deliberate mirror: the
7
7
  * installed runtime cannot import package source, so this file is kept
8
8
  * byte-semantic with the source module and locked by
9
9
  * tests/consistency/projectImportantRuntimeParity.test.js.