@event4u/agent-config 17.2.1 → 17.4.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 (225) 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/.claude-plugin/skills/install-agent-config/SKILL.md +9 -9
  5. package/CHANGELOG.md +167 -193
  6. package/CREDITS.md +2 -2
  7. package/README.md +1 -1
  8. package/dist/agent-src/skills/code-intelligence/SKILL.md +16 -12
  9. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  10. package/dist/agent-src/templates/scripts/check_memory.ts +1 -1
  11. package/dist/cli/commands/recordTriggerEval.js +1 -1
  12. package/dist/cli/registry.js +2 -2
  13. package/dist/cli-delegate/{chunk-KR5ZIFPO.js → chunk-5AYJGUA3.js} +1 -3
  14. package/dist/cli-delegate/chunk-DIFZBP4G.js +1336 -0
  15. package/dist/cli-delegate/chunk-E7ACTJTJ.js +6792 -0
  16. package/dist/cli-delegate/{chunk-VYZGJLCA.js → chunk-RKNT4LIK.js} +22 -1286
  17. package/dist/cli-delegate/{chunk-BZJ4Y3CI.js → chunk-WY5ZZPGL.js} +2 -2
  18. package/dist/cli-delegate/{chunk-CMZEKSNN.js → chunk-X6LZ7W5A.js} +73 -10
  19. package/dist/cli-delegate/cmd_conformance.js +190 -192
  20. package/dist/cli-delegate/cmd_doctor.js +5 -5
  21. package/dist/cli-delegate/cmd_doctor_neighbours.js +3 -3
  22. package/dist/cli-delegate/cmd_explain.js +1 -1
  23. package/dist/cli-delegate/cmd_export.js +2 -2
  24. package/dist/cli-delegate/cmd_handoff.js +2 -2
  25. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  26. package/dist/cli-delegate/cmd_prune.js +2 -2
  27. package/dist/cli-delegate/cmd_route_audit.js +1 -1
  28. package/dist/cli-delegate/cmd_session_recycle.js +2 -2
  29. package/dist/cli-delegate/cmd_settings_migrate.js +2 -2
  30. package/dist/cli-delegate/cmd_settings_set.js +8 -4
  31. package/dist/cli-delegate/cmd_sync.js +2 -2
  32. package/dist/cli-delegate/cmd_uninstall.js +2 -2
  33. package/dist/cli-delegate/cmd_update.js +24 -13
  34. package/dist/cli-delegate/cmd_upgrade.js +2 -2
  35. package/dist/cli-delegate/cmd_validate.js +2 -2
  36. package/dist/cli-delegate/dist-25AZAHOP.js +3240 -0
  37. package/dist/cli-delegate/dist-P7MFPMF3.js +411 -0
  38. package/dist/cli-delegate/dist-XAS5ZLQB.js +6 -0
  39. package/dist/cli-delegate/{upgrade_unattended-VVL6JLSX.js → upgrade_unattended-QCWOKTUN.js} +178 -163
  40. package/dist/discovery/deprecation-report.md +1 -1
  41. package/dist/discovery/discovery-manifest.json +3 -3
  42. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  43. package/dist/discovery/discovery-manifest.summary.md +1 -1
  44. package/dist/discovery/dormancy-report.md +1 -1
  45. package/dist/discovery/orphan-report.md +1 -1
  46. package/dist/discovery/packs.json +2 -2
  47. package/dist/discovery/trust-report.md +1 -1
  48. package/dist/discovery/workspaces.json +2 -2
  49. package/dist/hooks/code_graph_refresh.chunk.cjs +443 -0
  50. package/dist/hooks/code_graph_refresh.chunk.cjs.sha256 +1 -0
  51. package/dist/hooks/dispatch.js +1001 -938
  52. package/dist/hooks/dispatch.sha256 +1 -1
  53. package/dist/hooks/egress_engine.chunk.cjs +57 -7
  54. package/dist/hooks/egress_engine.chunk.cjs.sha256 +1 -1
  55. package/dist/hooks/update_notice.chunk.cjs +914 -0
  56. package/dist/hooks/update_notice.chunk.cjs.sha256 +1 -0
  57. package/dist/install/install.mjs +6974 -6037
  58. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -0
  59. package/dist/mcp/registry-manifest.json +3 -2
  60. package/dist/mcp/server.json +13 -4
  61. package/dist/mcp/server.mjs +71202 -63282
  62. package/dist/scripts/_lib/egress_rules.js +8 -2
  63. package/dist/scripts/condense.js +18 -15
  64. package/dist/server/routes/discovery.js +1 -1
  65. package/dist/server/routes/install.js +1 -1
  66. package/dist/server/routes/ping.js +1 -1
  67. package/dist/server/routes/schema.js +4 -4
  68. package/dist/server/routes/settings.js +2 -6
  69. package/dist/server/routes/wizard.js +6 -6
  70. package/dist/server/schemas/settings.js +42 -42
  71. package/dist/shared/settingsSurface.js +1 -1
  72. package/dist/shared/userMd/schema.js +1 -1
  73. package/dist/shared/zodJsonSchema.js +47 -0
  74. package/dist/ui/assets/index-B0bcIgi0.js +77 -0
  75. package/dist/ui/index.html +1 -1
  76. package/package.json +6 -3
  77. package/src/agent-src/templates/scripts/check_memory.ts +1 -1
  78. package/src/config/ci-local-parity.yml +11 -0
  79. package/src/config/continuity-surface.json +9 -2
  80. package/src/config/evaluator-budgets.json +9 -8
  81. package/src/config/gate-violation-baselines.json +3 -3
  82. package/src/config/gitignore-block.txt +6 -5
  83. package/src/config/hook-bundle-budget.json +46 -6
  84. package/src/config/pack-size-budget.json +12 -1
  85. package/src/config/packed-binary-manifest.json +18 -0
  86. package/src/config/sigstore/npm_keys.json +50 -0
  87. package/src/config/sigstore/trust-material.json +9 -0
  88. package/src/config/sigstore/trusted_root.json +126 -0
  89. package/src/config/skill-body-budget.json +7 -1
  90. package/src/scripts/_cli/cmd_settings_set.ts +3 -2
  91. package/src/scripts/_cli/cmd_update.ts +48 -20
  92. package/src/scripts/_cli/cmd_upgrade.ts +7 -1
  93. package/src/scripts/_cli/upgrade_unattended.ts +90 -76
  94. package/src/scripts/_dispatch.bash +4 -3
  95. package/src/scripts/_lib/confusables.ts +0 -19
  96. package/src/scripts/_lib/egress_normalize.ts +53 -23
  97. package/src/scripts/_lib/egress_rules.ts +8 -2
  98. package/src/scripts/_lib/egress_text.ts +5 -3
  99. package/src/scripts/_lib/egress_token.ts +7 -5
  100. package/src/scripts/_lib/gate_collector_experimental.ts +633 -0
  101. package/src/scripts/_lib/git_common_dir.ts +10 -0
  102. package/src/scripts/_lib/graph_feeder_record.ts +3 -2
  103. package/src/scripts/_lib/install_reach_checks.ts +32 -2
  104. package/src/scripts/_lib/lineage_backfill.ts +136 -0
  105. package/src/scripts/_lib/lineage_ledger.ts +211 -0
  106. package/src/scripts/_lib/lineage_map.ts +55 -0
  107. package/src/scripts/_lib/lineage_query.ts +140 -0
  108. package/src/scripts/_lib/lineage_seed.ts +116 -0
  109. package/src/scripts/_lib/lineage_watch.ts +249 -0
  110. package/src/scripts/_lib/link_crypto.ts +8 -4
  111. package/src/scripts/_lib/listing_manifests.ts +85 -0
  112. package/src/scripts/_lib/neighbour_census.ts +1 -0
  113. package/src/scripts/_lib/production_reach.ts +3 -3
  114. package/src/scripts/_lib/project_registry.ts +227 -0
  115. package/src/scripts/_lib/provenance_verify.ts +14 -242
  116. package/src/scripts/_lib/release_settings_surface.ts +2 -6
  117. package/src/scripts/_lib/sigstore_provenance.ts +177 -0
  118. package/src/scripts/_lib/source_id.ts +48 -0
  119. package/src/scripts/_lib/source_shape.ts +4 -0
  120. package/src/scripts/_lib/unattended_gates.ts +6 -1
  121. package/src/scripts/adoption_status.ts +231 -27
  122. package/src/scripts/advisories.ts +26 -10
  123. package/src/scripts/ai_council/council_egress.ts +5 -6
  124. package/src/scripts/bench_graph_feeder_latency.ts +10 -3
  125. package/src/scripts/build_mcp_registry_manifest.ts +23 -12
  126. package/src/scripts/check_dependency_floors.ts +14 -0
  127. package/src/scripts/check_egress_mutations.ts +1 -0
  128. package/src/scripts/check_release_manifest_content.ts +17 -2
  129. package/src/scripts/check_release_pr_shape.ts +5 -0
  130. package/src/scripts/code_graph/build.ts +145 -45
  131. package/src/scripts/code_graph/cli.ts +382 -35
  132. package/src/scripts/code_graph/conventions_default.ts +247 -0
  133. package/src/scripts/code_graph/detect.ts +5 -5
  134. package/src/scripts/code_graph/estate_cli.ts +135 -0
  135. package/src/scripts/code_graph/estate_index.ts +394 -0
  136. package/src/scripts/code_graph/estate_manifests.ts +223 -0
  137. package/src/scripts/code_graph/estate_map.ts +141 -0
  138. package/src/scripts/code_graph/extract.ts +8 -2
  139. package/src/scripts/code_graph/extract_more.ts +241 -2
  140. package/src/scripts/code_graph/graph_budget.ts +158 -0
  141. package/src/scripts/code_graph/graph_home.ts +80 -0
  142. package/src/scripts/code_graph/lineage_cli.ts +315 -0
  143. package/src/scripts/code_graph/loader.ts +10 -2
  144. package/src/scripts/code_graph/map.ts +195 -53
  145. package/src/scripts/code_graph/map_model.ts +113 -20
  146. package/src/scripts/code_graph/map_verify.ts +80 -5
  147. package/src/scripts/code_graph/map_viewer/viewer.css +18 -0
  148. package/src/scripts/code_graph/map_viewer/viewer.js +146 -15
  149. package/src/scripts/code_graph/passes.ts +173 -0
  150. package/src/scripts/code_graph/project_ref.ts +25 -0
  151. package/src/scripts/code_graph/projects_cli.ts +254 -0
  152. package/src/scripts/code_graph/providers/angular.ts +55 -0
  153. package/src/scripts/code_graph/providers/aspnetcore.ts +182 -0
  154. package/src/scripts/code_graph/providers/catalog.ts +299 -0
  155. package/src/scripts/code_graph/providers/django.ts +206 -0
  156. package/src/scripts/code_graph/providers/express.ts +25 -0
  157. package/src/scripts/code_graph/providers/fastapi.ts +49 -0
  158. package/src/scripts/code_graph/providers/flask.ts +99 -0
  159. package/src/scripts/code_graph/providers/go_http.ts +121 -0
  160. package/src/scripts/code_graph/providers/index.ts +103 -0
  161. package/src/scripts/code_graph/{laravel_overlay.ts → providers/laravel.ts} +113 -7
  162. package/src/scripts/code_graph/providers/nestjs.ts +34 -0
  163. package/src/scripts/code_graph/providers/nextjs.ts +91 -0
  164. package/src/scripts/code_graph/providers/nuxt.ts +55 -0
  165. package/src/scripts/code_graph/providers/rails.ts +204 -0
  166. package/src/scripts/code_graph/providers/react-router.ts +58 -0
  167. package/src/scripts/code_graph/providers/shared/detect.ts +78 -0
  168. package/src/scripts/code_graph/providers/shared/extractors.ts +249 -0
  169. package/src/scripts/code_graph/providers/shared/js.ts +252 -0
  170. package/src/scripts/code_graph/providers/shared/kit.ts +210 -0
  171. package/src/scripts/code_graph/providers/shared/php.ts +64 -0
  172. package/src/scripts/code_graph/providers/shared/python.ts +223 -0
  173. package/src/scripts/code_graph/providers/spring.ts +175 -0
  174. package/src/scripts/code_graph/providers/sqlalchemy.ts +62 -0
  175. package/src/scripts/code_graph/providers/sveltekit.ts +59 -0
  176. package/src/scripts/code_graph/providers/symfony.ts +142 -0
  177. package/src/scripts/code_graph/providers/typeorm.ts +58 -0
  178. package/src/scripts/code_graph/providers/types.ts +56 -0
  179. package/src/scripts/code_graph/providers/vue-router.ts +21 -0
  180. package/src/scripts/code_graph/providers/wordpress.ts +128 -0
  181. package/src/scripts/code_graph/query.ts +9 -9
  182. package/src/scripts/code_graph/refresh_cli.ts +81 -0
  183. package/src/scripts/code_graph/refresh_lock.ts +197 -0
  184. package/src/scripts/code_graph/repo_identity.ts +169 -0
  185. package/src/scripts/code_graph/resolution_tiers.ts +19 -7
  186. package/src/scripts/code_graph/scip_reader.ts +2 -2
  187. package/src/scripts/code_graph/sqlite_store.ts +31 -28
  188. package/src/scripts/code_graph/types.ts +79 -41
  189. package/src/scripts/code_graph/validate.ts +6 -8
  190. package/src/scripts/condense.ts +15 -15
  191. package/src/scripts/generate_settings_reference.ts +2 -6
  192. package/src/scripts/hook_chunks.mjs +11 -0
  193. package/src/scripts/hook_manifest.json +1 -1
  194. package/src/scripts/hook_manifest.yaml +43 -23
  195. package/src/scripts/hooks/code_graph_refresh_hook.ts +163 -0
  196. package/src/scripts/hooks/dispatch_hook.ts +6 -7
  197. package/src/scripts/hooks/host_semantics.ts +72 -0
  198. package/src/scripts/hooks/lazy_concern.ts +8 -0
  199. package/src/scripts/hooks/user_notice.ts +105 -0
  200. package/src/scripts/install-hooks.sh +54 -33
  201. package/src/scripts/install.ts +2 -6
  202. package/src/scripts/lint_harvest_provenance.ts +137 -11
  203. package/src/scripts/lint_hook_manifest.ts +2 -0
  204. package/src/scripts/lint_marketplace.ts +33 -0
  205. package/src/scripts/lint_mcp_registry_manifest.ts +36 -0
  206. package/src/scripts/mcp_server/consumer_tool_catalog.json +70 -15
  207. package/src/scripts/mcp_server/graph_tools.ts +165 -41
  208. package/src/scripts/network_sources.ts +24 -6
  209. package/src/scripts/release.ts +2 -5
  210. package/src/scripts/release_drill.ts +4 -1
  211. package/src/scripts/release_env.ts +17 -0
  212. package/src/scripts/release_mix_taxonomy.json +3 -0
  213. package/src/scripts/schemas/provenance-mechanism.schema.json +46 -0
  214. package/src/scripts/update_notice_hook.ts +75 -7
  215. package/src/server/schemas/settings.ts +42 -42
  216. package/src/shared/settingsSurface.ts +1 -1
  217. package/src/shared/userMd/schema.ts +1 -1
  218. package/src/shared/zodJsonSchema.ts +41 -0
  219. package/src/vendor/grammars/README.md +8 -6
  220. package/src/vendor/grammars/tree-sitter-c_sharp.wasm +0 -0
  221. package/src/vendor/grammars/tree-sitter-ruby.wasm +0 -0
  222. package/dist/cli-delegate/chunk-XIAPY44N.js +0 -4587
  223. package/dist/ui/assets/index-w70Ado09.js +0 -23
  224. /package/dist/cli-delegate/{chunk-FKYZOWVD.js → chunk-QBAFP67O.js} +0 -0
  225. /package/dist/cli-delegate/{chunk-BMGUGSY6.js → chunk-TQG6UMPC.js} +0 -0
