@event4u/agent-config 14.10.0 → 14.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +335 -0
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/design.md +88 -0
  7. package/dist/agent-src/commands/project/analyze.md +47 -0
  8. package/dist/agent-src/commands/review/changes.md +67 -6
  9. package/dist/agent-src/commands/roadmap/create.md +49 -0
  10. package/dist/agent-src/commands/roadmap/next.md +27 -11
  11. package/dist/agent-src/commands/roadmap/process-full.md +14 -0
  12. package/dist/agent-src/commands/video/from-script.md +60 -3
  13. package/dist/agent-src/commands/video/stitch.md +14 -0
  14. package/dist/agent-src/contexts/communication/rules-auto/guidelines-mechanics.md +1 -0
  15. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
  16. package/dist/agent-src/rules/active-remediation.md +3 -3
  17. package/dist/agent-src/rules/code-provenance.md +2 -2
  18. package/dist/agent-src/rules/context-hygiene.md +13 -33
  19. package/dist/agent-src/rules/council-availability.md +2 -2
  20. package/dist/agent-src/rules/decision-revisit-gate.md +3 -1
  21. package/dist/agent-src/rules/design-fidelity.md +18 -0
  22. package/dist/agent-src/rules/design-review-after-ui-write.md +2 -2
  23. package/dist/agent-src/rules/evaluator-independence.md +56 -44
  24. package/dist/agent-src/rules/fix-what-you-see.md +9 -1
  25. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  26. package/dist/agent-src/rules/minimal-safe-diff.md +14 -20
  27. package/dist/agent-src/rules/missing-skill-recovery.md +13 -1
  28. package/dist/agent-src/rules/playbook-precedence.md +105 -0
  29. package/dist/agent-src/rules/recurring-criticism.md +3 -1
  30. package/dist/agent-src/rules/roadmap-progress-sync.md +14 -13
  31. package/dist/agent-src/rules/scale-discipline.md +24 -0
  32. package/dist/agent-src/rules/security-sensitive-stop.md +2 -2
  33. package/dist/agent-src/rules/settings-ask-protocol.md +2 -2
  34. package/dist/agent-src/rules/ui-audit-gate.md +27 -15
  35. package/dist/agent-src/rules/untrusted-input-defense.md +2 -2
  36. package/dist/agent-src/skills/accessibility-auditor/SKILL.md +19 -0
  37. package/dist/agent-src/skills/adr-create/SKILL.md +7 -0
  38. package/dist/agent-src/skills/agents-md-thin-root/SKILL.md +33 -0
  39. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +17 -3
  40. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +31 -0
  41. package/dist/agent-src/skills/ai-council/references/procedure.md +19 -0
  42. package/dist/agent-src/skills/alerting-doctrine/SKILL.md +225 -0
  43. package/dist/agent-src/skills/alerting-doctrine/evals/triggers.json +17 -0
  44. package/dist/agent-src/skills/authz-review/SKILL.md +0 -1
  45. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +32 -0
  46. package/dist/agent-src/skills/brand/SKILL.md +3 -0
  47. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +3 -0
  48. package/dist/agent-src/skills/brand-audit/SKILL.md +3 -0
  49. package/dist/agent-src/skills/brand-identity/SKILL.md +3 -0
  50. package/dist/agent-src/skills/brand-strategy/SKILL.md +3 -0
  51. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +3 -0
  52. package/dist/agent-src/skills/check-refs/SKILL.md +3 -0
  53. package/dist/agent-src/skills/code-review/SKILL.md +11 -0
  54. package/dist/agent-src/skills/command-routing/SKILL.md +6 -0
  55. package/dist/agent-src/skills/condense-memory/SKILL.md +3 -0
  56. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  57. package/dist/agent-src/skills/conventional-commits-writing/SKILL.md +3 -0
  58. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +10 -0
  59. package/dist/agent-src/skills/corpus-grounding/SKILL.md +3 -0
  60. package/dist/agent-src/skills/design-intelligence/SKILL.md +3 -0
  61. package/dist/agent-src/skills/design-intelligence/data/landing.csv +36 -35
  62. package/dist/agent-src/skills/design-intelligence/data/stacks/threejs.csv +1 -0
  63. package/dist/agent-src/skills/design-review/SKILL.md +79 -1
  64. package/dist/agent-src/skills/design-review/references/verification-automation.md +41 -0
  65. package/dist/agent-src/skills/design-system-capture/SKILL.md +35 -40
  66. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +50 -0
  67. package/dist/agent-src/skills/design-tokens/SKILL.md +3 -0
  68. package/dist/agent-src/skills/design-variations/SKILL.md +3 -0
  69. package/dist/agent-src/skills/developer-like-execution/SKILL.md +3 -0
  70. package/dist/agent-src/skills/estimate-ticket/SKILL.md +3 -0
  71. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +20 -3
  72. package/dist/agent-src/skills/fe-design/SKILL.md +74 -41
  73. package/dist/agent-src/skills/fe-design/evals/triggers.json +65 -53
  74. package/dist/agent-src/skills/fe-design/references/craft-floor.md +52 -0
  75. package/dist/agent-src/skills/fe-design/references/source-led-port.md +36 -0
  76. package/dist/agent-src/skills/file-editor/SKILL.md +5 -0
  77. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +2 -2
  78. package/dist/agent-src/skills/git-workflow/SKILL.md +3 -0
  79. package/dist/agent-src/skills/html-deck/SKILL.md +3 -0
  80. package/dist/agent-src/skills/iconography/SKILL.md +3 -0
  81. package/dist/agent-src/skills/image-editing/SKILL.md +3 -0
  82. package/dist/agent-src/skills/image-generation/SKILL.md +3 -0
  83. package/dist/agent-src/skills/image-provider-routing/SKILL.md +3 -0
  84. package/dist/agent-src/skills/incident-commander/SKILL.md +10 -0
  85. package/dist/agent-src/skills/js-library-packaging/SKILL.md +173 -0
  86. package/dist/agent-src/skills/js-library-packaging/evals/triggers.json +17 -0
  87. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +270 -0
  88. package/dist/agent-src/skills/laravel-migration/SKILL.md +3 -0
  89. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +3 -0
  90. package/dist/agent-src/skills/lint-skills/SKILL.md +3 -0
  91. package/dist/agent-src/skills/llm-provider-knowledge/SKILL.md +3 -0
  92. package/dist/agent-src/skills/logging-monitoring/SKILL.md +234 -51
  93. package/dist/agent-src/skills/logo-generation/SKILL.md +3 -0
  94. package/dist/agent-src/skills/md-language-check/SKILL.md +3 -0
  95. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +149 -0
  96. package/dist/agent-src/skills/monorepo-workspace/evals/triggers.json +17 -0
  97. package/dist/agent-src/skills/motion-choreographer/SKILL.md +6 -0
  98. package/dist/agent-src/skills/multi-tenancy/SKILL.md +4 -0
  99. package/dist/agent-src/skills/operational-readiness/SKILL.md +184 -0
  100. package/dist/agent-src/skills/operational-readiness/evals/triggers.json +17 -0
  101. package/dist/agent-src/skills/override-management/SKILL.md +3 -0
  102. package/dist/agent-src/skills/persona-improvement/SKILL.md +3 -0
  103. package/dist/agent-src/skills/pest-testing/SKILL.md +3 -0
  104. package/dist/agent-src/skills/playbook-authoring/SKILL.md +162 -0
  105. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -0
  106. package/dist/agent-src/skills/privacy-review/SKILL.md +3 -0
  107. package/dist/agent-src/skills/prompt-engineering-image/SKILL.md +3 -0
  108. package/dist/agent-src/skills/quality-tools/SKILL.md +5 -0
  109. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +52 -21
  110. package/dist/agent-src/skills/readme-reviewer/SKILL.md +3 -0
  111. package/dist/agent-src/skills/readme-writing/SKILL.md +3 -0
  112. package/dist/agent-src/skills/readme-writing-package/SKILL.md +3 -0
  113. package/dist/agent-src/skills/receiving-code-review/SKILL.md +2 -2
  114. package/dist/agent-src/skills/refine-prompt/SKILL.md +3 -0
  115. package/dist/agent-src/skills/refine-ticket/SKILL.md +3 -0
  116. package/dist/agent-src/skills/requesting-code-review/SKILL.md +2 -2
  117. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  118. package/dist/agent-src/skills/roadmap-writing/SKILL.md +23 -41
  119. package/dist/agent-src/skills/roadmap-writing/references/follow-up-roadmap-shape.md +47 -0
  120. package/dist/agent-src/skills/rtk-output-filtering/SKILL.md +22 -6
  121. package/dist/agent-src/skills/runway-cognition/SKILL.md +3 -0
  122. package/dist/agent-src/skills/scene-expander/scene-blueprint.schema.yaml +26 -0
  123. package/dist/agent-src/skills/secrets-management/SKILL.md +4 -0
  124. package/dist/agent-src/skills/server-hardening/SKILL.md +159 -0
  125. package/dist/agent-src/skills/server-hardening/evals/triggers.json +17 -0
  126. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +3 -0
  127. package/dist/agent-src/skills/skill-management/SKILL.md +3 -0
  128. package/dist/agent-src/skills/skill-reviewer/SKILL.md +3 -0
  129. package/dist/agent-src/skills/skill-writing/SKILL.md +6 -0
  130. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +3 -0
  131. package/dist/agent-src/skills/storybook-workshop/SKILL.md +194 -0
  132. package/dist/agent-src/skills/storybook-workshop/evals/triggers.json +17 -0
  133. package/dist/agent-src/skills/storybook-workshop/scripts/story_contrast_floor.ts +134 -0
  134. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  135. package/dist/agent-src/skills/subagent-orchestration/prompts/README.md +25 -0
  136. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +12 -0
  137. package/dist/agent-src/skills/systematic-debugging/SKILL.md +1 -1
  138. package/dist/agent-src/skills/terraform/SKILL.md +3 -0
  139. package/dist/agent-src/skills/test-driven-development/SKILL.md +1 -1
  140. package/dist/agent-src/skills/threat-modeling/SKILL.md +0 -3
  141. package/dist/agent-src/skills/token-optimizer/SKILL.md +3 -0
  142. package/dist/agent-src/skills/typography-system/SKILL.md +3 -0
  143. package/dist/agent-src/skills/ui-component-architect/SKILL.md +9 -1
  144. package/dist/agent-src/skills/upstream-contribute/SKILL.md +3 -0
  145. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +3 -0
  146. package/dist/agent-src/skills/verify-completion-evidence/SKILL.md +2 -2
  147. package/dist/agent-src/skills/wireframe/SKILL.md +3 -0
  148. package/dist/agent-src/skills/wireframe/references/story-beat-ledger.schema.json +115 -0
  149. package/dist/agent-src/skills/workspace-link/SKILL.md +131 -0
  150. package/dist/agent-src/skills/workspace-link/evals/triggers.json +17 -0
  151. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  152. package/dist/agent-src/templates/playbook.md +75 -0
  153. package/dist/agent-src/templates/roadmaps.md +37 -0
  154. package/dist/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  155. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  156. package/dist/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  157. package/dist/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  158. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  159. package/dist/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  160. package/dist/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  161. package/dist/cli/commands/uiAudit.js +221 -0
  162. package/dist/cli/commands/uiAudit.js.map +1 -0
  163. package/dist/cli/commands/uiRender.js +206 -0
  164. package/dist/cli/commands/uiRender.js.map +1 -0
  165. package/dist/cli/main.js +22 -1
  166. package/dist/cli/main.js.map +1 -1
  167. package/dist/cli/mcp/content.js +64 -1
  168. package/dist/cli/mcp/content.js.map +1 -1
  169. package/dist/cli/mcp/dispatch.js +175 -10
  170. package/dist/cli/mcp/dispatch.js.map +1 -1
  171. package/dist/cli/registry.js +3 -0
  172. package/dist/cli/registry.js.map +1 -1
  173. package/dist/cli-delegate/{chunk-H4VIVD4C.js → chunk-236PNQZK.js} +413 -391
  174. package/dist/cli-delegate/{chunk-G23AT6GD.js → chunk-DMSZHXZS.js} +57 -1
  175. package/dist/cli-delegate/{chunk-77GR3VD4.js → chunk-FF7WAFMR.js} +58 -3
  176. package/dist/cli-delegate/{chunk-PLSG6UL5.js → chunk-K4FFODTS.js} +341 -204
  177. package/dist/cli-delegate/{chunk-YM4GZDJG.js → chunk-L43NCYPB.js} +5 -0
  178. package/dist/cli-delegate/{chunk-B2ERU2VA.js → chunk-WOKWX5PL.js} +1 -1
  179. package/dist/cli-delegate/cmd_brand_status.js +8 -6
  180. package/dist/cli-delegate/cmd_conformance.js +3 -3
  181. package/dist/cli-delegate/cmd_doctor.js +3 -3
  182. package/dist/cli-delegate/cmd_export.js +4 -4
  183. package/dist/cli-delegate/cmd_handoff.js +1 -1
  184. package/dist/cli-delegate/cmd_preflight.js +2 -2
  185. package/dist/cli-delegate/cmd_prune.js +4 -4
  186. package/dist/cli-delegate/cmd_session_recycle.js +70 -9
  187. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  188. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  189. package/dist/cli-delegate/cmd_sync.js +4 -4
  190. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  191. package/dist/cli-delegate/cmd_validate.js +4 -4
  192. package/dist/discovery/deprecation-report.md +1 -1
  193. package/dist/discovery/discovery-manifest.json +359 -124
  194. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  195. package/dist/discovery/discovery-manifest.summary.md +4 -4
  196. package/dist/discovery/dormancy-report.md +1 -1
  197. package/dist/discovery/orphan-report.md +1 -1
  198. package/dist/discovery/packs.json +18 -8
  199. package/dist/discovery/trust-report.md +3 -3
  200. package/dist/discovery/workspaces.json +16 -6
  201. package/dist/hooks/dispatch.js +2337 -1436
  202. package/dist/install/install.mjs +795 -708
  203. package/dist/mcp/registry-manifest.json +3 -3
  204. package/dist/mcp/server.json +2 -2
  205. package/dist/mcp/server.mjs +1685 -1250
  206. package/dist/router.json +1 -1
  207. package/dist/scripts/_lib/lean_projection_mode.js +40 -0
  208. package/dist/scripts/_lib/lean_projection_mode.js.map +1 -0
  209. package/dist/scripts/_lib/scoped_projection.js +84 -0
  210. package/dist/scripts/_lib/scoped_projection.js.map +1 -1
  211. package/dist/scripts/_lib/ui_surface.js +89 -0
  212. package/dist/scripts/_lib/ui_surface.js.map +1 -0
  213. package/dist/scripts/condense.js +6 -10
  214. package/dist/scripts/condense.js.map +1 -1
  215. package/dist/scripts/project_thin_rules.js +40 -2
  216. package/dist/scripts/project_thin_rules.js.map +1 -1
  217. package/dist/server/schemas/settings.js +3 -0
  218. package/dist/server/schemas/settings.js.map +1 -1
  219. package/dist/shared/skillRanking.js +159 -0
  220. package/dist/shared/skillRanking.js.map +1 -0
  221. package/docs/contracts/provider-lifecycle.md +47 -18
  222. package/docs/contracts/settings-classes.md +14 -4
  223. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +49 -0
  224. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  225. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +45 -1
  226. package/docs/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  227. package/docs/guidelines/design-antipatterns.md +4 -2
  228. package/docs/guidelines/design-asset-discipline.md +38 -0
  229. package/docs/guidelines/design-fidelity-mechanics.md +45 -29
  230. package/docs/guidelines/design-handover-extraction.md +35 -5
  231. package/docs/guidelines/design-modes.md +41 -1
  232. package/docs/guidelines/monorepo-antipatterns.md +141 -0
  233. package/llms.txt +50 -39
  234. package/package.json +1 -1
  235. package/src/agent-src/templates/scripts/check_playbook_invokes.ts +231 -0
  236. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +24 -0
  237. package/src/agent-src/templates/scripts/work_engine/directives/ui/polish.ts +2 -0
  238. package/src/agent-src/templates/scripts/work_engine/directives/ui/review.ts +216 -0
  239. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +159 -0
  240. package/src/agent-src/templates/scripts/work_engine/directives/ui/stack_bundles.ts +73 -4
  241. package/src/agent-src/templates/scripts/work_engine/stack/detect.ts +325 -40
  242. package/src/config/agent-settings.template.yml +28 -0
  243. package/src/config/assurance-capability-registry.json +223 -0
  244. package/src/config/assurance-threshold-budget.json +65 -0
  245. package/src/config/ci-local-parity.yml +14 -0
  246. package/src/config/discovery/unassigned-artefacts.yml +2 -0
  247. package/src/config/dispatch-economy-metrics.json +4 -2
  248. package/src/config/evaluator-budgets.json +14 -14
  249. package/src/config/gate-coverage.yml +207 -8
  250. package/src/config/gate-violation-baselines.json +76 -72
  251. package/src/config/hook-latency-budget.json +1 -0
  252. package/src/config/hook-token-budget.json +137 -125
  253. package/src/config/pack-size-budget.json +4 -2
  254. package/src/config/quorum-attendance-budget.json +12 -4
  255. package/src/config/rule-activation-census.json +7 -3
  256. package/src/config/rule-enforcement-baseline.json +0 -1
  257. package/src/config/rule-stub-ceilings.json +112 -91
  258. package/src/scripts/_cli/cmd_doctor.ts +15 -16
  259. package/src/scripts/_cli/doctor_install_mode.ts +49 -0
  260. package/src/scripts/_cli/doctor_overrides.ts +154 -0
  261. package/src/scripts/_dispatch.bash +17 -0
  262. package/src/scripts/_lib/as_of.ts +412 -0
  263. package/src/scripts/_lib/exec_evidence.ts +7 -0
  264. package/src/scripts/_lib/hook_settings.ts +33 -0
  265. package/src/scripts/_lib/host_listing_model.ts +192 -0
  266. package/src/scripts/_lib/lean_projection_mode.ts +44 -0
  267. package/src/scripts/_lib/mcp_bridge.ts +199 -0
  268. package/src/scripts/_lib/review_independence.ts +62 -10
  269. package/src/scripts/_lib/rule_injection.ts +239 -0
  270. package/src/scripts/_lib/run_checkpoint.ts +54 -1
  271. package/src/scripts/_lib/scoped_projection.ts +96 -0
  272. package/src/scripts/_lib/session_register.ts +44 -2
  273. package/src/scripts/_lib/skill_catalogue.ts +38 -2
  274. package/src/scripts/_lib/transcript_reads.ts +207 -0
  275. package/src/scripts/_lib/ui_authority.test.ts +251 -0
  276. package/src/scripts/_lib/ui_authority.ts +343 -0
  277. package/src/scripts/ai-video/adapters/fal.sh +8 -3
  278. package/src/scripts/ai-video/adapters/gemini-veo.sh +10 -0
  279. package/src/scripts/ai-video/adapters/higgsfield.sh +10 -2
  280. package/src/scripts/ai-video/adapters/kling.sh +10 -0
  281. package/src/scripts/ai-video/adapters/sora.sh +10 -0
  282. package/src/scripts/ai-video/lib/calibrate-cost.sh +145 -0
  283. package/src/scripts/ai-video/lib/model-capabilities/README.md +53 -7
  284. package/src/scripts/ai-video/lib/model-capabilities/comfyui.json +15 -3
  285. package/src/scripts/ai-video/lib/model-capabilities/fal.json +36 -6
  286. package/src/scripts/ai-video/lib/model-capabilities/gemini-veo.json +23 -0
  287. package/src/scripts/ai-video/lib/model-capabilities/higgsfield.json +23 -0
  288. package/src/scripts/ai-video/lib/model-capabilities/kling.json +23 -0
  289. package/src/scripts/ai-video/lib/model-capabilities/musetalk.json +8 -2
  290. package/src/scripts/ai-video/lib/model-capabilities/replicate.json +36 -6
  291. package/src/scripts/ai-video/lib/model-capabilities/sora.json +45 -0
  292. package/src/scripts/ai-video/lib/model-capabilities/syncso.json +8 -2
  293. package/src/scripts/ai-video/lib/parse-blueprint.sh +52 -5
  294. package/src/scripts/ai-video/lib/resume-scan.sh +92 -3
  295. package/src/scripts/ai-video/lib/seam-plan.sh +212 -0
  296. package/src/scripts/ai-video/smoke-trace.sh +450 -2
  297. package/src/scripts/ai-video/stitch.sh +191 -10
  298. package/src/scripts/ai-video/test-pipeline.sh +84 -6
  299. package/src/scripts/ai_council/cli_agency_bounds.ts +139 -0
  300. package/src/scripts/ai_council/cli_least_agency_canary.ts +347 -0
  301. package/src/scripts/ai_council/clients.ts +3 -2
  302. package/src/scripts/ai_council/consensus.ts +63 -6
  303. package/src/scripts/ai_council/events_log.ts +46 -1
  304. package/src/scripts/ai_council/orchestrator.ts +103 -108
  305. package/src/scripts/ai_council/orchestrator_results.ts +166 -0
  306. package/src/scripts/ai_council/prompts.ts +12 -5
  307. package/src/scripts/ai_council/quorum.ts +82 -1
  308. package/src/scripts/ai_council/quorum_wiring.ts +82 -5
  309. package/src/scripts/ai_council/stance_tally.ts +22 -0
  310. package/src/scripts/bench_hook_latency.ts +62 -0
  311. package/src/scripts/build_proof.ts +12 -1
  312. package/src/scripts/capture_skill_catalogue.ts +21 -0
  313. package/src/scripts/check_always_budget.ts +2 -1
  314. package/src/scripts/check_augmentignore.ts +2 -1
  315. package/src/scripts/check_beta_review_markers.ts +2 -1
  316. package/src/scripts/check_composite_arming.ts +364 -0
  317. package/src/scripts/check_corpus_staleness.ts +2 -1
  318. package/src/scripts/check_council_pin_staleness.ts +3 -1
  319. package/src/scripts/check_enforcement_coverage.ts +116 -3
  320. package/src/scripts/check_enforcement_denominator.ts +365 -0
  321. package/src/scripts/check_gate_coverage.ts +2 -1
  322. package/src/scripts/check_hook_bundle_freshness.ts +13 -1
  323. package/src/scripts/check_knowledge_cards.ts +2 -1
  324. package/src/scripts/check_knowledge_pages.ts +3 -2
  325. package/src/scripts/check_memory.ts +2 -1
  326. package/src/scripts/check_no_automerge_key.ts +287 -0
  327. package/src/scripts/check_pack_conformance_fixture.ts +565 -0
  328. package/src/scripts/check_proposal.ts +2 -1
  329. package/src/scripts/check_reach_staleness.ts +2 -1
  330. package/src/scripts/check_release_adjacent_health.ts +2 -1
  331. package/src/scripts/check_release_pr_shape.ts +5 -0
  332. package/src/scripts/check_review_schema.ts +34 -1
  333. package/src/scripts/check_roadmap_trackable.ts +48 -3
  334. package/src/scripts/check_source_size_budget.ts +2 -1
  335. package/src/scripts/check_standing_payload_delta.ts +505 -0
  336. package/src/scripts/check_trigger_evals.ts +2 -1
  337. package/src/scripts/classify_change_risk.ts +281 -0
  338. package/src/scripts/compute_skill_tiers.ts +186 -0
  339. package/src/scripts/condense.ts +8 -13
  340. package/src/scripts/council_attendance_metrics.ts +183 -0
  341. package/src/scripts/council_cli.ts +10 -8
  342. package/src/scripts/council_parse_rate.ts +116 -0
  343. package/src/scripts/derive_playbooks.ts +406 -0
  344. package/src/scripts/design_slop_rules.test.ts +7 -0
  345. package/src/scripts/design_slop_rules.ts +56 -2
  346. package/src/scripts/dispatch_r2_reviewer.ts +16 -0
  347. package/src/scripts/frontend_corpus_hash.ts +116 -0
  348. package/src/scripts/grade_target_readiness.ts +478 -0
  349. package/src/scripts/hook_manifest.json +1 -1
  350. package/src/scripts/hook_manifest.yaml +97 -16
  351. package/src/scripts/hooks/concern_registry.ts +4 -0
  352. package/src/scripts/hooks/design_pass_hook.ts +356 -0
  353. package/src/scripts/hooks/rtk_wrap_hook.ts +30 -7
  354. package/src/scripts/hooks/rule_inject_hook.ts +318 -0
  355. package/src/scripts/hot_context_hook.ts +74 -7
  356. package/src/scripts/install.ts +40 -89
  357. package/src/scripts/lint_adapter_tier.ts +663 -0
  358. package/src/scripts/lint_archived_skills.ts +93 -0
  359. package/src/scripts/lint_budget_ownership.ts +2 -1
  360. package/src/scripts/lint_deterministic_time.ts +470 -0
  361. package/src/scripts/lint_framework_leakage.ts +5 -0
  362. package/src/scripts/lint_handoffs.ts +525 -1
  363. package/src/scripts/lint_judge_prompt_expectation.ts +155 -0
  364. package/src/scripts/lint_marketplace.ts +88 -0
  365. package/src/scripts/lint_media_policy_linkage.ts +140 -1
  366. package/src/scripts/lint_one_off_age.ts +6 -1
  367. package/src/scripts/lint_override_kernel_guard.ts +87 -5
  368. package/src/scripts/lint_roadmap_complexity.ts +56 -0
  369. package/src/scripts/lint_rule_enforcement_declaration.ts +24 -7
  370. package/src/scripts/lint_rule_norm_pin.ts +321 -0
  371. package/src/scripts/lint_spawn_payload.ts +42 -5
  372. package/src/scripts/lint_symptom_intake.ts +2 -1
  373. package/src/scripts/mcp_parity_smoke.ts +30 -4
  374. package/src/scripts/mcp_render.ts +66 -1
  375. package/src/scripts/mcp_tool_fingerprint.ts +241 -0
  376. package/src/scripts/measure_risk_class_drift.ts +140 -0
  377. package/src/scripts/measure_skill_ranker_baseline.ts +212 -0
  378. package/src/scripts/media/lib/adapter-common.sh +211 -1
  379. package/src/scripts/media/lib/adapter-contract.md +74 -6
  380. package/src/scripts/model_rule_injection.ts +907 -0
  381. package/src/scripts/project_thin_rules.ts +45 -2
  382. package/src/scripts/release.ts +66 -860
  383. package/src/scripts/release_drill.ts +59 -3
  384. package/src/scripts/release_env.ts +298 -0
  385. package/src/scripts/release_publication.ts +720 -0
  386. package/src/scripts/roadmap_context.ts +778 -0
  387. package/src/scripts/schemas/fidelity-measurement-sheet.schema.json +169 -0
  388. package/src/scripts/schemas/rule.schema.json +24 -2
  389. package/src/scripts/schemas/skill.schema.json +39 -0
  390. package/src/scripts/schemas/ui-authority.schema.json +114 -0
  391. package/src/scripts/session_register_hook.ts +29 -3
  392. package/src/scripts/sessions_cli.ts +67 -3
  393. package/src/scripts/skill_tools/score_skill_relevance.ts +36 -53
  394. package/src/scripts/token_sink_report.ts +239 -0
  395. package/src/scripts/trigger_coverage.ts +122 -3
  396. package/src/scripts/update_counts.ts +7 -3
  397. package/src/scripts/validate_frontmatter.ts +66 -0
  398. package/src/server/schemas/settings.ts +5 -0
  399. package/src/shared/skillRanking.ts +183 -0
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Warn when a captured judge prompt states an EXPECTATION of the outcome.
4
+ *
5
+ * Step 4.2 of `road-to-review-independence`, and the companion to
6
+ * `evidence_independence.ts`. That concern blocks a prompt carrying a pre-loaded
7
+ * **verdict**; this one reads the prompts that were actually sent and warns on the
8
+ * softer form — a statement of what the author thinks the answer will be.
9
+ *
10
+ * The distinction is not academic. *"NO-FINDINGS is expected and welcome"* names no
11
+ * verdict and supplies one; it steered a real review into an honest-null that a later
12
+ * unsteered pass refuted with five findings, one critical, already live on the trunk.
13
+ * `evaluator-independence.md` states the rule; this is the part a script can see.
14
+ *
15
+ * WHAT IT CANNOT SEE — stated here so the gate is not oversold, exactly as
16
+ * `evidence_independence.ts` states its own phrase-list limit:
17
+ *
18
+ * 1. **A paraphrase.** This is a PHRASE LIST. "no findings expected" is caught; "I'd be
19
+ * surprised if anything turns up" is not. It catches recurrences of known steering
20
+ * wording, never steering as such. Closing that needs a judgement, not a check.
21
+ * 2. **Omission.** A round that commits no `prompt.md` is not in the scanned set at all —
22
+ * the same cheapest-bypass `check_review_prompt_binding` records for itself. Nothing
23
+ * in the tree requires the package to exist.
24
+ * 3. **Substitution.** The party that writes a steered prompt also writes the file, so
25
+ * swapping a clean one in passes. What changes is that steering then requires an act
26
+ * of substitution rather than merely a careless sentence.
27
+ *
28
+ * WARN-ONLY, deliberately. A phrase list that can refuse a review would refuse the
29
+ * false positives too, and the shape it is looking for is one sentence in a long prompt.
30
+ * Exit is always 0; the finding is the output.
31
+ */
32
+ import * as fs from 'node:fs';
33
+ import * as path from 'node:path';
34
+ import process from 'node:process';
35
+ import { fileURLToPath } from 'node:url';
36
+
37
+ import { reportScanned } from './_lib/scan_scope.js';
38
+
39
+ const _HERE = path.dirname(fileURLToPath(import.meta.url));
40
+ const REPO_ROOT = path.resolve(_HERE, '..', '..');
41
+ const REVIEWS_DIR = path.join('agents', 'evidence', 'reviews');
42
+
43
+ /**
44
+ * Phrases that state an expectation of the outcome.
45
+ *
46
+ * Each is a shape observed or narrowly derived from one, and the list is deliberately
47
+ * short: a long list of guesses produces false positives, and a warn nobody trusts is
48
+ * worse than no warn. The first entry is the measured one.
49
+ */
50
+ export const EXPECTATION_PHRASES: readonly RegExp[] = [
51
+ /no[- ]findings\s+(?:is|are)\s+(?:expected|welcome)/i,
52
+ /\bexpect(?:ing)?\s+(?:no|zero)\s+(?:findings|issues|problems)/i,
53
+ /\bshould\s+be\s+(?:clean|fine|correct|green)\b/i,
54
+ /\bi\s+believe\s+this\s+is\s+(?:correct|clean|right)\b/i,
55
+ /\bjust\s+confirm\b/i,
56
+ /\bplease\s+confirm\s+(?:that\s+)?(?:there\s+are\s+)?no\b/i,
57
+ /\bthis\s+(?:should|ought\s+to)\s+pass\b/i,
58
+ ];
59
+
60
+ export interface Finding {
61
+ readonly file: string;
62
+ readonly line: number;
63
+ readonly phrase: string;
64
+ readonly text: string;
65
+ }
66
+
67
+ /** Scan one prompt's text. Returns every match, not the first — a prompt can steer twice. */
68
+ export function scanPromptText(rel: string, text: string): Finding[] {
69
+ const out: Finding[] = [];
70
+ const lines = text.split('\n');
71
+ for (let i = 0; i < lines.length; i += 1) {
72
+ const line = lines[i]!;
73
+ for (const re of EXPECTATION_PHRASES) {
74
+ const m = re.exec(line);
75
+ if (m !== null) {
76
+ out.push({
77
+ file: rel,
78
+ line: i + 1,
79
+ phrase: m[0],
80
+ // Trimmed and capped: the finding names the sentence, and a prompt
81
+ // line can be very long.
82
+ text: line.trim().slice(0, 160),
83
+ });
84
+ }
85
+ }
86
+ }
87
+ return out;
88
+ }
89
+
90
+ /** Every `<slug>.review-input/prompt.md` under the reviews directory. */
91
+ export function collectPrompts(repoRoot: string): string[] {
92
+ const dir = path.join(repoRoot, REVIEWS_DIR);
93
+ if (!fs.existsSync(dir)) return [];
94
+ const out: string[] = [];
95
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) =>
96
+ a.name < b.name ? -1 : 1,
97
+ )) {
98
+ if (!entry.isDirectory() || !entry.name.endsWith('.review-input')) continue;
99
+ const p = path.join(dir, entry.name, 'prompt.md');
100
+ if (fs.existsSync(p)) out.push(p);
101
+ }
102
+ return out;
103
+ }
104
+
105
+ export function main(argv: readonly string[] = []): number {
106
+ const quiet = argv.includes('--quiet');
107
+ const rootIdx = argv.indexOf('--repo-root');
108
+ const repoRoot = rootIdx >= 0 ? (argv[rootIdx + 1] ?? REPO_ROOT) : REPO_ROOT;
109
+
110
+ const prompts = collectPrompts(repoRoot);
111
+ const findings: Finding[] = [];
112
+ for (const p of prompts) {
113
+ findings.push(...scanPromptText(path.relative(repoRoot, p), fs.readFileSync(p, 'utf-8')));
114
+ }
115
+
116
+ reportScanned({
117
+ gate: 'lint_judge_prompt_expectation',
118
+ scanned: prompts.length,
119
+ units: 'captured judge prompt(s)',
120
+ roots: [REVIEWS_DIR],
121
+ });
122
+
123
+ if (findings.length === 0) {
124
+ if (!quiet) {
125
+ process.stdout.write(
126
+ '✅ lint_judge_prompt_expectation: no captured prompt states an expectation ' +
127
+ 'of the outcome (phrase list only — a paraphrase is not caught).\n',
128
+ );
129
+ }
130
+ return 0;
131
+ }
132
+ process.stdout.write(
133
+ `⚠️ lint_judge_prompt_expectation: ${String(findings.length)} prompt line(s) state an ` +
134
+ 'expectation of the outcome. WARN ONLY — review them:\n',
135
+ );
136
+ for (const f of findings) {
137
+ process.stdout.write(` ${f.file}:${String(f.line)} — "${f.phrase}"\n ${f.text}\n`);
138
+ }
139
+ process.stdout.write(
140
+ '\n A prompt that says what the author thinks the answer is has authored the answer, ' +
141
+ 'whatever mood it used. See src/rules/evaluator-independence.md.\n',
142
+ );
143
+ // Always 0. See the header: a phrase list that can refuse would refuse its false
144
+ // positives too.
145
+ return 0;
146
+ }
147
+
148
+ function _isCliEntry(): boolean {
149
+ const invoked = process.argv[1];
150
+ return invoked !== undefined && path.resolve(invoked) === path.resolve(fileURLToPath(import.meta.url));
151
+ }
152
+
153
+ if (_isCliEntry()) {
154
+ process.exit(main(process.argv.slice(2)));
155
+ }
@@ -15,6 +15,8 @@
15
15
  * - owner must have name + email
