@event4u/agent-config 15.0.0 → 16.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +301 -347
  5. package/CONTRIBUTING.md +9 -0
  6. package/README.md +2 -2
  7. package/dist/agent-src/commands/analyze/inbox.md +26 -0
  8. package/dist/agent-src/commands/analyze/roadmap-repos.md +27 -0
  9. package/dist/agent-src/commands/challenge-me/closure.md +178 -0
  10. package/dist/agent-src/commands/challenge-me.md +9 -2
  11. package/dist/agent-src/commands/council/default.md +25 -5
  12. package/dist/agent-src/commands/feature/plan.md +28 -1
  13. package/dist/agent-src/commands/feature/roadmap.md +28 -1
  14. package/dist/agent-src/commands/implement-ticket.md +27 -0
  15. package/dist/agent-src/commands/jira-ticket.md +27 -0
  16. package/dist/agent-src/commands/pr/create.md +29 -0
  17. package/dist/agent-src/commands/pr/merge.md +60 -9
  18. package/dist/agent-src/commands/roadmap/ai-council.md +7 -1
  19. package/dist/agent-src/commands/roadmap/create.md +77 -29
  20. package/dist/agent-src/commands/roadmap/materialize.md +27 -0
  21. package/dist/agent-src/commands/roadmap/process-full.md +123 -18
  22. package/dist/agent-src/commands/team.md +22 -0
  23. package/dist/agent-src/contexts/authority/scope-growth-ownership.md +80 -0
  24. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +97 -0
  25. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +44 -3
  26. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +15 -15
  27. package/dist/agent-src/contexts/execution/decision-closure-execution.md +93 -0
  28. package/dist/agent-src/contexts/execution/fix-loop-ladder.md +108 -0
  29. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +4 -2
  30. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +75 -6
  31. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  32. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  33. package/dist/agent-src/guidelines/design-fidelity-routing.md +29 -0
  34. package/dist/agent-src/rules/autonomous-execution.md +15 -8
  35. package/dist/agent-src/rules/delegation-policy.md +23 -45
  36. package/dist/agent-src/rules/design-fidelity.md +32 -37
  37. package/dist/agent-src/rules/evaluator-independence.md +43 -49
  38. package/dist/agent-src/rules/test-first.md +41 -0
  39. package/dist/agent-src/rules/user-interaction.md +31 -30
  40. package/dist/agent-src/skills/accessibility-auditor/data/manifest.json +3 -3
  41. package/dist/agent-src/skills/ai-council/SKILL.md +11 -3
  42. package/dist/agent-src/skills/api-design/data/manifest.json +3 -3
  43. package/dist/agent-src/skills/database/data/manifest.json +4 -4
  44. package/dist/agent-src/skills/database/data/query-tuning.csv +3 -3
  45. package/dist/agent-src/skills/design-review/SKILL.md +50 -0
  46. package/dist/agent-src/skills/error-handling-patterns/SKILL.md +9 -0
  47. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +14 -4
  48. package/dist/agent-src/skills/experiment-loop/SKILL.md +31 -1
  49. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  50. package/dist/agent-src/skills/storybook-workshop/SKILL.md +42 -3
  51. package/dist/agent-src/skills/threat-modeling/SKILL.md +9 -4
  52. package/dist/agent-src/skills/threat-modeling/data/manifest.json +4 -4
  53. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +37 -3
  54. package/dist/agent-src/templates/agent-settings.md +1 -1
  55. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  56. package/dist/agent-src/templates/roadmaps.md +188 -0
  57. package/dist/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  58. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  59. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  60. package/dist/cli-delegate/check_update_banner.js +40 -2
  61. package/dist/cli-delegate/chunk-4E2W63DA.js +335 -0
  62. package/dist/cli-delegate/chunk-5R7HOLAF.js +99 -0
  63. package/dist/cli-delegate/{chunk-IVBPRCQO.js → chunk-6KFEC3G7.js} +1 -1
  64. package/dist/cli-delegate/{chunk-2TAQ2K4V.js → chunk-6KM6ORRY.js} +55 -386
  65. package/dist/cli-delegate/{chunk-2XY7ILBT.js → chunk-FC75PGJE.js} +42 -2
  66. package/dist/cli-delegate/{chunk-GYC3VRYN.js → chunk-FXYUYU4N.js} +57 -13
  67. package/dist/cli-delegate/{chunk-55ACLDUE.js → chunk-GJCBB2UG.js} +168 -10
  68. package/dist/cli-delegate/{chunk-AK6HODNQ.js → chunk-HDVVGPQW.js} +873 -539
  69. package/dist/cli-delegate/chunk-NUHLI2RX.js +80 -0
  70. package/dist/cli-delegate/{chunk-HZ52BRGG.js → chunk-P6ZHP5W2.js} +15 -90
  71. package/dist/cli-delegate/{chunk-TYSY33MD.js → chunk-QJWAUMJW.js} +12 -2
  72. package/dist/cli-delegate/{chunk-57PN4GYJ.js → chunk-RGNIWTEA.js} +1 -1
  73. package/dist/cli-delegate/chunk-ROYYTEZU.js +39 -0
  74. package/dist/cli-delegate/{chunk-2KKXJW25.js → chunk-S3VFXMTM.js} +1 -1
  75. package/dist/cli-delegate/{chunk-3FKR64R5.js → chunk-UNCRJBT3.js} +31 -7
  76. package/dist/cli-delegate/{chunk-2DK2VJWG.js → chunk-WGXTVKCQ.js} +20 -6
  77. package/dist/cli-delegate/chunk-YDPILCOL.js +152 -0
  78. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  79. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  80. package/dist/cli-delegate/cmd_conformance.js +918 -325
  81. package/dist/cli-delegate/cmd_doctor.js +7 -5
  82. package/dist/cli-delegate/cmd_explain.js +5 -3
  83. package/dist/cli-delegate/cmd_export.js +9 -7
  84. package/dist/cli-delegate/cmd_fleet.js +4 -2
  85. package/dist/cli-delegate/cmd_handoff.js +6 -6
  86. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  87. package/dist/cli-delegate/cmd_migrate.js +2 -2
  88. package/dist/cli-delegate/cmd_packs_active.js +3 -2
  89. package/dist/cli-delegate/cmd_preflight.js +4 -2
  90. package/dist/cli-delegate/cmd_prune.js +10 -8
  91. package/dist/cli-delegate/cmd_route_audit.js +2 -2
  92. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  93. package/dist/cli-delegate/cmd_session_recycle.js +4 -4
  94. package/dist/cli-delegate/cmd_settings_get.js +28 -2
  95. package/dist/cli-delegate/cmd_settings_migrate.js +9 -7
  96. package/dist/cli-delegate/cmd_settings_set.js +14 -1
  97. package/dist/cli-delegate/cmd_sync.js +10 -8
  98. package/dist/cli-delegate/cmd_uninstall.js +16 -13
  99. package/dist/cli-delegate/cmd_update.js +1 -1
  100. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  101. package/dist/cli-delegate/cmd_validate.js +12 -10
  102. package/dist/cli-delegate/cmd_versions.js +1 -1
  103. package/dist/discovery/deprecation-report.md +1 -1
  104. package/dist/discovery/discovery-manifest.json +87 -40
  105. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  106. package/dist/discovery/discovery-manifest.summary.md +4 -4
  107. package/dist/discovery/dormancy-report.md +1 -1
  108. package/dist/discovery/orphan-report.md +1 -1
  109. package/dist/discovery/packs.json +10 -8
  110. package/dist/discovery/trust-report.md +3 -3
  111. package/dist/discovery/workspaces.json +8 -6
  112. package/dist/hooks/dispatch.js +2601 -1073
  113. package/dist/install/claudeRuleRewrite.js +14 -3
  114. package/dist/install/conflict.js +60 -10
  115. package/dist/install/conflictTracker.js +218 -0
  116. package/dist/install/fsPrimitives.js +54 -0
  117. package/dist/install/install.mjs +2008 -1481
  118. package/dist/install/manifestFiles.js +259 -0
  119. package/dist/install/preflight.js +14 -2
  120. package/dist/install/preserve.js +157 -0
  121. package/dist/install/recordedOwnership.js +132 -0
  122. package/dist/install/txlog.js +11 -2
  123. package/dist/mcp/registry-manifest.json +3 -3
  124. package/dist/mcp/server.json +2 -2
  125. package/dist/mcp/server.mjs +1612 -667
  126. package/dist/router.json +1 -1
  127. package/dist/scripts/_lib/agent_settings.js +3 -2
  128. package/dist/scripts/_lib/fs_atomic.js +167 -0
  129. package/dist/scripts/_lib/installed_lock.js +1 -1
  130. package/dist/scripts/_lib/installed_tools.js +460 -0
  131. package/dist/scripts/_lib/lean_projection_mode.js +3 -2
  132. package/dist/scripts/_lib/settings_renamed_keys.js +78 -0
  133. package/dist/server/io/yamlIO.js +50 -0
  134. package/dist/server/routes/install.js +8 -0
  135. package/dist/server/routes/wizard.js +9 -3
  136. package/dist/server/schemas/settings.js +17 -5
  137. package/dist/shared/missionExecution.js +97 -0
  138. package/dist/ui/assets/{index-D0jaCRPM.js → index-DH1xc62v.js} +17 -17
  139. package/dist/ui/index.html +1 -1
  140. package/docs/MIGRATION.md +103 -0
  141. package/docs/contracts/settings-classes.md +26 -7
  142. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +57 -0
  143. package/docs/guidelines/agent-infra/evaluator-independence-mechanics.md +102 -0
  144. package/docs/guidelines/design-fidelity-routing.md +29 -0
  145. package/package.json +1 -1
  146. package/src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts +62 -2
  147. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +1 -0
  148. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +1 -0
  149. package/src/config/agent-settings.template.yml +139 -27
  150. package/src/config/auto-rule-budget.json +16 -0
  151. package/src/config/ci-local-parity.yml +18 -5
  152. package/src/config/continuity-surface.json +28 -0
  153. package/src/config/gate-coverage.yml +146 -13
  154. package/src/config/gate-violation-baselines.json +6 -6
  155. package/src/config/hook-token-budget.json +2 -0
  156. package/src/config/host-injection-effect.json +1 -1
  157. package/src/config/loop-surfaces.yaml +215 -0
  158. package/src/config/platform-anchor.json +3 -2
  159. package/src/config/preamble-payload-budget.json +12 -7
  160. package/src/config/preamble-payload-exceptions.json +28 -0
  161. package/src/config/release-gate-locality.yml +11 -0
  162. package/src/config/routing-coverage-seed.json +18 -4
  163. package/src/config/rule-enforcement-baseline.json +0 -1
  164. package/src/install/claudeRuleRewrite.ts +16 -2
  165. package/src/install/conflict.ts +65 -9
  166. package/src/install/conflictTracker.ts +299 -0
  167. package/src/install/fsPrimitives.ts +54 -0
  168. package/src/install/manifestFiles.ts +312 -0
  169. package/src/install/preflight.ts +16 -2
  170. package/src/install/preserve.ts +205 -0
  171. package/src/install/recordedOwnership.ts +149 -0
  172. package/src/install/txlog.ts +11 -2
  173. package/src/install/types.ts +19 -4
  174. package/src/scripts/_cli/cmd_conformance.ts +88 -15
  175. package/src/scripts/_cli/cmd_doctor.ts +4 -3
  176. package/src/scripts/_cli/cmd_route_explain.ts +9 -2
  177. package/src/scripts/_cli/cmd_settings_get.ts +44 -0
  178. package/src/scripts/_cli/doctor_execution.ts +90 -0
  179. package/src/scripts/_dispatch.bash +3 -1
  180. package/src/scripts/_lib/activation_payload.ts +247 -0
  181. package/src/scripts/_lib/agent_settings.ts +4 -2
  182. package/src/scripts/_lib/authority_path.ts +102 -0
  183. package/src/scripts/_lib/base_ref_payload.ts +315 -0
  184. package/src/scripts/_lib/cascade_base.ts +94 -0
  185. package/src/scripts/_lib/changelog_eras.ts +7 -2
  186. package/src/scripts/_lib/continuation_ladder.ts +149 -2
  187. package/src/scripts/_lib/council_transport.ts +129 -0
  188. package/src/scripts/_lib/delivery_ready.ts +112 -0
  189. package/src/scripts/_lib/dropped_decision.ts +142 -0
  190. package/src/scripts/_lib/forge_protection.ts +267 -0
  191. package/src/scripts/_lib/hook_platform_keys.ts +27 -0
  192. package/src/scripts/_lib/installed_lock.ts +1 -1
  193. package/src/scripts/_lib/json_python_parity.ts +127 -0
  194. package/src/scripts/_lib/lean_projection_mode.ts +14 -3
  195. package/src/scripts/_lib/loop_surfaces.ts +382 -0
  196. package/src/scripts/_lib/measured_payload_ceiling.ts +424 -0
  197. package/src/scripts/_lib/mission_record.ts +190 -0
  198. package/src/scripts/_lib/obligation_frequency.ts +217 -0
  199. package/src/scripts/_lib/obligations.ts +402 -0
  200. package/src/scripts/_lib/orchestration_record.ts +11 -20
  201. package/src/scripts/_lib/payload_catalogue_completeness.ts +211 -0
  202. package/src/scripts/_lib/release_findings_ingest.ts +324 -0
  203. package/src/scripts/_lib/release_highlights.ts +199 -10
  204. package/src/scripts/_lib/release_holds.ts +493 -0
  205. package/src/scripts/_lib/release_migration_gate.ts +184 -0
  206. package/src/scripts/_lib/release_tag_dispatch.ts +63 -0
  207. package/src/scripts/_lib/review_baseline.ts +254 -0
  208. package/src/scripts/_lib/review_skipped_record.ts +61 -1
  209. package/src/scripts/_lib/rides_along.ts +102 -0
  210. package/src/scripts/_lib/settings_renamed_keys.ts +82 -0
  211. package/src/scripts/_lib/standing_bound_ratchet.ts +216 -103
  212. package/src/scripts/_lib/test_delta.ts +166 -0
  213. package/src/scripts/_lib/test_provenance.ts +171 -0
  214. package/src/scripts/_lib/turn_end_refusals.ts +51 -4
  215. package/src/scripts/_lib/typed_op_grant.ts +246 -0
  216. package/src/scripts/_lib/typed_op_watch.ts +185 -0
  217. package/src/scripts/ai_council/config.ts +8 -11
  218. package/src/scripts/ai_council/fallback_config.ts +5 -3
  219. package/src/scripts/ai_council/ownership_classes.ts +118 -0
  220. package/src/scripts/ask_block_census.ts +285 -15
  221. package/src/scripts/check_beta_review_markers.ts +35 -4
  222. package/src/scripts/check_enforcement_matrix.ts +624 -0
  223. package/src/scripts/check_finding_dispositions.ts +167 -16
  224. package/src/scripts/check_gate_reachability.ts +173 -10
  225. package/src/scripts/check_generator_sync.ts +954 -0
  226. package/src/scripts/check_held_object_arrivals.ts +381 -0
  227. package/src/scripts/check_preamble_payload_budget.ts +474 -124
  228. package/src/scripts/check_release_highlights.ts +33 -1
  229. package/src/scripts/check_release_holds.ts +567 -0
  230. package/src/scripts/check_release_published.ts +1 -1
  231. package/src/scripts/check_reply_consistency.ts +86 -17
  232. package/src/scripts/check_rule_projection_integrity.ts +22 -12
  233. package/src/scripts/check_test_delta.ts +294 -0
  234. package/src/scripts/check_test_weakening.ts +299 -0
  235. package/src/scripts/closure_scan.ts +333 -0
  236. package/src/scripts/compile_hook_manifest.ts +43 -3
  237. package/src/scripts/council_record_shape.ts +209 -0
  238. package/src/scripts/hook_manifest.json +1 -1
  239. package/src/scripts/hook_manifest.yaml +127 -12
  240. package/src/scripts/hooks/block_kernel_rule_writes.ts +12 -2
  241. package/src/scripts/hooks/concern_registry.ts +6 -0
  242. package/src/scripts/hooks/design_pass_hook.ts +128 -3
  243. package/src/scripts/hooks/end_review_nudge_hook.ts +101 -21
  244. package/src/scripts/hooks/evidence_independence.ts +96 -0
  245. package/src/scripts/hooks/memory_recall_hook.ts +540 -0
  246. package/src/scripts/hooks/obligation_settle_hook.ts +182 -0
  247. package/src/scripts/hooks/review_baseline_hook.ts +130 -0
  248. package/src/scripts/hooks/rule_inject_hook.ts +49 -1
  249. package/src/scripts/hooks/run_continuation_hook.ts +17 -20
  250. package/src/scripts/hooks/turn_end_gate_hook.ts +232 -14
  251. package/src/scripts/hooks_doctor.ts +89 -1
  252. package/src/scripts/hooks_status.ts +19 -0
  253. package/src/scripts/install.ts +107 -207
  254. package/src/scripts/interruption_report.ts +8 -2
  255. package/src/scripts/janitor.ts +15 -1
  256. package/src/scripts/lint_decision_classes.ts +464 -0
  257. package/src/scripts/lint_hook_manifest.ts +11 -0
  258. package/src/scripts/lint_major_migration_sections.ts +450 -0
  259. package/src/scripts/lint_plan_risk_register.ts +47 -3
  260. package/src/scripts/lint_roadmap_blockers.ts +61 -0
  261. package/src/scripts/lint_roadmap_producers.ts +202 -0
  262. package/src/scripts/measure_rule_budget.ts +101 -5
  263. package/src/scripts/measure_turn_end_gate.ts +302 -5
  264. package/src/scripts/new_roadmap.ts +37 -0
  265. package/src/scripts/orchestration_record.ts +0 -5
  266. package/src/scripts/release.ts +66 -162
  267. package/src/scripts/release_drill.ts +460 -15
  268. package/src/scripts/release_env.ts +1 -1
  269. package/src/scripts/release_publication.ts +52 -1
  270. package/src/scripts/report_enforcement_drift.ts +566 -0
  271. package/src/scripts/report_held_object_arrivals.ts +456 -0
  272. package/src/scripts/report_host_injection_effect.ts +3 -11
  273. package/src/scripts/report_standing_payload_by_host.ts +26 -152
  274. package/src/scripts/schemas/agent-settings.schema.json +23 -0
  275. package/src/scripts/schemas/command.schema.json +4 -0
  276. package/src/scripts/scope_growth.ts +219 -0
  277. package/src/scripts/sync_agent_settings.ts +140 -18
  278. package/src/scripts/trigger_eval_grandfather.json +0 -1
  279. package/src/scripts/ui_conformance_probe.ts +622 -0
  280. package/src/server/io/yamlIO.ts +48 -0
  281. package/src/server/schemas/settings.ts +31 -7
  282. package/src/shared/missionExecution.ts +126 -0
  283. package/dist/cli-delegate/chunk-523HCFYO.js +0 -90