@@ -4,7 +4,7 @@
4
4
  "registered_at": "2026-10-01",
5
5
  "owner": "maintainer",
6
6
  "review_by": "2027-10-01",
7
- "max_bytes": 1550500,
7
+ "max_bytes": 1554000,
8
8
  "max_bytes_derivation": "Measured 1,514,715 bytes on origin/main at 213d87055 (the gate's own reading, APFS-cloned node_modules so no worktree path artefacts). The ceiling is that reading plus ~2.3 % of headroom, rounded to 1,550,000, on the same doctrine as the 2026-10-01 registration: a bundle is rebuilt from source on every run, so an esbuild minor that renames symbols moves the figure by hundreds of bytes with no change to this tree, and a ceiling one byte above the reading would red on that. Composition is healthy at this reading and was checked rather than assumed: one YAML package (258,833 bytes) and 1,238,525 bytes of own source, so the growth is own code, not a re-entered dependency. The 1,564,211-byte pre-swap regression this roadmap closed still cannot reappear under it. RAISED to 1,550,500 on 2026-10-23 for the InstructionsLoaded binding (237 bytes against 51 of headroom); the reasoning and the measured alternative are the last `raise_log` entry, so this paragraph describes the 1,550,000 registration and the raise is recorded there rather than restated.",
