@event4u/agent-config 14.12.0 → 14.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (521) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +118 -155
  5. package/CONTRIBUTING.md +38 -0
  6. package/CREDITS.md +135 -0
  7. package/NOTICE +13 -0
  8. package/README.md +8 -6
  9. package/dist/agent-src/commands/analyze/inbox.md +145 -2
  10. package/dist/agent-src/commands/feature/dev.md +7 -2
  11. package/dist/agent-src/commands/ghostwriter/write.md +5 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  14. package/dist/agent-src/commands/orchestrate.md +2 -2
  15. package/dist/agent-src/commands/post-as/me.md +5 -1
  16. package/dist/agent-src/commands/pr/merge.md +19 -6
  17. package/dist/agent-src/commands/roadmap/process-full.md +19 -5
  18. package/dist/agent-src/commands/tdd/red.md +12 -2
  19. package/dist/agent-src/commands/work.md +1 -1
  20. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
  21. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
  22. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
  23. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
  24. package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
  25. package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
  26. package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
  27. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  28. package/dist/agent-src/rules/broken-access-control.md +4 -0
  29. package/dist/agent-src/rules/code-comment-discipline.md +6 -0
  30. package/dist/agent-src/rules/code-provenance.md +4 -0
  31. package/dist/agent-src/rules/design-fidelity.md +1 -1
  32. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  33. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  34. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  35. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  36. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  37. package/dist/agent-src/rules/laravel-routing.md +1 -1
  38. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  39. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  40. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  41. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  42. package/dist/agent-src/rules/symfony-routing.md +1 -1
  43. package/dist/agent-src/rules/token-efficiency.md +14 -0
  44. package/dist/agent-src/rules/tool-safety.md +4 -0
  45. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  46. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  47. package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
  48. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  49. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  50. package/dist/agent-src/scripts/stubs_due.ts +516 -0
  51. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  52. package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
  53. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  54. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  55. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  56. package/dist/agent-src/skills/database/SKILL.md +8 -0
  57. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  58. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  59. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  60. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  61. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  62. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  63. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  64. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  65. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  66. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  67. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  68. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  69. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  70. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  71. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  72. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  73. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  74. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  75. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  76. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  77. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  78. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  79. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  80. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  81. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  82. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  83. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  84. package/dist/agent-src/templates/roadmaps.md +97 -3
  85. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  86. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  87. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  88. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  93. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  94. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  95. package/dist/cli/commands/uiAudit.js +124 -5
  96. package/dist/cli/registry.js +2 -0
  97. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  98. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  99. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  100. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  101. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  102. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  103. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  104. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  105. package/dist/cli-delegate/cmd_conformance.js +80 -11
  106. package/dist/cli-delegate/cmd_doctor.js +3 -3
  107. package/dist/cli-delegate/cmd_export.js +3 -2
  108. package/dist/cli-delegate/cmd_fleet.js +2 -2
  109. package/dist/cli-delegate/cmd_handoff.js +1 -1
  110. package/dist/cli-delegate/cmd_preflight.js +2 -2
  111. package/dist/cli-delegate/cmd_prune.js +3 -2
  112. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  113. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  114. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  115. package/dist/cli-delegate/cmd_sync.js +3 -2
  116. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  117. package/dist/cli-delegate/cmd_validate.js +3 -2
  118. package/dist/discovery/deprecation-report.md +1 -1
  119. package/dist/discovery/discovery-manifest.json +58 -58
  120. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  121. package/dist/discovery/discovery-manifest.summary.md +1 -1
  122. package/dist/discovery/dormancy-report.md +1 -1
  123. package/dist/discovery/orphan-report.md +1 -1
  124. package/dist/discovery/packs.json +2 -2
  125. package/dist/discovery/trust-report.md +1 -1
  126. package/dist/discovery/workspaces.json +2 -2
  127. package/dist/hooks/dispatch.js +2900 -1049
  128. package/dist/install/claudeRuleRewrite.js +254 -0
  129. package/dist/install/detect.js +29 -16
  130. package/dist/install/detect_php_shape.js +159 -0
  131. package/dist/install/install.mjs +634 -428
  132. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  133. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  134. package/dist/mcp/registry-manifest.json +3 -3
  135. package/dist/mcp/server.json +3 -3
  136. package/dist/mcp/server.mjs +4895 -2627
  137. package/dist/server/schemas/settings.js +3 -0
  138. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  139. package/dist/ui/index.html +1 -1
  140. package/docs/MIGRATION.md +1 -1
  141. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  142. package/docs/contracts/provider-lifecycle.md +1 -1
  143. package/docs/contracts/settings-classes.md +10 -4
  144. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  145. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  146. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  147. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  148. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  149. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  150. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  151. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  152. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  153. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  154. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  155. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  156. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  157. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  158. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  159. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  160. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  161. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  162. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  163. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  164. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  165. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  166. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  167. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  168. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  169. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  170. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  171. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  172. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  173. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  174. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  175. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  176. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  177. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  178. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  179. package/docs/guidelines/augment-portability-patterns.md +6 -4
  180. package/docs/guidelines/code-clarity.md +18 -0
  181. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  182. package/docs/guidelines/cross-role-handoff.md +2 -2
  183. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  184. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  185. package/docs/guidelines/php/database.md +90 -7
  186. package/docs/guidelines/prompt-templates.md +7 -7
  187. package/llms.txt +2 -2
  188. package/package.json +5 -2
  189. package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  190. package/src/agent-src/scripts/guarded_baseline.ts +343 -0
  191. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  192. package/src/agent-src/scripts/stub_queue.ts +82 -0
  193. package/src/agent-src/scripts/stubs_due.ts +516 -0
  194. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  195. package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
  196. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  197. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  198. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  199. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  202. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  203. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  204. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  205. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  206. package/src/config/agent-settings.template.yml +32 -3
  207. package/src/config/assurance-capability-registry.json +21 -9
  208. package/src/config/canonical-terms.yml +119 -0
  209. package/src/config/capability-native-outcome-bars.json +81 -0
  210. package/src/config/ci-local-parity.yml +80 -0
  211. package/src/config/drafting-channels.yml +43 -0
  212. package/src/config/estate-count-budget.json +57 -36
  213. package/src/config/evaluator-budgets.json +14 -14
  214. package/src/config/gate-coverage.yml +729 -63
  215. package/src/config/gate-reachability-exemptions.json +21 -0
  216. package/src/config/gate-violation-baselines.json +42 -19
  217. package/src/config/harness-evolution-budget.json +25 -0
  218. package/src/config/lapsed-beta-baseline.json +96 -0
  219. package/src/config/memory-twin-verdicts.yml +129 -0
  220. package/src/config/metric-registry.yml +124 -0
  221. package/src/config/pack-size-budget.json +16 -15
  222. package/src/config/preamble-payload-budget.json +12 -4
  223. package/src/config/profiles/balanced.ini +27 -0
  224. package/src/config/profiles/full.ini +27 -0
  225. package/src/config/profiles/minimal.ini +27 -0
  226. package/src/config/publish-surface.json +9 -2
  227. package/src/config/routing-coverage-seed.json +16 -2
  228. package/src/config/rule-stub-ceilings.json +133 -112
  229. package/src/config/turnaround-budget.json +66 -0
  230. package/src/install/claudeRuleRewrite.ts +288 -0
  231. package/src/install/detect.ts +60 -17
  232. package/src/install/detect_php_shape.ts +191 -0
  233. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  234. package/src/scripts/_dispatch.bash +23 -0
  235. package/src/scripts/_lib/activation_ladder.ts +255 -0
  236. package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
  237. package/src/scripts/_lib/activation_states.ts +88 -0
  238. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  239. package/src/scripts/_lib/adr_frontmatter.ts +26 -0
  240. package/src/scripts/_lib/arith_claims.ts +181 -0
  241. package/src/scripts/_lib/arm_ranking.ts +62 -0
  242. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  243. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  244. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  245. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  246. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  247. package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
  248. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  249. package/src/scripts/_lib/candidate_record.ts +601 -0
  250. package/src/scripts/_lib/capture_rate.ts +319 -0
  251. package/src/scripts/_lib/carrier_status.ts +118 -0
  252. package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
  253. package/src/scripts/_lib/collector_denominator.ts +771 -0
  254. package/src/scripts/_lib/collector_record.ts +340 -0
  255. package/src/scripts/_lib/collector_store.ts +664 -0
  256. package/src/scripts/_lib/collector_supervision.ts +827 -0
  257. package/src/scripts/_lib/concern_estate.ts +77 -0
  258. package/src/scripts/_lib/config_chain.ts +477 -0
  259. package/src/scripts/_lib/config_cost.ts +209 -0
  260. package/src/scripts/_lib/corpus_manifest.ts +726 -0
  261. package/src/scripts/_lib/council_settings_block.ts +6 -0
  262. package/src/scripts/_lib/curator_ops.ts +172 -0
  263. package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
  264. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  265. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  266. package/src/scripts/_lib/empty_cycles.ts +88 -0
  267. package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
  268. package/src/scripts/_lib/eval_publication.ts +354 -0
  269. package/src/scripts/_lib/evaluation_cascade.ts +452 -0
  270. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  271. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  272. package/src/scripts/_lib/evidence_basis.ts +118 -0
  273. package/src/scripts/_lib/evolution_roi.ts +562 -0
  274. package/src/scripts/_lib/exec_evidence.ts +8 -0
  275. package/src/scripts/_lib/experience_card.ts +272 -0
  276. package/src/scripts/_lib/experience_report.ts +151 -0
  277. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  278. package/src/scripts/_lib/generated_by.ts +66 -0
  279. package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
  280. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  281. package/src/scripts/_lib/host_denominator.ts +687 -0
  282. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  283. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  284. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  285. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  286. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  287. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  288. package/src/scripts/_lib/lexical_shortlist.ts +215 -0
  289. package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
  290. package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
  291. package/src/scripts/_lib/loop_guards.ts +299 -0
  292. package/src/scripts/_lib/loss_class.ts +129 -0
  293. package/src/scripts/_lib/machine_wake.ts +51 -0
  294. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  295. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  296. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  297. package/src/scripts/_lib/orchestration_record.ts +253 -5
  298. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  299. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  300. package/src/scripts/_lib/paired_stats.ts +245 -0
  301. package/src/scripts/_lib/paired_verdict.ts +226 -0
  302. package/src/scripts/_lib/pathology_archive.ts +393 -0
  303. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  304. package/src/scripts/_lib/privacy_class.ts +47 -0
  305. package/src/scripts/_lib/promotion_capability.ts +315 -0
  306. package/src/scripts/_lib/promotion_evidence.ts +414 -0
  307. package/src/scripts/_lib/promotion_review.ts +294 -0
  308. package/src/scripts/_lib/prompt_shape.ts +92 -0
  309. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  310. package/src/scripts/_lib/release_highlights.ts +70 -1
  311. package/src/scripts/_lib/release_material.ts +125 -2
  312. package/src/scripts/_lib/repeated_failure.ts +105 -0
  313. package/src/scripts/_lib/repo_root.ts +111 -0
  314. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  315. package/src/scripts/_lib/role_split.ts +338 -0
  316. package/src/scripts/_lib/routing_corpus.ts +307 -0
  317. package/src/scripts/_lib/routing_index_input.ts +104 -0
  318. package/src/scripts/_lib/rule_injection.ts +22 -1
  319. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  320. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  321. package/src/scripts/_lib/semantic_noop.ts +167 -0
  322. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  323. package/src/scripts/_lib/source_digest.ts +200 -0
  324. package/src/scripts/_lib/source_redact.ts +260 -0
  325. package/src/scripts/_lib/source_shape.ts +502 -0
  326. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  327. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  328. package/src/scripts/_lib/strip_comments.mjs +65 -0
  329. package/src/scripts/_lib/test_red_state.ts +154 -0
  330. package/src/scripts/_lib/trigger_shift.ts +144 -0
  331. package/src/scripts/_lib/untrusted_content.ts +82 -7
  332. package/src/scripts/activation_receipt.ts +258 -0
  333. package/src/scripts/adoption_report.ts +1 -1
  334. package/src/scripts/adr/evidence_census.ts +1 -1
  335. package/src/scripts/adr/regenerate_index.ts +26 -2
  336. package/src/scripts/adr_cite_check.ts +164 -1
  337. package/src/scripts/ai_council/blind_review.ts +11 -1
  338. package/src/scripts/ai_council/clients.ts +4 -0
  339. package/src/scripts/ai_council/config.ts +3 -0
  340. package/src/scripts/ai_council/consensus.ts +28 -8
  341. package/src/scripts/ai_council/consensus_round.ts +226 -0
  342. package/src/scripts/ai_council/cross_exam.ts +128 -0
  343. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  344. package/src/scripts/ai_council/explain_route.ts +157 -0
  345. package/src/scripts/ai_council/information_gain.ts +293 -0
  346. package/src/scripts/ai_council/inline_findings.ts +340 -0
  347. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  348. package/src/scripts/ai_council/leakage_corpus.ts +385 -0
  349. package/src/scripts/ai_council/leakage_patterns.ts +453 -0
  350. package/src/scripts/ai_council/minority_retention.ts +171 -0
  351. package/src/scripts/ai_council/orchestrator.ts +16 -203
  352. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  353. package/src/scripts/ai_council/pricing.ts +106 -0
  354. package/src/scripts/ai_council/prompts.ts +74 -7
  355. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  356. package/src/scripts/ai_council/py_format.ts +14 -3
  357. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  358. package/src/scripts/ai_council/recouncil_savings.ts +299 -0
  359. package/src/scripts/ai_council/replay_route.ts +223 -0
  360. package/src/scripts/ai_council/response_record.ts +50 -0
  361. package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
  362. package/src/scripts/ai_council/routing_training_row.ts +197 -0
  363. package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
  364. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  365. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  366. package/src/scripts/asset_delivery_ledger.ts +157 -0
  367. package/src/scripts/attest_artifact.ts +193 -0
  368. package/src/scripts/audit_auto_rules.ts +2 -1
  369. package/src/scripts/audit_command_surface.ts +1 -1
  370. package/src/scripts/audit_mcp_tools.ts +2 -2
  371. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  372. package/src/scripts/audit_user_type_axis.ts +2 -1
  373. package/src/scripts/bench_ab_clone.ts +215 -10
  374. package/src/scripts/bench_ab_integrity.ts +119 -5
  375. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  376. package/src/scripts/build_archive_index.ts +1 -1
  377. package/src/scripts/build_linear_digest.ts +1 -1
  378. package/src/scripts/build_proof.ts +11 -4
  379. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  380. package/src/scripts/build_source_digests.ts +157 -0
  381. package/src/scripts/cache_realization_report.ts +103 -0
  382. package/src/scripts/check_adr_frontmatter.ts +131 -10
  383. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  384. package/src/scripts/check_beta_review_markers.ts +235 -6
  385. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  386. package/src/scripts/check_claims.ts +576 -6
  387. package/src/scripts/check_composite_arming.ts +35 -0
  388. package/src/scripts/check_concern_admissions.ts +365 -0
  389. package/src/scripts/check_enforcement_coverage.ts +28 -0
  390. package/src/scripts/check_estate_count.ts +347 -25
  391. package/src/scripts/check_gate_reachability.ts +383 -0
  392. package/src/scripts/check_host_loadability.ts +104 -0
  393. package/src/scripts/check_loss_class_declared.ts +308 -0
  394. package/src/scripts/check_md_language.ts +15 -98
  395. package/src/scripts/check_memory_proposal.ts +18 -11
  396. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  397. package/src/scripts/check_no_external_sources.ts +281 -6
  398. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  399. package/src/scripts/check_pack_size.ts +59 -2
  400. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  401. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  402. package/src/scripts/check_publish_surface.ts +10 -1
  403. package/src/scripts/check_references.ts +24 -1
  404. package/src/scripts/check_release_highlights.ts +96 -13
  405. package/src/scripts/check_roadmap_trackable.ts +17 -2
  406. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  407. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  408. package/src/scripts/check_score_contract.ts +26 -3
  409. package/src/scripts/check_static_parity.ts +285 -0
  410. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  411. package/src/scripts/check_suppression_hygiene.ts +15 -0
  412. package/src/scripts/ci_settle.ts +39 -2
  413. package/src/scripts/code_graph/build.ts +60 -3
  414. package/src/scripts/code_graph/extract.ts +44 -0
  415. package/src/scripts/code_graph/types.ts +24 -0
  416. package/src/scripts/collector_daemon.ts +714 -0
  417. package/src/scripts/config_cost_report.ts +302 -0
  418. package/src/scripts/consumer_matrix.ts +74 -1
  419. package/src/scripts/corpus_manifest.ts +235 -0
  420. package/src/scripts/cost/budget.mjs +10 -3
  421. package/src/scripts/cost/track.mjs +10 -3
  422. package/src/scripts/council_cli.ts +37 -54
  423. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  424. package/src/scripts/evolution_lab.ts +1153 -0
  425. package/src/scripts/external_sources_denylist.json +5 -18
  426. package/src/scripts/extract_audit_patterns.ts +21 -0
  427. package/src/scripts/fold_intake.ts +12 -1
  428. package/src/scripts/gen_discovery_baseline.ts +1 -1
  429. package/src/scripts/generate_capabilities_index.ts +12 -5
  430. package/src/scripts/generate_capability_matrix.ts +3 -3
  431. package/src/scripts/generate_command_flows.ts +2 -2
  432. package/src/scripts/generate_cookbook.ts +2 -2
  433. package/src/scripts/generate_index.ts +8 -1
  434. package/src/scripts/generate_knowledge_index.ts +2 -1
  435. package/src/scripts/generate_ownership_matrix.ts +2 -1
  436. package/src/scripts/generate_pack_manifests.ts +10 -2
  437. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  438. package/src/scripts/generate_settings_reference.ts +1 -1
  439. package/src/scripts/git_authorization_hook.ts +22 -1
  440. package/src/scripts/grade_target_readiness.ts +48 -5
  441. package/src/scripts/hook_effect_doctor.ts +261 -0
  442. package/src/scripts/hook_manifest.json +1 -1
  443. package/src/scripts/hook_manifest.yaml +125 -16
  444. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  445. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  446. package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
  447. package/src/scripts/hooks/concern_registry.ts +6 -0
  448. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  449. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  450. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  451. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  452. package/src/scripts/hooks/shims/install.sh +61 -0
  453. package/src/scripts/hooks/shims/php +101 -0
  454. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  455. package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
  456. package/src/scripts/hot_context_hook.ts +16 -0
  457. package/src/scripts/install-hooks.sh +20 -5
  458. package/src/scripts/install.ts +17 -35
  459. package/src/scripts/inventory_frontmatter.ts +2 -1
  460. package/src/scripts/language_mirror_hook.ts +14 -2
  461. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  462. package/src/scripts/lint_canonical_terms.ts +604 -0
  463. package/src/scripts/lint_carrier_integrity.ts +820 -0
  464. package/src/scripts/lint_code_comments.ts +643 -0
  465. package/src/scripts/lint_composition_review.ts +619 -0
  466. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  467. package/src/scripts/lint_eval_specs.ts +593 -0
  468. package/src/scripts/lint_hook_manifest.ts +19 -0
  469. package/src/scripts/lint_host_portability.ts +373 -0
  470. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  471. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  472. package/src/scripts/lint_metric_consumers.ts +355 -0
  473. package/src/scripts/lint_plan_risk_register.ts +39 -19
  474. package/src/scripts/lint_promotion_paths.ts +779 -0
  475. package/src/scripts/lint_skill_descriptions.ts +18 -1
  476. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  477. package/src/scripts/lint_skill_link_reach.ts +252 -0
  478. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  479. package/src/scripts/lint_ticket_buildable.ts +17 -1
  480. package/src/scripts/llm_propose.ts +256 -0
  481. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  482. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  483. package/src/scripts/measure_delivery_sets.ts +361 -0
  484. package/src/scripts/measure_docs_dead_links.ts +348 -0
  485. package/src/scripts/measure_host_capture.ts +461 -0
  486. package/src/scripts/measure_routing_signal.ts +307 -0
  487. package/src/scripts/migration_status.ts +3 -3
  488. package/src/scripts/model_rule_injection.ts +76 -0
  489. package/src/scripts/orchestration_record.ts +14 -0
  490. package/src/scripts/preamble_byte_census.ts +139 -10
  491. package/src/scripts/prepack-check.mjs +4 -1
  492. package/src/scripts/probe_council_retention.ts +495 -0
  493. package/src/scripts/probe_turnaround.ts +384 -0
  494. package/src/scripts/probe_unblocked_ask.ts +279 -0
  495. package/src/scripts/release.ts +21 -37
  496. package/src/scripts/release_drill.ts +143 -0
  497. package/src/scripts/release_env.ts +35 -0
  498. package/src/scripts/release_publication.ts +84 -0
  499. package/src/scripts/render_benchmark_md.ts +1 -1
  500. package/src/scripts/rule_activation_census.ts +70 -9
  501. package/src/scripts/rule_backlinks.ts +1 -1
  502. package/src/scripts/run_lifecycle_suite.ts +208 -0
  503. package/src/scripts/run_skill_evals.ts +40 -0
  504. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  505. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  506. package/src/scripts/schemas/evals.schema.json +24 -1
  507. package/src/scripts/schemas/rule.schema.json +52 -1
  508. package/src/scripts/schemas/skill.schema.json +17 -2
  509. package/src/scripts/skill_overlap.ts +7 -1
  510. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  511. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  512. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  513. package/src/scripts/skill_usage_report.ts +2 -1
  514. package/src/scripts/stubs_due.ts +211 -0
  515. package/src/scripts/sweep_source_surfaces.ts +678 -0
  516. package/src/scripts/sync_pr_branch.ts +3 -3
  517. package/src/scripts/trigger_eval_grandfather.json +202 -222
  518. package/src/scripts/utilization_report.ts +22 -2
  519. package/src/server/schemas/settings.ts +5 -0
  520. package/src/templates/marketing-copy.yml +1 -1
  521. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,687 @@