@@ -34,9 +34,9 @@
34
34
  "note": "The nine active non-draft roadmaps that predate the `relates:` requirement (road-to-agentic-engineering-assurance, road-to-component-library-lifecycle, road-to-council-evidence-integrity, road-to-frontend-fidelity-calibration, road-to-monorepo-scope-and-detection, road-to-observability-plate, road-to-role-scoped-spawn-profiles, road-to-skill-delivery-over-mcp, road-to-standing-payload-diet). This is a NEW obligation rather than a repaired scan root, and the ratchet is the point: `depends:` shipped in the template with nothing requiring it and measured 0 adoption, so requiring `relates:` retroactively across the estate would be an owner-reserved write with no analysis behind the edges it would have to invent (held as step 4.3, deferred). Clearing an entry here is one roadmap at a time: run `agent-config roadmap:context` on it, write the rows the probe surfaces, and lower the count."
35
35
  },
36
36
  "check_source_size_budget": {
37
- "count": 17959,
38
- "landed": "2026-09-09",
39
- "note": "Lowered 17,963 -> 17,959 on 2026-09-09 by feat/cdd-fidelity-council, on the same shape as the entry below and with the same discriminator. The branch's src-link rewrite (a blind review found 253 of 268 links under dist/agent-src/guidelines/ dead, because condense.ts folded only the docs/ prefixes and never (../)+src/rules|skills) came in at +15 excess: condense.ts sits ~1,208 lines PAST the 1500 cap, so every line there is one unit. Paid down rather than baselined, in the way this entry's doctrine prescribes. `_rewrite_body_links` and its two regex constants moved out of condense.ts into _lib/guidelines_lane.ts, 151 lines and therefore UNDER the cap, so the function and its prose now cost nothing. It moved on merit rather than only on arithmetic: every rule the rewriter applies is a statement about which source tree projects where, which is that module's own subject, and condense.ts held it only because that is where the projector lives. condense.ts 2,712 -> 2,708 net, after the one import line and the one call-site rename -- a branch that ADDED a rewrite rule leaves the file four lines shorter than it found it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the branch's new src/ files tracked and nothing untracked, so a clean CI checkout of this commit measures the same 17,959. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,973 -> 17,963 on 2026-09-08 by drain/graph-shipped-close. The branch registers five code-graph MCP tools (road-to-a-graph-that-is-shipped 4.1). Their five records and schemas are ~250 lines, and putting them in mcp_server/tools.ts -- which sits ~500 lines PAST the 1500 cap, so every line there is one unit -- would have cost ~250 excess. They live in mcp_server/graph_tools.ts instead (~280 lines, UNDER the cap, so they and their prose cost nothing), and tools.ts spreads them into ALLOWLIST in two lines: one import and one `...GRAPH_TOOLS,`. Those two were paid for rather than baselined, in the way this entry's doctrine prescribes: `_strip` and `_resolvePath` -- a whitespace trim and a tolerant realpath, generic by nature -- moved out of tools.ts into mcp_server/path_util.ts, also under the cap. They are imported under their original underscore names, so all 28 call sites are unchanged and a two-function move does not read as a sweep. tools.ts 2,025 -> 2,015: -12 from the extraction, +2 from the registration, net -10 for a branch that ADDED a feature. CORRECTED 2026-09-08 after an independent review checked the figure against the tree -- this sentence read '2,025 -> 2,013, net -12, against the +2 the registration needed', which states an intermediate file length as the final one and leaves the arithmetic (-12) and the conclusion (-10) describing different trees. `git show origin/main:...tools.ts | wc -l` is 2025 and the working tree is 2015. The TOTAL, 17,963, was always the gate's own output and is unchanged. Every other file this branch touches or creates -- code_graph/verbs.ts, code_graph/cli.ts, code_graph/build.ts, code_graph/detect.ts, code_graph/query.ts, code_graph/sqlite_store.ts, code_graph/types.ts, _lib/regression_neighbourhood.ts -- is under the 1500 ceiling before and after, so it contributes zero excess whatever it grew by. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the two new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,963. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,974 -> 17,973 on 2026-09-08 by drain/topology-c1. The branch adds a live-path emit to council_cli.ts, which sits 2,454 lines PAST the 1500 cap so every line there is one unit, and paid its own way down rather than raising the baseline, in the way this entry's doctrine prescribes. The twelve-line `all_responses` assembly (a spread, three conditionals and a push) moved out of council_cli.ts into ai_council/deliberation_metrics.ts::runCallsFrom, 353 lines and therefore UNDER the cap, so the six stage labels and their prose cost nothing. It moved on merit rather than only on arithmetic: 'which calls did this run make, and at which stage' is that module's own subject, and the CLI held the list only as a flat array with the stage boundaries implicit in the order -- both readings now come out of one walk, so the billing total and the attribution can never be computed over different sets. council_cli.ts 3,955 -> 3,954 net, after the two call lines, the import and the one payload key the feature needed. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the two new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,973. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 18,016 -> 17,974 on 2026-09-07 by fix/single-delivery-unconditional. SETTLED FIGURE, and it supersedes an intra-session 17,962 this same branch committed earlier — read the direction against MAIN, which is what the ratchet protects: main is 18,016, the branch leaves 17,974, net -42. The 17,962 was this branch's own low before a neutral review returned twelve findings; fixing them added a real mechanism to mcp_server and condense.ts (the flat-wrapper carriage gate the review showed was missing, plus its four-skip predicate), and condense.ts sits ~1,215 lines PAST the cap so each of those lines is one unit. Paid down first, in the way this entry's doctrine prescribes: _suggestSkillForTaskHandler and its 18-line docstring moved out of mcp_server/tools.ts (2,079 -> 2,025) into mcp_server/suggest_skill.ts, 72 lines and UNDER the cap, so its prose costs nothing. The residual +12 against the intra-session low is the gate's own output on the settled tree and is recorded rather than engineered away, because the alternative was extracting _nested_command_subpath and its two callers out of condense.ts - which needs MODULE_STATE, _relativeToPosix and _domains_command_logical passed in, a wider diff than the finding warrants and one no review asked for. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the three new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,974. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: MERGE RECONCILIATION 2026-09-07, 18,061/18,017 -> 18,016. drain/admissible-council-seats and fix/release-obligation-answerable each lowered from the SAME 18,062 base in parallel — main to 18,061 (net -1: curlJsonPost, the seat-status helpers and the per-seat config parsing moved out of the three over-ceiling council files) and the branch to 18,017 (net -45: the /dev/tty prompt helpers moved out of release.ts into _lib/tty_prompt.ts, 76 lines and UNDER the cap, taking release.ts 1871 -> 1826). Taking either side alone is wrong in a different direction, which is the reconciliation doctrine this entry already carried from 2026-09-03: main's value silently discards the branch's earned -45, and the branch's value RAISES the baseline against main and weakens the gate. The committed number is neither — it is the gate's own output on the MERGED tree, where both reductions apply, and it equals the arithmetic (18,062 - 45 - 1 = 18,016) rather than being reconciled by it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports ZERO untracked files, so a clean CI checkout of this commit measures the same 18,016. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in the merge commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 18,062 -> 18,061 on 2026-09-07 by drain/admissible-council-seats. The branch's own additions to the three over-ceiling files (ai_council/config.ts, council_cli.ts, ai_council/clients.ts) came in at +96 excess and were paid down to -1 rather than baselined, in the four ways this entry's doctrine prescribes: `curlJsonPost` moved out of clients.ts into ai_council/api_transport.ts (UNDER the cap, so the prose and the three new provider shims cost nothing); the seat-status helpers moved out of council_cli.ts into ai_council/status_surface.ts, taking an orphaned doc comment with them; the three new per-seat config fields' parsing moved out of config.ts into ai_council/seat_policy.ts::parseSeatFields; and three prose blocks that the branch's own transport repair made FACTUALLY FALSE (the `openai` / `google-genai` Python-SDK claims, and a `_curlJsonPost` pointer to a function that had moved) were corrected and shortened in the same change. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports zero untracked files with the five new src/ files staged, so a clean CI checkout of this commit measures the same 18,061. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried here because tests/scripts/check_source_size_budget.test.ts:166 asserts baseline == live and therefore blocks where the gate only advises -- the lowering commit must carry its own baseline update. Lowered 18,068 -> 18,062 on 2026-09-06 by drain/host-enforcement-truth. Collapsing the five per-host binding constants in install.ts into src/scripts/hooks/host_lowering.yaml removed 29 lines from a file ~3,900 past the 1500 cap, where every line costs one excess; the journal's surface column and its extracted migration helper gave 23 back. Lowered 18,245 -> 18,230 on 2026-09-02 by drain/publication-integrity-option-a. Phase 2 Option A moved the authoring instruction out of the generator: release.ts, which sits ~530 lines PAST the 1500 cap so every line there costs one excess, loses the comment emission, a 16-line HEAD_DEFAULT doc block and its alias const, and gains a shorter writer docstring. The doc block moved to _lib/release_material.ts, which is 289 lines and therefore UNDER the cap, so the same prose now costs nothing. Net -15. The branch first came in at +8 and paid its own way down rather than raising the baseline.",
37
+ "count": 17762,
38
+ "landed": "2026-09-27",
39
+ "note": "LOWERING 2026-09-27, 17,765 -> 17,762 — the second half of the same repair, and a lowering for the same reason. Closing the remaining preservation defects needed lines in two over-cap files: `src/scripts/install.ts` (route the generated Claude Desktop marker through the tracker, hand the rule-rewrite its skip set) and `src/server/routes/wizard.ts` (surface the conflict count, stop reporting exit 3 as a failure). Both were paid from the same subject rather than from the ratchet: `_files_by_tool_from_bridges` joined its sibling in `src/install/manifestFiles.ts`, which now owns the whole per-tool inventory, and the wizard's exit-code semantics moved into `src/install/preserve.ts` beside `installDoneSummary`, which already lives there for this exact reason. install.ts 5,277 -> 5,270; wizard.ts 1,500 -> 1,504. PRIOR ENTRY: LOWERING 2026-09-27, 17,784 -> 17,765 — a lowering commit, same doctrine as the entry it replaces. Repairing the install-manifest digest loss needed new state in `_update_installed_tools_manifest` (a recorded-inventory read, a preserved-path index, a reconciliation call). Rather than pay that against `src/scripts/install.ts`, already 3,777 over the cap, the manifest file-inventory block (`_sha256_of_file`, `_file_entry`, `_files_by_tool_from_deploy` — 29 lines) moved out into the under-cap `src/install/manifestFiles.ts`, which is where the new logic lives too: one module now owns what the manifest's per-tool `files[]` holds, how it is read back, and how the two reconcile, so the unit is coherent rather than a line-count trim. install.ts 5,296 -> 5,277; total 17,784 -> 17,765. PRIOR ENTRY: LOWERING 2026-09-20, 17,858 -> 17,784 — a lowering commit, not a reconciliation, but measured under the same doctrine the four entries below carry: the committed number is the gate's own reading on the MERGED tree, taken after origin/main was merged into drain/headless-log-write rather than from either side. The branch's transaction-log write added 27 lines to `src/scripts/install.ts`, already 3,897 over the cap, taking the total to 17,885. Rather than pay that, the `json.dumps` byte-parity block (`jsonStrNoAscii`, `_jsonScalar`, `_dumpIndent`, `jsonDumpsIndent`, `jsonDumpsCompact` — 101 lines) moved out of `install.ts` into the under-cap `src/scripts/_lib/json_python_parity.ts`: pure, total functions of their input carrying no installer state, so the unit is coherent rather than a line-count trim. install.ts 5,397 -> 5,296; total 17,885 -> 17,784, a net -74 against the prior baseline. PRIOR ENTRY: MERGE RECONCILIATION 2026-09-14, 17,861 -> 17,858 — the FOURTH reconciliation of this entry, same doctrine as the three below: the committed number is the gate's own reading on the MERGED tree, never either side's. Neither branch earned the -3; it falls out of main having absorbed drain/release-head-field, whose `derive_head_prefill` extraction moved the span-to-prefill composition into an under-cap module. Taking this branch's 17,861 would have silently given that gain back. PRIOR ENTRY: MERGE RECONCILIATION 2026-09-13, 17,863 -> 17,861 — the THIRD reconciliation of this entry in one day, and re-measured on the merged tree rather than taken from either side, which is the only resolution that converges. drain/adversarial-verification reached 17,864 by paying for a `forge_protection` block and a cascade-base module entirely in files under the 1,500-line cap; the incoming reconciliation reached 17,863 from different work. Neither describes the merge. PRIOR ENTRY: MERGE RECONCILIATION 2026-09-13, 17,944/17,866 -> 17,863. drain/decision-closure and drain/breaking-line-contradiction each lowered from the SAME 17,947 base in parallel -- this branch to 17,944 (net -3: the ownership vocabulary, its two Iron-Law sets and the merged default-mode map moved out of ai_council/config.ts into ai_council/ownership_classes.ts, and the settings-rename block moved out of _lib/agent_settings.ts into _lib/settings_renamed_keys.ts, both UNDER the 1500 cap so both cost nothing) and main to 17,866. Taking either side alone is wrong in a different direction, which is the doctrine this entry already carries from 2026-09-03 and 2026-09-07: main's value silently discards this branch's earned -3, and this branch's value RAISES the baseline against main and weakens the gate. The committed number is neither -- it is the gate's own output on the MERGED tree, where both reductions apply. MAIN-SIDE ENTRY, carried so neither branch's record is lost: Lowered 17,947 -> 17,866 on 2026-09-13 by drain/breaking-line-contradiction, on this entry's own doctrine. The branch adds the BACKWARD half of the MIGRATION.md obligation -- a refusal for a major cut whose BREAKING section has no migration entry -- and writing it into release.ts came in at +61, because that file sits ~375 lines PAST the 1500 cap so every line there is one unit. Paid down rather than baselined, and the move was the coherent unit rather than the minimum one: BOTH refusals went, the new backward half and the pre-existing forward half (assert_scheduled_deprecations_clear), into _lib/release_migration_gate.ts at 184 lines and therefore UNDER the cap, so the pair and all their rationale now cost nothing. They moved on merit rather than only on arithmetic -- they are the two halves of one obligation, written eleven months apart, and release.ts held only the two call sites. parse_version stayed module-private in release.ts and the lib carries a two-line _minor_patch instead: exporting a private helper to serve one caller would widen the surface of the file the move exists to narrow. release.ts 1,875 -> 1,733: a branch that ADDED a pipeline refusal leaves the file eighty-one lines shorter than it found it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports nothing staged and nothing untracked at this commit, so a clean CI checkout measures the same 17,866. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises -- which is how CI found it: the gate exited 0 with a loose-ratchet warning and the test went red. PRIOR ENTRY: Lowered 17,959 -> 17,947 on 2026-09-11 by the findings-ledger branch, on this entry's own doctrine. The branch adds step 7 to release.ts, which sits ~326 lines PAST the 1500 cap so every line there is one unit, and it came in at +145. Paid down rather than baselined, in two moves. `settle_findings_ledger` and `_blocking_without_disposition` moved out of release.ts into _lib/release_findings_ingest.ts -- 95 lines, and that module is under the cap, so the step and its rationale now cost nothing. It moved on merit rather than only on arithmetic: the module already owns every message the step prints and every argv it builds, and release.ts held only the sequencing. Then the `--ci` fallback dispatch of the three tag-triggered workflows -- 24 lines of loop and warning with no reader elsewhere in step 10 -- moved into _lib/release_tag_dispatch.ts, also under the cap. release.ts 1,826 -> 1,814: a branch that ADDED a pipeline step leaves the file twelve lines shorter than it found it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the branch's new src/ file staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,947. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,963 -> 17,959 on 2026-09-09 by feat/cdd-fidelity-council, on the same shape as the entry below and with the same discriminator. The branch's src-link rewrite (a blind review found 253 of 268 links under dist/agent-src/guidelines/ dead, because condense.ts folded only the docs/ prefixes and never (../)+src/rules|skills) came in at +15 excess: condense.ts sits ~1,208 lines PAST the 1500 cap, so every line there is one unit. Paid down rather than baselined, in the way this entry's doctrine prescribes. `_rewrite_body_links` and its two regex constants moved out of condense.ts into _lib/guidelines_lane.ts, 151 lines and therefore UNDER the cap, so the function and its prose now cost nothing. It moved on merit rather than only on arithmetic: every rule the rewriter applies is a statement about which source tree projects where, which is that module's own subject, and condense.ts held it only because that is where the projector lives. condense.ts 2,712 -> 2,708 net, after the one import line and the one call-site rename -- a branch that ADDED a rewrite rule leaves the file four lines shorter than it found it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the branch's new src/ files tracked and nothing untracked, so a clean CI checkout of this commit measures the same 17,959. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,973 -> 17,963 on 2026-09-08 by drain/graph-shipped-close. The branch registers five code-graph MCP tools (road-to-a-graph-that-is-shipped 4.1). Their five records and schemas are ~250 lines, and putting them in mcp_server/tools.ts -- which sits ~500 lines PAST the 1500 cap, so every line there is one unit -- would have cost ~250 excess. They live in mcp_server/graph_tools.ts instead (~280 lines, UNDER the cap, so they and their prose cost nothing), and tools.ts spreads them into ALLOWLIST in two lines: one import and one `...GRAPH_TOOLS,`. Those two were paid for rather than baselined, in the way this entry's doctrine prescribes: `_strip` and `_resolvePath` -- a whitespace trim and a tolerant realpath, generic by nature -- moved out of tools.ts into mcp_server/path_util.ts, also under the cap. They are imported under their original underscore names, so all 28 call sites are unchanged and a two-function move does not read as a sweep. tools.ts 2,025 -> 2,015: -12 from the extraction, +2 from the registration, net -10 for a branch that ADDED a feature. CORRECTED 2026-09-08 after an independent review checked the figure against the tree -- this sentence read '2,025 -> 2,013, net -12, against the +2 the registration needed', which states an intermediate file length as the final one and leaves the arithmetic (-12) and the conclusion (-10) describing different trees. `git show origin/main:...tools.ts | wc -l` is 2025 and the working tree is 2015. The TOTAL, 17,963, was always the gate's own output and is unchanged. Every other file this branch touches or creates -- code_graph/verbs.ts, code_graph/cli.ts, code_graph/build.ts, code_graph/detect.ts, code_graph/query.ts, code_graph/sqlite_store.ts, code_graph/types.ts, _lib/regression_neighbourhood.ts -- is under the 1500 ceiling before and after, so it contributes zero excess whatever it grew by. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the two new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,963. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,974 -> 17,973 on 2026-09-08 by drain/topology-c1. The branch adds a live-path emit to council_cli.ts, which sits 2,454 lines PAST the 1500 cap so every line there is one unit, and paid its own way down rather than raising the baseline, in the way this entry's doctrine prescribes. The twelve-line `all_responses` assembly (a spread, three conditionals and a push) moved out of council_cli.ts into ai_council/deliberation_metrics.ts::runCallsFrom, 353 lines and therefore UNDER the cap, so the six stage labels and their prose cost nothing. It moved on merit rather than only on arithmetic: 'which calls did this run make, and at which stage' is that module's own subject, and the CLI held the list only as a flat array with the stage boundaries implicit in the order -- both readings now come out of one walk, so the billing total and the attribution can never be computed over different sets. council_cli.ts 3,955 -> 3,954 net, after the two call lines, the import and the one payload key the feature needed. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the two new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,973. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 18,016 -> 17,974 on 2026-09-07 by fix/single-delivery-unconditional. SETTLED FIGURE, and it supersedes an intra-session 17,962 this same branch committed earlier — read the direction against MAIN, which is what the ratchet protects: main is 18,016, the branch leaves 17,974, net -42. The 17,962 was this branch's own low before a neutral review returned twelve findings; fixing them added a real mechanism to mcp_server and condense.ts (the flat-wrapper carriage gate the review showed was missing, plus its four-skip predicate), and condense.ts sits ~1,215 lines PAST the cap so each of those lines is one unit. Paid down first, in the way this entry's doctrine prescribes: _suggestSkillForTaskHandler and its 18-line docstring moved out of mcp_server/tools.ts (2,079 -> 2,025) into mcp_server/suggest_skill.ts, 72 lines and UNDER the cap, so its prose costs nothing. The residual +12 against the intra-session low is the gate's own output on the settled tree and is recorded rather than engineered away, because the alternative was extracting _nested_command_subpath and its two callers out of condense.ts - which needs MODULE_STATE, _relativeToPosix and _domains_command_logical passed in, a wider diff than the finding warrants and one no review asked for. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the three new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,974. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: MERGE RECONCILIATION 2026-09-07, 18,061/18,017 -> 18,016. drain/admissible-council-seats and fix/release-obligation-answerable each lowered from the SAME 18,062 base in parallel — main to 18,061 (net -1: curlJsonPost, the seat-status helpers and the per-seat config parsing moved out of the three over-ceiling council files) and the branch to 18,017 (net -45: the /dev/tty prompt helpers moved out of release.ts into _lib/tty_prompt.ts, 76 lines and UNDER the cap, taking release.ts 1871 -> 1826). Taking either side alone is wrong in a different direction, which is the reconciliation doctrine this entry already carried from 2026-09-03: main's value silently discards the branch's earned -45, and the branch's value RAISES the baseline against main and weakens the gate. The committed number is neither — it is the gate's own output on the MERGED tree, where both reductions apply, and it equals the arithmetic (18,062 - 45 - 1 = 18,016) rather than being reconciled by it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports ZERO untracked files, so a clean CI checkout of this commit measures the same 18,016. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in the merge commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 18,062 -> 18,061 on 2026-09-07 by drain/admissible-council-seats. The branch's own additions to the three over-ceiling files (ai_council/config.ts, council_cli.ts, ai_council/clients.ts) came in at +96 excess and were paid down to -1 rather than baselined, in the four ways this entry's doctrine prescribes: `curlJsonPost` moved out of clients.ts into ai_council/api_transport.ts (UNDER the cap, so the prose and the three new provider shims cost nothing); the seat-status helpers moved out of council_cli.ts into ai_council/status_surface.ts, taking an orphaned doc comment with them; the three new per-seat config fields' parsing moved out of config.ts into ai_council/seat_policy.ts::parseSeatFields; and three prose blocks that the branch's own transport repair made FACTUALLY FALSE (the `openai` / `google-genai` Python-SDK claims, and a `_curlJsonPost` pointer to a function that had moved) were corrected and shortened in the same change. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports zero untracked files with the five new src/ files staged, so a clean CI checkout of this commit measures the same 18,061. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried here because tests/scripts/check_source_size_budget.test.ts:166 asserts baseline == live and therefore blocks where the gate only advises -- the lowering commit must carry its own baseline update. Lowered 18,068 -> 18,062 on 2026-09-06 by drain/host-enforcement-truth. Collapsing the five per-host binding constants in install.ts into src/scripts/hooks/host_lowering.yaml removed 29 lines from a file ~3,900 past the 1500 cap, where every line costs one excess; the journal's surface column and its extracted migration helper gave 23 back. Lowered 18,245 -> 18,230 on 2026-09-02 by drain/publication-integrity-option-a. Phase 2 Option A moved the authoring instruction out of the generator: release.ts, which sits ~530 lines PAST the 1500 cap so every line there costs one excess, loses the comment emission, a 16-line HEAD_DEFAULT doc block and its alias const, and gains a shorter writer docstring. The doc block moved to _lib/release_material.ts, which is 289 lines and therefore UNDER the cap, so the same prose now costs nothing. Net -15. The branch first came in at +8 and paid its own way down rather than raising the baseline. BRANCH-SIDE ENTRY: Lowered 17,947 -> 17,944 on 2026-09-13 by drain/decision-closure, on this entry's own doctrine and at the gate's own request. The branch's ownership-axis additions to ai_council/config.ts came in at +86 excess: that file sits ~700 lines PAST the 1500 cap, so every line there is one unit. Paid down rather than baselined, in one move. The eight ownership class names, the two Iron-Law sets, the merged default-mode map and the mode-check function moved out of config.ts into ai_council/ownership_classes.ts -- 91 lines, UNDER the cap, so the vocabulary and its prose now cost nothing. It moved on merit rather than only on arithmetic: the roadmap-side gate lint_decision_classes needs the same eight names and has no business importing the council's whole schema to learn them, and the loader now carries three lines where it carried twenty-four. config.ts 2,182 -> 2,179: a branch that ADDED an entire decision axis leaves the file three lines shorter than it found it. Every other src/ file this branch creates -- lint_decision_classes.ts, lint_roadmap_producers.ts, closure_scan.ts, council_record_shape.ts, scope_growth.ts, ownership_classes.ts -- is under the 1500 ceiling, so it contributes zero excess whatever it grew by. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the branch's new src/ files tracked and nothing untracked, so a clean CI checkout of this commit measures the same 17,944. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,959 -> 17,947 on 2026-09-11 by the findings-ledger branch, on this entry's own doctrine. The branch adds step 7 to release.ts, which sits ~326 lines PAST the 1500 cap so every line there is one unit, and it came in at +145. Paid down rather than baselined, in two moves. `settle_findings_ledger` and `_blocking_without_disposition` moved out of release.ts into _lib/release_findings_ingest.ts -- 95 lines, and that module is under the cap, so the step and its rationale now cost nothing. It moved on merit rather than only on arithmetic: the module already owns every message the step prints and every argv it builds, and release.ts held only the sequencing. Then the `--ci` fallback dispatch of the three tag-triggered workflows -- 24 lines of loop and warning with no reader elsewhere in step 10 -- moved into _lib/release_tag_dispatch.ts, also under the cap. release.ts 1,826 -> 1,814: a branch that ADDED a pipeline step leaves the file twelve lines shorter than it found it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the branch's new src/ file staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,947. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,963 -> 17,959 on 2026-09-09 by feat/cdd-fidelity-council, on the same shape as the entry below and with the same discriminator. The branch's src-link rewrite (a blind review found 253 of 268 links under dist/agent-src/guidelines/ dead, because condense.ts folded only the docs/ prefixes and never (../)+src/rules|skills) came in at +15 excess: condense.ts sits ~1,208 lines PAST the 1500 cap, so every line there is one unit. Paid down rather than baselined, in the way this entry's doctrine prescribes. `_rewrite_body_links` and its two regex constants moved out of condense.ts into _lib/guidelines_lane.ts, 151 lines and therefore UNDER the cap, so the function and its prose now cost nothing. It moved on merit rather than only on arithmetic: every rule the rewriter applies is a statement about which source tree projects where, which is that module's own subject, and condense.ts held it only because that is where the projector lives. condense.ts 2,712 -> 2,708 net, after the one import line and the one call-site rename -- a branch that ADDED a rewrite rule leaves the file four lines shorter than it found it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the branch's new src/ files tracked and nothing untracked, so a clean CI checkout of this commit measures the same 17,959. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,973 -> 17,963 on 2026-09-08 by drain/graph-shipped-close. The branch registers five code-graph MCP tools (road-to-a-graph-that-is-shipped 4.1). Their five records and schemas are ~250 lines, and putting them in mcp_server/tools.ts -- which sits ~500 lines PAST the 1500 cap, so every line there is one unit -- would have cost ~250 excess. They live in mcp_server/graph_tools.ts instead (~280 lines, UNDER the cap, so they and their prose cost nothing), and tools.ts spreads them into ALLOWLIST in two lines: one import and one `...GRAPH_TOOLS,`. Those two were paid for rather than baselined, in the way this entry's doctrine prescribes: `_strip` and `_resolvePath` -- a whitespace trim and a tolerant realpath, generic by nature -- moved out of tools.ts into mcp_server/path_util.ts, also under the cap. They are imported under their original underscore names, so all 28 call sites are unchanged and a two-function move does not read as a sweep. tools.ts 2,025 -> 2,015: -12 from the extraction, +2 from the registration, net -10 for a branch that ADDED a feature. CORRECTED 2026-09-08 after an independent review checked the figure against the tree -- this sentence read '2,025 -> 2,013, net -12, against the +2 the registration needed', which states an intermediate file length as the final one and leaves the arithmetic (-12) and the conclusion (-10) describing different trees. `git show origin/main:...tools.ts | wc -l` is 2025 and the working tree is 2015. The TOTAL, 17,963, was always the gate's own output and is unchanged. Every other file this branch touches or creates -- code_graph/verbs.ts, code_graph/cli.ts, code_graph/build.ts, code_graph/detect.ts, code_graph/query.ts, code_graph/sqlite_store.ts, code_graph/types.ts, _lib/regression_neighbourhood.ts -- is under the 1500 ceiling before and after, so it contributes zero excess whatever it grew by. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the two new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,963. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 17,974 -> 17,973 on 2026-09-08 by drain/topology-c1. The branch adds a live-path emit to council_cli.ts, which sits 2,454 lines PAST the 1500 cap so every line there is one unit, and paid its own way down rather than raising the baseline, in the way this entry's doctrine prescribes. The twelve-line `all_responses` assembly (a spread, three conditionals and a push) moved out of council_cli.ts into ai_council/deliberation_metrics.ts::runCallsFrom, 353 lines and therefore UNDER the cap, so the six stage labels and their prose cost nothing. It moved on merit rather than only on arithmetic: 'which calls did this run make, and at which stage' is that module's own subject, and the CLI held the list only as a flat array with the stage boundaries implicit in the order -- both readings now come out of one walk, so the billing total and the attribution can never be computed over different sets. council_cli.ts 3,955 -> 3,954 net, after the two call lines, the import and the one payload key the feature needed. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the two new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,973. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 18,016 -> 17,974 on 2026-09-07 by fix/single-delivery-unconditional. SETTLED FIGURE, and it supersedes an intra-session 17,962 this same branch committed earlier — read the direction against MAIN, which is what the ratchet protects: main is 18,016, the branch leaves 17,974, net -42. The 17,962 was this branch's own low before a neutral review returned twelve findings; fixing them added a real mechanism to mcp_server and condense.ts (the flat-wrapper carriage gate the review showed was missing, plus its four-skip predicate), and condense.ts sits ~1,215 lines PAST the cap so each of those lines is one unit. Paid down first, in the way this entry's doctrine prescribes: _suggestSkillForTaskHandler and its 18-line docstring moved out of mcp_server/tools.ts (2,079 -> 2,025) into mcp_server/suggest_skill.ts, 72 lines and UNDER the cap, so its prose costs nothing. The residual +12 against the intra-session low is the gate's own output on the settled tree and is recorded rather than engineered away, because the alternative was extracting _nested_command_subpath and its two callers out of condense.ts - which needs MODULE_STATE, _relativeToPosix and _domains_command_logical passed in, a wider diff than the finding warrants and one no review asked for. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports the three new src/ files staged and nothing untracked, so a clean CI checkout of this commit measures the same 17,974. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in this commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: MERGE RECONCILIATION 2026-09-07, 18,061/18,017 -> 18,016. drain/admissible-council-seats and fix/release-obligation-answerable each lowered from the SAME 18,062 base in parallel — main to 18,061 (net -1: curlJsonPost, the seat-status helpers and the per-seat config parsing moved out of the three over-ceiling council files) and the branch to 18,017 (net -45: the /dev/tty prompt helpers moved out of release.ts into _lib/tty_prompt.ts, 76 lines and UNDER the cap, taking release.ts 1871 -> 1826). Taking either side alone is wrong in a different direction, which is the reconciliation doctrine this entry already carried from 2026-09-03: main's value silently discards the branch's earned -45, and the branch's value RAISES the baseline against main and weakens the gate. The committed number is neither — it is the gate's own output on the MERGED tree, where both reductions apply, and it equals the arithmetic (18,062 - 45 - 1 = 18,016) rather than being reconciled by it. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports ZERO untracked files, so a clean CI checkout of this commit measures the same 18,016. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried in the merge commit because tests/scripts/check_source_size_budget.test.ts asserts baseline == live and therefore BLOCKS where the gate only advises. PRIOR ENTRY: Lowered 18,062 -> 18,061 on 2026-09-07 by drain/admissible-council-seats. The branch's own additions to the three over-ceiling files (ai_council/config.ts, council_cli.ts, ai_council/clients.ts) came in at +96 excess and were paid down to -1 rather than baselined, in the four ways this entry's doctrine prescribes: `curlJsonPost` moved out of clients.ts into ai_council/api_transport.ts (UNDER the cap, so the prose and the three new provider shims cost nothing); the seat-status helpers moved out of council_cli.ts into ai_council/status_surface.ts, taking an orphaned doc comment with them; the three new per-seat config fields' parsing moved out of config.ts into ai_council/seat_policy.ts::parseSeatFields; and three prose blocks that the branch's own transport repair made FACTUALLY FALSE (the `openai` / `google-genai` Python-SDK claims, and a `_curlJsonPost` pointer to a function that had moved) were corrected and shortened in the same change. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the 1500-line ceiling, and `git status --porcelain -uall -- src/` reports zero untracked files with the five new src/ files staged, so a clean CI checkout of this commit measures the same 18,061. If CI reads anything else, CI's number is the correct one and this note is the record of why. Carried here because tests/scripts/check_source_size_budget.test.ts:166 asserts baseline == live and therefore blocks where the gate only advises -- the lowering commit must carry its own baseline update. Lowered 18,068 -> 18,062 on 2026-09-06 by drain/host-enforcement-truth. Collapsing the five per-host binding constants in install.ts into src/scripts/hooks/host_lowering.yaml removed 29 lines from a file ~3,900 past the 1500 cap, where every line costs one excess; the journal's surface column and its extracted migration helper gave 23 back. Lowered 18,245 -> 18,230 on 2026-09-02 by drain/publication-integrity-option-a. Phase 2 Option A moved the authoring instruction out of the generator: release.ts, which sits ~530 lines PAST the 1500 cap so every line there costs one excess, loses the comment emission, a 16-line HEAD_DEFAULT doc block and its alias const, and gains a shorter writer docstring. The doc block moved to _lib/release_material.ts, which is 289 lines and therefore UNDER the cap, so the same prose now costs nothing. Net -15. The branch first came in at +8 and paid its own way down rather than raising the baseline.",
40
40
  "reason": "Lowered 18,230 -> 18,209 on 2026-09-03 by drain/artifact-location. `doctor --strict` needed 16 lines of integration wiring in cmd_doctor.ts, which sits ~2,100 lines PAST the 1500 cap so every line there costs one excess. The branch first came in at +137 and paid its own way down rather than raising the baseline: the strict semantics, threshold, kill switch, payload helper and argv fragments moved to _cli/_doctor_strict.ts (~160 lines, under the cap, costs nothing), taking it to +15; then the 37-line drift renderer moved to _cli/_doctor_emit.ts. Net -21. The renderer was chosen deliberately: pure rendering, two dependencies, no argparse involvement and therefore none of the byte-parity risk the parser surface carries against the retired Python implementation; nothing outside cmd_doctor.ts imported it. An AI council on the residual split (a: raise by 15 / d: descope the feature); neither was taken, because a parallel branch demonstrated the same day that paying down is achievable in this codebase, which is the evidence the split lacked. This gate's own test comment prescribes it: a commit that splits a god-file lowers the excess and must carry the lowered baseline. MERGE RECONCILIATION 2026-09-03, 18,209 -> 18,205: drain/wired-instruments and drain/artifact-location each lowered from the SAME 18,230 base in parallel -- the branch to 18,226 (net -4, run_continuation_hook.ts's termination ladder moved to _lib/continuation_ladder.ts and runtime_journal.ts's prose to _lib/outcome_vocabularies.ts, both under the cap) and main to 18,209 (net -21, the doctor --strict split above). Taking either side alone is wrong in a different direction: main's value silently discards the branch's earned -4, and the branch's value RAISES the baseline against main and weakens the gate. The committed number is neither -- it is the gate's own output on the merged tree, where both reductions apply. THIS LOCAL READING IS ADMISSIBLE HERE, and the discriminator matters because this file's ci-parity:local-only entry records a 165 -> 164 lowering that was reverted for exactly the opposite case: that count depends on how the environment resolves the projection surface, whereas this gate walks only SOURCE_ROOTS = ['src'] (check_source_size_budget.ts:88) counting excess lines over the 1500 ceiling, and `git status --porcelain -uall -- src/` reported ZERO untracked files, so a clean CI checkout of this commit measures the same 18,205. If CI reads anything else, CI's number is the correct one and this note is the record of why. LOWERED 18,205 -> 18,193 on 2026-09-03 by fix/release-curation-ask. The change adds a fifth publication guard, and its own additions landed at +10 excess: release.ts 2,008 -> 2,018, every line of which is past the 1500 cap. Paid down rather than baselined, in the two ways this gate's doctrine prescribes. The guard's rationale (~13 lines of docstring, including why prMerged is a parameter rather than a call-site if) lives in release_publication.ts, 915 lines and therefore UNDER the cap, so the prose costs nothing; and the two pure text helpers _splitlines and _rstrip moved out of release.ts into release_env.ts (333 lines, also under the cap), taking release.ts to 1,996 -- 12 BELOW where it started. The branch came in at +10 and leaves at -12. Recorded while moving them: _splitlines is duplicated a third and fourth time at adoption_report.ts:106 and readme_linter.ts:418; collapsing all three onto one definition touches three modules and was left out of this change rather than done silently. LOWERED 18,193 -> 18,180 on 2026-09-03 by fix/release-branch-reuse. The step-1 branch decision -- twenty lines of if/else in release.ts -- became one call to checkout_release_branch in release_publication.ts, which is 1,019 lines and therefore UNDER the 1500 cap, so the twenty lines plus a ~35-line rationale now cost nothing. release.ts 1,996 -> 1,983, every one of those lines being past the cap. The drill grew 765 -> 918 for two new scenarios and the snapshot/restore that keeps them from writing the real CHANGELOG, and it is under the cap too. A change that adds a feature and lowers the excess is the shape this gate's doctrine asks for; the alternative was a +13 raise for logic that had no business in the god-file. LOWERED 18,180 -> 18,068 on 2026-09-05 by fix/release-gate-producer-parity. The change wires the governance-mix obligation into the writer and the two local guards and adds a release-gate locality registry; its own additions to release.ts landed at +19 excess, every one of those lines past the 1500 cap. Paid down rather than baselined, in the way this entry's doctrine prescribes: the 132-line test-count-trend unit (_TEST_COUNT_LINE_RE, _TEST_LIST_MAX_BUFFER, _count_from_list_result, _count_tests_current, _previous_test_count_from_changelog, _render_test_trend_line) moved from release.ts into release_publication.ts, which is under the cap and where it now belongs on merit rather than only on arithmetic -- the same diff makes the missing `Tests: N` footer a section-level publication blocker, so the writer that emits the footer and the guard that refuses its absence sit in one module. release.ts 1,983 -> 1,871. All four names are re-exported from release.ts, so tests/scripts/release.test.ts is unchanged. LOCAL READING, ADMISSIBLE ON THIS ENTRY'S OWN DISCRIMINATOR: the gate walks only SOURCE_ROOTS=['src'] counting excess over the ceiling, and `git status --porcelain -uall -- src/` reports ZERO untracked files with the two new src/ files staged, so a clean CI checkout of this commit measures the same 18,068. If CI reads anything else, CI's number is the correct one and this note is the record of why."
41
41
  },
