@event4u/agent-config 14.12.0 → 14.13.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 (466) 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 +234 -0
  5. package/CONTRIBUTING.md +38 -0
  6. package/CREDITS.md +135 -0
  7. package/NOTICE +13 -0
  8. package/README.md +8 -6
  9. package/dist/agent-src/commands/analyze/inbox.md +109 -2
  10. package/dist/agent-src/commands/feature/dev.md +7 -2
  11. package/dist/agent-src/commands/ghostwriter/write.md +5 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  14. package/dist/agent-src/commands/orchestrate.md +2 -2
  15. package/dist/agent-src/commands/post-as/me.md +5 -1
  16. package/dist/agent-src/commands/pr/merge.md +19 -6
  17. package/dist/agent-src/commands/roadmap/process-full.md +19 -5
  18. package/dist/agent-src/commands/tdd/red.md +12 -2
  19. package/dist/agent-src/commands/work.md +1 -1
  20. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
  21. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
  22. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
  23. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
  24. package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
  25. package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
  26. package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
  27. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  28. package/dist/agent-src/rules/broken-access-control.md +4 -0
  29. package/dist/agent-src/rules/code-provenance.md +4 -0
  30. package/dist/agent-src/rules/design-fidelity.md +1 -1
  31. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  32. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  33. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  34. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  35. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  36. package/dist/agent-src/rules/laravel-routing.md +1 -1
  37. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  38. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  39. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  40. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  41. package/dist/agent-src/rules/symfony-routing.md +1 -1
  42. package/dist/agent-src/rules/token-efficiency.md +14 -0
  43. package/dist/agent-src/rules/tool-safety.md +4 -0
  44. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  45. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  46. package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
  47. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  48. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  49. package/dist/agent-src/scripts/stubs_due.ts +400 -0
  50. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  51. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
  52. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  53. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  54. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  55. package/dist/agent-src/skills/database/SKILL.md +8 -0
  56. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  57. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  58. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  59. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  60. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  61. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  62. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  63. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  64. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  65. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  66. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  67. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  68. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  69. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  70. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  71. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  72. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  73. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  74. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  75. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  76. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  77. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  78. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  79. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  80. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  81. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  82. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  83. package/dist/agent-src/templates/roadmaps.md +97 -3
  84. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  85. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  86. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  87. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  88. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  93. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  94. package/dist/cli/commands/uiAudit.js +124 -5
  95. package/dist/cli/registry.js +2 -0
  96. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  97. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  98. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  99. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  100. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  101. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  102. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  103. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  104. package/dist/cli-delegate/cmd_conformance.js +42 -10
  105. package/dist/cli-delegate/cmd_doctor.js +3 -3
  106. package/dist/cli-delegate/cmd_export.js +3 -2
  107. package/dist/cli-delegate/cmd_fleet.js +2 -2
  108. package/dist/cli-delegate/cmd_handoff.js +1 -1
  109. package/dist/cli-delegate/cmd_preflight.js +2 -2
  110. package/dist/cli-delegate/cmd_prune.js +3 -2
  111. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  112. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  113. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  114. package/dist/cli-delegate/cmd_sync.js +3 -2
  115. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  116. package/dist/cli-delegate/cmd_validate.js +3 -2
  117. package/dist/discovery/deprecation-report.md +1 -1
  118. package/dist/discovery/discovery-manifest.json +57 -57
  119. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  120. package/dist/discovery/discovery-manifest.summary.md +1 -1
  121. package/dist/discovery/dormancy-report.md +1 -1
  122. package/dist/discovery/orphan-report.md +1 -1
  123. package/dist/discovery/packs.json +2 -2
  124. package/dist/discovery/trust-report.md +1 -1
  125. package/dist/discovery/workspaces.json +2 -2
  126. package/dist/hooks/dispatch.js +1836 -712
  127. package/dist/install/claudeRuleRewrite.js +254 -0
  128. package/dist/install/detect.js +29 -16
  129. package/dist/install/detect_php_shape.js +159 -0
  130. package/dist/install/install.mjs +634 -428
  131. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  132. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  133. package/dist/mcp/registry-manifest.json +3 -3
  134. package/dist/mcp/server.json +3 -3
  135. package/dist/mcp/server.mjs +4818 -2645
  136. package/dist/server/schemas/settings.js +3 -0
  137. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  138. package/dist/ui/index.html +1 -1
  139. package/docs/MIGRATION.md +1 -1
  140. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  141. package/docs/contracts/provider-lifecycle.md +1 -1
  142. package/docs/contracts/settings-classes.md +10 -4
  143. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  144. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  145. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  146. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  147. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  148. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  149. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  150. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  151. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  152. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  153. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  154. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  155. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  156. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  157. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  158. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  159. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  160. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  161. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  162. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  163. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  164. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  165. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  166. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  167. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  168. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  169. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  170. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  171. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  172. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  173. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  174. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  175. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  176. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  177. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  178. package/docs/guidelines/augment-portability-patterns.md +6 -4
  179. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  180. package/docs/guidelines/cross-role-handoff.md +2 -2
  181. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  182. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  183. package/docs/guidelines/php/database.md +90 -7
  184. package/docs/guidelines/prompt-templates.md +7 -7
  185. package/llms.txt +2 -2
  186. package/package.json +5 -2
  187. package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  188. package/src/agent-src/scripts/guarded_baseline.ts +328 -0
  189. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  190. package/src/agent-src/scripts/stub_queue.ts +82 -0
  191. package/src/agent-src/scripts/stubs_due.ts +400 -0
  192. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  193. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
  194. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  195. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  196. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  197. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  198. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  199. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  202. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  203. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  204. package/src/config/agent-settings.template.yml +32 -3
  205. package/src/config/assurance-capability-registry.json +21 -9
  206. package/src/config/canonical-terms.yml +119 -0
  207. package/src/config/capability-native-outcome-bars.json +81 -0
  208. package/src/config/ci-local-parity.yml +80 -0
  209. package/src/config/drafting-channels.yml +43 -0
  210. package/src/config/estate-count-budget.json +38 -36
  211. package/src/config/evaluator-budgets.json +14 -14
  212. package/src/config/gate-coverage.yml +579 -63
  213. package/src/config/gate-reachability-exemptions.json +21 -0
  214. package/src/config/gate-violation-baselines.json +37 -19
  215. package/src/config/harness-evolution-budget.json +25 -0
  216. package/src/config/lapsed-beta-baseline.json +96 -0
  217. package/src/config/memory-twin-verdicts.yml +129 -0
  218. package/src/config/metric-registry.yml +124 -0
  219. package/src/config/pack-size-budget.json +16 -15
  220. package/src/config/preamble-payload-budget.json +8 -8
  221. package/src/config/profiles/balanced.ini +27 -0
  222. package/src/config/profiles/full.ini +27 -0
  223. package/src/config/profiles/minimal.ini +27 -0
  224. package/src/config/publish-surface.json +9 -2
  225. package/src/config/routing-coverage-seed.json +16 -2
  226. package/src/config/rule-stub-ceilings.json +126 -112
  227. package/src/config/turnaround-budget.json +66 -0
  228. package/src/install/claudeRuleRewrite.ts +288 -0
  229. package/src/install/detect.ts +60 -17
  230. package/src/install/detect_php_shape.ts +191 -0
  231. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  232. package/src/scripts/_dispatch.bash +27 -0
  233. package/src/scripts/_lib/activation_ladder.ts +211 -0
  234. package/src/scripts/_lib/activation_states.ts +88 -0
  235. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  236. package/src/scripts/_lib/arith_claims.ts +181 -0
  237. package/src/scripts/_lib/arm_ranking.ts +62 -0
  238. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  239. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  240. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  241. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  242. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  243. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  244. package/src/scripts/_lib/candidate_record.ts +601 -0
  245. package/src/scripts/_lib/capture_rate.ts +319 -0
  246. package/src/scripts/_lib/collector_denominator.ts +771 -0
  247. package/src/scripts/_lib/collector_record.ts +340 -0
  248. package/src/scripts/_lib/collector_store.ts +664 -0
  249. package/src/scripts/_lib/collector_supervision.ts +827 -0
  250. package/src/scripts/_lib/concern_estate.ts +77 -0
  251. package/src/scripts/_lib/config_chain.ts +477 -0
  252. package/src/scripts/_lib/config_cost.ts +209 -0
  253. package/src/scripts/_lib/council_settings_block.ts +6 -0
  254. package/src/scripts/_lib/curator_ops.ts +172 -0
  255. package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
  256. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  257. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  258. package/src/scripts/_lib/empty_cycles.ts +88 -0
  259. package/src/scripts/_lib/eval_publication.ts +354 -0
  260. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  261. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  262. package/src/scripts/_lib/evidence_basis.ts +118 -0
  263. package/src/scripts/_lib/exec_evidence.ts +8 -0
  264. package/src/scripts/_lib/experience_card.ts +272 -0
  265. package/src/scripts/_lib/experience_report.ts +151 -0
  266. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  267. package/src/scripts/_lib/generated_by.ts +66 -0
  268. package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
  269. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  270. package/src/scripts/_lib/host_denominator.ts +687 -0
  271. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  272. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  273. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  274. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  275. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  276. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  277. package/src/scripts/_lib/loop_guards.ts +299 -0
  278. package/src/scripts/_lib/loss_class.ts +129 -0
  279. package/src/scripts/_lib/machine_wake.ts +51 -0
  280. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  281. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  282. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  283. package/src/scripts/_lib/orchestration_record.ts +253 -5
  284. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  285. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  286. package/src/scripts/_lib/paired_stats.ts +245 -0
  287. package/src/scripts/_lib/paired_verdict.ts +226 -0
  288. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  289. package/src/scripts/_lib/privacy_class.ts +47 -0
  290. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  291. package/src/scripts/_lib/repeated_failure.ts +105 -0
  292. package/src/scripts/_lib/repo_root.ts +111 -0
  293. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  294. package/src/scripts/_lib/role_split.ts +338 -0
  295. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  296. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  297. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  298. package/src/scripts/_lib/source_digest.ts +200 -0
  299. package/src/scripts/_lib/source_redact.ts +260 -0
  300. package/src/scripts/_lib/source_shape.ts +502 -0
  301. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  302. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  303. package/src/scripts/_lib/strip_comments.mjs +65 -0
  304. package/src/scripts/_lib/test_red_state.ts +154 -0
  305. package/src/scripts/_lib/trigger_shift.ts +144 -0
  306. package/src/scripts/_lib/untrusted_content.ts +82 -7
  307. package/src/scripts/adoption_report.ts +1 -1
  308. package/src/scripts/adr/evidence_census.ts +1 -1
  309. package/src/scripts/adr/regenerate_index.ts +26 -2
  310. package/src/scripts/adr_cite_check.ts +164 -1
  311. package/src/scripts/ai_council/blind_review.ts +11 -1
  312. package/src/scripts/ai_council/clients.ts +4 -0
  313. package/src/scripts/ai_council/config.ts +3 -0
  314. package/src/scripts/ai_council/consensus.ts +28 -8
  315. package/src/scripts/ai_council/consensus_round.ts +226 -0
  316. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  317. package/src/scripts/ai_council/inline_findings.ts +340 -0
  318. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  319. package/src/scripts/ai_council/orchestrator.ts +16 -203
  320. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  321. package/src/scripts/ai_council/pricing.ts +106 -0
  322. package/src/scripts/ai_council/prompts.ts +74 -7
  323. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  324. package/src/scripts/ai_council/py_format.ts +14 -3
  325. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  326. package/src/scripts/ai_council/response_record.ts +50 -0
  327. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  328. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  329. package/src/scripts/asset_delivery_ledger.ts +157 -0
  330. package/src/scripts/attest_artifact.ts +193 -0
  331. package/src/scripts/audit_auto_rules.ts +2 -1
  332. package/src/scripts/audit_command_surface.ts +1 -1
  333. package/src/scripts/audit_mcp_tools.ts +2 -2
  334. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  335. package/src/scripts/audit_user_type_axis.ts +2 -1
  336. package/src/scripts/bench_ab_clone.ts +215 -10
  337. package/src/scripts/bench_ab_integrity.ts +119 -5
  338. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  339. package/src/scripts/build_archive_index.ts +1 -1
  340. package/src/scripts/build_linear_digest.ts +1 -1
  341. package/src/scripts/build_proof.ts +11 -4
  342. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  343. package/src/scripts/build_source_digests.ts +157 -0
  344. package/src/scripts/cache_realization_report.ts +103 -0
  345. package/src/scripts/check_adr_frontmatter.ts +126 -0
  346. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  347. package/src/scripts/check_beta_review_markers.ts +235 -6
  348. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  349. package/src/scripts/check_claims.ts +576 -6
  350. package/src/scripts/check_composite_arming.ts +35 -0
  351. package/src/scripts/check_concern_admissions.ts +365 -0
  352. package/src/scripts/check_enforcement_coverage.ts +28 -0
  353. package/src/scripts/check_estate_count.ts +142 -1
  354. package/src/scripts/check_gate_reachability.ts +383 -0
  355. package/src/scripts/check_host_loadability.ts +104 -0
  356. package/src/scripts/check_loss_class_declared.ts +308 -0
  357. package/src/scripts/check_md_language.ts +15 -98
  358. package/src/scripts/check_memory_proposal.ts +18 -11
  359. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  360. package/src/scripts/check_no_external_sources.ts +281 -6
  361. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  362. package/src/scripts/check_pack_size.ts +59 -2
  363. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  364. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  365. package/src/scripts/check_publish_surface.ts +10 -1
  366. package/src/scripts/check_references.ts +24 -1
  367. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  368. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  369. package/src/scripts/check_score_contract.ts +26 -3
  370. package/src/scripts/check_static_parity.ts +285 -0
  371. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  372. package/src/scripts/check_suppression_hygiene.ts +15 -0
  373. package/src/scripts/ci_settle.ts +39 -2
  374. package/src/scripts/code_graph/build.ts +60 -3
  375. package/src/scripts/code_graph/extract.ts +44 -0
  376. package/src/scripts/code_graph/types.ts +24 -0
  377. package/src/scripts/collector_daemon.ts +714 -0
  378. package/src/scripts/config_cost_report.ts +302 -0
  379. package/src/scripts/consumer_matrix.ts +74 -1
  380. package/src/scripts/cost/budget.mjs +10 -3
  381. package/src/scripts/cost/track.mjs +10 -3
  382. package/src/scripts/council_cli.ts +37 -54
  383. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  384. package/src/scripts/evolution_lab.ts +980 -0
  385. package/src/scripts/external_sources_denylist.json +5 -18
  386. package/src/scripts/extract_audit_patterns.ts +21 -0
  387. package/src/scripts/fold_intake.ts +12 -1
  388. package/src/scripts/gen_discovery_baseline.ts +1 -1
  389. package/src/scripts/generate_capabilities_index.ts +12 -5
  390. package/src/scripts/generate_capability_matrix.ts +3 -3
  391. package/src/scripts/generate_command_flows.ts +2 -2
  392. package/src/scripts/generate_cookbook.ts +2 -2
  393. package/src/scripts/generate_index.ts +8 -1
  394. package/src/scripts/generate_knowledge_index.ts +2 -1
  395. package/src/scripts/generate_ownership_matrix.ts +2 -1
  396. package/src/scripts/generate_pack_manifests.ts +10 -2
  397. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  398. package/src/scripts/generate_settings_reference.ts +1 -1
  399. package/src/scripts/git_authorization_hook.ts +22 -1
  400. package/src/scripts/grade_target_readiness.ts +48 -5
  401. package/src/scripts/hook_effect_doctor.ts +261 -0
  402. package/src/scripts/hook_manifest.json +1 -1
  403. package/src/scripts/hook_manifest.yaml +98 -11
  404. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  405. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  406. package/src/scripts/hooks/concern_registry.ts +4 -0
  407. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  408. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  409. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  410. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  411. package/src/scripts/hooks/shims/install.sh +61 -0
  412. package/src/scripts/hooks/shims/php +101 -0
  413. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  414. package/src/scripts/hot_context_hook.ts +16 -0
  415. package/src/scripts/install-hooks.sh +20 -5
  416. package/src/scripts/install.ts +17 -35
  417. package/src/scripts/inventory_frontmatter.ts +2 -1
  418. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  419. package/src/scripts/lint_canonical_terms.ts +604 -0
  420. package/src/scripts/lint_composition_review.ts +619 -0
  421. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  422. package/src/scripts/lint_eval_specs.ts +593 -0
  423. package/src/scripts/lint_hook_manifest.ts +19 -0
  424. package/src/scripts/lint_host_portability.ts +373 -0
  425. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  426. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  427. package/src/scripts/lint_metric_consumers.ts +355 -0
  428. package/src/scripts/lint_skill_descriptions.ts +18 -1
  429. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  430. package/src/scripts/lint_skill_link_reach.ts +252 -0
  431. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  432. package/src/scripts/lint_ticket_buildable.ts +17 -1
  433. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  434. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  435. package/src/scripts/measure_docs_dead_links.ts +348 -0
  436. package/src/scripts/measure_host_capture.ts +461 -0
  437. package/src/scripts/migration_status.ts +3 -3
  438. package/src/scripts/model_rule_injection.ts +60 -0
  439. package/src/scripts/orchestration_record.ts +14 -0
  440. package/src/scripts/preamble_byte_census.ts +139 -10
  441. package/src/scripts/prepack-check.mjs +4 -1
  442. package/src/scripts/probe_turnaround.ts +384 -0
  443. package/src/scripts/probe_unblocked_ask.ts +279 -0
  444. package/src/scripts/render_benchmark_md.ts +1 -1
  445. package/src/scripts/rule_activation_census.ts +70 -9
  446. package/src/scripts/rule_backlinks.ts +1 -1
  447. package/src/scripts/run_lifecycle_suite.ts +208 -0
  448. package/src/scripts/run_skill_evals.ts +40 -0
  449. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  450. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  451. package/src/scripts/schemas/evals.schema.json +24 -1
  452. package/src/scripts/schemas/rule.schema.json +52 -1
  453. package/src/scripts/schemas/skill.schema.json +17 -2
  454. package/src/scripts/skill_overlap.ts +7 -1
  455. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  456. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  457. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  458. package/src/scripts/skill_usage_report.ts +2 -1
  459. package/src/scripts/stubs_due.ts +211 -0
  460. package/src/scripts/sweep_source_surfaces.ts +678 -0
  461. package/src/scripts/sync_pr_branch.ts +3 -3
  462. package/src/scripts/trigger_eval_grandfather.json +202 -222
  463. package/src/scripts/utilization_report.ts +22 -2
  464. package/src/server/schemas/settings.ts +5 -0
  465. package/src/templates/marketing-copy.yml +1 -1
  466. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,21 @@