9
9
  "shrink_only": true,
10
10
  "shrink_only_note": "A RAISE needs a recorded reason in `raise_log` below naming what was added and why it could not be avoided. Enforced since road-to-a-ratification-fence-that-follows-its-imports 3.2: the gate reads `max_bytes` at the base revision, and a working value above it fails unless `raise_log` gained an entry whose `to` equals the new value. A lowering needs no entry. This file is also on the ratification gate's watched set, so a raise carries a record as well as a log entry.",
@@ -14,8 +14,8 @@
14
14
  "from": 1500000,
15
15
  "to": 1550000,
16
16
  "by": "agent, during the inbox-2026-10 drain",
17
- "what_was_added": "Nothing in this commit. The 1,500,000 ceiling was red on the very commit that registered it: measured 1,511,489 bytes at 22b19e520, which is the merge of the PR that introduced the budget. Its derivation read 1,469,738 bytes on the PR branch, whose base predated three PRs that had merged meanwhile \u2014 the failure-event binding of #2160 (sixteen concerns on a new slot), the touched-file quality pass of #2152, and the evidence classification of #2153 \u2014 and #2162 landed after it. The gate ran on each PR's pre-merge tree and never on the merge result, so every one of those PRs was green alone and the trunk was red the moment they were together.",
18
- "why_it_could_not_be_avoided": "The bytes are deliberately merged capability, not an accident to trim: the composition check above shows one parser and no duplicate dependency, so there is nothing to remove that would not remove a feature. The alternative \u2014 reverting a merged lane to fit a ceiling derived against a base that no longer exists \u2014 would discard working code to satisfy a number that never described this tree.",
17
+ "what_was_added": "Nothing in this commit. The 1,500,000 ceiling was red on the very commit that registered it: measured 1,511,489 bytes at 22b19e520, which is the merge of the PR that introduced the budget. Its derivation read 1,469,738 bytes on the PR branch, whose base predated three PRs that had merged meanwhile — the failure-event binding of #2160 (sixteen concerns on a new slot), the touched-file quality pass of #2152, and the evidence classification of #2153 — and #2162 landed after it. The gate ran on each PR's pre-merge tree and never on the merge result, so every one of those PRs was green alone and the trunk was red the moment they were together.",
18
+ "why_it_could_not_be_avoided": "The bytes are deliberately merged capability, not an accident to trim: the composition check above shows one parser and no duplicate dependency, so there is nothing to remove that would not remove a feature. The alternative — reverting a merged lane to fit a ceiling derived against a base that no longer exists — would discard working code to satisfy a number that never described this tree.",
19
19
  "what_would_have_caught_it": "Measuring the ceiling against the merge result rather than the PR branch. A ceiling derived on a branch is a statement about that branch; the trunk is what the gate defends, and the two diverge exactly when several lanes land in one day."
20
20
  },
