@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,515 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * check_read_surface_coverage.ts — generate the sanitize floor's read-surface
4
+ * table in `docs/contracts/retrieval-read-surfaces.md` from the tree, and fail
5
+ * when the committed table, the module header, or the structural detector
6
+ * disagree with what the tree actually says
7
+ * (road-to-a-sanitize-list-that-is-generated, Phase 1.2 + Phase 3.3).
8
+ *
9
+ * THREE CHECKS, ONE REASON
10
+ * ------------------------
11
+ * 1. DRIFT — the committed table equals the regenerated one. A new module that
12
+ * brings outside bytes in, or a sanitize import added or removed, changes the
13
+ * table; leaving the committed copy behind is the failure this gate exists
14
+ * for.
15
+ * 2. SECOND COPY — `retrieval_sanitize.ts`'s header points at the table instead
16
+ * of restating it. Two copies of a list is exactly how the first one went
17
+ * stale, twice, so a header that names a module path the table also names is
18
+ * a finding rather than a nicety.
19
+ * 3. NO PERCENTAGE — the structural-hiding detector publishes no recall or
20
+ * coverage rate. A rate needs a frozen corpus of hiding techniques and none
21
+ * exists; a number would be an invented denominator that a later reader
22
+ * quotes as measured coverage. Enforced rather than asserted, because a
23
+ * prose promise not to publish a number is the weakest control available.
24
+ *
25
+ * WHAT A GREEN RUN PROVES, AND WHAT IT DOES NOT
26
+ * ---------------------------------------------
27
+ * Green means the published table agrees with the tree's import graph. It
28
+ * proves nothing about whether any module applies the floor to the right
29
+ * string. `covered` is "the floor is in scope in this module"; establishing
30
+ * that it is actually reached needs a read of the module, and this gate does
31
+ * not pretend otherwise — the table header says so in its own first lines.
32
+ */
33
+ import * as fs from 'node:fs';
34
+ import * as os from 'node:os';
35
+ import * as path from 'node:path';
36
+ import process from 'node:process';
37
+ import { fileURLToPath, pathToFileURL } from 'node:url';
38
+
39
+ import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
40
+ import {
41
+ LOCAL_VCS_EXCLUSION,
42
+ type ReadSurfaceRow,
43
+ SCAN_ROOT,
44
+ renderTable,
45
+ scanReadSurfaces,
46
+ tally,
47
+ } from './_lib/read_surface_scan.js';
48
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
49
+
50
+ const _HERE = fileURLToPath(import.meta.url);
51
+ const ROOT = path.resolve(path.dirname(_HERE), '..', '..');
52
+
53
+ const GATE = 'check_read_surface_coverage';
54
+ export const DOC_REL = 'docs/contracts/retrieval-read-surfaces.md';
55
+ export const FLOOR_REL = 'src/scripts/_lib/retrieval_sanitize.ts';
56
+ export const DETECTOR_REL = 'src/scripts/_lib/structural_hiding.ts';
57
+
58
+ export const BEGIN_MARKER = '<!-- BEGIN read-surface-table (generated) -->';
59
+ export const END_MARKER = '<!-- END read-surface-table -->';
60
+
61
+ const REGEN_COMMAND = `./scripts-run src/scripts/${GATE} --write`;
62
+
63
+ function _read(root: string, rel: string): string | null {
64
+ try {
65
+ return fs.readFileSync(path.join(root, rel), 'utf-8');
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+
71
+ /** The leading block comment of a module — its header, and nothing after it. */
72
+ export function leadingBlockComment(src: string): string {
73
+ const m = /^\s*\/\*\*[\s\S]*?\*\//.exec(src);
74
+ return m === null ? '' : m[0];
75
+ }
76
+
77
+ /** Render the full generated region, header prose included. */
78
+ export function renderRegion(rows: readonly ReadSurfaceRow[]): string {
79
+ return [
80
+ '> Generated by `' + GATE + '`. Do not edit between the markers — a cell',
81
+ '> edited by hand is overwritten by the next regeneration and reported by the',
82
+ '> gate in between. Corrections belong in the tree or in the scanner.',
83
+ '',
84
+ '**A row is a claim about imports, not about safety.** `covered` means the',
85
+ 'module imports the sanitize floor, so the floor is in scope there. It does',
86
+ 'not say the floor is applied to the right string or at the right point —',
87
+ 'that needs a read of the module, and no import graph can supply it.',
88
+ '',
89
+ '**What is out of scope, said here rather than left to be discovered.** ' +
90
+ LOCAL_VCS_EXCLUSION,
91
+ '',
92
+ 'A module reaching the network through a shape in neither the strong nor the',
93
+ 'weak detector set is absent from this table entirely. That residual is the',
94
+ 'reason `unclassified` exists and the reason this paragraph does.',
95
+ '',
96
+ renderTable(rows),
97
+ ].join('\n');
98
+ }
99
+
100
+ /** Replace the marked region in `doc`, or append one when absent. */
101
+ export function spliceRegion(doc: string, region: string): string {
102
+ const begin = doc.indexOf(BEGIN_MARKER);
103
+ const end = doc.indexOf(END_MARKER);
104
+ if (begin === -1 || end === -1 || end < begin) {
105
+ return `${doc.trimEnd()}\n\n${BEGIN_MARKER}\n${region}\n${END_MARKER}\n`;
106
+ }
107
+ return `${doc.slice(0, begin)}${BEGIN_MARKER}\n${region}\n${doc.slice(end)}`;
108
+ }
109
+
110
+ /** Extract the marked region's body, or `null` when the markers are missing. */
111
+ export function extractRegion(doc: string): string | null {
112
+ const begin = doc.indexOf(BEGIN_MARKER);
113
+ const end = doc.indexOf(END_MARKER);
114
+ if (begin === -1 || end === -1 || end < begin) return null;
115
+ return doc.slice(begin + BEGIN_MARKER.length, end).trim();
116
+ }
117
+
118
+ /**
119
+ * Module paths the floor's header restates instead of pointing at.
120
+ *
121
+ * Matching on the basename keeps the check honest against a header that names
122
+ * `memory_lookup.ts` without its directory — the shape the previous header
123
+ * actually used.
124
+ */
125
+ export function headerSecondCopy(header: string, rows: readonly ReadSurfaceRow[]): string[] {
126
+ const hits = new Set<string>();
127
+ for (const r of rows) {
128
+ const base = r.module.split('/').pop() ?? r.module;
129
+ if (header.includes(base)) hits.add(base);
130
+ }
131
+ return [...hits].sort();
132
+ }
133
+
134
+ interface Options {
135
+ root: string;
136
+ write: boolean;
137
+ quiet: boolean;
138
+ }
139
+
140
+ /**
141
+ * A published rate — `99 %`, `72.33%`, `recall: 0.98`.
142
+ *
143
+ * Scoped to the DETECTOR FILE and nothing else, deliberately. The codepoint
144
+ * floor next door publishes two real, corpus-backed percentages in its own
145
+ * docblock; a check that swept every citing surface would red on those and be
146
+ * switched off within a week. The claim this rule defends is narrow — the
147
+ * STRUCTURAL layer has no frozen corpus, so it has no denominator — and the
148
+ * check is scoped to exactly that claim.
149
+ */
150
+ const PERCENTAGE_RE = /\b\d+(?:\.\d+)?\s*%|\brecall\s*[:=]\s*\d/i;
151
+
152
+ /** The register's exported name, cited by every surface claiming the coverage. */
153
+ export const GAP_REGISTER_SYMBOL = 'STRUCTURAL_HIDING_GAPS';
154
+
155
+ /**
156
+ * True when a percentage or recall figure is PUBLISHED in the detector.
157
+ *
158
+ * Inline code spans are removed before the test, and that exclusion is the
159
+ * difference between a rule and a nuisance. The gap register names
160
+ * `transform: translate(-100%, 0)` as an off-screen hiding technique — a CSS
161
+ * literal inside backticks, not a claim about this detector's coverage. The
162
+ * first version of this check red on exactly that and the fix belongs here,
163
+ * in the predicate, rather than in the register's wording: a gate that makes
164
+ * honest prose contort around it gets switched off. Both directions are pinned
165
+ * by self-test cases, because a widened matcher that no longer catches the
166
+ * thing it was written for fails silently.
167
+ */
168
+ export function publishesRate(detectorSrc: string): boolean {
169
+ for (const line of detectorSrc.split('\n')) {
170
+ // The rule states the prohibition in prose; the prose is not a breach.
171
+ if (line.includes('PERCENTAGE_RE') || line.includes('no recall or coverage')) continue;
172
+ const prose = line.replace(/`[^`]*`/g, '');
173
+ if (PERCENTAGE_RE.test(prose)) return true;
174
+ }
175
+ return false;
176
+ }
177
+
178
+ function parseArgs(argv: readonly string[]): Options {
179
+ const out: Options = { root: ROOT, write: false, quiet: false };
180
+ for (let i = 0; i < argv.length; i += 1) {
181
+ const a = argv[i];
182
+ if (a === '--root') {
183
+ out.root = path.resolve(argv[i + 1] ?? '.');
184
+ i += 1;
185
+ } else if (a === '--write') out.write = true;
186
+ else if (a === '--quiet') out.quiet = true;
187
+ }
188
+ return out;
189
+ }
190
+
191
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
192
+ if (argv.includes('--self-test')) return selfTest();
193
+ const opts = parseArgs(argv);
194
+ const say = (s: string): void => {
195
+ if (!opts.quiet) process.stdout.write(s);
196
+ };
197
+
198
+ const rows = scanReadSurfaces(opts.root);
199
+ const region = renderRegion(rows);
200
+
201
+ if (opts.write) {
202
+ const existing = _read(opts.root, DOC_REL) ?? `# Retrieval read surfaces\n`;
203
+ fs.mkdirSync(path.join(opts.root, path.dirname(DOC_REL)), { recursive: true });
204
+ fs.writeFileSync(path.join(opts.root, DOC_REL), spliceRegion(existing, region), 'utf-8');
205
+ process.stdout.write(`✍️ ${GATE}: wrote ${String(rows.length)} row(s) to ${DOC_REL}\n`);
206
+ return 0;
207
+ }
208
+
209
+ const findings: string[] = [];
210
+
211
+ // 1. Drift between the tree and the committed table.
212
+ const doc = _read(opts.root, DOC_REL);
213
+ if (doc === null) {
214
+ findings.push(`${DOC_REL} is missing — the generated table has no home.`);
215
+ } else {
216
+ const committed = extractRegion(doc);
217
+ if (committed === null) {
218
+ findings.push(`${DOC_REL} carries no \`${BEGIN_MARKER}\` … \`${END_MARKER}\` region.`);
219
+ } else if (committed !== region.trim()) {
220
+ findings.push(
221
+ `${DOC_REL} disagrees with the tree. The table is generated; regenerate it.`,
222
+ );
223
+ }
224
+ }
225
+
226
+ // 2. The floor's header points at the table rather than restating it.
227
+ const floor = _read(opts.root, FLOOR_REL);
228
+ if (floor === null) {
229
+ findings.push(`${FLOOR_REL} is missing — the floor this table describes is gone.`);
230
+ } else {
231
+ const header = leadingBlockComment(floor);
232
+ if (!header.includes(DOC_REL)) {
233
+ findings.push(
234
+ `${FLOOR_REL}'s header does not point at ${DOC_REL}. The coverage list is ` +
235
+ 'generated; the header carries the pointer, never a second copy.',
236
+ );
237
+ }
238
+ const copies = headerSecondCopy(header, rows);
239
+ if (copies.length > 0) {
240
+ findings.push(
241
+ `${FLOOR_REL}'s header names ${String(copies.length)} module(s) the table also ` +
242
+ `names (${copies.join(', ')}). Two copies of this list is how it went stale ` +
243
+ 'twice; the header points, the table lists.',
244
+ );
245
+ }
246
+ }
247
+
248
+ // 3. NO PERCENTAGE, and the gap register travels with the claim.
249
+ //
250
+ // This rule was REMOVED once, correctly: it watched a detector file that
251
+ // did not exist, and both review seats called it dead policy. It returns
252
+ // here with the detector, written against a file that exists, with its own
253
+ // rejecting self-test cases. If the detector is absent the rule is silent
254
+ // rather than red — a missing detector is Phase 3 being open, not a breach.
255
+ const detector = _read(opts.root, DETECTOR_REL);
256
+ if (detector !== null) {
257
+ if (publishesRate(detector)) {
258
+ findings.push(
259
+ `${DETECTOR_REL} publishes a recall or coverage figure. A rate needs a frozen ` +
260
+ 'corpus of hiding techniques and none exists in this tree, so the number ' +
261
+ 'would be an invented denominator a later reader quotes as measured coverage. ' +
262
+ 'State the covered-channel list and the gap register instead.',
263
+ );
264
+ }
265
+ if (!detector.includes(GAP_REGISTER_SYMBOL)) {
266
+ findings.push(
267
+ `${DETECTOR_REL} does not define ${GAP_REGISTER_SYMBOL}. The register of what the ` +
268
+ "detector does NOT catch belongs in the detector's own file — a detector " +
269
+ 'documented without its gaps is how the coverage claim becomes a false green.',
270
+ );
271
+ }
272
+ for (const [rel, src] of [
273
+ [FLOOR_REL, floor],
274
+ [DOC_REL, doc],
275
+ ] as const) {
276
+ if (src === null) continue;
277
+ if (!src.includes('structural_hiding')) continue; // claims nothing
278
+ if (src.includes(GAP_REGISTER_SYMBOL)) continue;
279
+ findings.push(
280
+ `${rel} claims the structural coverage without citing ${GAP_REGISTER_SYMBOL}. ` +
281
+ 'Every surface that claims this coverage cites the register alongside the ' +
282
+ 'claim, so the caveat travels with the claim rather than staying in one file.',
283
+ );
284
+ }
285
+ }
286
+
287
+ try {
288
+ reportScanned({
289
+ gate: GATE,
290
+ scanned: rows.length,
291
+ units: 'read surface(s)',
292
+ roots: [SCAN_ROOT],
293
+ });
294
+ } catch (e) {
295
+ if (e instanceof DeadScopeError) {
296
+ process.stdout.write(`❌ ${e.message}\n`);
297
+ return 1;
298
+ }
299
+ throw e;
300
+ }
301
+
302
+ if (findings.length > 0) {
303
+ for (const f of findings) process.stdout.write(`❌ ${GATE}: ${f}\n`);
304
+ process.stdout.write(`\n${String(findings.length)} finding(s). Regenerate with:\n ${REGEN_COMMAND}\n`);
305
+ return 1;
306
+ }
307
+ const t = tally(rows);
308
+ say(
309
+ `✅ ${GATE}: ${String(rows.length)} read surface(s) in ${DOC_REL} match the tree ` +
310
+ `(${String(t.covered)} covered, ${String(t.uncovered)} uncovered, ` +
311
+ `${String(t.unclassified)} unclassified).\n`,
312
+ );
313
+ return 0;
314
+ }
315
+
316
+ /**
317
+ * One rejecting case per way the three checks can be defeated.
318
+ *
319
+ * The empty-root case is the one that matters most here: a gate whose scan root
320
+ * moved reads zero surfaces and would otherwise certify a table it never
321
+ * compared. `assertScanned` has to turn that into a refusal, and only a fixture
322
+ * with no `src/scripts/` at all proves it does.
323
+ */
324
+ function selfTest(): number {
325
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'read-surface-'));
326
+ const floor = _read(ROOT, FLOOR_REL) ?? '';
327
+
328
+ /** Plant a fixture root with a one-module scan tree plus the three inputs. */
329
+ const plant = (
330
+ name: string,
331
+ opts: {
332
+ module?: string;
333
+ mutateRegion?: (r: string) => string;
334
+ floorSrc?: string;
335
+ detectorSrc?: string;
336
+ noScanRoot?: boolean;
337
+ },
338
+ ): string => {
339
+ const dir = path.join(tmp, name);
340
+ if (opts.noScanRoot !== true) {
341
+ fs.mkdirSync(path.join(dir, SCAN_ROOT, '_lib'), { recursive: true });
342
+ fs.writeFileSync(
343
+ path.join(dir, SCAN_ROOT, 'seed_surface.ts'),
344
+ opts.module ??
345
+ 'export async function pull(u: string): Promise<string> {\n' +
346
+ ' const r = await fetch(u);\n' +
347
+ ' return await r.text();\n}\n',
348
+ 'utf-8',
349
+ );
350
+ } else {
351
+ fs.mkdirSync(dir, { recursive: true });
352
+ }
353
+ fs.mkdirSync(path.join(dir, path.dirname(FLOOR_REL)), { recursive: true });
354
+ fs.mkdirSync(path.join(dir, path.dirname(DOC_REL)), { recursive: true });
355
+ fs.writeFileSync(path.join(dir, FLOOR_REL), opts.floorSrc ?? floor, 'utf-8');
356
+ // The detector is planted ONLY where a case needs it. Absent, rule 3 is
357
+ // silent — which is itself the behaviour the last case below pins.
358
+ if (opts.detectorSrc !== undefined) {
359
+ fs.mkdirSync(path.join(dir, path.dirname(DETECTOR_REL)), { recursive: true });
360
+ fs.writeFileSync(path.join(dir, DETECTOR_REL), opts.detectorSrc, 'utf-8');
361
+ }
362
+ const region = renderRegion(scanReadSurfaces(dir));
363
+ fs.writeFileSync(
364
+ path.join(dir, DOC_REL),
365
+ `# fixture\n\n${BEGIN_MARKER}\n${(opts.mutateRegion ?? ((r) => r))(region)}\n${END_MARKER}\n`,
366
+ 'utf-8',
367
+ );
368
+ return dir;
369
+ };
370
+
371
+ const run = (root: string): number =>
372
+ runGateCli(ROOT, `src/scripts/${GATE}.ts`, ['--root', root], root);
373
+
374
+ try {
375
+ return runSelfTest({
376
+ gate: GATE,
377
+ minCases: 10,
378
+ minRejectCases: 7,
379
+ cases: [
380
+ {
381
+ name: 'an unsanitized fetch-derived emit the committed table does not carry is rejected',
382
+ expect: 'reject',
383
+ run: () => {
384
+ const dir = plant('seeded', {});
385
+ fs.writeFileSync(
386
+ path.join(dir, SCAN_ROOT, 'seeded_leak.ts'),
387
+ 'export async function grab(u: string): Promise<void> {\n' +
388
+ ' const r = await fetch(u);\n' +
389
+ ' writeFileSync("out.md", await r.text());\n}\n',
390
+ 'utf-8',
391
+ );
392
+ return run(dir);
393
+ },
394
+ },
395
+ {
396
+ name: 'a hand-flipped coverage cell is rejected',
397
+ expect: 'reject',
398
+ run: () =>
399
+ run(
400
+ plant('flipped', {
401
+ mutateRegion: (r) => r.replace('**uncovered**', '**covered**'),
402
+ }),
403
+ ),
404
+ },
405
+ {
406
+ name: "a header restating a module path the table lists is rejected",
407
+ expect: 'reject',
408
+ run: () =>
409
+ run(
410
+ plant('second-copy', {
411
+ floorSrc: `/**\n * Floor.\n * See ${DOC_REL}.\n * - seed_surface.ts — yes\n */\nexport const x = 1;\n`,
412
+ }),
413
+ ),
414
+ },
415
+ {
416
+ name: 'a header with no pointer to the generated table is rejected',
417
+ expect: 'reject',
418
+ run: () => run(plant('no-pointer', { floorSrc: '/**\n * Floor.\n */\nexport const x = 1;\n' })),
419
+ },
420
+ {
421
+ name: 'an empty scan root is refused rather than certified',
422
+ expect: 'reject',
423
+ run: () => run(plant('empty-root', { noScanRoot: true })),
424
+ },
425
+ {
426
+ name: 'a detector publishing a coverage percentage is rejected',
427
+ expect: 'reject',
428
+ run: () =>
429
+ run(
430
+ plant('rate-published', {
431
+ floorSrc: `/**\n * Floor. Coverage list: ${DOC_REL}.\n * Gaps: ${GAP_REGISTER_SYMBOL}.\n */\nexport const x = 1;\n`,
432
+ detectorSrc:
433
+ `export const ${GAP_REGISTER_SYMBOL} = ['stylesheet-driven hiding'];\n` +
434
+ '/** Measured recall over the channel corpus: 94.2 %. */\n' +
435
+ 'export const y = 1;\n',
436
+ }),
437
+ ),
438
+ },
439
+ {
440
+ name: 'a detector with no gap register is rejected',
441
+ expect: 'reject',
442
+ run: () =>
443
+ run(
444
+ plant('no-register', {
445
+ floorSrc: `/**\n * Floor. Coverage list: ${DOC_REL}.\n * Gaps: ${GAP_REGISTER_SYMBOL}.\n */\nexport const x = 1;\n`,
446
+ detectorSrc: 'export const y = 1;\n',
447
+ }),
448
+ ),
449
+ },
450
+ {
451
+ name: 'a floor claiming the coverage without citing the gap register is rejected',
452
+ expect: 'reject',
453
+ run: () =>
454
+ run(
455
+ plant('register-uncited', {
456
+ floorSrc: `/**\n * Floor. Coverage list: ${DOC_REL}. Structural: structural_hiding.\n */\nexport const x = 1;\n`,
457
+ detectorSrc: `export const ${GAP_REGISTER_SYMBOL} = ['stylesheet-driven hiding'];\n`,
458
+ }),
459
+ ),
460
+ },
461
+ {
462
+ name: 'a CSS percentage inside a code span is NOT read as a published rate',
463
+ expect: 'accept',
464
+ run: () =>
465
+ run(
466
+ plant('rate-in-code-span', {
467
+ floorSrc: `/**\n * Floor. Coverage list: ${DOC_REL}.\n * Gaps: ${GAP_REGISTER_SYMBOL}.\n */\nexport const x = 1;\n`,
468
+ detectorSrc:
469
+ `export const ${GAP_REGISTER_SYMBOL} = [\n` +
470
+ " 'off-screen positioning — `transform: translate(-100%, 0)`',\n" +
471
+ '];\n',
472
+ }),
473
+ ),
474
+ },
475
+ {
476
+ name: 'a detector that exists, publishes no rate and carries its register passes',
477
+ expect: 'accept',
478
+ run: () =>
479
+ run(
480
+ plant('detector-clean', {
481
+ floorSrc: `/**\n * Floor. Coverage list: ${DOC_REL}.\n * Gaps: ${GAP_REGISTER_SYMBOL}.\n */\nexport const x = 1;\n`,
482
+ detectorSrc: `export const ${GAP_REGISTER_SYMBOL} = ['stylesheet-driven hiding'];\n`,
483
+ }),
484
+ ),
485
+ },
486
+ {
487
+ name: 'a regenerated table over an intact tree passes',
488
+ expect: 'accept',
489
+ run: () =>
490
+ run(
491
+ plant('good', {
492
+ floorSrc: `/**\n * Floor. Coverage list: ${DOC_REL}.\n */\nexport const x = 1;\n`,
493
+ }),
494
+ ),
495
+ },
496
+ ],
497
+ });
498
+ } finally {
499
+ fs.rmSync(tmp, { recursive: true, force: true });
500
+ }
501
+ }
502
+
503
+ function _isCliEntry(): boolean {
504
+ if (process.argv[1] === undefined) return false;
505
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
506
+ try {
507
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
508
+ } catch {
509
+ return false;
510
+ }
511
+ }
512
+
513
+ if (_isCliEntry()) {
514
+ process.exit(main());
515
+ }
@@ -79,6 +79,7 @@ import {
79
79
  CURATED_HEAD_INSTRUCTION,
80
80
  extract_changelog_section,
81
81
  } from './_lib/release_material.js';
