@event4u/agent-config 14.10.0 → 14.11.0

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 (399) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +335 -0
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/design.md +88 -0
  7. package/dist/agent-src/commands/project/analyze.md +47 -0
  8. package/dist/agent-src/commands/review/changes.md +67 -6
  9. package/dist/agent-src/commands/roadmap/create.md +49 -0
  10. package/dist/agent-src/commands/roadmap/next.md +27 -11
  11. package/dist/agent-src/commands/roadmap/process-full.md +14 -0
  12. package/dist/agent-src/commands/video/from-script.md +60 -3
  13. package/dist/agent-src/commands/video/stitch.md +14 -0
  14. package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
  15. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
  16. package/dist/agent-src/rules/active-remediation.md +3 -3
  17. package/dist/agent-src/rules/code-provenance.md +2 -2
  18. package/dist/agent-src/rules/context-hygiene.md +13 -33
  19. package/dist/agent-src/rules/council-availability.md +2 -2
  20. package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
  21. package/dist/agent-src/rules/design-fidelity.md +18 -0
  22. package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
  23. package/dist/agent-src/rules/evaluator-independence.md +56 -44
  24. package/dist/agent-src/rules/fix-what-you-see.md +9 -1
  25. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  26. package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
  27. package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
  28. package/dist/agent-src/rules/playbook-precedence.md +105 -0
  29. package/dist/agent-src/rules/recurring-criticism.md +3 -1
  30. package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
  31. package/dist/agent-src/rules/scale-discipline.md +24 -0
  32. package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
  33. package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
  34. package/dist/agent-src/rules/ui-audit-gate.md +27 -15
  35. package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
  36. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
  37. package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
  38. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
  39. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
  40. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
  41. package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
  42. package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
  43. package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
  44. package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
  45. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
  46. package/dist/agent-src/skills/brand/SKILL.md +3 -0
  47. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
  48. package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
  49. package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
  50. package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
  51. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
  52. package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
  53. package/dist/agent-src/skills/code-review/SKILL.md +11 -0
  54. package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
  55. package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
  56. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  57. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
  58. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
  59. package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
  60. package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
  61. package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
  62. package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
  63. package/dist/agent-src/skills/design-review/SKILL.md +79 -1
  64. package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
  65. package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
  66. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
  67. package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
  68. package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
  69. package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
  70. package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
  71. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
  72. package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
  73. package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
  74. package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
  75. package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
  76. package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
  77. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  78. package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
  79. package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
  80. package/dist/agent-src/skills/iconography/SKILL.md +3 -0
  81. package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
  82. package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
  83. package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
  84. package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
  85. package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
  86. package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
  87. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
  88. package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
  89. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
  90. package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
  91. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
  92. package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
  93. package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
  94. package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
  95. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
  96. package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
  97. package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
  98. package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
  99. package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
  100. package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
  101. package/dist/agent-src/skills/override-management/SKILL.md +3 -0
  102. package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
  103. package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
  104. package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
  105. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
  106. package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
  107. package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
  108. package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
  109. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
  110. package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
  111. package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
  112. package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
  113. package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
  114. package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
  115. package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
  116. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  117. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  118. package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
  119. package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
  120. package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
  121. package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
  122. package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
  123. package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
  124. package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
  125. package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
  126. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
  127. package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
  128. package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
  129. package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
  130. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
  131. package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
  132. package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
  133. package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
  134. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  135. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
  136. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
  137. package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
  138. package/dist/agent-src/skills/terraform/SKILL.md +3 -0
  139. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
  140. package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
  141. package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
  142. package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
  143. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
  144. package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
  145. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
  146. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
  147. package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
  148. package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
  149. package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
  150. package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
  151. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  152. package/dist/agent-src/templates/playbook.md +75 -0
  153. package/dist/agent-src/templates/roadmaps.md +37 -0
  154. package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  155. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  156. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  157. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  158. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  159. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  160. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  161. package/dist/cli/commands/uiAudit.js +221 -0
  162. package/dist/cli/commands/uiAudit.js.map +1 -0
  163. package/dist/cli/commands/uiRender.js +206 -0
  164. package/dist/cli/commands/uiRender.js.map +1 -0
  165. package/dist/cli/main.js +22 -1
  166. package/dist/cli/main.js.map +1 -1
  167. package/dist/cli/mcp/content.js +64 -1
  168. package/dist/cli/mcp/content.js.map +1 -1
  169. package/dist/cli/mcp/dispatch.js +175 -10
  170. package/dist/cli/mcp/dispatch.js.map +1 -1
  171. package/dist/cli/registry.js +3 -0
  172. package/dist/cli/registry.js.map +1 -1
  173. package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
  174. package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
  175. package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
  176. package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
  177. package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
  178. package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
  179. package/dist/cli-delegate/cmd_brand_status.js +8 -6
  180. package/dist/cli-delegate/cmd_conformance.js +3 -3
  181. package/dist/cli-delegate/cmd_doctor.js +3 -3
  182. package/dist/cli-delegate/cmd_export.js +4 -4
  183. package/dist/cli-delegate/cmd_handoff.js +1 -1
  184. package/dist/cli-delegate/cmd_preflight.js +2 -2
  185. package/dist/cli-delegate/cmd_prune.js +4 -4
  186. package/dist/cli-delegate/cmd_session_recycle.js +70 -9
  187. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  188. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  189. package/dist/cli-delegate/cmd_sync.js +4 -4
  190. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  191. package/dist/cli-delegate/cmd_validate.js +4 -4
  192. package/dist/discovery/deprecation-report.md +1 -1
  193. package/dist/discovery/discovery-manifest.json +359 -124
  194. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  195. package/dist/discovery/discovery-manifest.summary.md +4 -4
  196. package/dist/discovery/dormancy-report.md +1 -1
  197. package/dist/discovery/orphan-report.md +1 -1
  198. package/dist/discovery/packs.json +18 -8
  199. package/dist/discovery/trust-report.md +3 -3
  200. package/dist/discovery/workspaces.json +16 -6
  201. package/dist/hooks/dispatch.js +2337 -1436
  202. package/dist/install/install.mjs +795 -708
  203. package/dist/mcp/registry-manifest.json +3 -3
  204. package/dist/mcp/server.json +2 -2
  205. package/dist/mcp/server.mjs +1685 -1250
  206. package/dist/router.json +1 -1
  207. package/dist/scripts/_lib/lean_projection_mode.js +40 -0
  208. package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
  209. package/dist/scripts/_lib/scoped_projection.js +84 -0
  210. package/dist/scripts/_lib/scoped_projection.js.map +1 -1
  211. package/dist/scripts/_lib/ui_surface.js +89 -0
  212. package/dist/scripts/_lib/ui_surface.js.map +1 -0
  213. package/dist/scripts/condense.js +6 -10
  214. package/dist/scripts/condense.js.map +1 -1
  215. package/dist/scripts/project_thin_rules.js +40 -2
  216. package/dist/scripts/project_thin_rules.js.map +1 -1
  217. package/dist/server/schemas/settings.js +3 -0
  218. package/dist/server/schemas/settings.js.map +1 -1
  219. package/dist/shared/skillRanking.js +159 -0
  220. package/dist/shared/skillRanking.js.map +1 -0
  221. package/docs/contracts/provider-lifecycle.md +47 -18
  222. package/docs/contracts/settings-classes.md +14 -4
  223. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
  224. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  225. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
  226. package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  227. package/docs/guidelines/design-antipatterns.md +4 -2
  228. package/docs/guidelines/design-asset-discipline.md +38 -0
  229. package/docs/guidelines/design-fidelity-mechanics.md +45 -29
  230. package/docs/guidelines/design-handover-extraction.md +35 -5
  231. package/docs/guidelines/design-modes.md +41 -1
  232. package/docs/guidelines/monorepo-antipatterns.md +141 -0
  233. package/llms.txt +50 -39
  234. package/package.json +1 -1
  235. package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  236. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  237. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  238. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  239. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  240. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  241. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  242. package/src/config/agent-settings.template.yml +28 -0
  243. package/src/config/assurance-capability-registry.json +223 -0
  244. package/src/config/assurance-threshold-budget.json +65 -0
  245. package/src/config/ci-local-parity.yml +14 -0
  246. package/src/config/discovery/unassigned-artefacts.yml +2 -0
  247. package/src/config/dispatch-economy-metrics.json +4 -2
  248. package/src/config/evaluator-budgets.json +14 -14
  249. package/src/config/gate-coverage.yml +207 -8
  250. package/src/config/gate-violation-baselines.json +76 -72
  251. package/src/config/hook-latency-budget.json +1 -0
  252. package/src/config/hook-token-budget.json +137 -125
  253. package/src/config/pack-size-budget.json +4 -2
  254. package/src/config/quorum-attendance-budget.json +12 -4
  255. package/src/config/rule-activation-census.json +7 -3
  256. package/src/config/rule-enforcement-baseline.json +0 -1
  257. package/src/config/rule-stub-ceilings.json +112 -91
  258. package/src/scripts/_cli/cmd_doctor.ts +15 -16
  259. package/src/scripts/_cli/doctor_install_mode.ts +49 -0
  260. package/src/scripts/_cli/doctor_overrides.ts +154 -0
  261. package/src/scripts/_dispatch.bash +17 -0
  262. package/src/scripts/_lib/as_of.ts +412 -0
  263. package/src/scripts/_lib/exec_evidence.ts +7 -0
  264. package/src/scripts/_lib/hook_settings.ts +33 -0
  265. package/src/scripts/_lib/host_listing_model.ts +192 -0
  266. package/src/scripts/_lib/lean_projection_mode.ts +44 -0
  267. package/src/scripts/_lib/mcp_bridge.ts +199 -0
  268. package/src/scripts/_lib/review_independence.ts +62 -10
  269. package/src/scripts/_lib/rule_injection.ts +239 -0
  270. package/src/scripts/_lib/run_checkpoint.ts +54 -1
  271. package/src/scripts/_lib/scoped_projection.ts +96 -0
  272. package/src/scripts/_lib/session_register.ts +44 -2
  273. package/src/scripts/_lib/skill_catalogue.ts +38 -2
  274. package/src/scripts/_lib/transcript_reads.ts +207 -0
  275. package/src/scripts/_lib/ui_authority.test.ts +251 -0
  276. package/src/scripts/_lib/ui_authority.ts +343 -0
  277. package/src/scripts/ai-video/adapters/fal.sh +8 -3
  278. package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
  279. package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
  280. package/src/scripts/ai-video/adapters/kling.sh +10 -0
  281. package/src/scripts/ai-video/adapters/sora.sh +10 -0
  282. package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
  283. package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
  284. package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
  285. package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
  286. package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
  287. package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
  288. package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
  289. package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
  290. package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
  291. package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
  292. package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
  293. package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
  294. package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
  295. package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
  296. package/src/scripts/ai-video/smoke-trace.sh +450 -2
  297. package/src/scripts/ai-video/stitch.sh +191 -10
  298. package/src/scripts/ai-video/test-pipeline.sh +84 -6
  299. package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
  300. package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
  301. package/src/scripts/ai_council/clients.ts +3 -2
  302. package/src/scripts/ai_council/consensus.ts +63 -6
  303. package/src/scripts/ai_council/events_log.ts +46 -1
  304. package/src/scripts/ai_council/orchestrator.ts +103 -108
  305. package/src/scripts/ai_council/orchestrator_results.ts +166 -0
  306. package/src/scripts/ai_council/prompts.ts +12 -5
  307. package/src/scripts/ai_council/quorum.ts +82 -1
  308. package/src/scripts/ai_council/quorum_wiring.ts +82 -5
  309. package/src/scripts/ai_council/stance_tally.ts +22 -0
  310. package/src/scripts/bench_hook_latency.ts +62 -0
  311. package/src/scripts/build_proof.ts +12 -1
  312. package/src/scripts/capture_skill_catalogue.ts +21 -0
  313. package/src/scripts/check_always_budget.ts +2 -1
  314. package/src/scripts/check_augmentignore.ts +2 -1
  315. package/src/scripts/check_beta_review_markers.ts +2 -1
  316. package/src/scripts/check_composite_arming.ts +364 -0
  317. package/src/scripts/check_corpus_staleness.ts +2 -1
  318. package/src/scripts/check_council_pin_staleness.ts +3 -1
  319. package/src/scripts/check_enforcement_coverage.ts +116 -3
  320. package/src/scripts/check_enforcement_denominator.ts +365 -0
  321. package/src/scripts/check_gate_coverage.ts +2 -1
  322. package/src/scripts/check_hook_bundle_freshness.ts +13 -1
  323. package/src/scripts/check_knowledge_cards.ts +2 -1
  324. package/src/scripts/check_knowledge_pages.ts +3 -2
  325. package/src/scripts/check_memory.ts +2 -1
  326. package/src/scripts/check_no_automerge_key.ts +287 -0
  327. package/src/scripts/check_pack_conformance_fixture.ts +565 -0
  328. package/src/scripts/check_proposal.ts +2 -1
  329. package/src/scripts/check_reach_staleness.ts +2 -1
  330. package/src/scripts/check_release_adjacent_health.ts +2 -1
  331. package/src/scripts/check_release_pr_shape.ts +5 -0
  332. package/src/scripts/check_review_schema.ts +34 -1
  333. package/src/scripts/check_roadmap_trackable.ts +48 -3
  334. package/src/scripts/check_source_size_budget.ts +2 -1
  335. package/src/scripts/check_standing_payload_delta.ts +505 -0
  336. package/src/scripts/check_trigger_evals.ts +2 -1
  337. package/src/scripts/classify_change_risk.ts +281 -0
  338. package/src/scripts/compute_skill_tiers.ts +186 -0
  339. package/src/scripts/condense.ts +8 -13
  340. package/src/scripts/council_attendance_metrics.ts +183 -0
  341. package/src/scripts/council_cli.ts +10 -8
  342. package/src/scripts/council_parse_rate.ts +116 -0
  343. package/src/scripts/derive_playbooks.ts +406 -0
  344. package/src/scripts/design_slop_rules.test.ts +7 -0
  345. package/src/scripts/design_slop_rules.ts +56 -2
  346. package/src/scripts/dispatch_r2_reviewer.ts +16 -0
  347. package/src/scripts/frontend_corpus_hash.ts +116 -0
  348. package/src/scripts/grade_target_readiness.ts +478 -0
  349. package/src/scripts/hook_manifest.json +1 -1
  350. package/src/scripts/hook_manifest.yaml +97 -16
  351. package/src/scripts/hooks/concern_registry.ts +4 -0
  352. package/src/scripts/hooks/design_pass_hook.ts +356 -0
  353. package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
  354. package/src/scripts/hooks/rule_inject_hook.ts +318 -0
  355. package/src/scripts/hot_context_hook.ts +74 -7
  356. package/src/scripts/install.ts +40 -89
  357. package/src/scripts/lint_adapter_tier.ts +663 -0
  358. package/src/scripts/lint_archived_skills.ts +93 -0
  359. package/src/scripts/lint_budget_ownership.ts +2 -1
  360. package/src/scripts/lint_deterministic_time.ts +470 -0
  361. package/src/scripts/lint_framework_leakage.ts +5 -0
  362. package/src/scripts/lint_handoffs.ts +525 -1
  363. package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
  364. package/src/scripts/lint_marketplace.ts +88 -0
  365. package/src/scripts/lint_media_policy_linkage.ts +140 -1
  366. package/src/scripts/lint_one_off_age.ts +6 -1
  367. package/src/scripts/lint_override_kernel_guard.ts +87 -5
  368. package/src/scripts/lint_roadmap_complexity.ts +56 -0
  369. package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
  370. package/src/scripts/lint_rule_norm_pin.ts +321 -0
  371. package/src/scripts/lint_spawn_payload.ts +42 -5
  372. package/src/scripts/lint_symptom_intake.ts +2 -1
  373. package/src/scripts/mcp_parity_smoke.ts +30 -4
  374. package/src/scripts/mcp_render.ts +66 -1
  375. package/src/scripts/mcp_tool_fingerprint.ts +241 -0
  376. package/src/scripts/measure_risk_class_drift.ts +140 -0
  377. package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
  378. package/src/scripts/media/lib/adapter-common.sh +211 -1
  379. package/src/scripts/media/lib/adapter-contract.md +74 -6
  380. package/src/scripts/model_rule_injection.ts +907 -0
  381. package/src/scripts/project_thin_rules.ts +45 -2
  382. package/src/scripts/release.ts +66 -860
  383. package/src/scripts/release_drill.ts +59 -3
  384. package/src/scripts/release_env.ts +298 -0
  385. package/src/scripts/release_publication.ts +720 -0
  386. package/src/scripts/roadmap_context.ts +778 -0
  387. package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
  388. package/src/scripts/schemas/rule.schema.json +24 -2
  389. package/src/scripts/schemas/skill.schema.json +39 -0
  390. package/src/scripts/schemas/ui-authority.schema.json +114 -0
  391. package/src/scripts/session_register_hook.ts +29 -3
  392. package/src/scripts/sessions_cli.ts +67 -3
  393. package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
  394. package/src/scripts/token_sink_report.ts +239 -0
  395. package/src/scripts/trigger_coverage.ts +122 -3
  396. package/src/scripts/update_counts.ts +7 -3
  397. package/src/scripts/validate_frontmatter.ts +66 -0
  398. package/src/server/schemas/settings.ts +5 -0
  399. package/src/shared/skillRanking.ts +183 -0