1
+ {
2
+ "_comment": "Gate-shaped task targets that are deliberately NOT reachable from `task ci` or any workflow. road-to-gates-that-do-not-run Phase 3. Every entry carries a reason AND what would make it run — a class with no reason is not a class, and 'manual' without a promotion condition is a shrug. check_gate_reachability --gate fails on any unreachable target absent from this map, so a new one cannot join the set silently.",
3
+ "_registered_at": "2026-08-30",
4
+ "_measured": "22 unreachable at the start of Phase 2, 14 after it. The 8 that left were wired one per commit, each run locally first.",
5
+ "exempt": {
6
+ "ci-strict": "An ENTRY POINT, not a gate — the stricter sibling of `ci` itself, so wiring it into `ci` would be a cycle. Would run if strict became the default, which is a policy change rather than a wiring one.",
7
+ "check-augment-budget": "Emits a MEASUREMENT, not a verdict; a gate that cannot fail is a report. Would run once a pre-registered threshold exists to fail on.",
8
+ "check-corpus": "Requires council configuration, which is user-global (ADR-104) and absent in CI by construction. Would run against a fixture corpus that needs no configured council.",
9
+ "check-media-deps": "Requires external media tooling not installed on runners. Would run with those dependencies in the runner image, or behind a skip-with-reason path.",
10
+ "check-trunk-drift": "ADVISORY BY ITS OWN DOCSTRING — 'run it in the /create-pr pre-flight or wire into CI per your branch-protection policy'. Its red state is 'this branch is behind trunk', which is the normal state of an open PR, so wiring it would fail correct work. RECLASSIFIED from should-run during Phase 2 after reading what it asserts. Would run under a branch-protection policy that requires an up-to-date base.",
11
+ "dev:standing-rule-delivery": "`dev:` namespace — an inspection aid for a maintainer mid-change. Would run if promoted out of `dev:`, which is a scope decision.",
12
+ "lint-agents-layout-strict": "`--strict` over a corpus whose non-strict form is already reachable; strict carries a known backlog. Would run once that backlog is cleared and strict becomes the default.",
13
+ "lint-bench-ab": "Bench namespace, spend-bearing. Would run given a cached or dry arm that costs nothing per invocation.",
14
+ "lint-explain-trace": "NOT A GATE — a validator that takes a JSON document, and a bare invocation exits non-zero with 'pass a JSON file path or --stdin'. RECLASSIFIED from should-run during Phase 2, which is exactly what 2.2's run-it-locally-first rule exists to catch: wiring it would have made CI permanently red. Would run wired to a specific trace fixture.",
15
+ "lint-originality-shingles": "`--top 10` is a ranked REPORT, not a pass/fail. Would run given a ratcheted threshold, like the other originality gates carry.",
16
+ "mcp:glama-drift-check": "Queries an external registry — network-dependent and flaky by construction. Would run against a recorded snapshot instead of a live query.",
17
+ "migration-verify": "Verifies a physical move during a migration; there is no migration in flight. Would run during one.",
18
+ "value": "Renders a dashboard; the render is the product, not a check. Nothing would make it a gate.",
19
+ "value:lint": "Lints that dashboard, which is generated and regenerated on demand. Would run if the dashboard became a committed artefact a drift could break."
20
+ }
21
+ }
@@ -1,26 +1,32 @@
1
1
  {
2
- "$comment": "Violation ratchet for gates whose dead scan root was repaired. A repair REVEALS pre-existing debt; it does not create it. Each entry records the count revealed at repair time \u2014 the gate fails only when its count RISES. Lowering a count is a normal commit; raising one is a defect. Entries expire: a baseline that has not dropped within 56 days of `landed` (or of `reaffirmed.date`) fails its gate, because a number that never moves is suppression with extra steps. Mechanism + rationale: src/scripts/_lib/gate_baseline.ts. Decision: AI council 2026-08-02, roadmap road-to-gates-that-can-fail blocker `dead-gate-finding-triage`.",
2
+ "$comment": "Violation ratchet for gates whose dead scan root was repaired. A repair REVEALS pre-existing debt; it does not create it. Each entry records the count revealed at repair time — the gate fails only when its count RISES. Lowering a count is a normal commit; raising one is a defect. Entries expire: a baseline that has not dropped within 56 days of `landed` (or of `reaffirmed.date`) fails its gate, because a number that never moves is suppression with extra steps. Mechanism + rationale: src/scripts/_lib/gate_baseline.ts. Decision: AI council 2026-08-02, roadmap road-to-gates-that-can-fail blocker `dead-gate-finding-triage`.",
3
3
  "gates": {
4
+ "check_claims:non-inference": {
5
+ "count": 40,
6
+ "landed": "2026-08-26",
7
+ "falsifier": "./scripts-run src/scripts/check_claims # the ratchet line names the current count; it fails when the count RISES above this entry",
8
+ "note": "Backed `kind: quant` ledger entries carrying no `non_inference` field, which enumerates the readings the data does NOT license. Introduced by road-to-skill-ecosystem-eval-integrity Phase 5 Step 5. NOT a scan-root repair — the field is new, so every pre-existing quant entry lacks it by construction and 40 is the count at introduction rather than revealed debt. A ratchet rather than a requirement because failing the build on 41 entries at once produces a gate that can only block, which this repository's own records name as the reason a gate gets suppressed. Every NEW backed quant claim must carry one; the inherited entries come along as they are touched. One was written at introduction (`injection-scan-corpus-rates`) to prove the field is real rather than declared, which is why the count is 40 and not 41. Clearing this entry is authoring work spread across whoever next touches each claim, not a sweep: a non_inference written in bulk without re-reading the evidence would be the placeholder the <20-character check already refuses."
9
+ },
4
10
  "audit_user_type_axis": {
5
11
  "count": 1,
6
12
  "landed": "2026-08-02",
7
- "note": "One orphan user-type value: `legal`. Five legal-review-prep skills (contract-review, dpa-review, nda-triage, legal-intake-triage, legal-practice-profile) declare `recommended_for_user_types: [legal]`, but there is no `user-types/legal.yml` \u2014 the pack shipped an axis value with no user-type definition behind it, and the dead scan root hid it (the audit reported used=0 orphans=0 while reading zero skills; it now reads 288 and reports used=8). Clearing this entry is a product call, not a copy edit: either author `user-types/legal.yml` (tagline, recommended packs, install-path hint) or drop `legal` from those five skills. Not decided here because both options change shipped pack behaviour."
13
+ "note": "One orphan user-type value: `legal`. Five legal-review-prep skills (contract-review, dpa-review, nda-triage, legal-intake-triage, legal-practice-profile) declare `recommended_for_user_types: [legal]`, but there is no `user-types/legal.yml` — the pack shipped an axis value with no user-type definition behind it, and the dead scan root hid it (the audit reported used=0 orphans=0 while reading zero skills; it now reads 288 and reports used=8). Clearing this entry is a product call, not a copy edit: either author `user-types/legal.yml` (tagline, recommended packs, install-path hint) or drop `legal` from those five skills. Not decided here because both options change shipped pack behaviour."
8
14
  },
9
15
  "check_depth_budget": {
10
16
  "count": 4,
11
17
  "landed": "2026-08-06",
12
- "note": "Four depth files exceed the 16,000-char per-file ceiling: rule-body-migration-inventory.md (23,782), design-antipatterns.md (20,707), roadmap-process-loop.md (20,360), orchestration-telemetry.md (16,155). Recorded rather than fixed because splitting four large reference documents is unrelated to the change that introduced the ceiling, and a gate that lands as four instant blockers is the shape this repository has already recorded as a failure. Shrink-only from here: a FIFTH over-ceiling file reds. roadmap-process-loop.md is the file that motivated the gate \u2014 it states 'Size budget: <= 4,000 chars' in its own header and is 5x over it, which is what a declared budget with nothing measuring it decays into. The ceiling is a GROWTH RATCHET, not a measured quality threshold: the 7,308-trajectory study behind the 3,500-token skill ceiling (ADR-217) was taken on procedural always-co-loaded skills, and this layer is declarative and loaded one or two files at a time. Replace the number when someone measures comprehension on THIS layer."
18
+ "note": "Four depth files exceed the 16,000-char per-file ceiling: rule-body-migration-inventory.md (23,782), design-antipatterns.md (20,707), roadmap-process-loop.md (20,360), orchestration-telemetry.md (16,155). Recorded rather than fixed because splitting four large reference documents is unrelated to the change that introduced the ceiling, and a gate that lands as four instant blockers is the shape this repository has already recorded as a failure. Shrink-only from here: a FIFTH over-ceiling file reds. roadmap-process-loop.md is the file that motivated the gate — it states 'Size budget: <= 4,000 chars' in its own header and is 5x over it, which is what a declared budget with nothing measuring it decays into. The ceiling is a GROWTH RATCHET, not a measured quality threshold: the 7,308-trajectory study behind the 3,500-token skill ceiling (ADR-217) was taken on procedural always-co-loaded skills, and this layer is declarative and loaded one or two files at a time. Replace the number when someone measures comprehension on THIS layer."
13
19
  },
14
20
  "check_gate_completeness": {
15
- "count": 215,
16
- "landed": "2026-08-17",
17
- "note": "Ledger adoption ratchet. Gates registered under the CI task roots that carry neither per-target completeness accounting (`_lib/gate_ledger.ts`) nor a `// ledger-exempt:` marker. This is deliberately NOT a sweep: road-to-skill-ecosystem-gate-integrity Phase 1 adopts exactly three gates (lint_framework_leakage, check_references, lint_roadmap_complexity) plus the checker itself to prove the interface, and the remainder migrates as gates are touched. Shrink-only from here \u2014 the number may not grow, so a NEW gate must adopt or exempt. Lowered 216 -> 215 on 2026-08-17 by discharging the obligation three NEW arrivals had incurred, which is the standing rule being enforced rather than a drain: the registered population grew 244 -> 258 and three of the fourteen arrivals adopted nothing \u2014 `build_archive_index`, `check_gate_coverage`, `check_pr_ci_current`. The reading was 218 against this baseline of 216, and the missing arithmetic is that one PRE-existing gate (`lint_rule_skill_pack_reach`) had adopted in the meantime: 216 + 3 - 1 = 218. All three adopted a real ledger. `check_pr_ci_current` first took a reasoned exemption claiming no target population; the completion review refuted it from the file itself \u2014 the check rows ARE a population, and rows whose `state` is not a string were being dropped before any verdict ran, so a dropped row could be the failing one. The exemption was withdrawn and the ledger adopted, counting kept rows as read, dropped rows as skips, and rows a pre-row verdict never reached as out of scope. The denominator in this note was 14 stale (it said 244) and is now expressed without one, because a count pinned to a population that grows weekly rots faster than the count itself. Note what this lowering does NOT buy: headroom is zero either way, so the next un-adopted arrival reds this gate immediately \u2014 which is the intended behaviour and the reason the number is not padded. The refreshed `landed` is load-bearing rather than bookkeeping: `checkRatchet` returns `improved` BEFORE it evaluates staleness, so an entry left at 216 while the tree measures 215 would never expire at any age (pinned by tests/lib/gate_baseline.test.ts, which asserts `improved` at landed + STALE_AFTER_DAYS + 400 days) \u2014 the greenest available state and the worst, since it switches off the anti-fossilization clause exactly when someone has done real work.",
21
+ "count": 214,
22
+ "landed": "2026-08-30",
23
+ "note": "Ledger adoption ratchet. Gates registered under the CI task roots that carry neither per-target completeness accounting (`_lib/gate_ledger.ts`) nor a `// ledger-exempt:` marker. This is deliberately NOT a sweep: road-to-skill-ecosystem-gate-integrity Phase 1 adopts exactly three gates (lint_framework_leakage, check_references, lint_roadmap_complexity) plus the checker itself to prove the interface, and the remainder migrates as gates are touched. Shrink-only from here — the number may not grow, so a NEW gate must adopt or exempt. Lowered 216 -> 215 on 2026-08-17 by discharging the obligation three NEW arrivals had incurred, which is the standing rule being enforced rather than a drain: the registered population grew 244 -> 258 and three of the fourteen arrivals adopted nothing — `build_archive_index`, `check_gate_coverage`, `check_pr_ci_current`. The reading was 218 against this baseline of 216, and the missing arithmetic is that one PRE-existing gate (`lint_rule_skill_pack_reach`) had adopted in the meantime: 216 + 3 - 1 = 218. All three adopted a real ledger. `check_pr_ci_current` first took a reasoned exemption claiming no target population; the completion review refuted it from the file itself — the check rows ARE a population, and rows whose `state` is not a string were being dropped before any verdict ran, so a dropped row could be the failing one. The exemption was withdrawn and the ledger adopted, counting kept rows as read, dropped rows as skips, and rows a pre-row verdict never reached as out of scope. The denominator in this note was 14 stale (it said 244) and is now expressed without one, because a count pinned to a population that grows weekly rots faster than the count itself. Note what this lowering does NOT buy: headroom is zero either way, so the next un-adopted arrival reds this gate immediately — which is the intended behaviour and the reason the number is not padded. The refreshed `landed` is load-bearing rather than bookkeeping: `checkRatchet` returns `improved` BEFORE it evaluates staleness, so an entry left at 216 while the tree measures 215 would never expire at any age (pinned by tests/lib/gate_baseline.test.ts, which asserts `improved` at landed + STALE_AFTER_DAYS + 400 days) — the greenest available state and the worst, since it switches off the anti-fossilization clause exactly when someone has done real work. Lowered 215 -> 214 on 2026-08-30 by the same standing rule, and the arithmetic is worth stating because a new gate normally moves this number the OTHER way: `lint_metric_consumers` arrived registered, and it adopted a real ledger in the change that added it rather than spending the slot. The registered population grew by one and the non-adopter count fell by one. `landed` is refreshed for the reason the previous entry records: `checkRatchet` returns `improved` before it evaluates staleness, so a count left at 215 while the tree measures 214 would never expire at any age — the greenest available state and the worst.",
18
24
  "falsifier": "./scripts-run src/scripts/check_gate_completeness"
19
25
  },
20
26
  "check_no_new_legacy_path:hardcoded-scan-roots": {
21
- "count": 47,
22
- "landed": "2026-08-13",
23
- "note": "Lines under src/scripts/**/*.{ts,mts,mjs} that pass the retired `.agent-src.uncondensed` directory into `path.join(...)` \u2014 a filesystem path CONSTRUCTED against the tree ADR-051 abandoned, which is the exact shape of all 14 dead gates. Deliberately narrow so the number is signal, not noise: 236 raw mentions under src/scripts \u2192 147 string-literal lines \u2192 67 path-constructing lines when the pass was written, after exempting src/scripts/_lib/agent_src.ts (the shared resolver, whose job IS owning the constant \u2014 gates that route through it survived the move). Detectors holding the literal as data to match, strip, or print are not counted, and no prose, docs, tests or fixtures are read: that full-tree shape was measured at 44 files / 213 hits and rejected as the wrong lint (see the note in check_no_new_legacy_path.ts::find_offenders). Recorded at 58 rather than 67 because Phase 1's scan-root repairs were landing on this branch while the pass was being written and had already removed 9 \u2014 a baseline above the truth silently permits new violations. This count goes to ZERO as the remaining repairs land; every repair is a lowering commit. Lowered 56\u219251 by the road-to-renewal-foundation Phase 1 dead-root sweep (check_always_budget, check_portability, check_references, lint_framework_leakage, lint_agents_md). Lowered 51\u219249 by the gate-hardening adoption PR: skill_collision_clusters and skill_overlap were repointed at the live skills tree via the shared resolver \u2014 two gates that had been reading the retired container and scoring 0 of 288 skills. Lowered 49\u219248 by road-to-rule-delivery-integrity P2.2: score_skill_selection was repointed at the live skills tree via the shared resolver. It is the same shape as the two gates lowered before it \u2014 a scorer reading the retired container and scoring 0 of 288 skills \u2014 and here the consequence was sharper than a dead gate: the roadmap's pre-registered selection-accuracy criteria would have been compared against a baseline of silent zeros. Lowered 48\u219247 on 2026-08-13, and this one is a catch-up rather than a repair: the pass reported 47 against a baseline of 48, so a gain had already landed without the ratchet following it. Attributed to 455160160 (fix(evals): resolve the eval orchestrator against the live skills tree), the most recent repair in this branch's base that removes a path-constructing line \u2014 SKILLS_ROOT repointed through _lib/agent_src.ts::SRC_SKILLS(). A loose ratchet is not harmless: it silently permits one new violation to be added back without any gate noticing, which is the shape this entry exists to prevent."
27
+ "count": 46,
28
+ "landed": "2026-08-30",
29
+ "note": "Lowered 47 -> 46 on 2026-08-30 by road-to-source-silence-cutover step 3.1, and the gain was INCIDENTAL rather than sought: narrowing the `source-header` class replaced a whole-value scan with a per-token one, and one hardcoded scan root went with the code that no longer needed it. Set to the EXACT live total, per this file's convention — the gate reported the tree at 46 against a baseline of 47 and said so, which is how a loose ratchet surfaces here rather than by inspection. `landed` refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: Lines under src/scripts/**/*.{ts,mts,mjs} that pass the retired `.agent-src.uncondensed` directory into `path.join(...)` — a filesystem path CONSTRUCTED against the tree ADR-051 abandoned, which is the exact shape of all 14 dead gates. Deliberately narrow so the number is signal, not noise: 236 raw mentions under src/scripts → 147 string-literal lines → 67 path-constructing lines when the pass was written, after exempting src/scripts/_lib/agent_src.ts (the shared resolver, whose job IS owning the constant — gates that route through it survived the move). Detectors holding the literal as data t"
24
30
  },
25
31
  "check_roadmap_trackable:relates": {
26
32
  "count": 9,
@@ -28,31 +34,37 @@
28
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."
29
35
  },
30
36
  "check_source_size_budget": {
31
- "count": 18512,
32
- "landed": "2026-08-24",
33
- "note": "Lowered 18,561 -> 18,512 on 2026-08-24 by the same method every prior entry here prescribes \u2014 the merged tree MEASURED, never a side picked. main had reached 18,561; this branch (road-to-skill-delivery-over-mcp) carries its own extractions, and the merged total reads 18,512, a -49 gain that would have been silently given back by keeping main's number. Set to the EXACT live total, because check_source_size_budget.test.ts asserts baseline == tree total; a baseline loose by one line is a red test, and that is how this surfaced. Prior entry: lowered 18,566 -> 18,561 on 2026-08-24 by the method the two prior entries prescribe, for the same reason: independent gains met in a merge, so the merged tree was MEASURED rather than a side picked. main had reached 18,566 via road-to-skill-link-integrity-and-manifest-sync Phase 2; this branch had already paid its own extraction under road-to-trigger-delivered-rule-bodies 1.6 (condense.ts's inline mode literal moved whole to _lib/lean_projection_mode.ts, -5; the new module is 45 lines and therefore free). check_source_size_budget reports 18,561 on the merged tree, exactly 18,566 - 5, so picking either side's number would have given back the other's gain. Set to the EXACT live total: check_source_size_budget.test.ts asserts baseline == tree total, so a baseline loose by one line is a red test \u2014 which is how this lowering surfaced rather than by inspection. `landed` refreshed deliberately, not as bookkeeping: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: lowered 18,574 -> 18,571 on 2026-08-23, and the -3 is the SUM of two independent lowerings-through-extraction that met in a merge, not a new reduction. main had already reached 18,573 via road-to-override-efficacy-proof (-1: _check_overrides moved whole to _cli/doctor_overrides.ts, -119, and the install-mode detector plus its marker constant to _cli/doctor_install_mode.ts, -14, both names forwarded with `export ... from`; net -1 past zero rather than exactly to it, because the unit that paid is a unit). This branch had reached 18,572 via road-to-council-evidence-integrity Phases 1-2 (-2: the two result bundles PeerReviewResult and ConsensusResult, -98, the two options interfaces, -19, and CouncilQuestion, -11, all PURE MOVES into ai_council/orchestrator_results.ts, with orchestrator.ts re-exporting every name; the options interfaces required a TYPE-ONLY back-import of OnOverrunCallback, legal and runtime-free since both directions are erased). The merge conflict was resolved by MEASURING the merged tree rather than picking a side: check_source_size_budget reports 18571 on it, which is exactly 18,574 - 1 - 2. Picking either branch's number would have silently given back the other branch's gain -- the failure main's own entry names one line above. Set to the EXACT live total: check_source_size_budget.test.ts asserts baseline == tree total, so a baseline left loose by even one line is a red test. Lowered 18,571 -> 18,566 on 2026-08-23 by road-to-skill-link-integrity-and-manifest-sync Phase 2, which had to pay its own way before it could pass: adding set_augment_manifest_version to release.ts charged +35 lines, because release.ts is 564 lines PAST the 1500-line threshold and every line above it counts. The fix was extraction, never a bump. Both manifest-version writers -- the new set_augment_manifest_version and its pre-existing twin set_marketplace_version -- moved whole into release_env.ts, the leaf that already owns both manifest paths AND jsonDumpsIndent, so neither function needed anything it did not already have there. release_env.ts is 298 lines, far under the threshold, so those lines are now free. release.ts re-exports set_marketplace_version so its existing test import keeps resolving; the new function is imported from release_env directly. Net -5 past zero rather than exactly to it, for the same reason main's entry gives: the unit that pays is a unit."
37
+ "count": 18246,
38
+ "landed": "2026-08-30",
39
+ "note": "Lowered 18,437 -> 18,246 ON THE MERGE, 2026-08-30, by MEASURING the merged tree rather than picking a side -- the method every prior entry here prescribes and the exact case several of them describe. Two branches of one drain run each paid their own way independently against different bases: road-to-turnaround-followups Phase 3 reached 18,437 by moving the claude-code post-copy reporting into src/install/claudeRuleRewrite.ts, and this branch reached 18,249 by moving the inline-findings concern, run_consensus_scoring and _serialise_responses into three modules under the ceiling. The merged tree measures 18,246, which is BELOW both -- neither side's number would have been correct, and keeping either would have silently given back the other's gain. Set to the EXACT live total because check_source_size_budget.test.ts asserts baseline == tree total in both directions. ONE CORRECTION CARRIED FORWARD BY HAND, because the merge would otherwise have dropped it: this branch's superseded entry had fixed a stale figure a completion review found in it -- it recorded orchestrator.ts at 2,067 lines where the tree measures 2,038 -- and that entry is gone now, taking both the false sentence and the record of its correction with it. The false sentence is what mattered and it is gone; the correction is restated here so a reader can see it was made rather than inferring the number was never wrong. `landed` refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: Lowered 18,440 -> 18,437 on 2026-08-30 by road-to-turnaround-followups Phase 3, which had to pay its own way before it could pass. Calling the Claude host-form emitter from the installer charged lines to src/scripts/install.ts, which sits ~3,900 lines PAST the 1500-line threshold, so every added line counts. The fix was EXTRACTION, never a bump, and it went further than break-even: the new concern lives in src/install/claudeRuleRewrite.ts (far under the threshold and therefore free), and the claude-code flat-command WRAPPER reporting moved there with it. That reporting belongs there on merit rather than only on budget -- it is claude-code post-copy reporting exactly like the rule rewrite, the emitted messages are byte-identical, and the reviewer diffed them mechanically against HEAD~1 to confirm no guard changed scope. install.ts ends up SHORTER than before this feature. Set to the EXACT live total because check_source_size_budget.test.ts asserts baseline == tree total in BOTH directions -- a baseline left loose by even one line is a red test, not tolerated slack, and that is how this lowering surfaced rather than by inspection. NOTE ON METHOD, recorded because the first instinct here was wrong: a gate reporting its own ratchet loose is normally NOT evidence for lowering it -- only the enforcing environment's reading is, which is the lesson check_ci_local_parity taught when a local lowering met a CI count one higher. That caution does not transfer to THIS gate: its count is a line tally over tracked source, a property of the tree rather than of the environment, and its own test asserts equality, so leaving the baseline high is a red test rather than safe conservatism. `landed` refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: Lowered 18,446 -> 18,440 on 2026-08-27 by fix/council-cost-truth, which paid its own way through EXTRACTION rather than a bump. Replacing three inline cost-accumulation loops in council_cli.ts with calls to sumBillableCost took that file 3,981 -> 3,975 lines, and it sits 2,475 lines PAST the 1500-line threshold, so all six removed lines count. The three new helpers -- sumBillableCost, isBillableResponse, allSeatsNonBillable -- landed in ai_council/pricing.ts, which goes 445 -> 551 lines and is therefore still FAR under the threshold: those 106 added lines are free. Net -6, which is exactly the gate's reading. pricing.ts is where they belong on merit, not only on budget: it already owns estimate_cost and the price table, so cost logic reading a price table has no other home. Set to the EXACT live total, because check_source_size_budget.test.ts asserts baseline == tree total -- and that is how this lowering surfaced: CI shard 2/4 red on both ubuntu and macOS with 'expected 18446 to be 18440', where the gate itself only advises. `landed` refreshed deliberately, not as bookkeeping: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: Lowered 18,474 -> 18,446 on 2026-08-26 by road-to-consumer-repo-reality Phase 1, which had to pay its own way before it could pass. Wiring the three install-reach checks into cmd_doctor.ts charged +5 lines, because that file is ~2,150 lines PAST the 1500-line threshold and every line above it counts. The fix was extraction, never a bump: the two runtime-presence checks -- _check_python_runtime and _check_humanizer_runtime -- moved WHOLE into _lib/doctor_runtime_checks.ts. They are cohesive with each other and with nothing else in that file (each answers 'is a runtime present, and what happens when it is not'; neither reads the manifest, the drift sets, or the project root), and their one dependency, shutilWhich, is PASSED IN rather than imported -- it is defined in cmd_doctor.ts itself, so importing it back would have made the two modules circular, and a parameter is cheaper than moving a shared utility four other call sites already resolve from there. Thin wrappers keep the historical names and arity, so the runner map, the export block and the existing fallback test are untouched. cmd_doctor.ts goes 3,666 -> 3,638 lines. Set to the EXACT live total: check_source_size_budget.test.ts asserts baseline == tree total, so a baseline left loose by even one line is a RED TEST rather than tolerated slack -- which is how this lowering surfaced, in a neutral review of the branch rather than by inspection. `landed` refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: Lowered 18,489 -> 18,474 on 2026-08-26 by road-to-internal-estate-fit Phase 2, which paid its own way and then some. De-duplicating SCOPE_DETECT_MANIFESTS and SCOPE_DETECT_AI_DIRS removed two byte-for-byte constant blocks from src/scripts/install.ts, which is 3,902 lines PAST the 1500-line threshold, so every removed line counts. One exported definition each now lives in src/install/detect.ts (far under the threshold and therefore free) and install.ts imports them. Net -15. Set to the EXACT live total, because check_source_size_budget.test.ts asserts baseline == tree total -- a baseline left loose by even one line is a red test, and that is how this lowering surfaced rather than by inspection: CI reported 'expected 18489 to be 18474'. `landed` refreshed deliberately, not as bookkeeping: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Lowered 18,511 -> 18,489 ON THE MERGE, 2026-08-26, by MEASURING the merged tree rather than picking a side — which is the method every prior entry here prescribes and the exact case several of them describe. Two branches of one drain run each paid their own way independently: road-to-skill-ecosystem-runtime-enforcement extracted the four runtime-wiring checks into _lib/runtime_wiring_checks.ts and the transcript reader into _lib/loop_guards, reaching 18,490 against a base of 18,512; road-to-skill-ecosystem-eval-integrity extracted the exact binary tests, the CPython erf port, wilcoxon and the float-parity rounder into _lib/paired_stats.ts, reaching 18,511 against the same base. The merged tree measures 18,489 — which is 18,512 - 22 - 1, i.e. the SUM of both gains, so picking either branch's number would have silently given back the other branch's. Set to the EXACT live total: check_source_size_budget.test.ts asserts baseline == tree total, so a baseline loose by even one line is a red test. Both derivations are preserved below rather than one being dropped, because each records a real extraction and the pair is the evidence for this number. Prior entry (runtime-enforcement branch): lowered 18,512 -> 18,490 on 2026-08-26. Prior entry (eval-integrity branch): lowered 18,512 -> 18,511 on 2026-08-26 by road-to-skill-ecosystem-eval-integrity Phase 2, which had to pay its own way before it could pass. Adding direction counts to `_paired_median_block` charged +24 lines, because bench_ab_v2_stats.ts was 25 lines PAST the 1500-line threshold and every line above it counts. The fix was extraction, never a bump: _lib/paired_stats.ts now holds mcnemar_exact, cohens_h, the CPython erf/normal-CDF port, wilcoxon, and the float-parity rounder those need. Every name is re-exported from bench_ab_v2_stats.ts, so `check_quality_regression`'s existing `wilcoxon` import and every other consumer resolve unchanged. bench_ab_v2_stats.ts goes 1525 -> 1329 lines, well under the threshold, so those lines are now free. Net -1 past zero rather than exactly to it, for the reason every prior entry here gives: the unit that pays is a unit. Set to the EXACT live total — check_source_size_budget.test.ts asserts baseline == tree total, so a baseline left loose by one line is a red test, and that is how this lowering surfaced rather than by inspection. `landed` refreshed deliberately: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: lowered 18,561 -> 18,512 on 2026-08-24 by the same method every prior entry here prescribes — the merged tree MEASURED, never a side picked. main had reached 18,561; this branch (road-to-skill-delivery-over-mcp) carries its own extractions, and the merged total reads 18,512, a -49 gain that would have been silently given back by keeping main's number. Set to the EXACT live total, because check_source_size_budget.test.ts asserts baseline == tree total; a baseline loose by one line is a red test, and that is how this surfaced. Prior entry: lowered 18,566 -> 18,561 on 2026-08-24 by the method the two prior entries prescribe, for the same reason: independent gains met in a merge, so the merged tree was MEASURED rather than a side picked. main had reached 18,566 via road-to-skill-link-integrity-and-manifest-sync Phase 2; this branch had already paid its own extraction under road-to-trigger-delivered-rule-bodies 1.6 (condense.ts's inline mode literal moved whole to _lib/lean_projection_mode.ts, -5; the new module is 45 lines and therefore free). check_source_size_budget reports 18,561 on the merged tree, exactly 18,566 - 5, so picking either side's number would have given back the other's gain. Set to the EXACT live total: check_source_size_budget.test.ts asserts baseline == tree total, so a baseline loose by one line is a red test — which is how this lowering surfaced rather than by inspection. `landed` refreshed deliberately, not as bookkeeping: checkRatchet returns `improved` BEFORE it evaluates staleness, so an entry left at the old number while the tree measures lower would never expire at any age. Prior entry: lowered 18,574 -> 18,571 on 2026-08-23, and the -3 is the SUM of two independent lowerings-through-extraction that met in a merge, not a new reduction. main had already reached 18,573 via road-to-override-efficacy-proof (-1: _check_overrides moved whole to _cli/doctor_overrides.ts, -119, and the install-mode detector plus its marker constant to _cli/doctor_install_mode.ts, -14, both names forwarded with `export ... from`; net -1 past zero rather than exactly to it, because the unit that paid is a unit). This branch had reached 18,572 via road-to-council-evidence-integrity Phases 1-2 (-2: the two result bundles PeerReviewResult and ConsensusResult, -98, the two options interfaces, -19, and CouncilQuestion, -11, all PURE MOVES into ai_council/orchestrator_results.ts, with orchestrator.ts re-exporting every name; the options interfaces required a TYPE-ONLY back-import of OnOverrunCallback, legal and runtime-free since both directions are erased). The merge conflict was resolved by MEASURING the merged tree rather than picking a side: check_source_size_budget reports 18571 on it, which is exactly 18,574 - 1 - 2. Picking either branch's number would have silently given back the other branch's gain -- the failure main's own entry names one line above. Set to the EXACT live total: check_source_size_budget.test.ts asserts baseline == tree total, so a baseline left loose by even one line is a red test. Lowered 18,571 -> 18,566 on 2026-08-23 by road-to-skill-link-integrity-and-manifest-sync Phase 2, which had to pay its own way before it could pass: adding set_augment_manifest_version to release.ts charged +35 lines, because release.ts is 564 lines PAST the 1500-line threshold and every line above it counts. The fix was extraction, never a bump. Both manifest-version writers -- the new set_augment_manifest_version and its pre-existing twin set_marketplace_version -- moved whole into release_env.ts, the leaf that already owns both manifest paths AND jsonDumpsIndent, so neither function needed anything it did not already have there. release_env.ts is 298 lines, far under the threshold, so those lines are now free. release.ts re-exports set_marketplace_version so its existing test import keeps resolving; the new function is imported from release_env directly. Net -5 past zero rather than exactly to it, for the same reason main's entry gives: the unit that pays is a unit."
34
40
  },
35
41
  "ci-parity:local-only": {
36
42
  "count": 165,
37
43
  "landed": "2026-08-24",
38
- "note": "Gates that `task ci` runs and no workflow does \u2014 the direction this manifest's own header calls the one that let real defects merge (16 stale index rows reached the trunk behind a local-only check-index). Revealed, not created, by repairing the checker's extraction: check_ci_local_parity built its CI-side set by regexing RAW workflow text for `task <name>` and expanding each closure, comments included. Several workflow comments contain the literal string `task ci` while stating that no workflow invokes it, so `ci` was read as an invocation and its full 247-gate closure entered the 'runs in CI' set. The count was therefore 0 BY CONSTRUCTION, and the prose documenting the gap was what suppressed it. Measured at the repair: CI-side 273 \u2192 106, undeclared_local_only 0 \u2192 167 of 247 local gates (68%). Baselined rather than hard-failed because 167 findings nobody can clear in the change that reveals them is the gate-that-lands-as-N-instant-blockers failure this repository has refused before; shrink-only keeps the property that matters, namely that a NEW gate registered in `task ci` with no workflow reds immediately. Lowering happens by wiring gates into workflows or declaring them under `local_only:` with a reason. Note the punchline, because it bounds the risk of this entry: check_ci_local_parity ITSELF runs in no workflow, so it is its own finding and this ratchet has no remote reach either \u2014 clearing the backlog is what gives it teeth. DRAINED BY ONE, 2026-08-13: check_ci_local_parity itself was wired into consistency.yml, so it left the set it exists to report. That is the whole shape of a legitimate drain here \u2014 the gate stops being local-only because a workflow now runs it, not because the declaration list grew. The floor in gate-coverage.yml moved in the same change and for the same reason: wiring two gates raised the parsed population 357 -> 360 (109 CI + 251 local). The intermediate 359 was the reading after the CI-side wiring alone and before check_gate_coverage joined the local `ci` chain; it was committed here by mistake and is corrected rather than left as a second number for the same measurement. WALKED DOWN 166 -> 165 on 2026-08-20 (road-to-session-closeout 5.2): check_ci_local_parity reported `ci-parity:local-only: 165 violation(s), baseline 166 - ratchet is loose` and asked for exactly this, so the gain cannot be silently given back. The measurement is the gate's own output on the merged tree, not a branch. What is NOT done here is the classification the same step asks for: 165 gates each need a recorded class (belongs-in-CI / developer-aid / dead), which is per-gate judgement, and migrating them would red the trunk on the landing day - the step forbids it for that reason. ATTEMPTED 165 -> 164 on 2026-08-24 and REVERTED in the same change, recorded because the mistake is instructive rather than embarrassing. A local run of check_ci_local_parity reported the ratchet LOOSE at 164 and asked to be lowered; CI then measured 165 and red the gate at '1 new'. The local reading was environment-dependent -- the drain worktree resolves the projection surface differently from a clean checkout, which is the same worktree divergence check_rule_projection_integrity shows on the same tree -- so the number was never real slack. THE RULE THIS CONFIRMS: this baseline is walked down on a reading from the ENFORCING environment, never on a local one, exactly as the 166 -> 165 paragraph above says ('the measurement is the gate's own output on the merged tree, not a branch'). A gate inviting a lowering is not evidence that the lowering is correct.",
44
+ "note": "Gates that `task ci` runs and no workflow does — the direction this manifest's own header calls the one that let real defects merge (16 stale index rows reached the trunk behind a local-only check-index). Revealed, not created, by repairing the checker's extraction: check_ci_local_parity built its CI-side set by regexing RAW workflow text for `task <name>` and expanding each closure, comments included. Several workflow comments contain the literal string `task ci` while stating that no workflow invokes it, so `ci` was read as an invocation and its full 247-gate closure entered the 'runs in CI' set. The count was therefore 0 BY CONSTRUCTION, and the prose documenting the gap was what suppressed it. Measured at the repair: CI-side 273 → 106, undeclared_local_only 0 → 167 of 247 local gates (68%). Baselined rather than hard-failed because 167 findings nobody can clear in the change that reveals them is the gate-that-lands-as-N-instant-blockers failure this repository has refused before; shrink-only keeps the property that matters, namely that a NEW gate registered in `task ci` with no workflow reds immediately. Lowering happens by wiring gates into workflows or declaring them under `local_only:` with a reason. Note the punchline, because it bounds the risk of this entry: check_ci_local_parity ITSELF runs in no workflow, so it is its own finding and this ratchet has no remote reach either — clearing the backlog is what gives it teeth. DRAINED BY ONE, 2026-08-13: check_ci_local_parity itself was wired into consistency.yml, so it left the set it exists to report. That is the whole shape of a legitimate drain here — the gate stops being local-only because a workflow now runs it, not because the declaration list grew. The floor in gate-coverage.yml moved in the same change and for the same reason: wiring two gates raised the parsed population 357 -> 360 (109 CI + 251 local). The intermediate 359 was the reading after the CI-side wiring alone and before check_gate_coverage joined the local `ci` chain; it was committed here by mistake and is corrected rather than left as a second number for the same measurement. WALKED DOWN 166 -> 165 on 2026-08-20 (road-to-session-closeout 5.2): check_ci_local_parity reported `ci-parity:local-only: 165 violation(s), baseline 166 - ratchet is loose` and asked for exactly this, so the gain cannot be silently given back. The measurement is the gate's own output on the merged tree, not a branch. What is NOT done here is the classification the same step asks for: 165 gates each need a recorded class (belongs-in-CI / developer-aid / dead), which is per-gate judgement, and migrating them would red the trunk on the landing day - the step forbids it for that reason. ATTEMPTED 165 -> 164 on 2026-08-24 and REVERTED in the same change, recorded because the mistake is instructive rather than embarrassing. A local run of check_ci_local_parity reported the ratchet LOOSE at 164 and asked to be lowered; CI then measured 165 and red the gate at '1 new'. The local reading was environment-dependent -- the drain worktree resolves the projection surface differently from a clean checkout, which is the same worktree divergence check_rule_projection_integrity shows on the same tree -- so the number was never real slack. THE RULE THIS CONFIRMS: this baseline is walked down on a reading from the ENFORCING environment, never on a local one, exactly as the 166 -> 165 paragraph above says ('the measurement is the gate's own output on the merged tree, not a branch'). A gate inviting a lowering is not evidence that the lowering is correct.",
39
45
  "falsifier": "./scripts-run src/scripts/check_ci_local_parity"
40
46
  },
41
47
  "gate-self-test:registered-non-adopters": {
42
48
  "count": 24,
43
49
  "landed": "2026-08-06",
44
- "note": "Self-test adoption ratchet, expressed as a shrink-only NON-adopter count. 24 of the 32 gates registered enforced in gate-coverage.yml carry neither a `--self-test` (`_lib/gate_self_test.ts`) nor a `// self-test-exempt: <reason>` marker, so nothing proves they DISCRIMINATE \u2014 an enforced `scanned:` floor proves a gate read something, only a self-test proves the reading changes the verdict. Deliberately NOT an adoption column ratcheted upward: check_gate_coverage.ts's own report_hardening_ratchet rejects that shape in this same file (\"grades the solution instead of the problem\"), and the sibling adoption ratchet (check_gate_completeness) is already a non-adopter count. Population is the manifest, not every script under src/scripts: padding the manifest to move this number would mean adding a floor per row. Shrink-only from here \u2014 a NEW registered gate must adopt or exempt. Migration mechanism, same as the ledger ratchet above: gates adopt as they are touched, not in a sweep \u2014 the eight current adopters were each added alongside a real change to that gate. The 56-day non-stagnation clause applies unchanged, so a count parked here fails on its own.",
50
+ "note": "Self-test adoption ratchet, expressed as a shrink-only NON-adopter count. 24 of the 32 gates registered enforced in gate-coverage.yml carry neither a `--self-test` (`_lib/gate_self_test.ts`) nor a `// self-test-exempt: <reason>` marker, so nothing proves they DISCRIMINATE — an enforced `scanned:` floor proves a gate read something, only a self-test proves the reading changes the verdict. Deliberately NOT an adoption column ratcheted upward: check_gate_coverage.ts's own report_hardening_ratchet rejects that shape in this same file (\"grades the solution instead of the problem\"), and the sibling adoption ratchet (check_gate_completeness) is already a non-adopter count. Population is the manifest, not every script under src/scripts: padding the manifest to move this number would mean adding a floor per row. Shrink-only from here — a NEW registered gate must adopt or exempt. Migration mechanism, same as the ledger ratchet above: gates adopt as they are touched, not in a sweep — the eight current adopters were each added alongside a real change to that gate. The 56-day non-stagnation clause applies unchanged, so a count parked here fails on its own.",
45
51
  "falsifier": "./scripts-run src/scripts/check_gate_coverage"
46
52
  },
53
+ "lint_canonical_terms": {
54
+ "count": 1007,
55
+ "landed": "2026-08-26",
56
+ "note": "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 — `sweep_authorised: false` is a live constraint, and 1,025 occurrences cannot be rewritten in the change that introduces the check. The ratchet IS the council's staged promotion: report-only for existing debt, blocking for anything new. Measured 1,025 before the bounded pilot and 1,007 after it — the pilot was chosen by BLAST RADIUS, not by pair, per the council's explicit condition: the three smallest-radius pairs (`sub-agent`→`subagent`, `grey`→`gray`, `canonicalise`→`canonicalize`) at 18 occurrences across 12 files, with zero overlap with active work (no open PRs at the time). What remains is dominated by two large-radius pairs — `artefact`→`artifact` (619 occurrences / 239 files) and `behaviour`→`behavior` (325 / 171) — plus `hand-off`→`handoff` (46 / 36) and `licence`→`license` (17 / 12), the last of which the map flags `semantic-care-required` because licence TITLES are protected text. Shrink-only from here: each further wave lowers this number. Full classified inventory: agents/evidence/analysis/canonical-terms-inventory-2026-08-26.md.",
57
+ "falsifier": "./scripts-run src/scripts/lint_canonical_terms"
58
+ },
47
59
  "lint_handoffs": {
48
60
  "count": 18,
49
61
  "landed": "2026-08-02",
50
- "note": "All 18 are `handoff_tier_mismatch`: a senior-tier skill links to a peer whose frontmatter carries no `tier` (reported as tier='unset') \u2014 e.g. build-buy-partner \u2192 adr-create, customer-research \u2192 po-discovery, gated-reach \u2192 threat-modeling. This is a tier-metadata backfill backlog on the LINKED-TO skills, not a broken link. The one genuinely dangling link revealed by the same repair (competitive-positioning \u2192 a non-existent ../analyze-reference-repo/SKILL.md; it is a command, not a skill) was FIXED in the repairing commit rather than baselined. Clearing this entry means backfilling `tier` on the linked-to skills, or deciding that `tier: unset` on a link target is not a violation and narrowing the rule."
62
+ "note": "All 18 are `handoff_tier_mismatch`: a senior-tier skill links to a peer whose frontmatter carries no `tier` (reported as tier='unset') — e.g. build-buy-partner → adr-create, customer-research → po-discovery, gated-reach → threat-modeling. This is a tier-metadata backfill backlog on the LINKED-TO skills, not a broken link. The one genuinely dangling link revealed by the same repair (competitive-positioning → a non-existent ../analyze-reference-repo/SKILL.md; it is a command, not a skill) was FIXED in the repairing commit rather than baselined. Clearing this entry means backfilling `tier` on the linked-to skills, or deciding that `tier: unset` on a link target is not a violation and narrowing the rule."
51
63
  },
52
64
  "lint_pack_boundaries": {
53
65
  "count": 337,
54
66
  "landed": "2026-08-02",
55
- "note": "Markdown links between source artefacts that cross a pack boundary the source pack's `requires` graph does not reach \u2014 revealed when the scan root moved off the deleted packages/ tree to the live corpus (0 -> 753 artefacts scanned). 82 distinct pack pairs across 131 source files; largest single class is engineering-base -> meta (73), skills in a consumer-installable pack citing this package's own maintenance skills. Each is a link that dangles for a consumer who installs the source pack without the target's. Judged real drift rather than an over-strict gate because it is long-tailed \u2014 top bucket 22%, no single systematic cause \u2014 unlike the lint_artefact_frontmatter case, where one required shape had 0-of-288 adoption. Fix per finding: add the edge to packs.yml requires, retarget the link, or move the artefact."
67
+ "note": "Markdown links between source artefacts that cross a pack boundary the source pack's `requires` graph does not reach — revealed when the scan root moved off the deleted packages/ tree to the live corpus (0 -> 753 artefacts scanned). 82 distinct pack pairs across 131 source files; largest single class is engineering-base -> meta (73), skills in a consumer-installable pack citing this package's own maintenance skills. Each is a link that dangles for a consumer who installs the source pack without the target's. Judged real drift rather than an over-strict gate because it is long-tailed — top bucket 22%, no single systematic cause — unlike the lint_artefact_frontmatter case, where one required shape had 0-of-288 adoption. Fix per finding: add the edge to packs.yml requires, retarget the link, or move the artefact."
56
68
  },
57
69
  "lint_provenance_vocabulary:permanence-language": {
58
70
  "count": 5,
@@ -63,18 +75,24 @@
63
75
  "lint_settings_classes:derivable-surface": {
64
76
  "count": 83,
65
77
  "landed": "2026-08-12",
66
- "note": "Anti-regrowth ratchet for the settings disposition axis. 83 of 134 template leaves are classified `derivable` \u2014 the mechanism can decide from the situation, so the key should not exist \u2014 and each names the replacement that would decide instead (`lint_settings_classes` rejects the bare label, which is what keeps the class from becoming a synonym for \"inconvenient to keep\"). This is a DELETION QUEUE, not 83 deletions: a row stays until the mechanism it names actually exists, and deleting a key ahead of its mechanism is a silently-changed default rather than a simplification. Shrink-only from here, which is the anti-regrowth half \u2014 a NEW key classified `derivable` raises the number and reds, so a key whose answer the situation already carries cannot be added at all. The 56-day non-stagnation clause is the other half and is wanted here rather than tolerated: a queue that never drains is a stated direction nobody is walking. The queue opened at 88 of 140 on 2026-08-12 and drained to 83 of 134 the same day: six keys had no reader whatsoever (telegraph.speak_scope, chat_history.max_size_kb, chat_history.on_overflow, quality.wait_for_remote_ci, screenshots.data_bearing_gate, legal_review_prep.consented_at), five of them `derivable` and one a `consent` row reclassified because a published-egress confirmation is a Hard Floor no setting may lift. An unread key is the only deletion that cannot silently change a default, which is why that batch went first. The classification itself is docs/contracts/settings-classes.md.",
78
+ "note": "Anti-regrowth ratchet for the settings disposition axis. 83 of 134 template leaves are classified `derivable` — the mechanism can decide from the situation, so the key should not exist — and each names the replacement that would decide instead (`lint_settings_classes` rejects the bare label, which is what keeps the class from becoming a synonym for \"inconvenient to keep\"). This is a DELETION QUEUE, not 83 deletions: a row stays until the mechanism it names actually exists, and deleting a key ahead of its mechanism is a silently-changed default rather than a simplification. Shrink-only from here, which is the anti-regrowth half — a NEW key classified `derivable` raises the number and reds, so a key whose answer the situation already carries cannot be added at all. The 56-day non-stagnation clause is the other half and is wanted here rather than tolerated: a queue that never drains is a stated direction nobody is walking. The queue opened at 88 of 140 on 2026-08-12 and drained to 83 of 134 the same day: six keys had no reader whatsoever (telegraph.speak_scope, chat_history.max_size_kb, chat_history.on_overflow, quality.wait_for_remote_ci, screenshots.data_bearing_gate, legal_review_prep.consented_at), five of them `derivable` and one a `consent` row reclassified because a published-egress confirmation is a Hard Floor no setting may lift. An unread key is the only deletion that cannot silently change a default, which is why that batch went first. The classification itself is docs/contracts/settings-classes.md.",
67
79
  "falsifier": "./scripts-run src/scripts/lint_settings_classes"
80
+ },
81
+ "check_no_external_sources:shape-block": {
82
+ "count": 148,
83
+ "landed": "2026-08-30",
84
+ "falsifier": "./scripts-run src/scripts/check_no_external_sources # the 'attribution shape' line names the current block count; the gate fails when it RISES above this entry",
85
+ "note": "Lowered 243 -> 148 on 2026-08-30 by road-to-source-silence-cutover step 3.1. AI COUNCIL 2026-08-30, 2/2 seats present (anthropic + openai), option (a): NARROW the `source-header` class, do not delete it, and lower the baseline to the new measured total. REASON THE OLD NUMBER WAS WRONG, not merely high: the class flagged the VALUE of every `**Source:**` header that was not an ENC1 token or an opaque round id, so a correctly ANONYMISED header scored exactly like a leaking one. All 95 findings were read; not one named an external source in readable form, and six were flagging the anonymisation notice itself. One seat: the detector penalised correct behaviour. WHAT CHANGED: `sourceHeaderHits` now flags only a value carrying a readable identifier - an owner/repo slug, a domain, or an @scope/package - per the operational grammar in `readableIdentifierIn`, written out because a seat warned that 'readable slug' left unspecified 'merely moves subjective classification into code'. Both seats REFUSED option (c), deleting the class: a `**Source:**` header is where policy tells authors to record attribution and is therefore the highest-value place to keep looking. THE DELTA IS AUDITED: 148 = 127 tmp-quote + 21 repo-slug, and a full-tree recount removed exactly the 95 audited source-header findings and ADDED ZERO. The first run produced 150, on two middle-of-path segments (`uncondensed/rules`, `installer/src`) that read like slugs; both are pinned as fixtures. EVIDENCE: `tests/scripts/source_header_narrowing.test.ts` over three labeled fixtures under `tests/fixtures/source-headers/` - compliant (must not flag), internal-ref (must not flag), leaking (MUST flag, all three identifier shapes). The pre-narrowing predicate is kept as `legacySourceHeaderHits` and shadow-reported by the gate; it enforces nothing. ROLLBACK, as specified: revert the matcher and restore 243 if a readable identifier in a `**Source:**` fixture escapes detection, if the full-tree count is not reproducibly 148, or if the delta contains anything outside the audited source-header set. WHAT REMAINS IS REAL DEBT: 127 quoted speaking inbox-directory names and 21 repository slugs, 152 of them in `agents/roadmaps/archive/`. Paying it down is in-place redaction under ADR-250, which this change deliberately did not attempt. EXPIRY: 56 days from `landed`, i.e. 2026-10-25. HONEST LIMIT, added on the completion review that measured it: the narrowed `source-header` class now contributes ZERO of the 148 in-tree findings — 148 is 127 tmp-quote + 21 repo-slug — so IN THIS TREE it is operationally indistinguishable from option (c), deleting it, which both council seats refused. What separates them is the fixture corpus and nothing else, and the same review found the first corpus unrepresentative: it missed the most natural citation shape there is, a FILE inside an external repository (`somevendor/some-suite/skills/foo.md`), because the matcher judged a slug by the characters either side of it rather than by the whole token. The corpus now covers that shape in both directions, and the grammar tokenises. Nothing will notice if the class silently stops firing on real content — only the fixtures will, which is why they are the deliverable rather than a nicety."
68
86
  }
69
87
  },
70
88
  "retired": {
71
89
  "lint_roadmap_blockers:decidability": {
72
90
  "count": 0,
73
91
  "landed": "2026-08-22",
74
- "note": "Open blocker entries that are not yet DECIDABLE by the person who owns them \u2014 missing `Recommendation:` (which option and why), missing `If you do nothing:` (the cost of the non-decision), or a `What to do:` carrying no command, path or enumerated option set. Revealed by adding the decidability half to lint_roadmap_blockers, not created by it: the five original fields describe a situation and never made it actionable, so a blocker could pass the contract while handing the analysis back to the person least equipped to redo it. Measured at introduction: 36 open entries, ALL 36 undecidable, and 14 of the 46 total entries carry no command/path/option at all in `What to do`. Baselined rather than hard-failed because 36 findings nobody can clear in the change that reveals them is the gate-that-lands-as-N-instant-blockers failure this repository has refused before \u2014 the same reasoning as ci-parity:local-only above. First measured at 34 rather than 36 because the two blockers on the branch that introduced this (`ac3-false-positive-reading`, `publish-side-marker-invariant`) were rewritten to the new standard and then closed in the same change; a baseline above the truth silently permits new violations. Re-measured at 38 when the branch was re-pointed at current main, and the +4 is population growth rather than a loosening: main gained the four `road-to-inbox-harvest-2026-08-d-*` roadmaps (context-ledger, runtime-skill-routing, scheduled-deprecation, top-band-model-economy), each carrying one open blocker authored before this requirement existed. That is the honest number for the population this gate now scans \u2014 recording 34 against a 38-entry tree would have failed the gate on its own introducing commit and taught the next reader to distrust it. Lowering happens one blocker at a time, and every roadmap touched for other reasons is a chance to lower it. Lowered 38\u219237 by the scheduled-deprecation PR, which is exactly that shape: code-graph-removal-authorisation was rewritten to the new standard because the roadmap was being touched anyway. Its `If you do nothing:` was one of the few that was not the common no-cost answer \u2014 the release gate that PR ships would have refused the next major cut while the blocker stayed open. Recorded in the past tense because the maintainer then RESOLVED that blocker on the trunk by withdrawing the commitment, so nothing refuses a cut today. The lowering stands on the rewrite, not on the consequence, and the sentence is corrected rather than deleted because a baseline note arguing from a retracted state is how a ratchet's rationale rots. The 56-day expiry is the point, not a hazard: if this number has not moved in two months, the fields are not being written and the gate should fail until someone decides whether the requirement is real. Lowered 37\u219234 when the scheduled-deprecation branch merged current main: three blockers were resolved or rewritten on the trunk in the meantime, so the drop is a genuine drain plus a merge, not a loosening. Re-tightened here rather than left loose because a ratchet that lags its own tree permits violations back in silently. Lowered 34\u219229 on 2026-08-16 by rewriting six entries to the new standard (raw-capture-needs-host-env, telemetry-sample-size, repo-admin-and-usage, benchmark-spend, measurement-a-no-per-arm-builder-tier, measurement-b-no-renderable-lane-pair) in a PR whose only purpose was the drain \u2014 the first lowering not taken on the back of another change, which the note above says is the usual shape. Two findings from that pass are worth keeping. The tree measured 35 against a baseline of 34 BEFORE the drain, i.e. the ratchet was already red on main and nobody knew: this gate runs in `task ci`, no workflow invokes `task ci`, and the local run that would have shown it was read through a `tail`, which hid every row above the last six. And four of the six `If you do nothing:` answers are honestly that nothing degrades \u2014 that is the true answer for a held measurement, and writing it is what makes the entry decidable, so the field earns its place by being cheap to answer truthfully rather than by always carrying a cost. Lowered 29 \u2192 27 on 2026-08-16 by the merge of this branch and the trunk drain above, and the arithmetic matters more than the delta: both sides rewrote entries from the same tree of 35 independently \u2014 the trunk six (recorded above), this branch two (deferred-finding-decision-reopen, spent-inbox-artifacts-await-deletion, rewritten because road-to-inbox-harvest-residuals was being touched anyway). The sets are disjoint, so the merged tree measures 27 and the gate itself reported the slack. Tightened rather than banked: 29 against a 27-entry tree would absorb the next two undecidable blockers without anything noticing, which is the lag this note has now corrected twice. Lowered 27 \u2192 26 on 2026-08-16 by rewriting `picktier-wire-or-archive` (road-to-inbox-harvest-2026-08-d-top-band-model-economy), and this one is the usual shape the note describes rather than the dedicated-drain shape: the roadmap was being worked for its own Step 4.1 and the entry was rewritten because it was open on the desk. Worth recording for what writing the two fields SURFACED, which is the argument for the requirement: `Recommendation:` forced the question 'which option, and why' and the honest answer turned out not to be one of the three options at all \u2014 the entry defers to a converged council verdict, and the council cannot reach quorum (re-measured 0 of 2 the same day), so the actionable next step is a one-line fix to a user-global config file outside this repository. Five fields had described that situation accurately for two weeks without anyone noticing that the named blocker was infrastructure rather than judgement. Lowered 26 \u2192 22 on 2026-08-18 by road-to-estate-drawdown Step 0.1, which needed the two fields for a different reason and therefore drained six entries as a by-product: the consolidated decision sheet renders a DEFAULT plus that default's provenance per user-owned decision, and 7 of the 21 live entries recorded no `Recommendation:` to derive one from. Six were rewritten to the new standard (skill-activation-window, b-convergence-machine, maintainer-blind-ratings, real-orchestration-usage, human-gated-live-trigger-eval, manual-rubric-rater), each marked `agent-drafted` in the field itself so the sheet can label the provenance rather than presenting a drafted default beside a maintainer-recorded one as the same kind of statement. The seventh, `road-to-gated-reach-followup`'s legacy `> Blocked until \u2026` note, is NOT counted here and was not rewritten: it is a blocked-until note rather than a `### blocker:` entry, so it has no field to carry, and converting it is a roadmap restructure this change did not take. **The tree was RED at 28 against this baseline of 26 before the drain, and again nobody knew** \u2014 the same failure the 34\u219229 paragraph above records, one gate cycle later: two entries had been added on the trunk without the fields, and this gate runs in `task ci`, which no workflow invokes. That is the second recorded instance of this ratchet being red on main undetected, which is an argument about where it runs rather than about its number. `human-gated-live-trigger-eval` also gained a command in `What to do:` (`rule_trigger_eval`, verified to exist at src/scripts/) because the field carried a path-less instruction; the other five needed only the two decidability fields. Lowered 22 -> 20 on 2026-08-19 by road-to-estate-drawdown Phase 2 triage batch 1, and RE-MEASURED after two merges of origin/main rather than carried over: the trunk gained roadmaps in between (the long-horizon pair and the council-fallback set), and the live count over the merged tree is still 20 across 39 roadmaps. Six roadmaps moved to later/, and two of them carried an undecidable open blocker each. The gain is a side effect of parking rather than of drafting a recommendation, so it is recorded as such \u2014 the two entries are unchanged and still undecidable where they sit; they are simply outside the active tree this ratchet scans. Walked down because the gate reported itself loose, and a baseline above the measurement is headroom a later change can spend with nothing objecting. Lowered 20 -> 17 on 2026-08-20 by the road-to-frontend-skill-application closeout, and the shape is the usual one this note describes: the roadmap was being closed for its own reasons and its three open blockers were on the desk anyway. Two (ui-corpus-has-no-ui, enforcement-evidence) left the population by being RESOLVED rather than rewritten, which is the cleanest way to lower this number and the only one that does not add prose; the third (ui-session-capture-window) was rewritten to the new standard. Worth recording what writing the two fields surfaced, since that is the standing argument for the requirement: on ui-corpus-has-no-ui, `Recommendation:` forced the question \"which option, and why\" and the honest answer was that the entry's own premise was false \u2014 it asserted the question could not be answered without a human naming a consumer store, and the stores were already on the machine, readable by the command the entry itself printed. Five fields had described that situation accurately for a week without anyone noticing the blocker was a measurement nobody had run. Tightened rather than banked because 20 against a 17-entry tree is headroom the next three undecidable blockers would spend with nothing objecting, which is the lag the paragraphs above have now corrected three times. Walked 17 -> 12 at the drain/road-to-frontend-skill-application merge, 2026-08-21, on the gate's own loose-ratchet report. Re-measured against the merged tree rather than attributed: sibling drain PRs made entries decidable in parallel, so this branch's share is not separable here and is not claimed. Banked at the measurement rather than left as headroom a later change could spend.\n\nWALKED 12 -> 1 on 2026-08-22 by resolving the two `road-to-evidence-based-adr-governance` blockers (`owner-autonomy-batch`, `authority-coupling-decision`), which were undecidable in exactly the way this ratchet names: each handed a Hard-Floor question to the reader without a landed outcome. Both now carry one. The single remaining violation is `road-to-drain-commands:395` (`merge-authority`), which PR #1517 resolves and archives \u2014 so the honest count for THIS tree is 1 and it is expected to reach 0 once that lands. It is not lowered to 0 here, because a baseline must describe the tree it ships with rather than the tree someone expects next. Lowered 1 -> 0 on 2026-08-22, and the prediction the previous entry made is what closed it: the single remaining violation was `road-to-drain-commands:395` (`merge-authority`), and PR #1517 archived that roadmap, taking the entry out of the scanned population. Nothing was rewritten to reach zero -- the record left the active tree with its blocker RESOLVED, which is the cleanest of the two ways this number goes down and the only one that adds no prose. Zero is now the ceiling: any new open blocker missing `Recommendation:`, `If you do nothing:` or an actionable `What to do:` reds this gate immediately, with no headroom at all.",
92
+ "note": "Open blocker entries that are not yet DECIDABLE by the person who owns them — missing `Recommendation:` (which option and why), missing `If you do nothing:` (the cost of the non-decision), or a `What to do:` carrying no command, path or enumerated option set. Revealed by adding the decidability half to lint_roadmap_blockers, not created by it: the five original fields describe a situation and never made it actionable, so a blocker could pass the contract while handing the analysis back to the person least equipped to redo it. Measured at introduction: 36 open entries, ALL 36 undecidable, and 14 of the 46 total entries carry no command/path/option at all in `What to do`. Baselined rather than hard-failed because 36 findings nobody can clear in the change that reveals them is the gate-that-lands-as-N-instant-blockers failure this repository has refused before — the same reasoning as ci-parity:local-only above. First measured at 34 rather than 36 because the two blockers on the branch that introduced this (`ac3-false-positive-reading`, `publish-side-marker-invariant`) were rewritten to the new standard and then closed in the same change; a baseline above the truth silently permits new violations. Re-measured at 38 when the branch was re-pointed at current main, and the +4 is population growth rather than a loosening: main gained the four `road-to-inbox-harvest-2026-08-d-*` roadmaps (context-ledger, runtime-skill-routing, scheduled-deprecation, top-band-model-economy), each carrying one open blocker authored before this requirement existed. That is the honest number for the population this gate now scans — recording 34 against a 38-entry tree would have failed the gate on its own introducing commit and taught the next reader to distrust it. Lowering happens one blocker at a time, and every roadmap touched for other reasons is a chance to lower it. Lowered 38→37 by the scheduled-deprecation PR, which is exactly that shape: code-graph-removal-authorisation was rewritten to the new standard because the roadmap was being touched anyway. Its `If you do nothing:` was one of the few that was not the common no-cost answer — the release gate that PR ships would have refused the next major cut while the blocker stayed open. Recorded in the past tense because the maintainer then RESOLVED that blocker on the trunk by withdrawing the commitment, so nothing refuses a cut today. The lowering stands on the rewrite, not on the consequence, and the sentence is corrected rather than deleted because a baseline note arguing from a retracted state is how a ratchet's rationale rots. The 56-day expiry is the point, not a hazard: if this number has not moved in two months, the fields are not being written and the gate should fail until someone decides whether the requirement is real. Lowered 37→34 when the scheduled-deprecation branch merged current main: three blockers were resolved or rewritten on the trunk in the meantime, so the drop is a genuine drain plus a merge, not a loosening. Re-tightened here rather than left loose because a ratchet that lags its own tree permits violations back in silently. Lowered 34→29 on 2026-08-16 by rewriting six entries to the new standard (raw-capture-needs-host-env, telemetry-sample-size, repo-admin-and-usage, benchmark-spend, measurement-a-no-per-arm-builder-tier, measurement-b-no-renderable-lane-pair) in a PR whose only purpose was the drain — the first lowering not taken on the back of another change, which the note above says is the usual shape. Two findings from that pass are worth keeping. The tree measured 35 against a baseline of 34 BEFORE the drain, i.e. the ratchet was already red on main and nobody knew: this gate runs in `task ci`, no workflow invokes `task ci`, and the local run that would have shown it was read through a `tail`, which hid every row above the last six. And four of the six `If you do nothing:` answers are honestly that nothing degrades — that is the true answer for a held measurement, and writing it is what makes the entry decidable, so the field earns its place by being cheap to answer truthfully rather than by always carrying a cost. Lowered 29 → 27 on 2026-08-16 by the merge of this branch and the trunk drain above, and the arithmetic matters more than the delta: both sides rewrote entries from the same tree of 35 independently — the trunk six (recorded above), this branch two (deferred-finding-decision-reopen, spent-inbox-artifacts-await-deletion, rewritten because road-to-inbox-harvest-residuals was being touched anyway). The sets are disjoint, so the merged tree measures 27 and the gate itself reported the slack. Tightened rather than banked: 29 against a 27-entry tree would absorb the next two undecidable blockers without anything noticing, which is the lag this note has now corrected twice. Lowered 27 → 26 on 2026-08-16 by rewriting `picktier-wire-or-archive` (road-to-inbox-harvest-2026-08-d-top-band-model-economy), and this one is the usual shape the note describes rather than the dedicated-drain shape: the roadmap was being worked for its own Step 4.1 and the entry was rewritten because it was open on the desk. Worth recording for what writing the two fields SURFACED, which is the argument for the requirement: `Recommendation:` forced the question 'which option, and why' and the honest answer turned out not to be one of the three options at all — the entry defers to a converged council verdict, and the council cannot reach quorum (re-measured 0 of 2 the same day), so the actionable next step is a one-line fix to a user-global config file outside this repository. Five fields had described that situation accurately for two weeks without anyone noticing that the named blocker was infrastructure rather than judgement. Lowered 26 → 22 on 2026-08-18 by road-to-estate-drawdown Step 0.1, which needed the two fields for a different reason and therefore drained six entries as a by-product: the consolidated decision sheet renders a DEFAULT plus that default's provenance per user-owned decision, and 7 of the 21 live entries recorded no `Recommendation:` to derive one from. Six were rewritten to the new standard (skill-activation-window, b-convergence-machine, maintainer-blind-ratings, real-orchestration-usage, human-gated-live-trigger-eval, manual-rubric-rater), each marked `agent-drafted` in the field itself so the sheet can label the provenance rather than presenting a drafted default beside a maintainer-recorded one as the same kind of statement. The seventh, `road-to-gated-reach-followup`'s legacy `> Blocked until …` note, is NOT counted here and was not rewritten: it is a blocked-until note rather than a `### blocker:` entry, so it has no field to carry, and converting it is a roadmap restructure this change did not take. **The tree was RED at 28 against this baseline of 26 before the drain, and again nobody knew** — the same failure the 34→29 paragraph above records, one gate cycle later: two entries had been added on the trunk without the fields, and this gate runs in `task ci`, which no workflow invokes. That is the second recorded instance of this ratchet being red on main undetected, which is an argument about where it runs rather than about its number. `human-gated-live-trigger-eval` also gained a command in `What to do:` (`rule_trigger_eval`, verified to exist at src/scripts/) because the field carried a path-less instruction; the other five needed only the two decidability fields. Lowered 22 -> 20 on 2026-08-19 by road-to-estate-drawdown Phase 2 triage batch 1, and RE-MEASURED after two merges of origin/main rather than carried over: the trunk gained roadmaps in between (the long-horizon pair and the council-fallback set), and the live count over the merged tree is still 20 across 39 roadmaps. Six roadmaps moved to later/, and two of them carried an undecidable open blocker each. The gain is a side effect of parking rather than of drafting a recommendation, so it is recorded as such — the two entries are unchanged and still undecidable where they sit; they are simply outside the active tree this ratchet scans. Walked down because the gate reported itself loose, and a baseline above the measurement is headroom a later change can spend with nothing objecting. Lowered 20 -> 17 on 2026-08-20 by the road-to-frontend-skill-application closeout, and the shape is the usual one this note describes: the roadmap was being closed for its own reasons and its three open blockers were on the desk anyway. Two (ui-corpus-has-no-ui, enforcement-evidence) left the population by being RESOLVED rather than rewritten, which is the cleanest way to lower this number and the only one that does not add prose; the third (ui-session-capture-window) was rewritten to the new standard. Worth recording what writing the two fields surfaced, since that is the standing argument for the requirement: on ui-corpus-has-no-ui, `Recommendation:` forced the question \"which option, and why\" and the honest answer was that the entry's own premise was false — it asserted the question could not be answered without a human naming a consumer store, and the stores were already on the machine, readable by the command the entry itself printed. Five fields had described that situation accurately for a week without anyone noticing the blocker was a measurement nobody had run. Tightened rather than banked because 20 against a 17-entry tree is headroom the next three undecidable blockers would spend with nothing objecting, which is the lag the paragraphs above have now corrected three times. Walked 17 -> 12 at the drain/road-to-frontend-skill-application merge, 2026-08-21, on the gate's own loose-ratchet report. Re-measured against the merged tree rather than attributed: sibling drain PRs made entries decidable in parallel, so this branch's share is not separable here and is not claimed. Banked at the measurement rather than left as headroom a later change could spend.\n\nWALKED 12 -> 1 on 2026-08-22 by resolving the two `road-to-evidence-based-adr-governance` blockers (`owner-autonomy-batch`, `authority-coupling-decision`), which were undecidable in exactly the way this ratchet names: each handed a Hard-Floor question to the reader without a landed outcome. Both now carry one. The single remaining violation is `road-to-drain-commands:395` (`merge-authority`), which PR #1517 resolves and archives — so the honest count for THIS tree is 1 and it is expected to reach 0 once that lands. It is not lowered to 0 here, because a baseline must describe the tree it ships with rather than the tree someone expects next. Lowered 1 -> 0 on 2026-08-22, and the prediction the previous entry made is what closed it: the single remaining violation was `road-to-drain-commands:395` (`merge-authority`), and PR #1517 archived that roadmap, taking the entry out of the scanned population. Nothing was rewritten to reach zero -- the record left the active tree with its blocker RESOLVED, which is the cleanest of the two ways this number goes down and the only one that adds no prose. Zero is now the ceiling: any new open blocker missing `Recommendation:`, `If you do nothing:` or an actionable `What to do:` reds this gate immediately, with no headroom at all.",
75
93
  "falsifier": "./scripts-run src/scripts/lint_roadmap_blockers --quiet",
76
94
  "retired_on": "2026-08-22",
77
- "retired_because": "Walked to 0 and therefore removed from `gates`: an entry recording no debt is what gate_baseline.test.ts refuses, and a missing entry is not weaker \u2014 evaluateGate treats an absent baseline as ok only when the live count is 0, which is the same ceiling the note below asked for. Kept here because the note is dated history, not commentary; nothing reads this key at runtime."
95
+ "retired_because": "Walked to 0 and therefore removed from `gates`: an entry recording no debt is what gate_baseline.test.ts refuses, and a missing entry is not weaker — evaluateGate treats an absent baseline as ok only when the live count is 0, which is the same ceiling the note below asked for. Kept here because the note is dated history, not commentary; nothing reads this key at runtime."
78
96
  }
79
97
  }
80
98
  }
@@ -0,0 +1,25 @@
1
+ {
2
+ "_comment": "Pre-registered budget invariant for the governed harness-evolution programme (road-to-governed-harness-evolution step 0.5). FIXED BEFORE THE FIRST RUN, which is the whole of the step: a budget written afterwards is a description of what was spent. Enforced by assertWithinBudget() in src/scripts/_lib/harness_evolution_guards.ts, which ABORTS rather than truncating — a truncated run yields `underpowered`, which _lib/paired_verdict.ts:26 refuses to call a pass and which a reader mistakes for one. The numbers below are sized for the roadmap's own First cut (3-5 deterministic candidate descriptions for `code-intelligence` activation, evaluated against its existing 10-query evals/triggers.json), not for a programme-wide campaign. Raising any ceiling needs the reason as a sentence in the same commit, the discipline check_estate_count already enforces elsewhere.",
3
+ "schema_version": 1,
4
+ "registered_at": "2026-08-30",
5
+ "owner": "maintainer",
6
+ "review_by": "2027-02-28",
7
+ "enforced_by": "src/scripts/_lib/harness_evolution_guards.ts#assertWithinBudget",
8
+ "budget": {
9
+ "max_candidates": 5,
10
+ "max_trials_per_candidate": 20,
11
+ "max_spend_cents": 500
12
+ },
13
+ "why_these_numbers": {
14
+ "max_candidates": "The First cut asks for 3-5 candidates on ONE mutation dimension (steps 3.2, 3.5). Five is that ceiling exactly, so a run that wants six is a run that changed the cut.",
15
+ "max_trials_per_candidate": "The exact one-sided sign test in _lib/paired_verdict.ts derives its minimum discordant-trial floor from ALPHA rather than choosing one; 20 leaves room above that floor for a corpus of 10 queries run in both orders (judge_hygiene.ts:5-9). NOT a power calculation — stated as a ceiling with its reasoning, not as a sample size somebody computed.",
16
+ "max_spend_cents": "The cut is spend-bearing and the roadmap says so: description_route_check routes through a model backend behind a cache layer (src/scripts/description_route_check.ts:112-125). 500 cents is a deliberately small first ceiling — the point of the invariant is that the run STOPS at it, so the first number should be one an operator is willing to see an abort at."
17
+ },
18
+ "stop_conditions": {
19
+ "_comment": "Step 0.6. A spend cap stops on cost; these stop on VALIDITY. Each carries a detector or is explicitly marked model-carried — the list and the detectors are STOP_CONDITIONS in the same module. Stopping with INDETERMINATE is a valid result.",
20
+ "holdout-underpowered": "detector: holdoutUnderpowered",
21
+ "evaluator-leakage": "detector: discloseToProposer (throws HoldoutLeakError)",
22
+ "diversity-collapse": "detector: diversityCollapsed",
23
+ "cross-component-interference": "MODEL-CARRIED, no detector. Deciding whether two changes interfere needs a causal model of the components and this programme has none. Written out rather than given a detector that would pattern-match on file paths and report confidence it does not have."
24
+ }
25
+ }
@@ -0,0 +1,96 @@
1
+ {
2
+ "_comment": "FROZEN baseline of beta contracts already lapsed at 2026-08-25 \u2014 road-to-contract-review-deadlines step 0.2, AI council 2/2. These 86 WARN; any lapsed beta contract NOT in this list is an ERROR. The list may not GROW and an entry may not be RE-ADDED: both are the ratchet. An entry leaves only because the contract itself stopped being a lapsed beta \u2014 promoted, recorded unmaintained, superseded, or given a reviewed new deadline \u2014 never by editing this file to make a red go away. When the list reaches zero, the same change deletes it and sets LAPSED_SEVERITY to 'error'.",
3
+ "schema_version": "lapsed-beta-baseline-v1",
4
+ "frozen_at": "2026-08-25",
5
+ "measured_at_as_of": "2026-08-25",
6
+ "clear_by": "2026-11-23",
7
+ "_clear_by_comment": "Not a soft target. If the list is not empty by this date the 90-day review cadence itself is reassessed, on measured workload from the first complete post-migration cycle \u2014 the migration is not silently extended.",
8
+ "count": 85,
9
+ "contracts": [
10
+ "docs/contracts/adr-architectural-consensus-mechanism.md",
11
+ "docs/contracts/adr-chat-history-split.md",
12
+ "docs/contracts/adr-forecast-construction-shape.md",
13
+ "docs/contracts/adr-gtm-context-spine.md",
14
+ "docs/contracts/adr-install-user-type-axis.md",
15
+ "docs/contracts/adr-settings-sync-engine.md",
16
+ "docs/contracts/adr-user-types-axis.md",
17
+ "docs/contracts/adr-wing4-context-spine.md",
18
+ "docs/contracts/agent-user-schema.md",
19
+ "docs/contracts/agents-layout.md",
20
+ "docs/contracts/agents-md-tech-stack.md",
21
+ "docs/contracts/ai-council-config.md",
22
+ "docs/contracts/audit-log-v1.md",
23
+ "docs/contracts/benchmark-corpus-spec.md",
24
+ "docs/contracts/benchmark-report-schema.md",
25
+ "docs/contracts/brand-token-consumption.md",
26
+ "docs/contracts/capability-boundary.md",
27
+ "docs/contracts/command-category-governance.md",
28
+ "docs/contracts/command-clusters.md",
29
+ "docs/contracts/command-surface-tiers.md",
30
+ "docs/contracts/command-taxonomy.md",
31
+ "docs/contracts/condensation-default-kill-criterion.md",
32
+ "docs/contracts/config-presets.md",
33
+ "docs/contracts/context-paths.md",
34
+ "docs/contracts/cost-dashboard.md",
35
+ "docs/contracts/cost-profile-defaults.md",
36
+ "docs/contracts/cost-summary-schema.md",
37
+ "docs/contracts/creative-pack-boundary.md",
38
+ "docs/contracts/cross-wing-handoff.md",
39
+ "docs/contracts/decision-engine-gates.md",
40
+ "docs/contracts/decision-trace-v1.md",
41
+ "docs/contracts/discovery-manifest.md",
42
+ "docs/contracts/file-ownership-matrix.md",
43
+ "docs/contracts/frontmatter-contract.md",
44
+ "docs/contracts/ghostwriter-schema.md",
45
+ "docs/contracts/governance-enforcement-projection.md",
46
+ "docs/contracts/gui-wizard.md",
47
+ "docs/contracts/hook-architecture-v1.md",
48
+ "docs/contracts/implement-ticket-flow.md",
49
+ "docs/contracts/init-telemetry.md",
50
+ "docs/contracts/installed-tools-lockfile.md",
51
+ "docs/contracts/installer-agent-mode.md",
52
+ "docs/contracts/kernel-membership.md",
53
+ "docs/contracts/linear-ai-rules-inclusion.md",
54
+ "docs/contracts/linear-ai-three-layers.md",
55
+ "docs/contracts/linter-structural-model.md",
56
+ "docs/contracts/load-context-budget-model.md",
57
+ "docs/contracts/load-context-schema.md",
58
+ "docs/contracts/local-knowledge-ingestion.md",
59
+ "docs/contracts/local-server-api.md",
60
+ "docs/contracts/low-impact-corpus-format.md",
61
+ "docs/contracts/mcp-tool-inventory.md",
62
+ "docs/contracts/memory-visibility-v1.md",
63
+ "docs/contracts/multi-tool-projection-fidelity.md",
64
+ "docs/contracts/no-runtime-boundary.md",
65
+ "docs/contracts/one-off-script-lifecycle.md",
66
+ "docs/contracts/orchestration-dsl-v1.md",
67
+ "docs/contracts/package-self-orientation.md",
68
+ "docs/contracts/persona-schema.md",
69
+ "docs/contracts/profile-system.md",
70
+ "docs/contracts/provider-lifecycle.md",
71
+ "docs/contracts/release-trunk-sync.md",
72
+ "docs/contracts/review-lens-schema.md",
73
+ "docs/contracts/roadmap-complexity-standard.md",
74
+ "docs/contracts/role-experience.md",
75
+ "docs/contracts/router-blending.md",
76
+ "docs/contracts/rule-classification.md",
77
+ "docs/contracts/rule-interactions.md",
78
+ "docs/contracts/rule-priority-hierarchy.md",
79
+ "docs/contracts/rule-router.md",
80
+ "docs/contracts/safety-model.md",
81
+ "docs/contracts/settings-api.md",
82
+ "docs/contracts/settings-sync-yaml-subset.md",
83
+ "docs/contracts/skill-domains.md",
84
+ "docs/contracts/smoke-contracts.md",
85
+ "docs/contracts/subagent-boundary.md",
86
+ "docs/contracts/telegraph-telemetry.md",
87
+ "docs/contracts/ticket-bundle-format.md",
88
+ "docs/contracts/tier-3-contrib-plugin.md",
89
+ "docs/contracts/trust-and-safety.md",
90
+ "docs/contracts/ui-stack-extension.md",
91
+ "docs/contracts/ui-track-flow.md",
92
+ "docs/contracts/universal-skills.md",
93
+ "docs/contracts/user-type-schema.md",
94
+ "docs/contracts/workflow-packs.md"
95
+ ]
96
+ }
@@ -0,0 +1,129 @@
1
+ # Memory-twin parity verdicts — the allowlist `lint_memory_twin_parity.ts` reads.
2
+ #
3
+ # WHY THIS FILE EXISTS
4
+ # --------------------
5
+ # Seven scripts exist twice: once under `src/scripts/` (this repository's own
6
+ # tooling) and once under `src/agent-src/templates/scripts/` (what a consumer
7
+ # installs). `package.json:files[]` ships BOTH directories, and until
8
+ # `road-to-memory-twin-reconciliation` landed there was no sync, no drift check
9
+ # and no parity gate between them — so the copies diverged in both directions
10
+ # and nothing noticed.
11
+ #
12
+ # THE STRUCTURAL CONSTRAINT THAT SHAPES EVERY VERDICT
13
+ # ---------------------------------------------------
14
+ # The installed consumer tree has NO `scripts/_lib/`. A template script may
15
+ # import node built-ins, `yaml`, and its own installed siblings — nothing else.
16
+ # So every `keep-duplicated` verdict below is one of exactly two things:
17
+ #
18
+ # (a) the dev side uses a `_lib/` module the template cannot import, or
19
+ # (b) the dev side uses a sibling under `src/scripts/` that is not installed.
20
+ #
21
+ # A difference that is NEITHER is drift, and the gate says so.
22
+ #
23
+ # THE TWO MODES
24
+ # -------------
25
+ # `exact` — the non-comment diff must be EMPTY. Any divergence fails.
26
+ # NOTE ON THE NUMBERS: the ceilings are the gate's own MULTISET metric — a line
27
+ # present N times on one side and M on the other contributes |N-M| — not a
28
+ # `diff -u` hunk count, which is larger because it is order-sensitive. Read them
29
+ # with `lint_memory_twin_parity`, never off a diff.
30
+ #
31
+ # `bounded` — a recorded ceiling on non-comment changed lines, shrink-only. It
32
+ # catches GROWTH, which is the failure mode ("the copies drift apart again"),
33
+ # and deliberately does not claim to catch a same-size substitution. Where a
34
+ # twin can be driven to `exact` it is, because `exact` is the stronger check
35
+ # and a ceiling is what you accept when you cannot have one.
36
+ schema_version: memory-twin-verdicts-v1
37
+ registered_at: '2026-08-26'
38
+ owner: maintainer
39
+ review_by: '2027-08-26'
40
+
41
+ dev_root: src/scripts
42
+ template_root: src/agent-src/templates/scripts
43
+
44
+ twins:
45
+ - file: memory_signal.ts
46
+ mode: exact
47
+ verdict: dev-side-correct
48
+ reason: >-
49
+ Reconciled to zero on 2026-08-26. The template was missing ADR-130's
50
+ provenance gate entirely — ProvenanceRefusedError, _origin_is_global,
51
+ _assert_project_writable and the additive `subject: project` default — so a
52
+ consumer could write a `subject: user` record, and a record whose origin
53
+ resolves into the user-global store, into tracked project intake. That is
54
+ an ABSENT CONTROL rather than a behaviour difference. The gate is portable
55
+ (node built-ins only), so nothing justified the gap.
56
+
57
+ - file: memory_hash.ts
58
+ mode: exact
59
+ verdict: keep-duplicated
60
+ reason: >-
61
+ Already at zero before this roadmap. Recorded as `exact` rather than left
62
+ unlisted so a future divergence fails instead of being discovered later.
63
+
64
+ - file: check_memory.ts
65
+ mode: bounded
66
+ max_changed_lines: 18
67
+ verdict: dev-side-correct
68
+ reason: >-
69
+ Reconciled 195 -> 18 on 2026-08-26. The template was a stale snapshot
70
+ missing SEVEN validations the dev side had grown: the `priority` enum, the
71
+ critical-stale SLA, the one-fact length limit, relative-date discipline,
72
+ per-type caps, tier-0 inflation, and `status: superseded`. All are portable
73
+ and all were ported. The 18 that remain are case (a) twice — `assertScanned`
74
+ (`_lib/scan_scope.js`) and `asOf` (`_lib/as_of.js`) — plus the two import
75
+ lines and the `new Date()` substitution they force.
76
+
77
+ - file: check_memory_proposal.ts
78
+ mode: bounded
79
+ max_changed_lines: 12
80
+ verdict: mixed
81
+ reason: >-
82
+ Reconciled 45 -> 12 on 2026-08-26, and this twin is why a per-FILE verdict
83
+ would have been wrong. It diverged in BOTH directions: `--quiet` was
84
+ dev-only and was ported to the template, while the mutual-exclusion check
85
+ was TEMPLATE-correct and was ported to the dev side — the template's error
86
+ names the flag that arrived second, which is what argparse does and what
87
+ this file mirrors, whereas the dev side's post-loop check always blamed
88
+ `--proposal`. The remaining 12 are case (a): the `assertScanned` block and
89
+ its import.
90
+
91
+ - file: memory_report.ts
92
+ mode: bounded
93
+ max_changed_lines: 8
94
+ verdict: keep-duplicated
95
+ reason: >-
96
+ Case (a) — the `__AGENT_CONFIG_BUNDLE__` entry guard, whose absence in the
97
+ template is correct by construction: the flag is defined only by the three
98
+ `esbuild --define` bundles, every one of their entrypoints is under
99
+ `src/scripts/`, and it appears in no file under the templates tree.
100
+ Reconciling would put a guard into a file that can never be bundled.
101
+
102
+ - file: memory_status.ts
103
+ mode: bounded
104
+ max_changed_lines: 4
105
+ verdict: keep-duplicated
106
+ reason: Same `__AGENT_CONFIG_BUNDLE__` entry guard as memory_report.ts.
107
+
108
+ - file: memory_lookup.ts
109
+ mode: bounded
110
+ max_changed_lines: 504
111
+ verdict: keep-duplicated
112
+ reason: >-
113
+ The one twin that cannot be reconciled, and the ceiling is high because the
114
+ divergence is STRUCTURAL rather than neglect. The dev side depends on FOUR
115
+ modules the template cannot import — `_lib/lexical_index.js`,
116
+ `_lib/retrieval_sanitize.js`, `_lib/memory_fts_index.js`, `_lib/as_of.js` —
117
+ plus the sibling `learning_sidecar.js`, which is not installed. Lexical
118
+ reranking, FTS recall-gap hits, entry sanitisation, the learning overlay
119
+ and `retrieve_with_meta` all sit behind those imports.
120
+ TWO portable gaps were found inside that structural one and BOTH were
121
+ closed on 2026-08-26: curated entries with status `deprecated` / `archived`
122
+ / `superseded` were retrieved by the template (the dev side excludes them),
123
+ and the template had NO staleness handling at all — `grep -c stale`
124
+ returned zero — so it served curated entries past their own
125
+ `review_after_days` window. Both are pinned by tests that were observed RED
126
+ under sabotage.
127
+ Shrink-only from here. Lowering this number needs either a portable
128
+ re-implementation or a decision to install `_lib/`, which is the
129
+ delivery-authority question this roadmap explicitly does not answer.