@event4u/agent-config 14.12.0 → 14.14.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 (521) 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 +118 -155
  5. package/CONTRIBUTING.md +38 -0
  6. package/CREDITS.md +135 -0
  7. package/NOTICE +13 -0
  8. package/README.md +8 -6
  9. package/dist/agent-src/commands/analyze/inbox.md +145 -2
  10. package/dist/agent-src/commands/feature/dev.md +7 -2
  11. package/dist/agent-src/commands/ghostwriter/write.md +5 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  14. package/dist/agent-src/commands/orchestrate.md +2 -2
  15. package/dist/agent-src/commands/post-as/me.md +5 -1
  16. package/dist/agent-src/commands/pr/merge.md +19 -6
  17. package/dist/agent-src/commands/roadmap/process-full.md +19 -5
  18. package/dist/agent-src/commands/tdd/red.md +12 -2
  19. package/dist/agent-src/commands/work.md +1 -1
  20. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
  21. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
  22. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
  23. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
  24. package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
  25. package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
  26. package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
  27. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  28. package/dist/agent-src/rules/broken-access-control.md +4 -0
  29. package/dist/agent-src/rules/code-comment-discipline.md +6 -0
  30. package/dist/agent-src/rules/code-provenance.md +4 -0
  31. package/dist/agent-src/rules/design-fidelity.md +1 -1
  32. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  33. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  34. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  35. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  36. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  37. package/dist/agent-src/rules/laravel-routing.md +1 -1
  38. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  39. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  40. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  41. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  42. package/dist/agent-src/rules/symfony-routing.md +1 -1
  43. package/dist/agent-src/rules/token-efficiency.md +14 -0
  44. package/dist/agent-src/rules/tool-safety.md +4 -0
  45. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  46. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  47. package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
  48. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  49. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  50. package/dist/agent-src/scripts/stubs_due.ts +516 -0
  51. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  52. package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
  53. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  54. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  55. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  56. package/dist/agent-src/skills/database/SKILL.md +8 -0
  57. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  58. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  59. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  60. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  61. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  62. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  63. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  64. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  65. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  66. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  67. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  68. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  69. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  70. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  71. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  72. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  73. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  74. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  75. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  76. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  77. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  78. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  79. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  80. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  81. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  82. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  83. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  84. package/dist/agent-src/templates/roadmaps.md +97 -3
  85. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  86. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  87. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  88. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  93. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  94. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  95. package/dist/cli/commands/uiAudit.js +124 -5
  96. package/dist/cli/registry.js +2 -0
  97. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  98. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  99. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  100. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  101. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  102. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  103. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  104. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  105. package/dist/cli-delegate/cmd_conformance.js +80 -11
  106. package/dist/cli-delegate/cmd_doctor.js +3 -3
  107. package/dist/cli-delegate/cmd_export.js +3 -2
  108. package/dist/cli-delegate/cmd_fleet.js +2 -2
  109. package/dist/cli-delegate/cmd_handoff.js +1 -1
  110. package/dist/cli-delegate/cmd_preflight.js +2 -2
  111. package/dist/cli-delegate/cmd_prune.js +3 -2
  112. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  113. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  114. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  115. package/dist/cli-delegate/cmd_sync.js +3 -2
  116. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  117. package/dist/cli-delegate/cmd_validate.js +3 -2
  118. package/dist/discovery/deprecation-report.md +1 -1
  119. package/dist/discovery/discovery-manifest.json +58 -58
  120. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  121. package/dist/discovery/discovery-manifest.summary.md +1 -1
  122. package/dist/discovery/dormancy-report.md +1 -1
  123. package/dist/discovery/orphan-report.md +1 -1
  124. package/dist/discovery/packs.json +2 -2
  125. package/dist/discovery/trust-report.md +1 -1
  126. package/dist/discovery/workspaces.json +2 -2
  127. package/dist/hooks/dispatch.js +2900 -1049
  128. package/dist/install/claudeRuleRewrite.js +254 -0
  129. package/dist/install/detect.js +29 -16
  130. package/dist/install/detect_php_shape.js +159 -0
  131. package/dist/install/install.mjs +634 -428
  132. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  133. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  134. package/dist/mcp/registry-manifest.json +3 -3
  135. package/dist/mcp/server.json +3 -3
  136. package/dist/mcp/server.mjs +4895 -2627
  137. package/dist/server/schemas/settings.js +3 -0
  138. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  139. package/dist/ui/index.html +1 -1
  140. package/docs/MIGRATION.md +1 -1
  141. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  142. package/docs/contracts/provider-lifecycle.md +1 -1
  143. package/docs/contracts/settings-classes.md +10 -4
  144. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  145. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  146. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  147. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  148. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  149. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  150. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  151. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  152. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  153. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  154. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  155. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  156. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  157. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  158. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  159. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  160. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  161. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  162. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  163. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  164. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  165. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  166. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  167. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  168. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  169. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  170. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  171. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  172. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  173. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  174. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  175. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  176. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  177. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  178. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  179. package/docs/guidelines/augment-portability-patterns.md +6 -4
  180. package/docs/guidelines/code-clarity.md +18 -0
  181. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  182. package/docs/guidelines/cross-role-handoff.md +2 -2
  183. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  184. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  185. package/docs/guidelines/php/database.md +90 -7
  186. package/docs/guidelines/prompt-templates.md +7 -7
  187. package/llms.txt +2 -2
  188. package/package.json +5 -2
  189. package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  190. package/src/agent-src/scripts/guarded_baseline.ts +343 -0
  191. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  192. package/src/agent-src/scripts/stub_queue.ts +82 -0
  193. package/src/agent-src/scripts/stubs_due.ts +516 -0
  194. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  195. package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
  196. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  197. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  198. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  199. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  202. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  203. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  204. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  205. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  206. package/src/config/agent-settings.template.yml +32 -3
  207. package/src/config/assurance-capability-registry.json +21 -9
  208. package/src/config/canonical-terms.yml +119 -0
  209. package/src/config/capability-native-outcome-bars.json +81 -0
  210. package/src/config/ci-local-parity.yml +80 -0
  211. package/src/config/drafting-channels.yml +43 -0
  212. package/src/config/estate-count-budget.json +57 -36
  213. package/src/config/evaluator-budgets.json +14 -14
  214. package/src/config/gate-coverage.yml +729 -63
  215. package/src/config/gate-reachability-exemptions.json +21 -0
  216. package/src/config/gate-violation-baselines.json +42 -19
  217. package/src/config/harness-evolution-budget.json +25 -0
  218. package/src/config/lapsed-beta-baseline.json +96 -0
  219. package/src/config/memory-twin-verdicts.yml +129 -0
  220. package/src/config/metric-registry.yml +124 -0
  221. package/src/config/pack-size-budget.json +16 -15
  222. package/src/config/preamble-payload-budget.json +12 -4
  223. package/src/config/profiles/balanced.ini +27 -0
  224. package/src/config/profiles/full.ini +27 -0
  225. package/src/config/profiles/minimal.ini +27 -0
  226. package/src/config/publish-surface.json +9 -2
  227. package/src/config/routing-coverage-seed.json +16 -2
  228. package/src/config/rule-stub-ceilings.json +133 -112
  229. package/src/config/turnaround-budget.json +66 -0
  230. package/src/install/claudeRuleRewrite.ts +288 -0
  231. package/src/install/detect.ts +60 -17
  232. package/src/install/detect_php_shape.ts +191 -0
  233. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  234. package/src/scripts/_dispatch.bash +23 -0
  235. package/src/scripts/_lib/activation_ladder.ts +255 -0
  236. package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
  237. package/src/scripts/_lib/activation_states.ts +88 -0
  238. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  239. package/src/scripts/_lib/adr_frontmatter.ts +26 -0
  240. package/src/scripts/_lib/arith_claims.ts +181 -0
  241. package/src/scripts/_lib/arm_ranking.ts +62 -0
  242. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  243. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  244. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  245. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  246. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  247. package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
  248. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  249. package/src/scripts/_lib/candidate_record.ts +601 -0
  250. package/src/scripts/_lib/capture_rate.ts +319 -0
  251. package/src/scripts/_lib/carrier_status.ts +118 -0
  252. package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
  253. package/src/scripts/_lib/collector_denominator.ts +771 -0
  254. package/src/scripts/_lib/collector_record.ts +340 -0
  255. package/src/scripts/_lib/collector_store.ts +664 -0
  256. package/src/scripts/_lib/collector_supervision.ts +827 -0
  257. package/src/scripts/_lib/concern_estate.ts +77 -0
  258. package/src/scripts/_lib/config_chain.ts +477 -0
  259. package/src/scripts/_lib/config_cost.ts +209 -0
  260. package/src/scripts/_lib/corpus_manifest.ts +726 -0
  261. package/src/scripts/_lib/council_settings_block.ts +6 -0
  262. package/src/scripts/_lib/curator_ops.ts +172 -0
  263. package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
  264. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  265. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  266. package/src/scripts/_lib/empty_cycles.ts +88 -0
  267. package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
  268. package/src/scripts/_lib/eval_publication.ts +354 -0
  269. package/src/scripts/_lib/evaluation_cascade.ts +452 -0
  270. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  271. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  272. package/src/scripts/_lib/evidence_basis.ts +118 -0
  273. package/src/scripts/_lib/evolution_roi.ts +562 -0
  274. package/src/scripts/_lib/exec_evidence.ts +8 -0
  275. package/src/scripts/_lib/experience_card.ts +272 -0
  276. package/src/scripts/_lib/experience_report.ts +151 -0
  277. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  278. package/src/scripts/_lib/generated_by.ts +66 -0
  279. package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
  280. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  281. package/src/scripts/_lib/host_denominator.ts +687 -0
  282. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  283. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  284. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  285. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  286. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  287. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  288. package/src/scripts/_lib/lexical_shortlist.ts +215 -0
  289. package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
  290. package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
  291. package/src/scripts/_lib/loop_guards.ts +299 -0
  292. package/src/scripts/_lib/loss_class.ts +129 -0
  293. package/src/scripts/_lib/machine_wake.ts +51 -0
  294. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  295. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  296. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  297. package/src/scripts/_lib/orchestration_record.ts +253 -5
  298. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  299. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  300. package/src/scripts/_lib/paired_stats.ts +245 -0
  301. package/src/scripts/_lib/paired_verdict.ts +226 -0
  302. package/src/scripts/_lib/pathology_archive.ts +393 -0
  303. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  304. package/src/scripts/_lib/privacy_class.ts +47 -0
  305. package/src/scripts/_lib/promotion_capability.ts +315 -0
  306. package/src/scripts/_lib/promotion_evidence.ts +414 -0
  307. package/src/scripts/_lib/promotion_review.ts +294 -0
  308. package/src/scripts/_lib/prompt_shape.ts +92 -0
  309. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  310. package/src/scripts/_lib/release_highlights.ts +70 -1
  311. package/src/scripts/_lib/release_material.ts +125 -2
  312. package/src/scripts/_lib/repeated_failure.ts +105 -0
  313. package/src/scripts/_lib/repo_root.ts +111 -0
  314. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  315. package/src/scripts/_lib/role_split.ts +338 -0
  316. package/src/scripts/_lib/routing_corpus.ts +307 -0
  317. package/src/scripts/_lib/routing_index_input.ts +104 -0
  318. package/src/scripts/_lib/rule_injection.ts +22 -1
  319. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  320. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  321. package/src/scripts/_lib/semantic_noop.ts +167 -0
  322. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  323. package/src/scripts/_lib/source_digest.ts +200 -0
  324. package/src/scripts/_lib/source_redact.ts +260 -0
  325. package/src/scripts/_lib/source_shape.ts +502 -0
  326. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  327. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  328. package/src/scripts/_lib/strip_comments.mjs +65 -0
  329. package/src/scripts/_lib/test_red_state.ts +154 -0
  330. package/src/scripts/_lib/trigger_shift.ts +144 -0
  331. package/src/scripts/_lib/untrusted_content.ts +82 -7
  332. package/src/scripts/activation_receipt.ts +258 -0
  333. package/src/scripts/adoption_report.ts +1 -1
  334. package/src/scripts/adr/evidence_census.ts +1 -1
  335. package/src/scripts/adr/regenerate_index.ts +26 -2
  336. package/src/scripts/adr_cite_check.ts +164 -1
  337. package/src/scripts/ai_council/blind_review.ts +11 -1
  338. package/src/scripts/ai_council/clients.ts +4 -0
  339. package/src/scripts/ai_council/config.ts +3 -0
  340. package/src/scripts/ai_council/consensus.ts +28 -8
  341. package/src/scripts/ai_council/consensus_round.ts +226 -0
  342. package/src/scripts/ai_council/cross_exam.ts +128 -0
  343. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  344. package/src/scripts/ai_council/explain_route.ts +157 -0
  345. package/src/scripts/ai_council/information_gain.ts +293 -0
  346. package/src/scripts/ai_council/inline_findings.ts +340 -0
  347. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  348. package/src/scripts/ai_council/leakage_corpus.ts +385 -0
  349. package/src/scripts/ai_council/leakage_patterns.ts +453 -0
  350. package/src/scripts/ai_council/minority_retention.ts +171 -0
  351. package/src/scripts/ai_council/orchestrator.ts +16 -203
  352. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  353. package/src/scripts/ai_council/pricing.ts +106 -0
  354. package/src/scripts/ai_council/prompts.ts +74 -7
  355. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  356. package/src/scripts/ai_council/py_format.ts +14 -3
  357. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  358. package/src/scripts/ai_council/recouncil_savings.ts +299 -0
  359. package/src/scripts/ai_council/replay_route.ts +223 -0
  360. package/src/scripts/ai_council/response_record.ts +50 -0
  361. package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
  362. package/src/scripts/ai_council/routing_training_row.ts +197 -0
  363. package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
  364. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  365. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  366. package/src/scripts/asset_delivery_ledger.ts +157 -0
  367. package/src/scripts/attest_artifact.ts +193 -0
  368. package/src/scripts/audit_auto_rules.ts +2 -1
  369. package/src/scripts/audit_command_surface.ts +1 -1
  370. package/src/scripts/audit_mcp_tools.ts +2 -2
  371. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  372. package/src/scripts/audit_user_type_axis.ts +2 -1
  373. package/src/scripts/bench_ab_clone.ts +215 -10
  374. package/src/scripts/bench_ab_integrity.ts +119 -5
  375. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  376. package/src/scripts/build_archive_index.ts +1 -1
  377. package/src/scripts/build_linear_digest.ts +1 -1
  378. package/src/scripts/build_proof.ts +11 -4
  379. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  380. package/src/scripts/build_source_digests.ts +157 -0
  381. package/src/scripts/cache_realization_report.ts +103 -0
  382. package/src/scripts/check_adr_frontmatter.ts +131 -10
  383. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  384. package/src/scripts/check_beta_review_markers.ts +235 -6
  385. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  386. package/src/scripts/check_claims.ts +576 -6
  387. package/src/scripts/check_composite_arming.ts +35 -0
  388. package/src/scripts/check_concern_admissions.ts +365 -0
  389. package/src/scripts/check_enforcement_coverage.ts +28 -0
  390. package/src/scripts/check_estate_count.ts +347 -25
  391. package/src/scripts/check_gate_reachability.ts +383 -0
  392. package/src/scripts/check_host_loadability.ts +104 -0
  393. package/src/scripts/check_loss_class_declared.ts +308 -0
  394. package/src/scripts/check_md_language.ts +15 -98
  395. package/src/scripts/check_memory_proposal.ts +18 -11
  396. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  397. package/src/scripts/check_no_external_sources.ts +281 -6
  398. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  399. package/src/scripts/check_pack_size.ts +59 -2
  400. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  401. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  402. package/src/scripts/check_publish_surface.ts +10 -1
  403. package/src/scripts/check_references.ts +24 -1
  404. package/src/scripts/check_release_highlights.ts +96 -13
  405. package/src/scripts/check_roadmap_trackable.ts +17 -2
  406. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  407. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  408. package/src/scripts/check_score_contract.ts +26 -3
  409. package/src/scripts/check_static_parity.ts +285 -0
  410. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  411. package/src/scripts/check_suppression_hygiene.ts +15 -0
  412. package/src/scripts/ci_settle.ts +39 -2
  413. package/src/scripts/code_graph/build.ts +60 -3
  414. package/src/scripts/code_graph/extract.ts +44 -0
  415. package/src/scripts/code_graph/types.ts +24 -0
  416. package/src/scripts/collector_daemon.ts +714 -0
  417. package/src/scripts/config_cost_report.ts +302 -0
  418. package/src/scripts/consumer_matrix.ts +74 -1
  419. package/src/scripts/corpus_manifest.ts +235 -0
  420. package/src/scripts/cost/budget.mjs +10 -3
  421. package/src/scripts/cost/track.mjs +10 -3
  422. package/src/scripts/council_cli.ts +37 -54
  423. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  424. package/src/scripts/evolution_lab.ts +1153 -0
  425. package/src/scripts/external_sources_denylist.json +5 -18
  426. package/src/scripts/extract_audit_patterns.ts +21 -0
  427. package/src/scripts/fold_intake.ts +12 -1
  428. package/src/scripts/gen_discovery_baseline.ts +1 -1
  429. package/src/scripts/generate_capabilities_index.ts +12 -5
  430. package/src/scripts/generate_capability_matrix.ts +3 -3
  431. package/src/scripts/generate_command_flows.ts +2 -2
  432. package/src/scripts/generate_cookbook.ts +2 -2
  433. package/src/scripts/generate_index.ts +8 -1
  434. package/src/scripts/generate_knowledge_index.ts +2 -1
  435. package/src/scripts/generate_ownership_matrix.ts +2 -1
  436. package/src/scripts/generate_pack_manifests.ts +10 -2
  437. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  438. package/src/scripts/generate_settings_reference.ts +1 -1
  439. package/src/scripts/git_authorization_hook.ts +22 -1
  440. package/src/scripts/grade_target_readiness.ts +48 -5
  441. package/src/scripts/hook_effect_doctor.ts +261 -0
  442. package/src/scripts/hook_manifest.json +1 -1
  443. package/src/scripts/hook_manifest.yaml +125 -16
  444. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  445. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  446. package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
  447. package/src/scripts/hooks/concern_registry.ts +6 -0
  448. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  449. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  450. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  451. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  452. package/src/scripts/hooks/shims/install.sh +61 -0
  453. package/src/scripts/hooks/shims/php +101 -0
  454. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  455. package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
  456. package/src/scripts/hot_context_hook.ts +16 -0
  457. package/src/scripts/install-hooks.sh +20 -5
  458. package/src/scripts/install.ts +17 -35
  459. package/src/scripts/inventory_frontmatter.ts +2 -1
  460. package/src/scripts/language_mirror_hook.ts +14 -2
  461. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  462. package/src/scripts/lint_canonical_terms.ts +604 -0
  463. package/src/scripts/lint_carrier_integrity.ts +820 -0
  464. package/src/scripts/lint_code_comments.ts +643 -0
  465. package/src/scripts/lint_composition_review.ts +619 -0
  466. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  467. package/src/scripts/lint_eval_specs.ts +593 -0
  468. package/src/scripts/lint_hook_manifest.ts +19 -0
  469. package/src/scripts/lint_host_portability.ts +373 -0
  470. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  471. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  472. package/src/scripts/lint_metric_consumers.ts +355 -0
  473. package/src/scripts/lint_plan_risk_register.ts +39 -19
  474. package/src/scripts/lint_promotion_paths.ts +779 -0
  475. package/src/scripts/lint_skill_descriptions.ts +18 -1
  476. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  477. package/src/scripts/lint_skill_link_reach.ts +252 -0
  478. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  479. package/src/scripts/lint_ticket_buildable.ts +17 -1
  480. package/src/scripts/llm_propose.ts +256 -0
  481. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  482. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  483. package/src/scripts/measure_delivery_sets.ts +361 -0
  484. package/src/scripts/measure_docs_dead_links.ts +348 -0
  485. package/src/scripts/measure_host_capture.ts +461 -0
  486. package/src/scripts/measure_routing_signal.ts +307 -0
  487. package/src/scripts/migration_status.ts +3 -3
  488. package/src/scripts/model_rule_injection.ts +76 -0
  489. package/src/scripts/orchestration_record.ts +14 -0
  490. package/src/scripts/preamble_byte_census.ts +139 -10
  491. package/src/scripts/prepack-check.mjs +4 -1
  492. package/src/scripts/probe_council_retention.ts +495 -0
  493. package/src/scripts/probe_turnaround.ts +384 -0
  494. package/src/scripts/probe_unblocked_ask.ts +279 -0
  495. package/src/scripts/release.ts +21 -37
  496. package/src/scripts/release_drill.ts +143 -0
  497. package/src/scripts/release_env.ts +35 -0
  498. package/src/scripts/release_publication.ts +84 -0
  499. package/src/scripts/render_benchmark_md.ts +1 -1
  500. package/src/scripts/rule_activation_census.ts +70 -9
  501. package/src/scripts/rule_backlinks.ts +1 -1
  502. package/src/scripts/run_lifecycle_suite.ts +208 -0
  503. package/src/scripts/run_skill_evals.ts +40 -0
  504. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  505. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  506. package/src/scripts/schemas/evals.schema.json +24 -1
  507. package/src/scripts/schemas/rule.schema.json +52 -1
  508. package/src/scripts/schemas/skill.schema.json +17 -2
  509. package/src/scripts/skill_overlap.ts +7 -1
  510. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  511. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  512. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  513. package/src/scripts/skill_usage_report.ts +2 -1
  514. package/src/scripts/stubs_due.ts +211 -0
  515. package/src/scripts/sweep_source_surfaces.ts +678 -0
  516. package/src/scripts/sync_pr_branch.ts +3 -3
  517. package/src/scripts/trigger_eval_grandfather.json +202 -222
  518. package/src/scripts/utilization_report.ts +22 -2
  519. package/src/server/schemas/settings.ts +5 -0
  520. package/src/templates/marketing-copy.yml +1 -1
  521. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -55,7 +55,30 @@ function makeBrokenRef(
55
55
  return { file, line, ref, ref_type, severity, suggestion };
56
56
  }