@@ -18,6 +18,7 @@ import {
18
18
  import {
19
19
  is_ambiguous_stack,
20
20
  bundle_line,
21
+ scope_lines,
21
22
  unsupported_stack_questions,
22
23
  } from './stack_bundles.js';
23
24
 
@@ -266,6 +267,7 @@ function _delegate_to_polish_skill(
266
267
  agent_directive(directive),
267
268
  `> Stack: \`${stack_label}\`. Polish round ${next_round} of ${ceiling}.`,
268
269
  bundle_line(state.stack, 'build', stack_label),
270
+ ...scope_lines(state.stack),
269
271
  findings_line,
270
272
  '> Fix chart-type / contrast findings against the adopted ' +
271
273
  "corpus rows (design-intelligence § 'Grounding the " +
@@ -19,6 +19,7 @@ import {
19
19
  import {
20
20
  is_ambiguous_stack,
21
21
  bundle_line,
22
+ scope_lines,
22
23
  unsupported_stack_questions,
23
24
  } from './stack_bundles.js';
24
25
 
@@ -50,6 +51,29 @@ export const SEVERITY_ORDER: Record<string, number> = {
50
51
  /** R4 a11y default severity floor. */
51
52
  export const DEFAULT_SEVERITY_FLOOR = 'moderate';
52
53
 
54
+ /**
55
+ * Marker on a review finding that flags a hardcoded design value.
56
+ *
57
+ * Deliberately re-declared rather than imported from `polish.ts`: the two
58
+ * directives are siblings with no dependency edge between them, and
59
+ * `token_violation_kinds_agree` in the Phase 3 test pins the two literals
60
+ * equal so the duplication cannot drift silently.
61
+ */
62
+ export const TOKEN_VIOLATION_KIND = 'token_violation';
63
+
64
+ /** A finding produced by a deterministic check, not by an agent's judgement. */
65
+ export const DETECTOR_CHANNEL = 'detector';
66
+
67
+ /**
68
+ * A finding produced by an agent reading the surface.
69
+ *
70
+ * Named here only so the two channels are readable side by side. The prose
71
+ * channel (`tailwind-engineer` § arbitrary values) is unchanged by the
72
+ * detector — the detector is additive, and a finding that carries no
73
+ * `channel` at all predates the split and is treated as judgement.
74
+ */
75
+ export const JUDGEMENT_CHANNEL = 'judgement';
76
+
53
77
  export const AMBIGUITIES: ReadonlyArray<Record<string, string>> = [
54
78
  {
55
79
  code: 'review_envelope_missing',
@@ -151,11 +175,15 @@ export function run(state: DeliveryState): StepResult {
151
175
  return a11y_halt;
152
176
  }
153
177
 
178
+ _apply_token_detector(state, r);
179
+
154
180
  const preview_halt = _apply_preview_gate(state, r);
155
181
  if (preview_halt !== null) {
156
182
  return preview_halt;
157
183
  }
158
184
 
185
+ _stamp_verdict_scope(r);
186
+
159
187
  return new StepResult({ outcome: Outcome.SUCCESS });
160
188
  }
161
189
 
@@ -210,6 +238,7 @@ function _delegate_to_review_skill(state: DeliveryState): StepResult {
210
238
  `> Stack: \`${stack_label}\`. Reviewing rendered components ` +
211
239
  'against the locked design brief.',
212
240
  bundle_line(state.stack, 'review', stack_label),
241
+ ...scope_lines(state.stack),
213
242
  '> The review pass compares `state.ticket.ui_apply.rendered` ' +
214
243
  'against `state.ui_design` (microcopy, states, a11y, layout) ' +
215
244
  'and produces a structured `findings` list.',
@@ -372,6 +401,193 @@ function _synthesize_a11y_findings(findings: Any[], actionable: Any[]): void {
372
401
  }
373
402
  }
374
403
 
404
+ /**
405
+ * Return the audit token category whose bucket holds `value`, or null.
406
+ *
407
+ * This predicate IS the pre-registered scope of the measured dimension: "a raw
408
+ * literal where the audit found a token". A value the audit holds no token for
409
+ * is outside it and is never emitted — the `F4-unscoped` falsifier
410
+ * (`agents/evidence/analysis/frontend-fidelity-preregistered-falsifiers.md`)
411
+ * fires on a detector that flags every literal instead.
412
+ *
413
+ * Membership is tested with `Object.values(bucket).includes(value)`, the exact
414
+ * predicate `polish._classify_token_violations` uses. Sharing the predicate is
415
+ * what makes every detector-produced finding classify as `matched` downstream,
416
+ * so the detector channel can never trip the token-extraction halt.
417
+ */
418
+ function _audit_token_category(tokens: Record<string, Any>, value: string): string | null {
419
+ for (const category of Object.keys(tokens)) {
420
+ const bucket = tokens[category];
421
+ if (_isDict(bucket) && Object.values(bucket).includes(value)) {
422
+ return category;
423
+ }
424
+ }
425
+ return null;
426
+ }
427
+
428
+ /** Return `state.ui_audit.design_tokens` as a dict, or `{}`. */
429
+ function _audit_design_tokens(state: DeliveryState): Record<string, Any> {
430
+ const audit = _pyTruthy(state.ui_audit) ? state.ui_audit : {};
431
+ if (!_isDict(audit)) {
432
+ return {};
433
+ }
434
+ const tokens = _pyTruthy(audit['design_tokens']) ? audit['design_tokens'] : {};
435
+ return _isDict(tokens) ? tokens : {};
436
+ }
437
+
438
+ /** Dedup key for a detector finding — one per measured site and value. */
439
+ function _tokenKeyOf(file: Any, line: Any, value: Any): string {
440
+ return `${String(file)}\u0000${String(line)}\u0000${String(value)}`;
441
+ }
442
+
443
+ /**
444
+ * Append `token_violation` findings from the detector envelope.
445
+ *
446
+ * Mirrors `_synthesize_a11y_findings`: the review skill writes the raw scan
447
+ * into `state.ui_review.tokens.violations`, and this turns the in-scope subset
448
+ * into findings the polish gate already knows how to act on. Deduped by
449
+ * `(file, line, value)`, so re-running the step is idempotent.
450
+ *
451
+ * Returns the number of findings appended.
452
+ */
453
+ function _synthesize_token_findings(
454
+ findings: Any[],
455
+ violations: Any[],
456
+ tokens: Record<string, Any>,
457
+ ): number {
458
+ const existing = new Set<string>();
459
+ for (const f of findings) {
460
+ if (_isDict(f) && f['kind'] === TOKEN_VIOLATION_KIND) {
461
+ existing.add(_tokenKeyOf(f['file'], f['line'], f['value']));
462
+ }
463
+ }
464
+ let added = 0;
465
+ for (const v of violations) {
466
+ if (!_isDict(v)) {
467
+ continue;
468
+ }
469
+ const value = v['value'];
470
+ if (typeof value !== 'string') {
471
+ continue;
472
+ }
473
+ const category = _audit_token_category(tokens, value);
474
+ if (category === null) {
475
+ continue;
476
+ }
477
+ const key = _tokenKeyOf(v['file'], v['line'], value);
478
+ if (existing.has(key)) {
479
+ continue;
480
+ }
481
+ findings.push({
482
+ kind: TOKEN_VIOLATION_KIND,
483
+ channel: DETECTOR_CHANNEL,
484
+ category,
485
+ value,
486
+ file: v['file'] ?? null,
487
+ line: v['line'] ?? null,
488
+ detector_type: v['type'] ?? null,
489
+ });
490
+ existing.add(key);
491
+ added += 1;
492
+ }
493
+ return added;
494
+ }
495
+
496
+ /**
497
+ * Turn the detector envelope into findings, and take the review off clean.
498
+ *
499
+ * Never halts. An absent envelope is not an error: the detector is one channel
500
+ * of two, and a run that did not scan is a run with nothing measured — which is
501
+ * exactly what the `render_ok` gate below refuses to let pass silently for the
502
+ * render channel, and what a null record covers for a blocked dimension.
503
+ */
504
+ function _apply_token_detector(state: DeliveryState, review: Record<string, Any>): void {
505
+ const raw = review['tokens'];
506
+ if (!_isDict(raw)) {
507
+ return;
508
+ }
509
+ const violations = raw['violations'];
510
+ if (!Array.isArray(violations) || violations.length === 0) {
511
+ return;
512
+ }
513
+ const findings = review['findings'];
514
+ if (!Array.isArray(findings)) {
515
+ return;
516
+ }
517
+ const added = _synthesize_token_findings(
518
+ findings as Any[],
519
+ violations as Any[],
520
+ _audit_design_tokens(state),
521
+ );
522
+ if (added > 0) {
523
+ review['review_clean'] = false;
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Render-dependent checks, and the blocker that gates each of them.
529
+ *
530
+ * Named here so a static-scoped verdict can enumerate what it did NOT do.
531
+ * "Scope the verdict to what was statically checked and say so" is only
532
+ * readable if the unrun half is written down too — an enumerated `checks_run`
533
+ * with no `checks_not_run` beside it reads as a complete review.
534
+ */
535
+ export const RENDER_DEPENDENT_CHECKS: ReadonlyArray<string> = [
536
+ 'viewport-sweep',
537
+ 'touch-target-size',
538
+ 'rendered-contrast',
539
+ 'screenshot-diff',
540
+ ];
541
+
542
+ /** The blocker slug every render-dependent check is gated behind. */
543
+ export const RENDER_BLOCKER = 'b-page-capture-primitive';
544
+
545
+ /**
546
+ * Stamp the verdict scope onto the review envelope.
547
+ *
548
+ * W6: `design-review` makes browser automation a hard prerequisite and, below
549
+ * it, describes a static path in prose with no artefact recording which checks
550
+ * actually ran. This writes that artefact.
551
+ *
552
+ * Every field is DERIVED from the envelope — nothing is invented. A check is
553
+ * listed as run because the envelope carries its evidence, never because a
554
+ * skill said it ran. `scope` is always stamped, so an unscoped verdict is not a
555
+ * shape this step can leave behind.
556
+ */
557
+ function _stamp_verdict_scope(review: Record<string, Any>): void {
558
+ const raw_preview = review['preview'];
559
+ const preview: Record<string, Any> = _isDict(raw_preview) ? raw_preview : {};
560
+ const rendered = preview['render_ok'] === true;
561
+
562
+ const checks_run: string[] = ['findings-review'];
563
+ const a11y = review['a11y'];
564
+ if (_isDict(a11y) && Array.isArray(a11y['violations'])) {
565
+ checks_run.push('a11y-axe');
566
+ }
567
+ const tokens = review['tokens'];
568
+ if (_isDict(tokens) && Array.isArray(tokens['violations'])) {
569
+ checks_run.push('token-detector');
570
+ }
571
+ if (rendered) {
572
+ checks_run.push(...RENDER_DEPENDENT_CHECKS);
573
+ }
574
+
575
+ const scope: Record<string, Any> = {
576
+ scope: rendered ? 'render' : 'static',
577
+ render_available: rendered,
578
+ checks_run,
579
+ };
580
+ if (!rendered) {
581
+ scope['checks_not_run'] = [...RENDER_DEPENDENT_CHECKS];
582
+ scope['blocker'] = RENDER_BLOCKER;
583
+ const reason = preview['skip_reason'];
584
+ scope['skip_reason'] = typeof reason === 'string' && reason.length > 0
585
+ ? reason
586
+ : RENDER_BLOCKER;
587
+ }
588
+ review['verdict_scope'] = scope;
589
+ }
590
+
375
591
  /** BLOCKED halt — audit declared a baseline but review has no a11y. */
376
592
  function _halt_a11y_pending(state: DeliveryState): StepResult {
377
593
  const directive = _resolve_directive(state);
@@ -59,6 +59,146 @@ export const BRAND_TOKEN_PATHS: ReadonlyArray<string> = [
59
59
  'agents/settings/brand/tokens.json',
60
60
  ];
61
61
 
62
+ /**
63
+ * Conventional location of the project's `Playbook` contexts (ADR-244).
64
+ *
65
+ * A playbook is this repository's OWN procedure for a task, and it outranks a shipped
66
+ * skill: the generic skill answers a generic question, while the playbook carries decisions
67
+ * the repository already made (file layout, barrel exports, naming) that no shipped skill
68
+ * can know. Mirrors {@link BRAND_TOKEN_PATHS} deliberately — same acyclic,
69
+ * degrades-gracefully shape: present → the repository's command is proposed first, absent →
70
+ * nothing is emitted and the lane is byte-identical.
71
+ */
72
+ export const PLAYBOOK_HOME = path.join('agents', 'settings', 'contexts');
73
+
74
+ /** A playbook the lane may act on: `configured` grade, matching scope, non-empty `invokes`. */
75
+ export interface ScaffoldPlaybook {
76
+ readonly file: string;
77
+ readonly task: string;
78
+ readonly invokes: readonly string[];
79
+ }
80
+
81
+ /**
82
+ * Read a playbook's head. Only `configured` playbooks with a `scope` that covers
83
+ * `scope_root` are returned — an `observed` playbook is advisory (per the
84
+ * `playbook-precedence` rule) and MUST NOT be dispatched ahead of a shipped skill, because
85
+ * at least one of its ids was never resolved in the tree.
86
+ */
87
+ export function _read_playbook(file: string, scope_root: string): ScaffoldPlaybook | null {
88
+ let text = '';
89
+ try {
90
+ text = fs.readFileSync(file, 'utf8');
91
+ } catch {
92
+ return null;
93
+ }
94
+ if (!text.startsWith('---')) return null;
95
+ const end = text.indexOf('\n---', 3);
96
+ if (end < 0) return null;
97
+ const head = text.slice(3, end);
98
+
99
+ const grade = /^grade:\s*["']?([A-Za-z]+)["']?\s*$/m.exec(head);
100
+ if (grade === null || grade[1] !== 'configured') return null;
101
+
102
+ const scope = /^scope:\s*["']?(.+?)["']?\s*$/m.exec(head);
103
+ const scope_value = scope?.[1] ?? '';
104
+ // `repo` covers everything; otherwise the playbook's scope must be a prefix of the
105
+ // project's scope_root (or equal to it). A partial match is NOT a match — a playbook
106
+ // for `packages/ui` says nothing about `packages/api`.
107
+ const in_scope =
108
+ scope_value === 'repo' ||
109
+ (scope_value !== '' && (scope_root === scope_value || scope_root.startsWith(`${scope_value}/`)));
110
+ if (!in_scope) return null;
111
+
112
+ const task = /^task:\s*["']?(.+?)["']?\s*$/m.exec(head);
113
+ const invokes: string[] = [];
114
+ let in_list = false;
115
+ for (const line of head.split('\n')) {
116
+ if (/^invokes:\s*$/.test(line)) {
117
+ in_list = true;
118
+ continue;
119
+ }
120
+ if (in_list) {
121
+ const item = /^\s+-\s*["']?(.+?)["']?\s*$/.exec(line);
122
+ if (item?.[1] !== undefined) {
123
+ invokes.push(item[1]);
124
+ continue;
125
+ }
126
+ in_list = false;
127
+ }
128
+ const inline = /^invokes:\s*\[(.*)\]\s*$/.exec(line);
129
+ if (inline?.[1] !== undefined) {
130
+ for (const part of inline[1].split(',')) {
131
+ const v = part.trim().replace(/^["']|["']$/g, '');
132
+ if (v.length > 0) invokes.push(v);
133
+ }
134
+ }
135
+ }
136
+ // A `configured` playbook with no ids cannot be dispatched: there is nothing to propose,
137
+ // and proposing the empty set as "the repository's procedure" would be worse than silence.
138
+ if (invokes.length === 0) return null;
139
+ return { file, task: task?.[1] ?? '(untitled)', invokes };
140
+ }
141
+
142
+ /**
143
+ * The `configured` playbooks whose scope covers this project, for the given verb.
144
+ *
145
+ * `verb` is matched against the playbook's `task` as a plain lower-cased substring. That is
146
+ * deliberately loose: a playbook titled "Add a new component to this repository" must match
147
+ * the `scaffold` lane's component work, and a stricter match would make the whole mechanism
148
+ * unreachable for the phrasing `playbook-authoring` actually generates.
149
+ */
150
+ export function _scaffold_playbooks(
151
+ state: DeliveryState,
152
+ verb_terms: ReadonlyArray<string>,
153
+ root: string | null = null,
154
+ ): ScaffoldPlaybook[] {
155
+ const base = root !== null ? root : process.cwd();
156
+ const home = path.join(base, PLAYBOOK_HOME);
157
+ let names: string[] = [];
158
+ try {
159
+ names = fs.readdirSync(home).filter((n) => n.endsWith('.md')).sort();
160
+ } catch {
161
+ return [];
162
+ }
163
+ const stack = _pyTruthy(state.stack) ? state.stack : {};
164
+ const scope_root_raw = _isDict(stack) ? stack['scope_root'] : undefined;
165
+ const scope_root = typeof scope_root_raw === 'string' ? scope_root_raw : '';
166
+
167
+ const out: ScaffoldPlaybook[] = [];
168
+ for (const name of names) {
169
+ const pb = _read_playbook(path.join(home, name), scope_root);
170
+ if (pb === null) continue;
171
+ const task_lower = pb.task.toLowerCase();
172
+ if (!verb_terms.some((t) => task_lower.includes(t))) continue;
173
+ out.push(pb);
174
+ }
175
+ return out;
176
+ }
177
+
178
+ /**
179
+ * The lines that put the repository's own procedure ahead of the stack skill.
180
+ *
181
+ * Empty array when no playbook matches — that is what keeps a project with no playbook home
182
+ * byte-identical to before this existed. The commands are PROPOSED, never run: the
183
+ * engine-never-writes contract is unchanged, and a playbook is authoritative about *what*,
184
+ * never about who runs it.
185
+ */
186
+ export function _playbook_lines(playbooks: ReadonlyArray<ScaffoldPlaybook>): string[] {
187
+ if (playbooks.length === 0) return [];
188
+ const lines: string[] = [
189
+ '> **This repository has its own procedure for this, and it goes FIRST.** A shipped ' +
190
+ 'skill is a generic answer; the playbook below carries decisions this repository ' +
191
+ 'already made. Use the stack skill only for what the playbook does not cover.',
192
+ ];
193
+ for (const pb of playbooks) {
194
+ lines.push(
195
+ `> \`${pb.file}\` — ${pb.task}: propose \`${pb.invokes.join('`, `')}\` ` +
196
+ 'before any stack-skill step. Propose, never run — the human runs it.',
197
+ );
198
+ }
199
+ return lines;
200
+ }
201
+
62
202
  /**
63
203
  * Stack-agnostic directive that derives the scaffold plan.
64
204
  *
@@ -67,6 +207,23 @@ export const BRAND_TOKEN_PATHS: ReadonlyArray<string> = [
67
207
  */
68
208
  export const PLAN_DIRECTIVE = 'ui-scaffold-plan';
69
209
 
210
+ /**
211
+ * Task words that make a playbook relevant to the `scaffold` verb.
212
+ *
213
+ * Kept small and concrete rather than clever: these are the nouns
214
+ * `playbook-authoring` derives from a repository's own creation scripts
215
+ * (`new:component`, `new:package`, `generate:page`), so the terms and the generator are
216
+ * two halves of one contract.
217
+ */
218
+ export const SCAFFOLD_VERB_TERMS: ReadonlyArray<string> = [
219
+ 'component',
220
+ 'page',
221
+ 'package',
222
+ 'workspace',
223
+ 'route',
224
+ 'screen',
225
+ ];
226
+
70
227
  /**
71
228
  * Map `state.stack.frontend` → build-stage agent-directive skill name.
72
229
  *
@@ -324,10 +481,12 @@ function _delegate_build(state: DeliveryState, scaffold: Record<string, Any>): S
324
481
  const page_count = Array.isArray(pages) ? pages.length : 0;
325
482
  const routes = scaffold['routes'];
326
483
  const route_count = Array.isArray(routes) ? routes.length : 0;
484
+ const playbook_lines = _playbook_lines(_scaffold_playbooks(state, SCAFFOLD_VERB_TERMS));
327
485
  return new StepResult({
328
486
  outcome: Outcome.BLOCKED,
329
487
  questions: [
330
488
  agent_directive(directive),
489
+ ...playbook_lines,
331
490
  `> Stack: \`${stack_label}\`. Scaffold plan is ready ` +
332
491
  `(${page_count} page(s), ${route_count} route(s)). Create the ` +
333
492
  'skeleton from `state.ui_scaffold` — routes, layout shell, and ' +
@@ -212,17 +212,86 @@ export function unsupported_stack_questions(
212
212
  for (const c of conflicts) {
213
213
  lines.push(`> - \`${c}\``);
214
214
  }
215
+ // A scope conflict has a *closed* option set — the detector already named
216
+ // every candidate — so enumerate them instead of asking the open question.
217
+ // "Which workspace?" answered from a list is a pick; answered as free text
218
+ // it is a guess the agent has to validate, which is the same silent-pick
219
+ // failure one layer up.
220
+ const roots = workspace_roots_from_conflicts(conflicts);
221
+ let n = 1;
222
+ for (const root of roots) {
223
+ lines.push(
224
+ `> ${n}. Build for \`${root}\` — write it to \`state.stack.scope_root\` ` +
225
+ 'and re-run detection against that workspace.',
226
+ );
227
+ n += 1;
228
+ }
229
+ if (roots.length === 0) {
230
+ lines.push(
231
+ `> ${n}. Name the project to build for — the workspace path, or which ` +
232
+ 'framework owns this surface. Detection re-runs against that scope.',
233
+ );
234
+ n += 1;
235
+ }
215
236
  lines.push(
216
- '> 1. Name the project to build for — the workspace path, or which ' +
217
- 'framework owns this surface. Detection re-runs against that scope.',
218
- '> 2. Continue on the stack-neutral floor anyway — `ui-apply-generic` ' +
237
+ `> ${n}. Continue on the stack-neutral floor anyway — \`ui-apply-generic\` ` +
219
238
  'plus its companions. Output will not be idiomatic for either ' +
220
239
  'framework; say so in the result.',
221
- '> 3. Abort — drop this UI request.',
240
+ `> ${n + 1}. Abort — drop this UI request.`,
222
241
  );
223
242
  return lines;
224
243
  }
225
244
 
245
+ /** Prefix of the ambiguity string the detector emits for a scope conflict. */
246
+ const _WORKSPACE_CONFLICT_PREFIX = 'workspace roots: ';
247
+
248
+ /**
249
+ * The workspace names carried by a `workspace roots: a + b` conflict.
250
+ *
251
+ * Parsed back out of the ambiguity string rather than passed alongside it,
252
+ * because `StackResult.ambiguity` is the serialized contract the halt already
253
+ * echoes — adding a parallel field would give the same fact two representations
254
+ * that can disagree after a round-trip through `state.stack`.
255
+ */
256
+ export function workspace_roots_from_conflicts(
257
+ conflicts: ReadonlyArray<string>,
258
+ ): string[] {
259
+ for (const c of conflicts) {
260
+ if (c.startsWith(_WORKSPACE_CONFLICT_PREFIX)) {
261
+ return c
262
+ .slice(_WORKSPACE_CONFLICT_PREFIX.length)
263
+ .split('+')
264
+ .map((name) => name.trim())
265
+ .filter((name) => name !== '');
266
+ }
267
+ }
268
+ return [];
269
+ }
270
+
271
+ /**
272
+ * Name the workspace a dispatch is scoped to, when it is not the project root.
273
+ *
274
+ * Returns an empty array for every non-monorepo project, so those halts stay
275
+ * byte-identical. The line exists because the skills downstream read
276
+ * `components.json`, `components/ui/*` and the styling config by path, and in a
277
+ * monorepo none of those live at the repository root — which is the M5 prose
278
+ * defect, restated where the agent actually acts on it.
279
+ */
280
+ export function scope_lines(stack_state: unknown): string[] {
281
+ if (typeof stack_state !== 'object' || stack_state === null) {
282
+ return [];
283
+ }
284
+ const raw = (stack_state as Record<string, unknown>)['scope_root'];
285
+ if (typeof raw !== 'string' || raw === '') {
286
+ return [];
287
+ }
288
+ return [
289
+ `> Scope: \`${raw}\` — the workspace this stack was detected in. Read ` +
290
+ 'and write component files, `components.json`, and the styling ' +
291
+ 'config under that path. The repository root carries none of them.',
292
+ ];
293
+ }
294
+
226
295
  /**
227
296
  * Render the "load these skills" line for a dispatch halt.
228
297
  *