@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
@@ -48,6 +48,17 @@ type Dict = Record<string, unknown>;
48
48
 
49
49
  interface Artefact {
50
50
  path: string;
51
+ /**
52
+ * On-disk byte size, captured where the ABSOLUTE path is still known.
53
+ *
54
+ * `path` above is a LOGICAL relative path whose root differs per collection
55
+ * mode, so it cannot be stat'd later. A first version of the token passport
56
+ * did exactly that, and every `statSync` threw into a catch that returned 0
57
+ * — 17 packs generated an all-zero passport that would then have
58
+ * "reconciled" against nothing. Carrying the number from the one place it
59
+ * is knowable removes the failure mode rather than handling it.
60
+ */
61
+ bytes: number;
51
62
  name: string;
52
63
  description: string;
53
64
  category: string;
@@ -143,8 +154,15 @@ function _artefact_record(p: string, logicalRel: string, fm: Dict): Artefact {
143
154
  : path.basename(p) === 'SKILL.md'
144
155
  ? path.basename(path.dirname(p))
145
156
  : _stem(p);
157
+ let bytes = 0;
158
+ try {
159
+ bytes = fs.statSync(p).size;
160
+ } catch {
161
+ bytes = 0;
162
+ }
146
163
  return {
147
164
  path: logicalRel,
165
+ bytes,
148
166
  name,
149
167
  description: _pyStrip(_pyTruthy(fm.description) ? String(fm.description) : ''),
150
168
  category: _category_from_logical(logicalRel),
@@ -247,6 +265,65 @@ function _category_from_logical(logicalRel: string): string {
247
265
  * Build the pack.yaml meta dict. Mirrors `_build_pack_yaml`. Insertion
248
266
  * order here is irrelevant — `_py_safe_dump` sorts keys (sort_keys=True).
249
267
  */
268
+ /**
269
+ * What this pack contributes to the STANDING session payload.
270
+ *
271
+ * Derivation, tokenizer and reconciliation target are fixed by
272
+ * `docs/contracts/pack-token-passport.md`, written before the first passport
273
+ * was generated — a number whose derivation is undocumented becomes a figure
274
+ * people quote without being able to reproduce.
275
+ *
276
+ * `chars/4`, deliberately, because that is the basis
277
+ * `preamble-payload-budget.json` declares and `preamble_byte_census.ts` uses. A
278
+ * passport measured with an exact tokenizer could not be reconciled against a
279
+ * census measured with a proxy without the gap between the two METHODS reading
280
+ * as a discrepancy in the packs.
281
+ *
282
+ * The catalog line is built the same way `censusSkillsCatalog` builds it —
283
+ * `- <name>: <description>\n` — rather than approximated, so the two sides of
284
+ * the reconciliation are counting the same string.
285
+ *
286
+ * It measures the STANDING contribution only. A skill body loaded on invocation
287
+ * is a runtime cost and is not here; the residual bucket (tool definitions +
288
+ * dispatch prompt) is not attributable to a pack at all. Both are stated in the
289
+ * contract, which is where the number lives.
290
+ */
291
+ function _token_passport(artefacts: readonly Artefact[]): Dict {
292
+ const tok = (chars: number): number => Math.round(chars / 4);
293
+ let ruleChars = 0;
294
+ let catalogChars = 0;
295
+ let commandChars = 0;
296
+ let otherChars = 0;
297
+ for (const a of artefacts) {
298
+ if (a.category === 'skill') {
299
+ catalogChars += `- ${a.name}: ${a.description}\n`.length;
300
+ continue;
301
+ }
302
+ if (a.category === 'rule') ruleChars += a.bytes;
303
+ else if (a.category === 'command') commandChars += a.bytes;
304
+ // Everything else a pack CLAIMS — contexts, personas, presets,
305
+ // profiles, user-types. Counted, because a pack that claims 47
306
+ // artefacts and reports 0 tokens is worse than no passport: it reads as
307
+ // "this pack is free" when it means "the three named buckets do not
308
+ // cover what this pack holds". Measured: `core` claims 47 artefacts and
309
+ // none of them is a rule, a skill or a command — `src/agent-src/`
310
+ // carries no `rules/` or `skills/` subtree at all.
311
+ else otherChars += a.bytes;
312
+ }
313
+ const rules_tokens = tok(ruleChars);
314
+ const catalog_tokens = tok(catalogChars);
315
+ const commands_tokens = tok(commandChars);
316
+ const other_tokens = tok(otherChars);
317
+ return {
318
+ basis: 'chars/4',
319
+ rules_tokens,
320
+ catalog_tokens,
321
+ commands_tokens,
322
+ other_tokens,
323
+ total_tokens: rules_tokens + catalog_tokens + commands_tokens + other_tokens,
324
+ };
325
+ }
326
+
250
327
  function _build_pack_yaml(pid: string, vocab: Record<string, Dict>, artefacts: Artefact[]): Dict {
251
328
  const meta = vocab[pid] ?? {};
252
329
  const label = _pyTruthy(meta.label)
@@ -276,6 +353,7 @@ function _build_pack_yaml(pid: string, vocab: Record<string, Dict>, artefacts: A
276
353
  ? (meta.trust_level_default as unknown)
277
354
  : 'core',
278
355
  artefact_count: artefacts.length,
356
+ token_passport: _token_passport(artefacts),
279
357
  };
280
358
  if (_isPlainObject(meta.onboarding)) {
281
359
  out.onboarding = meta.onboarding;
@@ -0,0 +1,478 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Grade a TARGET repository's assurance readiness — the matrix `/project:analyze` prints.
4
+ *
5
+ * WHY A SCRIPT AND NOT PROSE. `road-to-target-project-assurance-readiness`
6
+ * Phase 1 asks for detection asserted "by a vitest spec", and a gather list
7
+ * written in a command's markdown cannot be asserted by anything. So the
8
+ * detection is here and the command invokes it; the command keeps the narrative.
9
+ *
10
+ * THE ANTI-VANITY RULE IS STRUCTURAL, NOT A STYLE NOTE. Ten dimensions are
11
+ * graded 0 Absent / 1 Present / 2 Enforced-in-CI / 3 Independent-and-diff-scoped,
12
+ * and the verdict is `min` over the FOUR knockout dimensions, reported as
13
+ * `L<n> — bound by <dimension>`. **No aggregate number is ever emitted** — no
14
+ * percentage, no x/100, no mean. A single score is the vanity metric the source
15
+ * report's own anti-vanity rule forbids, and `renderMatrix` carries a test that
16
+ * greps its own output for `%` and `/100`.
17
+ *
18
+ * NOT-DETECTABLE IS NOT ZERO, AND ON A KNOCKOUT IT BINDS. A `0` claims the target
19
+ * lacks something. `not detectable` says this tool cannot tell — a different fact,
20
+ * and the honest one for a Python target, because `quality-tools` routes PHP and
21
+ * JS/TS only. An undetectable KNOCKOUT binds at L0 with its reason printed, so the
22
+ * gap is visible rather than flattering.
23
+ *
24
+ * SCOPE — this grades, it does not install. Whether a missing gate then gets
25
+ * created in the target is a successor roadmap's problem
26
+ * (`stubs/road-to-target-project-bootstrap-enforce.md`).
27
+ *
28
+ * Exit codes:
29
+ * 0 — a matrix was produced (any level, including L0 — a low grade is a
30
+ * finding about the target, never a failure of this gate)
31
+ * 1 — nothing was gradeable (no target root)
32
+ * 2 — the gate could not run (bad args)
33
+ */
34
+ import * as fs from 'node:fs';
35
+ import * as os from 'node:os';
36
+ import * as path from 'node:path';
37
+ import { fileURLToPath, pathToFileURL } from 'node:url';
38
+
39
+ import { GateLedger } from './_lib/gate_ledger.js';
40
+ import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
41
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
42
+
43
+ const _HERE = fileURLToPath(import.meta.url);
44
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
45
+ const SELF = 'src/scripts/grade_target_readiness.ts';
46
+
47
+ const SELF_TEST_MIN_CASES = 6;
48
+ const SELF_TEST_MIN_REJECT = 2;
49
+
50
+ /** 0 Absent · 1 Present · 2 Enforced-in-CI · 3 Independent-and-diff-scoped. */
51
+ export type Grade = 0 | 1 | 2 | 3;
52
+
53
+ /** `null` means "this tool cannot tell", which is NOT a zero. */
54
+ export interface DimensionResult {
55
+ id: string;
56
+ label: string;
57
+ knockout: boolean;
58
+ grade: Grade | null;
59
+ /** Required when `grade` is null: why detection is impossible, not merely absent. */
60
+ notDetectable?: string;
61
+ evidence: string;
62
+ }
63
+
64
+ export interface Matrix {
65
+ level: Grade | 0;
66
+ boundBy: string;
67
+ boundReason?: string;
68
+ dimensions: DimensionResult[];
69
+ }
70
+
71
+ // ── primitive probes ───────────────────────────────────────────────────────
72
+
73
+ const _exists = (root: string, ...rel: string[]): boolean =>
74
+ rel.some((r) => fs.existsSync(path.join(root, r)));
75
+
76
+ function _glob1(root: string, dir: string, re: RegExp): boolean {
77
+ const d = path.join(root, dir);
78
+ try {
79
+ return fs.readdirSync(d).some((f) => re.test(f));
80
+ } catch {
81
+ return false;
82
+ }
83
+ }
84
+
85
+ function _readIfAny(root: string, ...rel: string[]): string {
86
+ for (const r of rel) {
87
+ try {
88
+ return fs.readFileSync(path.join(root, r), 'utf-8');
89
+ } catch {
90
+ /* next */
91
+ }
92
+ }
93
+ return '';
94
+ }
95
+
96
+ /** Every workflow file's text, concatenated. Empty when there is no CI at all. */
97
+ function _ciText(root: string): string {
98
+ const d = path.join(root, '.github', 'workflows');
99
+ let out = '';
100
+ try {
101
+ for (const f of fs.readdirSync(d)) {
102
+ if (/\.ya?ml$/.test(f)) out += `${fs.readFileSync(path.join(d, f), 'utf-8')}\n`;
103
+ }
104
+ } catch {
105
+ /* no CI */
106
+ }
107
+ return out;
108
+ }
109
+
110
+ /**
111
+ * Is this a Python-primary target?
112
+ *
113
+ * Load-bearing for dimension 4: `quality-tools` routes PHP and JS/TS only, so on
114
+ * a Python target the static-analysis dimension is NOT DETECTABLE rather than 0.
115
+ */
116
+ export function isPythonTarget(root: string): boolean {
117
+ const py = _exists(root, 'pyproject.toml', 'setup.cfg', 'requirements.txt', 'setup.py');
118
+ const other = _exists(root, 'composer.json', 'package.json');
119
+ return py && !other;
120
+ }
121
+
122
+ // ── the ten dimensions ─────────────────────────────────────────────────────
123
+
124
+ /**
125
+ * Grade one dimension. `ci` decides 1 → 2: a thing that exists is `Present`; a
126
+ * thing CI runs in a job that is not `continue-on-error` is `Enforced-in-CI`.
127
+ */
128
+ function _graded(present: boolean, enforced: boolean, diffScoped = false): Grade {
129
+ if (!present) return 0;
130
+ if (diffScoped && enforced) return 3;
131
+ return enforced ? 2 : 1;
132
+ }
133
+
134
+ /** A CI job that cannot fail the build enforces nothing. */
135
+ function _ciBlocks(ci: string, ...needles: string[]): boolean {
136
+ if (ci === '') return false;
137
+ const mentions = needles.some((n) => ci.toLowerCase().includes(n.toLowerCase()));
138
+ if (!mentions) return false;
139
+ // Coarse but honest: a workflow that marks EVERY job continue-on-error
140
+ // enforces nothing. Per-job attribution needs a YAML parse and is the
141
+ // successor roadmap's problem; stated rather than silently approximated.
142
+ const allSoft = /continue-on-error:\s*true/.test(ci) && !/continue-on-error:\s*false/.test(ci);
143
+ return !allSoft;
144
+ }
145
+
146
+ export function grade(root: string): Matrix {
147
+ const ci = _ciText(root);
148
+ const hasCi = ci !== '';
149
+ const py = isPythonTarget(root);
150
+ const pyproject = _readIfAny(root, 'pyproject.toml');
151
+
152
+ const dims: DimensionResult[] = [];
153
+
154
+ // 1. behaviour contract
155
+ const contract = _exists(root, 'AGENTS.md', 'openapi.yaml', 'openapi.yml', 'CONTRACT.md');
156
+ dims.push({
157
+ id: 'behaviour-contract',
158
+ label: 'behaviour contract',
159
+ knockout: false,
160
+ grade: _graded(contract, false),
161
+ evidence: contract ? 'AGENTS.md / OpenAPI / CONTRACT.md present' : 'none found',
162
+ });
163
+
164
+ // 2. test presence & types — KNOCKOUT
165
+ const testCfg =
166
+ _exists(root, 'vitest.config.ts', 'vitest.config.js', 'jest.config.js', 'jest.config.ts',
167
+ 'phpunit.xml', 'phpunit.xml.dist', 'pest.php', 'pytest.ini', 'tox.ini') ||
168
+ /\[tool\.pytest/.test(pyproject);
169
+ dims.push({
170
+ id: 'test-presence',
171
+ label: 'test presence & types',
172
+ knockout: true,
173
+ grade: _graded(testCfg, _ciBlocks(ci, 'vitest', 'jest', 'phpunit', 'pest', 'pytest', 'npm test', 'task test')),
174
+ evidence: testCfg ? 'a test-runner config is present' : 'no test-runner config',
175
+ });
176
+
177
+ // 3. test strength — mutation or property-based
178
+ const mutation =
179
+ _glob1(root, '.', /^stryker\.conf\./) || _exists(root, 'infection.json', 'infection.json.dist') ||
180
+ /\[tool\.mutmut\]/.test(pyproject) || /\[mutmut\]/.test(_readIfAny(root, 'setup.cfg'));
181
+ const property =
182
+ /fast-check/.test(_readIfAny(root, 'package.json')) || /hypothesis/.test(pyproject + _readIfAny(root, 'requirements.txt'));
183
+ dims.push({
184
+ id: 'test-strength',
185
+ label: 'test strength',
186
+ knockout: false,
187
+ grade: _graded(mutation || property, _ciBlocks(ci, 'stryker', 'infection', 'mutmut')),
188
+ evidence: mutation ? 'mutation config present' : property ? 'property-based library present' : 'neither mutation nor property testing',
189
+ });
190
+
191
+ // 4. static analysis & types — KNOCKOUT, and the not-detectable case
192
+ if (py) {
193
+ dims.push({
194
+ id: 'static-analysis',
195
+ label: 'static analysis & types',
196
+ knockout: true,
197
+ grade: null,
198
+ notDetectable: 'quality-tools has no Python mode',
199
+ evidence: 'Python-primary target',
200
+ });
201
+ } else {
202
+ const sa = _exists(root, 'phpstan.neon', 'phpstan.neon.dist', 'psalm.xml', 'tsconfig.json');
203
+ dims.push({
204
+ id: 'static-analysis',
205
+ label: 'static analysis & types',
206
+ knockout: true,
207
+ grade: _graded(sa, _ciBlocks(ci, 'phpstan', 'psalm', 'tsc', 'typecheck')),
208
+ evidence: sa ? 'a static-analysis config is present' : 'no static-analysis config',
209
+ });
210
+ }
211
+
212
+ // 5. architecture gates
213
+ const arch = _glob1(root, '.', /^\.dependency-cruiser\./) || _exists(root, 'deptrac.yaml', 'deptrac.yml');
214
+ dims.push({
215
+ id: 'architecture-gates',
216
+ label: 'architecture gates',
217
+ knockout: false,
218
+ grade: _graded(arch, _ciBlocks(ci, 'dependency-cruiser', 'deptrac')),
219
+ evidence: arch ? 'a boundary-gate config is present' : 'no architecture gate',
220
+ });
221
+
222
+ // 6. security & supply chain — KNOCKOUT
223
+ const lock = _exists(root, 'package-lock.json', 'pnpm-lock.yaml', 'yarn.lock', 'composer.lock', 'poetry.lock', 'uv.lock');
224
+ const sast = _glob1(root, '.', /^\.semgrep/) || _exists(root, 'bandit.yaml', '.bandit');
225
+ const audit = _ciBlocks(ci, 'npm audit', 'pnpm audit', 'composer audit', 'pip-audit', 'semgrep', 'bandit');
226
+ dims.push({
227
+ id: 'security-supply-chain',
228
+ label: 'security & supply chain',
229
+ knockout: true,
230
+ grade: _graded(lock || sast, audit),
231
+ evidence: `${lock ? 'lockfile' : 'no lockfile'}; ${sast ? 'SAST config' : 'no SAST config'}; ${audit ? 'audit runs in CI' : 'no blocking audit step'}`,
232
+ });
233
+
234
+ // 7. CI enforcement — KNOCKOUT
235
+ const blockingJob = hasCi && !(/continue-on-error:\s*true/.test(ci) && !/continue-on-error:\s*false/.test(ci));
236
+ dims.push({
237
+ id: 'ci-enforcement',
238
+ label: 'CI enforcement',
239
+ knockout: true,
240
+ grade: hasCi ? (blockingJob ? 2 : 1) : 0,
241
+ evidence: !hasCi ? 'no workflows' : blockingJob ? 'at least one job can fail the build' : 'every job is continue-on-error',
242
+ });
243
+
244
+ // 8. independent verification
245
+ const owners = _exists(root, 'CODEOWNERS', '.github/CODEOWNERS', 'docs/CODEOWNERS');
246
+ dims.push({
247
+ id: 'independent-verification',
248
+ label: 'independent verification',
249
+ knockout: false,
250
+ grade: _graded(owners, false),
251
+ evidence: owners ? 'CODEOWNERS present' : 'no CODEOWNERS',
252
+ });
253
+
254
+ // 9. evidence & traceability
255
+ const adr = _exists(root, 'docs/adr', 'docs/decisions', 'adr');
256
+ dims.push({
257
+ id: 'evidence-traceability',
258
+ label: 'evidence & traceability',
259
+ knockout: false,
260
+ grade: _graded(adr, false),
261
+ evidence: adr ? 'a decision record directory exists' : 'no decision records',
262
+ });
263
+
264
+ // 10. runtime verification — never detectable, and deliberately NOT a knockout
265
+ dims.push({
266
+ id: 'runtime-verification',
267
+ label: 'runtime verification',
268
+ knockout: false,
269
+ grade: null,
270
+ notDetectable: 'needs a deploy platform this tool does not own',
271
+ evidence: 'out of scope by design (see the roadmap exclusion table)',
272
+ });
273
+
274
+ // ── the verdict: min over knockouts, undetectable binds at L0 ──────────
275
+ const knockouts = dims.filter((d) => d.knockout);
276
+ const undetectable = knockouts.find((d) => d.grade === null);
277
+ if (undetectable !== undefined) {
278
+ // `boundReason` is spread in conditionally rather than assigned
279
+ // `undefined`: under `exactOptionalPropertyTypes` an optional property
280
+ // and a property explicitly set to `undefined` are different types, and
281
+ // the second does not satisfy `boundReason?: string`.
282
+ return {
283
+ level: 0,
284
+ boundBy: undetectable.label,
285
+ ...(undetectable.notDetectable === undefined ? {} : { boundReason: undetectable.notDetectable }),
286
+ dimensions: dims,
287
+ };
288
+ }
289
+ let level: Grade = 3;
290
+ let boundBy = knockouts[0]?.label ?? 'unknown';
291
+ for (const k of knockouts) {
292
+ const g = k.grade as Grade;
293
+ if (g < level) {
294
+ level = g;
295
+ boundBy = k.label;
296
+ }
297
+ }
298
+ return { level, boundBy, dimensions: dims };
299
+ }
300
+
301
+ // ── rendering ──────────────────────────────────────────────────────────────
302
+
303
+ const GRADE_WORD: Record<number, string> = { 0: 'Absent', 1: 'Present', 2: 'Enforced-in-CI', 3: 'Independent+diff-scoped' };
304
+
305
+ /**
306
+ * Render the matrix. Emits NO aggregate figure — no `%`, no `/100`, no mean.
307
+ * A test greps this function's own output for both, because the pressure to
308
+ * print one number is exactly what turns readiness into a vanity metric.
309
+ */
310
+ export function renderMatrix(m: Matrix): string {
311
+ const L: string[] = [];
312
+ L.push('READINESS');
313
+ L.push(
314
+ m.boundReason !== undefined
315
+ ? `L${String(m.level)} — bound by ${m.boundBy} (not detectable — ${m.boundReason})`
316
+ : `L${String(m.level)} — bound by ${m.boundBy}`,
317
+ );
318
+ L.push('');
319
+ for (const d of m.dimensions) {
320
+ const val = d.grade === null ? `not detectable — ${d.notDetectable ?? ''}` : `${String(d.grade)} ${GRADE_WORD[d.grade] ?? ''}`;
321
+ L.push(` ${d.knockout ? '!' : ' '} ${d.label.padEnd(28)} ${val}`);
322
+ }
323
+ L.push('');
324
+ L.push(' ! = knockout dimension. The level is the MINIMUM over knockouts;');
325
+ L.push(' an undetectable knockout binds at L0 with its reason shown.');
326
+ L.push(' No aggregate score is reported, by design.');
327
+ return L.join('\n');
328
+ }
329
+
330
+ // ── self-test ──────────────────────────────────────────────────────────────
331
+
332
+ function _mk(files: Record<string, string>): string {
333
+ const d = fs.mkdtempSync(path.join(os.tmpdir(), 'target-readiness-'));
334
+ for (const [rel, body] of Object.entries(files)) {
335
+ const p = path.join(d, rel);
336
+ fs.mkdirSync(path.dirname(p), { recursive: true });
337
+ fs.writeFileSync(p, body);
338
+ }
339
+ return d;
340
+ }
341
+
342
+ const BLOCKING_CI = 'jobs:\n t:\n steps:\n - run: npx vitest run\n - run: npx tsc --noEmit\n - run: npm audit\n';
343
+
344
+ export function selfTest(): number {
345
+ const made: string[] = [];
346
+ const mk = (f: Record<string, string>): string => {
347
+ const d = _mk(f);
348
+ made.push(d);
349
+ return d;
350
+ };
351
+ const cases: SelfTestCase[] = [
352
+ {
353
+ name: 'a bare directory grades L0 bound by a knockout, and does not crash',
354
+ expect: 'accept',
355
+ run: () => (grade(mk({ 'README.md': '#\n' })).level === 0 ? 0 : 1),
356
+ },
357
+ {
358
+ name: 'a Python target reports static analysis NOT DETECTABLE, never 0',
359
+ expect: 'accept',
360
+ run: () => {
361
+ const m = grade(mk({ 'pyproject.toml': '[tool.pytest.ini_options]\n' }));
362
+ const sa = m.dimensions.find((d) => d.id === 'static-analysis');
363
+ return sa?.grade === null && sa.notDetectable === 'quality-tools has no Python mode' ? 0 : 1;
364
+ },
365
+ },
366
+ {
367
+ name: 'an undetectable knockout BINDS at L0 with its reason',
368
+ expect: 'accept',
369
+ run: () => {
370
+ const m = grade(mk({ 'pyproject.toml': '[tool.pytest.ini_options]\n' }));
371
+ return m.level === 0 && m.boundBy === 'static analysis & types' && m.boundReason !== undefined ? 0 : 1;
372
+ },
373
+ },
374
+ {
375
+ name: 'CI enforcement at 0 binds even when everything else is enforced',
376
+ expect: 'accept',
377
+ run: () => {
378
+ const m = grade(mk({
379
+ 'package.json': '{"devDependencies":{"fast-check":"1"}}',
380
+ 'tsconfig.json': '{}',
381
+ 'vitest.config.ts': '',
382
+ 'package-lock.json': '{}',
383
+ '.semgrep.yml': '',
384
+ 'deptrac.yaml': '',
385
+ 'AGENTS.md': '#\n',
386
+ 'CODEOWNERS': '* @o\n',
387
+ 'docs/adr/ADR-1.md': '#\n',
388
+ }));
389
+ return m.level === 0 && m.boundBy === 'CI enforcement' ? 0 : 1;
390
+ },
391
+ },
392
+ {
393
+ name: 'the rendered matrix carries NO aggregate figure',
394
+ expect: 'accept',
395
+ run: () => {
396
+ const out = renderMatrix(grade(mk({ 'package.json': '{}', '.github/workflows/ci.yml': BLOCKING_CI })));
397
+ return /%|\/100/.test(out) ? 1 : 0;
398
+ },
399
+ },
400
+ {
401
+ name: 'rejects a missing target root rather than grading an empty tree',
402
+ expect: 'reject',
403
+ run: () => runGateCli(REPO_ROOT, SELF, ['--quiet', '--target', path.join(REPO_ROOT, 'no-such-target')], REPO_ROOT),
404
+ },
405
+ {
406
+ name: 'rejects a target argument that is a file, not a directory',
407
+ expect: 'reject',
408
+ run: () => runGateCli(REPO_ROOT, SELF, ['--quiet', '--target', path.join(REPO_ROOT, 'package.json')], REPO_ROOT),
409
+ },
410
+ ];
411
+ try {
412
+ return runSelfTest({ gate: 'grade_target_readiness', cases, minCases: SELF_TEST_MIN_CASES, minRejectCases: SELF_TEST_MIN_REJECT });
413
+ } finally {
414
+ for (const d of made) fs.rmSync(d, { recursive: true, force: true });
415
+ }
416
+ }
417
+
418
+ function main(argv?: readonly string[]): number {
419
+ const args = argv ?? process.argv.slice(2);
420
+ if (args.includes('--self-test')) return selfTest();
421
+ const quiet = args.includes('--quiet');
422
+ const i = args.indexOf('--target');
423
+ const target = i >= 0 ? args[i + 1] : process.cwd();
424
+ if (target === undefined) {
425
+ process.stderr.write('grade_target_readiness: --target requires a directory\n');
426
+ return 2;
427
+ }
428
+ let stat: fs.Stats;
429
+ try {
430
+ stat = fs.statSync(target);
431
+ } catch {
432
+ process.stderr.write(`❌ target not found: ${target}\n`);
433
+ return 1;
434
+ }
435
+ if (!stat.isDirectory()) {
436
+ process.stderr.write(`❌ target is not a directory: ${target}\n`);
437
+ return 1;
438
+ }
439
+
440
+ const m = grade(target);
441
+ const ledger = new GateLedger('grade_target_readiness');
442
+ ledger.plan(m.dimensions.map((d) => d.id));
443
+ for (const d of m.dimensions) {
444
+ if (d.grade === null) ledger.outOfScope(d.id, 'not_applicable_kind');
445
+ else ledger.complete(d.id);
446
+ }
447
+ ledger.report();
448
+ try {
449
+ reportScanned({
450
+ gate: 'grade_target_readiness',
451
+ scanned: m.dimensions.length,
452
+ units: 'readiness dimension(s)',
453
+ roots: [target],
454
+ });
455
+ } catch (err) {
456
+ if (err instanceof DeadScopeError) {
457
+ process.stderr.write(`❌ ${err.message}\n`);
458
+ return 2;
459
+ }
460
+ throw err;
461
+ }
462
+ if (!quiet) process.stdout.write(`${renderMatrix(m)}\n`);
463
+ return 0;
464
+ }
465
+
466
+ function _isCliEntry(): boolean {
467
+ if (process.argv[1] === undefined) return false;
468
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
469
+ try {
470
+ return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(path.resolve(process.argv[1]));
471
+ } catch {
472
+ return false;
473
+ }
474
+ }
475
+
476
+ if (_isCliEntry() || process.argv[1] === _HERE) process.exit(main());
477
+
478
+ export { main };