1
+ /**
2
+ * The host-emitted-event denominator — a typed, privacy-bounded count
3
+ * reconstructed from a HOST-authored artefact.
4
+ *
5
+ * `road-to-journal-host-capture-measurement` Phase 2 step 2.1 and AC-2. The
6
+ * survey of step 1.1
7
+ * (`agents/evidence/analysis/host-denominator-obtainability-2026-08-29.md`)
8
+ * established that exactly six `(platform, event)` cells carry an obtainable
9
+ * host denominator, all on `claude`, all reconstructable from the per-session
10
+ * transcript Claude Code writes at
11
+ * `~/.claude/projects/<project-slug>/<session-id>.jsonl`.
12
+ *
13
+ * ## Why this module exists rather than a one-off script
14
+ *
15
+ * AC-2 requires the denominator's record type to be *asserted against a
16
+ * committed key set, with a free-form write failing to type-check* — the same
17
+ * privacy property `_lib/runtime_journal.ts` carries for the numerator. A
18
+ * denominator computed inline in a script has no record type to assert, so the
19
+ * two halves of the capture rate would have been held to different standards.
20
+ * They are held to the same one here: {@link DENOMINATOR_RECORD_KEYS} is bound
21
+ * to {@link HostDenominator} in both directions, and the record is passed
22
+ * through the journal's own `NoFreeForm` guard rather than a local copy of it.
23
+ *
24
+ * ## The scope must match the numerator's, and v1 did not — R2 finding 1
25
+ *
26
+ * The numerator is ONE repository's journal (`<git-common-dir>/agent-journal/`,
27
+ * shared across that repository's worktrees and reaching nothing else). v1 of
28
+ * this module walked every project directory on the machine, so the ratio was
29
+ * over two different populations. It was invisible in the first published run
30
+ * only because the numerator was `store-absent`, and the evidence page's own
31
+ * `Revisit-if` told the next reader to re-run the script on a machine where it
32
+ * would not have been.
33
+ *
34
+ * {@link DenominatorScope} makes the scope an explicit, recorded field, and
35
+ * `repository` is the default: a rate needs one population, and the numerator's
36
+ * is the one that cannot be widened. `machine` remains available because a
37
+ * machine-wide denominator is a legitimate *different* figure — it just may
38
+ * never be divided by a repository-scoped numerator.
39
+ *
40
+ * ## The reconstruction is a stated rule set, not a heuristic
41
+ *
42
+ * {@link RECONSTRUCTION_RULE_VERSION} pins the rules, and the pinning matters:
43
+ * a denominator whose derivation can be adjusted after the numerator is known
44
+ * is not a denominator. v2 states two rules v1 left implicit — the sidechain
45
+ * treatment of *assistant* records, which governs 97 % of the count, and the
46
+ * direction in which the `session_start` rule fails.
47
+ *
48
+ * ## What this module refuses to count, and why that is the interesting half
49
+ *
50
+ * `stop` is journal-bound on `claude` and would widen the measurement from
51
+ * five journal-bound cells to six. Three candidate denominators for it were
52
+ * examined and **all three are refused**; {@link STOP_CANDIDATES} records them
53
+ * with the reading that refuses each, and they disagree by a factor of about 44
54
+ * (305 / 7). A `stop` denominator chosen from among three mutually inconsistent
55
+ * candidates would be a number with a footnote where the footnote is
56
+ * load-bearing.
57
+ */
58
+
59
+ import { execFileSync } from 'node:child_process';
60
+ import * as fs from 'node:fs';
61
+ import * as path from 'node:path';
62
+ import * as readline from 'node:readline';
63
+
64
+ import type { NoFreeForm } from './runtime_journal.js';
65
+
66
+ type Assert<T extends true> = T;
67
+
68
+ /**
69
+ * Bumped whenever any rule in {@link RECONSTRUCTION_RULES} changes. A published
70
+ * rate cites this number, so a later reader can tell a re-measurement from a
71
+ * re-derivation.
72
+ *
73
+ * - **v1** (2026-08-29) — the 1.1 survey's four rules plus the `isMeta` and
74
+ * `isSidechain` refinements on `user` records.
75
+ * - **v2** (2026-08-29, after R2 review) — states the sidechain rule for
76
+ * *assistant* records, which v1 left implicit while it governed 97 % of the
77
+ * count; states the direction in which the `session_start` rule fails; and
78
+ * takes `first_at` as the MINIMUM timestamp rather than the first one in file
79
+ * order.
80
+ */
81
+ export const RECONSTRUCTION_RULE_VERSION = 2;
82
+
83
+ /**
84
+ * Which population the denominator is over.
85
+ *
86
+ * `repository` — only transcripts whose project directory belongs to the
87
+ * measured repository or one of its worktrees. This is the scope the
88
+ * repository-scoped journal numerator can actually reach, and it is the default
89
+ * for that reason.
90
+ *
91
+ * `machine` — every transcript on the machine. A legitimate figure about the
92
+ * host, and NOT divisible by a repository-scoped numerator.
93
+ */
94
+ export const DENOMINATOR_SCOPES = ['repository', 'machine'] as const;
95
+ export type DenominatorScope = (typeof DENOMINATOR_SCOPES)[number];
96
+
97
+ /**
98
+ * The six `(claude, event)` cells the 1.1 survey found `counted`. This is the
99
+ * measurement's scope and no more: a rate over six of 43 bound cells is a
100
+ * different claim from a rate over all of them.
101
+ */
102
+ export const COUNTED_EVENTS = [
103
+ 'session_start',
104
+ 'user_prompt_submit',
105
+ 'pre_tool_use',
106
+ 'post_tool_use',
107
+ 'subagent_start',
108
+ 'subagent_stop',
109
+ ] as const;
110
+
111
+ export type CountedEvent = (typeof COUNTED_EVENTS)[number];
112
+
113
+ /**
114
+ * Of the six, the five where `journal-record` is actually bound in
115
+ * `src/scripts/hook_manifest.yaml` on the `claude` platform.
116
+ *
117
+ * `pre_tool_use` is the omission and it is deliberate rather than an oversight
118
+ * to be corrected here: that slot carries the safety guards, and the journal is
119
+ * not among them. Its numerator is therefore zero **by construction**, which is
120
+ * a different fact from zero-because-nothing-fired, and the published table
121
+ * separates the two instead of averaging them into one rate.
122
+ */
123
+ export const JOURNAL_BOUND_COUNTED_EVENTS = [
124
+ 'session_start',
125
+ 'user_prompt_submit',
126
+ 'post_tool_use',
127
+ 'subagent_start',
128
+ 'subagent_stop',
129
+ ] as const;
130
+
131
+ type _BoundIsSubsetOfCounted = Assert<
132
+ Exclude<(typeof JOURNAL_BOUND_COUNTED_EVENTS)[number], CountedEvent> extends never ? true : false
133
+ >;
134
+
135
+ /** Human-readable statement of every rule the reconstruction applies. */
136
+ export const RECONSTRUCTION_RULES: Readonly<Record<string, string>> = Object.freeze({
137
+ session_start:
138
+ 'One per transcript file. NOT an iff, and v1 claimed it was: the host fires `SessionStart` again on resume, clear and compact while a resumed session appends to the SAME file (under-count), and a compacted or forked session can produce a SECOND file for one logical session (over-count on the population side). Both directions are present and neither is corrected, so this cell is the least precise of the six and the population figure derived from it inherits that.',
139
+ user_prompt_submit:
140
+ 'A `type: "user"` record carrying no `tool_result` content block. REFINEMENT 1: records with `isMeta: true` are excluded — an injected system reminder is not a user prompt submit. REFINEMENT 2: records with `isSidechain: true` are excluded — a subagent brief does not fire the host event in the parent session. The two exclusion counters are INDEPENDENT: a record carrying both flags increments both, so they may sum to more than the number of records excluded.',
141
+ pre_tool_use:
142
+ 'One per `tool_use` content block in a `type: "assistant"` record. Sidechain records ARE INCLUDED — a subagent tool call fires the parent session tool hooks — and the sidechain share is counted separately in `sidechain_tool_use_blocks` so a reader who disagrees can subtract it. v1 left this rule unstated while it governed about 97 % of the six-cell total, which is why it is written here rather than inferred from the code.',
143
+ post_tool_use:
144
+ 'One per `tool_use` content block in a `type: "assistant"` record. Same sidechain treatment, same separately-published share.',
145
+ subagent_start:
146
+ 'One per `tool_use` content block whose `name` is `Agent` or `Task`. A subset of the tool_use blocks, and a distinct host event. Sidechain-nested spawns are included and counted in `sidechain_agent_tool_use_blocks`.',
147
+ subagent_stop:
148
+ 'One per `tool_use` content block whose `name` is `Agent` or `Task`. Same treatment as `subagent_start`.',
149
+ });
150
+
151
+ /**
152
+ * The three refused candidates for a `stop` denominator, each with the reading
153
+ * that refuses it. Kept in code rather than only in prose so a later attempt
154
+ * meets the measurement before it meets the idea.
155
+ *
156
+ * All three readings are from one transcript,
157
+ * `b818ccad-3581-4773-b9a2-c7272af04ce2`, and they disagree by a factor of
158
+ * about 44 (305 / 7 = 43.6).
159
+ */
160
+ export const STOP_CANDIDATES: readonly Readonly<{
161
+ candidate: string;
162
+ reading: number;
163
+ refused_because: string;
164
+ }>[] = Object.freeze([
165
+ Object.freeze({
166
+ candidate: 'assistant records carrying a `stop_reason`',
167
+ reading: 305,
168
+ refused_because:
169
+ 'counts assistant MESSAGES, not turn completions — every one read `stop_reason: "tool_use"` and none `end_turn`, so it over-counts by about two orders of magnitude (the 1.1 survey established this).',
170
+ }),
171
+ Object.freeze({
172
+ candidate: '`type: "last-prompt"` records',
173
+ reading: 95,
174
+ refused_because:
175
+ 'written once per assistant leaf and repeating the SAME prompt text, so it is a per-turn marker whose mapping onto the `stop` hook event is unverified rather than a published count.',
176
+ }),
177
+ Object.freeze({
178
+ candidate: '`hookInfos` entries whose command carries `--event stop`',
179
+ reading: 7,
180
+ refused_because:
181
+ 'host-authored and event-named — the strongest of the three — but it appears on only 7 of about 95 turns in the same session, so the host records these entries selectively (they co-occur with `hookAdditionalContext` / `preventedContinuation`) and the artefact UNDER-counts dispatches.',
182
+ }),
183
+ ]);
184
+
185
+ /**
186
+ * One denominator reading. These fields and no others.
187
+ *
188
+ * Every field is a bounded scalar: a count, an ISO calendar date, a scope
189
+ * literal, or the one platform literal the survey found countable. Nothing here
190
+ * can hold a path, a project name, a session id, a prompt, or a tool name — the
191
+ * same property the numerator's record carries, asserted the same way.
192
+ */
193
+ export interface HostDenominator {
194
+ /** The only platform with an obtainable host denominator (1.1 survey). */
195
+ platform: 'claude';
196
+ /** Which population the counts are over. See {@link DenominatorScope}. */
197
+ scope: DenominatorScope;
198
+ /** Which rule set produced the counts. See {@link RECONSTRUCTION_RULE_VERSION}. */
199
+ reconstruction_rule_version: number;
200
+ /** Inclusive window start, ISO calendar date (`YYYY-MM-DD`). */
201
+ window_start: string;
202
+ /** Inclusive window end, ISO calendar date (`YYYY-MM-DD`). */
203
+ window_end: string;
204
+ /** Transcripts inside the scope, before windowing. */
205
+ transcripts_found: number;
206
+ /** Project directories skipped because they are outside the scope. */
207
+ transcripts_out_of_scope: number;
208
+ /** Transcripts whose earliest record falls inside the window. */
209
+ sessions_in_window: number;
210
+ /** Transcripts whose earliest record predates the window. */
211
+ sessions_before_window: number;
212
+ /** Transcripts whose earliest record postdates the window. */
213
+ sessions_after_window: number;
214
+ /** Transcripts carrying no parseable timestamped record at all. */
215
+ sessions_undatable: number;
216
+ session_start: number;
217
+ user_prompt_submit: number;
218
+ pre_tool_use: number;
219
+ post_tool_use: number;
220
+ subagent_start: number;
221
+ subagent_stop: number;
222
+ /** `user` records excluded by refinement 1 (`isMeta`). Audit trail. */
223
+ excluded_meta_user_records: number;
224
+ /** `user` records excluded by refinement 2 (`isSidechain`). Audit trail. */
225
+ excluded_sidechain_user_records: number;
226
+ /** Of `pre_tool_use` / `post_tool_use`, how many came from sidechain records. */
227
+ sidechain_tool_use_blocks: number;
228
+ /** Of `subagent_start` / `subagent_stop`, how many came from sidechain records. */
229
+ sidechain_agent_tool_use_blocks: number;
230
+ /** Directories the walk could not read. Never silently zero. */
231
+ unreadable_directories: number;
232
+ /** Transcript lines that did not parse as JSON. Never silently discarded. */
233
+ unparseable_lines: number;
234
+ }
235
+
236
+ /** The committed key set. AC-2 asserts a record's keys against exactly this. */
237
+ export const DENOMINATOR_RECORD_KEYS = Object.freeze([
238
+ 'platform',
239
+ 'scope',
240
+ 'reconstruction_rule_version',
241
+ 'window_start',
242
+ 'window_end',
243
+ 'transcripts_found',
244
+ 'transcripts_out_of_scope',
245
+ 'sessions_in_window',
246
+ 'sessions_before_window',
247
+ 'sessions_after_window',
248
+ 'sessions_undatable',
249
+ 'session_start',
250
+ 'user_prompt_submit',
251
+ 'pre_tool_use',
252
+ 'post_tool_use',
253
+ 'subagent_start',
254
+ 'subagent_stop',
255
+ 'excluded_meta_user_records',
256
+ 'excluded_sidechain_user_records',
257
+ 'sidechain_tool_use_blocks',
258
+ 'sidechain_agent_tool_use_blocks',
259
+ 'unreadable_directories',
260
+ 'unparseable_lines',
261
+ ] as const);
262
+
263
+ type _KeysCoverTheRecord = Assert<
264
+ Exclude<keyof HostDenominator, (typeof DENOMINATOR_RECORD_KEYS)[number]> extends never
265
+ ? true
266
+ : false
267
+ >;
268
+ type _KeysAddNothing = Assert<
269
+ Exclude<(typeof DENOMINATOR_RECORD_KEYS)[number], keyof HostDenominator> extends never
270
+ ? true
271
+ : false
272
+ >;
273
+ /**
274
+ * Fails to compile if {@link HostDenominator} ever grows a key from the
275
+ * journal's `FREE_FORM_KEYS` — the numerator's guard, reused rather than
276
+ * re-implemented, so the two halves cannot drift apart. The list itself is not
277
+ * imported as a value here: only the type-level guard is needed, and the test
278
+ * asserts the runtime mirror against the journal's own export directly.
279
+ */
280
+ type _RecordCarriesNoFreeFormField = Assert<
281
+ [NoFreeForm<HostDenominator>] extends [never] ? false : true
282
+ >;
283
+
284
+ /** Raised when a record is handed to {@link validateDenominator} and fails it. */
285
+ export class DenominatorContractError extends Error {}
286
+
287
+ /** Keys that are not counts. Everything else must be a non-negative integer. */
288
+ const NON_COUNT_KEYS = new Set<string>(['platform', 'scope', 'window_start', 'window_end']);
289
+
290
+ /**
291
+ * Runtime half of the schema guard: an unknown key is **REJECTED, not
292
+ * dropped**, on the same reasoning `_lib/collector_record.ts` states — a
293
+ * producer whose extra field is silently discarded has been told the field is
294
+ * fine, and the leak then lives upstream where this schema cannot see it.
295
+ */
296
+ export function validateDenominator(record: Record<string, unknown>): HostDenominator {
297
+ const allowed = new Set<string>(DENOMINATOR_RECORD_KEYS);
298
+ for (const key of Object.keys(record)) {
299
+ if (!allowed.has(key)) {
300
+ throw new DenominatorContractError(`unknown field '${key}' — REJECTED, not dropped`);
301
+ }
302
+ }
303
+ for (const key of DENOMINATOR_RECORD_KEYS) {
304
+ if (!(key in record)) {
305
+ throw new DenominatorContractError(`missing field '${key}'`);
306
+ }
307
+ }
308
+ if (record.platform !== 'claude') {
309
+ throw new DenominatorContractError(
310
+ `platform must be 'claude' — the only cell set with an obtainable host denominator`,
311
+ );
312
+ }
313
+ if (!(DENOMINATOR_SCOPES as readonly string[]).includes(record.scope as string)) {
314
+ throw new DenominatorContractError(
315
+ `scope must be one of ${DENOMINATOR_SCOPES.join(' | ')} — an unrecorded scope is how ` +
316
+ `a denominator ends up over a different population than its numerator`,
317
+ );
318
+ }
319
+ for (const key of DENOMINATOR_RECORD_KEYS) {
320
+ if (NON_COUNT_KEYS.has(key)) continue;
321
+ const value = record[key];
322
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
323
+ throw new DenominatorContractError(`field '${key}' must be a non-negative integer`);
324
+ }
325
+ }
326
+ for (const key of ['window_start', 'window_end'] as const) {
327
+ const value = record[key];
328
+ if (typeof value !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
329
+ throw new DenominatorContractError(
330
+ `field '${key}' must be an ISO calendar date (YYYY-MM-DD) — a per-second timestamp beside a session count reconstructs working hours`,
331
+ );
332
+ }
333
+ }
334
+ if ((record.window_start as string) > (record.window_end as string)) {
335
+ throw new DenominatorContractError(
336
+ `window_start '${String(record.window_start)}' is after window_end ` +
337
+ `'${String(record.window_end)}' — an inverted window files every transcript as ` +
338
+ `out-of-window and reports a zero denominator instead of a bad input`,
339
+ );
340
+ }
341
+ return record as unknown as HostDenominator;
342
+ }
343
+
344
+ /** A zeroed record for the given scope and window. */
345
+ export function emptyDenominator(
346
+ windowStart: string,
347
+ windowEnd: string,
348
+ scope: DenominatorScope = 'repository',
349
+ ): HostDenominator {
350
+ return validateDenominator({
351
+ platform: 'claude',
352
+ scope,
353
+ reconstruction_rule_version: RECONSTRUCTION_RULE_VERSION,
354
+ window_start: windowStart,
355
+ window_end: windowEnd,
356
+ transcripts_found: 0,
357
+ transcripts_out_of_scope: 0,
358
+ sessions_in_window: 0,
359
+ sessions_before_window: 0,
360
+ sessions_after_window: 0,
361
+ sessions_undatable: 0,
362
+ session_start: 0,
363
+ user_prompt_submit: 0,
364
+ pre_tool_use: 0,
365
+ post_tool_use: 0,
366
+ subagent_start: 0,
367
+ subagent_stop: 0,
368
+ excluded_meta_user_records: 0,
369
+ excluded_sidechain_user_records: 0,
370
+ sidechain_tool_use_blocks: 0,
371
+ sidechain_agent_tool_use_blocks: 0,
372
+ unreadable_directories: 0,
373
+ unparseable_lines: 0,
374
+ });
375
+ }
376
+
377
+ /** Per-transcript counts, before windowing folds them into a total. */
378
+ export interface TranscriptCounts {
379
+ /**
380
+ * MINIMUM record timestamp in the file, not the first one in file order.
381
+ * A transcript whose leading record is back-dated would otherwise be
382
+ * windowed by that record's day, which decides whether the whole file's
383
+ * counts land in the denominator at all (R2 finding 12).
384
+ */
385
+ first_at: string | null;
386
+ user_prompt_submit: number;
387
+ tool_use_blocks: number;
388
+ agent_tool_use_blocks: number;
389
+ sidechain_tool_use_blocks: number;
390
+ sidechain_agent_tool_use_blocks: number;
391
+ excluded_meta_user_records: number;
392
+ excluded_sidechain_user_records: number;
393
+ unparseable_lines: number;
394
+ }
395
+
396
+ /**
397
+ * Apply {@link RECONSTRUCTION_RULES} to one transcript's records.
398
+ *
399
+ * Pure: takes already-parsed records, touches no filesystem, so the rules are
400
+ * testable against inline fixtures and the published counts are reproducible
401
+ * without the measured machine's `~/.claude`.
402
+ */
403
+ export function countTranscript(records: readonly Record<string, unknown>[]): TranscriptCounts {
404
+ const out = emptyTranscriptCounts();
405
+ for (const record of records) foldRecord(out, record);
406
+ return out;
407
+ }
408
+
409
+ /** A zeroed per-transcript accumulator. */
410
+ export function emptyTranscriptCounts(): TranscriptCounts {
411
+ return {
412
+ first_at: null,
413
+ user_prompt_submit: 0,
414
+ tool_use_blocks: 0,
415
+ agent_tool_use_blocks: 0,
416
+ sidechain_tool_use_blocks: 0,
417
+ sidechain_agent_tool_use_blocks: 0,
418
+ excluded_meta_user_records: 0,
419
+ excluded_sidechain_user_records: 0,
420
+ unparseable_lines: 0,
421
+ };
422
+ }
423
+
424
+ /**
425
+ * Apply the rules to a single record. The one place the rules live — the
426
+ * whole-file and the streaming path both call it, so they cannot diverge.
427
+ */
428
+ export function foldRecord(out: TranscriptCounts, record: Record<string, unknown>): void {
429
+ const at = record.timestamp;
430
+ if (typeof at === 'string' && at.length > 0) {
431
+ // MINIMUM, not first-seen. See TranscriptCounts.first_at.
432
+ if (out.first_at === null || at < out.first_at) out.first_at = at;
433
+ }
434
+
435
+ const sidechain = record.isSidechain === true;
436
+
437
+ if (record.type === 'user') {
438
+ // The two exclusion counters are INDEPENDENT: a record carrying both
439
+ // flags increments both. v1 tested `isSidechain` first and returned, so
440
+ // the two counts were published as independent while they were not
441
+ // (R2 finding 11).
442
+ if (sidechain) out.excluded_sidechain_user_records += 1;
443
+ if (record.isMeta === true) out.excluded_meta_user_records += 1;
444
+ if (sidechain || record.isMeta === true) return;
445
+
446
+ const content = (record.message as { content?: unknown } | undefined)?.content;
447
+ const carriesToolResult =
448
+ Array.isArray(content) &&
449
+ content.some(
450
+ (block) =>
451
+ typeof block === 'object' &&
452
+ block !== null &&
453
+ (block as { type?: unknown }).type === 'tool_result',
454
+ );
455
+ if (!carriesToolResult) out.user_prompt_submit += 1;
456
+ return;
457
+ }
458
+
459
+ if (record.type === 'assistant') {
460
+ const content = (record.message as { content?: unknown } | undefined)?.content;
461
+ if (!Array.isArray(content)) return;
462
+ for (const block of content) {
463
+ if (typeof block !== 'object' || block === null) continue;
464
+ const typed = block as { type?: unknown; name?: unknown };
465
+ if (typed.type !== 'tool_use') continue;
466
+ out.tool_use_blocks += 1;
467
+ if (sidechain) out.sidechain_tool_use_blocks += 1;
468
+ if (typed.name === 'Agent' || typed.name === 'Task') {
469
+ out.agent_tool_use_blocks += 1;
470
+ if (sidechain) out.sidechain_agent_tool_use_blocks += 1;
471
+ }
472
+ }
473
+ }
474
+ }
475
+
476
+ /** Fold one transcript's counts into a denominator, honouring the window. */
477
+ export function accumulate(
478
+ into: HostDenominator,
479
+ counts: TranscriptCounts,
480
+ windowStart: string,
481
+ windowEnd: string,
482
+ ): void {
483
+ into.transcripts_found += 1;
484
+ into.unparseable_lines += counts.unparseable_lines;
485
+
486
+ if (counts.first_at === null) {
487
+ into.sessions_undatable += 1;
488
+ return;
489
+ }
490
+ const day = counts.first_at.slice(0, 10);
491
+ if (day < windowStart) {
492
+ into.sessions_before_window += 1;
493
+ return;
494
+ }
495
+ if (day > windowEnd) {
496
+ // v1 filed this under `sessions_before_window`, which is reachable via
497
+ // `--days`, clock skew or a future-dated fixture and was silent because
498
+ // the totals still reconciled (R2 finding 10).
499
+ into.sessions_after_window += 1;
500
+ return;
501
+ }
502
+
503
+ into.sessions_in_window += 1;
504
+ into.session_start += 1;
505
+ into.user_prompt_submit += counts.user_prompt_submit;
506
+ into.pre_tool_use += counts.tool_use_blocks;
507
+ into.post_tool_use += counts.tool_use_blocks;
508
+ into.subagent_start += counts.agent_tool_use_blocks;
509
+ into.subagent_stop += counts.agent_tool_use_blocks;
510
+ into.excluded_meta_user_records += counts.excluded_meta_user_records;
511
+ into.excluded_sidechain_user_records += counts.excluded_sidechain_user_records;
512
+ into.sidechain_tool_use_blocks += counts.sidechain_tool_use_blocks;
513
+ into.sidechain_agent_tool_use_blocks += counts.sidechain_agent_tool_use_blocks;
514
+ }
515
+
516
+ /** The total across the six counted cells — the denominator of the rate. */
517
+ export function totalCountedEvents(record: HostDenominator): number {
518
+ return COUNTED_EVENTS.reduce((sum, event) => sum + record[event], 0);
519
+ }
520
+
521
+ /** The total across the five journal-bound counted cells. */
522
+ export function totalJournalBoundEvents(record: HostDenominator): number {
523
+ return JOURNAL_BOUND_COUNTED_EVENTS.reduce((sum, event) => sum + record[event], 0);
524
+ }
525
+
526
+ /**
527
+ * Claude Code's project-directory name for a working directory.
528
+ *
529
+ * The host replaces every path separator, and every `.`, with `-`. Derived by
530
+ * inspection of the directories this machine carries rather than from a
531
+ * documented rule, which is why {@link repositoryScopeSlugs} returns the slugs
532
+ * it computed: a slug matching no directory is then visible as an empty scope
533
+ * rather than as a silently small denominator.
534
+ */
535
+ export function projectSlug(dir: string): string {
536
+ return dir.replace(/[/.]/g, '-');
537
+ }
538
+
539
+ /** The result of asking git which directories belong to the measured repo. */
540
+ export interface RepositoryScope {
541
+ /** Absolute worktree paths, main checkout first. Empty outside a repo. */
542
+ worktrees: readonly string[];
543
+ /** The project-directory slugs those paths map to. */
544
+ slugs: readonly string[];
545
+ }
546
+
547
+ /**
548
+ * Every worktree of the repository containing `root`, as project slugs.
549
+ *
550
+ * The numerator's journal lives at the repository's COMMON git dir and is
551
+ * therefore shared by every worktree of that repository and reachable from none
552
+ * other. So the matching denominator is exactly this set — which cannot be
553
+ * derived from a path prefix, because a linked worktree may live anywhere (this
554
+ * repository's own live under `/private/tmp/`).
555
+ *
556
+ * `git worktree list --porcelain` is the only source that knows. A failure
557
+ * returns an EMPTY scope rather than falling back to machine-wide: a silent
558
+ * widening is precisely the defect this function exists to fix.
559
+ */
560
+ export function repositoryScopeSlugs(root: string): RepositoryScope {
561
+ let stdout: string;
562
+ try {
563
+ stdout = execFileSync('git', ['-C', root, 'worktree', 'list', '--porcelain'], {
564
+ encoding: 'utf8',
565
+ stdio: ['ignore', 'pipe', 'ignore'],
566
+ });
567
+ } catch {
568
+ return { worktrees: [], slugs: [] };
569
+ }
570
+ const worktrees: string[] = [];
571
+ for (const line of stdout.split('\n')) {
572
+ if (!line.startsWith('worktree ')) continue;
573
+ const dir = line.slice('worktree '.length).trim();
574
+ if (dir.length === 0) continue;
575
+ try {
576
+ worktrees.push(fs.realpathSync(dir));
577
+ } catch {
578
+ worktrees.push(dir);
579
+ }
580
+ }
581
+ return { worktrees, slugs: worktrees.map(projectSlug) };
582
+ }
583
+
584
+ /** What a scoped walk found, and what it could not read. */
585
+ export interface TranscriptWalk {
586
+ files: readonly string[];
587
+ /** Project directories skipped because they are outside the scope. */
588
+ outOfScope: number;
589
+ /** Directories that could not be listed. Reported, never swallowed. */
590
+ unreadable: number;
591
+ }
592
+
593
+ /**
594
+ * Every `*.jsonl` under a Claude Code projects root, recursively.
595
+ *
596
+ * Recursive on purpose: a flat one-level walk under-enumerates this machine's
597
+ * store by more than half (992 of 2,300 files), and a denominator that silently
598
+ * misses two thirds of its population is worse than none. Symlinked directories
599
+ * and transcripts are followed for the same reason — `isDirectory()` and
600
+ * `isFile()` are both false for a symlink, and v1 skipped them silently.
601
+ *
602
+ * `slugs` restricts the walk to the given top-level project directories. An
603
+ * EMPTY array means "no directory is in scope" and yields no files — never "all
604
+ * of them", which is the widening the scope field exists to prevent.
605
+ */
606
+ export function findTranscripts(projectsRoot: string, slugs?: readonly string[]): TranscriptWalk {
607
+ const files: string[] = [];
608
+ let unreadable = 0;
609
+ let outOfScope = 0;
610
+ const inScope = slugs === undefined ? null : new Set(slugs);
611
+
612
+ const walk = (dir: string): void => {
613
+ let entries: fs.Dirent[];
614
+ try {
615
+ entries = fs.readdirSync(dir, { withFileTypes: true });
616
+ } catch {
617
+ unreadable += 1;
618
+ return;
619
+ }
620
+ for (const entry of entries) {
621
+ const full = path.join(dir, entry.name);
622
+ let isDir = entry.isDirectory();
623
+ let isFile = entry.isFile();
624
+ if (entry.isSymbolicLink()) {
625
+ try {
626
+ const st = fs.statSync(full);
627
+ isDir = st.isDirectory();
628
+ isFile = st.isFile();
629
+ } catch {
630
+ unreadable += 1;
631
+ continue;
632
+ }
633
+ }
634
+ if (isDir) walk(full);
635
+ else if (isFile && entry.name.endsWith('.jsonl')) files.push(full);
636
+ }
637
+ };
638
+
639
+ let top: fs.Dirent[];
640
+ try {
641
+ top = fs.readdirSync(projectsRoot, { withFileTypes: true });
642
+ } catch {
643
+ return { files: [], outOfScope: 0, unreadable: 1 };
644
+ }
645
+ for (const entry of top) {
646
+ const full = path.join(projectsRoot, entry.name);
647
+ if (entry.isFile() && entry.name.endsWith('.jsonl')) {
648
+ // A transcript directly under the root belongs to no project
649
+ // directory, so it can never be attributed to a repository scope.
650
+ if (inScope === null) files.push(full);
651
+ else outOfScope += 1;
652
+ continue;
653
+ }
654
+ if (inScope !== null && !inScope.has(entry.name)) {
655
+ outOfScope += 1;
656
+ continue;
657
+ }
658
+ walk(full);
659
+ }
660
+ files.sort();
661
+ return { files, outOfScope, unreadable };
662
+ }
663
+
664
+ /** Stream one transcript file and count it. Unparseable lines are COUNTED. */
665
+ export async function countTranscriptFile(file: string): Promise<TranscriptCounts> {
666
+ const out = emptyTranscriptCounts();
667
+ const stream = readline.createInterface({
668
+ input: fs.createReadStream(file, { encoding: 'utf8' }),
669
+ crlfDelay: Infinity,
670
+ });
671
+ for await (const line of stream) {
672
+ if (line.trim().length === 0) continue;
673
+ try {
674
+ const parsed = JSON.parse(line);
675
+ if (typeof parsed === 'object' && parsed !== null) {
676
+ foldRecord(out, parsed as Record<string, unknown>);
677
+ } else {
678
+ out.unparseable_lines += 1;
679
+ }
680
+ } catch {
681
+ // A truncated tail line is not a host event — but it is not nothing
682
+ // either, and every other exclusion class here is published.
683
+ out.unparseable_lines += 1;
684
+ }
685
+ }
686
+ return out;
687
+ }