@event4u/agent-config 16.1.0 → 16.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +98 -257
  5. package/README.md +14 -12
  6. package/dist/agent-src/commands/analyze/inbox.md +1 -1
  7. package/dist/agent-src/commands/analyze/roadmap-repos.md +1 -1
  8. package/dist/agent-src/commands/bug/fix.md +17 -2
  9. package/dist/agent-src/commands/feature/plan.md +1 -1
  10. package/dist/agent-src/commands/feature/roadmap.md +1 -1
  11. package/dist/agent-src/commands/fix/ci.md +1 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/jira-ticket.md +1 -1
  14. package/dist/agent-src/commands/roadmap/create.md +1 -1
  15. package/dist/agent-src/commands/roadmap/materialize.md +1 -1
  16. package/dist/agent-src/commands/roadmap/process-full.md +5 -5
  17. package/dist/agent-src/commands/roadmap/resolve-blockers.md +361 -0
  18. package/dist/agent-src/commands/roadmap/triage-parked.md +325 -0
  19. package/dist/agent-src/commands/roadmap.md +18 -4
  20. package/dist/agent-src/commands/tests/create.md +17 -3
  21. package/dist/agent-src/commands/tests/execute.md +22 -5
  22. package/dist/agent-src/commands/work.md +4 -0
  23. package/dist/agent-src/contexts/authority/decision-revisit-gate-enforcement.md +43 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/design-fidelity-enforcement.md +24 -0
  25. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +6 -6
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +4 -8
  27. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +32 -2
  28. package/dist/agent-src/contexts/execution/session-canary-enforcement-history.md +67 -0
  29. package/dist/agent-src/contexts/execution/toolchain-resolver.md +101 -7
  30. package/dist/agent-src/rules/active-remediation.md +1 -1
  31. package/dist/agent-src/rules/autonomous-execution.md +1 -0
  32. package/dist/agent-src/rules/broken-access-control.md +1 -0
  33. package/dist/agent-src/rules/command-suggestion-policy.md +1 -0
  34. package/dist/agent-src/rules/context-hygiene.md +1 -1
  35. package/dist/agent-src/rules/decision-revisit-gate.md +16 -33
  36. package/dist/agent-src/rules/design-fidelity.md +13 -16
  37. package/dist/agent-src/rules/doc-screenshot-hygiene.md +1 -0
  38. package/dist/agent-src/rules/domain-safety-disclaimer.md +1 -0
  39. package/dist/agent-src/rules/domain-safety-pii.md +1 -0
  40. package/dist/agent-src/rules/domain-safety-retention.md +1 -0
  41. package/dist/agent-src/rules/engineering-safety-floor.md +1 -0
  42. package/dist/agent-src/rules/evaluator-independence.md +3 -2
  43. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  44. package/dist/agent-src/rules/finance-safety-floor.md +1 -0
  45. package/dist/agent-src/rules/git-history-discipline.md +1 -0
  46. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  47. package/dist/agent-src/rules/legal-safety-floor.md +3 -2
  48. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  49. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  50. package/dist/agent-src/rules/media-governance-routing.md +14 -17
  51. package/dist/agent-src/rules/persona-governance.md +2 -2
  52. package/dist/agent-src/rules/provider-lifecycle-discipline.md +1 -1
  53. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  54. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  55. package/dist/agent-src/rules/runtime-safety.md +1 -0
  56. package/dist/agent-src/rules/secret-vcs-guard.md +1 -0
  57. package/dist/agent-src/rules/security-sensitive-stop.md +3 -2
  58. package/dist/agent-src/rules/session-canary.md +8 -62
  59. package/dist/agent-src/rules/settings-ask-protocol.md +1 -0
  60. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  61. package/dist/agent-src/rules/strategy-safety-floor.md +1 -0
  62. package/dist/agent-src/rules/tool-safety.md +1 -0
  63. package/dist/agent-src/rules/ui-audit-gate.md +1 -2
  64. package/dist/agent-src/rules/untrusted-input-defense.md +1 -0
  65. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  66. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  67. package/dist/agent-src/scripts/deferral_carry.ts +339 -0
  68. package/dist/agent-src/scripts/update_roadmap_progress.ts +4 -1
  69. package/dist/agent-src/skills/accessibility-auditor/data/aria-patterns.csv +1 -1
  70. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +2 -2
  71. package/dist/agent-src/skills/api-design/data/manifest.json +2 -2
  72. package/dist/agent-src/skills/api-testing/SKILL.md +17 -0
  73. package/dist/agent-src/skills/code-intelligence/SKILL.md +14 -2
  74. package/dist/agent-src/skills/design-review/SKILL.md +30 -4
  75. package/dist/agent-src/skills/design-review/references/verification-automation.md +32 -0
  76. package/dist/agent-src/skills/design-system-capture/references/import-procedure.md +1 -1
  77. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +18 -3
  78. package/dist/agent-src/skills/existing-ui-audit/references/component-taxonomy-detection.md +56 -0
  79. package/dist/agent-src/skills/fe-design/SKILL.md +1 -1
  80. package/dist/agent-src/skills/iconography/SKILL.md +1 -1
  81. package/dist/agent-src/skills/js-library-packaging/SKILL.md +2 -2
  82. package/dist/agent-src/skills/markitdown/SKILL.md +4 -0
  83. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  84. package/dist/agent-src/skills/playwright-testing/SKILL.md +30 -6
  85. package/dist/agent-src/skills/quality-tools/SKILL.md +11 -1
  86. package/dist/agent-src/skills/quality-tools/references/go-tools.md +76 -0
  87. package/dist/agent-src/skills/quality-tools/references/python-tools.md +104 -0
  88. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  89. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  90. package/dist/agent-src/skills/storybook-workshop/SKILL.md +3 -3
  91. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +1 -1
  92. package/dist/agent-src/skills/test-case-discovery/SKILL.md +7 -0
  93. package/dist/agent-src/skills/test-driven-development/SKILL.md +17 -0
  94. package/dist/agent-src/skills/test-performance/SKILL.md +19 -1
  95. package/dist/agent-src/skills/ui-component-architect/SKILL.md +25 -2
  96. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  97. package/dist/agent-src/templates/roadmaps.md +30 -0
  98. package/dist/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  99. package/dist/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  100. package/dist/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  101. package/dist/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  102. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  103. package/dist/agent-src/templates/scripts/work_engine/state.ts +57 -7
  104. package/dist/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  105. package/dist/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  106. package/dist/cli/python/knowledge_ingest.js +1 -1
  107. package/dist/cli/python/workspace_drive.js +1 -1
  108. package/dist/cli/registry.js +1 -1
  109. package/dist/cli-delegate/archive_completed_roadmaps.js +92 -12
  110. package/dist/cli-delegate/check_update_banner.js +12 -1
  111. package/dist/cli-delegate/chunk-523HCFYO.js +90 -0
  112. package/dist/cli-delegate/{chunk-M2DPGFZ4.js → chunk-6V6TA25H.js} +22 -152
  113. package/dist/cli-delegate/chunk-7IQE3D5S.js +191 -0
  114. package/dist/cli-delegate/{chunk-6KFEC3G7.js → chunk-CQWX336L.js} +1 -1
  115. package/dist/cli-delegate/chunk-DEIV7XP7.js +108 -0
  116. package/dist/cli-delegate/chunk-EEHDXSYD.js +2040 -0
  117. package/dist/cli-delegate/{chunk-P6ZHP5W2.js → chunk-GKE7ZVFA.js} +4 -4
  118. package/dist/cli-delegate/chunk-JQOM7TTM.js +1201 -0
  119. package/dist/cli-delegate/{chunk-UNCRJBT3.js → chunk-JQVYKIZA.js} +41 -0
  120. package/dist/cli-delegate/{chunk-FC75PGJE.js → chunk-JY2I2DXV.js} +12 -1
  121. package/dist/cli-delegate/chunk-KB5FZ655.js +208 -0
  122. package/dist/cli-delegate/{chunk-YUM5KURG.js → chunk-KR6EM23A.js} +235 -1455
  123. package/dist/cli-delegate/{chunk-LTYVIY76.js → chunk-LIYTLH6O.js} +1 -1
  124. package/dist/cli-delegate/chunk-NQ7WT43P.js +2729 -0
  125. package/dist/cli-delegate/chunk-NXEILF2K.js +2160 -0
  126. package/dist/cli-delegate/{chunk-5R7HOLAF.js → chunk-NYX3L2PZ.js} +1 -1
  127. package/dist/cli-delegate/{chunk-4E2W63DA.js → chunk-OKJUIAPS.js} +62 -1
  128. package/dist/cli-delegate/{chunk-QAJS5YWY.js → chunk-PHD7OOLE.js} +2 -1
  129. package/dist/cli-delegate/{chunk-RGNIWTEA.js → chunk-QLDHIPWR.js} +1 -1
  130. package/dist/cli-delegate/{chunk-HDVVGPQW.js → chunk-RQNNW7IF.js} +1405 -567
  131. package/dist/cli-delegate/{chunk-S3VFXMTM.js → chunk-S4UMZNES.js} +1 -1
  132. package/dist/cli-delegate/{chunk-6KM6ORRY.js → chunk-S4YWNRKO.js} +24 -8
  133. package/dist/cli-delegate/{chunk-GJCBB2UG.js → chunk-TRI6DQZ6.js} +3054 -325
  134. package/dist/cli-delegate/chunk-ULQRUR23.js +208 -0
  135. package/dist/cli-delegate/{chunk-NUHLI2RX.js → chunk-YCU3TIXH.js} +2 -0
  136. package/dist/cli-delegate/chunk-ZBZV2G5R.js +210 -0
  137. package/dist/cli-delegate/{chunk-WGXTVKCQ.js → chunk-ZUZKZYCN.js} +5 -3
  138. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  139. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  140. package/dist/cli-delegate/cmd_conformance.js +1862 -809
  141. package/dist/cli-delegate/cmd_doctor.js +13 -6
  142. package/dist/cli-delegate/cmd_doctor_neighbours.js +23 -0
  143. package/dist/cli-delegate/cmd_explain.js +5 -5
  144. package/dist/cli-delegate/cmd_export.js +11 -8
  145. package/dist/cli-delegate/cmd_fleet.js +3 -3
  146. package/dist/cli-delegate/cmd_handoff.js +10 -7
  147. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  148. package/dist/cli-delegate/cmd_memory_get.js +3 -1
  149. package/dist/cli-delegate/cmd_migrate.js +2 -2
  150. package/dist/cli-delegate/cmd_packs_active.js +3 -3
  151. package/dist/cli-delegate/cmd_preflight.js +6 -6
  152. package/dist/cli-delegate/cmd_prune.js +11 -8
  153. package/dist/cli-delegate/cmd_refresh.js +2 -1
  154. package/dist/cli-delegate/cmd_route_audit.js +8 -6
  155. package/dist/cli-delegate/cmd_route_explain.js +4 -4
  156. package/dist/cli-delegate/cmd_session_recycle.js +4 -3
  157. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  158. package/dist/cli-delegate/cmd_settings_migrate.js +11 -8
  159. package/dist/cli-delegate/cmd_settings_set.js +4 -4
  160. package/dist/cli-delegate/cmd_sync.js +11 -8
  161. package/dist/cli-delegate/cmd_uninstall.js +11 -8
  162. package/dist/cli-delegate/cmd_update.js +1 -1
  163. package/dist/cli-delegate/cmd_upgrade.js +3 -2
  164. package/dist/cli-delegate/cmd_validate.js +11 -8
  165. package/dist/cli-delegate/cmd_versions.js +1 -1
  166. package/dist/cli-delegate/deferral_carry.js +16 -0
  167. package/dist/cli-delegate/gate_execute.js +2 -2
  168. package/dist/cli-delegate/roadmap_gates.js +5 -5
  169. package/dist/cli-delegate/update_roadmap_progress.js +1 -1
  170. package/dist/discovery/deprecation-report.md +1 -1
  171. package/dist/discovery/discovery-manifest.json +132 -80
  172. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  173. package/dist/discovery/discovery-manifest.summary.md +3 -3
  174. package/dist/discovery/dormancy-report.md +1 -1
  175. package/dist/discovery/orphan-report.md +1 -1
  176. package/dist/discovery/packs.json +7 -5
  177. package/dist/discovery/trust-report.md +2 -2
  178. package/dist/discovery/workspaces.json +6 -4
  179. package/dist/hooks/dispatch.js +7972 -5186
  180. package/dist/hooks/dispatch.sha256 +1 -0
  181. package/dist/install/claudePathsPlan.js +47 -6
  182. package/dist/install/claudeRuleRewrite.js +7 -0
  183. package/dist/install/emit_host_rules_cli.js +39 -36
  184. package/dist/install/globalRuleScope.js +87 -0
  185. package/dist/install/host_rule_ownership.js +160 -0
  186. package/dist/install/install.mjs +2226 -1055
  187. package/dist/install/installThinLayer.js +261 -0
  188. package/dist/install/installedRuleLinks.js +176 -0
  189. package/dist/install/wizard-plan.js +24 -0
  190. package/dist/mcp/registry-manifest.json +3 -3
  191. package/dist/mcp/server.json +2 -2
  192. package/dist/mcp/server.mjs +40913 -34865
  193. package/dist/scripts/_lib/agent_settings.js +11 -0
  194. package/dist/scripts/_lib/claude_settings_hooks.js +10 -8
  195. package/dist/scripts/_lib/installed_layer.js +378 -0
  196. package/dist/scripts/_lib/lean_projection_mode.js +218 -15
  197. package/dist/scripts/_lib/rule_consequence_class.js +45 -0
  198. package/dist/scripts/_lib/rule_injection.js +67 -10
  199. package/dist/scripts/_lib/rule_law_section.js +122 -0
  200. package/dist/scripts/_lib/thin_rules.js +458 -0
  201. package/dist/scripts/_lib/windsurf_render.js +60 -0
  202. package/dist/scripts/condense.js +14 -26
  203. package/dist/scripts/project_thin_rules.js +14 -294
  204. package/dist/server/schemas/settings.js +29 -0
  205. package/dist/shared/skillRanking.js +74 -13
  206. package/dist/ui/assets/index-Cwq4d0hX.js +23 -0
  207. package/dist/ui/assets/index-Cyjy8bWO.css +1 -0
  208. package/dist/ui/index.html +2 -2
  209. package/docs/contracts/settings-classes.md +10 -6
  210. package/package.json +4 -4
  211. package/src/agent-src/scripts/archive_completed_roadmaps.ts +115 -20
  212. package/src/agent-src/scripts/deferral_carry.ts +339 -0
  213. package/src/agent-src/scripts/update_roadmap_progress.ts +4 -1
  214. package/src/agent-src/templates/scripts/work_engine/directives/ui/app_spec.ts +10 -4
  215. package/src/agent-src/templates/scripts/work_engine/directives/ui/apply.ts +302 -21
  216. package/src/agent-src/templates/scripts/work_engine/directives/ui/audit.ts +22 -3
  217. package/src/agent-src/templates/scripts/work_engine/directives/ui/scaffold.ts +6 -1
  218. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +774 -109
  219. package/src/agent-src/templates/scripts/work_engine/state.ts +57 -7
  220. package/src/agent-src/templates/scripts/work_engine/taxonomy/detect.ts +500 -0
  221. package/src/agent-src/templates/scripts/work_engine/taxonomy/place.ts +183 -0
  222. package/src/config/agent-settings.template.yml +91 -22
  223. package/src/config/ci-local-parity.yml +18 -0
  224. package/src/config/continuity-surface.json +9 -2
  225. package/src/config/evaluator-budgets.json +4 -4
  226. package/src/config/gate-coverage.yml +327 -3
  227. package/src/config/gate-violation-baselines.json +21 -9
  228. package/src/config/hook-bundle-budget.json +25 -0
  229. package/src/config/hook-latency-budget.json +21 -0
  230. package/src/config/hook-token-budget.json +8 -3
  231. package/src/config/host-instruction-limits.json +33 -0
  232. package/src/config/metric-registry.yml +114 -0
  233. package/src/config/placeholder-drift-budget.json +10 -0
  234. package/src/config/routing-coverage-seed.json +38 -3
  235. package/src/config/rule-activation-census.json +7 -3
  236. package/src/config/rule-consequence-class.json +161 -0
  237. package/src/config/rule-law-ceilings.json +99 -0
  238. package/src/install/claudePathsPlan.ts +46 -4
  239. package/src/install/claudeRuleRewrite.ts +10 -1
  240. package/src/install/emit_host_rules_cli.ts +43 -34
  241. package/src/install/globalRuleScope.ts +109 -0
  242. package/src/install/host_rule_ownership.ts +170 -0
  243. package/src/install/installThinLayer.ts +312 -0
  244. package/src/install/installedRuleLinks.ts +220 -0
  245. package/src/install/wizard-plan.ts +24 -0
  246. package/src/scripts/_cli/cmd_doctor.ts +28 -90
  247. package/src/scripts/_cli/cmd_doctor_neighbours.ts +293 -0
  248. package/src/scripts/_cli/doctor_execution.ts +100 -17
  249. package/src/scripts/_cli/doctor_network_posture.ts +226 -0
  250. package/src/scripts/_dispatch.bash +16 -2
  251. package/src/scripts/_lib/agent_settings.ts +11 -0
  252. package/src/scripts/_lib/body_portable.ts +102 -0
  253. package/src/scripts/_lib/cc_transcript.ts +132 -1
  254. package/src/scripts/_lib/claude_settings_hooks.ts +10 -8
  255. package/src/scripts/_lib/concern_sla_window.ts +200 -0
  256. package/src/scripts/_lib/estate_offsets.ts +241 -0
  257. package/src/scripts/_lib/exemption_shape.ts +143 -0
  258. package/src/scripts/_lib/fnv.ts +23 -0
  259. package/src/scripts/_lib/foreign_scan.ts +106 -0
  260. package/src/scripts/_lib/forge_protection.ts +114 -0
  261. package/src/scripts/_lib/forge_reader.ts +558 -0
  262. package/src/scripts/_lib/gitignore_block.ts +314 -0
  263. package/src/scripts/_lib/global_deploy_inventory.ts +32 -0
  264. package/src/scripts/_lib/graph_feeder_record.ts +214 -0
  265. package/src/scripts/_lib/hook_settings.ts +73 -0
  266. package/src/scripts/_lib/host_capability.ts +40 -19
  267. package/src/scripts/_lib/host_env_write.ts +111 -0
  268. package/src/scripts/_lib/host_hook_merge.ts +165 -0
  269. package/src/scripts/_lib/installed_layer.ts +538 -0
  270. package/src/scripts/_lib/json_merge.ts +82 -0
  271. package/src/scripts/_lib/json_pointers.ts +93 -11
  272. package/src/scripts/_lib/lean_projection_mode.ts +275 -15
  273. package/src/scripts/_lib/llm_proposer_transport.ts +14 -4
  274. package/src/scripts/_lib/machine_wake.ts +16 -3
  275. package/src/scripts/_lib/neighbour_census.ts +760 -0
  276. package/src/scripts/_lib/neighbour_scan.ts +122 -0
  277. package/src/scripts/_lib/neighbour_tool_use.ts +189 -0
  278. package/src/scripts/_lib/obligations.ts +119 -8
  279. package/src/scripts/_lib/probe_inputs.ts +271 -0
  280. package/src/scripts/_lib/prompt_shape.ts +46 -0
  281. package/src/scripts/_lib/read_surface_scan.ts +322 -0
  282. package/src/scripts/_lib/release_highlights.ts +2 -1
  283. package/src/scripts/_lib/release_migration_gate.ts +19 -3
  284. package/src/scripts/_lib/reserved_name_sweep.ts +73 -0
  285. package/src/scripts/_lib/retrieval_sanitize.ts +77 -16
  286. package/src/scripts/_lib/review_coverage.ts +134 -0
  287. package/src/scripts/_lib/rule_consequence_class.ts +71 -0
  288. package/src/scripts/_lib/rule_injection.ts +130 -10
  289. package/src/scripts/_lib/rule_law_section.ts +147 -0
  290. package/src/scripts/_lib/rule_layer_overlap.ts +58 -0
  291. package/src/scripts/_lib/shell_write_shapes.ts +108 -0
  292. package/src/scripts/_lib/skill_origin.ts +254 -0
  293. package/src/scripts/_lib/structural_hiding.ts +622 -0
  294. package/src/scripts/_lib/structured_ask.ts +64 -21
  295. package/src/scripts/_lib/thin_rules.ts +540 -0
  296. package/src/scripts/_lib/touched_file_quality.ts +434 -0
  297. package/src/scripts/_lib/turn_end_refusals.ts +600 -4
  298. package/src/scripts/_lib/turn_end_transcript.ts +216 -0
  299. package/src/scripts/_lib/verification_command.ts +324 -0
  300. package/src/scripts/_lib/verification_evidence.ts +647 -0
  301. package/src/scripts/_lib/verify_clause.ts +280 -0
  302. package/src/scripts/_lib/windsurf_render.ts +63 -0
  303. package/src/scripts/ai_council/cli_call_budget.ts +13 -5
  304. package/src/scripts/ai_council/clients.ts +26 -57
  305. package/src/scripts/ai_council/config.ts +1 -1
  306. package/src/scripts/ai_council/vendor_defaults.ts +45 -0
  307. package/src/scripts/ai_team/team_dispatch.ts +4 -0
  308. package/src/scripts/audit_skill_overlap.ts +261 -0
  309. package/src/scripts/before_complete_hook.ts +573 -25
  310. package/src/scripts/bench_hook_latency.ts +412 -5
  311. package/src/scripts/bench_touched_file_quality.ts +238 -0
  312. package/src/scripts/cache_realization_report.ts +61 -1
  313. package/src/scripts/check_argument_hint.ts +287 -0
  314. package/src/scripts/check_claims.ts +125 -1
  315. package/src/scripts/check_enforcement_coverage.ts +38 -9
  316. package/src/scripts/check_enforcement_matrix.ts +621 -22
  317. package/src/scripts/check_estate_count.ts +130 -153
  318. package/src/scripts/check_finding_dispositions.ts +138 -7
  319. package/src/scripts/check_generator_sync.ts +71 -0
  320. package/src/scripts/check_hook_bundle_composition.ts +370 -0
  321. package/src/scripts/check_host_docs_digest.ts +786 -0
  322. package/src/scripts/check_host_format_column.ts +559 -0
  323. package/src/scripts/check_input_references.ts +228 -0
  324. package/src/scripts/check_inputs_parity.ts +235 -0
  325. package/src/scripts/check_kernel_edit_ratified.ts +89 -9
  326. package/src/scripts/check_kill_switch_table.ts +294 -0
  327. package/src/scripts/check_memory.ts +7 -1
  328. package/src/scripts/check_placeholder_drift.ts +221 -0
  329. package/src/scripts/check_read_surface_coverage.ts +515 -0
  330. package/src/scripts/check_release_highlights.ts +10 -0
  331. package/src/scripts/check_release_holds.ts +2 -1
  332. package/src/scripts/check_release_pr_shape.ts +38 -15
  333. package/src/scripts/check_routing_coverage.ts +378 -11
  334. package/src/scripts/check_standing_rule_delivery.ts +33 -13
  335. package/src/scripts/check_static_parity.ts +17 -0
  336. package/src/scripts/check_verify_expectation_delta.ts +521 -0
  337. package/src/scripts/ci_settle.ts +145 -19
  338. package/src/scripts/closure_scan.ts +115 -1
  339. package/src/scripts/code_graph/detect.ts +127 -7
  340. package/src/scripts/code_graph/foreign.ts +194 -0
  341. package/src/scripts/code_graph/query.ts +217 -4
  342. package/src/scripts/code_graph/types.ts +26 -2
  343. package/src/scripts/code_graph/validate.ts +3 -1
  344. package/src/scripts/code_graph/verbs.ts +103 -0
  345. package/src/scripts/compile_hook_manifest.ts +90 -14
  346. package/src/scripts/condense.ts +14 -27
  347. package/src/scripts/estate_exemption_shape.ts +202 -0
  348. package/src/scripts/external_sources_denylist.json +29 -4
  349. package/src/scripts/generate_host_cost_table.ts +1 -1
  350. package/src/scripts/hook_manifest.json +1 -1
  351. package/src/scripts/hook_manifest.yaml +192 -14
  352. package/src/scripts/hooks/block_config_weakening.ts +294 -4
  353. package/src/scripts/hooks/block_kernel_rule_writes.ts +9 -78
  354. package/src/scripts/hooks/block_plumbing_writes.ts +342 -0
  355. package/src/scripts/hooks/bundle_integrity.ts +291 -0
  356. package/src/scripts/hooks/chain_nudge_hook.ts +1 -2
  357. package/src/scripts/hooks/code_graph_context_hook.ts +253 -25
  358. package/src/scripts/hooks/comment_discipline_hook.ts +1 -3
  359. package/src/scripts/hooks/concern_failure_policy.ts +280 -0
  360. package/src/scripts/hooks/concern_registry.ts +2 -0
  361. package/src/scripts/hooks/concern_timings.ts +94 -0
  362. package/src/scripts/hooks/delegation_nudge_hook.ts +1 -2
  363. package/src/scripts/hooks/design_pass_hook.ts +100 -9
  364. package/src/scripts/hooks/design_slop_hook.ts +1 -2
  365. package/src/scripts/hooks/dispatch_hook.ts +77 -71
  366. package/src/scripts/hooks/edit_shape_hook.ts +1 -2
  367. package/src/scripts/hooks/end_review_nudge_hook.ts +1 -1
  368. package/src/scripts/hooks/evidence_independence.ts +1 -2
  369. package/src/scripts/hooks/exit_codes.ts +129 -0
  370. package/src/scripts/hooks/host_lowering.json +1 -0
  371. package/src/scripts/hooks/host_lowering.ts +146 -3
  372. package/src/scripts/hooks/host_lowering.yaml +262 -46
  373. package/src/scripts/hooks/host_semantics.ts +30 -2
  374. package/src/scripts/hooks/injection_budget.ts +9 -2
  375. package/src/scripts/hooks/interruption_ledger_hook.ts +1 -2
  376. package/src/scripts/hooks/journal_record_hook.ts +1 -2
  377. package/src/scripts/hooks/memory_recall_hook.ts +1 -2
  378. package/src/scripts/hooks/obligation_settle_hook.ts +151 -5
  379. package/src/scripts/hooks/one_question_per_ask_hook.ts +43 -6
  380. package/src/scripts/hooks/orchestration_record_hook.ts +1 -2
  381. package/src/scripts/hooks/payload_stub.ts +10 -1
  382. package/src/scripts/hooks/permission_gate.ts +1 -2
  383. package/src/scripts/hooks/push_settle_hook.ts +1 -3
  384. package/src/scripts/hooks/replay_hook.ts +2 -1
  385. package/src/scripts/hooks/reread_guard_hook.ts +1 -2
  386. package/src/scripts/hooks/review_baseline_hook.ts +1 -2
  387. package/src/scripts/hooks/rtk_wrap_hook.ts +1 -2
  388. package/src/scripts/hooks/rule_inject_hook.ts +765 -68
  389. package/src/scripts/hooks/run_continuation_hook.ts +13 -15
  390. package/src/scripts/hooks/skill_route_hook.ts +1 -2
  391. package/src/scripts/hooks/source_first_gate_hook.ts +1 -2
  392. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +1 -2
  393. package/src/scripts/hooks/subagent_ledger_hook.ts +1 -2
  394. package/src/scripts/hooks/suggestion_capture_hook.ts +1 -1
  395. package/src/scripts/hooks/table_fingerprint.ts +70 -0
  396. package/src/scripts/hooks/telemetry_flush_hook.ts +1 -2
  397. package/src/scripts/hooks/telemetry_usage_hook.ts +65 -10
  398. package/src/scripts/hooks/tool_result_bytes_hook.ts +93 -9
  399. package/src/scripts/hooks/turn_end_gate_hook.ts +421 -324
  400. package/src/scripts/hooks/ui_route_nudge_hook.ts +1 -2
  401. package/src/scripts/hooks_status.ts +112 -0
  402. package/src/scripts/injection_scan_hook.ts +7 -0
  403. package/src/scripts/install.ts +75 -189
  404. package/src/scripts/installed_layer_report.ts +103 -0
  405. package/src/scripts/language_mirror_hook.ts +15 -6
  406. package/src/scripts/learning_sidecar.ts +119 -8
  407. package/src/scripts/lint_deny_text.ts +419 -0
  408. package/src/scripts/lint_exit_codes.ts +262 -0
  409. package/src/scripts/lint_hook_manifest.ts +108 -0
  410. package/src/scripts/lint_major_migration_sections.ts +156 -26
  411. package/src/scripts/lint_pack_boundaries.ts +63 -5
  412. package/src/scripts/lint_roadmap_blockers.ts +78 -12
  413. package/src/scripts/lint_rule_law_section.ts +517 -0
  414. package/src/scripts/lint_skill_descriptions.ts +1 -1
  415. package/src/scripts/lint_skill_scripts_readonly.ts +1 -1
  416. package/src/scripts/lint_workflow_security.ts +161 -5
  417. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -0
  418. package/src/scripts/mcp_server/graph_tools.ts +72 -3
  419. package/src/scripts/mcp_server/prompts.ts +142 -1
  420. package/src/scripts/measure_routing_signal.ts +54 -16
  421. package/src/scripts/measure_skill_ranker_baseline.ts +515 -53
  422. package/src/scripts/measure_turn_end_gate.ts +193 -0
  423. package/src/scripts/memory_learn_hook.ts +91 -6
  424. package/src/scripts/memory_lookup.ts +1 -1
  425. package/src/scripts/model_rule_injection.ts +52 -5
  426. package/src/scripts/prepack-check.mjs +53 -0
  427. package/src/scripts/project_thin_rules.ts +34 -327
  428. package/src/scripts/release_publication.ts +13 -1
  429. package/src/scripts/report_evidence_temperature.ts +657 -0
  430. package/src/scripts/report_installed_rule_links.ts +157 -0
  431. package/src/scripts/report_invocation_surface.ts +383 -0
  432. package/src/scripts/report_label_agreement.ts +233 -0
  433. package/src/scripts/report_obligation_carriers.ts +699 -0
  434. package/src/scripts/report_obligation_mechanism.ts +230 -0
  435. package/src/scripts/report_obligation_writer_split.ts +236 -0
  436. package/src/scripts/report_single_token_triggers.ts +277 -0
  437. package/src/scripts/report_skill_menu_census.ts +208 -0
  438. package/src/scripts/report_skill_ranker_confusion.ts +442 -0
  439. package/src/scripts/report_standing_payload_by_host.ts +188 -15
  440. package/src/scripts/report_verification_record_coverage.ts +306 -0
  441. package/src/scripts/roadmap_verify_share.ts +213 -0
  442. package/src/scripts/rule_activation_census.ts +5 -2
  443. package/src/scripts/rule_trigger_eval.ts +9 -9
  444. package/src/scripts/schemas/command.schema.json +44 -0
  445. package/src/scripts/schemas/review-findings.schema.json +7 -2
  446. package/src/scripts/schemas/rule.schema.json +5 -0
  447. package/src/scripts/schemas/skill.schema.json +44 -0
  448. package/src/scripts/self_review_gate.ts +421 -17
  449. package/src/scripts/semantic_parity_census.ts +314 -0
  450. package/src/scripts/session_eol_report.ts +54 -1
  451. package/src/scripts/skill_tools/score_skill_relevance.ts +290 -25
  452. package/src/scripts/sweep_dead_scan_roots.ts +1 -1
  453. package/src/scripts/sweep_skill_ranker_signals.ts +129 -0
  454. package/src/scripts/sync_gitignore.ts +29 -235
  455. package/src/scripts/trigger_eval_grandfather.json +0 -7
  456. package/src/scripts/trigger_eval_rotation.ts +122 -27
  457. package/src/scripts/ui_conformance_probe.ts +156 -4
  458. package/src/scripts/update_prices.ts +85 -3
  459. package/src/scripts/write_bundle_digest.mjs +74 -0
  460. package/src/server/schemas/settings.ts +41 -0
  461. package/src/shared/skillRanking.ts +117 -11
  462. package/src/templates/consumer-settings/ONBOARDING.md +1 -0
  463. package/dist/cli-delegate/chunk-FXYUYU4N.js +0 -4416
  464. package/dist/cli-delegate/chunk-QJWAUMJW.js +0 -1072
  465. package/dist/cli-delegate/chunk-YDPILCOL.js +0 -152
  466. package/dist/ui/assets/index-DH1xc62v.js +0 -29
  467. package/dist/ui/assets/index-jSfMW8_t.css +0 -1
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Per rule: is the obligation already carried by a mechanism, and is there a
4
+ * slot that could carry it?
5
+ *
6
+ * Step 1.5 of `road-to-rule-triggers-and-links-that-hold`. It joins three
7
+ * instruments that already exist and had never been read together:
8
+ *
9
+ * · `check_enforcement_coverage --json` — the only place `enforced_by` and
10
+ * `obligation_frequency` are already resolved per rule, including what the
11
+ * declaration resolves TO (a wired validator, a bound hook, nothing).
12
+ * · `report_obligation_carriers` — how many artifacts restate the same
13
+ * obligation, which is a different question from whether one enforces it.
14
+ * · The `# obligation: line N` frontmatter marker — 107 of 121 rules carry
15
+ * one and nothing in the tree reads it, so this is its first reader.
16
+ *
17
+ * **Two columns, and conflating them would be the error worth avoiding.**
18
+ * `carried` is measured: a gate either refuses or it does not.
19
+ * `slot_exists` is NECESSARY, NEVER SUFFICIENT — it says a host event fires at
20
+ * the obligation's own frequency, so a carrier could at least be bound. It
21
+ * does not say the obligation is decidable from what that event sees, which is
22
+ * the actual question and is not answerable by a join. A rule whose body says
23
+ * `instruction-only` has usually already answered it in the other direction,
24
+ * and that answer is reproduced rather than overridden.
25
+ *
26
+ * Report only. Moving an obligation out of prose is a per-rule change with its
27
+ * own review, which this roadmap's scope section says in as many words.
28
+ */
29
+ import { execFileSync } from 'node:child_process';
30
+ import * as fs from 'node:fs';
31
+ import * as path from 'node:path';
32
+ import { fileURLToPath, pathToFileURL } from 'node:url';
33
+
34
+ // ledger-exempt: a REPORTER, not a gate. Its only non-zero exit says an input
35
+ // instrument could not be run, which is a statement about the walk.
36
+
37
+ const _HERE = fileURLToPath(import.meta.url);
38
+
39
+ /** Frequencies a host event is known to fire at — the `slot_exists` test. */
40
+ const EVENT_BOUND_FREQUENCIES: ReadonlySet<string> = new Set([
41
+ 'per-edit',
42
+ 'per-file-write',
43
+ 'per-commit',
44
+ 'per-turn',
45
+ 'per-session',
46
+ 'per-event',
47
+ 'per-task',
48
+ ]);
49
+
50
+ /** Resolutions where something can actually refuse. */
51
+ const REFUSING: ReadonlySet<string> = new Set(['validator', 'validator-local', 'test', 'hook']);
52
+
53
+ export interface MechanismRow {
54
+ rule: string;
55
+ tier: string;
56
+ marker_line: number | null;
57
+ frequency: string;
58
+ declared: number;
59
+ effective: string;
60
+ /** `gate` · `observer` · `declared-gap` · `undeclared`. */
61
+ carried: string;
62
+ /** A host event is known to fire at this frequency. Necessary, not sufficient. */
63
+ slot_exists: boolean;
64
+ /** Artifacts restating this rule's obligations, per the carrier census. */
65
+ restatements: number;
66
+ }
67
+
68
+ /** `# obligation: line N` inside the frontmatter block. */
69
+ export function markerLine(content: string): number | null {
70
+ if (!content.startsWith('---')) return null;
71
+ const end = content.indexOf('\n---', 3);
72
+ const block = end === -1 ? content : content.slice(0, end);
73
+ const m = /^#\s*obligation:\s*line\s+(\d+)\s*$/m.exec(block);
74
+ return m ? Number.parseInt(m[1] as string, 10) : null;
75
+ }
76
+
77
+ function run(root: string, script: string, args: readonly string[]): string {
78
+ return execFileSync(path.join(root, 'scripts-run'), [script, ...args], {
79
+ cwd: root,
80
+ encoding: 'utf8',
81
+ maxBuffer: 64 * 1024 * 1024,
82
+ stdio: ['ignore', 'pipe', 'ignore'],
83
+ });
84
+ }
85
+
86
+ interface CoverageRule {
87
+ id: string;
88
+ tier?: string;
89
+ declared?: string[];
90
+ effective?: string;
91
+ obligation_frequency?: string | null;
92
+ }
93
+
94
+ export function rows(root: string): MechanismRow[] {
95
+ const coverage = JSON.parse(run(root, 'src/scripts/check_enforcement_coverage', ['--json'])) as {
96
+ rules: CoverageRule[];
97
+ };
98
+
99
+ run(root, 'src/scripts/report_obligation_carriers', ['--top', '1']);
100
+ const carriersPath = path.join(root, 'agents', 'runtime', 'reports', 'obligation-carriers.json');
101
+ const restatements = new Map<string, number>();
102
+ if (!fs.existsSync(carriersPath)) {
103
+ // Not a degradation to absorb: `agents/runtime/` is gitignored, so a
104
+ // fresh checkout reaches this, and a silent fallback would publish a
105
+ // uniformly-zero Restatements column with nothing saying it is empty.
106
+ // Every other input failure in this script exits 1; so does this one.
107
+ throw new Error(
108
+ `report_obligation_carriers wrote no census at ${carriersPath} — the ` +
109
+ 'Restatements column would read 0 for every rule without saying so',
110
+ );
111
+ }
112
+ {
113
+ const census = JSON.parse(fs.readFileSync(carriersPath, 'utf8')) as {
114
+ rows: { carriers: { path: string; cls: string }[] }[];
115
+ };
116
+ for (const r of census.rows) {
117
+ // A row is one obligation; it counts for every RULE that carries it.
118
+ for (const c of r.carriers) {
119
+ if (c.cls !== 'rule') continue;
120
+ const id = path.basename(c.path, '.md');
121
+ restatements.set(id, (restatements.get(id) ?? 0) + r.carriers.length - 1);
122
+ }
123
+ }
124
+ }
125
+
126
+ const out: MechanismRow[] = [];
127
+ for (const r of coverage.rules) {
128
+ const file = path.join(root, 'src', 'rules', `${r.id}.md`);
129
+ const content = fs.existsSync(file) ? fs.readFileSync(file, 'utf8') : '';
130
+ const declared = r.declared ?? [];
131
+ const effective = r.effective ?? 'none';
132
+ const frequency = r.obligation_frequency ?? '—';
133
+
134
+ let carried: string;
135
+ if (REFUSING.has(effective)) carried = 'gate';
136
+ else if (effective === 'observer') carried = 'observer';
137
+ else if (declared.length > 0) carried = 'declared-gap';
138
+ else carried = 'undeclared';
139
+
140
+ out.push({
141
+ rule: r.id,
142
+ tier: r.tier ?? '—',
143
+ marker_line: markerLine(content),
144
+ frequency,
145
+ declared: declared.length,
146
+ effective,
147
+ carried,
148
+ slot_exists: EVENT_BOUND_FREQUENCIES.has(frequency),
149
+ restatements: restatements.get(r.id) ?? 0,
150
+ });
151
+ }
152
+ out.sort((a, b) => a.rule.localeCompare(b.rule));
153
+ return out;
154
+ }
155
+
156
+ export function renderTable(data: readonly MechanismRow[]): string[] {
157
+ const L: string[] = [];
158
+ L.push('| Rule | Tier | Marker | Frequency | `enforced_by` | Resolves to | Carried | Slot exists | Restatements |');
159
+ L.push('|---|---|---:|---|---:|---|---|---|---:|');
160
+ for (const r of data) {
161
+ L.push(
162
+ `| \`${r.rule}\` | ${r.tier} | ${r.marker_line === null ? '—' : String(r.marker_line)} | ` +
163
+ `${r.frequency} | ${String(r.declared)} | \`${r.effective}\` | ${r.carried} | ` +
164
+ `${r.slot_exists ? 'yes' : 'no'} | ${String(r.restatements)} |`,
165
+ );
166
+ }
167
+ return L;
168
+ }
169
+
170
+ const USAGE = 'usage: report_obligation_mechanism [--root DIR] [--json | --table]\n';
171
+
172
+ export function main(): number {
173
+ const argv = process.argv.slice(2);
174
+ if (argv.includes('--help') || argv.includes('-h')) {
175
+ process.stdout.write(USAGE);
176
+ return 0;
177
+ }
178
+ for (const a of argv) {
179
+ if (a.startsWith('-') && !['--root', '--json', '--table'].includes(a)) {
180
+ process.stderr.write(`unknown argument: ${a}\n${USAGE}`);
181
+ return 2;
182
+ }
183
+ }
184
+ const i = argv.indexOf('--root');
185
+ const root = i >= 0 && i + 1 < argv.length ? (argv[i + 1] as string) : process.cwd();
186
+
187
+ let data: MechanismRow[];
188
+ try {
189
+ data = rows(root);
190
+ } catch (e) {
191
+ process.stderr.write(`could not read an input instrument: ${String(e)}\n`);
192
+ return 1;
193
+ }
194
+
195
+ if (argv.includes('--json')) {
196
+ process.stdout.write(`${JSON.stringify(data, null, 2)}\n`);
197
+ return 0;
198
+ }
199
+ if (argv.includes('--table')) {
200
+ process.stdout.write(`${renderTable(data).join('\n')}\n`);
201
+ return 0;
202
+ }
203
+
204
+ const by = (k: string): number => data.filter((r) => r.carried === k).length;
205
+ const slotNoGate = data.filter((r) => r.carried !== 'gate' && r.slot_exists).length;
206
+ process.stdout.write(
207
+ `${String(data.length)} rule(s)\n` +
208
+ ` carried by a gate that can refuse: ${String(by('gate'))}\n` +
209
+ ` carried by an observer (fires, never refuses): ${String(by('observer'))}\n` +
210
+ ` declared gap (the rule says instruction-only / none): ${String(by('declared-gap'))}\n` +
211
+ ` no enforcement declaration at all: ${String(by('undeclared'))}\n` +
212
+ ` not gated, but a host event fires at the obligation's frequency: ${String(slotNoGate)}\n` +
213
+ ` carry no \`# obligation: line N\` marker: ${String(data.filter((r) => r.marker_line === null).length)}\n`,
214
+ );
215
+ return 0;
216
+ }
217
+
218
+ function _isCliEntry(): boolean {
219
+ if (process.argv[1] === undefined) return false;
220
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
221
+ try {
222
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
223
+ } catch {
224
+ return false;
225
+ }
226
+ }
227
+
228
+ if (_isCliEntry()) {
229
+ process.exit(main());
230
+ }
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * report_obligation_writer_split — which kind of tree wrote the obligation rows.
4
+ *
5
+ * WHAT QUESTION THIS ANSWERS, AND WHY IT NEEDED A TOOL.
6
+ * `obligation-settle-shadow-bar` is pre-registered against the shadow rows under
7
+ * `agents/runtime/state/obligations/`, and its own clause (7) says that corpus is
8
+ * one machine's runtime state. Until the rows carried a writer, that sentence was
9
+ * the ONLY place the fact lived: a reader holding the ledgers could count rows and
10
+ * could not separate them, so a reading that cleared the floor would have been
11
+ * quotable as evidence about a population nobody had measured. This prints the
12
+ * separation, from the rows themselves.
13
+ *
14
+ * IT REACHES NO VERDICT, AND THAT IS THE DESIGN. A split is an input to the corpus
15
+ * decision held in `road-to-an-obligation-row-that-names-its-writer`, not the
16
+ * decision — the three options there (accept the one-machine corpus and amend the
17
+ * bar, widen it deliberately, or file the window `resolved-null`) are owner-
18
+ * reserved, and all three name arming as owner-reserved too. So this exits 0 on
19
+ * every path, prints counts, and says nothing about whether anything may be armed.
20
+ * A reporter that graded the corpus would be handing the arming discussion a
21
+ * verdict wearing a number's clothes.
22
+ *
23
+ * `absent` IS REPORTED APART FROM `unknown`, and the distinction is load-bearing.
24
+ * `unknown` is a row whose writer WAS resolved and came back unresolvable; `absent`
25
+ * is a row written before the field existed. Folding them together would let the
26
+ * whole pre-field corpus read as "we looked and could not tell", which is a
27
+ * stronger claim than "we had not started looking". The ledger's own `parseRows`
28
+ * maps both to `unknown` — correct for a consumer that only needs a role — so this
29
+ * reads the JSON directly rather than through it, and uses `isWriterRole` for the
30
+ * vocabulary so the two cannot drift.
31
+ *
32
+ * PRIVACY, at the precision the code holds. Output is counts, plus the SCAN ROOT,
33
+ * which the caller supplied and which is the one thing a reader needs in order to
34
+ * know what was measured. Nothing else crosses: no session id, no ledger filename,
35
+ * no rule id, no timestamp. The scan reads those and keeps none of them.
36
+ *
37
+ * WRITES NOTHING. It opens files for reading and creates no directory, not even
38
+ * the ledger directory it looks for. A missing directory is a reported state, not
39
+ * a thing to fix.
40
+ *
41
+ * Exit: 0 always, except a usage error (1). Advisory — it gates nothing.
42
+ */
43
+
44
+ import * as fs from 'node:fs';
45
+ import * as path from 'node:path';
46
+ import process from 'node:process';
47
+ import { fileURLToPath } from 'node:url';
48
+
49
+ import { OBLIGATION_STATE_DIR, WRITER_ROLES, isWriterRole } from './_lib/obligations.js';
50
+
51
+ /** The reported classes: the closed vocabulary, plus the pre-field case. */
52
+ export const REPORTED_CLASSES = [...WRITER_ROLES, 'absent'] as const;
53
+ export type ReportedClass = (typeof REPORTED_CLASSES)[number];
54
+
55
+ /** The three row arrays a ledger carries, named as the file names them. */
56
+ export const ROW_ARRAYS = ['delivered', 'discharged', 'shadow'] as const;
57
+ export type RowArray = (typeof ROW_ARRAYS)[number];
58
+
59
+ export type Tally = Record<ReportedClass, number>;
60
+
61
+ export interface WriterSplit {
62
+ /** The directory scanned, echoed so a reader knows what was measured. */
63
+ readonly store: string;
64
+ /** `false` when the ledger directory does not exist at all. */
65
+ readonly storeExists: boolean;
66
+ /** Ledger files opened and parsed. */
67
+ readonly ledgers: number;
68
+ /** Files present but unreadable or unparseable — reported, never silently dropped. */
69
+ readonly unreadable: number;
70
+ /** Per row array, the split by writer class. */
71
+ readonly byArray: Record<RowArray, Tally>;
72
+ /** Every array folded together. */
73
+ readonly total: Tally;
74
+ }
75
+
76
+ function emptyTally(): Tally {
77
+ return { package: 0, consumer: 0, unknown: 0, absent: 0 };
78
+ }
79
+
80
+ /**
81
+ * Classify one row's writer field.
82
+ *
83
+ * A field that is missing entirely is `absent`. A field that is present but
84
+ * outside the closed vocabulary is `unknown`, matching `parseRows`: a corrupt
85
+ * provenance label degrades, it never deletes the record of a real row.
86
+ */
87
+ export function classifyRow(row: unknown): ReportedClass {
88
+ if (typeof row !== 'object' || row === null) return 'absent';
89
+ if (!('writer' in row)) return 'absent';
90
+ const writer = (row as { writer: unknown }).writer;
91
+ return isWriterRole(writer) ? writer : 'unknown';
92
+ }
93
+
94
+ /** Tally one ledger's arrays into an accumulator. */
95
+ function tallyLedger(doc: unknown, into: Record<RowArray, Tally>): void {
96
+ if (typeof doc !== 'object' || doc === null) return;
97
+ for (const name of ROW_ARRAYS) {
98
+ const rows = (doc as Record<string, unknown>)[name];
99
+ if (!Array.isArray(rows)) continue;
100
+ for (const row of rows) into[name][classifyRow(row)] += 1;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Read every ledger under `root` and split its rows by writer class.
106
+ *
107
+ * Opens files for reading only. A file that will not parse increments
108
+ * `unreadable` rather than being skipped in silence — a corpus with unreadable
109
+ * members is a different corpus from a clean one, and a reader deciding whether
110
+ * a sample floor is met needs to know which they have.
111
+ */
112
+ export function readWriterSplit(root: string): WriterSplit {
113
+ const store = path.join(root, OBLIGATION_STATE_DIR);
114
+ const byArray: Record<RowArray, Tally> = {
115
+ delivered: emptyTally(),
116
+ discharged: emptyTally(),
117
+ shadow: emptyTally(),
118
+ };
119
+
120
+ let entries: string[];
121
+ try {
122
+ entries = fs.readdirSync(store).filter((f) => f.endsWith('.json'));
123
+ } catch {
124
+ return { store, storeExists: false, ledgers: 0, unreadable: 0, byArray, total: emptyTally() };
125
+ }
126
+
127
+ let ledgers = 0;
128
+ let unreadable = 0;
129
+ for (const entry of entries) {
130
+ let doc: unknown;
131
+ try {
132
+ doc = JSON.parse(fs.readFileSync(path.join(store, entry), 'utf-8'));
133
+ } catch {
134
+ unreadable += 1;
135
+ continue;
136
+ }
137
+ ledgers += 1;
138
+ tallyLedger(doc, byArray);
139
+ }
140
+
141
+ const total = emptyTally();
142
+ for (const name of ROW_ARRAYS) {
143
+ for (const cls of REPORTED_CLASSES) total[cls] += byArray[name][cls];
144
+ }
145
+ return { store, storeExists: true, ledgers, unreadable, byArray, total };
146
+ }
147
+
148
+ const sum = (t: Tally): number => REPORTED_CLASSES.reduce((n, c) => n + t[c], 0);
149
+
150
+ /**
151
+ * Render the split as text.
152
+ *
153
+ * The line a reader is most likely to quote is the shadow row, so it is named
154
+ * rather than left to be inferred from a table: the pre-registered bar counts
155
+ * shadow rows and nothing else, and a split over `delivered` answers a question
156
+ * the bar did not ask.
157
+ */
158
+ export function render(split: WriterSplit): string {
159
+ const out: string[] = [];
160
+ out.push(`scanned: ${split.store}`);
161
+ if (!split.storeExists) {
162
+ out.push(' the ledger directory does not exist — nothing was measured.');
163
+ out.push(' This is not a reading of zero. It is the absence of a corpus.');
164
+ return `${out.join('\n')}\n`;
165
+ }
166
+ out.push(` ledgers: ${split.ledgers}${split.unreadable > 0 ? `, unreadable: ${split.unreadable}` : ''}`);
167
+ if (split.ledgers === 0) {
168
+ out.push(' no ledger files — the directory exists and holds nothing.');
169
+ return `${out.join('\n')}\n`;
170
+ }
171
+
172
+ const width = Math.max(...ROW_ARRAYS.map((n) => n.length));
173
+ out.push('');
174
+ out.push(`${'rows'.padEnd(width)} ${REPORTED_CLASSES.map((c) => c.padStart(9)).join('')} total`);
175
+ for (const name of ROW_ARRAYS) {
176
+ const t = split.byArray[name];
177
+ const cells = REPORTED_CLASSES.map((c) => String(t[c]).padStart(9)).join('');
178
+ out.push(`${name.padEnd(width)} ${cells} ${String(sum(t)).padStart(7)}`);
179
+ }
180
+ const cells = REPORTED_CLASSES.map((c) => String(split.total[c]).padStart(9)).join('');
181
+ out.push(`${'all'.padEnd(width)} ${cells} ${String(sum(split.total)).padStart(7)}`);
182
+
183
+ out.push('');
184
+ out.push(
185
+ `shadow rows — the only array the pre-registered bar counts: ${sum(split.byArray.shadow)}`,
186
+ );
187
+ out.push(
188
+ '`absent` is a row written before the writer field existed; `unknown` is a row whose',
189
+ );
190
+ out.push('writer was resolved and came back unresolvable. They are not the same reading.');
191
+ out.push('');
192
+ out.push('This is a split, not a verdict. Whether the corpus is fit to read the bar off,');
193
+ out.push('and what follows for the detector, are owner decisions this tool does not make.');
194
+ return `${out.join('\n')}\n`;
195
+ }
196
+
197
+ /**
198
+ * Read one flag's value, refusing a flag whose value is missing.
199
+ *
200
+ * A flag present as the last argv element must be a usage error and never a
201
+ * silent fall back to the default. The same slip in a sibling reporter measured
202
+ * the DEFAULT corpus while printing what read as a settled number — a confident
203
+ * figure from a tree nobody asked for is worse than no figure at all.
204
+ */
205
+ function argValue(argv: string[], flag: string, fallback: string): string {
206
+ const i = argv.indexOf(flag);
207
+ if (i === -1) return fallback;
208
+ const value = argv[i + 1];
209
+ if (value === undefined || value.startsWith('--')) {
210
+ process.stderr.write(`report_obligation_writer_split: ${flag} needs a value\n`);
211
+ process.exit(1);
212
+ }
213
+ return value;
214
+ }
215
+
216
+ export function main(argv: string[]): number {
217
+ if (argv.includes('--help') || argv.includes('-h')) {
218
+ process.stdout.write(
219
+ 'usage: report_obligation_writer_split [--root <dir>] [--json]\n\n' +
220
+ ' --root <dir> tree whose agents/runtime/state/obligations/ to read (default: cwd)\n' +
221
+ ' --json emit the split as JSON instead of text\n\n' +
222
+ 'Read-only. Writes nothing, gates nothing, exits 0.\n',
223
+ );
224
+ return 0;
225
+ }
226
+ const root = argValue(argv, '--root', process.cwd());
227
+ const split = readWriterSplit(root);
228
+ process.stdout.write(argv.includes('--json') ? `${JSON.stringify(split, null, 2)}\n` : render(split));
229
+ return 0;
230
+ }
231
+
232
+ const _HERE = fileURLToPath(import.meta.url);
233
+
234
+ if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(_HERE)) {
235
+ process.exit(main(process.argv.slice(2)));
236
+ }