@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,699 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * report_obligation_carriers — how many distinct artifacts carry one obligation.
4
+ *
5
+ * WHY THIS EXISTS. Seven independent code-level reviews of this tree, scoring it
6
+ * between 9.2 and 10, named the same bottleneck in different words — mechanism
7
+ * density — and proposed the same north star: one obligation, one authoritative
8
+ * carrier, delete the redundant copy. None of them produced a measurement, so the
9
+ * theme arrived across consecutive rounds as prose only. This reporter turns the
10
+ * impression into a number with named rows a reader can open.
11
+ *
12
+ * WHAT IT IS NOT, AND THE NON-GOALS ARE THE LOAD-BEARING PART. It is a reporter.
13
+ * It carries no threshold, no ceiling and no opinion about whether a count is too
14
+ * high; it is invoked by no CI workflow and registered in no gate ledger. Its only
15
+ * non-zero exit is a DEAD SCOPE — a run that read zero files did not measure
16
+ * anything, and reporting `0 obligations` from an empty walk is the single most
17
+ * comforting wrong answer this script could give. Refusing that is an assertion
18
+ * about the INSTRUMENT, never about the census verdict, and the distinction is why
19
+ * `assertScanned` here does not make this a gate.
20
+ *
21
+ * CARRIER CLASSES READ (six roots, one per class):
22
+ *
23
+ * rule src/rules kernel and tier-2 rules alike; the census
24
+ * does not distinguish them, because an
25
+ * obligation's body is the same body in
26
+ * either tier and the tier is a delivery
27
+ * fact, not an identity one.
28
+ * skill src/skills every `.md`, not only `SKILL.md`: a
29
+ * supporting reference that restates a law
30
+ * is a carrier of it.
31
+ * command src/domains `command.md` and its neighbours.
32
+ * context src/agent-src/contexts the mechanics files rule bodies migrate into.
33
+ * guideline docs/guidelines the other migration target.
34
+ * contract docs/contracts where a migrated body lands when it is a
35
+ * contract rather than a guideline.
36
+ *
37
+ * CLASSES EXCLUDED, EACH NAMED WITH ITS REASON — a class left out is a named
38
+ * exclusion, never a silent one. See {@link EXCLUDED_CLASSES}; the reasons live
39
+ * there rather than here so the reporter's own header can print them.
40
+ *
41
+ * HOW IDENTITY IS DECIDED — STRUCTURALLY, NEVER BY SIMILARITY. A similarity score
42
+ * makes every row unfalsifiable: a reader who disagrees cannot check it, only
43
+ * re-tune a threshold until the disagreement goes away. So two artifacts carry the
44
+ * same obligation when a STRUCTURAL anchor says so, and the three anchors are the
45
+ * ones this tree already maintains:
46
+ *
47
+ * fence-identity the fenced block under an `Iron Law` heading, equal
48
+ * after whitespace collapse and upper-casing. Exact.
49
+ * explicit-cross-reference the stating artifact's own `Body migrated to X` /
50
+ * `Body merged into X` pointer, resolved to a file.
51
+ * named-slug a `canonical: [`X`]` phrase anywhere in a file,
52
+ * naming the artifact that homes the law.
53
+ *
54
+ * A cross-reference token that resolves to no file on disk is recorded as
55
+ * `unknown` and counted as a carrier of unknown location — never dropped, because
56
+ * dropping it is how an unresolvable pointer reads as an absent one.
57
+ *
58
+ * THE MATCHER WAS SEEN UNDER-COUNTING BEFORE IT WAS TRUSTED. `fence-identity`
59
+ * alone finds almost nothing in this tree: duplication here is overwhelmingly a
60
+ * migration stub restating a law in prose beside the artifact that now holds the
61
+ * body, which has no fence to compare. {@link ANCHOR_KINDS} is a parameter for
62
+ * exactly that reason — `census(root, { anchors: ['fence-identity'] })` reproduces
63
+ * the blind definition on demand, and the test suite pins the under-count so the
64
+ * fix cannot silently regress to it.
65
+ *
66
+ * WHAT A COUNT DOES NOT DISTINGUISH, MEASURED THE FIRST TIME IT MATTERED. A
67
+ * `named-slug` carrier is an artifact that names the obligation's home. It may be
68
+ * a genuine second copy of the body, or it may be a bare pointer — the good shape,
69
+ * the one this census exists to encourage — and NO structural anchor separates the
70
+ * two, because the difference is whether the surrounding prose restates the law,
71
+ * which is a judgement and not a structure. The consequence is concrete: the
72
+ * `commit-policy` row's third carrier had its restated body deleted and replaced
73
+ * by a pointer, and the row still reads 3. The number counts artifacts a reader can
74
+ * meet the obligation in, which is the honest thing a structural matcher can count;
75
+ * it is NOT a count of redundant bodies, and reading it as one will overstate.
76
+ * Narrowing it would mean scoring prose, which is the trade this census refuses.
77
+ *
78
+ * Output: stdout, plus `agents/runtime/reports/obligation-carriers.json`, which is
79
+ * under the gitignored `/agents/runtime/` catch-all. Nothing is written into the
80
+ * tracked tree.
81
+ */
82
+ import { createHash } from 'node:crypto';
83
+ import * as fs from 'node:fs';
84
+ import * as path from 'node:path';
85
+ import process from 'node:process';
86
+ import { fileURLToPath, pathToFileURL } from 'node:url';
87
+
88
+ import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
89
+
90
+ // ledger-exempt: a REPORTER, not a gate. It has no verdict for a per-target ledger
91
+ // to account for — its only non-zero exit is a dead scope, which is a statement
92
+ // about the walk rather than about any target it walked.
93
+
94
+ const _HERE = fileURLToPath(import.meta.url);
95
+ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
96
+
97
+ /** One carrier class the census reads, with the root it walks. */
98
+ export interface CarrierClass {
99
+ readonly name: string;
100
+ readonly root: string;
101
+ }
102
+
103
+ /** The six roots. Order is the read order, and it decides which carrier is listed first. */
104
+ export const CARRIER_CLASSES: readonly CarrierClass[] = [
105
+ { name: 'rule', root: path.join('src', 'rules') },
106
+ { name: 'skill', root: path.join('src', 'skills') },
107
+ { name: 'command', root: path.join('src', 'domains') },
108
+ { name: 'context', root: path.join('src', 'agent-src', 'contexts') },
109
+ { name: 'guideline', root: path.join('docs', 'guidelines') },
110
+ { name: 'contract', root: path.join('docs', 'contracts') },
111
+ ];
112
+
113
+ /** A class that could plausibly carry an obligation and is deliberately not read. */
114
+ export interface ExcludedClass {
115
+ readonly name: string;
116
+ readonly reason: string;
117
+ }
118
+
119
+ /**
120
+ * Every exclusion, with the reason a reviewer can contest.
121
+ *
122
+ * Measured 2026-09-29 by grepping the whole tree for an `Iron Law` heading or an
123
+ * inline `**Iron Law` restatement: the counts below are the files each exclusion
124
+ * actually withholds, so the cost of each is visible rather than asserted.
125
+ */
126
+ export const EXCLUDED_CLASSES: readonly ExcludedClass[] = [
127
+ {
128
+ name: 'hook concern injected text',
129
+ reason:
130
+ 'the body is a TypeScript string literal under src/scripts/hooks/, carries no ' +
131
+ 'Iron Law fence, and would need a code parser rather than a markdown one. The ' +
132
+ 'census reads markdown. This is the largest honest gap in its coverage.',
133
+ },
134
+ {
135
+ name: 'generated projections',
136
+ reason:
137
+ 'dist/agent-src/ and the per-tool trees (.claude/, .cursor/, .clinerules/, ' +
138
+ '.windsurfrules, .augment/) are byte-equal copies of src/ — check_condensation ' +
139
+ 'asserts dist == rewrite(src) — so counting them would double every row by ' +
140
+ 'construction and measure the build, not the estate. Withholds ~150 files.',
141
+ },
142
+ {
143
+ name: 'workspace records under agents/',
144
+ reason:
145
+ 'roadmaps, evidence, decisions and overrides record work ABOUT obligations; ' +
146
+ 'they do not deliver one into a turn. Withholds ~12 files. agents/settings/ ' +
147
+ 'policies (~8 files) are the arguable case: they are project-local bindings a ' +
148
+ 'consumer writes, not package source, so they move with the project rather ' +
149
+ 'than with this tree.',
150
+ },
151
+ {
152
+ name: 'decision records under docs/decisions/',
153
+ reason:
154
+ 'an ADR quotes an obligation to record a decision about it; the quote is ' +
155
+ 'evidence, not a second delivery. Withholds 4 files.',
156
+ },
157
+ {
158
+ name: 'templates',
159
+ reason:
160
+ 'src/agent-src/templates/rule.md states `{The single non-negotiable behavior ' +
161
+ 'the rule enforces.}` — a placeholder, not an obligation. Withholds 1 file.',
162
+ },
163
+ {
164
+ name: 'narrative documentation',
165
+ reason:
166
+ 'ONBOARDING.md, docs/architecture.md and docs/hook-payload-capture.md describe ' +
167
+ 'the system for a reader rather than binding an agent. Withholds 3 files.',
168
+ },
169
+ ];
170
+
171
+ /** The anchors that can make two artifacts carriers of one obligation. */
172
+ export const ANCHOR_KINDS = ['fence-identity', 'explicit-cross-reference', 'named-slug'] as const;
173
+ export type AnchorKind = (typeof ANCHOR_KINDS)[number];
174
+
175
+ /** One artifact carrying an obligation, and the anchor that put it there. */
176
+ export interface Carrier {
177
+ /** Repo-relative path, or `unknown:<token>` when a pointer resolved to nothing. */
178
+ readonly path: string;
179
+ readonly cls: string;
180
+ readonly anchor: AnchorKind | 'statement';
181
+ }
182
+
183
+ /** One obligation and every artifact that carries it. */
184
+ export interface ObligationRow {
185
+ /** Readable name — the stem of the stating artifact, disambiguated when repeated. */
186
+ readonly slug: string;
187
+ /** `fence:<digest>` or `pointer:<path>#<n>`. Stable across runs, not across edits. */
188
+ readonly key: string;
189
+ readonly form: 'fence' | 'pointer';
190
+ /** First line of the binding text, for a reader scanning the table. */
191
+ readonly statement: string;
192
+ readonly carriers: readonly Carrier[];
193
+ readonly count: number;
194
+ /** True when at least one carrier is an unresolved pointer target. */
195
+ readonly unresolved: boolean;
196
+ }
197
+
198
+ export interface CensusOptions {
199
+ /** Which anchors may add a carrier. Defaults to all three. */
200
+ readonly anchors?: readonly AnchorKind[];
201
+ }
202
+
203
+ export interface CensusResult {
204
+ readonly rows: readonly ObligationRow[];
205
+ readonly scannedFiles: number;
206
+ readonly roots: readonly string[];
207
+ }
208
+
209
+ /** A statement of an obligation found in one file. */
210
+ interface Statement {
211
+ readonly file: string;
212
+ readonly cls: string;
213
+ readonly form: 'fence' | 'pointer';
214
+ /** Normalised binding text — whitespace collapsed, upper-cased. */
215
+ readonly norm: string;
216
+ /** First line of the raw text, for display. */
217
+ readonly display: string;
218
+ /** Index of this statement within its file, so a pointer key is unique. */
219
+ readonly ordinal: number;
220
+ }
221
+
222
+ /** One scanned file's directional cross-references, read once. */
223
+ interface FileRefs {
224
+ readonly file: string;
225
+ readonly cls: string;
226
+ /** Tokens this file points AT — `Body migrated to X`. */
227
+ readonly migratedTo: readonly string[];
228
+ /** Tokens this file defers TO — `canonical: [`X`]`. */
229
+ readonly canonicalOf: readonly string[];
230
+ }
231
+
232
+ const IRON_LAW_HEADING = /^(#{1,6})\s+.*\bIron Law/i;
233
+ const IRON_LAW_INLINE = /^\*\*Iron Law/;
234
+ const FENCE = /^\s*```/;
235
+
236
+ /**
237
+ * What a cross-reference token may look like: a lower-case slug, optionally
238
+ * prefixed (`skill:`, `guideline:`) or pathed (`docs/contracts/x`). No spaces, no
239
+ * angle brackets, no upper-case initial — see {@link crossRefTokens} for the live
240
+ * false positive that made this necessary.
241
+ */
242
+ export const SLUG_SHAPE = /^[a-z0-9][a-z0-9._:/-]*$/;
243
+
244
+ /**
245
+ * Collapse every whitespace run, including newlines, and upper-case.
246
+ *
247
+ * Line wrapping is the commonest way one law is restated in another file: rules
248
+ * wrap near 80 columns and a copy in a skill wraps somewhere else. A matcher that
249
+ * preserves newlines would call those two texts different, which is a formatting
250
+ * verdict wearing an identity verdict's clothes.
251
+ */
252
+ export function normaliseStatement(text: string): string {
253
+ return text.replace(/\s+/g, ' ').trim().toUpperCase();
254
+ }
255
+
256
+ /** Short, stable digest of a normalised statement. */
257
+ export function statementKey(norm: string): string {
258
+ return createHash('sha1').update(norm, 'utf-8').digest('hex').slice(0, 12);
259
+ }
260
+
261
+ /**
262
+ * Slug-shaped cross-reference tokens matched by one directional pattern.
263
+ *
264
+ * Only the two phrasings this tree actually maintains are read — a migration
265
+ * pointer and a canonicality claim. A bare link is NOT a cross-reference for this
266
+ * purpose: rules link each other constantly for context, and treating every link
267
+ * as a carrier claim would turn the census into a link graph and every count into
268
+ * noise.
269
+ *
270
+ * The token must also be SLUG-SHAPED, and that clause is a fix rather than a
271
+ * precaution. `canonical:?` alone matched `canonical \`Phase <id>\` form parsed by
272
+ * the dashboard` — a claim about a heading format, not about a carrier — and the
273
+ * census duly reported that obligation as carried by three artifacts, two of them
274
+ * `unknown`. A token carrying whitespace, angle brackets or an upper-case initial
275
+ * is not a slug this tree ever uses, so rejecting it at extraction keeps `unknown`
276
+ * meaning "a real pointer that resolves to nothing" rather than "the regex caught
277
+ * prose".
278
+ */
279
+ export function crossRefTokens(text: string, pattern: RegExp): string[] {
280
+ const out: string[] = [];
281
+ for (const m of text.matchAll(new RegExp(pattern.source, 'g'))) {
282
+ const raw = m[1];
283
+ if (raw === undefined) continue;
284
+ // Strip a trailing section marker: `skill:authz-review` then a section sign.
285
+ const token = (raw.split('§')[0] ?? '').trim();
286
+ if (!SLUG_SHAPE.test(token)) continue;
287
+ if (!out.includes(token)) out.push(token);
288
+ }
289
+ return out;
290
+ }
291
+
292
+ /**
293
+ * `Body migrated to X` / `Body merged into X` — OUTBOUND. The file states the law
294
+ * and names the artifact that now holds the body, so X is a second carrier of the
295
+ * obligations this file homes.
296
+ */
297
+ export const MIGRATED_TO = /Body (?:migrated|merged) (?:to|into)\s+(?:\[)?`([^`]+)`/;
298
+
299
+ /**
300
+ * `canonical: [`X`]` — INBOUND. The file restates a law and names X as its home,
301
+ * so the FILE is the second carrier.
302
+ *
303
+ * Read at file level rather than inside the Iron-Law region, and that is a
304
+ * correction rather than a convenience: `scope-control` restates the Hard Floor
305
+ * under its own topical heading and names `non-destructive-by-default` as
306
+ * canonical, which a region-scoped read cannot see — the census reported that
307
+ * obligation as carried by one artifact while four rules restate it. A named-slug
308
+ * reference names the ARTIFACT, not one law inside it, so it attaches to every
309
+ * obligation that artifact homes; a reader who wants to narrow it opens the named
310
+ * file, which is the property that keeps the row checkable.
311
+ */
312
+ export const CANONICAL_OF = /[Cc]anonical:?\s+(?:\[)?`([^`]+)`/;
313
+
314
+ /**
315
+ * Resolve a cross-reference token to a repo-relative markdown path, or null.
316
+ *
317
+ * The four prefixes are the ones the tokens actually use; a bare token is a rule
318
+ * slug, which is how every pointer stub names its own family. Returning null is a
319
+ * real answer and the caller records it as `unknown` rather than discarding it.
320
+ */
321
+ export function resolveToken(root: string, token: string): string | null {
322
+ const candidates: string[] = [];
323
+ if (token.startsWith('skill:')) {
324
+ candidates.push(path.join('src', 'skills', token.slice(6), 'SKILL.md'));
325
+ } else if (token.startsWith('guideline:')) {
326
+ candidates.push(path.join('docs', 'guidelines', `${token.slice(10)}.md`));
327
+ } else if (token.startsWith('contexts/')) {
328
+ candidates.push(path.join('src', 'agent-src', token.replace(/\.md$/, '')) + '.md');
329
+ } else if (token.startsWith('docs/')) {
330
+ candidates.push(token.endsWith('.md') ? token : `${token}.md`);
331
+ } else if (token.includes('/')) {
332
+ candidates.push(token.endsWith('.md') ? token : `${token}.md`);
333
+ } else {
334
+ candidates.push(path.join('src', 'rules', `${token}.md`));
335
+ candidates.push(path.join('src', 'skills', token, 'SKILL.md'));
336
+ }
337
+ for (const rel of candidates) {
338
+ if (fs.existsSync(path.join(root, rel))) return rel;
339
+ }
340
+ return null;
341
+ }
342
+
343
+ /** Every `.md` under one root, repo-relative, sorted for a reproducible read order. */
344
+ function walkMarkdown(root: string, rel: string): string[] {
345
+ const abs = path.join(root, rel);
346
+ if (!fs.existsSync(abs)) return [];
347
+ const out: string[] = [];
348
+ const stack = [abs];
349
+ while (stack.length > 0) {
350
+ const dir = stack.pop();
351
+ if (dir === undefined) break;
352
+ let entries: fs.Dirent[];
353
+ try {
354
+ entries = fs.readdirSync(dir, { withFileTypes: true });
355
+ } catch {
356
+ continue;
357
+ }
358
+ for (const e of entries) {
359
+ const full = path.join(dir, e.name);
360
+ if (e.isDirectory()) stack.push(full);
361
+ else if (e.isFile() && e.name.endsWith('.md')) out.push(path.relative(root, full));
362
+ }
363
+ }
364
+ return out.sort();
365
+ }
366
+
367
+ /**
368
+ * Every obligation statement in one file.
369
+ *
370
+ * Two forms, and the split is structural. An `Iron Law` heading whose first
371
+ * content is a fence states the law IN FULL — that text is the identity. An
372
+ * inline `**Iron Law` one-liner is the migration-stub shape: it restates the law
373
+ * in prose beside a pointer at the artifact now holding the body, so its identity
374
+ * is its own file rather than its text, because the prose is deliberately a
375
+ * paraphrase and paraphrases do not compare.
376
+ */
377
+ export function extractStatements(cls: string, file: string, text: string): Statement[] {
378
+ const lines = text.split('\n');
379
+ const out: Statement[] = [];
380
+ let ordinal = 0;
381
+ for (let i = 0; i < lines.length; i += 1) {
382
+ const line = lines[i] ?? '';
383
+ const heading = IRON_LAW_HEADING.exec(line);
384
+ if (heading !== null) {
385
+ let j = i + 1;
386
+ while (j < lines.length && (lines[j] ?? '').trim() === '') j += 1;
387
+ if (j >= lines.length || !FENCE.test(lines[j] ?? '')) continue;
388
+ const body: string[] = [];
389
+ let k = j + 1;
390
+ while (k < lines.length && !FENCE.test(lines[k] ?? '')) {
391
+ body.push(lines[k] ?? '');
392
+ k += 1;
393
+ }
394
+ const raw = body.join('\n').trim();
395
+ if (raw === '') {
396
+ i = k;
397
+ continue;
398
+ }
399
+ out.push({
400
+ file,
401
+ cls,
402
+ form: 'fence',
403
+ norm: normaliseStatement(raw),
404
+ display: firstLine(raw),
405
+ ordinal: ordinal++,
406
+ });
407
+ i = k;
408
+ continue;
409
+ }
410
+ if (IRON_LAW_INLINE.test(line)) {
411
+ out.push({
412
+ file,
413
+ cls,
414
+ form: 'pointer',
415
+ norm: normaliseStatement(line),
416
+ display: firstLine(line.replace(/^\*\*Iron Law[^*]*\*\*\s*/, '')),
417
+ ordinal: ordinal++,
418
+ });
419
+ }
420
+ }
421
+ return out;
422
+ }
423
+
424
+ function firstLine(raw: string): string {
425
+ const first = raw.split('\n')[0] ?? '';
426
+ return first.trim().slice(0, 96);
427
+ }
428
+
429
+ function classOf(file: string): string {
430
+ for (const c of CARRIER_CLASSES) {
431
+ if (file === c.root || file.startsWith(`${c.root}${path.sep}`)) return c.name;
432
+ }
433
+ return 'unknown';
434
+ }
435
+
436
+ /**
437
+ * Walk the six roots and group statements into obligations.
438
+ *
439
+ * @throws {DeadScopeError} when the walk read zero files.
440
+ */
441
+ export function census(root: string, opts: CensusOptions = {}): CensusResult {
442
+ const anchors = new Set<AnchorKind>(opts.anchors ?? ANCHOR_KINDS);
443
+ const statements: Statement[] = [];
444
+ const refs: FileRefs[] = [];
445
+ const roots: string[] = [];
446
+ let scannedFiles = 0;
447
+
448
+ for (const cls of CARRIER_CLASSES) {
449
+ const files = walkMarkdown(root, cls.root);
450
+ if (files.length > 0) roots.push(cls.root);
451
+ for (const file of files) {
452
+ scannedFiles += 1;
453
+ let text: string;
454
+ try {
455
+ text = fs.readFileSync(path.join(root, file), 'utf-8');
456
+ } catch {
457
+ continue;
458
+ }
459
+ statements.push(...extractStatements(cls.name, file, text));
460
+ refs.push({
461
+ file,
462
+ cls: cls.name,
463
+ migratedTo: crossRefTokens(text, MIGRATED_TO),
464
+ canonicalOf: crossRefTokens(text, CANONICAL_OF),
465
+ });
466
+ }
467
+ }
468
+
469
+ assertScanned({
470
+ gate: 'report_obligation_carriers',
471
+ scanned: scannedFiles,
472
+ units: 'markdown file(s)',
473
+ roots: CARRIER_CLASSES.map((c) => c.root),
474
+ });
475
+
476
+ // Fence statements group by text; pointer statements are their own obligation.
477
+ const groups = new Map<string, Statement[]>();
478
+ for (const s of statements) {
479
+ const key =
480
+ s.form === 'fence' && anchors.has('fence-identity')
481
+ ? `fence:${statementKey(s.norm)}`
482
+ : s.form === 'fence'
483
+ ? `fence:${statementKey(s.norm)}@${s.file}#${s.ordinal}`
484
+ : `pointer:${s.file}#${s.ordinal}`;
485
+ const bucket = groups.get(key);
486
+ if (bucket === undefined) groups.set(key, [s]);
487
+ else bucket.push(s);
488
+ }
489
+
490
+ // Inbound index: which files name file H as the canonical home of a law.
491
+ const deferrers = new Map<string, FileRefs[]>();
492
+ if (anchors.has('named-slug')) {
493
+ for (const r of refs) {
494
+ for (const token of r.canonicalOf) {
495
+ const home = resolveToken(root, token);
496
+ if (home === null || home === r.file) continue;
497
+ const bucket = deferrers.get(home);
498
+ if (bucket === undefined) deferrers.set(home, [r]);
499
+ else bucket.push(r);
500
+ }
501
+ }
502
+ }
503
+ const refsByFile = new Map(refs.map((r) => [r.file, r]));
504
+
505
+ const rows: ObligationRow[] = [];
506
+ for (const [key, members] of groups) {
507
+ // A pointer statement only becomes an obligation at all once a
508
+ // cross-reference anchor is enabled. Without one it is a lone paraphrase
509
+ // with no second carrier to compare against, and the blind definition this
510
+ // reproduces would never have seen it.
511
+ const crossRefEnabled =
512
+ anchors.has('explicit-cross-reference') || anchors.has('named-slug');
513
+ const first = members[0];
514
+ if (first === undefined) continue;
515
+ if (first.form === 'pointer' && !crossRefEnabled) continue;
516
+
517
+ const carriers: Carrier[] = [];
518
+ const seen = new Set<string>();
519
+ const add = (p: string, cls: string, anchor: Carrier['anchor']): void => {
520
+ if (seen.has(p)) return;
521
+ seen.add(p);
522
+ carriers.push({ path: p, cls, anchor });
523
+ };
524
+ for (const [idx, m] of members.entries()) {
525
+ add(m.file, m.cls, idx === 0 ? 'statement' : 'fence-identity');
526
+ }
527
+ let unresolved = false;
528
+ for (const m of members) {
529
+ if (anchors.has('explicit-cross-reference')) {
530
+ for (const token of refsByFile.get(m.file)?.migratedTo ?? []) {
531
+ const target = resolveToken(root, token);
532
+ if (target === null) {
533
+ unresolved = true;
534
+ add(`unknown:${token}`, 'unknown', 'explicit-cross-reference');
535
+ } else if (target !== m.file) {
536
+ add(target, classOf(target), 'explicit-cross-reference');
537
+ }
538
+ }
539
+ }
540
+ for (const d of deferrers.get(m.file) ?? []) add(d.file, d.cls, 'named-slug');
541
+ }
542
+ rows.push({
543
+ slug: path.basename(first.file, '.md') === 'SKILL.md'
544
+ ? path.basename(path.dirname(first.file))
545
+ : path.basename(first.file, '.md'),
546
+ key,
547
+ form: first.form,
548
+ statement: first.display,
549
+ carriers,
550
+ count: carriers.length,
551
+ unresolved,
552
+ });
553
+ }
554
+
555
+ rows.sort((a, b) => b.count - a.count || a.slug.localeCompare(b.slug) || a.key.localeCompare(b.key));
556
+ return { rows, scannedFiles, roots };
557
+ }
558
+
559
+ /** The reporter's header — every class read, every class excluded, and why. */
560
+ export function headerLines(): string[] {
561
+ const out: string[] = [];
562
+ out.push('obligation-carrier census — read-only, no threshold, reds no build');
563
+ out.push('');
564
+ out.push('classes READ:');
565
+ for (const c of CARRIER_CLASSES) out.push(` ${c.name.padEnd(10)} ${c.root}`);
566
+ out.push('');
567
+ out.push('classes EXCLUDED (named, never silent):');
568
+ for (const e of EXCLUDED_CLASSES) {
569
+ out.push(` ${e.name}`);
570
+ for (const line of wrap(e.reason, 72)) out.push(` ${line}`);
571
+ }
572
+ out.push('');
573
+ out.push('identity anchors (structural — no similarity score decides a match):');
574
+ out.push(' fence-identity same fenced Iron Law text after whitespace collapse');
575
+ out.push(' explicit-cross-reference `Body migrated to X` / `Body merged into X`, resolved');
576
+ out.push(' named-slug `canonical: [`X`]` naming the artifact that homes it');
577
+ out.push(' unknown a cross-reference token that resolves to no file');
578
+ return out;
579
+ }
580
+
581
+ function wrap(text: string, width: number): string[] {
582
+ const words = text.split(' ');
583
+ const out: string[] = [];
584
+ let line = '';
585
+ for (const w of words) {
586
+ if (line === '') line = w;
587
+ else if (line.length + 1 + w.length <= width) line += ` ${w}`;
588
+ else {
589
+ out.push(line);
590
+ line = w;
591
+ }
592
+ }
593
+ if (line !== '') out.push(line);
594
+ return out;
595
+ }
596
+
597
+ const OUT_REL = path.join('agents', 'runtime', 'reports', 'obligation-carriers.json');
598
+
599
+ export function main(argv?: readonly string[]): number {
600
+ const args = argv ?? process.argv.slice(2);
601
+ let root = REPO_ROOT;
602
+ let top = 10;
603
+ let write = true;
604
+ let fenceOnly = false;
605
+ for (let i = 0; i < args.length; i += 1) {
606
+ const a = args[i];
607
+ if (a === '--root') {
608
+ const v = args[i + 1];
609
+ if (v === undefined || v.startsWith('-')) {
610
+ process.stderr.write('report_obligation_carriers: --root needs a directory\n');
611
+ return 1;
612
+ }
613
+ root = path.resolve(v);
614
+ i += 1;
615
+ } else if (a === '--top') {
616
+ const v = args[i + 1];
617
+ const n = Number(v);
618
+ if (v === undefined || !Number.isInteger(n) || n < 1) {
619
+ process.stderr.write('report_obligation_carriers: --top needs a positive integer\n');
620
+ return 1;
621
+ }
622
+ top = n;
623
+ i += 1;
624
+ } else if (a === '--no-write') {
625
+ write = false;
626
+ } else if (a === '--fence-only') {
627
+ fenceOnly = true;
628
+ } else if (a === '--help' || a === '-h') {
629
+ process.stdout.write(
630
+ 'usage: report_obligation_carriers [--root DIR] [--top N] [--no-write] [--fence-only]\n' +
631
+ '\n' +
632
+ ' --fence-only reproduce the blind definition (fence identity alone), which\n' +
633
+ ' under-counts this tree by construction. Kept so the\n' +
634
+ ' under-count is reproducible rather than merely recorded.\n',
635
+ );
636
+ return 0;
637
+ } else if (a !== undefined) {
638
+ process.stderr.write(`report_obligation_carriers: unexpected argument ${a}\n`);
639
+ return 1;
640
+ }
641
+ }
642
+
643
+ let result: CensusResult;
644
+ try {
645
+ result = census(root, fenceOnly ? { anchors: ['fence-identity'] } : {});
646
+ } catch (err) {
647
+ if (err instanceof DeadScopeError) {
648
+ process.stderr.write(`${err.message}\n`);
649
+ return 1;
650
+ }
651
+ throw err;
652
+ }
653
+
654
+ for (const line of headerLines()) process.stdout.write(`${line}\n`);
655
+ const multi = result.rows.filter((r) => r.count > 1);
656
+ process.stdout.write('\n');
657
+ process.stdout.write(
658
+ `scanned ${result.scannedFiles} markdown file(s) across ${result.roots.length} root(s)\n`,
659
+ );
660
+ process.stdout.write(
661
+ `${result.rows.length} obligation(s); ${multi.length} carried by more than one artifact\n\n`,
662
+ );
663
+ process.stdout.write(`top ${Math.min(top, result.rows.length)} by carrier count:\n`);
664
+ for (const row of result.rows.slice(0, top)) {
665
+ process.stdout.write(`\n ${row.count} ${row.slug} [${row.form}]${row.unresolved ? ' (unresolved pointer)' : ''}\n`);
666
+ process.stdout.write(` ${row.statement}\n`);
667
+ for (const c of row.carriers) {
668
+ process.stdout.write(` - ${c.path} (${c.cls}, ${c.anchor})\n`);
669
+ }
670
+ }
671
+
672
+ if (write) {
673
+ const target = path.join(root, OUT_REL);
674
+ try {
675
+ fs.mkdirSync(path.dirname(target), { recursive: true });
676
+ fs.writeFileSync(target, `${JSON.stringify({ rows: result.rows, scannedFiles: result.scannedFiles }, null, 2)}\n`, 'utf-8');
677
+ process.stdout.write(`\nwrote ${OUT_REL}\n`);
678
+ } catch (err) {
679
+ // A report that could not be written is a missing reading, never a
680
+ // failed run: the table above is the product and it already printed.
681
+ process.stdout.write(`\ncould not write ${OUT_REL}: ${String(err)}\n`);
682
+ }
683
+ }
684
+ return 0;
685
+ }
686
+
687
+ function _isCliEntry(): boolean {
688
+ if (process.argv[1] === undefined) return false;
689
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
690
+ try {
691
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
692
+ } catch {
693
+ return false;
694
+ }
695
+ }
696
+
697
+ if (_isCliEntry()) {
698
+ process.exit(main());
699
+ }