42
42
  "ci-parity:local-only": {
@@ -52,9 +52,9 @@
52
52
  "falsifier": "./scripts-run src/scripts/check_gate_coverage"
53
53
  },
54
54
  "lint_canonical_terms": {
55
- "count": 1005,
56
- "landed": "2026-09-08",
57
- "note": "Lowered 1006 -> 1005 on 2026-09-08 by drain/graph-shipped, on the same shape as the entry below and with the same discriminator. This branch's payload migration moved a See-also line carrying `artefact` from the rule into the code-intelligence skill; keeping the word in both places would have RAISED the count, so both occurrences were written canonical LINE-SCOPED — only lines this diff authored, never a file-wide sweep. One of the two is a genuine reduction. The gate reported the tree at 1005 against a baseline of 1006 and asked for exactly this lowering. `landed` is refreshed for the reason the prior entry records: checkRatchet returns `improved` before it evaluates staleness, so an entry left high never expires. PRIOR ENTRY: Lowered 1007 -> 1006 on 2026-09-07 by drain/observed-learning-signal, and the gain was INCIDENTAL rather than sought: the branch's own new prose introduced five house-dialect occurrences under src/ and docs/ (four `artefact`/`artefacts`, one `behaviour`), which were rewritten LINE-SCOPED — only lines this diff authored, never a file-wide sweep, because `sweep_authorised: false` is still a live constraint. Four of the five were net-neutral (they replaced deleted lines carrying the same word) and one was a genuine reduction. The gate reported the tree at 1006 against a baseline of 1007 and asked for exactly this lowering, so the gain cannot be silently given back. LOCAL READING, ADMISSIBLE ON THE SAME DISCRIMINATOR THIS FILE'S check_source_size_budget ENTRY USES: the gate walks only authored prose under src/ and docs/, and `git status --porcelain -uall -- src docs` reported ZERO untracked files, so a clean CI checkout of this commit measures the same 1006. If CI reads anything else, CI's number is the correct one and this note is the record of why. `landed` is refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at 1007 while the tree measures 1006 would never expire at any age. PRIOR ENTRY: House-dialect debt in authored prose under src/ and docs/, measured by the gate this entry governs (road-to-canonical-terms 2.2). NOT a dead-root repair: the gate is new, and the debt is the corpus that predates the dialect decision recorded in src/config/canonical-terms.yml. A hard-zero gate was refused on the same ground the AI council refused an unconditional sweep on 2026-08-25. The ratchet IS the council's staged promotion: report-only for existing debt, blocking for anything new. What remains is dominated by two large-radius pairs — `artefact`->`artifact` and `behaviour`->`behavior` — plus `hand-off`->`handoff` and `licence`->`license`, the last of which the map flags `semantic-care-required` because licence TITLES are protected text. Shrink-only from here. Full classified inventory: agents/evidence/analysis/canonical-terms-inventory-2026-08-26.md.",
55
+ "count": 1004,
56
+ "landed": "2026-09-13",
57
+ "note": "Lowered 1005 -> 1004 on 2026-09-13 by drain/adversarial-verification, on the same shape and the same discriminator as every entry below. That branch added a routed rule and then paid its per-spawn payload cost by migrating argument prose out of three standing rules (autonomous-execution, delegation-policy, evaluator-independence) into their context and guideline files under the P4 pattern. Nothing was deleted and nothing was swept: the migrated lines were REWRITTEN CANONICAL where the diff authored them, LINE-SCOPED, because `sweep_authorised: false` is still a live constraint. Most were net-neutral -- they replaced deleted lines carrying the same word -- and one is a genuine reduction. The gate reported the tree at 1004 against a baseline of 1005 and asked for exactly this lowering, so the gain cannot be silently given back. LOCAL READING, ADMISSIBLE ON THE SAME DISCRIMINATOR THE ENTRIES BELOW USE: the gate walks only authored prose under src/ and docs/, and a porcelain status over those two roots reported ZERO untracked files, so a clean CI checkout of this commit measures the same 1004. If CI reads anything else, CI's number is the correct one and this note is the record of why. `landed` is refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at 1005 while the tree measures 1004 would never expire at any age. PRIOR ENTRY: Lowered 1006 -> 1005 on 2026-09-08 by drain/graph-shipped, on the same shape as the entry below and with the same discriminator. This branch's payload migration moved a See-also line carrying `artefact` from the rule into the code-intelligence skill; keeping the word in both places would have RAISED the count, so both occurrences were written canonical LINE-SCOPED — only lines this diff authored, never a file-wide sweep. One of the two is a genuine reduction. The gate reported the tree at 1005 against a baseline of 1006 and asked for exactly this lowering. `landed` is refreshed for the reason the prior entry records: checkRatchet returns `improved` before it evaluates staleness, so an entry left high never expires. PRIOR ENTRY: Lowered 1007 -> 1006 on 2026-09-07 by drain/observed-learning-signal, and the gain was INCIDENTAL rather than sought: the branch's own new prose introduced five house-dialect occurrences under src/ and docs/ (four `artefact`/`artefacts`, one `behaviour`), which were rewritten LINE-SCOPED — only lines this diff authored, never a file-wide sweep, because `sweep_authorised: false` is still a live constraint. Four of the five were net-neutral (they replaced deleted lines carrying the same word) and one was a genuine reduction. The gate reported the tree at 1006 against a baseline of 1007 and asked for exactly this lowering, so the gain cannot be silently given back. LOCAL READING, ADMISSIBLE ON THE SAME DISCRIMINATOR THIS FILE'S check_source_size_budget ENTRY USES: the gate walks only authored prose under src/ and docs/, and `git status --porcelain -uall -- src docs` reported ZERO untracked files, so a clean CI checkout of this commit measures the same 1006. If CI reads anything else, CI's number is the correct one and this note is the record of why. `landed` is refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at 1007 while the tree measures 1006 would never expire at any age. PRIOR ENTRY: House-dialect debt in authored prose under src/ and docs/, measured by the gate this entry governs (road-to-canonical-terms 2.2). NOT a dead-root repair: the gate is new, and the debt is the corpus that predates the dialect decision recorded in src/config/canonical-terms.yml. A hard-zero gate was refused on the same ground the AI council refused an unconditional sweep on 2026-08-25. The ratchet IS the council's staged promotion: report-only for existing debt, blocking for anything new. What remains is dominated by two large-radius pairs — `artefact`->`artifact` and `behaviour`->`behavior` — plus `hand-off`->`handoff` and `licence`->`license`, the last of which the map flags `semantic-care-required` because licence TITLES are protected text. Shrink-only from here. Full classified inventory: agents/evidence/analysis/canonical-terms-inventory-2026-08-26.md.",
58
58
  "falsifier": "./scripts-run src/scripts/lint_canonical_terms"
59
59
  },
