@event4u/agent-config 14.9.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 (426) 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 +384 -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/async-python-patterns/SKILL.md +1 -1
  45. package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
  46. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
  47. package/dist/agent-src/skills/brand/SKILL.md +3 -0
  48. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
  49. package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
  50. package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
  51. package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
  52. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
  53. package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
  54. package/dist/agent-src/skills/code-refactoring/SKILL.md +1 -1
  55. package/dist/agent-src/skills/code-review/SKILL.md +11 -0
  56. package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
  57. package/dist/agent-src/skills/condense-memory/SKILL.md +4 -1
  58. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  59. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +4 -1
  60. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
  61. package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
  62. package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
  63. package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
  64. package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
  65. package/dist/agent-src/skills/design-review/SKILL.md +80 -2
  66. package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
  67. package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
  68. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
  69. package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
  70. package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
  71. package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
  72. package/dist/agent-src/skills/discovery-interview/SKILL.md +1 -1
  73. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  74. package/dist/agent-src/skills/docx-authoring/SKILL.md +1 -1
  75. package/dist/agent-src/skills/editorial-calendar/SKILL.md +1 -1
  76. package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
  78. package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
  79. package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
  80. package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
  81. package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
  82. package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
  83. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  84. package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
  85. package/dist/agent-src/skills/github-ci/SKILL.md +1 -1
  86. package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
  87. package/dist/agent-src/skills/iconography/SKILL.md +3 -0
  88. package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
  89. package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
  90. package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
  91. package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
  92. package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
  93. package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
  94. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
  95. package/dist/agent-src/skills/judge-artifact-completeness/SKILL.md +1 -1
  96. package/dist/agent-src/skills/judge-injection-defense/SKILL.md +1 -1
  97. package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
  98. package/dist/agent-src/skills/laravel-validation/SKILL.md +1 -1
  99. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
  100. package/dist/agent-src/skills/legal-intake-triage/SKILL.md +1 -1
  101. package/dist/agent-src/skills/legal-practice-profile/SKILL.md +1 -1
  102. package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
  103. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
  104. package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
  105. package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
  106. package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
  107. package/dist/agent-src/skills/messaging-architecture/SKILL.md +1 -1
  108. package/dist/agent-src/skills/migration-architect/SKILL.md +1 -1
  109. package/dist/agent-src/skills/module-detect-on-the-fly/SKILL.md +1 -1
  110. package/dist/agent-src/skills/module-management/SKILL.md +1 -1
  111. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
  112. package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
  113. package/dist/agent-src/skills/motion-choreographer/SKILL.md +7 -1
  114. package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
  115. package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
  116. package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
  117. package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
  118. package/dist/agent-src/skills/override-management/SKILL.md +3 -0
  119. package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
  120. package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
  121. package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
  122. package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
  123. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
  124. package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
  125. package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
  126. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +1 -1
  127. package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
  128. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
  129. package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
  130. package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
  131. package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
  132. package/dist/agent-src/skills/receiving-code-review/SKILL.md +3 -3
  133. package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
  134. package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
  135. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  136. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  137. package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
  138. package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
  139. package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
  140. package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
  141. package/dist/agent-src/skills/scene-expander/SKILL.md +1 -1
  142. package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
  143. package/dist/agent-src/skills/secrets-management/SKILL.md +5 -1
  144. package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
  145. package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
  146. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
  147. package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
  148. package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
  149. package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
  150. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
  151. package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
  152. package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
  153. package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
  154. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  155. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
  156. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
  157. package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
  158. package/dist/agent-src/skills/terraform/SKILL.md +3 -0
  159. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
  160. package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
  161. package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
  162. package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
  163. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
  164. package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
  165. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +1 -1
  166. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
  167. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
  168. package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
  169. package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
  170. package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
  171. package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
  172. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  173. package/dist/agent-src/templates/playbook.md +75 -0
  174. package/dist/agent-src/templates/roadmaps.md +37 -0
  175. package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  176. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  177. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  178. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  179. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  180. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  181. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  182. package/dist/cli/commands/uiAudit.js +221 -0
  183. package/dist/cli/commands/uiAudit.js.map +1 -0
  184. package/dist/cli/commands/uiRender.js +206 -0
  185. package/dist/cli/commands/uiRender.js.map +1 -0
  186. package/dist/cli/main.js +22 -1
  187. package/dist/cli/main.js.map +1 -1
  188. package/dist/cli/mcp/content.js +64 -1
  189. package/dist/cli/mcp/content.js.map +1 -1
  190. package/dist/cli/mcp/dispatch.js +175 -10
  191. package/dist/cli/mcp/dispatch.js.map +1 -1
  192. package/dist/cli/registry.js +3 -0
  193. package/dist/cli/registry.js.map +1 -1
  194. package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
  195. package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
  196. package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
  197. package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
  198. package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
  199. package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
  200. package/dist/cli-delegate/cmd_brand_status.js +8 -6
  201. package/dist/cli-delegate/cmd_conformance.js +3 -3
  202. package/dist/cli-delegate/cmd_doctor.js +3 -3
  203. package/dist/cli-delegate/cmd_export.js +4 -4
  204. package/dist/cli-delegate/cmd_handoff.js +1 -1
  205. package/dist/cli-delegate/cmd_preflight.js +2 -2
  206. package/dist/cli-delegate/cmd_prune.js +4 -4
  207. package/dist/cli-delegate/cmd_session_recycle.js +70 -9
  208. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  209. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  210. package/dist/cli-delegate/cmd_sync.js +4 -4
  211. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  212. package/dist/cli-delegate/cmd_validate.js +4 -4
  213. package/dist/discovery/deprecation-report.md +1 -1
  214. package/dist/discovery/discovery-manifest.json +380 -145
  215. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  216. package/dist/discovery/discovery-manifest.summary.md +4 -4
  217. package/dist/discovery/dormancy-report.md +1 -1
  218. package/dist/discovery/orphan-report.md +1 -1
  219. package/dist/discovery/packs.json +18 -8
  220. package/dist/discovery/trust-report.md +3 -3
  221. package/dist/discovery/workspaces.json +16 -6
  222. package/dist/hooks/dispatch.js +2337 -1436
  223. package/dist/install/install.mjs +795 -708
  224. package/dist/mcp/registry-manifest.json +3 -3
  225. package/dist/mcp/server.json +2 -2
  226. package/dist/mcp/server.mjs +1685 -1250
  227. package/dist/router.json +1 -1
  228. package/dist/scripts/_lib/lean_projection_mode.js +40 -0
  229. package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
  230. package/dist/scripts/_lib/scoped_projection.js +84 -0
  231. package/dist/scripts/_lib/scoped_projection.js.map +1 -1
  232. package/dist/scripts/_lib/ui_surface.js +89 -0
  233. package/dist/scripts/_lib/ui_surface.js.map +1 -0
  234. package/dist/scripts/condense.js +6 -10
  235. package/dist/scripts/condense.js.map +1 -1
  236. package/dist/scripts/project_thin_rules.js +40 -2
  237. package/dist/scripts/project_thin_rules.js.map +1 -1
  238. package/dist/server/schemas/settings.js +3 -0
  239. package/dist/server/schemas/settings.js.map +1 -1
  240. package/dist/shared/skillRanking.js +159 -0
  241. package/dist/shared/skillRanking.js.map +1 -0
  242. package/docs/contracts/provider-lifecycle.md +47 -18
  243. package/docs/contracts/settings-classes.md +14 -4
  244. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
  245. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  246. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
  247. package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  248. package/docs/guidelines/design-antipatterns.md +4 -2
  249. package/docs/guidelines/design-asset-discipline.md +38 -0
  250. package/docs/guidelines/design-fidelity-mechanics.md +45 -29
  251. package/docs/guidelines/design-handover-extraction.md +35 -5
  252. package/docs/guidelines/design-modes.md +41 -1
  253. package/docs/guidelines/monorepo-antipatterns.md +141 -0
  254. package/llms.txt +50 -39
  255. package/package.json +1 -1
  256. package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  257. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  258. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  259. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  260. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  261. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  262. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  263. package/src/config/agent-settings.template.yml +28 -0
  264. package/src/config/assurance-capability-registry.json +223 -0
  265. package/src/config/assurance-threshold-budget.json +65 -0
  266. package/src/config/ci-local-parity.yml +14 -0
  267. package/src/config/discovery/unassigned-artefacts.yml +2 -0
  268. package/src/config/dispatch-economy-metrics.json +4 -2
  269. package/src/config/evaluator-budgets.json +14 -14
  270. package/src/config/gate-coverage.yml +227 -8
  271. package/src/config/gate-violation-baselines.json +76 -72
  272. package/src/config/hook-latency-budget.json +1 -0
  273. package/src/config/hook-token-budget.json +137 -125
  274. package/src/config/pack-size-budget.json +4 -2
  275. package/src/config/preamble-payload-budget.json +71 -67
  276. package/src/config/quorum-attendance-budget.json +12 -4
  277. package/src/config/rule-activation-census.json +7 -3
  278. package/src/config/rule-enforcement-baseline.json +0 -1
  279. package/src/config/rule-stub-ceilings.json +112 -91
  280. package/src/scripts/_cli/cmd_doctor.ts +15 -16
  281. package/src/scripts/_cli/doctor_install_mode.ts +49 -0
  282. package/src/scripts/_cli/doctor_overrides.ts +154 -0
  283. package/src/scripts/_dispatch.bash +17 -0
  284. package/src/scripts/_lib/as_of.ts +412 -0
  285. package/src/scripts/_lib/exec_evidence.ts +7 -0
  286. package/src/scripts/_lib/hook_settings.ts +33 -0
  287. package/src/scripts/_lib/host_listing_model.ts +192 -0
  288. package/src/scripts/_lib/lean_projection_mode.ts +44 -0
  289. package/src/scripts/_lib/mcp_bridge.ts +199 -0
  290. package/src/scripts/_lib/review_independence.ts +62 -10
  291. package/src/scripts/_lib/rule_injection.ts +239 -0
  292. package/src/scripts/_lib/run_checkpoint.ts +54 -1
  293. package/src/scripts/_lib/scoped_projection.ts +96 -0
  294. package/src/scripts/_lib/session_register.ts +44 -2
  295. package/src/scripts/_lib/skill_catalogue.ts +38 -2
  296. package/src/scripts/_lib/transcript_reads.ts +207 -0
  297. package/src/scripts/_lib/ui_authority.test.ts +251 -0
  298. package/src/scripts/_lib/ui_authority.ts +343 -0
  299. package/src/scripts/ai-video/adapters/fal.sh +8 -3
  300. package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
  301. package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
  302. package/src/scripts/ai-video/adapters/kling.sh +10 -0
  303. package/src/scripts/ai-video/adapters/sora.sh +10 -0
  304. package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
  305. package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
  306. package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
  307. package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
  308. package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
  309. package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
  310. package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
  311. package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
  312. package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
  313. package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
  314. package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
  315. package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
  316. package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
  317. package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
  318. package/src/scripts/ai-video/smoke-trace.sh +450 -2
  319. package/src/scripts/ai-video/stitch.sh +191 -10
  320. package/src/scripts/ai-video/test-pipeline.sh +84 -6
  321. package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
  322. package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
  323. package/src/scripts/ai_council/clients.ts +3 -2
  324. package/src/scripts/ai_council/consensus.ts +63 -6
  325. package/src/scripts/ai_council/events_log.ts +46 -1
  326. package/src/scripts/ai_council/orchestrator.ts +103 -108
  327. package/src/scripts/ai_council/orchestrator_results.ts +166 -0
  328. package/src/scripts/ai_council/prompts.ts +12 -5
  329. package/src/scripts/ai_council/quorum.ts +82 -1
  330. package/src/scripts/ai_council/quorum_wiring.ts +82 -5
  331. package/src/scripts/ai_council/seating.ts +211 -0
  332. package/src/scripts/ai_council/stance_tally.ts +22 -0
  333. package/src/scripts/bench_hook_latency.ts +62 -0
  334. package/src/scripts/build_proof.ts +12 -1
  335. package/src/scripts/capture_skill_catalogue.ts +21 -0
  336. package/src/scripts/check_always_budget.ts +2 -1
  337. package/src/scripts/check_augmentignore.ts +2 -1
  338. package/src/scripts/check_beta_review_markers.ts +2 -1
  339. package/src/scripts/check_composite_arming.ts +364 -0
  340. package/src/scripts/check_corpus_staleness.ts +2 -1
  341. package/src/scripts/check_council_pin_staleness.ts +3 -1
  342. package/src/scripts/check_enforcement_coverage.ts +116 -3
  343. package/src/scripts/check_enforcement_denominator.ts +365 -0
  344. package/src/scripts/check_gate_coverage.ts +2 -1
  345. package/src/scripts/check_hook_bundle_freshness.ts +13 -1
  346. package/src/scripts/check_knowledge_cards.ts +2 -1
  347. package/src/scripts/check_knowledge_pages.ts +3 -2
  348. package/src/scripts/check_memory.ts +2 -1
  349. package/src/scripts/check_no_automerge_key.ts +287 -0
  350. package/src/scripts/check_pack_conformance_fixture.ts +565 -0
  351. package/src/scripts/check_pack_passport_reconciliation.ts +274 -0
  352. package/src/scripts/check_proposal.ts +2 -1
  353. package/src/scripts/check_reach_staleness.ts +2 -1
  354. package/src/scripts/check_release_adjacent_health.ts +2 -1
  355. package/src/scripts/check_release_pr_shape.ts +5 -0
  356. package/src/scripts/check_review_schema.ts +34 -1
  357. package/src/scripts/check_roadmap_trackable.ts +48 -3
  358. package/src/scripts/check_source_size_budget.ts +2 -1
  359. package/src/scripts/check_standing_payload_delta.ts +505 -0
  360. package/src/scripts/check_trigger_evals.ts +2 -1
  361. package/src/scripts/classify_change_risk.ts +281 -0
  362. package/src/scripts/compute_skill_tiers.ts +186 -0
  363. package/src/scripts/condense.ts +8 -13
  364. package/src/scripts/council_attendance_metrics.ts +183 -0
  365. package/src/scripts/council_cli.ts +10 -8
  366. package/src/scripts/council_parse_rate.ts +116 -0
  367. package/src/scripts/derive_playbooks.ts +406 -0
  368. package/src/scripts/design_slop_rules.test.ts +7 -0
  369. package/src/scripts/design_slop_rules.ts +56 -2
  370. package/src/scripts/dispatch_r2_reviewer.ts +16 -0
  371. package/src/scripts/frontend_corpus_hash.ts +116 -0
  372. package/src/scripts/generate_pack_manifests.ts +78 -0
  373. package/src/scripts/grade_target_readiness.ts +478 -0
  374. package/src/scripts/hook_manifest.json +1 -1
  375. package/src/scripts/hook_manifest.yaml +97 -16
  376. package/src/scripts/hooks/concern_registry.ts +4 -0
  377. package/src/scripts/hooks/design_pass_hook.ts +356 -0
  378. package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
  379. package/src/scripts/hooks/rule_inject_hook.ts +318 -0
  380. package/src/scripts/hot_context_hook.ts +74 -7
  381. package/src/scripts/install.ts +40 -89
  382. package/src/scripts/lint_adapter_tier.ts +663 -0
  383. package/src/scripts/lint_archived_skills.ts +93 -0
  384. package/src/scripts/lint_budget_ownership.ts +2 -1
  385. package/src/scripts/lint_deterministic_time.ts +470 -0
  386. package/src/scripts/lint_framework_leakage.ts +5 -0
  387. package/src/scripts/lint_handoffs.ts +525 -1
  388. package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
  389. package/src/scripts/lint_marketplace.ts +88 -0
  390. package/src/scripts/lint_media_policy_linkage.ts +140 -1
  391. package/src/scripts/lint_one_off_age.ts +6 -1
  392. package/src/scripts/lint_override_kernel_guard.ts +87 -5
  393. package/src/scripts/lint_roadmap_complexity.ts +56 -0
  394. package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
  395. package/src/scripts/lint_rule_norm_pin.ts +321 -0
  396. package/src/scripts/lint_spawn_payload.ts +42 -5
  397. package/src/scripts/lint_symptom_intake.ts +2 -1
  398. package/src/scripts/mcp_parity_smoke.ts +30 -4
  399. package/src/scripts/mcp_render.ts +66 -1
  400. package/src/scripts/mcp_tool_fingerprint.ts +241 -0
  401. package/src/scripts/measure_risk_class_drift.ts +140 -0
  402. package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
  403. package/src/scripts/media/lib/adapter-common.sh +211 -1
  404. package/src/scripts/media/lib/adapter-contract.md +74 -6
  405. package/src/scripts/model_rule_injection.ts +907 -0
  406. package/src/scripts/project_thin_rules.ts +45 -2
  407. package/src/scripts/release.ts +66 -860
  408. package/src/scripts/release_drill.ts +59 -3
  409. package/src/scripts/release_env.ts +298 -0
  410. package/src/scripts/release_publication.ts +720 -0
  411. package/src/scripts/roadmap_context.ts +778 -0
  412. package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
  413. package/src/scripts/schemas/pack.schema.json +62 -4
  414. package/src/scripts/schemas/rule.schema.json +24 -2
  415. package/src/scripts/schemas/skill.schema.json +41 -2
  416. package/src/scripts/schemas/ui-authority.schema.json +114 -0
  417. package/src/scripts/session_register_hook.ts +29 -3
  418. package/src/scripts/sessions_cli.ts +67 -3
  419. package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
  420. package/src/scripts/tighten_skill_descriptions.ts +264 -0
  421. package/src/scripts/token_sink_report.ts +239 -0
  422. package/src/scripts/trigger_coverage.ts +122 -3
  423. package/src/scripts/update_counts.ts +7 -3
  424. package/src/scripts/validate_frontmatter.ts +66 -0
  425. package/src/server/schemas/settings.ts +5 -0
  426. package/src/shared/skillRanking.ts +183 -0
