@event4u/agent-config 16.1.0 → 16.3.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 (467) 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 +98 -257
  5. package/README.md +14 -12
  6. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  7. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  8. package/dist/agent-src/commands/bug/fix.md +17 -2
  9. package/dist/agent-src/commands/feature/plan.md +1 -1
  10. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  11. package/dist/agent-src/commands/fix/ci.md +1 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/jira-ticket.md +1 -1
  14. package/dist/agent-src/commands/roadmap/create.md +1 -1
  15. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  16. package/dist/agent-src/commands/roadmap/process-full.md +5 -5
  17. package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
  18. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  19. package/dist/agent-src/commands/roadmap.md +18 -4
  20. package/dist/agent-src/commands/tests/create.md +17 -3
  21. package/dist/agent-src/commands/tests/execute.md +22 -5
  22. package/dist/agent-src/commands/work.md +4 -0
  23. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  25. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
  27. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  28. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  29. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  30. package/dist/agent-src/rules/active-remediation.md +1 -1
  31. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  32. package/dist/agent-src/rules/broken-access-control.md +1 -0
  33. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  34. package/dist/agent-src/rules/context-hygiene.md +1 -1
  35. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  36. package/dist/agent-src/rules/design-fidelity.md +13 -16
  37. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  39. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  40. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  41. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  42. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  43. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  44. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  45. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  46. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  47. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  48. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  49. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  50. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  51. package/dist/agent-src/rules/persona-governance.md +2 -2
  52. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  53. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  54. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  55. package/dist/agent-src/rules/runtime-safety.md +1 -0
  56. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  57. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  58. package/dist/agent-src/rules/session-canary.md +8 -62
  59. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  60. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  61. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  62. package/dist/agent-src/rules/tool-safety.md +1 -0
  63. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  64. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  65. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  66. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  67. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  68. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  69. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  70. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
  71. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  72. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  73. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  74. package/dist/agent-src/skills/design-review/SKILL.md +30 -4
  75. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  76. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
  78. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  79. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  80. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  81. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  82. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  83. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  84. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  85. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  86. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  87. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  88. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  89. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  90. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  91. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  92. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  93. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  94. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  95. package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
  96. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/dist/agent-src/templates/roadmaps.md +30 -0
  98. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  99. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  100. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  101. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  102. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  103. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  104. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  105. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  106. package/dist/cli/python/knowledge_ingest.js +1 -1
  107. package/dist/cli/python/workspace_drive.js +1 -1
  108. package/dist/cli/registry.js +1 -1
  109. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  110. package/dist/cli-delegate/check_update_banner.js +12 -1
  111. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  112. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  113. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  114. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  115. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  116. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  117. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  118. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  119. package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
  120. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  121. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  122. package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
  123. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  124. package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
  125. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  126. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  127. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  128. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  129. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  130. package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
  131. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
  132. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  133. package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
  134. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  135. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  136. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  137. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  138. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  139. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  140. package/dist/cli-delegate/cmd_conformance.js +1862 -809
  141. package/dist/cli-delegate/cmd_doctor.js +13 -6
  142. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  143. package/dist/cli-delegate/cmd_explain.js +5 -5
  144. package/dist/cli-delegate/cmd_export.js +11 -8
  145. package/dist/cli-delegate/cmd_fleet.js +3 -3
  146. package/dist/cli-delegate/cmd_handoff.js +10 -7
  147. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  148. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  149. package/dist/cli-delegate/cmd_migrate.js +2 -2
  150. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  151. package/dist/cli-delegate/cmd_preflight.js +6 -6
  152. package/dist/cli-delegate/cmd_prune.js +11 -8
  153. package/dist/cli-delegate/cmd_refresh.js +2 -1
  154. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  155. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  156. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  157. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  158. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  159. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  160. package/dist/cli-delegate/cmd_sync.js +11 -8
  161. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  162. package/dist/cli-delegate/cmd_update.js +1 -1
  163. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  164. package/dist/cli-delegate/cmd_validate.js +11 -8
  165. package/dist/cli-delegate/cmd_versions.js +1 -1
  166. package/dist/cli-delegate/deferral_carry.js +16 -0
  167. package/dist/cli-delegate/gate_execute.js +2 -2
  168. package/dist/cli-delegate/roadmap_gates.js +5 -5
  169. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  170. package/dist/discovery/deprecation-report.md +1 -1
  171. package/dist/discovery/discovery-manifest.json +132 -80
  172. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  173. package/dist/discovery/discovery-manifest.summary.md +3 -3
  174. package/dist/discovery/dormancy-report.md +1 -1
  175. package/dist/discovery/orphan-report.md +1 -1
  176. package/dist/discovery/packs.json +7 -5
  177. package/dist/discovery/trust-report.md +2 -2
  178. package/dist/discovery/workspaces.json +6 -4
  179. package/dist/hooks/dispatch.js +7972 -5186
  180. package/dist/hooks/dispatch.sha256 +1 -0
  181. package/dist/install/claudePathsPlan.js +47 -6
  182. package/dist/install/claudeRuleRewrite.js +7 -0
  183. package/dist/install/emit_host_rules_cli.js +39 -36
  184. package/dist/install/globalRuleScope.js +87 -0
  185. package/dist/install/host_rule_ownership.js +160 -0
  186. package/dist/install/install.mjs +2226 -1055
  187. package/dist/install/installThinLayer.js +261 -0
  188. package/dist/install/installedRuleLinks.js +176 -0
  189. package/dist/install/wizard-plan.js +24 -0
  190. package/dist/mcp/registry-manifest.json +3 -3
  191. package/dist/mcp/server.json +2 -2
  192. package/dist/mcp/server.mjs +40913 -34865
  193. package/dist/scripts/_lib/agent_settings.js +11 -0
  194. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  195. package/dist/scripts/_lib/installed_layer.js +378 -0
  196. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  197. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  198. package/dist/scripts/_lib/rule_injection.js +67 -10
  199. package/dist/scripts/_lib/rule_law_section.js +122 -0
  200. package/dist/scripts/_lib/thin_rules.js +458 -0
  201. package/dist/scripts/_lib/windsurf_render.js +60 -0
  202. package/dist/scripts/condense.js +14 -26
  203. package/dist/scripts/project_thin_rules.js +14 -294
  204. package/dist/server/schemas/settings.js +29 -0
  205. package/dist/shared/skillRanking.js +74 -13
  206. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  207. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  208. package/dist/ui/index.html +2 -2
  209. package/docs/contracts/settings-classes.md +10 -6
  210. package/package.json +4 -4
  211. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  212. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  213. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  214. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  215. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  216. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  217. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  218. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  219. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  220. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  221. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  222. package/src/config/agent-settings.template.yml +91 -22
  223. package/src/config/ci-local-parity.yml +18 -0
  224. package/src/config/continuity-surface.json +9 -2
  225. package/src/config/evaluator-budgets.json +4 -4
  226. package/src/config/gate-coverage.yml +327 -3
  227. package/src/config/gate-violation-baselines.json +21 -9
  228. package/src/config/hook-bundle-budget.json +25 -0
  229. package/src/config/hook-latency-budget.json +21 -0
  230. package/src/config/hook-token-budget.json +8 -3
  231. package/src/config/host-instruction-limits.json +33 -0
  232. package/src/config/metric-registry.yml +114 -0
  233. package/src/config/placeholder-drift-budget.json +10 -0
  234. package/src/config/routing-coverage-seed.json +38 -3
  235. package/src/config/rule-activation-census.json +7 -3
  236. package/src/config/rule-consequence-class.json +161 -0
  237. package/src/config/rule-law-ceilings.json +99 -0
  238. package/src/install/claudePathsPlan.ts +46 -4
  239. package/src/install/claudeRuleRewrite.ts +10 -1
  240. package/src/install/emit_host_rules_cli.ts +43 -34
  241. package/src/install/globalRuleScope.ts +109 -0
  242. package/src/install/host_rule_ownership.ts +170 -0
  243. package/src/install/installThinLayer.ts +312 -0
  244. package/src/install/installedRuleLinks.ts +220 -0
  245. package/src/install/wizard-plan.ts +24 -0
  246. package/src/scripts/_cli/cmd_doctor.ts +28 -90
  247. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  248. package/src/scripts/_cli/doctor_execution.ts +100 -17
  249. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  250. package/src/scripts/_dispatch.bash +16 -2
  251. package/src/scripts/_lib/agent_settings.ts +11 -0
  252. package/src/scripts/_lib/body_portable.ts +102 -0
  253. package/src/scripts/_lib/cc_transcript.ts +132 -1
  254. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  255. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  256. package/src/scripts/_lib/estate_offsets.ts +241 -0
  257. package/src/scripts/_lib/exemption_shape.ts +143 -0
  258. package/src/scripts/_lib/fnv.ts +23 -0
  259. package/src/scripts/_lib/foreign_scan.ts +106 -0
  260. package/src/scripts/_lib/forge_protection.ts +114 -0
  261. package/src/scripts/_lib/forge_reader.ts +558 -0
  262. package/src/scripts/_lib/gitignore_block.ts +314 -0
  263. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  264. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  265. package/src/scripts/_lib/hook_settings.ts +73 -0
  266. package/src/scripts/_lib/host_capability.ts +40 -19
  267. package/src/scripts/_lib/host_env_write.ts +111 -0
  268. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  269. package/src/scripts/_lib/installed_layer.ts +538 -0
  270. package/src/scripts/_lib/json_merge.ts +82 -0
  271. package/src/scripts/_lib/json_pointers.ts +93 -11
  272. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  273. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  274. package/src/scripts/_lib/machine_wake.ts +16 -3
  275. package/src/scripts/_lib/neighbour_census.ts +760 -0
  276. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  277. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  278. package/src/scripts/_lib/obligations.ts +119 -8
  279. package/src/scripts/_lib/probe_inputs.ts +271 -0
  280. package/src/scripts/_lib/prompt_shape.ts +46 -0
  281. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  282. package/src/scripts/_lib/release_highlights.ts +2 -1
  283. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  284. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  285. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  286. package/src/scripts/_lib/review_coverage.ts +134 -0
  287. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  288. package/src/scripts/_lib/rule_injection.ts +130 -10
  289. package/src/scripts/_lib/rule_law_section.ts +147 -0
  290. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  291. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  292. package/src/scripts/_lib/skill_origin.ts +254 -0
  293. package/src/scripts/_lib/structural_hiding.ts +622 -0
  294. package/src/scripts/_lib/structured_ask.ts +64 -21
  295. package/src/scripts/_lib/thin_rules.ts +540 -0
  296. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  297. package/src/scripts/_lib/turn_end_refusals.ts +600 -4
  298. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  299. package/src/scripts/_lib/verification_command.ts +324 -0
  300. package/src/scripts/_lib/verification_evidence.ts +647 -0
  301. package/src/scripts/_lib/verify_clause.ts +280 -0
  302. package/src/scripts/_lib/windsurf_render.ts +63 -0
  303. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  304. package/src/scripts/ai_council/clients.ts +26 -57
  305. package/src/scripts/ai_council/config.ts +1 -1
  306. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  307. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  308. package/src/scripts/audit_skill_overlap.ts +261 -0
  309. package/src/scripts/before_complete_hook.ts +573 -25
  310. package/src/scripts/bench_hook_latency.ts +412 -5
  311. package/src/scripts/bench_touched_file_quality.ts +238 -0
  312. package/src/scripts/cache_realization_report.ts +61 -1
  313. package/src/scripts/check_argument_hint.ts +287 -0
  314. package/src/scripts/check_claims.ts +125 -1
  315. package/src/scripts/check_enforcement_coverage.ts +38 -9
  316. package/src/scripts/check_enforcement_matrix.ts +621 -22
  317. package/src/scripts/check_estate_count.ts +130 -153
  318. package/src/scripts/check_finding_dispositions.ts +138 -7
  319. package/src/scripts/check_generator_sync.ts +71 -0
  320. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  321. package/src/scripts/check_host_docs_digest.ts +786 -0
  322. package/src/scripts/check_host_format_column.ts +559 -0
  323. package/src/scripts/check_input_references.ts +228 -0
  324. package/src/scripts/check_inputs_parity.ts +235 -0
  325. package/src/scripts/check_kernel_edit_ratified.ts +89 -9
  326. package/src/scripts/check_kill_switch_table.ts +294 -0
  327. package/src/scripts/check_memory.ts +7 -1
  328. package/src/scripts/check_placeholder_drift.ts +221 -0
  329. package/src/scripts/check_read_surface_coverage.ts +515 -0
  330. package/src/scripts/check_release_highlights.ts +10 -0
  331. package/src/scripts/check_release_holds.ts +2 -1
  332. package/src/scripts/check_release_pr_shape.ts +38 -15
  333. package/src/scripts/check_routing_coverage.ts +378 -11
  334. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  335. package/src/scripts/check_static_parity.ts +17 -0
  336. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  337. package/src/scripts/ci_settle.ts +145 -19
  338. package/src/scripts/closure_scan.ts +115 -1
  339. package/src/scripts/code_graph/detect.ts +127 -7
  340. package/src/scripts/code_graph/foreign.ts +194 -0
  341. package/src/scripts/code_graph/query.ts +217 -4
  342. package/src/scripts/code_graph/types.ts +26 -2
  343. package/src/scripts/code_graph/validate.ts +3 -1
  344. package/src/scripts/code_graph/verbs.ts +103 -0
  345. package/src/scripts/compile_hook_manifest.ts +90 -14
  346. package/src/scripts/condense.ts +14 -27
  347. package/src/scripts/estate_exemption_shape.ts +202 -0
  348. package/src/scripts/external_sources_denylist.json +29 -4
  349. package/src/scripts/generate_host_cost_table.ts +1 -1
  350. package/src/scripts/hook_manifest.json +1 -1
  351. package/src/scripts/hook_manifest.yaml +192 -14
  352. package/src/scripts/hooks/block_config_weakening.ts +294 -4
  353. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  354. package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
  355. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  356. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  357. package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
  358. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  359. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  360. package/src/scripts/hooks/concern_registry.ts +2 -0
  361. package/src/scripts/hooks/concern_timings.ts +94 -0
  362. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  363. package/src/scripts/hooks/design_pass_hook.ts +100 -9
  364. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  365. package/src/scripts/hooks/dispatch_hook.ts +77 -71
  366. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  367. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  368. package/src/scripts/hooks/evidence_independence.ts +1 -2
  369. package/src/scripts/hooks/exit_codes.ts +129 -0
  370. package/src/scripts/hooks/host_lowering.json +1 -0
  371. package/src/scripts/hooks/host_lowering.ts +146 -3
  372. package/src/scripts/hooks/host_lowering.yaml +262 -46
  373. package/src/scripts/hooks/host_semantics.ts +30 -2
  374. package/src/scripts/hooks/injection_budget.ts +9 -2
  375. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  376. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  377. package/src/scripts/hooks/memory_recall_hook.ts +1 -2
  378. package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
  379. package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
  380. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  381. package/src/scripts/hooks/payload_stub.ts +10 -1
  382. package/src/scripts/hooks/permission_gate.ts +1 -2
  383. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  384. package/src/scripts/hooks/replay_hook.ts +2 -1
  385. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  386. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  387. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  388. package/src/scripts/hooks/rule_inject_hook.ts +765 -68
  389. package/src/scripts/hooks/run_continuation_hook.ts +13 -15
  390. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  391. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  392. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  393. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  394. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  395. package/src/scripts/hooks/table_fingerprint.ts +70 -0
  396. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  397. package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
  398. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  399. package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
  400. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  401. package/src/scripts/hooks_status.ts +112 -0
  402. package/src/scripts/injection_scan_hook.ts +7 -0
  403. package/src/scripts/install.ts +75 -189
  404. package/src/scripts/installed_layer_report.ts +103 -0
  405. package/src/scripts/language_mirror_hook.ts +15 -6
  406. package/src/scripts/learning_sidecar.ts +119 -8
  407. package/src/scripts/lint_deny_text.ts +419 -0
  408. package/src/scripts/lint_exit_codes.ts +262 -0
  409. package/src/scripts/lint_hook_manifest.ts +108 -0
  410. package/src/scripts/lint_major_migration_sections.ts +156 -26
  411. package/src/scripts/lint_pack_boundaries.ts +63 -5
  412. package/src/scripts/lint_roadmap_blockers.ts +78 -12
  413. package/src/scripts/lint_rule_law_section.ts +517 -0
  414. package/src/scripts/lint_skill_descriptions.ts +1 -1
  415. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  416. package/src/scripts/lint_workflow_security.ts +161 -5
  417. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  418. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  419. package/src/scripts/mcp_server/prompts.ts +142 -1
  420. package/src/scripts/measure_routing_signal.ts +54 -16
  421. package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
  422. package/src/scripts/measure_turn_end_gate.ts +193 -0
  423. package/src/scripts/memory_learn_hook.ts +91 -6
  424. package/src/scripts/memory_lookup.ts +1 -1
  425. package/src/scripts/model_rule_injection.ts +52 -5
  426. package/src/scripts/prepack-check.mjs +53 -0
  427. package/src/scripts/project_thin_rules.ts +34 -327
  428. package/src/scripts/release_publication.ts +13 -1
  429. package/src/scripts/report_evidence_temperature.ts +657 -0
  430. package/src/scripts/report_installed_rule_links.ts +157 -0
  431. package/src/scripts/report_invocation_surface.ts +383 -0
  432. package/src/scripts/report_label_agreement.ts +233 -0
  433. package/src/scripts/report_obligation_carriers.ts +699 -0
  434. package/src/scripts/report_obligation_mechanism.ts +230 -0
  435. package/src/scripts/report_obligation_writer_split.ts +236 -0
  436. package/src/scripts/report_single_token_triggers.ts +277 -0
  437. package/src/scripts/report_skill_menu_census.ts +208 -0
  438. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  439. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  440. package/src/scripts/report_verification_record_coverage.ts +306 -0
  441. package/src/scripts/roadmap_verify_share.ts +213 -0
  442. package/src/scripts/rule_activation_census.ts +5 -2
  443. package/src/scripts/rule_trigger_eval.ts +9 -9
  444. package/src/scripts/schemas/command.schema.json +44 -0
  445. package/src/scripts/schemas/review-findings.schema.json +7 -2
  446. package/src/scripts/schemas/rule.schema.json +5 -0
  447. package/src/scripts/schemas/skill.schema.json +44 -0
  448. package/src/scripts/self_review_gate.ts +421 -17
  449. package/src/scripts/semantic_parity_census.ts +314 -0
  450. package/src/scripts/session_eol_report.ts +54 -1
  451. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  452. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  453. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  454. package/src/scripts/sync_gitignore.ts +29 -235
  455. package/src/scripts/trigger_eval_grandfather.json +0 -7
  456. package/src/scripts/trigger_eval_rotation.ts +122 -27
  457. package/src/scripts/ui_conformance_probe.ts +156 -4
  458. package/src/scripts/update_prices.ts +85 -3
  459. package/src/scripts/write_bundle_digest.mjs +74 -0
  460. package/src/server/schemas/settings.ts +41 -0
  461. package/src/shared/skillRanking.ts +117 -11
  462. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  463. package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
  464. package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
  465. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  466. package/dist/ui/assets/index-DH1xc62v.js +0 -29
  467. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