60
60
  "lint_handoffs": {
@@ -26,6 +26,8 @@
26
26
  "edit-shape_reason": "one advisory line naming the cheaper edit primitive (roadmap 5.2: budget row from day one - the economy nudge must not itself become an economy problem)",
27
27
  "reread-guard": 1024,
28
28
  "reread-guard_reason": "one advisory line naming the earlier read / ranged alternative (roadmap 6.1)",
29
+ "memory-recall": 768,
30
+ "memory-recall_reason": "ONE memory pointer per fire: the slug, one authored why-now clause, the absolute path, and the memory's OWN frontmatter description, truncated so the emission is provably under this number (`CAP_BYTES` in hooks/memory_recall_hook.ts is the same constant, enforced at emission by buildEmission rather than left to the bench to notice). Registered BELOW the 1024 default deliberately, for the reason `skill-route` gives for its 512: this row is the ceiling that keeps the concern a POINTER. A memory file in this store runs 1.5-6 kB, so a later change that starts injecting bodies fails the build instead of quietly multiplying the hottest slot in the manifest by ten. Measured emission over the four seeded rules on the real store: 356-768 B, one of the four hitting the cap and truncating its description (`hook-latency-gate-has-runner-variance`, whose own description is 517 B).",
29
31
  "session-eol": 1024,
30
32
  "session-eol_reason": "one recycle-advisory line, once per session past the committed threshold (road-to-token-economy-recycling 3.2); recording itself emits nothing",
31
33
  "skill-route": 512,
@@ -5,7 +5,7 @@
5
5
  "host_version": null,
6
6
  "transcript": null,
7
7
  "date": "2026-09-10",
8
- "reason": "UPDATED 2026-09-10. The premise of the earlier reason is now FALSE and the state is unchanged, which is the finding. That reason said the concern had emitted zero bytes in every session on record because `lean_projection.mode` resolved to `eager-all` throughout. It has now delivered: with `mode: delivery` set locally, a live Claude Code session (2.1.268) received 2 rule bodies / 7,685 B on `user_prompt_submit`, and later in the same session 4 bodies / 16,314 B. So delivery into a live model context is no longer the open question. AN INDEPENDENT READER — a fresh context that did not produce the turn — was given the transcript and a neutral three-way question, and returned ACTED, with a qualification it raised itself and which is why this row is NOT `observed-true`: \"the ACTED verdict rests on 'referring to its substance', not on 'doing something it asks for'\". The model quoted the injection's own byte count (a string the reader confirmed appears nowhere else in the transcript, so the reference is demonstrable) and treated the payload as an OBJECT OF STUDY. On the two delivered rules' actual obligations it returned NONE: no point in the turn surfaces a source discrepancy (`cross-source-consistency`) or classifies the prompt continuation-vs-interrupt (`user-interrupt-priority`). E3 asks for a model that VISIBLY ACTS ON a delivered body; citing that a body arrived is not that, and it is especially not that when the observed turn was one that had been WAITING for the delivery — which makes the reference cheap and is the K1 shape one layer further in. A STRUCTURAL LIMIT THE READER ALSO FOUND, and it bounds what any future attempt can prove: thinking blocks are recorded with length 0 in the transcript, so an internal application of a delivered rule is invisible by construction. Only externally visible behaviour can ever satisfy E3 here. The language pin delivered in the same payload is separately COINCIDENT rather than acted on — the prompt was German anyway, and the pin's own text concedes its trigger is not observable from the transcript."
8
+ "reason": "UPDATED 2026-09-10. The premise of the earlier reason is now FALSE and the state is unchanged, which is the finding. That reason said the concern had emitted zero bytes in every session on record because `lean_projection.mode` resolved to `eager-all` throughout. It has now delivered: with `mode: delivery` set locally, a live Claude Code session (2.1.268) received 2 rule bodies / 7,685 B on `user_prompt_submit`, and later in the same session 4 bodies / 16,314 B. So delivery into a live model context is no longer the open question. AN INDEPENDENT READER — a fresh context that did not produce the turn — was given the transcript and a neutral three-way question, and returned ACTED, with a qualification it raised itself and which is why this row is NOT `observed-true`: \"the ACTED verdict rests on 'referring to its substance', not on 'doing something it asks for'\". The model quoted the injection's own byte count (a string the reader confirmed appears nowhere else in the transcript, so the reference is demonstrable) and treated the payload as an OBJECT OF STUDY. On the two delivered rules' actual obligations it returned NONE: no point in the turn surfaces a source discrepancy (`cross-source-consistency`) or classifies the prompt continuation-vs-interrupt (`user-interrupt-priority`). E3 asks for a model that VISIBLY ACTS ON a delivered body; citing that a body arrived is not that, and it is especially not that when the observed turn was one that had been WAITING for the delivery — which makes the reference cheap and is the K1 shape one layer further in. A STRUCTURAL LIMIT THE READER ALSO FOUND, and it bounds what any future attempt can prove: thinking blocks are recorded with length 0 in the transcript, so an internal application of a delivered rule is invisible by construction. Only externally visible behaviour can ever satisfy E3 here. The language pin delivered in the same payload is separately COINCIDENT rather than acted on — the prompt was German anyway, and the pin's own text concedes its trigger is not observable from the transcript. UPDATED 2026-09-11. The state is UNCHANGED and the update is the round that tried hardest to change it. Four ordinary-work turns carrying live deliveries were mechanically selected from the whole transcript store and each judged by a fresh reader on a neutral four-question prompt: one clean NONE, two UNCLEAR, and one NONE on a packet whose rule body was truncated (recorded as defective rather than repaired quietly). Condition 1 was satisfied TWICE, so the bar is not unreachable; condition 2 failed 4/4, and in one candidate the delivered clause that would have CHANGED the outcome went unfollowed while the clause the agent had independent reason to follow was honoured. Full round, method and limits: agents/evidence/analysis/e3-candidate-round-2026-09-11.md. An AI council (2/2 convergent, 2026-09-11) amended E3 prospectively rather than lowering it: a predeclared externally observable obligation class is the admissible witness set, the four conditions stand unchanged, and an eventual observed-true is CLASS-SCOPED — it may not admit this host wholesale for reasoning-only rules. unobserved stays a RESULT here, not a gap. SUPERSEDED THE SAME DAY, AND THE SUPERSESSION IS THE POINT. The enumeration that amendment called for found a confound that makes the four verdicts non-identifying: 106 of 106 `type: auto` rules already carry a byte-equivalent obligation body in the same session unconditionally — 89 in the user-global rule layer, 3 differing by a single blank line, and the 14 maintainer-scoped ones inline in the system prompt. All ten rules judged in the four candidates are body-identical across both channels. So the injected copy adds no text, removing the injection does not remove the body, and the intervention varies one copy versus two rather than absent versus present. The corpus explanation and duplicate exposure fit the four results equally and nothing in the round separates them. Council round 3 (2/2 present, same day) split on the label — anthropic not-measurable-as-specified, openai continue-only-in-a-clean-environment — and converged on the terms: suspend condition-2 judgement wherever a second copy of the obligation exists, record an exposure audit over every auto-loaded channel before admitting a candidate, and require injection to be the SOLE source of the tested body. The residual measurable set in this repository is empty."
9
9
  },
