@event4u/agent-config 14.12.0 → 14.13.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 (466) 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 +234 -0
  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 +109 -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-provenance.md +4 -0
  30. package/dist/agent-src/rules/design-fidelity.md +1 -1
  31. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  32. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  33. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  34. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  35. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  36. package/dist/agent-src/rules/laravel-routing.md +1 -1
  37. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  38. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  39. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  40. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  41. package/dist/agent-src/rules/symfony-routing.md +1 -1
  42. package/dist/agent-src/rules/token-efficiency.md +14 -0
  43. package/dist/agent-src/rules/tool-safety.md +4 -0
  44. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  45. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  46. package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
  47. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  48. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  49. package/dist/agent-src/scripts/stubs_due.ts +400 -0
  50. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  51. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
  52. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  53. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  54. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  55. package/dist/agent-src/skills/database/SKILL.md +8 -0
  56. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  57. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  58. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  59. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  60. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  61. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  62. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  63. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  64. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  65. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  66. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  67. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  68. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  69. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  70. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  71. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  72. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  73. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  74. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  75. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  76. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  77. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  78. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  79. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  80. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  81. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  82. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  83. package/dist/agent-src/templates/roadmaps.md +97 -3
  84. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  85. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  86. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  87. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  88. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  93. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  94. package/dist/cli/commands/uiAudit.js +124 -5
  95. package/dist/cli/registry.js +2 -0
  96. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  97. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  98. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  99. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  100. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  101. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  102. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  103. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  104. package/dist/cli-delegate/cmd_conformance.js +42 -10
  105. package/dist/cli-delegate/cmd_doctor.js +3 -3
  106. package/dist/cli-delegate/cmd_export.js +3 -2
  107. package/dist/cli-delegate/cmd_fleet.js +2 -2
  108. package/dist/cli-delegate/cmd_handoff.js +1 -1
  109. package/dist/cli-delegate/cmd_preflight.js +2 -2
  110. package/dist/cli-delegate/cmd_prune.js +3 -2
  111. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  112. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  113. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  114. package/dist/cli-delegate/cmd_sync.js +3 -2
  115. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  116. package/dist/cli-delegate/cmd_validate.js +3 -2
  117. package/dist/discovery/deprecation-report.md +1 -1
  118. package/dist/discovery/discovery-manifest.json +57 -57
  119. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  120. package/dist/discovery/discovery-manifest.summary.md +1 -1
  121. package/dist/discovery/dormancy-report.md +1 -1
  122. package/dist/discovery/orphan-report.md +1 -1
  123. package/dist/discovery/packs.json +2 -2
  124. package/dist/discovery/trust-report.md +1 -1
  125. package/dist/discovery/workspaces.json +2 -2
  126. package/dist/hooks/dispatch.js +1836 -712
  127. package/dist/install/claudeRuleRewrite.js +254 -0
  128. package/dist/install/detect.js +29 -16
  129. package/dist/install/detect_php_shape.js +159 -0
  130. package/dist/install/install.mjs +634 -428
  131. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  132. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  133. package/dist/mcp/registry-manifest.json +3 -3
  134. package/dist/mcp/server.json +3 -3
  135. package/dist/mcp/server.mjs +4818 -2645
  136. package/dist/server/schemas/settings.js +3 -0
  137. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  138. package/dist/ui/index.html +1 -1
  139. package/docs/MIGRATION.md +1 -1
  140. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  141. package/docs/contracts/provider-lifecycle.md +1 -1
  142. package/docs/contracts/settings-classes.md +10 -4
  143. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  144. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  145. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  146. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  147. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  148. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  149. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  150. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  151. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  152. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  153. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  154. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  155. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  156. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  157. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  158. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  159. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  160. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  161. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  162. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  163. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  164. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  165. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  166. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  167. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  168. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  169. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  170. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  171. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  172. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  173. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  174. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  175. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  176. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  177. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  178. package/docs/guidelines/augment-portability-patterns.md +6 -4
  179. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  180. package/docs/guidelines/cross-role-handoff.md +2 -2
  181. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  182. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  183. package/docs/guidelines/php/database.md +90 -7
  184. package/docs/guidelines/prompt-templates.md +7 -7
  185. package/llms.txt +2 -2
  186. package/package.json +5 -2
  187. package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  188. package/src/agent-src/scripts/guarded_baseline.ts +328 -0
  189. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  190. package/src/agent-src/scripts/stub_queue.ts +82 -0
  191. package/src/agent-src/scripts/stubs_due.ts +400 -0
  192. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  193. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
  194. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  195. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  196. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  197. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  198. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  199. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  202. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  203. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  204. package/src/config/agent-settings.template.yml +32 -3
  205. package/src/config/assurance-capability-registry.json +21 -9
  206. package/src/config/canonical-terms.yml +119 -0
  207. package/src/config/capability-native-outcome-bars.json +81 -0
  208. package/src/config/ci-local-parity.yml +80 -0
  209. package/src/config/drafting-channels.yml +43 -0
  210. package/src/config/estate-count-budget.json +38 -36
  211. package/src/config/evaluator-budgets.json +14 -14
  212. package/src/config/gate-coverage.yml +579 -63
  213. package/src/config/gate-reachability-exemptions.json +21 -0
  214. package/src/config/gate-violation-baselines.json +37 -19
  215. package/src/config/harness-evolution-budget.json +25 -0
  216. package/src/config/lapsed-beta-baseline.json +96 -0
  217. package/src/config/memory-twin-verdicts.yml +129 -0
  218. package/src/config/metric-registry.yml +124 -0
  219. package/src/config/pack-size-budget.json +16 -15
  220. package/src/config/preamble-payload-budget.json +8 -8
  221. package/src/config/profiles/balanced.ini +27 -0
  222. package/src/config/profiles/full.ini +27 -0
  223. package/src/config/profiles/minimal.ini +27 -0
  224. package/src/config/publish-surface.json +9 -2
  225. package/src/config/routing-coverage-seed.json +16 -2
  226. package/src/config/rule-stub-ceilings.json +126 -112
  227. package/src/config/turnaround-budget.json +66 -0
  228. package/src/install/claudeRuleRewrite.ts +288 -0
  229. package/src/install/detect.ts +60 -17
  230. package/src/install/detect_php_shape.ts +191 -0
  231. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  232. package/src/scripts/_dispatch.bash +27 -0
  233. package/src/scripts/_lib/activation_ladder.ts +211 -0
  234. package/src/scripts/_lib/activation_states.ts +88 -0
  235. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  236. package/src/scripts/_lib/arith_claims.ts +181 -0
  237. package/src/scripts/_lib/arm_ranking.ts +62 -0
  238. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  239. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  240. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  241. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  242. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  243. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  244. package/src/scripts/_lib/candidate_record.ts +601 -0
  245. package/src/scripts/_lib/capture_rate.ts +319 -0
  246. package/src/scripts/_lib/collector_denominator.ts +771 -0
  247. package/src/scripts/_lib/collector_record.ts +340 -0
  248. package/src/scripts/_lib/collector_store.ts +664 -0
  249. package/src/scripts/_lib/collector_supervision.ts +827 -0
  250. package/src/scripts/_lib/concern_estate.ts +77 -0
  251. package/src/scripts/_lib/config_chain.ts +477 -0
  252. package/src/scripts/_lib/config_cost.ts +209 -0
  253. package/src/scripts/_lib/council_settings_block.ts +6 -0
  254. package/src/scripts/_lib/curator_ops.ts +172 -0
  255. package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
  256. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  257. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  258. package/src/scripts/_lib/empty_cycles.ts +88 -0
  259. package/src/scripts/_lib/eval_publication.ts +354 -0
  260. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  261. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  262. package/src/scripts/_lib/evidence_basis.ts +118 -0
  263. package/src/scripts/_lib/exec_evidence.ts +8 -0
  264. package/src/scripts/_lib/experience_card.ts +272 -0
  265. package/src/scripts/_lib/experience_report.ts +151 -0
  266. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  267. package/src/scripts/_lib/generated_by.ts +66 -0
  268. package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
  269. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  270. package/src/scripts/_lib/host_denominator.ts +687 -0
  271. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  272. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  273. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  274. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  275. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  276. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  277. package/src/scripts/_lib/loop_guards.ts +299 -0
  278. package/src/scripts/_lib/loss_class.ts +129 -0
  279. package/src/scripts/_lib/machine_wake.ts +51 -0
  280. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  281. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  282. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  283. package/src/scripts/_lib/orchestration_record.ts +253 -5
  284. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  285. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  286. package/src/scripts/_lib/paired_stats.ts +245 -0
  287. package/src/scripts/_lib/paired_verdict.ts +226 -0
  288. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  289. package/src/scripts/_lib/privacy_class.ts +47 -0
  290. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  291. package/src/scripts/_lib/repeated_failure.ts +105 -0
  292. package/src/scripts/_lib/repo_root.ts +111 -0
  293. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  294. package/src/scripts/_lib/role_split.ts +338 -0
  295. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  296. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  297. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  298. package/src/scripts/_lib/source_digest.ts +200 -0
  299. package/src/scripts/_lib/source_redact.ts +260 -0
  300. package/src/scripts/_lib/source_shape.ts +502 -0
  301. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  302. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  303. package/src/scripts/_lib/strip_comments.mjs +65 -0
  304. package/src/scripts/_lib/test_red_state.ts +154 -0
  305. package/src/scripts/_lib/trigger_shift.ts +144 -0
  306. package/src/scripts/_lib/untrusted_content.ts +82 -7
  307. package/src/scripts/adoption_report.ts +1 -1
  308. package/src/scripts/adr/evidence_census.ts +1 -1
  309. package/src/scripts/adr/regenerate_index.ts +26 -2
  310. package/src/scripts/adr_cite_check.ts +164 -1
  311. package/src/scripts/ai_council/blind_review.ts +11 -1
  312. package/src/scripts/ai_council/clients.ts +4 -0
  313. package/src/scripts/ai_council/config.ts +3 -0
  314. package/src/scripts/ai_council/consensus.ts +28 -8
  315. package/src/scripts/ai_council/consensus_round.ts +226 -0
  316. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  317. package/src/scripts/ai_council/inline_findings.ts +340 -0
  318. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  319. package/src/scripts/ai_council/orchestrator.ts +16 -203
  320. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  321. package/src/scripts/ai_council/pricing.ts +106 -0
  322. package/src/scripts/ai_council/prompts.ts +74 -7
  323. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  324. package/src/scripts/ai_council/py_format.ts +14 -3
  325. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  326. package/src/scripts/ai_council/response_record.ts +50 -0
  327. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  328. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  329. package/src/scripts/asset_delivery_ledger.ts +157 -0
  330. package/src/scripts/attest_artifact.ts +193 -0
  331. package/src/scripts/audit_auto_rules.ts +2 -1
  332. package/src/scripts/audit_command_surface.ts +1 -1
  333. package/src/scripts/audit_mcp_tools.ts +2 -2
  334. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  335. package/src/scripts/audit_user_type_axis.ts +2 -1
  336. package/src/scripts/bench_ab_clone.ts +215 -10
  337. package/src/scripts/bench_ab_integrity.ts +119 -5
  338. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  339. package/src/scripts/build_archive_index.ts +1 -1
  340. package/src/scripts/build_linear_digest.ts +1 -1
  341. package/src/scripts/build_proof.ts +11 -4
  342. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  343. package/src/scripts/build_source_digests.ts +157 -0
  344. package/src/scripts/cache_realization_report.ts +103 -0
  345. package/src/scripts/check_adr_frontmatter.ts +126 -0
  346. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  347. package/src/scripts/check_beta_review_markers.ts +235 -6
  348. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  349. package/src/scripts/check_claims.ts +576 -6
  350. package/src/scripts/check_composite_arming.ts +35 -0
  351. package/src/scripts/check_concern_admissions.ts +365 -0
  352. package/src/scripts/check_enforcement_coverage.ts +28 -0
  353. package/src/scripts/check_estate_count.ts +142 -1
  354. package/src/scripts/check_gate_reachability.ts +383 -0
  355. package/src/scripts/check_host_loadability.ts +104 -0
  356. package/src/scripts/check_loss_class_declared.ts +308 -0
  357. package/src/scripts/check_md_language.ts +15 -98
  358. package/src/scripts/check_memory_proposal.ts +18 -11
  359. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  360. package/src/scripts/check_no_external_sources.ts +281 -6
  361. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  362. package/src/scripts/check_pack_size.ts +59 -2
  363. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  364. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  365. package/src/scripts/check_publish_surface.ts +10 -1
  366. package/src/scripts/check_references.ts +24 -1
  367. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  368. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  369. package/src/scripts/check_score_contract.ts +26 -3
  370. package/src/scripts/check_static_parity.ts +285 -0
  371. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  372. package/src/scripts/check_suppression_hygiene.ts +15 -0
  373. package/src/scripts/ci_settle.ts +39 -2
  374. package/src/scripts/code_graph/build.ts +60 -3
  375. package/src/scripts/code_graph/extract.ts +44 -0
  376. package/src/scripts/code_graph/types.ts +24 -0
  377. package/src/scripts/collector_daemon.ts +714 -0
  378. package/src/scripts/config_cost_report.ts +302 -0
  379. package/src/scripts/consumer_matrix.ts +74 -1
  380. package/src/scripts/cost/budget.mjs +10 -3
  381. package/src/scripts/cost/track.mjs +10 -3
  382. package/src/scripts/council_cli.ts +37 -54
  383. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  384. package/src/scripts/evolution_lab.ts +980 -0
  385. package/src/scripts/external_sources_denylist.json +5 -18
  386. package/src/scripts/extract_audit_patterns.ts +21 -0
  387. package/src/scripts/fold_intake.ts +12 -1
  388. package/src/scripts/gen_discovery_baseline.ts +1 -1
  389. package/src/scripts/generate_capabilities_index.ts +12 -5
  390. package/src/scripts/generate_capability_matrix.ts +3 -3
  391. package/src/scripts/generate_command_flows.ts +2 -2
  392. package/src/scripts/generate_cookbook.ts +2 -2
  393. package/src/scripts/generate_index.ts +8 -1
  394. package/src/scripts/generate_knowledge_index.ts +2 -1
  395. package/src/scripts/generate_ownership_matrix.ts +2 -1
  396. package/src/scripts/generate_pack_manifests.ts +10 -2
  397. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  398. package/src/scripts/generate_settings_reference.ts +1 -1
  399. package/src/scripts/git_authorization_hook.ts +22 -1
  400. package/src/scripts/grade_target_readiness.ts +48 -5
  401. package/src/scripts/hook_effect_doctor.ts +261 -0
  402. package/src/scripts/hook_manifest.json +1 -1
  403. package/src/scripts/hook_manifest.yaml +98 -11
  404. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  405. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  406. package/src/scripts/hooks/concern_registry.ts +4 -0
  407. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  408. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  409. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  410. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  411. package/src/scripts/hooks/shims/install.sh +61 -0
  412. package/src/scripts/hooks/shims/php +101 -0
  413. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  414. package/src/scripts/hot_context_hook.ts +16 -0
  415. package/src/scripts/install-hooks.sh +20 -5
  416. package/src/scripts/install.ts +17 -35
  417. package/src/scripts/inventory_frontmatter.ts +2 -1
  418. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  419. package/src/scripts/lint_canonical_terms.ts +604 -0
  420. package/src/scripts/lint_composition_review.ts +619 -0
  421. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  422. package/src/scripts/lint_eval_specs.ts +593 -0
  423. package/src/scripts/lint_hook_manifest.ts +19 -0
  424. package/src/scripts/lint_host_portability.ts +373 -0
  425. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  426. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  427. package/src/scripts/lint_metric_consumers.ts +355 -0
  428. package/src/scripts/lint_skill_descriptions.ts +18 -1
  429. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  430. package/src/scripts/lint_skill_link_reach.ts +252 -0
  431. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  432. package/src/scripts/lint_ticket_buildable.ts +17 -1
  433. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  434. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  435. package/src/scripts/measure_docs_dead_links.ts +348 -0
  436. package/src/scripts/measure_host_capture.ts +461 -0
  437. package/src/scripts/migration_status.ts +3 -3
  438. package/src/scripts/model_rule_injection.ts +60 -0
  439. package/src/scripts/orchestration_record.ts +14 -0
  440. package/src/scripts/preamble_byte_census.ts +139 -10
  441. package/src/scripts/prepack-check.mjs +4 -1
  442. package/src/scripts/probe_turnaround.ts +384 -0
  443. package/src/scripts/probe_unblocked_ask.ts +279 -0
  444. package/src/scripts/render_benchmark_md.ts +1 -1
  445. package/src/scripts/rule_activation_census.ts +70 -9
  446. package/src/scripts/rule_backlinks.ts +1 -1
  447. package/src/scripts/run_lifecycle_suite.ts +208 -0
  448. package/src/scripts/run_skill_evals.ts +40 -0
  449. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  450. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  451. package/src/scripts/schemas/evals.schema.json +24 -1
  452. package/src/scripts/schemas/rule.schema.json +52 -1
  453. package/src/scripts/schemas/skill.schema.json +17 -2
  454. package/src/scripts/skill_overlap.ts +7 -1
  455. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  456. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  457. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  458. package/src/scripts/skill_usage_report.ts +2 -1
  459. package/src/scripts/stubs_due.ts +211 -0
  460. package/src/scripts/sweep_source_surfaces.ts +678 -0
  461. package/src/scripts/sync_pr_branch.ts +3 -3
  462. package/src/scripts/trigger_eval_grandfather.json +202 -222
  463. package/src/scripts/utilization_report.ts +22 -2
  464. package/src/server/schemas/settings.ts +5 -0
  465. package/src/templates/marketing-copy.yml +1 -1
  466. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,383 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Which gate-shaped task targets can CI actually reach?