21
21
  {
@@ -36,6 +36,34 @@
36
36
  "what_was_added": "The `InstructionsLoaded` binding: one `LAZY_CONCERNS` row for the observer (its 11,097-byte body ships in its own chunk, never in this bundle) and the event name in the three vocabularies the bundle carries (dispatcher, collector, journal). Measured 1,550,186 bytes with the binding by the gate; the same esbuild invocation on the base and on this branch differs by 237 bytes, so the base sat at 1,549,949 — 51 bytes of headroom.",
37
37
  "why_it_could_not_be_avoided": "D8 (council, 2026-10-18) asked for room before a raise. Room was tried and measured: moving `session-eol` (27,708 B in-bundle, `stop` alone) into a chunk freed 29,948 B (same esbuild invocation, with and without the move) but produced a 259,330-byte chunk (`yaml` external) required on every `stop` — about 8.5 times the bytes that event parses today, to buy 186. The observer itself was already moved out. What remains in the bundle is the row and three event-name strings, which no chunk can carry.",
38
38
  "what_would_have_caught_it": "Nothing earlier: the base sat 51 bytes under the ceiling, so any new event in the vocabulary would have tripped it. Sized to this binding plus about 300 bytes; step 3.3's promotion is sized when it is built."
39
+ },
40
+ {
41
+ "date": "2026-10-24",
42
+ "from": 1550500,
43
+ "to": 1551000,
44
+ "by": "agent, feat/code-graph-auto-refresh (PR #2604) merged onto docs/inbox-2026-10-ac-roadmap (PR #2603) on the owner's instruction to target #2603",
45
+ "what_was_added": "One `LAZY_CONCERNS` row for the `code-graph-refresh` session concern (its 12,726-byte body ships in its own chunk). Each branch fit alone: #2603 measured 1,550,498 B, #2604 added 153 B to a base that sat 356 B under. Merged, the gate measured 1,550,617 B — 117 over. With the `provider_id` type check restored in validate.ts (the one #2603 had dropped for its last 2 bytes, asked for by both ratification seats of round 12) the final combined measurement is 1,550,751 B, 249 under the new ceiling.",
46
+ "why_it_could_not_be_avoided": "Room was tried and measured, as D8 asks: moving `handoff-context` (10,433 B in-bundle, `session_start` alone) into a chunk would free about 10 KB but produces a 581,613-byte chunk inlined, 319,233 bytes with `yaml` external — required on every `session_start` to buy 117 bytes, the same trade the 2026-10-23 entry refused for `session-eol`. Shortening the row's strings saves under 20 bytes. What remains is the row, which no chunk can carry. Sized to the merged measurement plus about 380 bytes.",
47
+ "what_would_have_caught_it": "Measuring the two branches together before the merge: two lanes that each fit a ceiling with a few hundred bytes to spare do not fit it together, and #2603 had already spent its last 2 bytes by dropping a provider_id type check in validate.ts."
48
+ },
49
+ {
50
+ "date": "2026-10-24",
51
+ "from": 1551000,
52
+ "to": 1554000,
53
+ "by": "agent, drain/update-installs-itself-20261024 (road-to-an-update-that-installs-itself-only-when-it-is-safe 3.1)",
54
+ "what_was_added": "A user-addressed channel in the dispatcher: a `notification` concern may reply `user_notice`, and on claude the dispatcher emits it as `systemMessage`, the field the host documents as shown to the user and not added to model context (hooks/user_notice.ts: collectUserNotice; host_semantics: withUserNotice, which merges context, the native emission and the notice as structures and falls back to the old output whenever a field it would extend has the wrong type, and writeStdout, which writes the output and only then a small user-global receipt naming the session and the notice id for each notice actually in the output, so a concern counts a notice as shown only on that receipt). Plus one LAZY_CONCERNS row for `update-notice`, whose body ships in its own chunk. Measured with one esbuild invocation over origin/main and over this branch after merging it: +2,945 bytes of own source (host_semantics +1,582, user_notice +1,095, dispatch_hook +116, lazy_concern +152; identifier renames elsewhere net 0), so 1,553,708 B against 1,551,000, the base reading 1,550,763. The logic sits in the two helper modules rather than in dispatch_hook.ts because that file is at the 1,500-line source cap. The first measurement, +1,391 B, predated the structural merge, the type guards and the delivery receipt that council rounds asked for.",
55
+ "why_it_could_not_be_avoided": "The channel is what step 3.1 was reopened for: every host runs the dispatcher on pipes, so a notice on stderr reached nobody, and a council round refused the registration for exactly that. The bytes are dispatcher code on the emission path of every event, so a chunk cannot carry them; the concern body is already in one. Room was not re-tried: the 2026-10-23 and 2026-10-24 entries measured the two narrow-event chunk candidates (`session-eol`, `handoff-context`) as buying a few hundred bytes for a quarter-megabyte require on every event, and nothing in this tree has changed that trade. Own code was compacted first (1,545 -> 1,391 B).",
56
+ "what_would_have_caught_it": "Nothing earlier: the base sat about 240 bytes under the ceiling. Sized to this change plus 292 bytes."
57
+ },
58
+ {
59
+ "date": "2026-10-24",
60
+ "chunk": "src/scripts/_lib/egress_engine.ts",
61
+ "from": 32000,
62
+ "to": 33000,
63
+ "by": "agent, drain/one-detector-20261024 (road-to-one-detector-and-the-senders-we-own 2.5)",
64
+ "what_was_added": "The invisible-character normalisation of one-detector 2.5 wired into the engine: `replaceValues` and `tallyText` now detect through `egress_normalize.ts` (`detectWithExtent`), and a rule's extent reader (`through`) runs on the normalised text with its end mapped back, so a key block whose BEGIN and END markers both carry a zero-width character is removed whole instead of refused or left behind. Measured 30,511 bytes on origin/main, 31,907 with the wiring alone, 32,305 with the extent fix.",
65
+ "why_it_could_not_be_avoided": "The 2026-10-18 derivation queued this rescan inside the 32,000 ceiling and the 2026-10-22 raise recorded it as not yet in the chunk. Room was taken first: `LATIN_TWIN` moved out of confusables.ts as a hex-encoded string pair so the chunk no longer carries that module's four script regexes, and the normaliser keeps one origin array instead of two (32,670 down to 31,907). The extent fix that a council seat found in round 1 of the ratification review adds about 400 bytes of mapping code no smaller form carries. The chunk loads only when a caller needs detection; the dispatch bundle is unchanged.",
66
+ "what_would_have_caught_it": "Measuring the wired engine when 2.5 was first built rather than the unwired module, and a disguised-marker key block in the extent tests from the start."
39
67
  }
40
68
  ],
41
69
  "chunks": [
@@ -47,7 +75,7 @@
47
75
  },
48
76
  {
49
77
  "entry": "src/scripts/_lib/egress_engine.ts",
50
- "max_bytes": 32000,
78
+ "max_bytes": 33000,
51
79
  "registered_at": "2026-10-18",
52
80
  "derivation": "Measured 18,478 bytes on 2026-10-18 (the rule table, the token grammar and the commit scanner, with the per-rule linearity prose moved to a test-only module). The ceiling is that reading plus the queued engine work of road-to-one-detector-and-the-senders-we-own (validated identifier rules about 4.3 KB, known values, the invisible-character rescan and the variant suffix about 1-2 KB each), rounded up. An AI council of two providers chose on 2026-10-18 to move the engine out of the dispatch bundle into this conditional chunk rather than raise the dispatch ceiling, and asked that the chunk carry a measured budget of its own so the move does not just relocate uncontrolled growth. A raise follows the same rule as max_bytes: a raise_log entry naming the chunk (`chunk`: this entry) and what was added."
53
81
  },
@@ -55,17 +83,29 @@
55
83
  "entry": "src/scripts/chat_history.ts",
56
84
  "max_bytes": 232000,
57
85
  "registered_at": "2026-10-20",
58
- "derivation": "Measured 209,890 bytes on 2026-10-20, with `yaml` external (inlined it is 472,201 \u2014 a second copy of the parser the dispatch bundle already carries). The ceiling is that reading plus about 10 %, rounded, because this chunk carries a 2,300-line concern plus the memory lookup and FTS index it reads, all of which still grow.\n\nWHY IT WAS MOVED \u2014 AND THE REASON FIRST GIVEN WAS FALSE, which is recorded here rather than corrected silently. This entry said `chat-history` is bound on `session_start` and on no other event, and called it the largest narrow-event module the metafile ranks. An independent provider review of 2026-10-20 checked the manifest and refused the change on it: `chat-history` is bound on FIVE events \u2014 `session_start`, `session_end`, `stop`, `post_tool_use` and `user_prompt_submit` \u2014 across seven hosts. It is close to the widest-bound concern in the tree, not the narrowest. The claim came from reading the `session_start:` rows of the manifest and never the others.\n\nWHAT SURVIVES THE CORRECTION, stated as narrowly as the evidence allows: the move takes 120,586 bytes out of a bundle every hook event parses (1,549,961 -> 1,429,414 B) and pays for them with one `require` of a 209,890-byte CJS file on the events that actually need the concern. Whether that is a latency WIN is UNMEASURED, and the 2026-10-18 council that chose this mechanism asked for exactly that proof inside `src/config/hook-latency-budget.json`. Until it exists this chunk is a byte-budget move with an unproven wall-clock effect, and the honest narrow-event candidates the same metafile ranks are recorded for whoever re-does it: `turn-end-gate` 71,928 B on `stop` alone, `injection-scan` 46,660 B on `post_tool_use` alone, `skill-route` 31,183 B and `git-authorization` 30,761 B on `user_prompt_submit` alone, `session-eol` 27,708 B on `stop` alone, `handoff-context` 25,220 B on `session_start` alone.\n\nUNLIKE THE OTHER TWO CHUNKS this one carries a CONCERN, so there is a correct path behind the fast one: `_run_concern` tries the static registry, then `loadLazyConcern`, then the historical spawn-per-concern path. A missing or mis-digested chunk costs latency, never the concern's effect \u2014 which the same review confirmed, noting it holds because `src/scripts/` ships in the package."
86
+ "derivation": "Measured 209,890 bytes on 2026-10-20, with `yaml` external (inlined it is 472,201 — a second copy of the parser the dispatch bundle already carries). The ceiling is that reading plus about 10 %, rounded, because this chunk carries a 2,300-line concern plus the memory lookup and FTS index it reads, all of which still grow.\n\nWHY IT WAS MOVED — AND THE REASON FIRST GIVEN WAS FALSE, which is recorded here rather than corrected silently. This entry said `chat-history` is bound on `session_start` and on no other event, and called it the largest narrow-event module the metafile ranks. An independent provider review of 2026-10-20 checked the manifest and refused the change on it: `chat-history` is bound on FIVE events — `session_start`, `session_end`, `stop`, `post_tool_use` and `user_prompt_submit` — across seven hosts. It is close to the widest-bound concern in the tree, not the narrowest. The claim came from reading the `session_start:` rows of the manifest and never the others.\n\nWHAT SURVIVES THE CORRECTION, stated as narrowly as the evidence allows: the move takes 120,586 bytes out of a bundle every hook event parses (1,549,961 -> 1,429,414 B) and pays for them with one `require` of a 209,890-byte CJS file on the events that actually need the concern. Whether that is a latency WIN is UNMEASURED, and the 2026-10-18 council that chose this mechanism asked for exactly that proof inside `src/config/hook-latency-budget.json`. Until it exists this chunk is a byte-budget move with an unproven wall-clock effect, and the honest narrow-event candidates the same metafile ranks are recorded for whoever re-does it: `turn-end-gate` 71,928 B on `stop` alone, `injection-scan` 46,660 B on `post_tool_use` alone, `skill-route` 31,183 B and `git-authorization` 30,761 B on `user_prompt_submit` alone, `session-eol` 27,708 B on `stop` alone, `handoff-context` 25,220 B on `session_start` alone.\n\nUNLIKE THE OTHER TWO CHUNKS this one carries a CONCERN, so there is a correct path behind the fast one: `_run_concern` tries the static registry, then `loadLazyConcern`, then the historical spawn-per-concern path. A missing or mis-digested chunk costs latency, never the concern's effect — which the same review confirmed, noting it holds because `src/scripts/` ships in the package."
59
87
  },