10
10
  "_cursor_md_tree_loaded": {
11
11
  "state": "unobserved",
@@ -0,0 +1,215 @@
1
+ # Loop surfaces and the instruments they are meant to call.
2
+ #
3
+ # Read by `src/scripts/check_gate_reachability.ts` (the `_lib-export-reach`
4
+ # axis) via `src/scripts/_lib/loop_surfaces.ts`. NOTHING ELSE READS IT AND
5
+ # NOTHING EXECUTES FROM IT. The file is reader input: it adds no behaviour to
6
+ # any surface listed here, and the moment something dispatches off it, it has
7
+ # become the loop engine a recorded decision forbids.
8
+ #
9
+ # Why a separate file rather than a section in `hook_manifest.yaml`: that
10
+ # manifest is keyed on hook slots — every `concerns:` row carries `script`,
11
+ # `args`, `fail_closed`, `severity` and binds to a lifecycle event. Three of
12
+ # the five surfaces below have no hook slot at all (two skills and one
13
+ # execution context), so folding them in would mean inventing a row shape for
14
+ # a thing the manifest does not model. `src/config/` is where this tree
15
+ # already keeps gate-read configuration, and `check_gate_reachability.ts`
16
+ # already reads one of its files (`gate-reachability-exemptions.json`).
17
+ #
18
+ # ---------------------------------------------------------------------------
19
+ # surfaces: a thing that iterates under a bound.
20
+ #
21
+ # kind `code` (a TypeScript module) or `prose` (a skill / context doc)
22
+ # bound_kind `code` when cap + no_progress name symbols; `prose` when they
23
+ # name documented knobs. A prose bound is REPORTED, never red —
24
+ # but it may never masquerade as a code one, which is what this
25
+ # field exists to prevent.
26
+ # cap `path:TOKEN` — the maximum-iterations bound
27
+ # no_progress `path:TOKEN` — the non-advance detector
28
+ #
29
+ # `cap` and `no_progress` resolve or the gate reds: a `.ts` target must be a
30
+ # DEFINED symbol, a `.md` target must be a token the file actually carries.
31
+ # ---------------------------------------------------------------------------
32
+ surfaces:
33
+ run_continuation_hook:
34
+ kind: code
35
+ bound_kind: code
36
+ cap: src/scripts/_lib/continuation_ladder.ts:MAX_ITERATIONS
37
+ no_progress: src/scripts/_lib/loop_guards.ts:stallSignal
38
+ success_stop: >-
39
+ continuation_ladder.ts:ladder returns 'complete' when openCount === 0 and
40
+ blockedCount === 0; run_continuation_hook.ts:main clears the run state.
41
+ checker: >-
42
+ run_continuation_hook.ts:scanOpenSteps re-scans the claimed roadmap every
43
+ fire. It never EXECUTES a step's verify line — it only prints it.
44
+ human_gate: >-
45
+ none. The nearest thing is printed prose in _continuationText; the
46
+ refusedThisTurn check defers to a quality gate, not to a person.
47
+ terminal_vocabulary: src/scripts/_lib/continuation_ladder.ts:TERMINAL_STATE_BY_ACTION
48
+ production_consumers:
49
+ - src/scripts/hooks/concern_registry.ts
50
+ - src/scripts/hook_manifest.yaml
51
+
52
+ self_fix:
53
+ kind: code
54
+ bound_kind: code
55
+ cap: src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts:SELF_FIX_CEILING
56
+ no_progress: src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts:verdict_signature
57
+ success_stop: >-
58
+ none of its own, by design — the module is entered on a red and every exit
59
+ it owns is BLOCKED or PARTIAL. The green exit lives in its callers,
60
+ directives/backend/test.ts and directives/backend/verify.ts.
61
+ checker: >-
62
+ none inside the module — the caller supplies the recorded verdict, which
63
+ verdict_signature reduces to a comparable string.
64
+ human_gate: src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts:partial_exit
65
+ terminal_vocabulary: src/agent-src/templates/scripts/work_engine/directives/backend/_self_fix.ts:RUN_TERMINAL_BY_KIND
66
+ production_consumers:
67
+ - src/agent-src/templates/scripts/work_engine/directives/backend/test.ts
68
+ - src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts
69
+
70
+ verify_repair_loop:
71
+ kind: prose
72
+ bound_kind: prose
73
+ cap: src/skills/verify-repair-loop/SKILL.md:max_attempts
74
+ no_progress: src/skills/verify-repair-loop/SKILL.md:plateau_window
75
+ success_stop: >-
76
+ judge verdict `apply` ends the loop DONE. The numeric threshold gate is
77
+ not the exit — it only decides whether another attempt is authorised.
78
+ checker: >-
79
+ the project's verdict commands per toolchain-resolver, plus the
80
+ deterministic src/scripts/detect_verification_tampering.ts, plus a
81
+ fresh-context judge subagent.
82
+ human_gate: >-
83
+ hand-back only. Every terminus stops and hands the envelope to the user;
84
+ a mid-loop user instruction changes the fingerprint and aborts.
85
+ terminal_vocabulary: >-
86
+ RunTerminalState, named in the skill's Output format with its full value
87
+ set and a per-stop-reason mapping. Its local verdict
88
+ (DONE | DONE_WITH_CONCERNS | BLOCKED) is kept as the human-facing line;
89
+ `run_terminal` is the aggregatable one.
90
+ production_consumers:
91
+ - src/domains/engineering-base/review/changes/command.md
92
+ - src/domains/engineering-base/mission/upgrade/command.md
93
+
94
+ experiment_loop:
95
+ kind: prose
96
+ bound_kind: prose
97
+ cap: src/skills/experiment-loop/references/protocol.md:max_iterations
98
+ no_progress: src/skills/experiment-loop/references/protocol.md:consecutive_reverts
99
+ success_stop: >-
100
+ none — the skill has a direction, not a destination. Exit is symmetric:
101
+ the declared bound is reached, or the declared exit signal fires.
102
+ checker: >-
103
+ an external evaluator emitting the evaluator-output contract JSON. `pass`
104
+ is sovereign; the metric never is.
105
+ human_gate: >-
106
+ none. The pivot ladder's terminal rung publishes a null rather than
107
+ escalating to a person.
108
+ terminal_vocabulary: >-
109
+ RunTerminalState, named in the skill's Output format with its full value
110
+ set and a per-exit-condition mapping. The register's own decision enum
111
+ (pending | keep | revert) is per-iteration and stays local.
112
+ production_consumers:
113
+ - src/domains/meta/README.md
114
+
115
+ roadmap_process_loop:
116
+ kind: prose
117
+ bound_kind: code
118
+ cap: src/scripts/_lib/continuation_ladder.ts:MAX_ITERATIONS
119
+ no_progress: src/scripts/_lib/continuation_ladder.ts:STALL_WINDOW
120
+ success_stop: >-
121
+ count_open == 0 with the PR open. `blocked` is never presented as
122
+ completion and no checkbox is flipped to reach it.
123
+ checker: >-
124
+ the per-step `verify:` command when a step declares one, the
125
+ git-status flip guard, and the quality pipeline on the declared cadence.
126
+ human_gate: src/scripts/_lib/blocked_by_marker.ts:decideAsk
127
+ terminal_vocabulary: >-
128
+ reached through contexts/execution/terminal-states.md, which the document
129
+ names; it uses `approval-required` and `blocked` by name.
130
+ production_consumers:
131
+ - src/domains/product-basic/roadmap/process-full/command.md
132
+ - src/domains/product-basic/roadmap/process-phase/command.md
133
+ - src/domains/product-basic/roadmap/process-step/command.md
134
+
135
+ # ---------------------------------------------------------------------------
136
+ # instruments: an exported helper a surface is meant to CALL.
137
+ #
138
+ # The reach question applies only here. A surface is reached by being bound;
139
+ # an instrument is reached by being called, and only the second is answerable
140
+ # by counting occurrences of a symbol.
141
+ #
142
+ # An instrument is DEAD when its symbol appears in `src/` exactly once — its
143
+ # own declaration. `tests/` is outside `src/` and therefore outside the count
144
+ # by construction: a test-only caller is precisely the state this detects.
145
+ #
146
+ # status: experimental exempts it from the reach requirement
147
+ # expires: YYYY-MM-DD REQUIRED under that status; a past date reds the
148
+ # gate. An exemption without a deadline is the same
149
+ # dead code wearing a label.
150
+ # ---------------------------------------------------------------------------
151
+ instruments:
152
+ # --- The two open instances this inventory was built to make findable. ---
153
+ rejectedTacticRepeat:
154
+ file: src/scripts/_lib/loop_guards.ts
155
+ role: >-
156
+ Identity-keyed repeat suppression for run_continuation_hook. Catches what
157
+ the numeric stall detector cannot see: the same rejected tactic retried
158
+ while the surrounding prose changes every time.
159
+ status: experimental
160
+ expires: '2026-12-12'
161
+ note: >-
162
+ Deliberately not wired. Its only consumer would be the continuation hook,
163
+ and giving that hook a new refusal rung before it has demonstrably engaged
164
+ more than once reverses the order the evidence supports (roadmap Risk 2).
165
+ The observation it is waiting on is parked in
166
+ agents/roadmaps/later/road-to-run-continuation-observation.md. The expiry
167
+ is the date that question comes back, not a date this decision is
168
+ considered settled.
169
+
170
+ compareTriggers:
171
+ file: src/scripts/_lib/capsule_trigger.ts
172
+ role: >-
173
+ Shadow comparison of two capsule-emission arms — token watermark against
174
+ novelty saturation — reporting where each WOULD have fired.
175
+ status: experimental
176
+ expires: '2026-12-12'
177
+ note: >-
178
+ It cannot be wired today and faking it is forbidden by the tree's own
179
+ recorded position. It needs StepObservation[] — per-step token counts AND
180
+ per-step surfaced terms — and no payload this tree has observed carries
181
+ either. subagent_ledger_hook.ts says so in as many words, citing this very
182
+ module: "inventing a proxy is the move capsule_trigger.ts refuses".
183
+
184
+ earlierArm:
185
+ file: src/scripts/_lib/capsule_trigger.ts
186
+ role: Which of the two compareTriggers arms fired first, for the paired comparison.
187
+ status: experimental
188
+ expires: '2026-12-12'
189
+ note: Same input gap as compareTriggers — it consumes that function's output.
190
+
191
+ # --- Live instruments, declared so the axis is shown NOT over-firing. ---
192
+ # All three are called only from inside their own declaring file. A predicate
193
+ # that counted importers alone would report every one of them dead; that is
194
+ # the false-positive class the occurrence criterion exists to remove.
195
+ detectUnavailableDependency:
196
+ file: src/scripts/_lib/loop_guards.ts
197
+ role: Scans a transcript tail for an unavailable-dependency signal.
198
+
199
+ DEPENDENCY_SCAN_BYTES:
200
+ file: src/scripts/_lib/loop_guards.ts
201
+ role: How much of a transcript tail the dependency scan reads.
202
+
203
+ StallSignal:
204
+ file: src/scripts/_lib/loop_guards.ts
205
+ role: The shape stallSignal returns — level plus the window it was read over.
206
+
207
+ # Reached across files, the ordinary case. Declared so the axis is exercised
208
+ # on both sides of its own boundary rather than only on the interesting one.
209
+ stallSignal:
210
+ file: src/scripts/_lib/loop_guards.ts
211
+ role: Numeric non-advance detector — the open-step count over a window.
212
+
213
+ terminalStateFor:
214
+ file: src/scripts/_lib/continuation_ladder.ts
215
+ role: Maps a ladder action onto its RunTerminalState.
@@ -38,10 +38,11 @@
38
38
  }