4
+ *
5
+ * A gate nobody invokes is not a gate. It can be written, registered,
6
+ * documented and red for months while every pipeline stays green — which is
7
+ * exactly what happened to `lint_positioning`, whose closing roadmap step
8
+ * recorded CI wiring that never existed.
9
+ *
10
+ * ## What "reachable" means here
11
+ *
12
+ * A target is reachable when it is in the transitive closure of `task ci`, or
13
+ * when a workflow under `.github/workflows/` invokes it directly. Both halves
14
+ * are needed and neither is sufficient: a workflow-only target never runs in a
15
+ * local `task ci`, and a `task ci`-only target never runs on a PR that skips
16
+ * that job.
17
+ *
18
+ * ## What "gate-shaped" means, and why the predicate is deliberately loose
19
+ *
20
+ * A target whose command runs a `check_*` / `lint_*` / `verify_*` script, or
21
+ * whose name starts with `check-` / `lint-` / `verify-`. Loose on purpose: the
22
+ * cost of a false positive is one classified row saying "variant of X", and the
23
+ * cost of a false negative is precisely the silence this script exists to end.
24
+ *
25
+ * ## Stability
26
+ *
27
+ * Everything is sorted and the parse is line-based over committed files, so two
28
+ * runs on one tree print the same set. That is asserted rather than assumed —
29
+ * the 1.1 verify line asks for it.
30
+ */
31
+
32
+ import * as fs from 'node:fs';
33
+ import * as path from 'node:path';
34
+
35
+ import * as os from 'node:os';
36
+
37
+ import { reportScanned } from './_lib/scan_scope.js';
38
+ import { runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
39
+
40
+ const REPO_ROOT = process.cwd();
41
+ const TASKFILES_DIR = 'taskfiles';
42
+ const ROOT_TASKFILE = 'Taskfile.yml';
43
+ const WORKFLOWS_DIR = '.github/workflows';
44
+
45
+ /** ` <name>:` at two-space indent inside a `tasks:` map — one target. */
46
+ const TARGET_DECL = /^ {2}([a-z_][a-z0-9:_-]*):\s*$/;
47
+ /** `- task: <name>` — a dependency edge. */
48
+ const TASK_EDGE = /^\s*-\s*task:\s*([a-z_][a-z0-9:_-]*)\s*$/;
49
+ /** `defer: { task: <name> }` — also an edge. */
50
+ const DEFER_EDGE = /defer:\s*\{\s*task:\s*([a-z_][a-z0-9:_-]*)\s*\}/;
51
+ /**
52
+ * `deps: [a, b]` — a THIRD edge kind, and one it is easy to miss.
53
+ *
54
+ * Missing it does not merely undercount: it reports a target as unreachable
55
+ * when CI does run it, which is the one error this script must not make. Found
56
+ * by the count disagreeing with the roadmap's own two-command reading.
57
+ */
58
+ const DEPS_EDGE = /^\s*deps:\s*\[([^\]]*)\]/;
59
+ /** `task <name>` inside a workflow `run:` line. */
60
+ const WORKFLOW_CALL = /\btask\s+([a-z_][a-z0-9:_-]*)/g;
61
+
62
+ /** A target is gate-shaped by NAME or by the script its command runs. */
63
+ const GATE_NAME = /^(check|lint|verify)[-:]/;
64
+ const GATE_CMD = /\b(check|lint|verify)_[a-z0-9_]+/;
65
+
66
+ export interface TargetDef {
67
+ name: string;
68
+ /** Targets it depends on. */
69
+ edges: string[];
70
+ /** Raw command lines, for the gate-shape predicate. */
71
+ cmds: string[];
72
+ /** Which file declared it. */
73
+ file: string;
74
+ }
75
+
76
+ function taskfilePaths(root: string): string[] {
77
+ const out = [path.join(root, ROOT_TASKFILE)];
78
+ const dir = path.join(root, TASKFILES_DIR);
79
+ if (fs.existsSync(dir)) {
80
+ for (const f of fs.readdirSync(dir).sort()) {
81
+ if (f.endsWith('.yml') || f.endsWith('.yaml')) out.push(path.join(dir, f));
82
+ }
83
+ }
84
+ return out.filter((p) => fs.existsSync(p));
85
+ }
86
+
87
+ /**
88
+ * Parse targets and their edges.
89
+ *
90
+ * A hand parse rather than a YAML load, deliberately: `task` merges several
91
+ * files into one namespace and the includes carry prefixes, so a structural
92
+ * load would have to reimplement `task`'s own resolution to be more correct
93
+ * than this — and would still be a second implementation of it. Line-based
94
+ * keeps the failure mode legible: a target this misses is absent from BOTH
95
+ * sides of the diff, so it cannot create a false unreachable.
96
+ */
97
+ export function parseTargets(root = REPO_ROOT): Map<string, TargetDef> {
98
+ const defs = new Map<string, TargetDef>();
99
+ for (const file of taskfilePaths(root)) {
100
+ const rel = path.relative(root, file);
101
+ let current: TargetDef | null = null;
102
+ for (const line of fs.readFileSync(file, 'utf-8').split('\n')) {
103
+ const decl = TARGET_DECL.exec(line);
104
+ if (decl !== null) {
105
+ current = { name: decl[1] as string, edges: [], cmds: [], file: rel };
106
+ // Later files win, matching `task`'s own override order.
107
+ defs.set(current.name, current);
108
+ continue;
109
+ }
110
+ if (current === null) continue;
111
+ // A column-0 key ends the tasks block.
112
+ if (/^[a-z_]/.test(line)) {
113
+ current = null;
114
+ continue;
115
+ }
116
+ const deps = DEPS_EDGE.exec(line);
117
+ if (deps !== null) {
118
+ for (const d of (deps[1] as string).split(',')) {
119
+ const t = d.trim().replace(/^["']|["']$/g, '');
120
+ if (t !== '') current.edges.push(t);
121
+ }
122
+ continue;
123
+ }
124
+ const edge = TASK_EDGE.exec(line) ?? DEFER_EDGE.exec(line);
125
+ if (edge !== null) current.edges.push(edge[1] as string);
126
+ else current.cmds.push(line);
127
+ }
128
+ }
129
+ return defs;
130
+ }
131
+
132
+ /** Transitive closure from a set of roots, following `task:` edges. */
133
+ export function closure(defs: Map<string, TargetDef>, roots: readonly string[]): Set<string> {
134
+ const seen = new Set<string>();
135
+ const stack = [...roots];
136
+ while (stack.length > 0) {
137
+ const n = stack.pop() as string;
138
+ if (seen.has(n)) continue;
139
+ seen.add(n);
140
+ for (const e of defs.get(n)?.edges ?? []) if (!seen.has(e)) stack.push(e);
141
+ }
142
+ return seen;
143
+ }
144
+
145
+ /** Every `task <name>` a workflow invokes. */
146
+ export function workflowCalls(root = REPO_ROOT): Set<string> {
147
+ const out = new Set<string>();
148
+ const dir = path.join(root, WORKFLOWS_DIR);
149
+ if (!fs.existsSync(dir)) return out;
150
+ for (const f of fs.readdirSync(dir).sort()) {
151
+ if (!f.endsWith('.yml') && !f.endsWith('.yaml')) continue;
152
+ const text = fs.readFileSync(path.join(dir, f), 'utf-8');
153
+ for (const m of text.matchAll(WORKFLOW_CALL)) out.add(m[1] as string);
154
+ }
155
+ return out;
156
+ }
157
+
158
+ /** Every workflow file's text, concatenated — for direct-script detection. */
159
+ function workflowSources(root: string): string {
160
+ const dir = path.join(root, WORKFLOWS_DIR);
161
+ if (!fs.existsSync(dir)) return '';
162
+ return fs
163
+ .readdirSync(dir)
164
+ .filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'))
165
+ .sort()
166
+ .map((f) => fs.readFileSync(path.join(dir, f), 'utf-8'))
167
+ .join('\n');
168
+ }
169
+
170
+ export function isGateShaped(d: TargetDef): boolean {
171
+ if (GATE_NAME.test(d.name)) return true;
172
+ return d.cmds.some((c) => GATE_CMD.test(c));
173
+ }
174
+
175
+ export interface Reachability {
176
+ /** Gate-shaped targets reachable from `task ci` or a `task <name>` workflow call. */
177
+ reachable: string[];
178
+ /**
179
+ * Target unwired, but the SCRIPT it runs is invoked directly by a workflow.
180
+ *
181
+ * This distinction is the difference between "this gate does not run" and
182
+ * "this convenience alias is not wired", and conflating them overstates the
183
+ * hole by a factor of two on this tree. A workflow step that calls
184
+ * `./scripts-run src/scripts/foo` runs the gate whether or not any task
185
+ * target points at it — the target is then a local ergonomic, not a hole.
186
+ */
187
+ scriptInWorkflow: string[];
188
+ /** Neither the target nor its script is reached. THE SET THIS EXISTS FOR. */
189
+ unreachable: string[];
190
+ }
191
+
192
+ /** The script a target runs, as a repo-relative path, or `null`. */
193
+ export function scriptOf(d: TargetDef): string | null {
194
+ const m = d.cmds.join(' ').match(/src\/scripts\/[a-z0-9_/]+/);
195
+ return m === null ? null : m[0];
196
+ }
197
+
198
+ export function analyse(root = REPO_ROOT): Reachability {
199
+ const defs = parseTargets(root);
200
+ const fromCi = closure(defs, ['ci']);
201
+ const fromWorkflows = workflowCalls(root);
202
+ // A workflow may call a target that itself has dependencies.
203
+ const viaWorkflows = closure(defs, [...fromWorkflows].filter((n) => defs.has(n)));
204
+
205
+ const workflowText = workflowSources(root);
206
+ const reachable: string[] = [];
207
+ const scriptInWorkflow: string[] = [];
208
+ const unreachable: string[] = [];
209
+ for (const [name, d] of [...defs].sort(([a], [b]) => a.localeCompare(b))) {
210
+ if (!isGateShaped(d)) continue;
211
+ if (fromCi.has(name) || viaWorkflows.has(name)) {
212
+ reachable.push(name);
213
+ continue;
214
+ }
215
+ const script = scriptOf(d);
216
+ if (script !== null && workflowText.includes(script)) scriptInWorkflow.push(name);
217
+ else unreachable.push(name);
218
+ }
219
+ return {
220
+ reachable: reachable.sort(),
221
+ scriptInWorkflow: scriptInWorkflow.sort(),
222
+ unreachable: unreachable.sort(),
223
+ };
224
+ }
225
+
226
+ export const EXEMPTIONS_REL = 'src/config/gate-reachability-exemptions.json';
227
+
228
+ /** Targets recorded as deliberately unreachable, id → reason. */
229
+ export function readExemptions(root = REPO_ROOT): Map<string, string> {
230
+ const p = path.join(root, EXEMPTIONS_REL);
231
+ if (!fs.existsSync(p)) return new Map();
232
+ const doc = JSON.parse(fs.readFileSync(p, 'utf-8')) as { exempt?: Record<string, string> };
233
+ return new Map(Object.entries(doc.exempt ?? {}));
234
+ }
235
+
236
+ export interface GateVerdict {
237
+ /** Unreachable and NOT recorded — the failure. */
238
+ unreasoned: string[];
239
+ /** Recorded exemptions that are no longer unreachable — stale rows. */
240
+ stale: string[];
241
+ }
242
+
243
+ /**
244
+ * The gate verdict.
245
+ *
246
+ * Both directions, because a one-way check rots. An unreachable target with no
247
+ * row is the defect this roadmap is about; a row for a target that is now
248
+ * reachable is an exemption nobody withdrew, and a registry full of those stops
249
+ * being read.
250
+ */
251
+ export function gateVerdict(root = REPO_ROOT): GateVerdict {
252
+ const r = analyse(root);
253
+ const exempt = readExemptions(root);
254
+ const unreachable = new Set(r.unreachable);
255
+ return {
256
+ unreasoned: r.unreachable.filter((n) => !exempt.has(n)).sort(),
257
+ stale: [...exempt.keys()].filter((n) => !unreachable.has(n)).sort(),
258
+ };
259
+ }
260
+
261
+ function runGate(root: string): number {
262
+ const v = gateVerdict(root);
263
+ const exempt = readExemptions(root);
264
+ reportScanned({
265
+ gate: 'check_gate_reachability',
266
+ scanned: exempt.size + analyse(root).unreachable.length,
267
+ units: 'exemption row(s) + unreachable target(s)',
268
+ roots: [EXEMPTIONS_REL, ROOT_TASKFILE, TASKFILES_DIR],
269
+ });
270
+ if (v.unreasoned.length === 0 && v.stale.length === 0) {
271
+ process.stdout.write(
272
+ `✅ check_gate_reachability: every unreachable gate target carries a recorded reason ` +
273
+ `(${String(exempt.size)} exempt).\n`,
274
+ );
275
+ return 0;
276
+ }
277
+ for (const n of v.unreasoned) {
278
+ process.stderr.write(
279
+ `❌ ${n} is gate-shaped, unreachable from \`task ci\` and every workflow, and carries ` +
280
+ `no row in ${EXEMPTIONS_REL}. Wire it, or record why it is manual AND what would make it run.\n`,
281
+ );
282
+ }
283
+ for (const n of v.stale) {
284
+ process.stderr.write(
285
+ `❌ ${n} is exempt in ${EXEMPTIONS_REL} but is now reachable. Remove the row — an ` +
286
+ 'exemption nobody withdrew is how a registry stops being read.\n',
287
+ );
288
+ }
289
+ return 1;
290
+ }
291
+
292
+ /**
293
+ * The self-test builds throwaway trees rather than touching this one, so both
294
+ * directions are proven without a canary that has to be removed again.
295
+ */
296
+ function selfTest(): number {
297
+ const roots: string[] = [];
298
+ const fixture = (opts: { target: string; wired: boolean; exempt: Record<string, string> }): number => {
299
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gr-selftest-'));
300
+ roots.push(dir);
301
+ fs.mkdirSync(path.join(dir, TASKFILES_DIR), { recursive: true });
302
+ fs.mkdirSync(path.join(dir, 'src', 'config'), { recursive: true });
303
+ fs.mkdirSync(path.join(dir, WORKFLOWS_DIR), { recursive: true });
304
+ fs.writeFileSync(
305
+ path.join(dir, ROOT_TASKFILE),
306
+ ['tasks:', ' ci:', ' cmds:', ...(opts.wired ? [` - task: ${opts.target}`] : [])].join('\n'),
307
+ 'utf-8',
308
+ );
309
+ fs.writeFileSync(
310
+ path.join(dir, TASKFILES_DIR, 'a.yml'),
311
+ ['tasks:', ` ${opts.target}:`, ' cmd: ./scripts-run src/scripts/check_thing'].join('\n'),
312
+ 'utf-8',
313
+ );
314
+ fs.writeFileSync(
315
+ path.join(dir, EXEMPTIONS_REL),
316
+ JSON.stringify({ exempt: opts.exempt }, null, 2),
317
+ 'utf-8',
318
+ );
319
+ const v = gateVerdict(dir);
320
+ return v.unreasoned.length === 0 && v.stale.length === 0 ? 0 : 1;
321
+ };
322
+
323
+ const cases: SelfTestCase[] = [
324
+ {
325
+ name: 'a wired gate target → accept',
326
+ expect: 'accept',
327
+ run: () => fixture({ target: 'check-x', wired: true, exempt: {} }),
328
+ },
329
+ {
330
+ name: 'an unreachable gate target with no row → reject',
331
+ expect: 'reject',
332
+ run: () => fixture({ target: 'check-x', wired: false, exempt: {} }),
333
+ },
334
+ {
335
+ name: 'an unreachable gate target WITH a row → accept',
336
+ expect: 'accept',
337
+ run: () => fixture({ target: 'check-x', wired: false, exempt: { 'check-x': 'a stated reason' } }),
338
+ },
339
+ {
340
+ // The other direction. Without it a registry accumulates rows for
341
+ // targets that were wired long ago, and stops being read.
342
+ name: 'a row for a target that IS reachable → reject (stale exemption)',
343
+ expect: 'reject',
344
+ run: () => fixture({ target: 'check-x', wired: true, exempt: { 'check-x': 'stale' } }),
345
+ },
346
+ ];
347
+ try {
348
+ return runSelfTest({ gate: 'check_gate_reachability', cases, minCases: 4, minRejectCases: 2 });
349
+ } finally {
350
+ for (const d of roots) fs.rmSync(d, { recursive: true, force: true });
351
+ }
352
+ }
353
+
354
+ export function main(argv: string[] = process.argv.slice(2), root = REPO_ROOT): number {
355
+ if (argv.includes('--self-test')) return selfTest();
356
+ if (argv.includes('--gate')) return runGate(root);
357
+ const r = analyse(root);
358
+ if (argv.includes('--json')) {
359
+ process.stdout.write(`${JSON.stringify(r, null, 2)}\n`);
360
+ return 0;
361
+ }
362
+ // Emitted on the DEFAULT invocation too, not only under `--gate`: the
363
+ // coverage gate reads a bare run, and a gate that reports what it inspected
364
+ // only in one mode is a gate that reports nothing in the other.
365
+ reportScanned({
366
+ gate: 'check_gate_reachability',
367
+ scanned: readExemptions(root).size + r.unreachable.length,
368
+ units: 'exemption row(s) + unreachable target(s)',
369
+ roots: [EXEMPTIONS_REL, ROOT_TASKFILE, TASKFILES_DIR],
370
+ });
371
+ const total = r.reachable.length + r.scriptInWorkflow.length + r.unreachable.length;
372
+ process.stdout.write(
373
+ `gate-shaped targets: ${String(total)} · target-reachable ${String(r.reachable.length)} · ` +
374
+ `script-runs-in-workflow ${String(r.scriptInWorkflow.length)} · ` +
375
+ `UNREACHABLE ${String(r.unreachable.length)}\n`,
376
+ );
377
+ for (const n of r.unreachable) process.stdout.write(` · ${n}\n`);
378
+ return 0;
379
+ }
380
+
381
+ if (process.argv[1] !== undefined && process.argv[1].includes('check_gate_reachability')) {
382
+ process.exit(main());
383
+ }
@@ -16,8 +16,13 @@ import * as path from 'node:path';
16
16
 
17
17
  import { parse as parseYaml } from 'yaml';
18
18
 
19
+ import { GateLedger } from './_lib/gate_ledger.js';
20
+ import { runGateCli, runSelfTest } from './_lib/gate_self_test.js';
21
+ import { HOST_SURFACES, measureReach } from './_lib/host_projection_reach.js';
19
22
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
20
23
 
24
+ const REPO_ROOT = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
25
+
21
26
  /** @returns how many skill directories were examined. */
22
27
  export function check_claude_skills(root: string, errors: string[]): number {
23
28
  const dir = path.join(root, '.claude', 'skills');
@@ -84,11 +89,110 @@ export function run(root: string): string[] {
84
89
  return errors;
85
90
  }
86
91
 
92
+ /**
93
+ * `--reach`: per-host projection reach, with a NAMED reason for every host that
94
+ * carries nothing (road-to-skill-ecosystem-runtime-enforcement Phase 3 Step 1).
95
+ *
96
+ * The shape checks above answer "is what exists well-formed". This answers "does
97
+ * anything exist, and if not, is the tool absent or the projection dead" — two
98
+ * findings the shape checks report as the same green, because a checker that
99
+ * returns early on a missing tree cannot distinguish them.
100
+ *
101
+ * A dead projection for a PRESENT tool fails. An absent tool is a ledger SKIP
102
+ * with its detection signals named, never a silent zero.
103
+ */
104
+ export function runReach(root: string): { failures: string[]; scanned: number } {
105
+ const ledger = new GateLedger('check_host_loadability:reach');
106
+ ledger.plan(HOST_SURFACES.map((s) => s.id));
107
+ const failures: string[] = [];
108
+ for (const r of measureReach(root)) {
109
+ if (r.status === 'ok') {
110
+ ledger.complete(r.id);
111
+ continue;
112
+ }
113
+ if (r.status === 'skipped-tool-absent') {
114
+ // `precondition_unmet` rather than a new code: the closed union in
115
+ // `_lib/gate_ledger.ts` is the audit surface, and an absent host
116
+ // tool IS a precondition that settled the verdict before the
117
+ // projection could be inspected. Widening the union for one caller
118
+ // would make the ledger's vocabulary grow per gate, which is the
119
+ // property that keeps `SKIP_REASON_MESSAGE` readable.
120
+ ledger.skip(r.id, 'precondition_unmet');
121
+ continue;
122
+ }
123
+ ledger.fail(r.id, r.reason);
124
+ failures.push(`${r.id}: ${r.reason}`);
125
+ }
126
+ ledger.report();
127
+ return { failures, scanned: HOST_SURFACES.length };
128
+ }
129
+
130
+
131
+ /**
132
+ * Self-test — proof that the reach mode's REJECTIONS still fire.
133
+ *
134
+ * Required by the `gate-self-test:registered-non-adopters` ratchet, and worth
135
+ * having independently: an enforced `scanned:` floor proves the gate READ
136
+ * something, and only a self-test proves the reading changes the verdict.
137
+ *
138
+ * **One case is deliberately absent and the reason is a real limit.** The
139
+ * verdict this mode exists for — an INSTALLED tool whose projection directory
140
+ * is empty — cannot be built from a fixture root, because presence is read from
141
+ * the machine (`PATH` and `$HOME`), not from the tree under test. A fixture can
142
+ * make a projection empty; it cannot make a tool installed. The rejecting case
143
+ * below is therefore the dead-scope one, and the discriminating half rests on
144
+ * the live measurement, which reports every surface with its own verdict.
145
+ */
146
+ function reachSelfTest(): number {
147
+ const tmp = fs.mkdtempSync(path.join(REPO_ROOT, '.host-reach-selftest-'));
148
+ const invoke = (dir: string): number =>
149
+ runGateCli(
150
+ REPO_ROOT,
151
+ 'src/scripts/check_host_loadability.ts',
152
+ ['--reach', '--root', dir],
153
+ REPO_ROOT,
154
+ );
155
+ try {
156
+ return runSelfTest({
157
+ gate: 'check_host_loadability',
158
+ minCases: 2,
159
+ minRejectCases: 1,
160
+ cases: [
161
+ {
162
+ name: 'a root carrying no host projection at all is REFUSED, never passed',
163
+ expect: 'reject',
164
+ run: () => invoke(tmp),
165
+ },
166
+ {
167
+ name: 'this repository accounts for every host surface',
168
+ expect: 'accept',
169
+ run: () => invoke(REPO_ROOT),
170
+ },
171
+ ],
172
+ });
173
+ } finally {
174
+ fs.rmSync(tmp, { recursive: true, force: true });
175
+ }
176
+ }
177
+
87
178
  const isMain = process.argv[1] !== undefined
88
179
  && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname);
89
180
  if (isMain) {
90
181
  const rootIdx = process.argv.indexOf('--root');
91
182
  const root = rootIdx !== -1 ? process.argv[rootIdx + 1] ?? '.' : '.';
183
+ if (process.argv.includes('--self-test')) {
184
+ process.exit(reachSelfTest());
185
+ }
186
+ if (process.argv.includes('--reach')) {
187
+ const { failures, scanned } = runReach(root);
188
+ process.stdout.write(`scanned: ${String(scanned)}\n`);
189
+ if (failures.length > 0) {
190
+ for (const f of failures) process.stderr.write(`❌ ${f}\n`);
191
+ process.exit(1);
192
+ }
193
+ process.stdout.write(`✅ host projection reach: ${String(scanned)} host surface(s) accounted for\n`);
194
+ process.exit(0);
195
+ }
92
196
  let errors: string[];
93
197
  try {
94
198
  errors = run(root);