@@ -0,0 +1,559 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * check_host_format_column.ts — the compile-time (format) column of
4
+ * `docs/enforcement-by-host.md`'s host table may only name paths an emitter in
5
+ * this tree actually writes.
6
+ *
7
+ * WHY THIS EXISTS
8
+ * ---------------
9
+ * The Cursor cell read `.cursorrules` from the day the table was written until
10
+ * 2026-09-29. Nothing in this tree has ever written that file: the projection
11
+ * maps `.cursor/rules` (`condense.ts` `TOOL_DIRS`) and the install-time emitter
12
+ * writes `.cursor/rules/<name>.mdc` (`src/install/emit_host_rules_cli.ts`
13
+ * `emitCursor`). The cell was hand-maintained, nothing compared it to an
14
+ * emitter, and an external reader found it before any check did.
15
+ *
16
+ * A hand-maintained cell describing generated output is the defect. Correcting
17
+ * the cell once fixes today; this gate is what makes the NEXT drift a failing
18
+ * check rather than a reader's discovery.
19
+ *
20
+ * WHAT IT PROVES, AND WHAT IT DOES NOT
21
+ * ------------------------------------
22
+ * It proves every path the format column names is a path some emitter in this
23
+ * tree produces. It does NOT prove the converse — a host whose surface this
24
+ * package writes but whose cell omits it is not a finding here, because the
25
+ * cell is prose describing a host's native format and is allowed to name one
26
+ * representative surface rather than enumerate all of them. Nor does it say
27
+ * anything about whether a host READS what is written; that is a fact about the
28
+ * host and no gate in this repository can reach it.
29
+ *
30
+ * THE ORACLE — MEASURED FIRST, DECLARED SECOND, NEVER SCRAPED
31
+ * -----------------------------------------------------------
32
+ * The risk with a check like this is the inverse failure: it reds on a cell
33
+ * that is correct, gets disabled, and the column goes back to being
34
+ * hand-maintained — which is what produced the Cursor error in the first place.
35
+ * Scraping literal strings out of an emitter's source is how that happens,
36
+ * because targets built by interpolation never appear as literals. So the
37
+ * emitted set is built two ways and neither reads the emitters' text:
38
+ *
39
+ * 1. MEASURED. {@link measuredEmitterSurfaces} RUNS the two install-time rule
40
+ * emitters against a throwaway rules directory and walks what they left on
41
+ * disk. Interpolated or not, a path only enters the set if an emitter
42
+ * actually wrote it. This is the strongest half and it covers the two rows
43
+ * the original defect touched.
44
+ * 2. DECLARED. {@link declaredRoots} and {@link anchorDirs} import two
45
+ * registries the projection generators and the installer are already bound
46
+ * to — `ADAPTER_REGISTRY` (kept in step with the README matrix and with
47
+ * `GENERATOR_OUTPUT_ROOTS` by `lint_supported_tools_matrix`) and
48
+ * `USER_SCOPE_PATHS`. These cover the surfaces whose generators need a
49
+ * whole repository to run and so cannot be executed from inside a gate.
50
+ * The two are NOT interchangeable and the split is load-bearing: a
51
+ * declared root is a directory an emitter writes into, so a cell may
52
+ * refine it; an anchor is a whole tool's home and is matched exactly. See
53
+ * {@link anchorDirs} for what conflating them accepted.
54
+ *
55
+ * Exit codes: 0 every named path is emitted · 1 a cell names a path no emitter
56
+ * writes · 2 the document is missing, or its table is gone (a gate that read
57
+ * nothing has not passed).
58
+ */
59
+ import * as fs from 'node:fs';
60
+ import * as os from 'node:os';
61
+ import * as path from 'node:path';
62
+ import process from 'node:process';
63
+ import { fileURLToPath, pathToFileURL } from 'node:url';
64
+
65
+ import { ADAPTER_REGISTRY } from './_lib/tool_adapter_registry.js';
66
+ import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
67
+ import { splitMarkdownRow } from './_lib/md_table.js';
68
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
69
+ import { emitCursor, emitWindsurf } from '../install/emit_host_rules_cli.js';
70
+ import { USER_SCOPE_PATHS } from '../install/wizard-plan.js';
71
+
72
+ const _HERE = fileURLToPath(import.meta.url);
73
+ const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
74
+
75
+ export const GATE = 'check_host_format_column';
76
+ export const DOC_REL = path.join('docs', 'enforcement-by-host.md');
77
+
78
+ /** The header row that opens the table this gate reads. Matched exactly. */
79
+ export const TABLE_HEADER = '| Host | Compile-time rules | Lifecycle slots bound |';
80
+
81
+ const KNOWN_FLAGS: ReadonlySet<string> = new Set(['--self-test', '--root', '--quiet']);
82
+
83
+ export interface FormatCell {
84
+ /** The row's first cell, verbatim. */
85
+ host: string;
86
+ /** The compile-time cell, verbatim. */
87
+ cell: string;
88
+ /** Backtick-quoted tokens in the cell that look like paths. */
89
+ tokens: string[];
90
+ }
91
+
92
+ /**
93
+ * Does a backticked token look like a path rather than prose?
94
+ *
95
+ * Deliberately permissive in one direction only: a token that is not a path is
96
+ * skipped, so a cell may carry `✅` or a word in backticks without being
97
+ * dragged into the comparison. A token that IS a path is always checked — the
98
+ * class this gate exists for.
99
+ */
100
+ export function looksLikePath(token: string): boolean {
101
+ if (token === '') return false;
102
+ return token.includes('/') || token.startsWith('.') || token.endsWith('.md');
103
+ }
104
+
105
+ /** Read the host table's format column. Returns [] when the table is absent. */
106
+ export function parseFormatColumn(docText: string): FormatCell[] {
107
+ const lines = docText.split('\n');
108
+ const start = lines.findIndex((l) => l.trim() === TABLE_HEADER);
109
+ if (start === -1) return [];
110
+ const out: FormatCell[] = [];
111
+ for (let i = start + 1; i < lines.length; i += 1) {
112
+ const line = lines[i] ?? '';
113
+ if (!line.trim().startsWith('|')) break;
114
+ const cells = splitMarkdownRow(line);
115
+ const host = cells[0] ?? '';
116
+ // The separator row (`|---|---|---|`) is structure, not a row.
117
+ if (/^:?-{2,}:?$/.test(host)) continue;
118
+ const cell = cells[1] ?? '';
119
+ const tokens = [...cell.matchAll(/`([^`]+)`/g)]
120
+ .map((m) => m[1] ?? '')
121
+ .filter(looksLikePath);
122
+ out.push({ host, cell, tokens });
123
+ }
124
+ return out;
125
+ }
126
+
127
+ /** Strip `~/`, collapse separators, drop leading and trailing slashes. */
128
+ export function normalizeSurface(p: string): string[] {
129
+ const cleaned = p
130
+ .trim()
131
+ .replace(/^~[/\\]/, '')
132
+ .replace(/\\/g, '/')
133
+ .replace(/^\/+/, '')
134
+ .replace(/\/+$/, '');
135
+ return cleaned.split('/').filter((s) => s !== '');
136
+ }
137
+
138
+ /** One path segment, with `*` matching any run of non-separator characters. */
139
+ function segmentMatches(tokenSeg: string, surfaceSeg: string): boolean {
140
+ if (!tokenSeg.includes('*')) return tokenSeg === surfaceSeg;
141
+ const rx = new RegExp(
142
+ `^${tokenSeg.split('*').map((s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('[^/]*')}$`,
143
+ );
144
+ return rx.test(surfaceSeg);
145
+ }
146
+
147
+ /**
148
+ * Does a table token name the same surface as an emitted path?
149
+ *
150
+ * Three relations count, and each answers a real shape the column uses:
151
+ *
152
+ * - the token is the emitted path, segment for segment (`.clinerules`);
153
+ * - the token REFINES an emitted root, so the root is a prefix of it
154
+ * (`.cursor/rules/*.mdc` under the emitted root `.cursor/rules`), or the
155
+ * token is a root the emitter wrote a file beneath;
156
+ * - the token is the emitted path's tail, so a cell may name a surface by the
157
+ * filename a reader recognises (`copilot-instructions.md` for the emitted
158
+ * `.github/copilot-instructions.md`).
159
+ *
160
+ * The tail relation is the loosest of the three and is worth naming as such: it
161
+ * accepts a token that omits a directory. It does NOT loosen the case this gate
162
+ * was built for — `.cursorrules` is one segment, and no emitted path in this
163
+ * tree has a segment by that name, so it matches under none of the three.
164
+ */
165
+ export function matchesSurface(token: string, surface: string, refineable = true): boolean {
166
+ const t = normalizeSurface(token);
167
+ const s = normalizeSurface(surface);
168
+ if (t.length === 0 || s.length === 0) return false;
169
+ const prefix = (a: string[], b: string[]): boolean =>
170
+ a.length <= b.length && a.every((seg, i) => segmentMatches(seg, b[i] ?? ''));
171
+ if (prefix(t, s)) return true;
172
+ if (!refineable) return false;
173
+ if (prefix(s, t)) return true;
174
+ // Tail relation: compare the token against the last |t| segments.
175
+ if (t.length < s.length) {
176
+ const tail = s.slice(s.length - t.length);
177
+ return t.every((seg, i) => segmentMatches(seg, tail[i] ?? ''));
178
+ }
179
+ return false;
180
+ }
181
+
182
+ /**
183
+ * Run the install-time rule emitters into a throwaway tree and report what they
184
+ * wrote, repo-relative and posix-separated.
185
+ *
186
+ * This is the measured half of the oracle. The fixture is one rule file with
187
+ * the frontmatter a real rule carries, because the emitters read frontmatter to
188
+ * build their host-native forms and an empty file would exercise a path no
189
+ * install takes.
190
+ */
191
+ export function measuredEmitterSurfaces(): string[] {
192
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'host-format-column-'));
193
+ try {
194
+ const rulesDir = path.join(tmp, 'rules');
195
+ const projectRoot = path.join(tmp, 'project');
196
+ fs.mkdirSync(rulesDir, { recursive: true });
197
+ fs.mkdirSync(projectRoot, { recursive: true });
198
+ fs.writeFileSync(
199
+ path.join(rulesDir, 'fixture-rule.md'),
200
+ [
201
+ '---',
202
+ 'type: auto',
203
+ 'description: Fixture rule, used only to measure emitter output paths.',
204
+ 'triggers: [fixture]',
205
+ '---',
206
+ '# Fixture rule',
207
+ '',
208
+ 'Body.',
209
+ '',
210
+ ].join('\n'),
211
+ 'utf-8',
212
+ );
213
+ emitCursor(rulesDir, projectRoot);
214
+ emitWindsurf(rulesDir, projectRoot);
215
+
216
+ const found: string[] = [];
217
+ const walk = (dir: string): void => {
218
+ for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
219
+ const full = path.join(dir, ent.name);
220
+ if (ent.isDirectory()) walk(full);
221
+ else found.push(path.relative(projectRoot, full).split(path.sep).join('/'));
222
+ }
223
+ };
224
+ walk(projectRoot);
225
+ return found.sort();
226
+ } finally {
227
+ fs.rmSync(tmp, { recursive: true, force: true });
228
+ }
229
+ }
230
+
231
+ /**
232
+ * The declared half of the oracle — tool roots the projection generators are
233
+ * already bound to. These are roots an emitter writes INTO, so a cell may
234
+ * legitimately refine one (`.cursor/rules` → `.cursor/rules/*.mdc`).
235
+ */
236
+ export function declaredRoots(): string[] {
237
+ const out = new Set<string>();
238
+ for (const entry of ADAPTER_REGISTRY) {
239
+ for (const root of entry.roots) out.add(root);
240
+ }
241
+ return [...out].sort();
242
+ }
243
+
244
+ /**
245
+ * The installer's per-tool user-scope anchor directories.
246
+ *
247
+ * These are matched EXACTLY and are deliberately not refineable, which the
248
+ * self-test pins. An anchor is a whole tool's home (`~/.cursor/`), so treating
249
+ * it as a root anything may refine accepts every path beneath it — and the
250
+ * gate's own self-test caught exactly that: `.cursor/rules.mdc`, a plausible
251
+ * mistyping of the Cursor cell, passed on the strength of the `~/.cursor/`
252
+ * anchor while no emitter writes it. A cell may name an anchor (the Codex row
253
+ * names `~/.codex/`); it may not name something inside one and be believed.
254
+ */
255
+ export function anchorDirs(): string[] {
256
+ return [...new Set(Object.values(USER_SCOPE_PATHS))].sort();
257
+ }
258
+
259
+ export interface Finding {
260
+ host: string;
261
+ token: string;
262
+ }
263
+
264
+ /** Every format-column token that no emitted surface accounts for. */
265
+ export function unemittedTokens(
266
+ cells: readonly FormatCell[],
267
+ roots: readonly string[],
268
+ anchors: readonly string[],
269
+ ): Finding[] {
270
+ const findings: Finding[] = [];
271
+ for (const row of cells) {
272
+ for (const token of row.tokens) {
273
+ const backed =
274
+ roots.some((s) => matchesSurface(token, s)) ||
275
+ anchors.some((s) => matchesSurface(token, s, false));
276
+ if (!backed) findings.push({ host: row.host, token });
277
+ }
278
+ }
279
+ return findings;
280
+ }
281
+
282
+ function _read(root: string, rel: string): string | null {
283
+ try {
284
+ return fs.readFileSync(path.join(root, rel), 'utf-8');
285
+ } catch {
286
+ return null;
287
+ }
288
+ }
289
+
290
+ export function main(argv?: readonly string[]): number {
291
+ const args = argv ?? process.argv.slice(2);
292
+ // An unrecognised flag is refused rather than ignored: this gate runs in a
293
+ // required CI job, and a mistyped flag that still exits 0 hands back a
294
+ // green nobody earned.
295
+ const unknown = args.filter(
296
+ (a, i) => a.startsWith('-') && !KNOWN_FLAGS.has(a) && args[i - 1] !== '--root',
297
+ );
298
+ if (unknown.length > 0) {
299
+ process.stderr.write(
300
+ `${GATE}: unrecognised flag(s): ${unknown.join(', ')}\n` +
301
+ ` known: ${[...KNOWN_FLAGS].join(', ')}\n`,
302
+ );
303
+ return 2;
304
+ }
305
+ if (args.includes('--self-test')) return selfTest();
306
+ // `--root` is validated rather than coalesced. Silently falling back to
307
+ // ROOT on a missing or option-shaped value means `--root --quiet` checks
308
+ // THIS repository while the caller believes it checked a fixture, and a
309
+ // fixture test written that way passes without ever reading the fixture.
310
+ // Repeats are refused for the same reason: two values and one winner is a
311
+ // caller who does not know which root was read.
312
+ const rootFlags = args.filter((a) => a === '--root');
313
+ if (rootFlags.length > 1) {
314
+ process.stderr.write(`${GATE}: \`--root\` given ${String(rootFlags.length)} times; pass it once.\n`);
315
+ return 2;
316
+ }
317
+ const rootIdx = args.indexOf('--root');
318
+ if (rootIdx !== -1) {
319
+ const v = args[rootIdx + 1];
320
+ if (v === undefined || v.startsWith('-')) {
321
+ process.stderr.write(
322
+ `${GATE}: \`--root\` needs a directory` +
323
+ (v === undefined ? '' : `, got \`${v}\``) +
324
+ '.\n',
325
+ );
326
+ return 2;
327
+ }
328
+ }
329
+ const positional = args.filter((a, i) => !a.startsWith('-') && args[i - 1] !== '--root');
330
+ if (positional.length > 0) {
331
+ process.stderr.write(`${GATE}: unexpected argument(s): ${positional.join(', ')}\n`);
332
+ return 2;
333
+ }
334
+ const root = rootIdx === -1 ? ROOT : (args[rootIdx + 1] as string);
335
+ const quiet = args.includes('--quiet');
336
+
337
+ const docText = _read(root, DOC_REL);
338
+ if (docText === null) {
339
+ process.stderr.write(`❌ ${GATE}: ${DOC_REL} not found under ${root}\n`);
340
+ return 2;
341
+ }
342
+
343
+ const cells = parseFormatColumn(docText);
344
+
345
+ // The scope assertion runs BEFORE the verdict. A document whose table
346
+ // header moved or whose rows were deleted yields zero cells, and a gate
347
+ // that read nothing must fail loudly rather than print a green over an
348
+ // empty corpus.
349
+ try {
350
+ reportScanned({
351
+ gate: GATE,
352
+ scanned: cells.length,
353
+ units: 'format-column cell(s)',
354
+ roots: [DOC_REL],
355
+ });
356
+ } catch (exc) {
357
+ if (exc instanceof DeadScopeError) {
358
+ process.stderr.write(
359
+ `❌ ${exc.message}\n` +
360
+ ` The table is found by its header line, matched exactly:\n` +
361
+ ` ${TABLE_HEADER}\n`,
362
+ );
363
+ return 2;
364
+ }
365
+ throw exc;
366
+ }
367
+
368
+ const measured = measuredEmitterSurfaces();
369
+ const roots = [...new Set([...measured, ...declaredRoots()])];
370
+ const anchors = anchorDirs();
371
+
372
+ const findings = unemittedTokens(cells, roots, anchors);
373
+
374
+ if (!quiet) {
375
+ process.stdout.write(
376
+ `${GATE}: ${String(measured.length)} measured emitter path(s), ` +
377
+ `${String(roots.length)} emitted root(s), ` +
378
+ `${String(anchors.length)} user-scope anchor(s) (exact match only)\n`,
379
+ );
380
+ for (const m of measured) process.stdout.write(` measured ${m}\n`);
381
+ }
382
+
383
+ if (findings.length > 0) {
384
+ for (const f of findings) {
385
+ process.stdout.write(
386
+ `❌ ${GATE}: ${DOC_REL} § the ${f.host} row names \`${f.token}\`, ` +
387
+ 'which is neither a measured emitter output nor a declared ' +
388
+ 'emitted root.\n',
389
+ );
390
+ }
391
+ process.stdout.write(
392
+ `\n${String(findings.length)} finding(s). The format column describes generated ` +
393
+ 'output, so the correction belongs in the cell — name the path an emitter ' +
394
+ 'really writes. Emitted roots this gate knows about:\n' +
395
+ roots
396
+ .slice()
397
+ .sort()
398
+ .map((s) => ` ${s}\n`)
399
+ .join('') +
400
+ 'If a NEW emitter was added, it belongs in `ADAPTER_REGISTRY` (or in the ' +
401
+ 'measured pair) in the same change — a gate that cannot see an emitter ' +
402
+ 'reports a true cell as drift, which is how a gate gets disabled.\n',
403
+ );
404
+ return 1;
405
+ }
406
+
407
+ // The claim is deliberately weaker than "an emitter wrote this path". Only
408
+ // the MEASURED half was observed being written; the DECLARED half is a root
409
+ // read out of `ADAPTER_REGISTRY`, which is the projection's source of truth
410
+ // but is not an observation this run took. An independent review refused
411
+ // the earlier wording for overstating exactly that gap, and a gate whose
412
+ // green line claims more than its oracle checked is the failure this file
413
+ // was written to stop, one level up.
414
+ process.stdout.write(
415
+ `✅ ${GATE}: every path named in ${String(cells.length)} format-column cell(s) of ` +
416
+ `${DOC_REL} resolves to a measured emitter output or to a root declared in ` +
417
+ '`ADAPTER_REGISTRY`.\n',
418
+ );
419
+ return 0;
420
+ }
421
+
422
+ /**
423
+ * One rejecting case per way the column and the emitters can part company.
424
+ *
425
+ * The first is the historical defect by name: planting `.cursorrules` back into
426
+ * the Cursor cell must red the gate. The empty-root case is the scope
427
+ * assertion's own — a document with no table must fail rather than pass over an
428
+ * empty corpus.
429
+ */
430
+ function selfTest(): number {
431
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'host-format-column-st-'));
432
+ const docText = _read(ROOT, DOC_REL) ?? '';
433
+ const plant = (name: string, mutate: (doc: string) => string): string => {
434
+ const dir = path.join(tmp, name);
435
+ fs.mkdirSync(path.join(dir, path.dirname(DOC_REL)), { recursive: true });
436
+ fs.writeFileSync(path.join(dir, DOC_REL), mutate(docText), 'utf-8');
437
+ return dir;
438
+ };
439
+ const run = (root: string): number =>
440
+ runGateCli(ROOT, `src/scripts/${GATE}.ts`, ['--root', root, '--quiet'], root);
441
+ // Argv cases run against a planted-GOOD root, so the only thing that can
442
+ // make them non-zero is the argument shape. An argv guard tested against a
443
+ // root that would fail anyway proves nothing about the guard.
444
+ const runArgs = (args: readonly string[]): number =>
445
+ runGateCli(ROOT, `src/scripts/${GATE}.ts`, args, ROOT);
446
+
447
+ try {
448
+ return runSelfTest({
449
+ gate: GATE,
450
+ minCases: 9,
451
+ minRejectCases: 8,
452
+ cases: [
453
+ {
454
+ name: 'the historical defect — `.cursorrules` planted back into the Cursor cell',
455
+ expect: 'reject',
456
+ run: () =>
457
+ run(
458
+ plant('cursorrules', (d) =>
459
+ d.replace(
460
+ '| Cursor | ✅ `.cursor/rules/*.mdc` | 5 |',
461
+ '| Cursor | ✅ `.cursorrules` | 5 |',
462
+ ),
463
+ ),
464
+ ),
465
+ },
466
+ {
467
+ // The row is replaced whole, never just the token: the same
468
+ // token appears in the prose paragraph above the table,
469
+ // which this gate does not scan, and `String.replace` takes
470
+ // the FIRST occurrence — so a token-level fixture silently
471
+ // mutated the prose and asserted nothing. Caught by this
472
+ // suite reporting the case as not behaving.
473
+ name: 'a plausible near-miss — `.cursor/rules.mdc` — is rejected',
474
+ expect: 'reject',
475
+ run: () =>
476
+ run(
477
+ plant('nearmiss', (d) =>
478
+ d.replace(
479
+ '| Cursor | ✅ `.cursor/rules/*.mdc` | 5 |',
480
+ '| Cursor | ✅ `.cursor/rules.mdc` | 5 |',
481
+ ),
482
+ ),
483
+ ),
484
+ },
485
+ {
486
+ name: 'an invented surface on a correct neighbouring row is rejected',
487
+ expect: 'reject',
488
+ run: () =>
489
+ run(plant('invented', (d) => d.replace('| Cline | ✅ `.clinerules` | 5 |', '| Cline | ✅ `.clinereles` | 5 |'))),
490
+ },
491
+ {
492
+ name: 'a document with no host table is rejected, not passed over an empty corpus',
493
+ expect: 'reject',
494
+ run: () => run(plant('empty', (d) => d.replace(TABLE_HEADER, '| Host | Other |'))),
495
+ },
496
+ {
497
+ name: 'the committed table passes',
498
+ expect: 'accept',
499
+ run: () => run(plant('good', (d) => d)),
500
+ },
501
+ // The three argv shapes an independent review found accepted on
502
+ // 2026-09-29. Each one silently read THIS repository while the
503
+ // caller believed it had named a root — a fixture test written
504
+ // that way passes without ever opening the fixture, which is the
505
+ // failure mode a gate's own self-test exists to make impossible.
506
+ // Both shapes below are constructed so the COALESCING code
507
+ // would have exited 0: a trailing `--root` and a repeated
508
+ // `--root ROOT` both fall back to ROOT, which passes. Pointing
509
+ // them at a root that fails anyway would have made the cases
510
+ // reject on the unfixed code too — a test that cannot fail for
511
+ // the reason it names.
512
+ {
513
+ name: 'a trailing `--root` with no value is refused, not coalesced to ROOT',
514
+ expect: 'reject',
515
+ run: () => runArgs(['--quiet', '--root']),
516
+ },
517
+ {
518
+ name: '`--root` given twice is refused rather than silently picking one',
519
+ expect: 'reject',
520
+ run: () => runArgs(['--root', ROOT, '--root', ROOT, '--quiet']),
521
+ },
522
+ {
523
+ name: 'an unexpected positional argument is refused',
524
+ expect: 'reject',
525
+ run: () => runArgs(['stray', '--quiet']),
526
+ },
527
+ // Round 3 of the review asked for this shape by name, and it is
528
+ // carried with its limitation stated: it does NOT discriminate.
529
+ // The coalescing code set `root = '--quiet'`, found no document
530
+ // under it, and also exited 2 — so this case pins the branch's
531
+ // behavior and documents the motivating shape, while the three
532
+ // cases above are the ones that would have caught the defect.
533
+ // Labelled rather than quietly counted, because a self-test
534
+ // suite whose cases are not all discriminating should say which.
535
+ {
536
+ name: '`--root` with an option-shaped value is refused (pins the shape; does not discriminate)',
537
+ expect: 'reject',
538
+ run: () => runArgs(['--root', '--quiet']),
539
+ },
540
+ ],
541
+ });
542
+ } finally {
543
+ fs.rmSync(tmp, { recursive: true, force: true });
544
+ }
545
+ }
546
+
547
+ function _isCliEntry(): boolean {
548
+ if (process.argv[1] === undefined) return false;
549
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
550
+ try {
551
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
552
+ } catch {
553
+ return false;
554
+ }
555
+ }
556
+
557
+ if (_isCliEntry()) {
558
+ process.exit(main());
559
+ }