60
88
  {
61
89
  "entry": "src/scripts/hooks/instructions_observer_hook.ts",
62
90
  "max_bytes": 12000,
63
91
  "registered_at": "2026-10-23",
64
92
  "derivation": "Measured 11,097 bytes on 2026-10-23 (the observe-only `InstructionsLoaded` capture, its classifier, and the CLI entry the spawn fallback needs). The ceiling is that reading plus about 10 %, rounded, with no growth queued. Bound on `instructions_loaded` alone, so a chunk keeps it off every other dispatch's parse; the observer body ships here, never in the dispatch bundle. The binding that reaches it (one registry row and the event name in three vocabularies, 237 bytes) does sit in the bundle and is the 2026-10-23 raise of `max_bytes` recorded in `raise_log`. Like `chat_history` it carries a concern, so a missing chunk falls back to the spawn path and costs latency, never the capture."
93
+ },
94
+ {
95
+ "entry": "src/scripts/hooks/code_graph_refresh_hook.ts",
96
+ "max_bytes": 15400,
97
+ "registered_at": "2026-10-23",
98
+ "derivation": "Measured 14,284 bytes on 2026-10-24 (the session-start code-graph refresh concern with its opt-in, tracked-file and PATH-trust checks, the CLI capability probe and outcome record of the PR #2604 review follow-up, the refresh-lock staleness check it shares with `code-graph refresh --single-flight`, and the hardened spawn environment). The ceiling is that reading plus about 8 %, rounded, with no growth queued; it was registered at 14,000 against 12,726 B and re-derived in the same PR, before any release carried it. Bound on `session_start` alone; a chunk keeps it off every other dispatch's parse, and the dispatch bundle carries only its `LAZY_CONCERNS` row. Like `chat_history` it carries a concern, so a missing chunk falls back to the spawn path and costs latency, never the refresh."
99
+ },
100
+ {
101
+ "entry": "src/scripts/update_notice_hook.ts",
102
+ "max_bytes": 35500,
103
+ "registered_at": "2026-10-24",
104
+ "derivation": "Measured 32,812 bytes on 2026-10-24 (the concern, its decision library and the delivery-receipt reader) with `yaml` external (the concern reads one user-global settings file with it; inlined it would be a second copy of the parser the dispatch bundle already carries). The ceiling is that reading plus about 10 %, rounded, with no growth queued. Bound on claude `session_start` alone, so a chunk keeps its body off every other dispatch parse; the bundle carries only its LAZY_CONCERNS row. Like `chat_history` it carries a concern, so a missing chunk falls back to the spawn path and costs latency, never the notice."
65
105
  }
66
106
  ],
67
107
  "chunks_note": "A chunk is loaded only when a caller needs it, so its bytes are not paid by every dispatch; its ceiling exists so that the move out of dispatch.js stays a measured place rather than an unmeasured one. The gate builds each chunk with the exact esbuild segment `build:hook-chunks` uses for its entry.",
68
108
  "max_yaml_packages": 1,
69
- "max_yaml_packages_note": "The dispatch path reads YAML for the hook manifest, the host-lowering table and the settings contract. One reader covers all three. Two cost 95,846 bytes for a single call site and were invisible until an external rescore counted them \u2014 which is why this is a cap rather than prose. The package set the cap counts over is YAML_PACKAGES in the gate.",
109
+ "max_yaml_packages_note": "The dispatch path reads YAML for the hook manifest, the host-lowering table and the settings contract. One reader covers all three. Two cost 95,846 bytes for a single call site and were invisible until an external rescore counted them — which is why this is a cap rather than prose. The package set the cap counts over is YAML_PACKAGES in the gate.",
70
110
  "what_this_does_not_bound": "Latency. A smaller bundle is not a measured speed-up; src/config/hook-latency-budget.json owns the wall-clock axis and is not derived from this file. Nor does it bound dist/install/install.mjs or dist/mcp/server.mjs, which carry their own module graphs."
71
111
  }
@@ -123,5 +123,16 @@
123
123
  "measured_at": "2026-10-17",
124
124
  "measured_on": "One machine, one clean checkout of origin/main at 8c90aad26, plus the earlier readings taken in a separate worktree of the same content. Node and npm as resolved by the repo's engines field (node >=20.11.0). From this change onward the required Consistency job also produces a CI reading of the built surface, which the 2026-09-10 record said was impossible."
125
125
  },