16
16
  * - metadata must have description + version
17
17
  * - metadata.version must match package.json (single source of truth)
18
+ * - every version field in BOTH .augment-plugin/ manifests matches
19
+ * package.json too — see check_augment_manifests()
18
20
  * - the union of plugins[].skills[] must be EXACTLY the pointer skill
19
21
  * (./.claude-plugin/skills/install-agent-config) — a repopulated
20
22
  * content-skill list FAILS by design
@@ -88,6 +90,87 @@ function require_key(
88
90
  return true;
89
91
  }
90
92
 
93
+ /**
94
+ * Every version field in both `.augment-plugin/` manifests must equal
95
+ * `package.json`'s.
96
+ *
97
+ * WHY THE AUGMENT TWIN IS IN SCOPE OF THIS GATE. Both files ship in the npm
98
+ * tarball — `src/config/publish-surface.json` lists `.augment-plugin/` as a
99
+ * publish root — and both carried `version: 1.0.0` while `package.json` moved
100
+ * to 14.x. Nothing in the tree ever claimed `1.0.0` was an independent
101
+ * plugin-API version: no comment, no test, no doc, and the only reader anywhere
102
+ * is `src/scripts/probe_skill_registration.ts:137`. `plugin.json` had not been
103
+ * touched since 2026-04-17. An unclaimed constant no reader interprets is
104
+ * drift, not a deliberate independent version — so the Augment manifests are
105
+ * treated as the projection counterpart of the `.claude-plugin` twin this gate
106
+ * already version-syncs, and are held to the same rule.
107
+ *
108
+ * Reversible in one commit if that reading is ever wrong, which is why
109
+ * `docs/CLAIMS.md` records the choice rather than leaving it implicit.
110
+ *
111
+ * The nesting differs between the two files, so the fields are enumerated
112
+ * rather than discovered: a recursive "every key named version" walk would
113
+ * silently start policing a future field that is legitimately independent.
114
+ */
115
+ export function check_augment_manifests(
116
+ pkgVersion: string,
117
+ errors: string[],
118
+ base: string = ROOT,
119
+ ): void {
120
+ const targets: Array<[string, string[][]]> = [
121
+ [path.join(base, ".augment-plugin", "plugin.json"), [["version"]]],
122
+ [
123
+ path.join(base, ".augment-plugin", "marketplace.json"),
124
+ [["version"], ["metadata", "version"], ["plugins", "*", "version"]],
125
+ ],
126
+ ];
127
+ for (const [file, paths] of targets) {
128
+ if (!_exists(file)) {
129
+ errors.push(`${file} not found (listed in publish-surface.json roots)`);
130
+ continue;
131
+ }
132
+ let data: JsonValue;
133
+ try {
134
+ data = JSON.parse(fs.readFileSync(file, "utf-8")) as JsonValue;
135
+ } catch (e) {
136
+ errors.push(`${file} is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
137
+ continue;
138
+ }
139
+ for (const keys of paths) {
140
+ for (const [label, value] of _resolveVersionField(data, keys)) {
141
+ if (value !== pkgVersion) {
142
+ errors.push(
143
+ `${file}: ${label} \`${String(value)}\` does not match ` +
144
+ `package.json version \`${pkgVersion}\``,
145
+ );
146
+ }
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ /** Resolve a key path, expanding `*` over array indices. Returns [label, value]. */
153
+ function _resolveVersionField(
154
+ data: JsonValue,
155
+ keys: readonly string[],
156
+ prefix = "",
157
+ ): Array<[string, JsonValue | undefined]> {
158
+ if (keys.length === 0) {
159
+ return [[prefix.replace(/^\./, ""), data]];
160
+ }
161
+ const [head, ...rest] = keys as [string, ...string[]];
162
+ if (head === "*") {
163
+ if (!Array.isArray(data)) {
164
+ return [[`${prefix}[*]`.replace(/^\./, ""), undefined]];
165
+ }
166
+ return data.flatMap((item, i) => _resolveVersionField(item, rest, `${prefix}[${String(i)}]`));
167
+ }
168
+ if (!isObject(data)) {
169
+ return [[`${prefix}.${head}`.replace(/^\./, ""), undefined]];
170
+ }
171
+ return _resolveVersionField(data[head] ?? null, rest, `${prefix}.${head}`);
172
+ }
173
+
91
174
  export function main(): number {
92
175
  // No corpus to count — the shim is exactly one manifest plus one pointer
93
176
  // skill, and every count the shape offers (plugins, skill entries, dirs under
@@ -100,6 +183,8 @@ export function main(): number {
100
183
  gate: "lint_marketplace",
101
184
  candidates: [
102
185
  ".claude-plugin/marketplace.json",
186
+ ".augment-plugin/plugin.json",
187
+ ".augment-plugin/marketplace.json",
103
188
  "package.json",
104
189
  `${POINTER_SKILL_ENTRY.replace(/^\.\//, "")}/SKILL.md`,
105
190
  ],
@@ -161,6 +246,9 @@ export function main(): number {
161
246
  `package.json version \`${String(pkgVersion)}\``,
162
247
  );
163
248
  }
249
+ if (typeof pkgVersion === "string") {
250
+ check_augment_manifests(pkgVersion, errors);
251
+ }
164
252
  }
165
253
  } else {
166
254
  errors.push("`metadata` must be an object");
@@ -18,7 +18,13 @@
18
18
  * shallow and the referrer roots named the pre-ADR-051 container. Repaired
19
19
  * 2026-08-02; see the constants below.
20
20
  *
21
- * Exit codes: 0 all policies linked, 1 one or more orphan policies, 2 dead scope.
21
+ * SECOND PASS (skill-link-integrity Phase 3): adapter lifecycle parity. See
22
+ * {@link adapter_lifecycle_findings} — the nearest existing scope for a check
23
+ * `docs/contracts/provider-lifecycle.md` says in its own words that CI does not
24
+ * perform.
25
+ *
26
+ * Exit codes: 0 all policies linked and lifecycle tags agree, 1 one or more
27
+ * orphan policies or a lifecycle disagreement, 2 dead scope.
22
28
  */
23
29
 
24
30
  import * as fs from 'node:fs';
@@ -186,6 +192,110 @@ function referrers_for(policy: string, scanFiles: readonly string[]): string[] {
186
192
  return referrers;
187
193
  }
188
194
 
195
+ // ── Adapter lifecycle parity ────────────────────────────────────────────────
196
+ // `docs/contracts/provider-lifecycle.md:101` states the obligation and its own
197
+ // gap in one sentence: "Editing an adapter and leaving its header `Lifecycle:`
198
+ // comment out of sync with `agents/templates/.ai-video.xml.example` → violation
199
+ // (CI does not catch this; the agent must)." This pass makes CI catch it.
200
+ //
201
+ // EXPECTED GREEN ON LANDING, and that is the point rather than a weakness. The
202
+ // premise this was drafted against claimed a live contradiction between the
203
+ // higgsfield adapter header and the contract; re-reading the tree refuted it —
204
+ // the two surfaces the contract actually obliges to agree DO agree at `stable`,
205
+ // and the surface reading `experimental` is § 5, a table that says in its own
206
+ // words that it lists the tiers "on the day this contract lands". So there is
207
+ // nothing to repair today; the check exists so the next divergence is caught.
208
+ // Its sensitivity is proven by a fixture that must be red, not by a finding.
209
+ //
210
+ // § 5 IS DELIBERATELY NOT AN INPUT. A historical record must not be able to
211
+ // fail a live check — wiring it in would make the gate demand that a
212
+ // day-one table be edited, which would destroy the record it is.
213
+ //
214
+ // DRIVEN FROM THE ADAPTERS, NOT FROM THE XML. The example declares providers
215
+ // that have no adapter at all (`allin1`, `whisperx`) and one that is a
216
+ // documentation placeholder inside a commented example block
217
+ // (`my-future-backend`); iterating the xml would demand adapters for all three.
218
+ // The reverse direction is still covered: an adapter with no provider entry is
219
+ // reported, because a shipped adapter the example never declares is exactly the
220
+ // drift this pass is for.
221
+
222
+ /** `# Lifecycle: <tier>` from an adapter header. */
223
+ const ADAPTER_LIFECYCLE_RE = /^#\s*Lifecycle:\s*([a-z]+)/m;
224
+
225
+ /** Repo-relative adapter dir and the xml example the contract pairs it with. */
226
+ const ADAPTER_DIR = path.join(REPO, 'src', 'scripts', 'ai-video', 'adapters');
227
+ const AI_VIDEO_EXAMPLE = path.join(REPO, 'agents', 'templates', '.ai-video.xml.example');
228
+
229
+ /** `<provider id="x" …> … <lifecycle>tier</lifecycle>` pairs, xml order. */
230
+ export function parse_example_lifecycles(xml: string): Map<string, string> {
231
+ const out = new Map<string, string>();
232
+ const re = /<provider\s+id="([^"]+)"[^>]*>([\s\S]*?)<\/provider>/g;
233
+ let m: RegExpExecArray | null;
234
+ while ((m = re.exec(xml)) !== null) {
235
+ const tier = /<lifecycle>\s*([a-z]+)\s*<\/lifecycle>/.exec(m[2] as string);
236
+ // First declaration wins: the example's commented "how to add one"
237
+ // block repeats an id shape, and a later placeholder must not overwrite
238
+ // a real entry.
239
+ if (tier && !out.has(m[1] as string)) {
240
+ out.set(m[1] as string, tier[1] as string);
241
+ }
242
+ }
243
+ return out;
244
+ }
245
+
246
+ /** Findings for adapter-vs-example lifecycle disagreement. `[]` = parity holds. */
247
+ export function adapter_lifecycle_findings(
248
+ adapterDir: string = ADAPTER_DIR,
249
+ examplePath: string = AI_VIDEO_EXAMPLE,
250
+ ): string[] {
251
+ const findings: string[] = [];
252
+ let xml: string;
253
+ try {
254
+ xml = fs.readFileSync(examplePath, 'utf-8');
255
+ } catch {
256
+ return [`${_relToPosix(examplePath, REPO)} is unreadable — lifecycle parity cannot be checked`];
257
+ }
258
+ const declared = parse_example_lifecycles(xml);
259
+ let entries: string[];
260
+ try {
261
+ entries = fs.readdirSync(adapterDir).filter((f) => f.endsWith('.sh')).sort();
262
+ } catch {
263
+ return [`${_relToPosix(adapterDir, REPO)} is unreadable — lifecycle parity cannot be checked`];
264
+ }
265
+ for (const file of entries) {
266
+ const id = file.replace(/\.sh$/, '');
267
+ const header = ADAPTER_LIFECYCLE_RE.exec(fs.readFileSync(path.join(adapterDir, file), 'utf-8'));
268
+ if (header === null) {
269
+ findings.push(`adapters/${file}: no \`# Lifecycle:\` header comment`);
270
+ continue;
271
+ }
272
+ const inXml = declared.get(id);
273
+ if (inXml === undefined) {
274
+ findings.push(
275
+ `adapters/${file}: header says \`${header[1] as string}\` but no ` +
276
+ `<provider id="${id}"> exists in ${_relToPosix(examplePath, REPO)}`,
277
+ );
278
+ continue;
279
+ }
280
+ if (inXml !== header[1]) {
281
+ findings.push(
282
+ `adapters/${file}: header \`${header[1] as string}\` != ` +
283
+ `<provider id="${id}"><lifecycle>${inXml}</lifecycle>`,
284
+ );
285
+ }
286
+ }
287
+ return findings;
288
+ }
289
+
290
+ /** Adapter count, for the dead-scope assertion. */
291
+ export function count_adapters(adapterDir: string = ADAPTER_DIR): number {
292
+ try {
293
+ return fs.readdirSync(adapterDir).filter((f) => f.endsWith('.sh')).length;
294
+ } catch {
295
+ return 0;
296
+ }
297
+ }
298
+
189
299
  function main(): number {
190
300
  // Scope assertions replace the two silent early returns this gate used to
191
301
  // take. Both are deliberately WITHOUT `allowEmpty`: "the policy directory
@@ -207,6 +317,13 @@ function main(): number {
207
317
  units: 'referrer-candidate file(s)',
208
318
  roots: SCAN_ROOTS.map((r) => _relToPosix(r, REPO)),
209
319
  });
