@event4u/agent-config 14.21.0 → 14.23.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 (235) 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 +164 -187
  5. package/CREDITS.md +37 -0
  6. package/README.md +1 -1
  7. package/dist/agent-src/commands/analyze/inbox.md +380 -5
  8. package/dist/agent-src/commands/analyze/repo.md +4 -2
  9. package/dist/agent-src/commands/pr/merge.md +47 -38
  10. package/dist/agent-src/commands/roadmap/next.md +8 -0
  11. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +69 -0
  12. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -5
  13. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +12 -0
  14. package/dist/agent-src/rules/external-code-graph-interop.md +19 -14
  15. package/dist/agent-src/rules/notes-first-reasoning.md +36 -25
  16. package/dist/agent-src/rules/token-efficiency.md +26 -3
  17. package/dist/agent-src/scripts/_cli_entry.ts +51 -0
  18. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
  19. package/dist/agent-src/scripts/roadmap_gates.ts +4 -20
  20. package/dist/agent-src/scripts/roadmap_set_step.ts +5 -2
  21. package/dist/agent-src/scripts/stubs_due.ts +4 -18
  22. package/dist/agent-src/scripts/update_roadmap_progress.ts +7 -24
  23. package/dist/agent-src/skills/code-intelligence/SKILL.md +82 -1
  24. package/dist/agent-src/skills/git-workflow/references/push-closes-its-loop.md +9 -0
  25. package/dist/agent-src/skills/roadmap-writing/SKILL.md +17 -0
  26. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +52 -2
  27. package/dist/agent-src/templates/agent-settings.md +0 -1
  28. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  29. package/dist/cli/registry.js +1 -1
  30. package/dist/cli-delegate/_cli_entry.js +8 -0
  31. package/dist/cli-delegate/_lib/pin_resolver.js +170 -0
  32. package/dist/cli-delegate/archival_sweep.js +8 -0
  33. package/dist/cli-delegate/archive_completed_roadmaps.js +542 -0
  34. package/dist/cli-delegate/check_update_banner.js +923 -0
  35. package/dist/cli-delegate/{chunk-ZVBOHSVF.js → chunk-2KKXJW25.js} +23 -9
  36. package/dist/cli-delegate/chunk-5EK5WQN6.js +28 -0
  37. package/dist/cli-delegate/chunk-7XGD2OEU.js +96 -0
  38. package/dist/cli-delegate/chunk-DBH4AHDK.js +155 -0
  39. package/dist/cli-delegate/{chunk-4FS4WRXP.js → chunk-IAI3XL43.js} +15 -3
  40. package/dist/cli-delegate/chunk-JO25G5H7.js +20 -0
  41. package/dist/cli-delegate/{chunk-643Z7FIC.js → chunk-KCNTUSPI.js} +7 -1
  42. package/dist/cli-delegate/chunk-LTYVIY76.js +7961 -0
  43. package/dist/cli-delegate/chunk-QAJS5YWY.js +999 -0
  44. package/dist/cli-delegate/{chunk-YS6XTLEK.js → chunk-TYSY33MD.js} +56 -6
  45. package/dist/cli-delegate/chunk-ULET4BYS.js +328 -0
  46. package/dist/cli-delegate/chunk-YDQSHTD7.js +187 -0
  47. package/dist/cli-delegate/chunk-YWVXLR44.js +48 -0
  48. package/dist/cli-delegate/chunk-ZZQBUHFK.js +273 -0
  49. package/dist/cli-delegate/cmd_conformance.js +2 -2
  50. package/dist/cli-delegate/cmd_export.js +2 -2
  51. package/dist/cli-delegate/cmd_handoff.js +45 -13
  52. package/dist/cli-delegate/cmd_prune.js +2 -2
  53. package/dist/cli-delegate/cmd_session_recycle.js +4 -14
  54. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  55. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  56. package/dist/cli-delegate/cmd_sync.js +2 -2
  57. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  58. package/dist/cli-delegate/cmd_validate.js +2 -2
  59. package/dist/cli-delegate/dashboard_mode.js +16 -0
  60. package/dist/cli-delegate/gate_budget.js +24 -0
  61. package/dist/cli-delegate/gate_execute.js +25 -0
  62. package/dist/cli-delegate/guarded_baseline.js +18 -0
  63. package/dist/cli-delegate/resume_probe.js +22 -0
  64. package/dist/cli-delegate/roadmap_gates.js +638 -0
  65. package/dist/cli-delegate/roadmap_set_step.js +173 -0
  66. package/dist/cli-delegate/stub_queue.js +47 -0
  67. package/dist/cli-delegate/stubs_due.js +38 -0
  68. package/dist/cli-delegate/ticket_bundles.js +59 -0
  69. package/dist/cli-delegate/update_roadmap_progress.js +60 -0
  70. package/dist/discovery/deprecation-report.md +1 -1
  71. package/dist/discovery/discovery-manifest.json +13 -13
  72. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  73. package/dist/discovery/discovery-manifest.summary.md +1 -1
  74. package/dist/discovery/dormancy-report.md +1 -1
  75. package/dist/discovery/orphan-report.md +1 -1
  76. package/dist/discovery/packs.json +2 -2
  77. package/dist/discovery/trust-report.md +1 -1
  78. package/dist/discovery/workspaces.json +2 -2
  79. package/dist/hooks/dispatch.js +1813 -946
  80. package/dist/install/claudeLayerCarriage.js +237 -0
  81. package/dist/install/claudePathsPlan.js +79 -0
  82. package/dist/install/hostLayerFingerprint.js +1 -1
  83. package/dist/install/install.mjs +21 -3
  84. package/dist/install/partitionEligibility.js +231 -117
  85. package/dist/install/ruleLayerPartition.js +10 -7
  86. package/dist/mcp/registry-manifest.json +2 -2
  87. package/dist/mcp/server.json +2 -2
  88. package/dist/mcp/server.mjs +10870 -7641
  89. package/dist/scripts/_lib/lean_projection_mode.js +108 -0
  90. package/dist/scripts/_lib/router_match.js +243 -0
  91. package/dist/scripts/_lib/rule_injection.js +216 -0
  92. package/dist/scripts/condense.js +52 -45
  93. package/dist/scripts/project_thin_rules.js +139 -19
  94. package/dist/server/schemas/settings.js +16 -3
  95. package/docs/MIGRATION.md +105 -1
  96. package/docs/contracts/settings-classes.md +40 -8
  97. package/docs/guidelines/agent-infra/minimal-safe-diff-mechanics.md +73 -0
  98. package/docs/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  99. package/llms.txt +1 -1
  100. package/package.json +7 -4
  101. package/src/agent-src/scripts/_cli_entry.ts +51 -0
  102. package/src/agent-src/scripts/archive_completed_roadmaps.ts +120 -27
  103. package/src/agent-src/scripts/roadmap_gates.ts +4 -20
  104. package/src/agent-src/scripts/roadmap_set_step.ts +5 -2
  105. package/src/agent-src/scripts/stubs_due.ts +4 -18
  106. package/src/agent-src/scripts/update_roadmap_progress.ts +7 -24
  107. package/src/config/agent-settings.template.yml +47 -1
  108. package/src/config/continuity-surface.json +516 -0
  109. package/src/config/estate-count-budget.json +1 -1
  110. package/src/config/evaluator-budgets.json +4 -4
  111. package/src/config/gate-coverage.yml +29 -8
  112. package/src/config/gate-violation-baselines.json +8 -8
  113. package/src/config/gitignore-block.txt +19 -0
  114. package/src/config/hook-token-budget.json +7 -6
  115. package/src/config/host-injection-effect.json +73 -0
  116. package/src/config/packed-binary-manifest.json +33 -0
  117. package/src/config/preamble-payload-budget.json +112 -105
  118. package/src/config/publish-surface.json +4 -2
  119. package/src/config/routing-coverage-seed.json +9 -2
  120. package/src/install/claudeLayerCarriage.ts +273 -0
  121. package/src/install/claudePathsPlan.ts +76 -0
  122. package/src/install/hostLayerFingerprint.ts +1 -1
  123. package/src/install/partitionEligibility.ts +261 -127
  124. package/src/install/ruleLayerPartition.ts +19 -23
  125. package/src/scripts/_cli/cmd_session_recycle.ts +2 -25
  126. package/src/scripts/_cli/handoff_sessions.ts +14 -44
  127. package/src/scripts/_dispatch.bash +77 -27
  128. package/src/scripts/_lib/auto_dispatch.ts +2 -2
  129. package/src/scripts/_lib/catalogue_layer_parity.ts +146 -0
  130. package/src/scripts/_lib/continuity_slot.ts +295 -0
  131. package/src/scripts/_lib/continuity_surface.ts +296 -0
  132. package/src/scripts/_lib/continuity_writer.ts +253 -0
  133. package/src/scripts/_lib/corpus_manifest.ts +26 -9
  134. package/src/scripts/_lib/hook_settings.ts +86 -1
  135. package/src/scripts/_lib/injection_effect.ts +151 -0
  136. package/src/scripts/_lib/layer_overlap_notice.ts +50 -6
  137. package/src/scripts/_lib/lean_projection_mode.ts +127 -0
  138. package/src/scripts/_lib/packed_binary_predicate.ts +262 -0
  139. package/src/scripts/_lib/pin_resolver.ts +13 -0
  140. package/src/scripts/_lib/recycle_envelope_paths.ts +109 -21
  141. package/src/scripts/_lib/regression_neighbourhood.ts +159 -22
  142. package/src/scripts/_lib/retired_status.ts +74 -0
  143. package/src/scripts/_lib/session_eol.ts +44 -0
  144. package/src/scripts/_lib/session_index_trust.ts +346 -0
  145. package/src/scripts/_lib/skill_catalogue.ts +156 -21
  146. package/src/scripts/_lib/standing_bound_ratchet.ts +154 -0
  147. package/src/scripts/_lib/subagent_capsule.ts +117 -8
  148. package/src/scripts/_lib/vendored_grammar_upstream.ts +280 -0
  149. package/src/scripts/ai_council/api_transport.ts +5 -0
  150. package/src/scripts/ai_council/deliberation_metrics.ts +353 -0
  151. package/src/scripts/ai_council/prompts.ts +9 -0
  152. package/src/scripts/ai_council/synthesis_disagreement.ts +206 -0
  153. package/src/scripts/audit_mcp_tools.ts +69 -25
  154. package/src/scripts/build_mcp_catalog.ts +24 -1
  155. package/src/scripts/capture_skill_catalogue.ts +24 -11
  156. package/src/scripts/check_candidate_lines.ts +499 -0
  157. package/src/scripts/check_continuity_surface.ts +475 -0
  158. package/src/scripts/check_dependency_floors.ts +13 -6
  159. package/src/scripts/check_estate_count.ts +40 -79
  160. package/src/scripts/check_host_tree_parity.ts +291 -0
  161. package/src/scripts/check_pack_size.ts +262 -23
  162. package/src/scripts/check_preamble_payload_budget.ts +136 -7
  163. package/src/scripts/check_roadmap_trackable.ts +19 -16
  164. package/src/scripts/check_rule_layer_partition.ts +54 -34
  165. package/src/scripts/check_rule_projection_integrity.ts +102 -2
  166. package/src/scripts/check_single_delivery.ts +97 -31
  167. package/src/scripts/check_update_banner.ts +13 -0
  168. package/src/scripts/ci_settle.ts +205 -5
  169. package/src/scripts/code_graph/build.ts +217 -15
  170. package/src/scripts/code_graph/cli.ts +334 -15
  171. package/src/scripts/code_graph/detect.ts +38 -0
  172. package/src/scripts/code_graph/extract.ts +11 -0
  173. package/src/scripts/code_graph/grammar_probe.ts +43 -0
  174. package/src/scripts/code_graph/loader.ts +88 -14
  175. package/src/scripts/code_graph/query.ts +144 -11
  176. package/src/scripts/code_graph/resolution_tiers.ts +238 -0
  177. package/src/scripts/code_graph/sqlite_store.ts +262 -6
  178. package/src/scripts/code_graph/types.ts +117 -3
  179. package/src/scripts/code_graph/validate.ts +26 -1
  180. package/src/scripts/code_graph/verbs.ts +590 -0
  181. package/src/scripts/condense.ts +54 -42
  182. package/src/scripts/corpus_manifest.ts +5 -5
  183. package/src/scripts/council_cli.ts +11 -12
  184. package/src/scripts/count_intent_disagreement.ts +426 -0
  185. package/src/scripts/handoff_context_hook.ts +118 -1
  186. package/src/scripts/hook_effect_doctor.ts +82 -1
  187. package/src/scripts/hook_manifest.json +1 -1
  188. package/src/scripts/hook_manifest.yaml +87 -12
  189. package/src/scripts/hooks/block_speaking_inbox_dir.ts +182 -16
  190. package/src/scripts/hooks/chain_nudge_hook.ts +282 -0
  191. package/src/scripts/hooks/code_graph_context_hook.ts +201 -0
  192. package/src/scripts/hooks/concern_registry.ts +4 -2
  193. package/src/scripts/hooks/host_semantics.ts +1 -1
  194. package/src/scripts/hooks/orchestration_record_hook.ts +2 -2
  195. package/src/scripts/hooks/push_settle_hook.ts +3 -2
  196. package/src/scripts/hooks/rule_inject_hook.ts +108 -21
  197. package/src/scripts/hooks/session_eol_hook.ts +120 -2
  198. package/src/scripts/hooks/skill_route_hook.ts +11 -4
  199. package/src/scripts/hot_context_hook.ts +62 -7
  200. package/src/scripts/inbox_source_census.ts +322 -0
  201. package/src/scripts/install-hooks.sh +82 -0
  202. package/src/scripts/{lint_carrier_integrity.ts → lint_deferral_integrity.ts} +60 -214
  203. package/src/scripts/lint_plan_risk_register.ts +13 -17
  204. package/src/scripts/lint_roadmap_blockers.ts +164 -1
  205. package/src/scripts/mcp_server/consumer_tool_catalog.json +152 -2
  206. package/src/scripts/mcp_server/graph_tools.ts +294 -0
  207. package/src/scripts/mcp_server/path_util.ts +31 -0
  208. package/src/scripts/mcp_server/suggest_skill.ts +72 -0
  209. package/src/scripts/mcp_server/tool_catalog_source.ts +7 -1
  210. package/src/scripts/mcp_server/tools.ts +5 -69
  211. package/src/scripts/media/lib/adapter-contract.md +7 -2
  212. package/src/scripts/media/lib/fixtures/flux/asset-0001.png +0 -0
  213. package/src/scripts/media/lib/fixtures/gemini-image/asset-0001.png +0 -0
  214. package/src/scripts/media/lib/fixtures/ideogram/asset-0001.png +0 -0
  215. package/src/scripts/model_rule_injection.ts +61 -4
  216. package/src/scripts/project_thin_rules.ts +149 -16
  217. package/src/scripts/rdp_candidates_delta.ts +276 -0
  218. package/src/scripts/rdp_quality_eval.ts +217 -19
  219. package/src/scripts/release_mix_taxonomy.json +3 -2
  220. package/src/scripts/report_host_injection_effect.ts +189 -0
  221. package/src/scripts/report_layer_overlap.ts +41 -0
  222. package/src/scripts/report_skill_menu_census.ts +341 -0
  223. package/src/scripts/report_standing_payload_by_host.ts +650 -0
  224. package/src/scripts/schemas/agent-settings.schema.json +7 -1
  225. package/src/scripts/session_memory_index.ts +81 -8
  226. package/src/scripts/skill_tools/score_skill_relevance.ts +70 -6
  227. package/src/scripts/skill_tools/suggest_skill_for_task.ts +37 -3
  228. package/src/server/schemas/settings.ts +23 -4
  229. package/src/vendor/grammars/README.md +86 -0
  230. package/src/vendor/grammars/tree-sitter-javascript.wasm +0 -0
  231. package/src/vendor/grammars/tree-sitter-php.wasm +0 -0
  232. package/src/vendor/grammars/tree-sitter-typescript.wasm +0 -0
  233. package/src/scripts/_lib/carrier_status.ts +0 -118
  234. package/src/scripts/_lib/estate_carrier_cases.ts +0 -72
  235. package/src/scripts/hooks/code_graph_nudge_hook.ts +0 -191