126
- "built_surface_enforcement_2026_08_30": "How the two surfaces this file records are now ENFORCED, which until 2026-08-30 they were not. `check_pack_size` compared every payload against `budgets.packed_size_mb.max`, and that cap was measured on the UNBUILT tree — this file has said so since 2026-08-24 in `measurement_conditions` and in `built_surface_measurement_2026_08_24`, and the gate did not read it. Measured on the day this note was written: main packed 8.985 MB over 2715 entries with `--ignore-scripts` and passed; a branch adding six source files packed 9.922 over 2827 and failed `max: 9.1`. The 112-entry difference is `dist/cli` plus `dist/cli-delegate` — the build, not the diff. The gate now reads the payload it is judging (`payloadIsBuilt`, keyed on `dist/cli/**`, already used by the content classes for the same reason) and routes: an UNBUILT payload against `max` and the `last_measured` creep line, unchanged; a BUILT payload against `built_surface_measurement_*.built.packed_mb` with the same `regression_pct`. A built payload with no recorded built figure is a FINDING, not a pass — otherwise removing the record would silently disable the built path. What this does NOT do: it does not raise `max`, and it does not gate the built surface against an absolute cap. The built surface gets a regression line only, because no absolute figure for it was ever set by a maintainer and inventing one here would be exactly the invented number the `_comment` warns about. Revisit-if: a maintainer sets an absolute built cap, or the built figure is re-measured (add a new `built_surface_measurement_<date>` key — the newest is read, so no code changes)."
126
+ "built_surface_enforcement_2026_08_30": "How the two surfaces this file records are now ENFORCED, which until 2026-08-30 they were not. `check_pack_size` compared every payload against `budgets.packed_size_mb.max`, and that cap was measured on the UNBUILT tree — this file has said so since 2026-08-24 in `measurement_conditions` and in `built_surface_measurement_2026_08_24`, and the gate did not read it. Measured on the day this note was written: main packed 8.985 MB over 2715 entries with `--ignore-scripts` and passed; a branch adding six source files packed 9.922 over 2827 and failed `max: 9.1`. The 112-entry difference is `dist/cli` plus `dist/cli-delegate` — the build, not the diff. The gate now reads the payload it is judging (`payloadIsBuilt`, keyed on `dist/cli/**`, already used by the content classes for the same reason) and routes: an UNBUILT payload against `max` and the `last_measured` creep line, unchanged; a BUILT payload against `built_surface_measurement_*.built.packed_mb` with the same `regression_pct`. A built payload with no recorded built figure is a FINDING, not a pass — otherwise removing the record would silently disable the built path. What this does NOT do: it does not raise `max`, and it does not gate the built surface against an absolute cap. The built surface gets a regression line only, because no absolute figure for it was ever set by a maintainer and inventing one here would be exactly the invented number the `_comment` warns about. Revisit-if: a maintainer sets an absolute built cap, or the built figure is re-measured (add a new `built_surface_measurement_<date>` key — the newest is read, so no code changes).",
127
+ "built_surface_measurement_2026_10_23": {
128
+ "purpose": "Re-measure of the BUILT surface for PR #2603 (road-to-graph-providers-for-every-stack). It vendors one itemised addition: the C# tree-sitter grammar (src/vendor/grammars/tree-sitter-c_sharp.wasm, 3,978,594 B uncompressed, about 0.25 MB packed), which brings C# extraction and the ASP.NET Core provider. CI measured the built tarball at 16.036 MB against the 15.949 line derived from built_surface_measurement_2026_10_17. AI council 2026-10-23, round 2, two seats convergent: record a dated built measurement for the C# grammar and carry Ruby + Rails to road-to-graph-providers-for-every-stack-carried. The re-anchor is OWNER-RESERVED under the 2026-10-17 precedent (the agent proposing a reset is the one it unblocks); the owner chose it on 2026-10-24.",
129
+ "built": {
130
+ "packed_mb": 16.036,
131
+ "command": "CI: Sync + Generate Tools Consistency job, check_pack_size on the BUILT surface (the same callers built_surface_measurement_2026_10_17 aligned)",
132
+ "note": "The derived ceiling becomes 17.640 at regression_pct 10. Local pristine builds read about 0.1 MB lower (base 15.683, with the C# grammar 15.937); the CI figure is recorded because CI is the caller that gates."
133
+ },
134
+ "policy_clarification": "REQUIRED BY BOTH SEATS. This re-anchor admits the itemised C# grammar only. It does NOT authorise the roughly 1.6 MB of headroom the 10 % rule now derives for unrelated growth: the next built re-anchor must itemise every payload addition since this record, and a grammar (Ruby, blocker built-pack-budget-for-grammars in the carried roadmap) is decided on its own. Revisit-if: an addition lands under this line without being itemised here or in a later record, or a maintainer sets an absolute built cap.",
135
+ "measured_at": "2026-10-23",
136
+ "measured_on": "GitHub Actions, PR #2603 head 2c06e7881, required job Sync + Generate Tools Consistency."
137
+ }
127
138
  }
@@ -55,6 +55,24 @@
55
55
  "grammar_id": "java",
56
56
  "abi": 14,
57
57
  "why": "The Java grammar (road-to-a-map-that-draws-itself 6.1). Same reason as the php entry: the engine indexes .java files in a consumer install with no manual parser step."
58
+ },
59
+ {
60
+ "path": "src/vendor/grammars/tree-sitter-c_sharp.wasm",
61
+ "sha256": "6266a7e32d68a3459104d994dc848df15d5672b0ea8e86d327274b694f8e6991",
62
+ "size": 3978594,
63
+ "kind": "tree-sitter-wasm-grammar",
64
+ "grammar_id": "c_sharp",
65
+ "abi": 13,
66
+ "why": "The C# grammar (road-to-graph-providers-for-every-stack 5.2). Same reason as the php entry: the engine indexes .cs files in a consumer install with no manual parser step. ABI 13, not 14: tree-sitter-wasms@0.1.13 compiles this one grammar at ABI 13, which the pinned web-tree-sitter loads, so the loader pins it per language."
67
+ },
68
+ {
69
+ "path": "src/vendor/grammars/tree-sitter-ruby.wasm",
70
+ "sha256": "93a5022855314cdb45458c7bb026a24a0ebc3a5ff6439e542e881f14dfa13a39",
71
+ "size": 2106447,
72
+ "kind": "tree-sitter-wasm-grammar",
73
+ "grammar_id": "ruby",
74
+ "abi": 14,
75
+ "why": "The Ruby grammar (road-to-graph-providers-for-every-stack-carried 1.1). Same reason as the php entry: the engine indexes .rb files in a consumer install with no manual parser step."
58
76
  }
59
77
  ]
60
78
  }