39
39
  ],
40
40
  "accepted_risk_note": "THE FLOOR IS NOW TWO TIERS, and this file says so rather than implying otherwise. Six dimensions are hard \u2014 `NEVER_WAIVABLE` in `src/scripts/_lib/platform_anchor.ts`: enforcement, target, default-branch coverage, unconditional bypass, deletion and force-push. The rest are baseline expectations a complete, unexpired, owner-authorised waiver may trade against a documented operational benefit. Calling that 'the non-negotiable floor unchanged' would be false; it is a 6-dimension hard floor plus trade-offable dimensions with documentation requirements. WHY A THIRD STATE rather than deletion or a permanent red: deleting a dimension the repository still considers safer erases the difference between 'never expected' and 'expected and knowingly waived', while an enforced-and-red dimension makes the gate report a policy violation when the policy is what chose the configuration. openai: 'If noncompliance does not fail the gate, that dimension is not enforced for the duration of the waiver. It remains a baseline expectation subject to an active exception.' WHAT STOPS THIS BECOMING AN EXEMPTION REGISTRY, which both seats warned it would: eligibility is bounded by a committed list rather than by the quality of a waiver's prose; every field is required and an incomplete waiver is REFUSED rather than honoured, so the dimension it names reds normally; a waiver past `expires` is not honoured; and a waiver for a dimension the forge already satisfies is reported as stale. A malformed waiver is worse than no waiver, never better. DECIDED BY: the owner on the policy; an AI council (anthropic/claude-sonnet-4-5 + openai/codex-default, 2 rounds, blind peer review, 2/2 convergent) on this shape, which both seats reached after rejecting outright removal AND a permanent red.",
41
- "required_status_check_contexts_note": "The context that CARRIES the ratification gate, not the gate's own script name. `check_kernel_edit_ratified` is a STEP inside the `Sync + Generate Tools Consistency` job (`.github/workflows/consistency.yml:811-825`), and a GitHub required status check pins a job's reported context, never the steps inside it. This distinction is load-bearing and was corrected mid-decision: the council question asserted that the gate 'is not a required status check at all', which measurement then falsified \u2014 the containing job IS the ruleset's one required context. What survives the correction, and what the round-2 ratification review actually refused the deny-retirement over, is that pinning a job name does not pin its steps: a candidate branch may delete the gate's step and the job still reports the same context, green. A required context is therefore necessary and not sufficient, and this file asserts the necessary half.",
41
+ "required_status_check_contexts_note": "The context that CARRIES the ratification gate, not the gate's own script name. `check_kernel_edit_ratified` is a STEP inside the `Sync + Generate Tools Consistency` job (`.github/workflows/consistency.yml:811-825`), and a GitHub required status check pins a job's reported context, never the steps inside it. This distinction is load-bearing and was corrected mid-decision: the council question asserted that the gate 'is not a required status check at all', which measurement then falsified \u2014 the containing job IS a required context on the ruleset. (That clause read \u0060the ruleset's ONE required context\u0060 until 2026-09-13; it is now one of TWO \u2014 \u0060Standing payload delta + budget gate\u0060 was added on 2026-09-11. The correction does not touch the argument, which is about jobs versus steps, and the expectation naming only this context is still satisfied because \u0060minimum_required_contexts\u0060 is a floor.) What survives the correction, and what the round-2 ratification review actually refused the deny-retirement over, is that pinning a job name does not pin its steps: a candidate branch may delete the gate's step and the job still reports the same context, green. A required context is therefore necessary and not sufficient, and this file asserts the necessary half.",
42
42
  "owner_ruling_2026_09_10": "THE THREAT-MODEL QUESTION IS ANSWERED, and the answer removed two dimensions from this expectation rather than adding an exception for them. Owner ruling, 2026-09-10, quoted in substance and translated from German: 'I reset the settings deliberately. I am the only maintainer, or the main one. There are others, but they are rarely active. That is why this would be a blocker.' Measured: five accounts carry write access (four write/maintain, one admin), and the owner states the four are rarely available. So a mandatory approving review is not a control on this repository, it is a stop. WHAT THIS COST, stated because a green anchor must not be read as more than it is: `minimum_approving_reviews` and `require_last_push_approval` are gone from this file AND from `NON_NEGOTIABLE_FLOOR`, and they are NOT exemptions \u2014 a dimension outside the trust model is not a waived rule. The mechanism therefore proves nothing about independent human review, separation of duties, or protection against unilateral administrator action, and `docs/contracts/ratification-artifact.md` now says so in those words. WHO MAY DO THIS AGAIN: only the owner may AUTHORIZE a floor reduction; an agent may implement one. The distinguishable event is the owner's own review and merge of a conspicuously labelled trust-model change \u2014 not an agent's transcription of a chat message, and not a council record, which is evidence and never authorization. The verifier cannot authenticate that the owner meant it, and that limit is part of the record rather than hidden by it. THE BOUNDARY, which the mechanism cannot check: a floor reduction is legitimate only where the operating model CANNOT satisfy the floor \u2014 no second human exists \u2014 never where waiting is merely inconvenient. DECIDED BY: the owner on the policy; an AI council (anthropic/claude-sonnet-4-5 + openai/codex-default, 2 rounds each of two runs, blind peer review, 2/2 convergent on option (b)) on the implementation shape, which is council-decidable rather than owner-reserved. openai: 'Keeping those requirements hard-coded would make red mean the repository intentionally chose a different trust model, rather than the configured platform violated its policy. That is not a useful compliance signal.'",
