@event4u/agent-config 15.0.0 → 16.1.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 (283) 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 +301 -347
  5. package/CONTRIBUTING.md +9 -0
  6. package/README.md +2 -2
  7. package/dist/agent-src/commands/analyze/inbox.md +26 -0
  8. package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
  9. package/dist/agent-src/commands/challenge-me/closure.md +178 -0
  10. package/dist/agent-src/commands/challenge-me.md +9 -2
  11. package/dist/agent-src/commands/council/default.md +25 -5
  12. package/dist/agent-src/commands/feature/plan.md +28 -1
  13. package/dist/agent-src/commands/feature/roadmap.md +28 -1
  14. package/dist/agent-src/commands/implement-ticket.md +27 -0
  15. package/dist/agent-src/commands/jira-ticket.md +27 -0
  16. package/dist/agent-src/commands/pr/create.md +29 -0
  17. package/dist/agent-src/commands/pr/merge.md +60 -9
  18. package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
  19. package/dist/agent-src/commands/roadmap/create.md +77 -29
  20. package/dist/agent-src/commands/roadmap/materialize.md +27 -0
  21. package/dist/agent-src/commands/roadmap/process-full.md +123 -18
  22. package/dist/agent-src/commands/team.md +22 -0
  23. package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +97 -0
  25. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
  27. package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
  28. package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
  29. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
  30. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
  31. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  32. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  33. package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
  34. package/dist/agent-src/rules/autonomous-execution.md +15 -8
  35. package/dist/agent-src/rules/delegation-policy.md +23 -45
  36. package/dist/agent-src/rules/design-fidelity.md +32 -37
  37. package/dist/agent-src/rules/evaluator-independence.md +43 -49
  38. package/dist/agent-src/rules/test-first.md +41 -0
  39. package/dist/agent-src/rules/user-interaction.md +31 -30
  40. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  41. package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
  42. package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
  43. package/dist/agent-src/skills/database/data/manifest.json +4 -4
  44. package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
  45. package/dist/agent-src/skills/design-review/SKILL.md +50 -0
  46. package/dist/agent-src/skills/error-handling-patterns/SKILL.md +9 -0
  47. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
  48. package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
  49. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  50. package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
  51. package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
  52. package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
  53. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
  54. package/dist/agent-src/templates/agent-settings.md +1 -1
  55. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  56. package/dist/agent-src/templates/roadmaps.md +188 -0
  57. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  58. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  59. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  60. package/dist/cli-delegate/check_update_banner.js +40 -2
  61. package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
  62. package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
  63. package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
  64. package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
  65. package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
  66. package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
  67. package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
  68. package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
  69. package/dist/cli-delegate/chunk-NUHLI2RX.js +80 -0
  70. package/dist/cli-delegate/{chunk-HZ52BRGG.js → chunk-P6ZHP5W2.js} +15 -90
  71. package/dist/cli-delegate/{chunk-TYSY33MD.js → chunk-QJWAUMJW.js} +12 -2
  72. package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
  73. package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
  74. package/dist/cli-delegate/{chunk-2KKXJW25.js → chunk-S3VFXMTM.js} +1 -1
  75. package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
  76. package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
  77. package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
  78. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  79. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  80. package/dist/cli-delegate/cmd_conformance.js +918 -325
  81. package/dist/cli-delegate/cmd_doctor.js +7 -5
  82. package/dist/cli-delegate/cmd_explain.js +5 -3
  83. package/dist/cli-delegate/cmd_export.js +9 -7
  84. package/dist/cli-delegate/cmd_fleet.js +4 -2
  85. package/dist/cli-delegate/cmd_handoff.js +6 -6
  86. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  87. package/dist/cli-delegate/cmd_migrate.js +2 -2
  88. package/dist/cli-delegate/cmd_packs_active.js +3 -2
  89. package/dist/cli-delegate/cmd_preflight.js +4 -2
  90. package/dist/cli-delegate/cmd_prune.js +10 -8
  91. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  92. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  93. package/dist/cli-delegate/cmd_session_recycle.js +4 -4
  94. package/dist/cli-delegate/cmd_settings_get.js +28 -2
  95. package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
  96. package/dist/cli-delegate/cmd_settings_set.js +14 -1
  97. package/dist/cli-delegate/cmd_sync.js +10 -8
  98. package/dist/cli-delegate/cmd_uninstall.js +16 -13
  99. package/dist/cli-delegate/cmd_update.js +1 -1
  100. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  101. package/dist/cli-delegate/cmd_validate.js +12 -10
  102. package/dist/cli-delegate/cmd_versions.js +1 -1
  103. package/dist/discovery/deprecation-report.md +1 -1
  104. package/dist/discovery/discovery-manifest.json +87 -40
  105. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  106. package/dist/discovery/discovery-manifest.summary.md +4 -4
  107. package/dist/discovery/dormancy-report.md +1 -1
  108. package/dist/discovery/orphan-report.md +1 -1
  109. package/dist/discovery/packs.json +10 -8
  110. package/dist/discovery/trust-report.md +3 -3
  111. package/dist/discovery/workspaces.json +8 -6
  112. package/dist/hooks/dispatch.js +2601 -1073
  113. package/dist/install/claudeRuleRewrite.js +14 -3
  114. package/dist/install/conflict.js +60 -10
  115. package/dist/install/conflictTracker.js +218 -0
  116. package/dist/install/fsPrimitives.js +54 -0
  117. package/dist/install/install.mjs +2008 -1481
  118. package/dist/install/manifestFiles.js +259 -0
  119. package/dist/install/preflight.js +14 -2
  120. package/dist/install/preserve.js +157 -0
  121. package/dist/install/recordedOwnership.js +132 -0
  122. package/dist/install/txlog.js +11 -2
  123. package/dist/mcp/registry-manifest.json +3 -3
  124. package/dist/mcp/server.json +2 -2
  125. package/dist/mcp/server.mjs +1612 -667
  126. package/dist/router.json +1 -1
  127. package/dist/scripts/_lib/agent_settings.js +3 -2
  128. package/dist/scripts/_lib/fs_atomic.js +167 -0
  129. package/dist/scripts/_lib/installed_lock.js +1 -1
  130. package/dist/scripts/_lib/installed_tools.js +460 -0
  131. package/dist/scripts/_lib/lean_projection_mode.js +3 -2
  132. package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
  133. package/dist/server/io/yamlIO.js +50 -0
  134. package/dist/server/routes/install.js +8 -0
  135. package/dist/server/routes/wizard.js +9 -3
  136. package/dist/server/schemas/settings.js +17 -5
  137. package/dist/shared/missionExecution.js +97 -0
  138. package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
  139. package/dist/ui/index.html +1 -1
  140. package/docs/MIGRATION.md +103 -0
  141. package/docs/contracts/settings-classes.md +26 -7
  142. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  143. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  144. package/docs/guidelines/design-fidelity-routing.md +29 -0
  145. package/package.json +1 -1
  146. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  147. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  148. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  149. package/src/config/agent-settings.template.yml +139 -27
  150. package/src/config/auto-rule-budget.json +16 -0
  151. package/src/config/ci-local-parity.yml +18 -5
  152. package/src/config/continuity-surface.json +28 -0
  153. package/src/config/gate-coverage.yml +146 -13
  154. package/src/config/gate-violation-baselines.json +6 -6
  155. package/src/config/hook-token-budget.json +2 -0
  156. package/src/config/host-injection-effect.json +1 -1
  157. package/src/config/loop-surfaces.yaml +215 -0
  158. package/src/config/platform-anchor.json +3 -2
  159. package/src/config/preamble-payload-budget.json +12 -7
  160. package/src/config/preamble-payload-exceptions.json +28 -0
  161. package/src/config/release-gate-locality.yml +11 -0
  162. package/src/config/routing-coverage-seed.json +18 -4
  163. package/src/config/rule-enforcement-baseline.json +0 -1
  164. package/src/install/claudeRuleRewrite.ts +16 -2
  165. package/src/install/conflict.ts +65 -9
  166. package/src/install/conflictTracker.ts +299 -0
  167. package/src/install/fsPrimitives.ts +54 -0
  168. package/src/install/manifestFiles.ts +312 -0
  169. package/src/install/preflight.ts +16 -2
  170. package/src/install/preserve.ts +205 -0
  171. package/src/install/recordedOwnership.ts +149 -0
  172. package/src/install/txlog.ts +11 -2
  173. package/src/install/types.ts +19 -4
  174. package/src/scripts/_cli/cmd_conformance.ts +88 -15
  175. package/src/scripts/_cli/cmd_doctor.ts +4 -3
  176. package/src/scripts/_cli/cmd_route_explain.ts +9 -2
  177. package/src/scripts/_cli/cmd_settings_get.ts +44 -0
  178. package/src/scripts/_cli/doctor_execution.ts +90 -0
  179. package/src/scripts/_dispatch.bash +3 -1
  180. package/src/scripts/_lib/activation_payload.ts +247 -0
  181. package/src/scripts/_lib/agent_settings.ts +4 -2
  182. package/src/scripts/_lib/authority_path.ts +102 -0
  183. package/src/scripts/_lib/base_ref_payload.ts +315 -0
  184. package/src/scripts/_lib/cascade_base.ts +94 -0
  185. package/src/scripts/_lib/changelog_eras.ts +7 -2
  186. package/src/scripts/_lib/continuation_ladder.ts +149 -2
  187. package/src/scripts/_lib/council_transport.ts +129 -0
  188. package/src/scripts/_lib/delivery_ready.ts +112 -0
  189. package/src/scripts/_lib/dropped_decision.ts +142 -0
  190. package/src/scripts/_lib/forge_protection.ts +267 -0
  191. package/src/scripts/_lib/hook_platform_keys.ts +27 -0
  192. package/src/scripts/_lib/installed_lock.ts +1 -1
  193. package/src/scripts/_lib/json_python_parity.ts +127 -0
  194. package/src/scripts/_lib/lean_projection_mode.ts +14 -3
  195. package/src/scripts/_lib/loop_surfaces.ts +382 -0
  196. package/src/scripts/_lib/measured_payload_ceiling.ts +424 -0
  197. package/src/scripts/_lib/mission_record.ts +190 -0
  198. package/src/scripts/_lib/obligation_frequency.ts +217 -0
  199. package/src/scripts/_lib/obligations.ts +402 -0
  200. package/src/scripts/_lib/orchestration_record.ts +11 -20
  201. package/src/scripts/_lib/payload_catalogue_completeness.ts +211 -0
  202. package/src/scripts/_lib/release_findings_ingest.ts +324 -0
  203. package/src/scripts/_lib/release_highlights.ts +199 -10
  204. package/src/scripts/_lib/release_holds.ts +493 -0
  205. package/src/scripts/_lib/release_migration_gate.ts +184 -0
  206. package/src/scripts/_lib/release_tag_dispatch.ts +63 -0
  207. package/src/scripts/_lib/review_baseline.ts +254 -0
  208. package/src/scripts/_lib/review_skipped_record.ts +61 -1
  209. package/src/scripts/_lib/rides_along.ts +102 -0
  210. package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
  211. package/src/scripts/_lib/standing_bound_ratchet.ts +216 -103
  212. package/src/scripts/_lib/test_delta.ts +166 -0
  213. package/src/scripts/_lib/test_provenance.ts +171 -0
  214. package/src/scripts/_lib/turn_end_refusals.ts +51 -4
  215. package/src/scripts/_lib/typed_op_grant.ts +246 -0
  216. package/src/scripts/_lib/typed_op_watch.ts +185 -0
  217. package/src/scripts/ai_council/config.ts +8 -11
  218. package/src/scripts/ai_council/fallback_config.ts +5 -3
  219. package/src/scripts/ai_council/ownership_classes.ts +118 -0
  220. package/src/scripts/ask_block_census.ts +285 -15
  221. package/src/scripts/check_beta_review_markers.ts +35 -4
  222. package/src/scripts/check_enforcement_matrix.ts +624 -0
  223. package/src/scripts/check_finding_dispositions.ts +167 -16
  224. package/src/scripts/check_gate_reachability.ts +173 -10
  225. package/src/scripts/check_generator_sync.ts +954 -0
  226. package/src/scripts/check_held_object_arrivals.ts +381 -0
  227. package/src/scripts/check_preamble_payload_budget.ts +474 -124
  228. package/src/scripts/check_release_highlights.ts +33 -1
  229. package/src/scripts/check_release_holds.ts +567 -0
  230. package/src/scripts/check_release_published.ts +1 -1
  231. package/src/scripts/check_reply_consistency.ts +86 -17
  232. package/src/scripts/check_rule_projection_integrity.ts +22 -12
  233. package/src/scripts/check_test_delta.ts +294 -0
  234. package/src/scripts/check_test_weakening.ts +299 -0
  235. package/src/scripts/closure_scan.ts +333 -0
  236. package/src/scripts/compile_hook_manifest.ts +43 -3
  237. package/src/scripts/council_record_shape.ts +209 -0
  238. package/src/scripts/hook_manifest.json +1 -1
  239. package/src/scripts/hook_manifest.yaml +127 -12
  240. package/src/scripts/hooks/block_kernel_rule_writes.ts +12 -2
  241. package/src/scripts/hooks/concern_registry.ts +6 -0
  242. package/src/scripts/hooks/design_pass_hook.ts +128 -3
  243. package/src/scripts/hooks/end_review_nudge_hook.ts +101 -21
  244. package/src/scripts/hooks/evidence_independence.ts +96 -0
  245. package/src/scripts/hooks/memory_recall_hook.ts +540 -0
  246. package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
  247. package/src/scripts/hooks/review_baseline_hook.ts +130 -0
  248. package/src/scripts/hooks/rule_inject_hook.ts +49 -1
  249. package/src/scripts/hooks/run_continuation_hook.ts +17 -20
  250. package/src/scripts/hooks/turn_end_gate_hook.ts +232 -14
  251. package/src/scripts/hooks_doctor.ts +89 -1
  252. package/src/scripts/hooks_status.ts +19 -0
  253. package/src/scripts/install.ts +107 -207
  254. package/src/scripts/interruption_report.ts +8 -2
  255. package/src/scripts/janitor.ts +15 -1
  256. package/src/scripts/lint_decision_classes.ts +464 -0
  257. package/src/scripts/lint_hook_manifest.ts +11 -0
  258. package/src/scripts/lint_major_migration_sections.ts +450 -0
  259. package/src/scripts/lint_plan_risk_register.ts +47 -3
  260. package/src/scripts/lint_roadmap_blockers.ts +61 -0
  261. package/src/scripts/lint_roadmap_producers.ts +202 -0
  262. package/src/scripts/measure_rule_budget.ts +101 -5
  263. package/src/scripts/measure_turn_end_gate.ts +302 -5
  264. package/src/scripts/new_roadmap.ts +37 -0
  265. package/src/scripts/orchestration_record.ts +0 -5
  266. package/src/scripts/release.ts +66 -162
  267. package/src/scripts/release_drill.ts +460 -15
  268. package/src/scripts/release_env.ts +1 -1
  269. package/src/scripts/release_publication.ts +52 -1
  270. package/src/scripts/report_enforcement_drift.ts +566 -0
  271. package/src/scripts/report_held_object_arrivals.ts +456 -0
  272. package/src/scripts/report_host_injection_effect.ts +3 -11
  273. package/src/scripts/report_standing_payload_by_host.ts +26 -152
  274. package/src/scripts/schemas/agent-settings.schema.json +23 -0
  275. package/src/scripts/schemas/command.schema.json +4 -0
  276. package/src/scripts/scope_growth.ts +219 -0
  277. package/src/scripts/sync_agent_settings.ts +140 -18
  278. package/src/scripts/trigger_eval_grandfather.json +0 -1
  279. package/src/scripts/ui_conformance_probe.ts +622 -0
  280. package/src/server/io/yamlIO.ts +48 -0
  281. package/src/server/schemas/settings.ts +31 -7
  282. package/src/shared/missionExecution.ts +126 -0
  283. package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Every roadmap producer ends in closure — mechanically, not by convention.