320
+ // Zero adapters means the adapter root moved, not that parity holds.
321
+ assertScanned({
322
+ gate: 'lint_media_policy_linkage',
323
+ scanned: count_adapters(),
324
+ units: 'ai-video adapter(s)',
325
+ roots: [_relToPosix(ADAPTER_DIR, REPO)],
326
+ });
210
327
  } catch (exc) {
211
328
  if (!(exc instanceof DeadScopeError)) {
212
329
  throw exc;
@@ -227,6 +344,11 @@ function main(): number {
227
344
  emit(`✅ ${rel} (${referrers.length} referrer(s))`);
228
345
  }
229
346
 
347
+ const lifecycle = adapter_lifecycle_findings();
348
+ for (const f of lifecycle) {
349
+ emit(`❌ LIFECYCLE ${f}`);
350
+ }
351
+
230
352
  if (orphans.length > 0) {
231
353
  process.stderr.write(
232
354
  `\nmedia-policy-linkage: ${orphans.length} orphan policy ` +
@@ -239,10 +361,27 @@ function main(): number {
239
361
  return 1;
240
362
  }
241
363
 
364
+ if (lifecycle.length > 0) {
365
+ process.stderr.write(
366
+ `\nadapter-lifecycle-parity: ${lifecycle.length} disagreement(s) ` +
367
+ `between an adapter header and agents/templates/.ai-video.xml.example. ` +
368
+ `The day-one table in docs/contracts/provider-lifecycle.md § 5 is NOT ` +
369
+ `an input here — it is a historical record.\n`,
370
+ );
371
+ for (const f of lifecycle) {
372
+ process.stderr.write(` - ${f}\n`);
373
+ }
374
+ return 1;
375
+ }
376
+
242
377
  emit(
243
378
  `media-policy-linkage: ${policies.length} policy file(s) — all ` +
244
379
  `linked (${scanFiles.length} file(s) scanned for referrers).`,
245
380
  );
381
+ emit(
382
+ `adapter-lifecycle-parity: ${count_adapters()} adapter(s) — every ` +
383
+ `\`# Lifecycle:\` header agrees with its <provider> entry.`,
384
+ );
246
385
  return 0;
247
386
  }
248
387
 
@@ -28,6 +28,7 @@ import * as fs from 'node:fs';
28
28
  import * as path from 'node:path';
29
29
  import { fileURLToPath, pathToFileURL } from 'node:url';
30
30
 
31
+ import { asOf, asOfBanner } from './_lib/as_of.js';
31
32
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
32
33
 
33
34
  const _HERE = fileURLToPath(import.meta.url);
@@ -59,7 +60,7 @@ interface SimpleDate {
59
60
  }
60
61
 
61
62
  function _today_utc(): SimpleDate {
62
- const now = new Date();
63
+ const now = asOf();
63
64
  return {
64
65
  y: now.getUTCFullYear(),
65
66
  m: now.getUTCMonth() + 1,
@@ -369,6 +370,10 @@ export function main(): number {
369
370
  }));
370
371
  process.stdout.write(JSON.stringify(payload, null, 2) + '\n');
371
372
  } else {
373
+ // Text only: the JSON payload is consumed by tooling and must stay a
374
+ // bare array. A reviewer reading the text report needs to know which
375
+ // "now" produced these ages — see `_lib/as_of.ts`.
376
+ process.stdout.write(`${asOfBanner()}\n`);
372
377
  process.stdout.write(format_text(findings) + '\n');
373
378
  }
374
379
  return findings.some((f) => f.severity === 'fail') ? 1 : 0;
@@ -184,21 +184,32 @@ export function classify_violations(input: {
184
184
  return violations;
185
185
  }
186
186
 
187
- export function audit(): OverrideRow[] {
188
- if (!fs.existsSync(OVERRIDES_RULES)) return [];
187
+ /**
188
+ * @param overridesDir Directory of override files to audit. Defaults to the real
189
+ * `agents/overrides/rules/`; a caller passes a fixture directory so the
190
+ * reachability of the audit itself can be tested against a KNOWN pair rather
191
+ * than against whatever the tree happens to contain. Added by step 1.2 of
192
+ * `road-to-override-efficacy-proof`: with the path hardcoded, a test could only
193
+ * assert against the one real override, so a regression that stopped
194
+ * discovering files would still read clean on an empty directory.
195
+ *
196
+ * Additive, with a default, so no existing caller changes.
197
+ */
198
+ export function audit(overridesDir: string = OVERRIDES_RULES): OverrideRow[] {
199
+ if (!fs.existsSync(overridesDir)) return [];
189
200
  const floor = safety_floor_ids(RULES_DIR);
190
201
  const registered = fs.existsSync(REGISTRY)
191
202
  ? registered_rules(fs.readFileSync(REGISTRY, 'utf-8'))
192
203
  : new Set<string>();
193
204
 
194
205
  const rows: OverrideRow[] = [];
195
- for (const name of fs.readdirSync(OVERRIDES_RULES).sort()) {
206
+ for (const name of fs.readdirSync(overridesDir).sort()) {
196
207
  if (!name.endsWith('.md')) continue;
197
208
  const rule = name.replace(/\.md$/, '');
198
209
  const kernel = is_kernel_rule(rule);
199
210
  const is_floor = floor.has(rule);
200
211
 
201
- const text = fs.readFileSync(path.join(OVERRIDES_RULES, name), 'utf-8');
212
+ const text = fs.readFileSync(path.join(overridesDir, name), 'utf-8');
202
213
  const mode = parse_mode(text);
203
214
  const cited = has_citation(text);
204
215
  const is_registered = registered.has(rule);
@@ -206,7 +217,7 @@ export function audit(): OverrideRow[] {
206
217
 
207
218
  rows.push({
208
219
  rule,
209
- file: path.relative(REPO_ROOT, path.join(OVERRIDES_RULES, name)),
220
+ file: path.relative(REPO_ROOT, path.join(overridesDir, name)),
210
221
  mode,
211
222
  kernel,
212
223
  safety_floor: is_floor,
@@ -218,9 +229,65 @@ export function audit(): OverrideRow[] {
218
229
  return rows;
219
230
  }
220
231
 
232
+ /**
233
+ * Render the precedence table — step 1.4 of `road-to-override-efficacy-proof`.
234
+ *
235
+ * The audit's answer already existed as JSON nobody runs. This is the same answer
236
+ * in a form a reviewer reads, and it is GENERATED rather than written: regenerating
237
+ * it on an unchanged tree must produce no diff, so the table is a fact about the
238
+ * tree rather than a snapshot of when someone last looked.
239
+ *
240
+ * Rows are sorted by `rule` (the audit already reads its directory sorted), and no
241
+ * timestamp is emitted. A generated file carrying "last updated" changes on every
242
+ * run and makes `git diff --exit-code` useless as a freshness check — the check the
243
+ * step's verify actually performs.
244
+ */
245
+ export function render_precedence_table(rows: readonly OverrideRow[]): string {
246
+ const L: string[] = [];
247
+ L.push('<!-- evidence-type: analysis -->');
248
+ L.push('');
249
+ L.push('<!-- GENERATED by `lint_override_kernel_guard --write-table`. Do not hand-edit. -->');
250
+ L.push('');
251
+ L.push('# Override precedence table');
252
+ L.push('');
253
+ L.push(
254
+ 'Every override in the tree, with the rule it overrides and its audit state. ' +
255
+ 'Generated from the same `audit()` the strict gate runs, so the table and the ' +
256
+ 'gate cannot disagree.',
257
+ );
258
+ L.push('');
259
+ L.push(
260
+ '**This is a DELIVERY table, not an efficacy claim.** It says an override file ' +
261
+ 'is discovered, resolves to a rule, and carries its citation. Whether the agent ' +
262
+ 'then behaves differently is a separate question, and it is measured nowhere in ' +
263
+ 'this table — see `road-to-override-efficacy-proof` Phase 2, deferred on ' +
264
+ 'population validity.',
265
+ );
266
+ L.push('');
267
+ if (rows.length === 0) {
268
+ L.push('No override files are present. That is a real and common state, not a fault.');
269
+ L.push('');
270
+ return L.join('\n');
271
+ }
272
+ L.push('| rule | mode | kernel | safety floor | registered | cited | violations |');
273
+ L.push('|---|---|---|---|---|---|---|');
274
+ for (const r of rows) {
275
+ L.push(
276
+ `| \`${r.rule}\` | \`${r.mode}\` | ${r.kernel ? 'yes' : 'no'} | ` +
277
+ `${r.safety_floor ? 'yes' : 'no'} | ${r.registered ? 'yes' : 'no'} | ` +
278
+ `${r.cited ? 'yes' : 'no'} | ${r.violations.length === 0 ? '—' : r.violations.join('; ')} |`,
279
+ );
280
+ }
281
+ L.push('');
282
+ L.push(`${String(rows.length)} override(s).`);
283
+ L.push('');
284
+ return L.join('\n');
285
+ }
286
+
221
287
  function main(argv: string[]): number {
222
288
  const as_json = argv.includes('--json');
223
289
  const strict = argv.includes('--strict');
290
+ const tableIdx = argv.indexOf('--write-table');
224
291
 
225
292
  // Not the override corpus: an empty `agents/overrides/rules/` is a real and
226
293
  // common state (the report says so in words). The scope that cannot be
@@ -252,6 +319,21 @@ function main(argv: string[]): number {
252
319
 
253
320
  const rows = audit();
254
321
 
322
+ if (tableIdx >= 0) {
323
+ const rel = argv[tableIdx + 1];
324
+ if (rel === undefined || rel.startsWith('--')) {
325
+ process.stderr.write('--write-table needs a path\n');
326
+ return 2;
327
+ }
328
+ const out = path.join(REPO_ROOT, rel);
329
+ fs.mkdirSync(path.dirname(out), { recursive: true });
330
+ fs.writeFileSync(out, render_precedence_table(rows), 'utf-8');
331
+ process.stdout.write(
332
+ `override precedence table: ${String(rows.length)} row(s) → ${rel}\n`,
333
+ );
334
+ return 0;
335
+ }
336
+
255
337
  if (as_json) {
256
338
  process.stdout.write(JSON.stringify({ overrides: rows }, null, 2) + '\n');
257
339
  return 0;