43
43
  "strict_status_checks_note": "SUPERSEDED the same day by the owner's second ruling, and marked rather than left standing — its sibling `threat_model_note` was marked and this one was not, which a blind review filed as its own contradiction. `strict_required_status_checks` is now a BASELINE EXPECTATION covered by the waiver `arr-2026-09-10-strict-status-checks` above, so the gate reports PASS_WITH_ACCEPTED_RISK rather than reding on it, and it has left `NON_NEGOTIABLE_FLOOR` because a floored dimension is unwaivable by construction. Original text, which was true between 12:51 and the ruling: `strict_required_status_checks` STAYS in the enforced set and is currently NOT satisfied, which is deliberate. It read true before this work, true in the write of 2026-09-10, and false afterwards, and the owner's ruling covers reviewer availability rather than whether a branch may merge against a stale base \u2014 so it is collateral rather than part of the decision. Both council seats put it out of scope for the ruling and one added the constraint this file honours: approval of a trust-model change is NOT authorization to mutate the live ruleset, so nothing here was restored on the forge. The gate consequently reds on exactly this one dimension, which is a control pointing at a real gap nobody has argued for \u2014 the opposite of the noise a permanently unsatisfiable floor would have produced. Restoring it is one setting and needs no reviewer.",
44
- "threat_model_note": "SUPERSEDED IN PART by `owner_ruling_2026_09_10` above, and kept because a superseded record reads differently from a deleted one \u2014 this is what the question looked like while it was open. Its unconditional-bypass half still stands and is still enforced: `bypass_actors` was emptied on 2026-09-10 and that change held through the revert of the two approval dimensions. Original text follows. UNRESOLVED, and named rather than assumed. openai/codex-default made this an explicit condition: the contract must state whether repository administrators are inside the threat model. Measured 2026-09-10, `bypass_actors` carries `{actor_type: RepositoryRole, actor_id: 5, bypass_mode: always}` and the acting account reports `current_user_can_bypass: always`, so every rule above is advisory for that actor. `allow_unconditional_bypass: false` records the council's answer for the mechanism's own surface \u2014 an unconditional bypass actor is a FAILURE \u2014 but whether the owner intends administrators as a deliberate root-of-trust escape hatch is an owner question this file cannot answer. Until it is answered the mechanism supplies process evidence, not a platform-enforced guarantee, which is what `docs/contracts/ratification-artifact.md` now says.",
44
+ "threat_model_note": "SUPERSEDED IN PART by `owner_ruling_2026_09_10` above, and kept because a superseded record reads differently from a deleted one \u2014 this is what the question looked like while it was open. Its unconditional-bypass half still stands and is still enforced, and the history is NOT the uninterrupted one this sentence used to claim \u2014 corrected 2026-09-13 against the ruleset version history rather than against memory. `bypass_actors` was emptied on 2026-09-10 and that change held through the revert of the two approval dimensions; it then did NOT hold, because an `OrganizationAdmin` actor with `bypass_mode: always` was re-added on 2026-09-11 (version `49393554`, the edit `ADR-276` records) and removed again on 2026-09-12 (version `49500777`). Live on 2026-09-13: `bypass_actors: []`, `current_user_can_bypass: never` \u2014 so the half stands TODAY and stood for all but one day, and saying 'held' without that gap would have been the convenient reading rather than the measured one. A verifier reads the forge, never this sentence; the sentence exists so a human reviewer knows the dimension has a re-entry history and is worth re-measuring rather than assuming. Original text follows. UNRESOLVED, and named rather than assumed. openai/codex-default made this an explicit condition: the contract must state whether repository administrators are inside the threat model. Measured 2026-09-10, `bypass_actors` carries `{actor_type: RepositoryRole, actor_id: 5, bypass_mode: always}` and the acting account reports `current_user_can_bypass: always`, so every rule above is advisory for that actor. `allow_unconditional_bypass: false` records the council's answer for the mechanism's own surface \u2014 an unconditional bypass actor is a FAILURE \u2014 but whether the owner intends administrators as a deliberate root-of-trust escape hatch is an owner question this file cannot answer. Until it is answered the mechanism supplies process evidence, not a platform-enforced guarantee, which is what `docs/contracts/ratification-artifact.md` now says.",
45
+ "enforcement_boundary_note": "WHAT THIS GATE IS, STATED BEFORE ANYONE READS A GREEN VERDICT AS MORE THAN IT IS. `check_platform_anchor` is a LOCAL, VOLUNTARILY INVOKED pre-push control. It runs in `taskfiles/ci-fast.yml` \u2014 in `preflight` and as its own target \u2014 and in NO workflow, because the rulesets endpoint needs the repository `administration` permission, which is not an available workflow `GITHUB_TOKEN` scope. Two consequences, both of which limit the claims this file may support. FIRST: an administrator may merge without ever invoking it. SECOND, and sharper: the acting account holds `admin: true`, so the same party can modify BOTH SIDES of the comparison \u2014 the expectation committed here and the forge state it is compared against. openai/codex-default, reviewing the shipped mechanism on 2026-09-13: 'a voluntarily invoked local check is advisory control, especially when the acting account is an administrator', and its explicit instruction, which this field exists to honour: DO NOT DESCRIBE `check_platform_anchor` AS ENFORCING REPOSITORY-WIDE COMPLIANCE. What it does establish is narrower and still worth having: that at the moment someone ran it, the committed expectation and the live ruleset agreed, and that any disagreement was either a hard floor violation or a recorded, dated, owner-authorised waiver. WHAT WOULD CHANGE THIS ASSESSMENT, in openai's own terms: evidence of mandatory execution from an independently controlled environment, with read-only policy inputs and suitable forge credentials. None of that exists today. NOT A SCHEMA CHANGE: this is a prose field alongside the other `*_note` fields, and the EVALUATED field set is untouched, so `schema_version` stays 2 \u2014 the 1 \u2192 2 bump was for a change in what the reader must understand, which this is not.",
45
46
  "evaluation_note": "The verifier evaluates the EFFECTIVE combination of every applicable ACTIVE branch ruleset, never a single ruleset by id or name. openai required this explicitly: ruleset 17749383 ('main protection') is what exists today, and assuming its id, its name, or that one monolithic ruleset carries every rule would make the check wrong the first time an administrator splits it.",
46
47
  "revisit_if": "The repository's governance model changes; or the default branch's protection moves back to classic branch protection (this file's evaluator reads rulesets, and `repos/{owner}/{repo}/branches/main/protection` returned 404 on 2026-09-10); or the job that carries the ratification gate is renamed, in which case `required_status_check_contexts` names a context that no longer exists and the verifier reds until this file is corrected."
47
48
  }
@@ -76,16 +76,20 @@
76
76
  "ci_delivery": {
77
77
  "workflow": ".github/workflows/standing-payload-delta.yml",
78
78
  "trigger": "pull_request",
79
- "posture": "blocking_on_ceiling_breach_with_grace_ceiling",
79
+ "posture": "blocking_on_measured_ceiling",
80
80
  "design_ceiling": 107646,
81
- "grace_ceiling": 138490,
82
- "grace_measured_at": "2026-09-08",
81
+ "required_status_check": "Standing payload delta + budget gate -- added to required_status_checks on ruleset 'main protection' (id 17749383) on 2026-09-11, with OrganizationAdmin as a bypass actor (bypass_mode: always). AI council option (b), 2/2: plain 'required' against an empty bypass list made any INFRASTRUCTURE red an unbypassable merge block for the only person who could fix it, which is the owner constraint read backwards. Verify with `gh api repos/:owner/:repo/rulesets`, never by reading this file. The bypass contract: permitted only for an infrastructure failure or a demonstrated gate defect, never for disagreement with the payload policy or for ordinary exceptional growth (that is what preamble-payload-exceptions.json is for); every use records cause and remediation; the gate is repaired or reverted before the next ordinary merge.",
82
+ "the_ceiling_is_measured": "READ THIS BEFORE THE FIELDS ABOVE. THERE IS NO STORED CEILING IN THIS FILE. The bound is COMPUTED per run: ceiling = max(design_ceiling, payload measured at the base ref + active grants). Nothing here can be edited to widen it, which is the whole point -- a stored number stayed where a human last put it, so payload a merge REMOVED could be added straight back into the space it freed and nothing objected. A measured ceiling captures every merged reduction automatically, and on a tree that is over design it means ZERO NET GROWTH per pull request. The last stored value was 138,490, measured 2026-09-08, deleted 2026-09-11 in stage 2 of the migration; the two RAISES it took while its own text said it may never move up are kept under superseded_stored_ceiling as the evidence behind ADR-264, and neither is reachable now because there is no number left to raise. What the shrink-only ratchet bounds instead is design_ceiling plus every existing exception grant and watermark, and it refuses a DELETED grant -- the one failure a shrink-only comparison misses by construction. Mechanism and the six ledger contract rules: src/scripts/_lib/measured_payload_ceiling.ts. Decisions: ADR-275 (stage 1, the formula and its prerequisites) and ADR-276 (stage 2, this deletion plus the required check). Break-glass: src/config/preamble-payload-exceptions.json.",
83
83
  "decision": "OPTION (b) of b-preamble-ci-placement: fold into the existing standing-payload-delta.yml rather than add a per-PR job or a scheduled main job. That workflow already computes the neighbouring number and already DECLINED to fail on the premise that this gate 'already fails on growth' -- a premise that was false, because nothing in .github/ ran this gate at all. Making it fail is the smallest change that removes the contradiction instead of adding a third surface. AI council 2026-08-24, 2/2 convergent, on a maintainer delegation.",
84
84
  "why_a_single_ci_run_is_enough": "The 'per-spawn' in this metric's name describes WHERE the cost is paid, not random sampling. The measurement is a deterministic census of revision-controlled inputs -- rules, the skill catalogue and CLAUDE.md, all read from the checkout -- so one CI run represents the checked-out revision exactly. Variation between two runs on the same commit would be a CHECKER DEFECT, never budget noise, and is asserted against by the repeatability test in tests/scripts/check_preamble_payload_budget.test.ts. Both council seats rejected the single-sample objection on this ground.",
85
- "why_a_grace_ceiling": "HEAD measures 138,212 against a design ceiling of 107,646 -- 28.4 % over. Making the gate blocking at the design ceiling would fail EVERY pull request from the moment it lands, which is a self-inflicted CI stop rather than a gate: nobody can reduce 30,566 tokens inside the PR that turns the gate on. The grace ceiling is set AT the measurement so growth beyond today reds immediately while today's tree passes, and it ratchets DOWN toward the design ceiling as reductions land. It may never move UP. **IT NEVER EXPIRED, and the sentence that used to stand here said it did.** This field read \"It expires at the milestone-1 date, at which point the design ceiling applies\" from the day the concession landed, and nothing in the tree ever implemented that: `grace_end_date` was read in exactly two places, an `echo` in the workflow and a test-helper return type, and `check_preamble_payload_budget.ts` carried no date logic at all. So the design ceiling did not become operative on 2026-11-10; it becomes operative when a human edits this file. The date was deleted rather than moved, because moving it would have re-published the same fiction with a later number -- an AI council under a written owner delegation converged on that (2/2, 2026-09-10) and forbade both the extension and building the missing expiry, the latter because arming a repository-wide stop on a date where `status_2026_08_24.committed_reduction_mechanism` is still the string \"NONE\" creates a cliff nobody can clear. What survives is the half that was always real and is unchanged here: the ceiling is 138,490, it is compared against the measured total on every pull request, and it may only walk down. Evidence: agents/evidence/analysis/grace-ceiling-expiry-is-unenforced-2026-09-10.md; decision: ADR-274.",
86
- "decision_record": "docs/decisions/ADR-264-standing-payload-grace-ceiling-may-not-rise.md -- resolves the contradiction a reader hits in why_a_grace_ceiling above, which says the ceiling is 'set AT the measurement' AND that 'It may never move UP', while grace_ceiling_history records it moving up twice. ADR-264 decides AGAINST the measurement framing and FOR the cap: the ceiling may not rise, standing-rule growth needs a compensating reduction elsewhere, and the two recorded raises stand as violations caused by the contradictory wording rather than as precedent. It also designs, and deliberately does NOT ship, a 128-token aggregate Iron Law reserve -- because the deciding seat's own condition was that wording without enforcement and protected approval is an exploitable trust gap, and this citation is therefore the whole of this file's edit. No bound here is changed by it. ADR-274 is the second record on this block and changes no bound either: it deletes the unenforced `grace_end_date` and leaves ADR-264's cap standing untouched. It also records that ADR-264's third `review_trigger` clause -- \"the milestone-1 date arrives and the design ceiling of 107,646 applies\" -- describes an event no code produces and therefore cannot fire; that ADR is not edited here, because its `reopen_policy` is `owner` and nothing in this change needs its decision reopened.",
85
+ "why_a_stored_ceiling_existed_until_2026_09_11": "HISTORY, kept rather than deleted. The stored ceiling this paragraph describes is GONE as of 2026-09-11 (ADR-276); the bound is measured at the base ref now. The field survives because the correction it carries -- that the concession's advertised expiry was never enforced by anything -- is the record of a fiction this tree published for weeks, and deleting the ceiling is not a reason to delete the finding. Read it in the past tense. HEAD measures 138,212 against a design ceiling of 107,646 -- 28.4 % over. Making the gate blocking at the design ceiling would fail EVERY pull request from the moment it lands, which is a self-inflicted CI stop rather than a gate: nobody can reduce 30,566 tokens inside the PR that turns the gate on. The grace ceiling is set AT the measurement so growth beyond today reds immediately while today's tree passes, and it ratchets DOWN toward the design ceiling as reductions land. It may never move UP. **IT NEVER EXPIRED, and the sentence that used to stand here said it did.** This field read \"It expires at the milestone-1 date, at which point the design ceiling applies\" from the day the concession landed, and nothing in the tree ever implemented that: `grace_end_date` was read in exactly two places, an `echo` in the workflow and a test-helper return type, and `check_preamble_payload_budget.ts` carried no date logic at all. So the design ceiling did not become operative on 2026-11-10; it becomes operative when a human edits this file. The date was deleted rather than moved, because moving it would have re-published the same fiction with a later number -- an AI council under a written owner delegation converged on that (2/2, 2026-09-10) and forbade both the extension and building the missing expiry, the latter because arming a repository-wide stop on a date where `status_2026_08_24.committed_reduction_mechanism` is still the string \"NONE\" creates a cliff nobody can clear. What survived that correction was the half that was always real: a bound compared against the measured total on every pull request, which may only walk down. That half is now the MEASURED ceiling, and it walks down by itself rather than waiting for a human. Evidence: agents/evidence/analysis/grace-ceiling-expiry-is-unenforced-2026-09-10.md; decisions: ADR-274 (the expiry), ADR-275 (the measured formula), ADR-276 (this deletion).",
86
+ "decision_record": "docs/decisions/ADR-264-standing-payload-grace-ceiling-may-not-rise.md -- resolves the contradiction a reader hits in why_a_stored_ceiling_existed_until_2026_09_11 above, which says the stored ceiling was 'set AT the measurement' AND that 'It may never move UP', while its own raise history under superseded_stored_ceiling records it moving up twice. ADR-264 decides AGAINST the measurement framing and FOR the cap: the ceiling may not rise, standing-rule growth needs a compensating reduction elsewhere, and the two recorded raises stand as violations caused by the contradictory wording rather than as precedent. It also designs, and deliberately does NOT ship, a 128-token aggregate Iron Law reserve -- because the deciding seat's own condition was that wording without enforcement and protected approval is an exploitable trust gap, and this citation is therefore the whole of this file's edit. No bound here is changed by it. ADR-274 is the second record on this block and changes no bound either: it deletes the unenforced `grace_end_date` and leaves ADR-264's cap standing untouched. It also records that ADR-264's third `review_trigger` clause -- \"the milestone-1 date arrives and the design ceiling of 107,646 applies\" -- describes an event no code produces and therefore cannot fire; that ADR is not edited here, because its `reopen_policy` is `owner` and nothing in this change needs its decision reopened.",
87
87
  "honest_limit": "Editing this workflow makes it FAIL; it does not make it REQUIRED. Whether a failing check blocks a merge is branch-protection configuration, which is a repo-admin action outside this change and outside an autonomous run. So the claim this record supports is 'the gate can now fail a PR', never 'the gate now blocks a merge'. Verify the latter with `gh api repos/:owner/:repo/rulesets` rather than by reading this file.",
88
- "grace_ceiling_history": [
88
+ "superseded_stored_ceiling": {
89
+ "_note": "The stored ceiling this file carried from 2026-08-24 until 2026-09-11, kept as the record of what the measured formula replaced. Last value 138,490, measured 2026-09-08. Retained rather than deleted because its two RAISES are the evidence behind ADR-264 -- a ceiling whose own text said it may never move up, moving up twice under careful prose each time. Both predate src/scripts/_lib/standing_bound_ratchet.ts; neither is reachable now, because there is no stored number left to raise. CORRECTION carried with the entries: both `why` texts below call the concession a dated window expiring 2026-11-10. It was never dated in any executable sense -- nothing read the expiry key except an echo -- and the key was deleted 2026-09-10 (ADR-274). The texts are kept verbatim as the record of what was believed at the time; this note is the correction.",
90
+ "last_stored_value": 138490,
91
+ "last_measured_at": "2026-09-08",
92
+ "raises": [
89
93
  {
90
94
  "from": 138273,
91
95
  "to": 138490,
@@ -98,7 +102,8 @@
98
102
  "at": "2026-09-02",
99
103
  "why": "code-comment-discipline gained three Iron Law lines: a comment naming where the code came from is evidence in the wrong place, provenance is not a WHY, and a roadmap cannot license a comment the rule forbids. +61 tok after two condensations — the section was first written at +546, moved to its pointer target (code-clarity.md) at +172, and folded into the existing Iron Law block rather than opening a second one at +61. What remains is obligation surface that preservation-guard forbids condensing further, and it cannot move to the guideline because a rule whose Iron Law is elsewhere is a rule nobody reads. The defect it closes was measured, not argued: 509 German comment lines and 21 report- or provenance-shaped comments across 41 of 45 changed source files in a consumer repository, with both governing rules holding an enforcement hole — one naming a .md-only validator for a source-file clause, the other naming no enforcer at all. This raises the GRACE ceiling, which is a dated window (expires 2026-11-10), not the design ceiling of 107646, which this tree passed long before this change."
100
104
  }
101
- ]
105
+ ]
106
+ }
102
107
  },