4
+ *
5
+ * A command that produces a plan and hands it back with open decisions in it
6
+ * has moved those decisions into execution, where meeting one costs a run.
7
+ * The entrance list used to be hard-coded in three command bodies, so the
8
+ * other six producers were simply not in it and nothing said so.
9
+ *
10
+ * The declaration is now the command's own: `produces_roadmap: true` in the
11
+ * frontmatter. This gate reds a command that declares it and does not end in
12
+ * the closure pass, which is the half a hard-coded list could never check.
13
+ *
14
+ * What counts as ending in closure: the body references the closure pass by
15
+ * one of its two names — the `/challenge-me closure` sub-command, or the
16
+ * `closure_scan` detector it runs. Deliberately a reference check rather than
17
+ * a prose check: prose drifts, and a gate that guesses at intent from wording
18
+ * is the detector that gets weakened until it finds nothing.
19
+ *
20
+ * Exit codes: 0 clean · 1 violations · 2 internal error / bad argv.
21
+ */
22
+
23
+ import * as fs from 'node:fs';
24
+ import * as path from 'node:path';
25
+ import process from 'node:process';
26
+ import { fileURLToPath } from 'node:url';
27
+
28
+ import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
29
+
30
+ const _HERE = fileURLToPath(import.meta.url);
31
+ const _PROG = 'lint_roadmap_producers';
32
+
33
+ /** The frontmatter declaration a producer carries. */
34
+ export const DECLARATION_RE = /^produces_roadmap:\s*true\s*$/m;
35
+
36
+ /** Either name of the closure pass discharges the obligation. */
37
+ export const CLOSURE_REFS: readonly RegExp[] = [
38
+ /\/challenge-me\s+closure/,
39
+ /challenge-me\/closure/,
40
+ /\bclosure_scan\b/,
41
+ ];
42
+
43
+ export interface Violation {
44
+ readonly file: string;
45
+ readonly reason: string;
46
+ }
47
+
48
+ function _frontmatter(text: string): string {
49
+ if (!text.startsWith('---')) return '';
50
+ const end = text.indexOf('\n---', 3);
51
+ return end < 0 ? '' : text.slice(0, end);
52
+ }
53
+
54
+ export function declaresProducer(text: string): boolean {
55
+ return DECLARATION_RE.test(_frontmatter(text));
56
+ }
57
+
58
+ export function endsInClosure(text: string): boolean {
59
+ return CLOSURE_REFS.some((re) => re.test(text));
60
+ }
61
+
62
+ export function checkFile(rel: string, text: string): Violation[] {
63
+ if (!declaresProducer(text)) return [];
64
+ if (endsInClosure(text)) return [];
65
+ return [
66
+ {
67
+ file: rel,
68
+ reason:
69
+ 'declares `produces_roadmap: true` and does not end in the closure pass — ' +
70
+ 'a producer hands back an execution contract, not a plan with open decisions ' +
71
+ 'in it. Reference `/challenge-me closure` (or the `closure_scan` detector) ' +
72
+ 'as the command’s last step.',
73
+ },
74
+ ];
75
+ }
76
+
77
+ function _walk(dir: string, out: string[]): void {
78
+ let entries: fs.Dirent[];
79
+ try {
80
+ entries = fs.readdirSync(dir, { withFileTypes: true });
81
+ } catch {
82
+ return;
83
+ }
84
+ for (const e of entries.sort((a, b) => a.name.localeCompare(b.name))) {
85
+ const full = path.join(dir, e.name);
86
+ if (e.isDirectory()) _walk(full, out);
87
+ else if (e.isFile() && e.name === 'command.md') out.push(full);
88
+ }
89
+ }
90
+
91
+ export function listCommands(root: string): string[] {
92
+ const out: string[] = [];
93
+ _walk(root, out);
94
+ return out;
95
+ }
96
+
97
+ function _repoRoot(): string {
98
+ return path.resolve(path.dirname(_HERE), '..', '..');
99
+ }
100
+
101
+ function _usage(): string {
102
+ return (
103
+ `usage: ${_PROG} [-h] [--quiet] [--json] [--self-test]\n\n` +
104
+ `Every command declaring \`produces_roadmap: true\` ends in the closure pass.\n`
105
+ );
106
+ }
107
+
108
+ export function main(argv?: readonly string[]): number {
109
+ const args = argv ?? process.argv.slice(2);
110
+ let quiet = false;
111
+ let json = false;
112
+ let selfTest = false;
113
+ const unknown: string[] = [];
114
+ for (const a of args) {
115
+ if (a === '-h' || a === '--help') {
116
+ process.stdout.write(_usage());
117
+ return 0;
118
+ } else if (a === '--quiet') quiet = true;
119
+ else if (a === '--json') json = true;
120
+ else if (a === '--self-test') selfTest = true;
121
+ else unknown.push(a);
122
+ }
123
+ if (unknown.length) {
124
+ process.stderr.write(`${_usage()}${_PROG}: error: unrecognized arguments: ${unknown.join(' ')}\n`);
125
+ return 2;
126
+ }
127
+ if (selfTest) return _selfTest();
128
+
129
+ const repo = _repoRoot();
130
+ const root = path.join(repo, 'src', 'domains');
131
+ const files = listCommands(root);
132
+ const producers = files.filter((f) => declaresProducer(fs.readFileSync(f, 'utf-8')));
133
+
134
+ try {
135
+ // The corpus is the DECLARED producers, not every command: a tree where
136
+ // nobody declares the key is a tree where the declaration was lost, and
137
+ // that is exactly the silent-disarm this assertion exists to catch.
138
+ assertScanned({
139
+ gate: _PROG,
140
+ scanned: producers.length,
141
+ units: 'roadmap producer(s)',
142
+ roots: ['src/domains'],
143
+ });
144
+ } catch (e) {
145
+ if (e instanceof DeadScopeError) {
146
+ process.stderr.write(`❌ ${e.message}\n`);
147
+ return 2;
148
+ }
149
+ throw e;
150
+ }
151
+
152
+ const violations: Violation[] = [];
153
+ for (const f of producers) {
154
+ violations.push(...checkFile(path.relative(repo, f), fs.readFileSync(f, 'utf-8')));
155
+ }
156
+
157
+ if (json) {
158
+ process.stdout.write(JSON.stringify(violations, null, 2) + '\n');
159
+ return violations.length ? 1 : 0;
160
+ }
161
+ if (violations.length) {
162
+ process.stderr.write(`❌ ${_PROG}: ${violations.length} producer(s) do not end in closure\n`);
163
+ for (const v of violations) process.stderr.write(` ${v.file} — ${v.reason}\n`);
164
+ return 1;
165
+ }
166
+ if (!quiet) {
167
+ process.stdout.write(
168
+ `✅ ${_PROG}: ${producers.length} roadmap producer(s), all ending in closure\n`,
169
+ );
170
+ }
171
+ return 0;
172
+ }
173
+
174
+ /** Both directions in-process: a producer without closure reds, one with it does not. */
175
+ function _selfTest(): number {
176
+ const withClosure = '---\nname: x\nproduces_roadmap: true\n---\n\nRun `/challenge-me closure`.\n';
177
+ const without = '---\nname: x\nproduces_roadmap: true\n---\n\nHand the plan back.\n';
178
+ const notAProducer = '---\nname: x\n---\n\nHand the plan back.\n';
179
+ const failures: string[] = [];
180
+ if (checkFile('a.md', without).length === 0) failures.push('a producer without closure did not red');
181
+ if (checkFile('b.md', withClosure).length !== 0) failures.push('a producer with closure red');
182
+ if (checkFile('c.md', notAProducer).length !== 0) failures.push('a non-producer was judged');
183
+ if (failures.length) {
184
+ for (const f of failures) process.stderr.write(`❌ ${_PROG} --self-test: ${f}\n`);
185
+ return 1;
186
+ }
187
+ process.stdout.write(`✅ ${_PROG} --self-test: both directions hold\n`);
188
+ return 0;
189
+ }
190
+
191
+ function _isCliEntry(): boolean {
192
+ if (!process.argv[1]) return false;
193
+ try {
194
+ return fs.realpathSync(_HERE) === fs.realpathSync(path.resolve(process.argv[1]));
195
+ } catch {
196
+ return false;
197
+ }
198
+ }
199
+
200
+ if (_isCliEntry() || process.argv[1] === _HERE) {
201
+ process.exitCode = main();
202
+ }
@@ -38,6 +38,7 @@ const REPO_ROOT = path.resolve(path.dirname(_HERE), '..', '..');
38
38
 
