@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,279 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * The unblocked-ask rate — the class `user-interaction` measured and then had
4
+ * no instrument for.
5
+ *
6
+ * ## Why this one, and not one of the other 55
7
+ *
8
+ * `road-to-undeclared-obligation-disposition` Phase 2.1 ranks the
9
+ * `cheaply-probeable` bucket by MEASURED failure rather than by feel, and the
10
+ * ranking is lopsided: of 56 rules in that bucket, exactly **one** carries a
11
+ * cited measurement of its own failure. `user-interaction.md:75` records a
12
+ * 30-session conformance audit in which **every** malformed ask was a one-line
13
+ * parenthetical or a trailing free-text offer, and states that **no gate ships**
14
+ * for that class because `check_reply_consistency` inspects numbered-option
15
+ * blocks — "exactly the surface that did not fail".
16
+ *
17
+ * That is the whole case for building this and not a fourth probe. Phase 2.3
18
+ * caps the roadmap at one.
19
+ *
20
+ * ## What is counted
21
+ *
22
+ * A **hand-back** assistant turn — one immediately followed by a genuine user
23
+ * turn, i.e. where the agent actually stopped — that HANDS A DECISION and
24
+ * carries **no** numbered-options block. The rule's own § "The trigger is a
25
+ * decision, not a format" says the obligation fires on handing a decision in any
26
+ * form, so a trailing offer is an ask and owes a recommendation line.
27
+ *
28
+ * Of those, an ask is **malformed** when no recommendation line follows it.
29
+ *
30
+ * ## Honest bounds, and they are wide
31
+ *
32
+ * 1. **"Hands a decision" is a heuristic.** It matches offer shapes — *"soll ich
33
+ * …?"*, *"shall I …?"*, *"sag Bescheid, wenn …"*, *"willst du …?"* — anchored
34
+ * in the closing lines. A genuine clarifying question is deliberately NOT
35
+ * excluded, because `user-interaction` treats a bare yes/no as an ask too.
36
+ * Some rhetorical questions will be counted. The rate is therefore a
37
+ * CEILING for malformed asks of this class, not a point estimate.
38
+ * 2. **Turns WITH a numbered block are excluded**, not judged. That surface
39
+ * already has `check_reply_consistency`; measuring it here would double-count
40
+ * a covered class and hide the uncovered one.
41
+ * 3. **A recommendation line is matched on the label**, `Recommendation:` or
42
+ * `Empfehlung:` (with or without emphasis). A recommendation phrased without
43
+ * the label reads as malformed here. The rule requires the label — a
44
+ * wrong-language label is explicitly "no recommendation" — so this is the
45
+ * rule's own bar, but it is a bar on FORM.
46
+ *
47
+ * Both edges are printed. A reader who cannot see the bracket cannot judge the
48
+ * number.
49
+ *
50
+ * Usage:
51
+ * ./scripts-run src/scripts/probe_unblocked_ask [--limit N] [--store PATH] [--json]
52
+ * ./scripts-run src/scripts/probe_unblocked_ask --self-test
53
+ *
54
+ * Exit codes: 0 always — a measurement, not a gate. `--self-test` exits 1 when
55
+ * the detector fails to fire on its fixtures.
56
+ */
57
+ import fs from 'node:fs';
58
+ import path from 'node:path';
59
+ import { pathToFileURL } from 'node:url';
60
+
61
+ import { defaultStore, HARNESS_TEXT, isInjectedBody } from './conformance_scan.js';
62
+ import { isSyntheticPrompt } from './_lib/prompt_shape.js';
63
+
64
+ /** A numbered-options block — the surface `check_reply_consistency` already reads. */
65
+ export const NUMBERED_BLOCK = /^\s{0,3}(\d+)[.)]\s+\S/m;
66
+
67
+ /** The recommendation line, matched on its label. Either language. */
68
+ export const RECOMMENDATION = /^\s{0,3}\**\s*(Recommendation|Empfehlung)\s*:?\**/im;
69
+
70
+ /**
71
+ * Offer shapes that hand a decision without a block. Every one of these is a
72
+ * shape the 2026-08-06 audit found in a REAL malformed ask.
73
+ */
74
+ export const OFFER_SHAPES: readonly RegExp[] = [
75
+ /\bsoll(en)? ich\b[^.!?]{0,120}\?/i,
76
+ /\bwillst du\b[^.!?]{0,120}\?/i,
77
+ /\bm(ö|oe)chtest du\b[^.!?]{0,120}\?/i,
78
+ /\bsag (mir )?bescheid,? (wenn|ob|falls)\b/i,
79
+ /\bwenn du (willst|m(ö|oe)chtest),? (dann )?(mache|kann|nehme|ziehe)\b/i,
80
+ /\bshall i\b[^.!?]{0,120}\?/i,
81
+ /\bshould i\b[^.!?]{0,120}\?/i,
82
+ /\bdo you want me to\b[^.!?]{0,120}\?/i,
83
+ /\bwould you like me to\b[^.!?]{0,120}\?/i,
84
+ /\blet me know (if|whether)\b/i,
85
+ ];
86
+
87
+ interface Turn {
88
+ role: 'user' | 'assistant';
89
+ text: string;
90
+ at: string;
91
+ }
92
+
93
+ function turns(lines: string[]): Turn[] {
94
+ const out: Turn[] = [];
95
+ for (const line of lines) {
96
+ if (!line.trim()) continue;
97
+ let e: Record<string, unknown>;
98
+ try {
99
+ e = JSON.parse(line) as Record<string, unknown>;
100
+ } catch {
101
+ continue;
102
+ }
103
+ if (e['isSidechain'] === true) continue;
104
+ if (e['type'] === 'user' && e['toolUseResult'] !== undefined) continue;
105
+ if (e['isCompactSummary'] === true) continue;
106
+ const msg = e['message'] as { role?: string; content?: unknown } | undefined;
107
+ const role = msg?.role;
108
+ if (role !== 'user' && role !== 'assistant') continue;
109
+ const c = msg?.content;
110
+ const text =
111
+ typeof c === 'string'
112
+ ? c
113
+ : Array.isArray(c)
114
+ ? c
115
+ .filter((b: { type?: string }) => b?.type === 'text')
116
+ .map((b: { text?: string }) => b.text ?? '')
117
+ .join('\n')
118
+ : '';
119
+ if (!text.trim()) continue;
120
+ if (role === 'assistant' && HARNESS_TEXT.test(text.trim())) continue;
121
+ if (role === 'user' && (isSyntheticPrompt(text) || isInjectedBody(text))) continue;
122
+ out.push({ role, text, at: String(e['timestamp'] ?? '') });
123
+ }
124
+ return out;
125
+ }
126
+
127
+ export interface AskVerdict {
128
+ /** The turn hands a decision with no numbered block. */
129
+ unblockedAsk: boolean;
130
+ /** …and carries no recommendation label. */
131
+ malformed: boolean;
132
+ }
133
+
134
+ /** Classify one assistant hand-back's closing lines. */
135
+ export function classifyTail(tail: string): AskVerdict {
136
+ if (NUMBERED_BLOCK.test(tail)) return { unblockedAsk: false, malformed: false };
137
+ const offers = OFFER_SHAPES.some((re) => re.test(tail));
138
+ if (!offers) return { unblockedAsk: false, malformed: false };
139
+ return { unblockedAsk: true, malformed: !RECOMMENDATION.test(tail) };
140
+ }
141
+
142
+ export interface Result {
143
+ handbacks: number;
144
+ withBlock: number;
145
+ unblockedAsks: number;
146
+ malformed: number;
147
+ samples: { session: string; at: string; span: string }[];
148
+ }
149
+
150
+ export function measure(store: string, limit: number): Result {
151
+ const r: Result = { handbacks: 0, withBlock: 0, unblockedAsks: 0, malformed: 0, samples: [] };
152
+ let files: string[];
153
+ try {
154
+ files = fs.readdirSync(store).filter((f) => f.endsWith('.jsonl'));
155
+ } catch {
156
+ return r;
157
+ }
158
+ const ordered = files
159
+ .map((f) => ({ f, m: fs.statSync(path.join(store, f)).mtimeMs }))
160
+ .sort((a, b) => b.m - a.m)
161
+ .slice(0, limit)
162
+ .map((x) => x.f);
163
+
164
+ for (const f of ordered) {
165
+ const session = f.replace(/\.jsonl$/, '').slice(0, 8);
166
+ const ts = turns(fs.readFileSync(path.join(store, f), 'utf8').split('\n'));
167
+ for (let i = 0; i < ts.length; i += 1) {
168
+ const t = ts[i] as Turn;
169
+ if (t.role !== 'assistant') continue;
170
+ const next = ts[i + 1];
171
+ if (next !== undefined && next.role !== 'user') continue;
172
+ r.handbacks += 1;
173
+ // Closing lines only: an offer buried mid-reply is not the hand-back.
174
+ const tail = t.text.trimEnd().split('\n').slice(-8).join('\n');
175
+ if (NUMBERED_BLOCK.test(tail)) {
176
+ r.withBlock += 1;
177
+ continue;
178
+ }
179
+ const v = classifyTail(tail);
180
+ if (!v.unblockedAsk) continue;
181
+ r.unblockedAsks += 1;
182
+ if (v.malformed) {
183
+ r.malformed += 1;
184
+ if (r.samples.length < 5) {
185
+ const hit = OFFER_SHAPES.find((re) => re.test(tail));
186
+ r.samples.push({
187
+ session,
188
+ at: t.at,
189
+ span: (tail.match(hit as RegExp)?.[0] ?? '').slice(0, 110),
190
+ });
191
+ }
192
+ }
193
+ }
194
+ }
195
+ return r;
196
+ }
197
+
198
+ /**
199
+ * Prove the detector fires, and prove it stays silent where it must.
200
+ *
201
+ * An instrument never seen fire has unknown sensitivity — and one that fires on
202
+ * everything measures nothing, which is why the negative cases are here too.
203
+ */
204
+ export function selfTest(): number {
205
+ const cases: Array<[string, string, boolean, boolean]> = [
206
+ ['a trailing German offer with no recommendation', 'Fertig.\n\nSag Bescheid, wenn ich die drei Zeilen mitnehmen soll.', true, true],
207
+ ['a bare yes/no offer', 'Der Branch ist grün.\n\nSoll ich das so umsetzen?', true, true],
208
+ ['an English trailing offer', 'Done.\n\nLet me know if you want the second half too.', true, true],
209
+ ['an offer WITH a recommendation label', 'Soll ich das so umsetzen?\n\n**Empfehlung:** ja, es ist reversibel.', true, false],
210
+ ['a numbered block is excluded — another gate reads it', '1. do it\n2. skip it\n\nRecommendation: 1', false, false],
211
+ ['an ordinary statement hands nothing', 'Fixed the schema lint; force-pushed b17c4ef8.', false, false],
212
+ ['a question about the code is not an offer to act', 'Why does this function take a callback?', false, false],
213
+ ];
214
+ let failed = 0;
215
+ for (const [name, tail, wantAsk, wantMalformed] of cases) {
216
+ const v = classifyTail(tail);
217
+ const ok = v.unblockedAsk === wantAsk && v.malformed === wantMalformed;
218
+ process.stdout.write(
219
+ `${ok ? '✅' : '❌'} ${name} — ask=${String(v.unblockedAsk)} malformed=${String(v.malformed)}` +
220
+ (ok ? '\n' : ` (wanted ask=${String(wantAsk)} malformed=${String(wantMalformed)})\n`),
221
+ );
222
+ if (!ok) failed += 1;
223
+ }
224
+ const positives = cases.filter((c) => c[3]).length;
225
+ if (positives < 3) {
226
+ process.stderr.write('❌ probe_unblocked_ask --self-test: fewer than 3 positive cases — a truncated suite must fail.\n');
227
+ return 1;
228
+ }
229
+ process.stdout.write(
230
+ `\nprobe_unblocked_ask --self-test: ${String(cases.length - failed)}/${String(cases.length)} case(s) behaved ` +
231
+ `(${String(positives)} positive, ${String(cases.length - positives)} negative)\n`,
232
+ );
233
+ return failed > 0 ? 1 : 0;
234
+ }
235
+
236
+ export function main(argv: string[]): number {
237
+ let limit = 60;
238
+ let storeArg: string | null = null;
239
+ let json = false;
240
+ for (let i = 0; i < argv.length; i += 1) {
241
+ const a = argv[i] as string;
242
+ if (a === '--limit') limit = Number(argv[++i]);
243
+ else if (a === '--store') storeArg = String(argv[++i]);
244
+ else if (a === '--json') json = true;
245
+ // --self-test runs BEFORE the store is resolved: the fixtures are
246
+ // in-process, and resolving a transcript store that may not exist here
247
+ // would make the sensitivity proof depend on the host having one.
248
+ else if (a === '--self-test') return selfTest();
249
+ else {
250
+ process.stderr.write(`probe_unblocked_ask: unrecognized argument: ${a}\n`);
251
+ return 0;
252
+ }
253
+ }
254
+ const store = storeArg ?? defaultStore(process.cwd());
255
+ const r = measure(store, limit);
256
+ if (json) {
257
+ process.stdout.write(`${JSON.stringify(r, null, 2)}\n`);
258
+ return 0;
259
+ }
260
+ const pct = (n: number, d: number): string => (d === 0 ? 'n/a' : `${((100 * n) / d).toFixed(1)}%`);
261
+ process.stdout.write(
262
+ `probe_unblocked_ask · ${String(limit)} most recent session(s) under ${store}\n` +
263
+ ` hand-back turns ${String(r.handbacks)}\n` +
264
+ ` …with a numbered block ${String(r.withBlock)} (excluded — check_reply_consistency reads that surface)\n` +
265
+ ` …unblocked asks ${String(r.unblockedAsks)} ${pct(r.unblockedAsks, r.handbacks)} of hand-backs\n` +
266
+ ` …of those, malformed ${String(r.malformed)} ${pct(r.malformed, r.unblockedAsks)} of unblocked asks\n` +
267
+ '\n CEILING, not a point estimate: "hands a decision" is a heuristic and a\n' +
268
+ ' rhetorical question can match it. A recommendation is matched on its LABEL,\n' +
269
+ ' which is the rule\'s own bar but a bar on form.\n',
270
+ );
271
+ for (const s of r.samples) {
272
+ process.stdout.write(` · ${s.session} ${s.at}: ${s.span}\n`);
273
+ }
274
+ return 0;
275
+ }
276
+
277
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
278
+ process.exit(main(process.argv.slice(2)));
279
+ }
@@ -617,7 +617,7 @@ export function render(quiet = false): number {
617
617
  const parts = [
618
618
  '# Package-Impact A/B Benchmark',
619
619
  '',
620
- '> Generated by `scripts/render_benchmark_md.py`. Source of truth: ' +
620
+ '> Generated by `render_benchmark_md`. Do not edit. Source of truth: ' +
621
621
  '`internal/bench/reports/ab/`. Re-render anytime with `task bench:ab:diff`.',
622
622
  '',
623
623
  render_headline(trackA, trackB, trackBRdp),
@@ -58,6 +58,7 @@ import * as fs from 'node:fs';
58
58
  import * as path from 'node:path';
59
59
  import { fileURLToPath, pathToFileURL } from 'node:url';
60
60
 
61
+ import { isExclusivelyPackageOnly } from '../install/partitionEligibility.js';
61
62
  import { _claude_paths_plan, _has_non_path_trigger, _parse_frontmatter } from './condense.js';
62
63
 
63
64
  const RULES_DIR = path.join('src', 'rules');
@@ -83,6 +84,13 @@ export interface RuleActivation {
83
84
  emitted_globs: string[];
84
85
  /** Patterns the emitter deliberately drops, with the reason it records. */
85
86
  dropped: { pattern: string; reason: string }[];
87
+ /**
88
+ * Scoped to this package alone, so ADR-236 withholds it from every global
89
+ * host layer. Load-bearing for the projection comparison: a package-only
90
+ * rule is counted by the source verdict and is absent from a delivered
91
+ * tree by design, not by drift.
92
+ */
93
+ package_only: boolean;
86
94
  /**
87
95
  * The emitter's verdict in one word.
88
96
  * `scoped` — loads on a path match · `unconditional` — loads every session ·
@@ -111,7 +119,11 @@ function _declares(meta: Record<string, unknown>, keys: readonly string[]): bool
111
119
  }
112
120
 
113
121
  /** Classify one rule file through the emitter's own exported decision path. */
114
- export function classify_rule(id: string, content: string): RuleActivation {
122
+ export function classify_rule(
123
+ id: string,
124
+ content: string,
125
+ package_only = false,
126
+ ): RuleActivation {
115
127
  const [meta] = _parse_frontmatter(content);
116
128
  const plan = _claude_paths_plan(meta);
117
129
  const has_path_trigger = _declares(meta, PATH_TRIGGER_KEYS);
@@ -139,6 +151,7 @@ export function classify_rule(id: string, content: string): RuleActivation {
139
151
  emitted_globs: plan.globs,
140
152
  dropped: plan.dropped.map((d) => ({ pattern: d.pattern, reason: d.reason })),
141
153
  verdict,
154
+ package_only,
142
155
  };
143
156
  }
144
157
 
@@ -150,7 +163,11 @@ export function census(root: string): RuleActivation[] {
150
163
  .map((e) => e.name)
151
164
  .sort();
152
165
  return files.map((f) =>
153
- classify_rule(f.replace(/\.md$/, ''), fs.readFileSync(path.join(dir, f), 'utf8')),
166
+ classify_rule(
167
+ f.replace(/\.md$/, ''),
168
+ fs.readFileSync(path.join(dir, f), 'utf8'),
169
+ isExclusivelyPackageOnly(path.join(dir, f)),
170
+ ),
154
171
  );
155
172
  }
156
173
 
@@ -223,10 +240,14 @@ export function main(): number {
223
240
 
224
241
  const rows = census(root);
225
242
  const sum = summarize(rows);
243
+ const resolved_projection_dir =
244
+ projection_dir === undefined || projection_dir === null || projection_dir === ''
245
+ ? ''
246
+ : path.isAbsolute(projection_dir)
247
+ ? projection_dir
248
+ : path.join(root, projection_dir);
226
249
  const projection = projection_dir
227
- ? projection_reading(path.isAbsolute(projection_dir)
228
- ? projection_dir
229
- : path.join(root, projection_dir))
250
+ ? projection_reading(resolved_projection_dir)
230
251
  : null;
231
252
 
232
253
  if (as_json) {
@@ -259,11 +280,51 @@ export function main(): number {
259
280
  `\n host projection at ${projection_dir} — reported SEPARATELY, not merged:\n` +
260
281
  ` files ${projection.files} · declaring paths: ${projection.with_paths}\n`,
261
282
  );
262
- if (projection.with_paths !== sum.scoped) {
283
+ // The source verdict counts EVERY rule in `src/rules/`. A GLOBAL host
284
+ // layer does not carry the package-only ones: ADR-236 partitions them to
285
+ // the project layer, so such a tree is expected to be short by exactly
286
+ // that many. Comparing the raw counts reported a divergence on every
287
+ // partitioned install forever — the emitter was right and the
288
+ // comparator was not subtracting.
289
+ //
290
+ // But the subtraction is NOT unconditional, and making it so was its own
291
+ // regression (completion review, 2026-08-30): a full or project-layer
292
+ // projection — which is also the fail-safe default `partitionEligibility`
293
+ // returns on a fresh checkout, an absent install record, or a version or
294
+ // fingerprint mismatch — DOES carry those rules, and for this repo's own
295
+ // project layer `source-of-truth` is the one rule delivered there and the
296
+ // only one declaring `paths:`. Subtracting it there inverts the line.
297
+ //
298
+ // So the partition is DETECTED from the projection rather than assumed:
299
+ // if a package-only rule's file is present, this is not a global layer.
300
+ const pkg_only_ids = rows.filter((r) => r.package_only).map((r) => r.id);
301
+ const partitioned = !pkg_only_ids.some((id) =>
302
+ fs.existsSync(path.join(resolved_projection_dir, `${id}.md`)),
303
+ );
304
+ const scoped_pkg_only = partitioned
305
+ ? rows.filter((r) => r.verdict === 'scoped' && r.package_only)
306
+ : [];
307
+ const expected = sum.scoped - scoped_pkg_only.length;
308
+ if (scoped_pkg_only.length > 0) {
309
+ process.stdout.write(
310
+ ` source scopes ${sum.scoped}; ${scoped_pkg_only.length} of those ` +
311
+ `${scoped_pkg_only.length === 1 ? 'is' : 'are'} package-only and never\n` +
312
+ ` delivered (${scoped_pkg_only.map((r) => r.id).join(', ')}), so a ` +
313
+ `partitioned projection is\n expected to declare ${expected}.\n`,
314
+ );
315
+ }
316
+ if (projection.with_paths !== expected) {
317
+ process.stdout.write(
318
+ ` ⚠️ diverges from the source verdict (${expected} expected` +
319
+ `${scoped_pkg_only.length > 0 ? `, ${sum.scoped} before the package-only partition` : ''}).\n` +
320
+ ` A projection carries no record of the scope or commit it was generated\n` +
321
+ ` at, so this is a reason to regenerate it — never a reading of the\n` +
322
+ ` emitter.\n`,
323
+ );
324
+ } else {
263
325
  process.stdout.write(
264
- ` ⚠️ diverges from the source verdict (${sum.scoped} scoped). A projection\n` +
265
- ` carries no record of the scope or commit it was generated at, so this\n` +
266
- ` is a reason to regenerate it — never a reading of the emitter.\n`,
326
+ ` ✅ consistent with the source verdict (${expected} expected, ` +
327
+ `${projection.with_paths} found).\n`,
267
328
  );
268
329
  }
269
330
  } else if (projection_dir) {
@@ -228,7 +228,7 @@ export function render(
228
228
  validation: ValidationResult = validate_targets(byTarget),
229
229
  ): string {
230
230
  const L: string[] = [];
231
- L.push('<!-- GENERATED by src/scripts/rule_backlinks.ts — do NOT hand-edit.');
231
+ L.push('<!-- GENERATED by rule_backlinks — do NOT hand-edit.');
232
232
  L.push(' Regenerate after each P4 migration batch. Report-only. -->');
233
233
  L.push('');
234
234
  L.push('# Rule backlinks — which rules route here');
@@ -0,0 +1,208 @@
1
+ /**
2
+ * run_lifecycle_suite — run the process-level lifecycle suite and write the
3
+ * evidence artifact `check_supervision_claim_atomicity` reads
4
+ * (`road-to-supervised-telemetry-collector` steps 5.1 and 5.2).
5
+ *
6
+ * ## Why a producer script and not just `vitest run`
7
+ *
8
+ * The atomicity gate refuses a present-tense supervision claim unless
9
+ * `internal/reports/supervision-lifecycle.json` records a suite that ran on THIS
10
+ * revision, exercised real processes, and was not empty or mostly skipped. That
11
+ * artifact has to be written by something that knows all four facts. A test file
12
+ * knows whether it ran; only the runner knows the revision and the counts.
13
+ *
14
+ * ## Every field here is observed, not asserted
15
+ *
16
+ * - `revision` — `git rev-parse HEAD`, read at run time. Never a constant.
17
+ * - `cases_run` / `cases_skipped` — parsed out of vitest's own JSON report,
18
+ * never counted by hand from the source.
19
+ * - `processes_exercised` — true only when the suite ACTUALLY spawned daemons,
20
+ * established by re-reading the report for the property names that can only
21
+ * pass against real processes. A hardcoded `true` here would defeat the entire
22
+ * point of the gate, which exists because a mocked suite can demonstrate all
23
+ * five properties and prove none of them.
24
+ *
25
+ * ## A skip is a failure
26
+ *
27
+ * AC-8: *"a suite that skips on a platform is a failure on that platform, not an
28
+ * absence."* So a run whose cases were skipped writes the artifact with the
29
+ * honest counts and exits non-zero, rather than writing nothing — a missing
30
+ * artifact and a skipped suite need different remediation and the gate
31
+ * distinguishes them.
32
+ */
33
+
34
+ import { execFileSync, spawnSync } from 'node:child_process';
35
+ import fs from 'node:fs';
36
+ import os from 'node:os';
37
+ import path from 'node:path';
38
+ import { fileURLToPath } from 'node:url';
39
+
40
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
41
+ const REPO = path.resolve(HERE, '..', '..');
42
+
43
+ /** The suite, by path. Named once so the artifact and the runner cannot drift. */
44
+ export const SUITE_REL = 'tests/scripts/collector_lifecycle.test.ts';
45
+ export const SUITE_NAME = 'supervision-lifecycle';
46
+ export const EVIDENCE_REL = path.join('internal', 'reports', 'supervision-lifecycle.json');
47
+
48
+ /**
49
+ * The five property names the suite must have RUN for the artifact to claim
50
+ * real processes were exercised.
51
+ *
52
+ * Matched against the report's test names rather than counted, because a count
53
+ * cannot tell five properties from five repeats of one.
54
+ */
55
+ export const REQUIRED_PROPERTIES = [
56
+ 'PROPERTY 1',
57
+ 'PROPERTY 2',
58
+ 'PROPERTY 3',
59
+ 'PROPERTY 4',
60
+ 'PROPERTY 5',
61
+ ] as const;
62
+
63
+ export interface SuiteCounts {
64
+ readonly run: number;
65
+ readonly skipped: number;
66
+ readonly passedNames: readonly string[];
67
+ }
68
+
69
+ export function countsFromReport(reportJson: string): SuiteCounts {
70
+ const raw = JSON.parse(reportJson) as {
71
+ testResults?: { assertionResults?: { fullName?: string; status?: string }[] }[];
72
+ };
73
+ let run = 0;
74
+ let skipped = 0;
75
+ const passedNames: string[] = [];
76
+ for (const suite of raw.testResults ?? []) {
77
+ for (const assertion of suite.assertionResults ?? []) {
78
+ const status = assertion.status ?? 'unknown';
79
+ if (status === 'pending' || status === 'skipped' || status === 'todo') {
80
+ skipped += 1;
81
+ continue;
82
+ }
83
+ run += 1;
84
+ if (status === 'passed') passedNames.push(assertion.fullName ?? '');
85
+ }
86
+ }
87
+ return { run, skipped, passedNames };
88
+ }
89
+
90
+ /**
91
+ * Did the run exercise real processes?
92
+ *
93
+ * True only when every one of the five named properties PASSED. Anything less —
94
+ * a skipped property, a renamed one, a suite that never collected — leaves this
95
+ * false, and the gate then refuses the capability claim rather than accepting a
96
+ * partial demonstration as a whole one.
97
+ */
98
+ export function processesExercised(counts: SuiteCounts): boolean {
99
+ return REQUIRED_PROPERTIES.every((property) =>
100
+ counts.passedNames.some((name) => name.includes(property)),
101
+ );
102
+ }
103
+
104
+ export function headRevision(repo: string = REPO): string {
105
+ try {
106
+ return execFileSync('git', ['-C', repo, 'rev-parse', 'HEAD'], { encoding: 'utf8' }).trim();
107
+ } catch {
108
+ return '';
109
+ }
110
+ }
111
+
112
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
113
+ const dryRun = argv.includes('--dry-run');
114
+ const report = path.join(os.tmpdir(), `lifecycle-report-${process.pid}.json`);
115
+ fs.rmSync(report, { force: true });
116
+
117
+ // Clear the parity gate's alias switch, the same guard its sibling spawner
118
+ // takes (R2 round-5 finding 10). An ambient `AGENT_CONFIG_COLLECTOR_ABSENT`
119
+ // stubs the collector away for this run too, so `enableCollector` becomes a
120
+ // no-op and every daemon refuses with `not-enabled`. It fails loudly rather
121
+ // than silently — but the asymmetry between two spawners in one change is
122
+ // the shape the earlier finding was about.
123
+ const env = { ...process.env };
124
+ delete env.AGENT_CONFIG_COLLECTOR_ABSENT;
125
+
126
+ const result = spawnSync(
127
+ path.join(REPO, 'node_modules', '.bin', 'vitest'),
128
+ ['run', SUITE_REL, '--reporter=json', `--outputFile=${report}`],
129
+ { cwd: REPO, encoding: 'utf8', env, stdio: ['ignore', 'pipe', 'pipe'] },
130
+ );
131
+
132
+ if (!fs.existsSync(report)) {
133
+ process.stderr.write(
134
+ `run_lifecycle_suite: no report produced.\n${result.stdout ?? ''}\n${result.stderr ?? ''}\n`,
135
+ );
136
+ return 1;
137
+ }
138
+ const counts = countsFromReport(fs.readFileSync(report, 'utf8'));
139
+ fs.rmSync(report, { force: true });
140
+
141
+ const revision = headRevision();
142
+ const suiteGreen = result.status === 0;
143
+ // A red suite is a THIRD state, and the artifact used to record neither it
144
+ // nor anything that implied it: `processes_exercised` depends only on the
145
+ // five named properties, so a run where all five passed and a sixth case
146
+ // failed wrote `processes_exercised: true, cases_skipped: 0` and then exited
147
+ // 1 — a pass-shaped artifact left on disk by a failing run (R2 finding 18).
148
+ //
149
+ // Two changes close it. The flag itself is conjoined with the suite's exit
150
+ // status, so a red run can never claim the processes were exercised; and
151
+ // `suite_exit_status` is recorded outright, so the state is readable rather
152
+ // than inferred. The gate's own contract is unchanged — it reads
153
+ // `processes_exercised`, which is now false on a red run.
154
+ const exercised = processesExercised(counts) && suiteGreen;
155
+ const evidence = {
156
+ suite: SUITE_NAME,
157
+ revision,
158
+ processes_exercised: exercised,
159
+ cases_run: counts.run,
160
+ cases_skipped: counts.skipped,
161
+ suite_exit_status: result.status ?? null,
162
+ platform: `${process.platform}-${process.arch}`,
163
+ recorded_at: new Date().toISOString(),
164
+ };
165
+
166
+ process.stdout.write(
167
+ `run_lifecycle_suite: ${counts.run} run, ${counts.skipped} skipped, `
168
+ + `suite_exit=${String(result.status ?? 'null')}, `
169
+ + `processes_exercised=${String(exercised)}, revision=${revision || '(unknown)'}\n`,
170
+ );
171
+
172
+ if (dryRun) {
173
+ process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`);
174
+ return suiteGreen && exercised && counts.skipped === 0 ? 0 : 1;
175
+ }
176
+
177
+ const target = path.join(REPO, EVIDENCE_REL);
178
+ fs.mkdirSync(path.dirname(target), { recursive: true });
179
+ fs.writeFileSync(target, `${JSON.stringify(evidence, null, 2)}\n`);
180
+ process.stdout.write(`run_lifecycle_suite: wrote ${EVIDENCE_REL}\n`);
181
+
182
+ if (result.status !== 0) {
183
+ process.stderr.write('run_lifecycle_suite: the suite is RED\n');
184
+ return 1;
185
+ }
186
+ if (counts.skipped > 0) {
187
+ // AC-8 makes a skip a failure on that platform rather than an absence.
188
+ process.stderr.write(
189
+ `run_lifecycle_suite: ${counts.skipped} case(s) SKIPPED — on a declared platform a `
190
+ + 'skip is a failure, not an absence\n',
191
+ );
192
+ return 1;
193
+ }
194
+ if (!exercised) {
195
+ process.stderr.write(
196
+ 'run_lifecycle_suite: not every named property passed — the artifact records '
197
+ + '`processes_exercised: false` and the capability claim stays prohibited\n',
198
+ );
199
+ return 1;
200
+ }
201
+ return 0;
202
+ }
203
+
204
+ const invokedDirectly =
205
+ process.argv[1] !== undefined && process.argv[1].includes('run_lifecycle_suite');
206
+ if (invokedDirectly) {
207
+ process.exitCode = main();
208
+ }