@@ -0,0 +1,50 @@
1
+ {
2
+ "keys": [
3
+ {
4
+ "keyId": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
5
+ "keyUsage": "npm:signatures",
6
+ "publicKey": {
7
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==",
8
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
9
+ "validFor": {
10
+ "start": "1999-01-01T00:00:00.000Z",
11
+ "end": "2025-01-29T00:00:00.000Z"
12
+ }
13
+ }
14
+ },
15
+ {
16
+ "keyId": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
17
+ "keyUsage": "npm:attestations",
18
+ "publicKey": {
19
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1Olb3zMAFFxXKHiIkQO5cJ3Yhl5i6UPp+IhuteBJbuHcA5UogKo0EWtlWwW6KSaKoTNEYL7JlCQiVnkhBktUgg==",
20
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
21
+ "validFor": {
22
+ "start": "2022-12-01T00:00:00.000Z",
23
+ "end": "2025-01-29T00:00:00.000Z"
24
+ }
25
+ }
26
+ },
27
+ {
28
+ "keyId": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U",
29
+ "keyUsage": "npm:signatures",
30
+ "publicKey": {
31
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY6Ya7W++7aUPzvMTrezH6Ycx3c+HOKYCcNGybJZSCJq/fd7Qa8uuAKtdIkUQtQiEKERhAmE5lMMJhP8OkDOa2g==",
32
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
33
+ "validFor": {
34
+ "start": "2025-01-13T00:00:00.000Z"
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "keyId": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U",
40
+ "keyUsage": "npm:attestations",
41
+ "publicKey": {
42
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY6Ya7W++7aUPzvMTrezH6Ycx3c+HOKYCcNGybJZSCJq/fd7Qa8uuAKtdIkUQtQiEKERhAmE5lMMJhP8OkDOa2g==",
43
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
44
+ "validFor": {
45
+ "start": "2025-01-13T00:00:00.000Z"
46
+ }
47
+ }
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "_comment": "Trust material the unattended upgrade verifies release provenance against (road-to-an-update-that-installs-itself-only-when-it-is-safe D15). Pinned, never refreshed at run time: a candidate release can never choose the roots it is checked against. Read by src/scripts/_lib/sigstore_provenance.ts, which refuses when a file's sha256 differs from the one recorded here. Refresh by re-extracting both targets from a newer @sigstore/tuf seeds.json and updating source and digests together; until a release carries new material, an unattended run refuses anything signed under a rotated root and `agent-config upgrade` by hand still works.",
3
+ "source": "@sigstore/tuf@5.0.0 seeds.json, mirror https://tuf-repo-cdn.sigstore.dev, extracted 2026-10-24",
4
+ "files": {
5
+ "trusted_root.json": "6494e21ea73fa7ee769f85f57d5a3e6a08725eae1e38c755fc3517c9e6bc0b66",
6
+ "npm_keys.json": "160677eb6e1c7083c89b166b20f8fe4e837fb71181506aff1991b80b89184f7d"
7
+ },
8
+ "npm_keys_live_check": "Equal on 2026-10-24 to https://registry.npmjs.org/-/npm/v1/keys: SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA (expired 2025-01-29) and SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U (no expiry)."
9
+ }
@@ -0,0 +1,126 @@
1
+ {
2
+ "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1",
3
+ "tlogs": [
4
+ {
5
+ "baseUrl": "https://rekor.sigstore.dev",
6
+ "hashAlgorithm": "SHA2_256",
7
+ "publicKey": {
8
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==",
9
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
10
+ "validFor": {
11
+ "start": "2021-01-12T11:53:27Z"
12
+ }
13
+ },
14
+ "logId": {
15
+ "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
16
+ }
17
+ },
18
+ {
19
+ "baseUrl": "https://log2025-1.rekor.sigstore.dev",
20
+ "hashAlgorithm": "SHA2_256",
21
+ "publicKey": {
22
+ "rawBytes": "MCowBQYDK2VwAyEAt8rlp1knGwjfbcXAYPYAkn0XiLz1x8O4t0YkEhie244=",
23
+ "keyDetails": "PKIX_ED25519",
24
+ "validFor": {
25
+ "start": "2025-09-23T00:00:00Z"
26
+ }
27
+ },
28
+ "logId": {
29
+ "keyId": "zxGZFVvd0FEmjR8WrFwMdcAJ9vtaY/QXf44Y1wUeP6A="
30
+ }
31
+ }
32
+ ],
33
+ "certificateAuthorities": [
34
+ {
35
+ "subject": {
36
+ "organization": "sigstore.dev",
37
+ "commonName": "sigstore"
38
+ },
39
+ "uri": "https://fulcio.sigstore.dev",
40
+ "certChain": {
41
+ "certificates": [
42
+ {
43
+ "rawBytes": "MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAqMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIxMDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSyA7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0JcastaRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2uSu1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJxVe/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uupHr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ=="
44
+ }
45
+ ]
46
+ },
47
+ "validFor": {
48
+ "start": "2021-03-07T03:20:29Z",
49
+ "end": "2022-12-31T23:59:59.999Z"
50
+ }
51
+ },
52
+ {
53
+ "subject": {
54
+ "organization": "sigstore.dev",
55
+ "commonName": "sigstore"
56
+ },
57
+ "uri": "https://fulcio.sigstore.dev",
58
+ "certChain": {
59
+ "certificates": [
60
+ {
61
+ "rawBytes": "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow="
62
+ },
63
+ {
64
+ "rawBytes": "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ"
65
+ }
66
+ ]
67
+ },
68
+ "validFor": {
69
+ "start": "2022-04-13T20:06:15Z"
70
+ }
71
+ }
72
+ ],
73
+ "ctlogs": [
74
+ {
75
+ "baseUrl": "https://ctfe.sigstore.dev/test",
76
+ "hashAlgorithm": "SHA2_256",
77
+ "publicKey": {
78
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==",
79
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
80
+ "validFor": {
81
+ "start": "2021-03-14T00:00:00Z",
82
+ "end": "2022-10-31T23:59:59.999Z"
83
+ }
84
+ },
85
+ "logId": {
86
+ "keyId": "CGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3I="
87
+ }
88
+ },
89
+ {
90
+ "baseUrl": "https://ctfe.sigstore.dev/2022",
91
+ "hashAlgorithm": "SHA2_256",
92
+ "publicKey": {
93
+ "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw==",
94
+ "keyDetails": "PKIX_ECDSA_P256_SHA_256",
95
+ "validFor": {
96
+ "start": "2022-10-20T00:00:00Z"
97
+ }
98
+ },
99
+ "logId": {
100
+ "keyId": "3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4="
101
+ }
102
+ }
103
+ ],
104
+ "timestampAuthorities": [
105
+ {
106
+ "subject": {
107
+ "organization": "sigstore.dev",
108
+ "commonName": "sigstore-tsa-selfsigned"
109
+ },
110
+ "uri": "https://timestamp.sigstore.dev/api/v1/timestamp",
111
+ "certChain": {
112
+ "certificates": [
113
+ {
114
+ "rawBytes": "MIICEDCCAZagAwIBAgIUOhNULwyQYe68wUMvy4qOiyojiwwwCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTA0MDgwNjU5NDNaFw0zNTA0MDYwNjU5NDNaMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4ra2Z8hKNig2T9kFjCAToGG30jky+WQv3BzL+mKvh1SKNR/UwuwsfNCg4sryoYAd8E6isovVA3M4aoNdm9QDi50Z8nTEyvqgfDPtTIwXItfiW/AFf1V7uwkbkAoj0xxco2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFIn9eUOHz9BlRsMCRscsc1t9tOsDMB8GA1UdIwQYMBaAFJjsAe9/u1H/1JUeb4qImFMHic6/MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMDA2gAMGUCMDtpsV/6KaO0qyF/UMsX2aSUXKQFdoGTptQGc0ftq1csulHPGG6dsmyMNd3JB+G3EQIxAOajvBcjpJmKb4Nv+2Taoj8Uc5+b6ih6FXCCKraSqupe07zqswMcXJTe1cExvHvvlw=="
115
+ },
116
+ {
117
+ "rawBytes": "MIIB9zCCAXygAwIBAgIUV7f0GLDOoEzIh8LXSW80OJiUp14wCgYIKoZIzj0EAwMwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZDAeFw0yNTA0MDgwNjU5NDNaFw0zNTA0MDYwNjU5NDNaMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQUQNtfRT/ou3YATa6wB/kKTe70cfJwyRIBovMnt8RcJph/COE82uyS6FmppLLL1VBPGcPfpQPYJNXzWwi8icwhKQ6W/Qe2h3oebBb2FHpwNJDqo+TMaC/tdfkv/ElJB72jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSY7AHvf7tR/9SVHm+KiJhTB4nOvzAKBggqhkjOPQQDAwNpADBmAjEAwGEGrfGZR1cen1R8/DTVMI943LssZmJRtDp/i7SfGHmGRP6gRbuj9vOK3b67Z0QQAjEAuT2H673LQEaHTcyQSZrkp4mX7WwkmF+sVbkYY5mXN+RMH13KUEHHOqASaemYWK/E"
118
+ }
119
+ ]
120
+ },
121
+ "validFor": {
122
+ "start": "2025-07-04T00:00:00Z"
123
+ }
124
+ }
125
+ ]
126
+ }
@@ -38,7 +38,7 @@
38
38
  "character-consistency": 8555,
39
39
  "check-refs": 4188,
40
40
  "churn-prevention": 8014,
41
- "code-intelligence": 16998,
41
+ "code-intelligence": 17182,
42
42
  "code-refactoring": 13717,
43
43
  "code-review": 16261,
44
44
  "command-routing": 6040,
@@ -687,6 +687,12 @@
687
687
  "old": 16492,
688
688
  "new": 16998,
689
689
  "reason": "road-to-a-map-that-draws-itself (ADR-297): step 0 sends an orientation question to agents/map/MAP.md before any graph query, and the MCP table gains rows for graph_map_status and graph_area. Both are the skill's routing surface for the new map; trimming them would hide the tools the roadmap added."
690
+ },
691
+ {
692
+ "skill": "code-intelligence",
693
+ "old": 16998,
694
+ "new": 17182,
695
+ "reason": "road-to-a-graph-that-follows-you (ADR-299): the MCP table gains a row for graph_estate and one line naming the new project parameter on every other graph tool. The ceiling sat 3 bytes above the body, so documenting the tool at all needs a raise; the wording was compressed first, from 262 to 184 bytes."
690
696
  }
691
697
  ]
692
698
  }
@@ -44,7 +44,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
44
44
 
45
45
  import { dump as yamlDump, load as yamlLoad } from 'js-yaml';
46
46
 
47
- import { z } from 'zod';
47
+ import * as z from 'zod';
48
48
 
49
49
  import { mergeIntoTemplate } from '../../server/io/yamlIO.js';
50
50
  import { settingsSchema } from '../../server/schemas/settings.js';
@@ -269,10 +269,11 @@ function _unwrap(schema: z.ZodTypeAny): z.ZodTypeAny {
269
269
  let current: z.ZodTypeAny = schema;
270
270
  while (
271
271
  current instanceof z.ZodDefault ||
272
+ current instanceof z.ZodPrefault ||
272
273
  current instanceof z.ZodOptional ||
273
274
  current instanceof z.ZodNullable
274
275
  ) {
275
- current = (current._def as { innerType: z.ZodTypeAny }).innerType;
276
+ current = (current._def as unknown as { innerType: z.ZodTypeAny }).innerType;
276
277
  }
277
278
  return current;
278
279
  }
@@ -21,6 +21,12 @@
21
21
  * Downgrades are allowed; the pin is a project decision.
22
22
  * - (no flag) — pin to the registry's `latest` tag.
23
23
  *
24
+ * The global install moves first. Only the CLI follows the pin (`pin_resolver`
25
+ * re-execs through npx); hooks, rules and skills run from the global install. So
26
+ * when `installed.lock` records an older version than the target, this runs
27
+ * `agent-config upgrade` to exactly that version and writes the pin only once it
28
+ * succeeded — offline, where it cannot, the pin is refused instead.
29
+ *
24
30
  * Write target: the **deepest** `.agent-settings.yml` in the project cascade
25
31
  * that already carries the `agent_config_version` key. When no file carries
26
32
  * it, the repo-root file is created/edited. Comments and key ordering are
@@ -405,6 +411,10 @@ interface MainOptions {
405
411
  state_path?: string | null;
406
412
  out?: OutSink;
407
413
  err?: OutSink;
414
+ /** The version the global install recorded in `installed.lock`, or `null` when there is none. */
415
+ global_version?: () => string | null;
416
+ /** Install exactly this version globally; returns the exit code. */
417
+ upgrader?: (version: string, out: OutSink, err: OutSink) => Promise<number>;
408
418
  }
409
419
 
410
420
  interface Args {
@@ -526,6 +536,29 @@ export async function main(argv: string[] | null = null, options: MainOptions =
526
536
  return 0;
527
537
  }
528
538
 
539
+ // The pin only steers the CLI (`pin_resolver` re-execs through npx); hooks,
540
+ // rules and skills run from the global install. A pin ahead of it would
541
+ // leave the project naming one version while every session runs another,
542
+ // so the global install moves first, and the pin only once it has.
543
+ const global = (options.global_version ?? _global_install_version)();
544
+ if (global !== null && update_check._is_newer(latest, global)) {
545
+ if (offline) {
546
+ _print(
547
+ err,
548
+ `❌ agent-config: the global install is ${global} and cannot be upgraded to ${latest} offline; ` +
549
+ 'the pin is unchanged. Run `agent-config update` again with registry access.',
550
+ );
551
+ return 1;
552
+ }
553
+ _print(out, `→ The global install is ${global}; installing ${latest} first so the pin matches what runs.`);
554
+ const upgrader = options.upgrader ?? _upgrade_global;
555
+ const rc = await upgrader(latest, out, err);
556
+ if (rc !== 0) {
557
+ _print(err, `❌ agent-config: the global upgrade to ${latest} failed (exit ${rc}); the pin is unchanged.`);
558
+ return 1;
559
+ }
560
+ }
561
+
529
562
  const pin_file = _find_pin_file(cwd);
530
563
  const changed = _write_pin(pin_file, latest);
531
564
  const rel = _relativeToOr(pin_file, cwd);
@@ -542,7 +575,6 @@ export async function main(argv: string[] | null = null, options: MainOptions =
542
575
  cache_warmer(latest);
543
576
  }
544
577
  _refresh_state(latest, latest, state_path);
545
- _report_global_install(latest, out);
546
578
  return 0;
547
579
  }
548
580
 
@@ -556,28 +588,24 @@ function _relativeToOr(target: string, base: string): string {
556
588
  }
557
589
 
558
590
  /**
559
- * Name `agent-config upgrade` when the global install is older than the pin.
591
+ * The version the global install recorded, or `null` when there is no global
592
+ * install to keep in step with.
560
593
  *
561
- * Read-only by design: `installed.lock` records what the global install
562
- * deployed, and `upgrade` (plus its `--check` and unattended paths) reads it as
563
- * the installed version. This command used to rewrite it to the pin, so after
564
- * `update` the lock claimed a version no `npm install -g` had installed and
565
- * `upgrade --check` reported "up to date" over the old binary.
594
+ * Read-only by design: `installed.lock` is written by the global install itself.
595
+ * This command once rewrote it to the pin, so the lock claimed a version no
596
+ * `npm install -g` had installed and `upgrade --check` reported "up to date"
597
+ * over the old binary.
566
598
  */
567
- function _report_global_install(version: string, out: OutSink): void {
599
+ function _global_install_version(): string | null {
568
600
  const existing = installed_lock.read_lockfile(installed_lock.lockfile_path());
569
- if (existing === null) {
570
- return;
571
- }
572
- const recorded = (existing as unknown as Record<string, unknown>)['agent_config_version'];
573
- if (typeof recorded !== 'string' || !update_check._is_newer(version, _normalize(recorded))) {
574
- return;
575
- }
576
- _print(
577
- out,
578
- `ℹ️ The global install is ${_normalize(recorded)}; this pin does not change it. ` +
579
- `Run \`agent-config upgrade\` to install ${version} globally.`,
580
- );
601
+ const recorded = (existing as unknown as Record<string, unknown> | null)?.['agent_config_version'];
602
+ return typeof recorded === 'string' && recorded.trim() !== '' ? _normalize(recorded) : null;
603
+ }
604
+
605
+ /** `agent-config upgrade`, in process, to exactly `version`. */
606
+ async function _upgrade_global(version: string, out: OutSink, err: OutSink): Promise<number> {
607
+ const upgrade = await import('./cmd_upgrade.js');
608
+ return upgrade.main([], { version, out, err });
581
609
  }
582
610
 
583
611
  /** Read `version` from the package's own `package.json`. */
@@ -505,6 +505,12 @@ interface MainOptions {
505
505
  project_root?: string | null;
506
506
  out?: OutSink;
507
507
  err?: OutSink;
508
+ /**
509
+ * Install this exact version instead of `latest`. Programmatic only — set by
510
+ * `agent-config update`, which must install the version it is about to pin;
511
+ * the command line keeps `update --to` as the one way to name a version.
512
+ */
513
+ version?: string;
508
514
  }
509
515
 
510
516
  export async function main(argv: string[] | null = null, options: MainOptions = {}): Promise<number> {
@@ -549,7 +555,7 @@ export async function main(argv: string[] | null = null, options: MainOptions =
549
555
  return 0;
550
556
  }
551
557
 
552
- const target = `${PACKAGE_NAME}@latest`;
558
+ const target = `${PACKAGE_NAME}@${options.version ?? 'latest'}`;
553
559
  const npm_cmd: string[] = ['npm', 'install', '-g', target];
554
560
  // --no-ui: the setup wizard is an onboarding surface, not an upgrade
555
561
  // step — its foreground server used to block the upgrade until Ctrl-C.