39
39
  const OVERRIDES_FILE = path.join(REPO_ROOT, 'docs', 'contracts', 'iron-law-overrides.txt');
40
40
  const TREND_FILE = path.join(REPO_ROOT, 'agents', 'runtime', '.rule-budget-history.jsonl');
41
+ const AUTO_BUDGET_FILE = path.join(REPO_ROOT, 'src', 'config', 'auto-rule-budget.json');
41
42
 
42
43
  // Council R2 amendments (2026-05-06) — see docs/contracts/kernel-membership.md § 5.1.
43
44
  // Per-rule cap raised 1.5k → 2.5k; warning band raised 1.2k → 2.0k.
@@ -59,6 +60,8 @@ export interface RuleMeasure {
59
60
  lines: number;
60
61
  tokens_gpt: number;
61
62
  tokens_claude: number;
63
+ /** Iron-Law headings in the body — the obligation count a char count hides. */
64
+ iron_laws: number;
62
65
  }
63
66
 
64
67
  export interface Aggregate {
@@ -80,6 +83,7 @@ export interface Aggregate {
80
83
  per_rule_hard: number;
81
84
  per_rule_target: number;
82
85
  per_rule_override_ceiling: number;
86
+ iron_law_total: number;
83
87
  oversize_rules: RuleMeasure[];
84
88
  top5_largest: RuleMeasure[];
85
89
  }
@@ -130,9 +134,32 @@ export function measure_rule(p: string): RuleMeasure {
130
134
  lines: _count(body, '\n'),
131
135
  tokens_gpt: token_count.gpt_tokens(body).tokens,
132
136
  tokens_claude: token_count.claude_tokens(body).tokens,
137
+ iron_laws: count_iron_laws(body),
133
138
  };
134
139
  }