@@ -65,6 +65,19 @@ const COMPLEXITY_PAT = /^complexity:\s*(lightweight|structural)\s*$/m;
65
65
  const EXEC_MODE_PAT = /^execution:[^\S\n]*\n(?:[ \t]+(?!mode:).*\n)*[ \t]+mode:[ \t]*([^\s#]+)/m;
66
66
  const EXEC_MODE_VALUES = new Set(['autonomous', 'phase-checkpoints', 'interactive']);
67
67
 
68
+ /**
69
+ * `relates:` relations (templates/roadmaps.md rule 18) — a CLOSED set.
70
+ *
71
+ * An open vocabulary here degrades into free-text notes nothing can read, which
72
+ * is the state `depends:` was in when its adoption measured 0/22. Four values,
73
+ * and an unknown one is a hard problem rather than a warning: the field feeds a
74
+ * decision (order, and whether a sibling supersedes this roadmap), so a value no
75
+ * reader understands is worse than an absent field.
76
+ */
77
+ const RELATES_RELATIONS = new Set(['extends', 'supersedes', 'depends', 'disjoint']);
78
+ // The `relation:` line under each `- slug:` row inside the `relates:` block.
79
+ const RELATES_RELATION_PAT = /^[ \t]+relation:[ \t]*([^\s#]+)/gm;
80
+
68
81
  // Plate / horizon detection — template rule 16 forbids time-boxed plates.
69
82
  const PLATE_PATS: ReadonlyArray<readonly [RegExp, string]> = [
70
83
  [/^##\s+Horizon\b/im, "'## Horizon' section header"],
@@ -211,6 +224,7 @@ function lint_roadmap(
211
224
  _check_no_plate(text, problems);
212
225
  }
213
226
  _check_execution_mode(fm, problems);
227
+ _check_relates(fm, problems);
214
228
  if (warnings) {
215
229
  _check_autonomous_authoring(text, fm, warnings);
216
230
  _check_human_gate_steps(text, warnings);
@@ -443,6 +457,47 @@ function _check_external_population_gates(text: string, warnings: string[]): voi
443
457
  }
444
458
  }
445
459
 
460
+ /**
461
+ * Validate a declared `relates:` block. Absent is valid here — requiring the
462
+ * block is `check_roadmap_trackable`'s ratchet, not this linter's job. This one
463
+ * only judges a declaration that IS present, exactly as `_check_execution_mode`
464
+ * does above.
465
+ */
466
+ export function _check_relates(fm: string, problems: string[]): void {
467
+ if (!fm || !/^relates:/m.test(fm)) return;
468
+ const inline_empty = /^relates:[^\S\n]*\[[^\S\n]*\][^\S\n]*(?:#[^\n]*)?$/m.test(fm);
469
+ RELATES_RELATION_PAT.lastIndex = 0;
470
+ const values: string[] = [];
471
+ let m: RegExpExecArray | null;
472
+ while ((m = RELATES_RELATION_PAT.exec(fm)) !== null) {
473
+ values.push(m[1]!.replace(/^['"]|['"]$/g, ''));
474
+ }
475
+ for (const v of values) {
476
+ if (!RELATES_RELATIONS.has(v)) {
477
+ problems.push(
478
+ `unknown relates[].relation '${v}' — allowed: extends | supersedes | ` +
479
+ 'depends | disjoint (templates/roadmaps.md rule 18)',
480
+ );
481
+ }
482
+ }
483
+ if (!inline_empty && values.length === 0) {
484
+ problems.push(
485
+ "'relates:' present but no 'relation:' key found — every row needs " +
486
+ "slug + relation, or write 'relates: []' with the probe's scanned: line " +
487
+ '(templates/roadmaps.md rule 18)',
488
+ );
489
+ }
490
+ // A `depends` row that does not mirror into `depends:` splits the set
491
+ // contract's edge source in two, which rule 18 forbids in as many words.
492
+ if (values.includes('depends') && !/^depends:/m.test(fm)) {
493
+ problems.push(
494
+ "relates[].relation: depends declared but no 'depends:' key mirrors it — " +
495
+ 'the set contract reads `depends:` and only `depends:` ' +
496
+ '(templates/roadmaps.md rule 18)',
497
+ );
498
+ }
499
+ }
500
+
446
501
  function _check_execution_mode(fm: string, problems: string[]): void {
447
502
  if (!fm || !/^execution:/m.test(fm)) {
448
503
  // Absent is VALID and stays valid — but it no longer means "interactive".
@@ -708,6 +763,7 @@ if (_isCliEntry() || process.argv[1] === _HERE) {
708
763
  }
709
764
 
710
765
  export {
766
+ RELATES_RELATIONS,
711
767
  REPO_ROOT,
712
768
  ROADMAP_GLOB,
713
769
  LIGHTWEIGHT_LINE_CAP,
@@ -84,11 +84,25 @@ function _declaration(fm: Record<string, string | string[]>): string[] | null {
84
84
  return list.length === 0 ? null : list;
85
85
  }
86
86
 
87
- /** The body must state a `none` gap in prose — the honesty convention. */
88
- function _bodyStatesNone(text: string): boolean {
87
+ /**
88
+ * The body must state the gap in prose — the honesty convention.
89
+ *
90
+ * BOTH spellings are accepted, and that is not leniency. The bare `none` was
91
+ * retired for `instruction-only: <reason>` on 2026-08-23 (one rule still carries
92
+ * it: `non-destructive-by-default`, a kernel rule `block_kernel_rule_writes`
93
+ * denies the agent write to). A body-check that knew only the old word would
94
+ * fail a NEW rule that spelled the declaration the new way and said so in prose —
95
+ * the rename would have made the honesty convention unsatisfiable for exactly
96
+ * the rules adopting it.
97
+ */
98
+ function _bodyStatesGap(text: string): boolean {
89
99
  const end = text.indexOf('\n---\n', 4);
90
100
  const body = end === -1 ? text : text.slice(end + 5);
91
- return body.includes('enforced_by: none') || body.includes('`enforced_by: none`');
101
+ return (
102
+ body.includes('enforced_by: none') ||
103
+ body.includes('`enforced_by: none`') ||
104
+ body.includes('instruction-only')
105
+ );
92
106
  }
93
107
 
94
108
  function _readBaseline(root: string): string[] | null {
@@ -144,11 +158,14 @@ function _scan(root: string, baseline: ReadonlySet<string>, ledger: GateLedger |
144
158
  // shape validate_frontmatter uses for obligation_frequency. Their
145
159
  // projected bytes are stability-gated, so requiring a prose line here
146
160
  // would force an un-editable edit.
147
- if (decl.includes('none') && !_bodyStatesNone(text) && !is_kernel_rule(file)) {
161
+ const declaresGap =
162
+ decl.includes('none') || decl.some((d) => d.startsWith('instruction-only'));
163
+ if (declaresGap && !_bodyStatesGap(text) && !is_kernel_rule(file)) {
148
164
  const f =
149
- `src/rules/${file} declares \`enforced_by: none\` in frontmatter but never states the gap ` +
150
- `in its body — the honesty convention is one prose line naming \`enforced_by: none\`, so a ` +
151
- `reader of the rule sees the gap, not only a machine.`;
165
+ `src/rules/${file} declares a model-carried gap in frontmatter but never states it ` +
166
+ `in its body — the honesty convention is one prose line naming \`instruction-only\` ` +
167
+ `(or the retired \`enforced_by: none\`), so a reader of the rule sees the gap, not ` +
168
+ `only a machine.`;
152
169
  findings.push(f);
153
170
  ledger?.fail(file, f);
154
171
  continue;
@@ -0,0 +1,321 @@
1
+ #!/usr/bin/env -S npx tsx
2
+ /**
3
+ * Gate — a rule that declares `norm` stays inside the budget it declared.
4
+ *
5
+ * `road-to-standing-payload-diet` Phase 1 step 1.2.
6
+ *
7
+ * ## What `norm` pins, and why nothing pinned it before
8
+ *
9
+ * A rule file mixes three things at one uniform standing cost: the obligation
10
+ * (an Iron Law and its clauses), the routing (pointers to skills and
11
+ * guidelines), and the rationale (why the rule exists, what it measured, what it
12
+ * declines to claim). All three are re-sent on every session and every spawn.
13
+ * Only the first two have to be. Before this gate, `norm` appeared nowhere in
14
+ * `src/rules/` and nowhere in `rule.schema.json` (0 hits, measured 2026-08-23),
15
+ * so nothing objected when a rule grew by 200 lines of rationale.
16
+ *
17
+ * `norm.tokens` is the declared exact-BPE ceiling for the rule body below the
18
+ * frontmatter; `norm.remainder` names where the non-normative prose went. Both
19
+ * are required together, and the pairing is the point rather than tidiness: a
20
+ * pin with no destination is a licence to delete, and `preservation-guard`
21
+ * forbids deleting a passage during a transformation. The schema enforces the
22
+ * pairing; this gate enforces the number.
23
+ *
24
+ * ## Three deliberate properties
25
+ *
26
+ * 1. **Opt-in, and the opt-out count is the published metric.** Rules without
27
+ * `norm` are SKIPPED and counted, and the count is printed on the green path.
28
+ * A required key would have redded every rule file on the day it landed,
29
+ * which is the gate-that-teaches-you-to-ignore-it failure
30
+ * `src/config/preamble-payload-budget.json` warns about in its own
31
+ * `_comment`. So the un-pinned fraction is a number rather than an unknown.
32
+ * 2. **Exact tokenizer, or refuse to judge.** `js-tiktoken` is a devDependency
33
+ * and can be absent. Where it is, this gate does NOT fall back to the
34
+ * `chars/4` proxy and pass anyway — a pin enforced in a different unit from
35
+ * the one it was derived in is enforced against a number nobody can
36
+ * reproduce. It exits 2 and says so.
37
+ * 3. **`assertScanned` posture.** Zero rule files is exit 3, not green. This
38
+ * repo has shipped gates that scanned an emptied tree and certified coverage
39
+ * that did not exist.
40
+ *
41
+ * ## What it deliberately does NOT check
42
+ *
43
+ * Whether the body that remains is *genuinely* normative. That is a human read.
44
+ * The gate checks a declared number against a measured one, and the schema
45
+ * checks that a destination exists; `check_references` checks the destination
46
+ * resolves. None of the three can tell obligation from rationale, and claiming
47
+ * otherwise would be the coverage inflation this tree keeps removing.
48
+ *
49
+ * Modes: `--quiet` verdict only · `--json` machine-readable · `--self-test`.
50
+ *
51
+ * Exit codes: 0 every pin honoured · 1 a pin exceeded · 2 no exact tokenizer or
52
+ * a usage error · 3 dead scan scope.
53
+ */
54
+
55
+ import * as fs from 'node:fs';
56
+ import * as path from 'node:path';
57
+ import process from 'node:process';
58
+ import { fileURLToPath, pathToFileURL } from 'node:url';
59
+
60
+ import { parse as parseYaml } from 'yaml';
61
+
62
+ import { GateLedger } from './_lib/gate_ledger.js';
63
+ import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
64
+ import { strip_frontmatter } from './_lib/preservation_migration.js';
65
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
66
+ import { gpt_tokens, method_note, TIKTOKEN_AVAILABLE } from './_lib/token_count.js';
67
+
68
+ const PROG = 'lint_rule_norm_pin';
69
+ const _HERE = fileURLToPath(import.meta.url);
70
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
71
+ const RULES_DIR = path.join(REPO_ROOT, 'src', 'rules');
72
+ const SCRIPT_REL = 'src/scripts/lint_rule_norm_pin.ts';
73
+ const SELF_TEST_MIN_CASES = 5;
74
+ const SELF_TEST_MIN_REJECT = 3;
75
+
76
+ export interface NormPin {
77
+ readonly tokens: number;
78
+ readonly remainder: readonly string[];
79
+ }
80
+
81
+ export interface Finding {
82
+ readonly rule: string;
83
+ readonly declared: number;
84
+ readonly measured: number;
85
+ readonly over: number;
86
+ }
87
+
88
+ export interface Verdict {
89
+ readonly pinned: Finding[];
90
+ readonly violations: Finding[];
91
+ readonly unpinned: string[];
92
+ readonly method: string;
93
+ }
94
+
95
+ /** The `norm` block of one rule file, or `null` when it declares none. */
96
+ export function readNormPin(text: string): NormPin | null {
97
+ const m = /^---\n([\s\S]*?)\n---\n/.exec(text);
98
+ if (m === null) return null;
99
+ let fm: unknown;
100
+ try {
101
+ fm = parseYaml(m[1] ?? '');
102
+ } catch {
103
+ return null;
104
+ }
105
+ if (typeof fm !== 'object' || fm === null) return null;
106
+ const raw = (fm as Record<string, unknown>)['norm'];
107
+ if (typeof raw !== 'object' || raw === null) return null;
108
+ const block = raw as Record<string, unknown>;
109
+ const tokens = block['tokens'];
110
+ const remainder = block['remainder'];
111
+ if (typeof tokens !== 'number' || !Number.isInteger(tokens) || tokens < 1) return null;
112
+ if (!Array.isArray(remainder) || remainder.length === 0) return null;
113
+ return { tokens, remainder: remainder.map(String) };
114
+ }
115
+
116
+ /**
117
+ * Exact-BPE size of the rule body BELOW the frontmatter.
118
+ *
119
+ * The frontmatter is excluded because it is not prose a reader consumes and
120
+ * because including it would make a pin move when an unrelated trigger is added.
121
+ */
122
+ export function measureBody(text: string): number {
123
+ return gpt_tokens(strip_frontmatter(text)).tokens;
124
+ }
125
+
126
+ export function check(dir: string = RULES_DIR): Verdict {
127
+ let entries: string[];
128
+ try {
129
+ entries = fs.readdirSync(dir).filter((f) => f.endsWith('.md')).sort();
130
+ } catch {
131
+ entries = [];
132
+ }
133
+ const pinned: Finding[] = [];
134
+ const violations: Finding[] = [];
135
+ const unpinned: string[] = [];
136
+ for (const name of entries) {
137
+ const text = fs.readFileSync(path.join(dir, name), 'utf-8');
138
+ const pin = readNormPin(text);
139
+ if (pin === null) {
140
+ unpinned.push(name);
141
+ continue;
142
+ }
143
+ const measured = measureBody(text);
144
+ const finding: Finding = {
145
+ rule: name,
146
+ declared: pin.tokens,
147
+ measured,
148
+ over: measured - pin.tokens,
149
+ };
150
+ pinned.push(finding);
151
+ if (finding.over > 0) violations.push(finding);
152
+ }
153
+ return { pinned, violations, unpinned, method: method_note() };
154
+ }
155
+
156
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
157
+ if (argv.includes('--self-test')) return selfTest();
158
+ const unknown = argv.filter((a) => a !== '--quiet' && a !== '--json');
159
+ if (unknown.length > 0) {
160
+ process.stderr.write(`${PROG}: unknown argument(s): ${unknown.join(' ')}\n`);
161
+ return 2;
162
+ }
163
+ const quiet = argv.includes('--quiet');
164
+ const json = argv.includes('--json');
165
+
166
+ if (!TIKTOKEN_AVAILABLE) {
167
+ process.stderr.write(
168
+ `${PROG}: no exact tokenizer available (js-tiktoken absent). A \`norm\` pin is ` +
169
+ 'derived in exact BPE, so enforcing it against the chars/4 proxy would hold ' +
170
+ 'the author to a number they cannot reproduce. Install devDependencies and ' +
171
+ 're-run; this gate does NOT fall back and pass.\n',
172
+ );
173
+ return 2;
174
+ }
175
+
176
+ const v = check();
177
+ const ledger = new GateLedger(PROG);
178
+ ledger.plan([...v.pinned.map((f) => f.rule), ...v.unpinned]);
179
+ for (const f of v.pinned) {
180
+ if (f.over > 0) ledger.fail(f.rule, `${String(f.measured)} > ${String(f.declared)}`);
181
+ else ledger.complete(f.rule);
182
+ }
183
+ for (const name of v.unpinned) ledger.skip(name, 'declared_exemption');
184
+
185
+ if (json) {
186
+ process.stdout.write(`${JSON.stringify(v, null, 2)}\n`);
187
+ } else if (!quiet) {
188
+ process.stdout.write(`${PROG} · ${v.method}\n`);
189
+ for (const f of v.pinned) {
190
+ const mark = f.over > 0 ? '❌' : '✅';
191
+ const room = f.over > 0 ? `+${String(f.over)} over` : `${String(-f.over)} tok of room`;
192
+ process.stdout.write(
193
+ ` ${mark} ${f.rule.padEnd(42)} ${String(f.measured).padStart(6)} / ` +
194
+ `${String(f.declared).padStart(6)} pinned (${room})\n`,
195
+ );
196
+ }
197
+ }
198
+
199
+ try {
200
+ reportScanned({
201
+ gate: PROG,
202
+ scanned: v.pinned.length + v.unpinned.length,
203
+ units: 'rule file(s)',
204
+ roots: ['src/rules'],
205
+ });
206
+ } catch (err) {
207
+ if (err instanceof DeadScopeError) {
208
+ process.stderr.write(`❌ ${err.message}\n`);
209
+ return 3;
210
+ }
211
+ throw err;
212
+ }
213
+ ledger.report();
214
+
215
+ // The un-pinned count is this phase's own progress metric, so it is printed
216
+ // on the GREEN path too — a number only visible on failure is not a metric.
217
+ process.stdout.write(
218
+ `${PROG}: ${String(v.pinned.length)} rule(s) declare \`norm\`, ` +
219
+ `${String(v.unpinned.length)} do not (un-pinned remainder).\n`,
220
+ );
221
+ if (v.violations.length > 0) {
222
+ process.stdout.write(
223
+ `❌ ${PROG}: ${String(v.violations.length)} rule(s) exceed the \`norm\` budget they ` +
224
+ 'declared. Either move more prose to the `remainder` destination, or raise the ' +
225
+ 'pin in the same commit with the measurement that justifies it — never silently.\n',
226
+ );
227
+ return 1;
228
+ }
229
+ process.stdout.write(`✅ ${PROG}: every declared \`norm\` pin is honoured.\n`);
230
+ return 0;
231
+ }
232
+
233
+ /**
234
+ * Prove the gate discriminates.
235
+ *
236
+ * The reject cases exercise the three ways it must refuse: a pin genuinely
237
+ * exceeded, a dead scan root, and a usage error. The accept cases prove an
238
+ * honoured pin and an un-pinned corpus both pass — the second matters because
239
+ * the opt-in design means most runs see no pin at all, and a gate that reddened
240
+ * on "nobody opted in" would have been abandoned in a week.
241
+ */
242
+ function selfTest(): number {
243
+ const tmp = fs.mkdtempSync(path.join(REPO_ROOT, '.norm-pin-selftest-'));
244
+ const fixture = (name: string, body: string, pin: string | null): void => {
245
+ const fm = pin === null ? '' : `norm:\n tokens: ${pin}\n remainder:\n - docs/x.md\n`;
246
+ fs.writeFileSync(path.join(tmp, name), `---\ntype: auto\n${fm}---\n\n${body}\n`);
247
+ };
248
+ // ~120 tokens of prose: comfortably over a pin of 5, comfortably under 4000.
249
+ const body = 'The obligation is stated here. '.repeat(24);
250
+ try {
251
+ const cases: SelfTestCase[] = [
252
+ {
253
+ name: 'pin exceeded → exit 1',
254
+ expect: 'reject',
255
+ run: () => {
256
+ fixture('over.md', body, '5');
257
+ const v = check(tmp);
258
+ fs.rmSync(path.join(tmp, 'over.md'));
259
+ return v.violations.length > 0 ? 1 : 0;
260
+ },
261
+ },
262
+ {
263
+ name: 'dead scan root → exit 3',
264
+ expect: 'reject',
265
+ run: () => {
266
+ const v = check(path.join(tmp, 'no-such-dir'));
267
+ try {
268
+ reportScanned({
269
+ gate: PROG,
270
+ scanned: v.pinned.length + v.unpinned.length,
271
+ units: 'rule file(s)',
272
+ roots: ['src/rules'],
273
+ });
274
+ } catch (err) {
275
+ return err instanceof DeadScopeError ? 3 : 1;
276
+ }
277
+ return 0;
278
+ },
279
+ },
280
+ {
281
+ name: 'unknown argument → exit 2',
282
+ expect: 'reject',
283
+ run: () => runGateCli(REPO_ROOT, SCRIPT_REL, ['--nonsense'], REPO_ROOT),
284
+ },
285
+ {
286
+ name: 'pin honoured → exit 0',
287
+ expect: 'accept',
288
+ run: () => {
289
+ fixture('under.md', body, '4000');
290
+ const v = check(tmp);
291
+ fs.rmSync(path.join(tmp, 'under.md'));
292
+ return v.violations.length > 0 ? 1 : 0;
293
+ },
294
+ },
295
+ {
296
+ name: 'no rule declares a pin → still exit 0',
297
+ expect: 'accept',
298
+ run: () => {
299
+ fixture('bare.md', body, null);
300
+ const v = check(tmp);
301
+ const ok = v.pinned.length === 0 && v.unpinned.length === 1;
302
+ fs.rmSync(path.join(tmp, 'bare.md'));
303
+ return ok ? 0 : 1;
304
+ },
305
+ },
306
+ ];
307
+ return runSelfTest({ gate: PROG, cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
308
+ } finally {
309
+ fs.rmSync(tmp, { recursive: true, force: true });
310
+ }
311
+ }
312
+
313
+ function invokedDirectly(): boolean {
314
+ const entry = process.argv[1];
315
+ if (entry === undefined) return false;
316
+ return import.meta.url === pathToFileURL(path.resolve(entry)).href;
317
+ }
318
+
319
+ if (invokedDirectly()) {
320
+ process.exit(main());
321
+ }
@@ -4,7 +4,19 @@
4
4
  * ("NEVER BULK-DUMP CONTEXT INTO A SUBAGENT") deterministic
5
5
  * (road-to-lean-agent-init Phase 3).
6
6
  *
7
- * Scans two surfaces for spawn-brief-shaped payloads: (a) JSON fixtures
7
+ * WIDENED 2026-08-23 (road-to-review-independence step 0.4) to a THIRD surface: the
8
+ * SHIPPED prompt templates under `src/skills/subagent-orchestration/prompts/`. The gate
9
+ * made the "NEVER BULK-DUMP CONTEXT INTO A SUBAGENT" Iron Law deterministic over test
10
+ * fixtures and golden transcripts — i.e. over the places a violation is *simulated* —
11
+ * while the templates that actually construct a spawn brief in production sat outside
12
+ * it. Eight diff-payload placeholder sites across five of those files, plus two further
13
+ * placeholder shapes in two more, were unscanned.
14
+ *
15
+ * Still WARN-ONLY, exactly as before: this surface is prose with placeholders, and a
16
+ * placeholder is not yet a payload. What the widening buys is that a template growing a
17
+ * bulk-dump shape is now visible rather than invisible.
18
+ *
19
+ * Scans three surfaces for spawn-brief-shaped payloads: (a) JSON fixtures
8
20
  * matching `tests/fixtures/**\/*spawn*.json`; (b) fenced code blocks in
9
21
  * `tests/reasoning-layer-eval/golden-transcripts/*.md` that either parse as
10
22
  * JSON with both a `task` and a `knowledge_refs` key, or are introduced by
@@ -41,7 +53,7 @@ import * as fs from 'node:fs';
41
53
  import * as path from 'node:path';
42
54
  import { fileURLToPath, pathToFileURL } from 'node:url';
43
55
 
44
- import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
56
+ import { reportScanned, DeadScopeError } from './_lib/scan_scope.js';
45
57
 
46
58
  const _HERE = path.dirname(fileURLToPath(import.meta.url));
47
59
  const REPO_ROOT = path.resolve(_HERE, '..', '..');
@@ -219,6 +231,22 @@ function scanRepo(repoRoot: string): Finding[] {
219
231
  }
220
232
  }
221
233
 
234
+ // The shipped templates — step 0.4's surface. Counted the same way as the other two
235
+ // (the walk, not the filter), so "no violations" and "no files read" stay
236
+ // distinguishable; that distinction is why `scanned` is incremented before any
237
+ // content test in all three loops.
238
+ const templatesDir = path.join(repoRoot, 'src', 'skills', 'subagent-orchestration', 'prompts');
239
+ if (fs.existsSync(templatesDir)) {
240
+ for (const entry of fs.readdirSync(templatesDir, { withFileTypes: true })) {
241
+ if (entry.isFile() && entry.name.endsWith('.md')) {
242
+ scanned += 1;
243
+ findings.push(
244
+ ...scanMarkdownTranscript(path.join(templatesDir, entry.name), repoRoot),
245
+ );
246
+ }
247
+ }
248
+ }
249
+
222
250
  const transcriptsDir = path.join(repoRoot, 'tests', 'reasoning-layer-eval', 'golden-transcripts');
223
251
  if (fs.existsSync(transcriptsDir)) {
224
252
  for (const entry of fs.readdirSync(transcriptsDir, { withFileTypes: true })) {
@@ -229,11 +257,20 @@ function scanRepo(repoRoot: string): Finding[] {
229
257
  }
230
258
  }
231
259
 
232
- assertScanned({
260
+ // `reportScanned`, not `assertScanned`: step 0.4's verify compares the scanned count
261
+ // against the pre-change one, and a count the gate never prints cannot be compared.
262
+ // The helper's own docstring makes the same point — "a count only visible without
263
+ // `--quiet` is not a count, since CI passes `--quiet`" — so the line goes to stdout
264
+ // unconditionally.
265
+ reportScanned({
233
266
  gate: 'lint_spawn_payload',
234
267
  scanned,
235
- units: 'fixture / transcript file(s)',
236
- roots: ['tests/fixtures', 'tests/reasoning-layer-eval/golden-transcripts'],
268
+ units: 'fixture / transcript / template file(s)',
269
+ roots: [
270
+ 'tests/fixtures',
271
+ 'tests/reasoning-layer-eval/golden-transcripts',
272
+ 'src/skills/subagent-orchestration/prompts',
273
+ ],
237
274
  });
238
275
  return findings;
239
276
  }
@@ -30,6 +30,7 @@ import * as fs from 'node:fs';
30
30
  import * as path from 'node:path';
31
31
  import { fileURLToPath, pathToFileURL } from 'node:url';
32
32
 
33
+ import { asOf } from './_lib/as_of.js';
33
34
  import { GateLedger } from './_lib/gate_ledger.js';
34
35
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
35
36
 
@@ -132,7 +133,7 @@ function _now(): Date {
132
133
  const parsed = Date.parse(`${flag.slice('--now='.length)}T00:00:00Z`);
133
134
  if (!Number.isNaN(parsed)) return new Date(parsed);
134
135
  }
135
- return new Date();
136
+ return asOf();
136
137
  }
137
138
 
138
139
  function main(): number {
@@ -420,6 +420,15 @@ async function _run_http_leg(target: string): Promise<number> {
420
420
  return failed;
421
421
  }
422
422
 
423
+ /**
424
+ * The turnkey stdio surface's tool names, code-point sorted and joined.
425
+ * Kept as a literal rather than imported from `src/cli/` so this maintainer
426
+ * script does not take a build dependency on the CLI bundle; the CLI-side
427
+ * source of truth is `LITE_TOOLS` in `src/cli/mcp/dispatch.ts`, and
428
+ * `tests/scripts/mcp_lite_tools.test.ts` pins that side.
429
+ */
430
+ const LITE_TOOL_NAMES_EXPECTED = 'read_skill,suggest_skill_for_task';
431
+
423
432
  /** ALL skill+command prompt metas (uncapped — for full-set parity). */
424
433
  function _local_prompts_all(): Record<string, unknown>[] {
425
434
  const [prompts] = load_all_prompts();
@@ -438,7 +447,8 @@ function _local_resources_all(): Record<string, unknown>[] {
438
447
  * Compares the FULL SUBSET the turnkey surface serves (skill/command prompts,
439
448
  * rule/guideline resources — contexts excluded by design) via cursor
440
449
  * pagination, on name/kind/uri keys, and asserts the read-only boundary
441
- * (`tools/list` empty). Skips with a note if the binary isn't built.
450
+ * (the two read-only discovery tools and nothing else). Skips with a note if
451
+ * the binary isn't built.
442
452
  */
443
453
  function _run_node_leg(cli: string): number {
444
454
  if (!_exists(cli)) {
@@ -473,13 +483,29 @@ function _run_node_leg(cli: string): number {
473
483
  _subset_resources(_normalize_resources({ resources: _local_resources_all() })),
474
484
  _subset_resources(_normalize_resources({ resources: nodeResources })),
475
485
  );
476
- if (nodeTools.length > 0) {
486
+ // Phase 1.1 of `road-to-skill-delivery-over-mcp`: the turnkey surface now
487
+ // serves exactly two read-only discovery tools, and this leg is where risk 6
488
+ // ("two implementations diverge silently") stops being a claim. Both names
489
+ // are checked, not counted — a count would pass on the wrong pair.
490
+ //
491
+ // `suggest_skill_for_task` is shared with the kernel and both now compute
492
+ // their score through the single `src/shared/skillRanking.ts` formula.
493
+ // `read_skill` is lite-only and deliberately NARROWER than the kernel's
494
+ // `read_resource_body`: it resolves a skill NAME through the content tree's
495
+ // uri map and can reach nothing else.
496
+ const nodeToolNames = nodeTools
497
+ .map((t) => String(t.name ?? ''))
498
+ .sort(_cmpCodePoints)
499
+ .join(',');
500
+ if (nodeToolNames !== LITE_TOOL_NAMES_EXPECTED) {
477
501
  process.stdout.write(
478
- `❌ node tools/list: expected empty (read-only), got ${nodeTools.length}\n`,
502
+ `❌ node tools/list: expected exactly [${LITE_TOOL_NAMES_EXPECTED}], got [${nodeToolNames}]\n`,
479
503
  );
480
504
  failed += 1;
481
505
  } else {
482
- process.stdout.write('✅ node tools/list: empty (read-only, ADR-085)\n');
506
+ process.stdout.write(
507
+ `✅ node tools/list: ${LITE_TOOL_NAMES_EXPECTED} (read-only discovery, ADR-085 + Phase 1.1)\n`,
508
+ );
483
509
  }
484
510
  process.stdout.write(
485
511
  `${`${failed ? '' : 'node-stdio parity OK '}(${path.basename(cli)})`.trim()}\n`,