103
108
  "status_2026_08_24": {
104
109
  "state": "at_risk",
@@ -0,0 +1,28 @@
1
+ {
2
+ "_comment": "The break-glass ledger for the standing-payload ceiling. EMPTY, and expected to stay empty: 96.8 % of the last 250 merged pull requests moved this payload by zero or less, so the ordinary path is zero net growth and fully autonomous. This file is for the tail of the tail -- a change whose offsetting reduction is genuinely unsafe. Reading order: src/scripts/_lib/measured_payload_ceiling.ts carries the mechanism and the six contract rules with the reasoning behind each; ADR-275 carries the decision; src/config/preamble-payload-budget.json carries the ceiling this widens.",
3
+ "schema_version": 1,
4
+ "registered_at": "2026-09-11",
5
+ "owner": "maintainer",
6
+ "exceptions": [],
7
+ "contract": {
8
+ "ceiling_effect": "ceiling = max(design_ceiling, min(payload_at_base_ref, watermark) + granted_tokens, stored_ceiling?). The base is PINNED to the watermark while a grant is live, which is what stops the grant becoming permanent: without the pin, the grant raises the measurement, the next pull request measures the raised base, and the exceptional growth is the new ordinary one merge later.",
9
+ "at_most_one_active": "At most ONE grant may be active at a time. Overlapping grants have no defined composition -- a later watermark can already contain an earlier grant's growth, so summing counts it twice. Repay or expire one before recording the next. (AI council 2026-09-11, blocking finding 1.)",
10
+ "approval_must_be_authenticated": "approval_event names a platform event OUTSIDE the diff that requests the grant, and the gate honours the grant only when a caller with platform access has verified it (--approved <id>). An approval recorded solely by the change requesting it is self-asserted data: the same diff can claim the grant, the approver and the date. An unverified grant contributes ZERO tokens and refuses the run. (Blocking finding 2, and the council's hardest pushback in both seats.)",
11
+ "deletion_cannot_discharge_debt": "A record may not be deleted. Removing an entry that exists at the base ref is refused by the shrink-only ratchet: a deleted record is not a repaid one, and erasing it erases the evidence along with the debt. (Blocking finding 3.)",
12
+ "repayment_is_measured": "repaid_at RECORDS a measurement, it does not assert one. Repayment is established by the payload returning to the watermark; a record marked repaid while the measurement says otherwise is refused. (Blocking finding 4.)",
13
+ "consumption_is_derived": "There is deliberately no consumed_tokens field. Consumption is measured - watermark, computed by the gate. A stored copy would be an editable assertion about a measurement. It matters because any future numeric cap must come from actual CONSUMED tokens rather than granted ones -- both seats refused to derive a cap from granted amounts. (Blocking finding 5 / Q3.)",
14
+ "expiry_is_evaluated_at_gate_time": "Expiry is read when the gate runs, which on a required check is merge time. A grant that expires while its pull request sits in review reds that pull request. The fix is a fresh approved grant, never an edit to the old one's date -- which the shrink-only ratchet refuses anyway. (Blocking finding 6.)",
15
+ "no_numeric_cap": "There is no aggregate token cap, and its absence is a finding rather than an omission. The 250-PR delta distribution (p50 0, p90 0, p95 0/+167, max +288) is CENSORED by the very ratchet a cap would relax, so every percentile describes what got through rather than what was attempted. A p95 cap would license the top 5 % of ordinary work to use the break-glass routinely, which makes it not exceptional. Until rejection instrumentation and derived consumption uncensor the distribution, the approver is the cap.",
16
+ "honest_limit": "This file is editable by the pull request it governs, exactly like the gate code. It is an auditable control, not a preventive one -- the council's own words for the sibling mechanism: 'the mechanism does not prevent the exploit; it makes the exploit auditable'. The two rules that keep it from being weaker than that are approval verification (an unverified grant buys nothing) and the deletion check (a removed grant is still owed)."
17
+ },
18
+ "entry_shape": {
19
+ "id": "stable identifier; it is the record's identity and may not be reused",
20
+ "granted_tokens": "positive integer; may never be enlarged after the fact -- record a new grant instead",
21
+ "watermark": "the payload measured immediately BEFORE the grant; immutable, including across a rebase",
22
+ "reason": "why an offsetting reduction was unsafe for this change specifically",
23
+ "approval_event": "reference to the platform event that authorised it, outside this diff",
24
+ "approved_at": "YYYY-MM-DD",
25
+ "expires_at": "YYYY-MM-DD; after it, an unrepaid grant is a hard refusal",
26
+ "repaid_at": "YYYY-MM-DD once the payload has measurably returned to the watermark, else null"
27
+ }
28
+ }
@@ -140,3 +140,14 @@ jobs:
140
140
  verify: true
141
141
  script: src/scripts/report_skill_activation.ts
142
142
  guard: ~
143
+
144
+ release-holds:
145
+ # Template rule 28. Fully local by construction: the evaluator reads the
146
+ # roadmap corpus out of the checked-out tree and talks to nothing, so the
147
+ # runner and a maintainer's laptop can only disagree if the trees differ —
148
+ # which is the disagreement the gate is supposed to surface.
149
+ local: './scripts-run src/scripts/check_release_holds --lint'
150
+ verify: true
151
+ network: false
152
+ script: src/scripts/check_release_holds.ts
153
+ guard: ~
@@ -9,12 +9,12 @@
9
9
  "skills": "src/skills/*/evals/triggers.json over src/skills/*/SKILL.md."
10
10
  },
11
11
  "seed": {
12
- "rules": 0.9619,
13
- "skills": 0.3344
12
+ "rules": 0.9623,
13
+ "skills": 0.3378
14
14
  },
15
15
  "seed_provenance": {
16
- "rules": "101 covered of 105 routed rules on 2026-09-08; was 94 of 105 (tier-1 21/24, tier-2 73/81) on 2026-08-25.",
17
- "skills": "100 of 299 skills carry evals/triggers.json on 2026-08-30.",
16
+ "rules": "102 covered of 106 routed rules on 2026-09-13; was 101 of 105 on 2026-09-08 and 94 of 105 (tier-1 21/24, tier-2 73/81) on 2026-08-25.",
17
+ "skills": "101 of 299 skills carry evals/triggers.json on 2026-09-19; was 100 on 2026-08-30.",
18
18
  "finding": "The gap between the two seeds IS the roadmap defect D1, quantified. The rules surface is ~90% covered by a deterministic corpus that can fail a PR; the skills surface -- the one production routes on -- is 25%, covered only by a harness that is advisory only, never gating (rule_trigger_eval.ts:4)."
19
19
  },
20
20
  "history": [
@@ -45,6 +45,20 @@
45
45
  "from": 0.8952,
46
46
  "to": 0.9619,
47
47
  "reason": "road-to-delivery-for-every-host authored seven routing-matrix fixtures -- council-availability, evaluator-independence, fix-what-you-see, missing-skill-recovery, playbook-precedence, recurring-criticism, self-repair-loop (94 -> 101 of 105 routed rules). First entry on the RULES scope; the three above are all skills. The seed rises because this file's own test asserts seed == live measurement in both directions, so the gain would otherwise red the suite for doing what the ratchet encourages. It may never be LOWERED."
48
+ },
49
+ {
50
+ "date": "2026-09-13",
51
+ "scope": "rules",
52
+ "from": 0.9619,
53
+ "to": 0.9623,
54
+ "reason": "road-to-adversarial-verification-and-long-runs Phase 1.1 added `test-first` as a routed rule, which moved the DENOMINATOR from 105 to 106 -- the ratio-falls-two-ways case this file's own _comment names, and the one that is a defect to record rather than repair. The repair is the corpus file, not the seed: `tests/eval/routing-matrix/test-first.yaml` landed in the same change (101 -> 102 of 106), so the ratio ROSE across a denominator increase rather than merely holding. The rule is trigger-less by design, so its positives describe the situations it governs rather than strings that summon it, and its near-misses are its own \u00a7 Does NOT fire set. The seed follows the gain because this file's test asserts seed == live measurement in both directions; it may never be LOWERED."
55
+ },
56
+ {
57
+ "date": "2026-09-19",
58
+ "scope": "skills",
59
+ "from": 0.3344,
60
+ "to": 0.3378,
61
+ "reason": "road-to-release-holds-that-refuse step 1.4 authored one corpus file for `roadmap-writing` (100 -> 101 of 299) and removed its now-false entry from trigger_eval_grandfather.json. ONE file rather than a wave: the step asked for a single positive case whose expected output is a re-sequenced phase rather than a hold, and the eval set is where that expectation is pinned. The seed rises so the gain cannot be given back silently; it may never be LOWERED. Two published measurements moved with it and were re-taken in the same change -- routing-body-signal-verdict.json and the measure_delivery_sets record -- because the trigger corpus is their input, so any skill gaining an eval set re-takes both."
48
62
  }
49
63
  ]
50
64
  }