135
140
 
141
+ /**
142
+ * Count Iron-Law HEADINGS in a rule body.
143
+ *
144
+ * road-to-design-fidelity-proof Phase 3.2. A rule is not an instruction:
145
+ * `token-efficiency` carries five Iron Laws in one file, so a file count and a
146
+ * char count both understate what a model is asked to hold at once. The
147
+ * instruction-following literature measures against the number of SIMULTANEOUS
148
+ * constraints, and an Iron-Law heading is the closest proxy this tree can count
149
+ * deterministically.
150
+ *
151
+ * Heading forms accepted, matching `preservation-guard`'s own definition: any
152
+ * level, optional `The`, singular or plural, optional trailing number or
153
+ * qualifier (`## Iron Law 2`, `## Iron Law — Gate`). A prose mention is NOT a
154
+ * heading, and a heading that merely contains the words later (`## Why the Iron
155
+ * Law exists`) is not one either — the phrase must open the heading text, or
156
+ * every retrospective paragraph would inflate the count.
157
+ */
158
+ export function count_iron_laws(body: string): number {
159
+ const re = /^#{1,6}[ \t]+(?:The[ \t]+)?Iron[ \t]+Laws?\b/gim;
160
+ return (body.match(re) ?? []).length;
161
+ }
162
+
136
163
  /**
137
164
  * Collect rule measurements from every source root (multi-root aware).
138
165
  * Deduplicates on logical rule id (stem) — first root wins. Mirrors
@@ -198,6 +225,7 @@ export function aggregate(rules: RuleMeasure[]): Aggregate {
198
225
  per_rule_hard: PER_RULE_HARD,
199
226
  per_rule_target: PER_RULE_TARGET,
200
227
  per_rule_override_ceiling: PER_RULE_OVERRIDE_CEILING,
228
+ iron_law_total: _sum(rules.map((r) => r.iron_laws)),
201
229
  oversize_rules: rules
202
230
  .filter((r) => r.chars > PER_RULE_HARD)
203
231
  .sort((a, b) => _cmp([-a.chars, a.id], [-b.chars, b.id])),
@@ -324,6 +352,59 @@ export function kernel_budget_check(
324
352
  return [0, out];
325
353
  }
326
354
 
355
+ export interface AutoBudgetConfig {
356
+ baseline_chars: number;
357
+ }
358
+
359
+ /** Read the auto-bucket baseline. Throws rather than defaulting: a ratchet that
360
+ * silently falls back to "no bound" is a permanently green gate. */
361
+ export function load_auto_budget(file: string = AUTO_BUDGET_FILE): AutoBudgetConfig {
362
+ const raw = JSON.parse(fs.readFileSync(file, 'utf-8')) as { baseline_chars?: unknown };
363
+ if (typeof raw.baseline_chars !== 'number') {
364
+ throw new Error(`${file}: baseline_chars must be a number`);
365
+ }
366
+ return { baseline_chars: raw.baseline_chars };
367
+ }
368
+
369
+ /**
370
+ * Enforce the `auto`-bucket growth ratchet. Returns `[exit_code, report_lines]`.
371
+ *
372
+ * road-to-design-fidelity-proof Phase 3.1. `kernel_budget_check` above bounds
373
+ * nine rules; this bounds the other 107, which carry ~93 % of the estate's rule
374
+ * prose and grew against nothing. Shrink-only: growth fails, a shrink passes and
375
+ * says how much slack it created, so the number walks down rather than becoming
376
+ * unused headroom.
377
+ *
378
+ * The Iron-Law total is REPORTED, never gated. No measurement in this tree says
379
+ * how many simultaneous obligations this layer can carry, and a bound nobody
380
+ * measured would publish a guess as a finding.
381
+ */
382
+ export function auto_budget_check(agg: Aggregate, cfg: AutoBudgetConfig): [number, string[]] {
383
+ const out: string[] = [];
384
+ const delta = agg.auto_chars - cfg.baseline_chars;
385
+ const signed = delta >= 0 ? `+${delta}` : String(delta);
386
+ out.push(
387
+ `auto-bucket: ${agg.auto_chars} / ${cfg.baseline_chars} chars ` +
388
+ `(${agg.auto_count} rules, ${signed} vs baseline)`,
389
+ );
390
+ out.push(`iron-law total: ${agg.iron_law_total} heading(s) — reported, not gated`);
391
+ out.push('');
392
+ if (delta > 0) {
393
+ out.push(`\u274c auto budget check: the auto bucket grew ${signed} chars`);
394
+ out.push(
395
+ ' The baseline may only move DOWN. Walk the bucket back, or state the ' +
396
+ 'compensating reduction — raising it to clear this is config weakening.',
397
+ );
398
+ return [1, out];
399
+ }
400
+ out.push(
401
+ delta === 0
402
+ ? '\u2705 auto budget check: pass (at the baseline)'
403
+ : `\u2705 auto budget check: pass (${signed} chars of slack — ratchet it down)`,
404
+ );
405
+ return [0, out];
406
+ }
407
+
327
408
  /**
328
409
  * Append a daily snapshot to agents/runtime/.rule-budget-history.jsonl.
329
410
  * Idempotent per UTC day. Mirrors `trend_append`. Returns `[exit, msg]`.
@@ -363,19 +444,22 @@ export function trend_append(agg: Aggregate): [number, string] {
363
444
  interface Args {
364
445
  json: boolean;
365
446
  kernelBudgetCheck: boolean;
447
+ autoBudgetCheck: boolean;
366
448
  trendAppend: boolean;
367
449
  }
368
450
 
369
451
  function parse_args(argv: string[]): Args {
370
452
  let json = false;
371
453
  let kernelBudgetCheck = false;
454
+ let autoBudgetCheck = false;
372
455
  let trendAppend = false;
373
456
  for (const a of argv) {
374
457
  if (a === '--json') json = true;
375
458
  else if (a === '--kernel-budget-check') kernelBudgetCheck = true;
459
+ else if (a === '--auto-budget-check') autoBudgetCheck = true;
376
460
  else if (a === '--trend-append') trendAppend = true;
377
461
  }
378
- return { json, kernelBudgetCheck, trendAppend };
462
+ return { json, kernelBudgetCheck, autoBudgetCheck, trendAppend };
379
463
  }
380
464
 
381
465
  export function main(argv: string[] = process.argv.slice(2)): number {
@@ -384,10 +468,22 @@ export function main(argv: string[] = process.argv.slice(2)): number {
384
468
  const rules = collect();
385
469
  const agg = aggregate(rules);
386
470
 
387
- if (args.kernelBudgetCheck) {
388
- const overrides = load_overrides();
389
- const [code, report] = kernel_budget_check(rules, agg, overrides);
390
- process.stdout.write(report.join('\n') + '\n');
471
+ // Both budget flags may be passed in one invocation, and the CI step does
472
+ // exactly that — a second task step would be a new gate `check_ci_local_parity`
473
+ // has to be told about, for two checks over one measurement.
474
+ if (args.kernelBudgetCheck || args.autoBudgetCheck) {
475
+ let code = 0;
476
+ if (args.kernelBudgetCheck) {
477
+ const overrides = load_overrides();
478
+ const [kCode, report] = kernel_budget_check(rules, agg, overrides);
479
+ process.stdout.write(report.join('\n') + '\n');
480
+ code = Math.max(code, kCode);
481
+ }
482
+ if (args.autoBudgetCheck) {
483
+ const [aCode, report] = auto_budget_check(agg, load_auto_budget());
484
+ process.stdout.write(report.join('\n') + '\n');
485
+ code = Math.max(code, aCode);
486
+ }
391
487
  return code;
392
488
  }
393
489