82
+ import { coverageLimitationNote, ledgerCoverageLabel } from './_lib/review_coverage.js';
82
83
  import { assertScanned, assertWatchlistResolves, DeadScopeError } from './_lib/scan_scope.js';
83
84
 
84
85
  const _HERE = fileURLToPath(import.meta.url);
@@ -339,6 +340,15 @@ export function main(argv: readonly string[]): number {
339
340
  const contradictions = highlight_contradictions(curated, derived);
340
341
  if (contradictions.length === 0) {
341
342
  process.stdout.write(`✅ curated head plausible for ${version} (span ${from}..${to})\n`);
343
+ // How much of the change the self-review read, printed where the head's
344
+ // Known-limitations field is decided. Partial coverage IS a known
345
+ // limitation of the record, and the ledger was the only place it was
346
+ // written down. A label, not a floor — the exit code above is already
347
+ // fixed at 0 by the time this runs, deliberately.
348
+ const covNote = coverageLimitationNote(ledgerCoverageLabel(REPO_ROOT, version));
349
+ if (covNote !== null) {
350
+ process.stdout.write(`${covNote}\n`);
351
+ }
342
352
  // Risk 2 of the roadmap that made `Known limitations` derivable, paid
343
353
  // where it lands rather than in a comment: a self-declared residual is
344
354
  // only detectable when somebody WROTE IT DOWN, so a derived `_none_`
@@ -45,7 +45,8 @@ const _HERE = fileURLToPath(import.meta.url);
45
45
  /**
46
46
  * The folders a release question must read.
47
47
  *
48
- * Wider than `lint_roadmap_blockers`' active-only glob on purpose: rule 28's
48
+ * Wider than `lint_roadmap_blockers`' glob on purpose — that gate reads the
49
+ * active tree plus `stubs/` and stops there (2026-09-28), while rule 28's
49
50
  * per-folder lifecycle says a window does not disappear by moving the file, and
50
51
  * a `later/` roadmap still refuses. `archive/` and `skipped/` are included
51
52
  * because the move INTO them is refused while a window is open — a file that
@@ -45,6 +45,16 @@ const ALLOWLIST_GLOBS = [
45
45
  // be able to carry the dispositions of its own self-review findings; the
46
46
  // finding-dispositions gate is red until blocking ones are recorded here.
47
47
  'agents/evidence/release-findings/*.json',
48
+ // Evidence-temperature census — `taskfiles/content.yml` § release-prepare
49
+ // writes one per release, so without this entry the pipeline generates a
50
+ // file its own shape step refuses. Digit classes rather than `?`: fnmatch
51
+ // `?` compiles to `.` under the `s` flag, so it matches any character AND
52
+ // crosses `/` — `????-??-??` admits `evidence-temperature-x/yz-ab-cd.md`,
53
+ // which `[0-9]` cannot. Two reports can appear in one release PR, and
54
+ // both are in shape: `--resume` re-runs release-prepare, so a release
55
+ // carried across UTC midnight writes a second census. What that one
56
+ // contains is the census's business, not this gate's.
57
+ 'agents/evidence/analysis/evidence-temperature-[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].md', // code-comment-allow provenance-comment -- the glob IS this gate's operand, not where the code came from
48
58
  // Project-settings template pin — bumped by release.ts set_template_pin and
49
59
  // its regenerated dist twin (kept in lockstep with package.json.version).
50
60
  'src/agent-src/templates/agents/agent-project-settings.example.yml',
@@ -52,16 +62,26 @@ const ALLOWLIST_GLOBS = [
52
62
  ] as const;
53
63
 
54
64
  /**
55
- * Translate a Python `fnmatch` shell pattern to a RegExp, mirroring
56
- * `fnmatch.translate`. fnmatch is case-sensitive on POSIX (fnmatchcase
57
- * semantics on the normalized path); `*` and `?` do NOT cross path
58
- * separators is NOT a property of fnmatch — `*` matches everything
59
- * including `/`. The allowlist relies on that (e.g. nested-file rejection
60
- * in the test works because none of the globs end with the file).
65
+ * Translate a Python `fnmatch` shell pattern to a RegExp, following
66
+ * `fnmatch.translate` for the constructs the allowlist actually uses: `*` and
67
+ * `[0-9]`. No entry uses `?`, and bracket handling beyond that one class is
68
+ * unverified against CPython — see the note at the bracket branch.
69
+ *
70
+ * Matching is case-sensitive, as `fnmatchcase` on a normalized path.
71
+ *
72
+ * THE PROPERTY THE WILDCARD ENTRIES TURN ON — the literal paths are unaffected:
73
+ * in fnmatch, `*` and `?` DO cross path separators.
74
+ * `*` becomes `.*` and `?` becomes `.`, both under the `s` flag, so each matches
75
+ * `/` like any other character. Glob syntax elsewhere (shells, .gitignore) stops
76
+ * `*` at a segment boundary; this does not. So the pack entry admits any depth
77
+ * beneath `src/packs/`, and the census entry uses digit classes precisely
78
+ * because they cannot match a separator. Both sides are pinned in
79
+ * `check_release_pr_shape.test.ts`.
61
80
  */
62
81
  function _fnmatchToRegExp(pat: string): RegExp {
63
- // Mirror Python fnmatch.translate: `*` → `.*`, `?` → `.`, `[seq]` kept,
64
- // everything else escaped. The full pattern is anchored with `(?s:...)\Z`.
82
+ // `*` → `.*`, `?` → `.`, a bracket class kept, everything else escaped.
83
+ // CPython does more inside a class (hyphen and set-operator escaping, `(?!)`
84
+ // for an empty one) and this does not — see the bracket branch below.
65
85
  let i = 0;
66
86
  const n = pat.length;
67
87
  let res = '';
@@ -87,12 +107,13 @@ function _fnmatchToRegExp(pat: string): RegExp {
87
107
  res += '\\[';
88
108
  } else {
89
109
  let stuff = pat.slice(i, j);
90
- if (!stuff.includes('-')) {
91
- stuff = stuff.replace(/\\/g, '\\\\');
92
- } else {
93
- // Rare; not used by the allowlist. Keep simple escape.
94
- stuff = stuff.replace(/\\/g, '\\\\');
95
- }
110
+ // The two arms this replaces were byte-identical, so the branch
111
+ // implemented nothing. Bracket handling here is checked against
112
+ // `[0-9]`, the only class the allowlist uses; anything else is
113
+ // untested against CPython, whose behaviour also varies by
114
+ // version. Add a bracket glob and verify it rather than assuming
115
+ // this mirrors `fnmatch.translate` beyond that one case.
116
+ stuff = stuff.replace(/\\/g, '\\\\');
96
117
  i = j + 1;
97
118
  if (stuff.startsWith('!')) {
98
119
  stuff = '^' + stuff.slice(1);
@@ -105,7 +126,9 @@ function _fnmatchToRegExp(pat: string): RegExp {
105
126
  res += c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
106
127
  }
107
128
  }
108
- // Python uses `(?s:%s)\Z` — dotAll + full match.
129
+ // Full match with dotAll. Python spells the same thing `(?s:%s)\Z`; in JS
130
+ // `$` without the `m` flag does not match before a trailing newline, so
131
+ // `^(?:…)$` is equivalent rather than merely similar.
109
132
  return new RegExp(`^(?:${res})$`, 's');
110
133
  }
111
134