57
57
 
58
- const SCAN_DIRS = ['dist/agent-src', 'agents'];
58
+ // `docs/guidelines` joins the scan on 2026-08-26 (`road-to-contract-review-deadlines`
59
+ // 4.3), and the decision is the NARROW one of the three that step offered —
60
+ // widen to the SHIPPED roots only.
61
+ //
62
+ // Priced before deciding, which is what the step asked for. Measured with
63
+ // `measure_docs_dead_links`: 544 dead relative links across `docs/`, of which
64
+ // **104 sat in files `package.json:files[]` publishes** and 440 did not.
65
+ // Widening to all of `docs/` would land ~300 findings on the next unrelated pull
66
+ // request — the flood that gets a gate waived rather than adopted, and the same
67
+ // argument this roadmap's Phase 0 already accepted for the beta backlog.
68
+ // Widening to the shipped roots lands **zero**, because 4.2 repaired all 104
69
+ // first, so the gate arrives green and holds the gain instead of announcing it.
70
+ //
71
+ // The excluded class is named rather than left implicit: **297 dead links in
72
+ // NON-shipped `docs/`** — analysis notes, ADR records, architecture pages — stay
73
+ // out of scope. They cost a maintainer a confused minute; a dead link under
74
+ // `docs/guidelines/` is shipped to a consumer and is the only half that reaches
75
+ // anyone. Re-measure any time with `./scripts-run src/scripts/measure_docs_dead_links`.
76
+ //
77
+ // The three named single-file contracts in `files[]`
78
+ // (`persona-schema`, `provider-lifecycle`, `settings-classes`) are NOT added:
79
+ // a directory scan cannot express "these three files under a directory that is
80
+ // otherwise excluded", and all three measure zero dead links today.
81
+ const SCAN_DIRS = ['dist/agent-src', 'agents', 'docs/guidelines'];
59
82
  const SKIP_DIRS = [
60
83
  // Archived roadmaps have historical refs — a link to a file that existed when
61
84
  // the plan was written is not drift, so the exclusion is right on the merits.
@@ -18,7 +18,33 @@
18
18
  * `_none_` everywhere. That removes the guaranteed first-run red (9.17.0,
19
19
  * 9.18.0) without blunting this gate: a machine-written `_none_` was never the
20
20
  * failure it was built for — a HUMAN writing one was (9.13.0, 9.14.0), and that
21
- * still fails here. An unrewritten derived line warns; it never blocks.
21
+ * still fails here.
22
+ *
23
+ * ## REVERSED 2026-09-01 — an unrewritten derived line now BLOCKS
24
+ *
25
+ * This header used to end the paragraph above with *"An unrewritten derived
26
+ * line warns; it never blocks."* That is no longer the behaviour, and the
27
+ * sentence is replaced rather than deleted so the reversal is legible.
28
+ *
29
+ * **The premise was never wrong; the conclusion drawn from it was.** A derived
30
+ * line does carry true evidence — the deriving reason plus citing SHAs — so it
31
+ * is not false-if-shipped. What the advisory conclusion assumed is that
32
+ * "unpolished-if-unedited" would in fact get edited. Measured at `b50b27281`,
33
+ * it did not: `_auto-derived, rewrite before merge:_` shipped in FIVE
34
+ * consecutive released sections — 14.9.0 (4 lines), 14.10.0 (2), 14.11.0 (4),
35
+ * 14.12.0 (4), 14.13.0 (4), eighteen lines in total. A warning that has been
36
+ * ignored eighteen times is not a warning; it is a comment.
37
+ *
38
+ * **Instructing authority:** the maintainer, in the closing instruction of the
39
+ * 2026-09-a inbox round, requiring that the release-placeholder defect be taken
40
+ * into a roadmap and fixed. Carried into
41
+ * `agents/roadmaps/archive/road-to-publication-integrity-hard-fail.md` § Phase 1, which
42
+ * is the record of this change.
43
+ *
44
+ * **What did NOT change.** The read stays scoped to the section under release
45
+ * (`extract_changelog_section` below), so the eighteen historical lines cannot
46
+ * red a future release; a filled field is still never judged for prose quality;
47
+ * and the `_none_` contradiction check is untouched.
22
48
  *
23
49
  * Derivation is deliberately conservative (documented per-label below):
24
50
  * a false red makes every release annoying; a miss only returns the head to
@@ -29,7 +55,8 @@
29
55
  * [--changelog <path>]
30
56
  *
31
57
  * `--from` defaults to the latest reachable release tag before `--to`
32
- * (default HEAD). Exit codes: 0 plausible · 1 contradiction · 2 usage error.
58
+ * (default HEAD). Exit codes: 0 plausible · 1 refusal (an unrewritten
59
+ * auto-derived head line, or a `_none_` contradiction) · 2 usage error.
33
60
  */
34
61
  import * as fs from 'node:fs';
35
62
  import * as path from 'node:path';
@@ -37,6 +64,7 @@ import process from 'node:process';
37
64
  import { fileURLToPath } from 'node:url';
38
65
 
39
66
  import {
67
+ DERIVED_MARKER,
40
68
  HEAD_LABELS,
41
69
  HEAD_NONE,
42
70
  type SpanCommit,
@@ -46,7 +74,10 @@ import {
46
74
  previous_release_tag,
47
75
  stale_draft_labels,
48
76
  } from './_lib/release_highlights.js';
49
- import { extract_changelog_section } from './_lib/release_material.js';
77
+ import {
78
+ CURATED_HEAD_INSTRUCTION,
79
+ extract_changelog_section,
80
+ } from './_lib/release_material.js';
50
81
  import { assertScanned, assertWatchlistResolves, DeadScopeError } from './_lib/scan_scope.js';
51
82
 
52
83
  const _HERE = fileURLToPath(import.meta.url);
@@ -116,9 +147,17 @@ export function highlight_contradictions(
116
147
 
117
148
  /**
118
149
  * Exported so the advisory-vs-blocking decision is a fixture, not a claim.
150
+ *
151
+ * CORRECTED 2026-09-01 with the reversal. This comment used to say that
119
152
  * `stale_draft_labels` firing while the exit code stays 0 is the behaviour the
120
- * cadence blocker adjudicates; pinning it here makes either branch of that
121
- * decision a one-line diff with a test that notices.
153
+ * cadence blocker adjudicates. That is no longer what happens — the branch at
154
+ * the call site returns 1 — and the sentence is replaced rather than deleted
155
+ * because it was the load-bearing claim on the other side.
156
+ *
157
+ * What it got RIGHT is worth keeping: the decision was a one-line diff with a
158
+ * test that notices, and the reversal proved it. The two fixtures that pinned
159
+ * the advisory branch were updated in place, not deleted, so the change of
160
+ * contract reads off the diff.
122
161
  */
123
162
  export function main(argv: readonly string[]): number {
124
163
  let version: string | null = null;
@@ -171,6 +210,33 @@ export function main(argv: readonly string[]): number {
171
210
  process.stderr.write(`CHANGELOG carries no section for ${version}\n`);
172
211
  return 2;
173
212
  }
213
+ // A LEAKED AUTHORING INSTRUCTION REFUSES THE RELEASE (roadmap § 2.2).
214
+ //
215
+ // A different mechanism from the marker check below: that one catches an
216
+ // unpolished claim, this one catches a reminder to the releaser that was
217
+ // never meant to be release content at all. `CHANGELOG.md` is the bare
218
+ // entry in `package.json` `files`, so a comment surviving here is
219
+ // published to npm — it did, twice, before Option A stopped the writer
220
+ // emitting it.
221
+ //
222
+ // SAME SCOPE as the marker check, and for the same reason: `section` is
223
+ // the ONE section `extract_changelog_section` cut for `--version`. A
224
+ // historical section carrying the identical comment is not read here and
225
+ // does not block this release. Detection is the named sentinel, never a
226
+ // shape match over comment prose.
227
+ if (section.body.includes(CURATED_HEAD_INSTRUCTION)) {
228
+ process.stderr.write(
229
+ `❌ the ${version} section still carries the generator's authoring instruction ` +
230
+ `(\`${CURATED_HEAD_INSTRUCTION}\`).\n` +
231
+ ' It is a reminder to the releaser, not release content, and CHANGELOG.md ' +
232
+ 'is published to npm.\n' +
233
+ ` Delete that comment line from the ${version} section. Only that section is ` +
234
+ 'read; historical\n' +
235
+ ' sections carrying the same comment are out of scope and do not block this ' +
236
+ 'release.\n',
237
+ );
238
+ return 1;
239
+ }
174
240
  const curated = parse_curated_head(section.body);
175
241
  if (!curated) {
176
242
  process.stdout.write(`ℹ️ no curated head in the ${version} section — nothing to check\n`);
@@ -199,17 +265,34 @@ export function main(argv: readonly string[]): number {
199
265
  'could contradict. Deleting the scan root is not the same state — that is the ' +
200
266
  'throwing branch, not this one.',
201
267
  });
202
- // A generator-derived line that nobody rewrote is a prose gap, never a
203
- // contradiction: the line's evidence is true, it is just unpolished. Warn
204
- // so the omission is visible, and keep the exit code owned solely by the
205
- // `_none_` check — a warning that reds the build is the guaranteed-red
206
- // failure mode this whole change exists to remove.
268
+ // A generator-derived line that nobody rewrote REFUSES the release.
269
+ //
270
+ // REVERSED 2026-09-01. This block used to warn and return the exit code to
271
+ // the `_none_` check alone, on the reasoning that a derived line is true
272
+ // and merely unpolished. The reasoning still holds and the conclusion does
273
+ // not: the warning was emitted and ignored through five consecutive
274
+ // released sections. See this file's header for the full record and the
275
+ // instructing authority.
276
+ //
277
+ // SCOPE, and it is the load-bearing half (roadmap § 1.3): `curated` comes
278
+ // from `parse_curated_head(section.body)` above, and `section` is the ONE
279
+ // section `extract_changelog_section` cut for `--version`. No read here
280
+ // reaches another section, another era file, or `docs/archive/`. That is
281
+ // what keeps eighteen historical marker lines from turning this into a
282
+ // permanent red on every future release.
207
283
  const drafts = stale_draft_labels(curated);
208
284
  if (drafts.length > 0) {
209
- process.stdout.write(
210
- `⚠️ auto-derived head line(s) not yet rewritten for ${version}: ` +
211
- `${drafts.join(', ')} — advisory, not blocking.\n`,
285
+ process.stderr.write(
286
+ `❌ unrewritten auto-derived head line(s) in the ${version} section: ` +
287
+ `${drafts.join(', ')}\n` +
288
+ ` Each still carries \`${DERIVED_MARKER}\` — the generator's draft, not a ` +
289
+ 'curated claim.\n' +
290
+ ` Rewrite those line(s) in the ${version} section of the changelog. Only that ` +
291
+ 'section is read;\n' +
292
+ ' historical sections carrying the same marker are out of scope and do not ' +
293
+ 'block this release.\n',
212
294
  );
295
+ return 1;
213
296
  }
214
297
  const derived = derive_categories(span);
215
298
  const contradictions = highlight_contradictions(curated, derived);
@@ -15,7 +15,7 @@
15
15
  * (Python-only); these pure regex/parse helpers are replicated here
16
16
  * byte-for-byte from that module. Keep in lock-step with it.
17
17
  *
18
- * Every non-draft file under `agents/roadmaps/` (excluding `archive/`,
18
+ * Every non-draft file under `agents/roadmaps/` (excluding `archive/`, code-comment-allow provenance-comment -- the path is this script's operand, not where the code came from
19
19
  * `skipped/`, template/README/open-questions) MUST:
20
20
  * 1. Be parseable by the dashboard's `PHASE_RE` (>= one `## Phase <id>`).
21
21
  * 2. Have at least one trackable checkbox under every parsed phase.
@@ -49,6 +49,15 @@ const PHASE_RE =
49
49
  // FRONTMATTER_RE = re.compile(r"\A---\n(.*?)\n---\s*\n", re.DOTALL)
50
50
  const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\s*\n/;
51
51
  const DRAFT_VALUES: ReadonlySet<string> = new Set(['draft']);
52
+ /**
53
+ * A carrier holds obligations deferred out of an archived parent. It is not
54
+ * schedulable work — every item in it has an unmet resumption trigger — and it
55
+ * has no `## Phase` headings by construction, so it is skipped exactly where a
56
+ * draft is. It differs from a draft in what protects it: a draft may be deleted
57
+ * freely, a carrier may not, and `lint_carrier_integrity` reds when one loses
58
+ * its receiver.
59
+ */
60
+ const CARRIER_VALUES: ReadonlySet<string> = new Set(['carrier']);
52
61
 
53
62
  const EXCLUDE_NAMES: ReadonlySet<string> = new Set([
54
63
  'template.md',
@@ -92,6 +101,11 @@ function is_draft(fm: Map<string, string>): boolean {
92
101
  return DRAFT_VALUES.has((fm.get('status') ?? '').toLowerCase());
93
102
  }
94
103
 
104
+ /** True for a `status: carrier` roadmap — see CARRIER_VALUES. */
105
+ function is_carrier(fm: Map<string, string>): boolean {
106
+ return CARRIER_VALUES.has((fm.get('status') ?? '').toLowerCase());
107
+ }
108
+
95
109
  /** Mirror update_roadmap_progress.is_roadmap_candidate (POSIX path parts). */
96
110
  function is_roadmap_candidate(p: string): boolean {
97
111
  const name = path.basename(p);
@@ -168,7 +182,7 @@ function find_active_roadmaps(root: string): string[] {
168
182
  continue;
169
183
  }
170
184
  const text = fs.readFileSync(p, 'utf-8');
171
- if (is_draft(parse_frontmatter(text))) {
185
+ if (is_draft(parse_frontmatter(text)) || is_carrier(parse_frontmatter(text))) {
172
186
  continue;
173
187
  }
174
188
  out.push(p);
@@ -345,6 +359,7 @@ export {
345
359
  CHECKBOX_RE,
346
360
  PHASE_RE,
347
361
  is_draft,
362
+ is_carrier,
348
363
  is_roadmap_candidate,
349
364
  parse_frontmatter,
350
365
  find_active_roadmaps,
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Provenance-declaration gate for the security and safety floors.
4
+ *
5
+ * WHY THIS SCOPE AND NOT ALL 120 RULES. `src/rules/code-provenance.md`
6
+ * § The knowledge layer states the obligation for prose: an artefact asserting
7
+ * an externally-sourced claim either cites it or labels the statement as own
8
+ * analysis, and "silence is neither". That rule also says plainly that nothing
9
+ * enforces it — `lint_harvest_provenance` validates the harvest ledger's own
10
+ * rows and "cannot see a claim nobody recorded". This gate is the structural
11
+ * half for the surface where an unsourced normative claim costs the most.
12
+ *
13
+ * road-to-retired-claims-stay-retired Phase 3.2. The roadmap picked the ten
14
+ * deliberately: holding all 120 at once is the strict-gate-fires-on-everything
15
+ * failure this repository has recorded before, and the ten are the rules whose
16
+ * normative content most plausibly came from outside.
17
+ *
18
+ * WHAT IT CHECKS. Each in-scope rule carries an `evidence:` block with
19
+ * `source_type`, `verified_on` and `normative_level`. The block's SHAPE —
20
+ * enums, the date pattern, unknown keys — is `rule.schema.json`'s job via
21
+ * `validate_frontmatter`, and is deliberately not duplicated here: two
22
+ * validators for one shape drift, and the schema is the one a rule author
23
+ * already runs. This gate owns PRESENCE within a declared scope, which the
24
+ * schema cannot express because the block is optional everywhere else.
25
+ *
26
+ * THE SCOPE IS A LIST, AND THAT IS THE POINT. There is no frontmatter marker
27
+ * that delimits "security and safety floor" — measured 2026-08-30, the ten
28
+ * span three tiers (`2a`, `2b`, `safety-floor`), two `type` values and three
29
+ * pack sets, and `packs: [engineering-base]` also holds rules that are not
30
+ * safety floors. Deriving the scope from a proxy would silently admit and drop
31
+ * rules as unrelated frontmatter moved. An explicit list is reviewable, and a
32
+ * rule joining it is a decision somebody makes rather than a side effect.
33
+ *
34
+ * Exit codes: 0 = every in-scope rule declares · 1 = a declaration is missing
35
+ * or the scope is dead · 2 = usage error.
36
+ *
37
+ * Usage:
38
+ * ./scripts-run src/scripts/check_rule_evidence_declaration
39
+ * ./scripts-run src/scripts/check_rule_evidence_declaration --root <dir>
40
+ * ./scripts-run src/scripts/check_rule_evidence_declaration --self-test
41
+ */
42
+ import * as fs from 'node:fs';
43
+ import * as os from 'node:os';
44
+ import * as path from 'node:path';
45
+ import { fileURLToPath } from 'node:url';
46
+
47
+ import { runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
48
+ import { assertWatchlistResolves, DeadScopeError, reportScanned } from './_lib/scan_scope.js';
49
+
50
+ const _FILE = fileURLToPath(import.meta.url);
51
+ const REPO_ROOT = path.resolve(path.dirname(_FILE), '..', '..');
52
+
53
+ /**
54
+ * The declared scope, with the reason each row is in it.
55
+ *
56
+ * Growing this list is the intended way to widen the obligation: adding a row
57
+ * makes the gate fail until that rule declares, which is exactly the
58
+ * "an eleventh rule added without one fails" behaviour the roadmap asked for.
59
+ */
60
+ export const SCOPE: ReadonlyArray<{ rule: string; why: string }> = [
61
+ { rule: 'security-sensitive-stop', why: 'gates every edit to an auth / tenancy / billing / secrets surface' },
62
+ { rule: 'untrusted-input-defense', why: 'the data-not-instructions boundary; cites OWASP LLM01' },
63
+ { rule: 'lethal-trifecta-guard', why: 'the three-leg exfiltration shape; cites the OWASP ASI list' },
64
+ { rule: 'secret-vcs-guard', why: 'the last gate before a credential reaches history' },
65
+ { rule: 'broken-access-control', why: 'cites OWASP A01:2021 and BOLA/IDOR, and GDPR exposure' },
66
+ { rule: 'tool-safety', why: 'Least Agency; cites OWASP ASI excessive-agency and LLM06' },
67
+ { rule: 'domain-safety-pii', why: 'cites GDPR, CCPA, HIPAA, EEO and a k-anonymity figure' },
68
+ // NOT `non-destructive-by-default`, and the reason is a real constraint on
69
+ // this scope rather than a preference. That rule is `type: "always"`, so its
70
+ // bytes are charged to the kernel budget: adding the four-line block moved
71
+ // it 9,657 -> 9,752 chars and breached `check_always_budget`'s top-3 cap
72
+ // (37,948 > 37,855). An optional frontmatter block is not free on an
73
+ // always-rule, and trimming a kernel rule to make room is a maintainer
74
+ // decision this gate has no business forcing. `domain-safety-retention`
75
+ // takes the slot: same class, `type: "auto"`, and its normative content is
76
+ // more externally sourced than most (GDPR Art. 17, tax and VAT floors).
77
+ { rule: 'domain-safety-retention', why: 'cites GDPR Art. 17 plus tax and VAT retention floors by jurisdiction' },
78
+ { rule: 'engineering-safety-floor', why: 'the production / infra / bulk-destructive floor' },
79
+ { rule: 'code-provenance', why: 'states the knowledge-layer obligation this gate enforces' },
80
+ ];
81
+
82
+ /** Keys every declaration must carry, per rule.schema.json. */
83
+ const REQUIRED_KEYS = ['source_type'] as const;
84
+
85
+ /**
86
+ * `normative_level` is required only where an external source exists.
87
+ *
88
+ * It states how binding the SOURCE is. For `own-analysis` there is no external
89
+ * source, so the field answers a question that does not arise and `informative`
90
+ * is its only coherent value — requiring it there forces a non-answer. The
91
+ * schema draws the same line with an `if`/`then`, and the two are kept in step
92
+ * deliberately rather than one being inferred from the other: a gate that
93
+ * enforced more than the schema would reject a rule the schema accepts.
94
+ */
95
+ const OWN_ANALYSIS = 'own-analysis';
96
+
97
+ export interface Finding {
98
+ rule: string;
99
+ reason: string;
100
+ }
101
+
102
+ /** Extract the frontmatter block of a markdown file, or `null`. */
103
+ function frontmatter(body: string): string | null {
104
+ if (!body.startsWith('---\n')) return null;
105
+ const end = body.indexOf('\n---', 3);
106
+ if (end === -1) return null;
107
+ return body.slice(4, end + 1);
108
+ }
109
+
110
+ /**
111
+ * The `evidence:` mapping's own lines, or `null` when the key is absent.
112
+ *
113
+ * Deliberately a line scan rather than a YAML parse: this gate runs on every
114
+ * `task ci`, the schema validator already parses the same file properly, and a
115
+ * second parser is a second thing that can disagree about the first.
116
+ */
117
+ export function evidenceLines(fm: string): string[] | null {
118
+ const lines = fm.split('\n');
119
+ const start = lines.findIndex((l) => /^evidence:\s*$/.test(l));
120
+ if (start === -1) return null;
121
+ const out: string[] = [];
122
+ for (const line of lines.slice(start + 1)) {
123
+ if (line.trim() === '') continue;
124
+ if (!/^\s+\S/.test(line)) break; // dedented — the block ended
125
+ out.push(line);
126
+ }
127
+ return out;
128
+ }
129
+
130
+ export function analyse(root = REPO_ROOT): Finding[] {
131
+ const findings: Finding[] = [];
132
+ for (const { rule } of SCOPE) {
133
+ const abs = path.join(root, 'src', 'rules', `${rule}.md`);
134
+ let body: string;
135
+ try {
136
+ body = fs.readFileSync(abs, 'utf8');
137
+ } catch {
138
+ findings.push({ rule, reason: 'in scope but the rule file does not exist — remove the row or restore the rule' });
139
+ continue;
140
+ }
141
+ const fm = frontmatter(body);
142
+ if (fm === null) {
143
+ findings.push({ rule, reason: 'no frontmatter block' });
144
+ continue;
145
+ }
146
+ const block = evidenceLines(fm);
147
+ if (block === null) {
148
+ findings.push({
149
+ rule,
150
+ reason:
151
+ 'carries no `evidence:` block — state where its normative content came from, ' +
152
+ 'or record `source_type: own-analysis`, which is a complete discharge',
153
+ });
154
+ continue;
155
+ }
156
+ const has = (key: string): boolean =>
157
+ block.some((l) => new RegExp(`^\\s+${key}:\\s*\\S`).test(l));
158
+ for (const key of REQUIRED_KEYS) {
159
+ if (!has(key)) findings.push({ rule, reason: `evidence block is missing \`${key}\`` });
160
+ }
161
+ const ownAnalysis = block.some((l) => l.includes(`source_type: ${OWN_ANALYSIS}`));
162
+ if (!ownAnalysis && has('source_type')) {
163
+ for (const key of ['normative_level', 'verified_on'] as const) {
164
+ if (has(key)) continue;
165
+ findings.push({
166
+ rule,
167
+ reason:
168
+ `evidence block names an external source but no \`${key}\` — both are real ` +
169
+ 'questions wherever a source exists, and neither is where one does not',
170
+ });
171
+ }
172
+ }
173
+ }
174
+ return findings;
175
+ }
176
+
177
+ function runGate(root: string): number {
178
+ try {
179
+ assertWatchlistResolves({
180
+ gate: 'check_rule_evidence_declaration',
181
+ candidates: SCOPE.map((s) => `src/rules/${s.rule}.md`),
182
+ repoRoot: root,
183
+ });
184
+ } catch (exc) {
185
+ if (!(exc instanceof DeadScopeError)) throw exc;
186
+ process.stderr.write(`❌ ${exc.message}\n`);
187
+ return 1;
188
+ }
189
+ reportScanned({
190
+ gate: 'check_rule_evidence_declaration',
191
+ scanned: SCOPE.length,
192
+ units: 'in-scope rule(s)',
193
+ roots: ['src/rules/'],
194
+ });
195
+ const findings = analyse(root);
196
+ if (findings.length > 0) {
197
+ process.stderr.write(
198
+ `❌ check_rule_evidence_declaration: ${String(findings.length)} finding(s):\n`,
199
+ );
200
+ for (const f of findings) process.stderr.write(` src/rules/${f.rule}.md — ${f.reason}\n`);
201
+ process.stderr.write(
202
+ ' → the block is documented at `evidence` in src/scripts/schemas/rule.schema.json.\n',
203
+ );
204
+ return 1;
205
+ }
206
+ process.stdout.write(
207
+ `✅ check_rule_evidence_declaration: ${String(SCOPE.length)} security/safety rule(s) declare their provenance.\n`,
208
+ );
209
+ return 0;
210
+ }
211
+
212
+ function selfTest(): number {
213
+ const roots: string[] = [];
214
+ const fixture = (frontmatterBody: string, rules = [SCOPE[0]!.rule]): number => {
215
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'rule-evidence-'));
216
+ roots.push(dir);
217
+ fs.mkdirSync(path.join(dir, 'src', 'rules'), { recursive: true });
218
+ // Every in-scope rule must exist or the run fails for the wrong reason;
219
+ // the ones not under test get a well-formed block.
220
+ const good = ['evidence:', ' source_type: own-analysis'].join('\n');
221
+ for (const { rule } of SCOPE) {
222
+ const fm = rules.includes(rule) ? frontmatterBody : good;
223
+ fs.writeFileSync(
224
+ path.join(dir, 'src', 'rules', `${rule}.md`),
225
+ `---\ntype: "auto"\n${fm}\n---\n\n# ${rule}\n`,
226
+ );
227
+ }
228
+ return runGate(dir);
229
+ };
230
+
231
+ const EXT = ['evidence:', ' source_type: external-standard', ' verified_on: 2026-08-30', ' normative_level: recommended'];
232
+ const OWN = ['evidence:', ' source_type: own-analysis'];
233
+
234
+ const cases: SelfTestCase[] = [
235
+ {
236
+ name: 'every in-scope rule declares → accept',
237
+ expect: 'accept',
238
+ run: () => fixture(EXT.join('\n')),
239
+ },
240
+ {
241
+ name: 'an in-scope rule with NO evidence block → reject',
242
+ expect: 'reject',
243
+ run: () => fixture('description: "a rule with no provenance"'),
244
+ },
245
+ {
246
+ // The conditional rule, in the direction that must REJECT: an
247
+ // external source is named, so how binding it is and when it was
248
+ // last checked are both real questions.
249
+ name: 'an external-source block missing normative_level → reject',
250
+ expect: 'reject',
251
+ run: () => fixture(['evidence:', ' source_type: external-standard', ' verified_on: 2026-08-30'].join('\n')),
252
+ },
253
+ {
254
+ name: 'an external-source block missing verified_on → reject',
255
+ expect: 'reject',
256
+ run: () => fixture(['evidence:', ' source_type: external-standard', ' normative_level: recommended'].join('\n')),
257
+ },
258
+ {
259
+ name: 'a source_type present but valueless → reject',
260
+ expect: 'reject',
261
+ run: () => fixture(['evidence:', ' source_type:'].join('\n')),
262
+ },
263
+ {
264
+ // The same shape in the direction that must ACCEPT. `own-analysis`
265
+ // names no external source, so neither field has a question to
266
+ // answer — requiring them there would force a non-answer, and a
267
+ // gate that rejected this would reject what the schema accepts.
268
+ name: 'an own-analysis block with neither field → accept',
269
+ expect: 'accept',
270
+ run: () => fixture(OWN.join('\n')),
271
+ },
272
+ ];
273
+
274
+ try {
275
+ return runSelfTest({
276
+ gate: 'check_rule_evidence_declaration',
277
+ cases,
278
+ minCases: 6,
279
+ minRejectCases: 4,
280
+ });
281
+ } finally {
282
+ for (const d of roots) fs.rmSync(d, { recursive: true, force: true });
283
+ }
284
+ }
285
+
286
+ export function main(argv: string[] = process.argv.slice(2)): number {
287
+ if (argv.includes('--self-test')) return selfTest();
288
+ let root = REPO_ROOT;
289
+ for (let i = 0; i < argv.length; i += 1) {
290
+ const a = argv[i]!;
291
+ if (a === '--root') {
292
+ const v = argv[i + 1];
293
+ if (v === undefined) {
294
+ process.stderr.write('check_rule_evidence_declaration: --root needs a directory\n');
295
+ return 2;
296
+ }
297
+ root = path.resolve(v);
298
+ i += 1;
299
+ } else if (a === '--quiet') {
300
+ continue;
301
+ } else if (a === '-h' || a === '--help') {
302
+ process.stdout.write(
303
+ 'usage: check_rule_evidence_declaration [--root DIR] [--quiet] [--self-test]\n',
304
+ );
305
+ return 0;
306
+ } else {
307
+ process.stderr.write(`check_rule_evidence_declaration: unrecognized argument: ${a}\n`);
308
+ return 2;
309
+ }
310
+ }
311
+ return runGate(root);
312
+ }
313
+
314
+ if (process.argv[1] !== undefined && process.argv[1].includes('check_rule_evidence_declaration')) {
315
+ process.exit(main());
316
+ }
@@ -6,10 +6,20 @@
6
6
  * WHY THIS GATE EXISTS (road-to-conformance-round5 Phase 1, measured 2026-08-07)
7
7
  * ---------------------------------------------------------------------------
8
8
  * `docs/contracts/rule-router.md` (§ "The router earns its place as a
9
- * **compile-time** artifact", measured: zero consumers under
10
- * `src/scripts/hooks/`) states that nothing loads
11
- * `dist/router.json` at runtime, so **projection is the only reach mechanism
12
- * there is**: a non-kernel rule activates by the model's judgment over text
9
+ * **compile-time** artifact") states that under every shipped default nothing
10
+ * loads `dist/router.json` at runtime, so **projection is the only reach
11
+ * mechanism there is**:
12
+ *
13
+ * CORRECTED 2026-08-26. This docblock used to cite that section's "measured:
14
+ * zero consumers under `src/scripts/hooks/`", and that measurement is stale: the
15
+ * `rule-inject` concern reads the router via `_lib/rule_injection.ts:76-79` and
16
+ * is bound on three slots. The gate's rationale survives the correction because
17
+ * the concern is DEFAULT-OFF and returns before reading the router unless
18
+ * `lean_projection.mode: delivery` is set — so on a shipped default, projection
19
+ * IS still the only reach mechanism. What no longer holds is the stronger claim
20
+ * that no such mechanism exists. Stated here rather than quietly re-worded,
21
+ * because a gate whose stated reason rests on a refuted premise is exactly the
22
+ * decoration ADR-127 rejects: a non-kernel rule activates by the model's judgment over text
13
23
  * already in context, and the per-tool rule tree is what puts it there. That
14
24
  * makes the state of the projection load-bearing, and it was broken:
15
25
  *
@@ -63,6 +63,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
63
63
  import * as os from 'node:os';
64
64
  import { parse as parseYaml } from 'yaml';
65
65
  import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
66
+ import { GateLedger } from './_lib/gate_ledger.js';
66
67
 
67
68
  const _FILE = fileURLToPath(import.meta.url);
68
69
  const REPO = path.resolve(path.dirname(_FILE), '..', '..');
@@ -323,37 +324,57 @@ export function checkRubric(rubric: Row, rowCount: number, ids: string[]): Findi
323
324
 
324
325
  /* ── driver ────────────────────────────────────────────────────────────────── */
325
326
 
326
- export function check(rel: string): Finding[] {
327
+ export function check(rel: string, ledger?: GateLedger): Finding[] {
327
328
  // An absolute `--file` must be honoured as given. path.join(REPO, '/abs')
328
329
  // silently produces REPO + '/abs', which reports `missing_file` for a file
329
330
  // that exists — the shape a test using a temp copy hits first.
330
331
  const abs = path.isAbsolute(rel) ? rel : path.join(REPO, rel);
331
332
  if (!fs.existsSync(abs)) {
333
+ ledger?.plan([rel]);
334
+ ledger?.fail(rel, 'scorecard does not exist');
332
335
  return [{ where: rel, code: 'missing_file', detail: 'scorecard does not exist' }];
333
336
  }
334
337
  let doc: unknown;
335
338
  try {
336
339
  doc = parseYaml(fs.readFileSync(abs, 'utf8'));
337
340
  } catch (exc) {
341
+ ledger?.plan([rel]);
342
+ ledger?.fail(rel, 'unparseable YAML');
338
343
  return [{ where: rel, code: 'unparseable', detail: String(exc) }];
339
344
  }
340
345
  if (doc === null || typeof doc !== 'object') {
346
+ ledger?.plan([rel]);
347
+ ledger?.fail(rel, 'top level is not a mapping');
341
348
  return [{ where: rel, code: 'unparseable', detail: 'top level is not a mapping' }];
342
349
  }
343
350
  const top = doc as Row;
344
351
  const rubric = top['rubric'];
345
352
  const cats = top['categories'];
346
353
  if (rubric === undefined || typeof rubric !== 'object' || rubric === null) {
354
+ ledger?.plan([rel]);
355
+ ledger?.fail(rel, 'no `rubric:` block');
347
356
  return [{ where: rel, code: 'missing_field', detail: 'no `rubric:` block' }];
348
357
  }
349
358
  if (!Array.isArray(cats)) {
359
+ ledger?.plan([rel]);
360
+ ledger?.fail(rel, '`categories:` must be a list');
350
361
  return [{ where: rel, code: 'missing_field', detail: '`categories:` must be a list' }];
351
362
  }
352
363
  const rows = cats as Row[];
353
364
  const ids = rows.map((r) => String(r['category'] ?? '<unnamed>'));
365
+ // Per-row accounting. Every early return above aborts BEFORE any row is
366
+ // read, and until this ledger existed those aborts produced a one-line
367
+ // finding indistinguishable, in the coverage record, from a full pass over
368
+ // 23 rows. The ledger separates "checked every row and found one problem"
369
+ // from "never reached a row".
370
+ ledger?.plan(ids.map((id, i) => `${id}#${String(i)}`));
354
371
  const findings = [...checkRubric(rubric as Row, rows.length, ids)];
355
372
  rows.forEach((r, i) => {
356
- findings.push(...checkRow(r, `${rel} → ${ids[i] ?? `row ${i}`}`));
373
+ const target = `${ids[i] ?? '<unnamed>'}#${String(i)}`;
374
+ const rowFindings = checkRow(r, `${rel} → ${ids[i] ?? `row ${i}`}`);
375
+ findings.push(...rowFindings);
376
+ if (rowFindings.length > 0) ledger?.fail(target, `${String(rowFindings.length)} finding(s)`);
377
+ else ledger?.complete(target);
357
378
  });
358
379
  return findings;
359
380
  }
@@ -450,7 +471,9 @@ export function main(argv: readonly string[] = process.argv.slice(2)): number {
450
471
  process.stderr.write('usage: check_score_contract [--quiet] [--file <path>]\n');
451
472
  return 2;
452
473
  }
453
- const findings = check(rel);
474
+ const ledger = new GateLedger('check_score_contract');
475
+ const findings = check(rel, ledger);
476
+ ledger.report(quiet ? () => undefined : undefined);
454
477
  // Rule 1 of the gate-coverage contract: exactly one `scanned: <N>` line,
455
478
  // emitted on the red path too — a gate that only reports coverage when it
456
479
  // passes cannot be caught going blind at the moment it matters.