@@ -0,0 +1,475 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `check_continuity_surface` — the continuity estate walks DOWN, and a new
4
+ * continuity mechanism pays for itself.
5
+ *
6
+ * WHY THIS EXISTS
7
+ * ---------------
8
+ * Twelve archived roadmaps built this package's continuity layers and not one
9
+ * retired the layer before it. `road-to-one-continuity-record` recorded that as
10
+ * its own Risk 1 — "the record is added and nothing is retired" — and stated
11
+ * its success as five numbers rather than a sentence:
12
+ *
13
+ * public continuity commands: 0
14
+ * session resume pickers: 0
15
+ * persistent continuity artefacts: 1
16
+ * continuity schemas: 1
17
+ * normal-path manual actions: 0
18
+ *
19
+ * A number nobody derives is a number nobody can be wrong about. Until this
20
+ * gate there was no command in the tree that produced those five figures: a
21
+ * grep for `end-state` over `src/scripts/` returned one unrelated hit, and a
22
+ * grep for `continuity` returned implementation prose and an unrelated
23
+ * AI-video seam. So "re-derived by command rather than asserted" was an
24
+ * obligation with no instrument.
25
+ *
26
+ * WHY IT PUBLISHES AN INVENTORY AND NOT ONLY FIVE NUMBERS
27
+ * ------------------------------------------------------
28
+ * The AI council of 2026-09-07 (2 seats, both present) found the failure mode
29
+ * before it happened: the five numbers are gameable by NAMING. Position 3 can
30
+ * be made to read `1` with nothing retired, simply by classifying an artefact
31
+ * as something other than "continuity". Both seats required the inventory rule
32
+ * to be behavioural instead —
33
+ *
34
+ * Any persisted state written for later session/run recovery,
35
+ * verification, or context restoration must be listed, whether or not it
36
+ * is labeled "continuity."
37
+ *
38
+ * — and required exclusions to stay legitimate AND stay visible. This gate
39
+ * therefore DISCOVERS its artefact corpus from behaviour (every distinct leaf
40
+ * under `agents/runtime/state/` that any source file names) rather than from
41
+ * vocabulary, requires the committed inventory to dispose of every one of them,
42
+ * and prints the exclusions with their reasons on every run — including the one
43
+ * the council named as the worked example, `checkpoints/`.
44
+ *
45
+ * THREE CHECKS, ONE GATE
46
+ * ----------------------
47
+ * T1 — inventory validity. Every discovered leaf is disposed of, every row's
48
+ * `locus` still resolves, every row carries a reason. A retirement is performed
49
+ * by DELETING a row, so a row left standing over a deleted surface reddens: the
50
+ * count cannot claim a subtraction the tree did not make.
51
+ *
52
+ * T2 — the ratchet. No axis may read HIGHER than it reads on the base ref. The
53
+ * floor is measured, not stored, from the base ref's own copy of the inventory
54
+ * — a single file, so `git show` rather than a materialised subtree, the same
55
+ * reasoning `check_estate_count` records for its concern axis. A count BELOW
56
+ * the floor is a drawdown and passes.
57
+ *
58
+ * T3 — the rule is stated where the check fails. The roadmap requires that a
59
+ * reader who trips this gate learns the rule without going to find it, so the
60
+ * failure text carries it verbatim rather than a pointer.
61
+ *
62
+ * WHAT THIS GATE DELIBERATELY DOES NOT DO
63
+ * ---------------------------------------
64
+ * It does not fail when an axis is above target. The targets are the roadmap's
65
+ * destination, not this gate's admission criterion: failing on them would red
66
+ * the tree on every branch until the whole retirement lands, which is the
67
+ * "gate that fails its own tree on debt the landing change did not cause"
68
+ * this repository reverts rather than adopts. Distance-to-target is REPORTED
69
+ * on every run and ratcheted downward; closing it is the roadmap's job.
70
+ *
71
+ * ./scripts-run src/scripts/check_continuity_surface
72
+ * ./scripts-run src/scripts/check_continuity_surface --json
73
+ * ./scripts-run src/scripts/check_continuity_surface --base origin/main
74
+ * ./scripts-run src/scripts/check_continuity_surface --self-test
75
+ */
76
+ import { spawnSync } from 'node:child_process';
77
+ import * as fs from 'node:fs';
78
+ import * as os from 'node:os';
79
+ import * as path from 'node:path';
80
+ import { fileURLToPath, pathToFileURL } from 'node:url';
81
+
82
+ import {
83
+ AXES,
84
+ INVENTORY_POSIX,
85
+ TARGETS,
86
+ countAxes,
87
+ discoverStateLeaves,
88
+ readInventory,
89
+ validateInventory,
90
+ type Axis,
91
+ type Inventory,
92
+ type InventoryRow,
93
+ type SurfaceCounts,
94
+ } from './_lib/continuity_surface.js';
95
+ import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
96
+ import { runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
97
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
98
+
99
+ const GATE = 'check_continuity_surface';
100
+
101
+ /**
102
+ * Built by concatenation on purpose. The self-test below has to write fixture
103
+ * files that LOOK like real state paths, and a contiguous literal would be
104
+ * discovered by this gate's own walk — the gate would then red on its own
105
+ * fixtures. Excluding this file from the walk was the other option and is
106
+ * strictly worse: an excluded file is a blind spot, and the one file guaranteed
107
+ * to be edited by whoever wants to weaken this gate is this one.
108
+ */
109
+ const _STATE_PREFIX = 'agents/runtime/' + 'state/';
110
+
111
+ /**
112
+ * The rule the ratchet encodes, verbatim from the parent roadmap. Printed at
113
+ * the point of failure, per that roadmap's own verify line: "the rule is stated
114
+ * where the check fails, not only here".
115
+ */
116
+ const RULE =
117
+ 'A new continuity mechanism may be introduced only if it replaces an existing one, or\n' +
118
+ 'demonstrably covers a capability the one record cannot.';
119
+
120
+ function repoRootFrom(start: string): string {
121
+ let cur = path.resolve(start);
122
+ for (;;) {
123
+ if (fs.existsSync(path.join(cur, INVENTORY_POSIX))) return cur;
124
+ const parent = path.dirname(cur);
125
+ if (parent === cur) return path.resolve(start);
126
+ cur = parent;
127
+ }
128
+ }
129
+
130
+ function gitShow(repoRoot: string, ref: string, rel: string): string | null {
131
+ const res = spawnSync('git', ['show', `${ref}:${rel}`], {
132
+ cwd: repoRoot,
133
+ encoding: 'utf-8',
134
+ maxBuffer: 64 * 1024 * 1024,
135
+ });
136
+ if (res.status !== 0 || typeof res.stdout !== 'string') return null;
137
+ return res.stdout;
138
+ }
139
+
140
+ function countsAt(repoRoot: string, ref: string): SurfaceCounts | null {
141
+ const raw = gitShow(repoRoot, ref, INVENTORY_POSIX);
142
+ if (raw === null) return null;
143
+ try {
144
+ const parsed = JSON.parse(raw) as { rows?: unknown };
145
+ const rows = Array.isArray(parsed.rows) ? (parsed.rows as InventoryRow[]) : [];
146
+ return countAxes({ rows });
147
+ } catch {
148
+ return null;
149
+ }
150
+ }
151
+
152
+ function renderInventory(inv: Inventory, write: (s: string) => void): void {
153
+ for (const axis of AXES) {
154
+ const rows = inv.rows.filter((r) => r.axis === axis);
155
+ const counted = rows.filter((r) => r.disposition === 'counted');
156
+ const excluded = rows.filter((r) => r.disposition === 'excluded');
157
+ write(`\n ${axis} — counted ${String(counted.length)}, target ${String(TARGETS[axis])}\n`);
158
+ for (const row of counted) {
159
+ write(` ▸ ${row.id} (${row.locus})\n`);
160
+ }
161
+ if (excluded.length > 0) {
162
+ write(` excluded (${String(excluded.length)}) — visible by contract, never silent:\n`);
163
+ for (const row of excluded) {
164
+ write(` · ${row.id} (${row.locus})\n`);
165
+ write(` ${row.reason}\n`);
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ export interface RunOptions {
172
+ repoRoot?: string;
173
+ baseRef?: string | null;
174
+ json?: boolean;
175
+ quiet?: boolean;
176
+ write?: (s: string) => void;
177
+ }
178
+
179
+ export function run(opts: RunOptions = {}): number {
180
+ const write = opts.write ?? ((s: string) => void process.stdout.write(s));
181
+ const repoRoot = opts.repoRoot ?? repoRootFrom(process.cwd());
182
+
183
+ let inv: Inventory;
184
+ try {
185
+ inv = readInventory(repoRoot);
186
+ } catch (exc) {
187
+ write(`❌ ${GATE}: cannot read ${INVENTORY_POSIX} — ${String(exc)}\n`);
188
+ return 1;
189
+ }
190
+
191
+ const discovered = discoverStateLeaves(repoRoot);
192
+ try {
193
+ reportScanned(
194
+ {
195
+ gate: GATE,
196
+ scanned: discovered.length + inv.rows.length,
197
+ units: 'inventory row(s) + discovered state leaf/leaves',
198
+ roots: [INVENTORY_POSIX, 'src/scripts', 'src/agent-src/scripts', 'src/cli'],
199
+ },
200
+ (chunk: string) => {
201
+ write(String(chunk));
202
+ return true;
203
+ },
204
+ );
205
+ } catch (exc) {
206
+ if (exc instanceof DeadScopeError) {
207
+ write(`❌ ${exc.message}\n`);
208
+ return 1;
209
+ }
210
+ throw exc;
211
+ }
212
+
213
+ const findings = validateInventory(repoRoot, inv, discovered);
214
+ const counts = countAxes(inv);
215
+
216
+ const baseRef = opts.baseRef === undefined ? resolveBaseRef(repoRoot) : opts.baseRef;
217
+ const floor = baseRef === null ? null : countsAt(repoRoot, baseRef);
218
+ const grew: Array<{ axis: Axis; floor: number; live: number }> = [];
219
+ if (floor !== null) {
220
+ for (const axis of AXES) {
221
+ if (counts[axis] > floor[axis]) {
222
+ grew.push({ axis, floor: floor[axis], live: counts[axis] });
223
+ }
224
+ }
225
+ }
226
+
227
+ if (opts.json === true) {
228
+ write(
229
+ JSON.stringify(
230
+ {
231
+ gate: GATE,
232
+ counts,
233
+ targets: TARGETS,
234
+ base_ref: baseRef,
235
+ floor,
236
+ grew,
237
+ findings,
238
+ discovered_leaves: discovered.length,
239
+ inventory_rows: inv.rows.length,
240
+ },
241
+ null,
242
+ 2,
243
+ ) + '\n',
244
+ );
245
+ return findings.length > 0 || grew.length > 0 ? 1 : 0;
246
+ }
247
+
248
+ if (opts.quiet !== true) {
249
+ write(`\n${GATE}: the five end-state numbers, derived from ${INVENTORY_POSIX}\n`);
250
+ renderInventory(inv, write);
251
+ write('\n ');
252
+ write(AXES.map((a) => String(counts[a])).join(' / '));
253
+ write(' (target ');
254
+ write(AXES.map((a) => String(TARGETS[a])).join(' / '));
255
+ write(')\n');
256
+ const remaining = AXES.filter((a) => counts[a] !== TARGETS[a]);
257
+ if (remaining.length === 0) {
258
+ write(' ✅ every axis is at target.\n');
259
+ } else {
260
+ write(
261
+ ` · ${String(remaining.length)} axis/axes above target — reported, not failed: ` +
262
+ 'the targets are the roadmap destination, not this gate\'s admission criterion.\n',
263
+ );
264
+ }
265
+ if (floor === null) {
266
+ write(
267
+ ` · no floor: ${baseRef === null ? 'no base ref resolved' : `${baseRef} carries no ${INVENTORY_POSIX}`} — ` +
268
+ 'the ratchet did not run this time.\n',
269
+ );
270
+ } else {
271
+ write(` · floor from ${String(baseRef)}: ${AXES.map((a) => String(floor[a])).join(' / ')}\n`);
272
+ }
273
+ }
274
+
275
+ if (findings.length === 0 && grew.length === 0) {
276
+ if (opts.quiet !== true) {
277
+ write(`✅ ${GATE}: inventory describes the tree, and no axis grew.\n`);
278
+ }
279
+ return 0;
280
+ }
281
+
282
+ if (grew.length > 0) {
283
+ write(`\n❌ ${GATE}: a continuity axis grew above the base ref.\n\n`);
284
+ for (const g of grew) {
285
+ write(` ${g.axis}: ${String(g.floor)} → ${String(g.live)}\n`);
286
+ }
287
+ write('\n The rule this ratchet encodes:\n\n');
288
+ for (const line of RULE.split('\n')) write(` ${line}\n`);
289
+ write(
290
+ '\n So: retire one in the same change (delete its row — that is the subtraction),\n' +
291
+ ' or state in the row\'s `reason` which capability the one record cannot cover.\n',
292
+ );
293
+ }
294
+
295
+ if (findings.length > 0) {
296
+ write(`\n❌ ${GATE}: ${String(findings.length)} inventory finding(s).\n\n`);
297
+ for (const f of findings) {
298
+ write(` [${f.kind}] ${f.detail}\n`);
299
+ }
300
+ write(
301
+ `\n The inventory is ${INVENTORY_POSIX}. It is behavioural by contract: every\n` +
302
+ ' persisted-state leaf under agents/runtime/state/ that any source names must be\n' +
303
+ ' disposed of there, because a count keyed on the WORD "continuity" is gameable by\n' +
304
+ ' renaming — which is the defect this gate exists to make impossible.\n',
305
+ );
306
+ }
307
+ return 1;
308
+ }
309
+
310
+ function _mkRepo(dir: string, rows: unknown[]): void {
311
+ fs.mkdirSync(path.join(dir, 'src', 'config'), { recursive: true });
312
+ fs.mkdirSync(path.join(dir, 'src', 'scripts'), { recursive: true });
313
+ fs.writeFileSync(
314
+ path.join(dir, INVENTORY_POSIX),
315
+ JSON.stringify({ targets: TARGETS, rows }, null, 2),
316
+ );
317
+ }
318
+
319
+ function _row(over: Partial<InventoryRow> = {}): InventoryRow {
320
+ return {
321
+ id: 'placeholder.json',
322
+ axis: 'persistent_continuity_artefacts',
323
+ disposition: 'excluded',
324
+ locus: INVENTORY_POSIX,
325
+ reason: 'a reason long enough to clear the substance floor this gate enforces',
326
+ ...over,
327
+ };
328
+ }
329
+
330
+
331
+ function selfTest(): number {
332
+ const mk = (): string => fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'ccs-'));
333
+ const silent = (): void => {};
334
+
335
+ const cases: SelfTestCase[] = [
336
+ {
337
+ name: 'a persisted-state leaf the inventory does not dispose of → reject',
338
+ expect: 'reject',
339
+ run: () => {
340
+ const dir = mk();
341
+ _mkRepo(dir, []);
342
+ fs.writeFileSync(
343
+ path.join(dir, 'src', 'scripts', 'newthing.ts'),
344
+ `const P = '${_STATE_PREFIX}brand-new-leaf.json';\n`,
345
+ );
346
+ return run({ repoRoot: dir, baseRef: null, quiet: true, write: silent });
347
+ },
348
+ },
349
+ {
350
+ name: 'a row whose locus no longer resolves → reject (a claimed retirement the tree did not make)',
351
+ expect: 'reject',
352
+ run: () => {
353
+ const dir = mk();
354
+ _mkRepo(dir, [_row({ id: 'ghost', locus: 'src/scripts/deleted_thing.ts' })]);
355
+ return run({ repoRoot: dir, baseRef: null, quiet: true, write: silent });
356
+ },
357
+ },
358
+ {
359
+ name: 'a counted axis above the base-ref floor → reject',
360
+ expect: 'reject',
361
+ run: () => {
362
+ const dir = mk();
363
+ _mkRepo(dir, [
364
+ _row({ id: 'a', disposition: 'counted' }),
365
+ _row({ id: 'b', disposition: 'counted' }),
366
+ ]);
367
+ const git = (args: string[]): void => {
368
+ spawnSync('git', args, { cwd: dir, encoding: 'utf-8' });
369
+ };
370
+ git(['init', '-q']);
371
+ git(['config', 'user.email', 'g@example.com']);
372
+ git(['config', 'user.name', 'g']);
373
+ // Base carries ONE counted row; HEAD carries two.
374
+ _mkRepo(dir, [_row({ id: 'a', disposition: 'counted' })]);
375
+ git(['add', '-A']);
376
+ git(['commit', '-qm', 'base']);
377
+ const base = spawnSync('git', ['rev-parse', 'HEAD'], {
378
+ cwd: dir,
379
+ encoding: 'utf-8',
380
+ }).stdout.trim();
381
+ _mkRepo(dir, [
382
+ _row({ id: 'a', disposition: 'counted' }),
383
+ _row({ id: 'b', disposition: 'counted' }),
384
+ ]);
385
+ return run({ repoRoot: dir, baseRef: base, quiet: true, write: silent });
386
+ },
387
+ },
388
+ {
389
+ name: 'a row with no reason of substance → reject',
390
+ expect: 'reject',
391
+ run: () => {
392
+ const dir = mk();
393
+ _mkRepo(dir, [_row({ id: 'terse', reason: 'because' })]);
394
+ return run({ repoRoot: dir, baseRef: null, quiet: true, write: silent });
395
+ },
396
+ },
397
+ {
398
+ name: 'a leaf named only inside a *.test.ts fixture is not a surface → accept',
399
+ expect: 'accept',
400
+ run: () => {
401
+ const dir = mk();
402
+ // A real leaf as well, so the corpus is non-empty and the case
403
+ // isolates the ONE property under test: the `.test.ts` leaf is
404
+ // not flagged. Without it the gate would refuse an empty scan
405
+ // and the case would pass for the wrong reason.
406
+ _mkRepo(dir, [_row({ id: 'real-leaf.json' })]);
407
+ fs.writeFileSync(
408
+ path.join(dir, 'src', 'scripts', 'thing.ts'),
409
+ `const P = '${_STATE_PREFIX}real-leaf.json';\n`,
410
+ );
411
+ fs.writeFileSync(
412
+ path.join(dir, 'src', 'scripts', 'thing.test.ts'),
413
+ `const P = '${_STATE_PREFIX}fixture-only.json';\n`,
414
+ );
415
+ return run({ repoRoot: dir, baseRef: null, quiet: true, write: silent });
416
+ },
417
+ },
418
+ {
419
+ name: 'a disposed leaf plus a resolving locus, no growth → accept',
420
+ expect: 'accept',
421
+ run: () => {
422
+ const dir = mk();
423
+ _mkRepo(dir, [_row({ id: 'real-leaf.json' })]);
424
+ fs.writeFileSync(
425
+ path.join(dir, 'src', 'scripts', 'thing.ts'),
426
+ `const P = '${_STATE_PREFIX}real-leaf.json';\n`,
427
+ );
428
+ return run({ repoRoot: dir, baseRef: null, quiet: true, write: silent });
429
+ },
430
+ },
431
+ {
432
+ name: 'the shipped inventory describes the shipped tree → accept',
433
+ expect: 'accept',
434
+ run: () =>
435
+ run({
436
+ repoRoot: repoRootFrom(path.dirname(fileURLToPath(import.meta.url))),
437
+ baseRef: null,
438
+ quiet: true,
439
+ write: silent,
440
+ }),
441
+ },
442
+ ];
443
+
444
+ return runSelfTest({ gate: GATE, cases, minCases: 6, minRejectCases: 4 });
445
+ }
446
+
447
+ export function main(argv: readonly string[] = process.argv.slice(2)): number {
448
+ if (argv.includes('--self-test')) return selfTest();
449
+ const baseIdx = argv.indexOf('--base');
450
+ const baseRef = baseIdx >= 0 ? (argv[baseIdx + 1] ?? null) : undefined;
451
+ return run({
452
+ json: argv.includes('--json'),
453
+ quiet: argv.includes('--quiet'),
454
+ ...(baseRef !== undefined ? { baseRef } : {}),
455
+ });
456
+ }
457
+
458
+ declare const __AGENT_CONFIG_BUNDLE__: boolean | undefined;
459
+ function _isCliEntry(): boolean {
460
+ if (typeof __AGENT_CONFIG_BUNDLE__ !== 'undefined' && __AGENT_CONFIG_BUNDLE__) return false;
461
+ if (process.argv[1] === undefined) return false;
462
+ if (import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) return true;
463
+ try {
464
+ return (
465
+ fs.realpathSync(fileURLToPath(import.meta.url)) ===
466
+ fs.realpathSync(path.resolve(process.argv[1]))
467
+ );
468
+ } catch {
469
+ return false;
470
+ }
471
+ }
472
+
473
+ if (_isCliEntry()) {
474
+ process.exitCode = main();
475
+ }
@@ -47,13 +47,20 @@ const REPO_ROOT = path.resolve(fileURLToPath(import.meta.url), '..', '..', '..')
47
47
  * cached or it is not), but it also forfeits patch fixes — so each one is
48
48
  * named here rather than silently tolerated.
49
49
  *
50
- * Empty since the code-graph parser pair (`web-tree-sitter` /
51
- * `tree-sitter-wasms`) left `dependencies` — it was the only entry. The pair's
52
- * ABI pin now lives in `code_graph/loader.ts`'s install hint, because that is
53
- * the only place a re-enabler reads it; this gate scans `dependencies` and so
54
- * no longer sees the pair at all.
50
+ * `web-tree-sitter` returned to `dependencies` under ADR-259 (amended
51
+ * 2026-09-07), so this gate sees it again and it needs its exception back. The
52
+ * grammars it loads are vendored at `src/vendor/grammars/` rather than pulled
53
+ * from `tree-sitter-wasms`, which stays a devDependency and is therefore still
54
+ * outside this gate's scope.
55
55
  */
56
- export const EXACT_PIN_EXCEPTIONS: Readonly<Record<string, string>> = {};
56
+ export const EXACT_PIN_EXCEPTIONS: Readonly<Record<string, string>> = {
57
+ 'web-tree-sitter':
58
+ 'ABI-coupled to the vendored grammar set (grammar ABI 14, ' +
59
+ '`EXPECTED_GRAMMAR_ABI` in code_graph/types.ts). A patch bump can move the ABI, ' +
60
+ 'which would make every grammar load throw rather than degrade — so the runtime ' +
61
+ 'and its grammars move together, in one reviewed change, or not at all. ' +
62
+ 'Refresh procedure: src/vendor/grammars/README.md.',
63
+ };
57
64
 
58
65
  /**
59
66
  * Floors that are non-settled ON PURPOSE, because every version below them is