@event4u/agent-config 14.23.0 → 16.0.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 (541) 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 +144 -152
  5. package/README.md +1 -1
  6. package/dist/agent-src/commands/agent-handoff.md +8 -7
  7. package/dist/agent-src/commands/agents/init.md +1 -1
  8. package/dist/agent-src/commands/agents/user/accept.md +4 -4
  9. package/dist/agent-src/commands/agents/user/delete.md +2 -2
  10. package/dist/agent-src/commands/agents/user/init.md +3 -3
  11. package/dist/agent-src/commands/agents/user/review.md +3 -3
  12. package/dist/agent-src/commands/agents/user/show.md +3 -3
  13. package/dist/agent-src/commands/agents/user/update.md +2 -2
  14. package/dist/agent-src/commands/agents/user.md +6 -6
  15. package/dist/agent-src/commands/analytics/prune.md +1 -1
  16. package/dist/agent-src/commands/analytics/show.md +2 -2
  17. package/dist/agent-src/commands/analyze/decision.md +2 -2
  18. package/dist/agent-src/commands/analyze/inbox.md +5 -5
  19. package/dist/agent-src/commands/analyze/incident.md +3 -3
  20. package/dist/agent-src/commands/analyze/near-miss.md +3 -3
  21. package/dist/agent-src/commands/analyze/postmortem.md +4 -4
  22. package/dist/agent-src/commands/analyze/premortem.md +2 -2
  23. package/dist/agent-src/commands/analyze.md +2 -2
  24. package/dist/agent-src/commands/bug/fix.md +1 -1
  25. package/dist/agent-src/commands/bug/investigate.md +2 -2
  26. package/dist/agent-src/commands/cost/profile.md +3 -3
  27. package/dist/agent-src/commands/design.md +1 -1
  28. package/dist/agent-src/commands/feature/explore.md +1 -1
  29. package/dist/agent-src/commands/feature/plan.md +2 -2
  30. package/dist/agent-src/commands/feature/roadmap.md +2 -2
  31. package/dist/agent-src/commands/ghostwriter/fetch.md +4 -4
  32. package/dist/agent-src/commands/ghostwriter/list.md +1 -1
  33. package/dist/agent-src/commands/ghostwriter/show.md +1 -1
  34. package/dist/agent-src/commands/ghostwriter/write.md +9 -9
  35. package/dist/agent-src/commands/humanize.md +6 -6
  36. package/dist/agent-src/commands/jira-ticket.md +1 -1
  37. package/dist/agent-src/commands/judge/solo.md +1 -1
  38. package/dist/agent-src/commands/judge.md +1 -1
  39. package/dist/agent-src/commands/knowledge/cross-repo.md +1 -1
  40. package/dist/agent-src/commands/knowledge/forget.md +1 -1
  41. package/dist/agent-src/commands/knowledge/ingest.md +2 -2
  42. package/dist/agent-src/commands/knowledge/list.md +1 -1
  43. package/dist/agent-src/commands/memory/add.md +3 -3
  44. package/dist/agent-src/commands/memory/load.md +4 -4
  45. package/dist/agent-src/commands/memory/mine-session.md +1 -1
  46. package/dist/agent-src/commands/memory/promote.md +4 -4
  47. package/dist/agent-src/commands/memory/propose.md +2 -2
  48. package/dist/agent-src/commands/mode.md +5 -5
  49. package/dist/agent-src/commands/post-as/ghostwriter.md +3 -3
  50. package/dist/agent-src/commands/post-as/me.md +7 -7
  51. package/dist/agent-src/commands/pr/create.md +1 -1
  52. package/dist/agent-src/commands/pr/merge.md +1 -1
  53. package/dist/agent-src/commands/profile/activate.md +1 -1
  54. package/dist/agent-src/commands/profile/show.md +1 -1
  55. package/dist/agent-src/commands/research/deep.md +2 -2
  56. package/dist/agent-src/commands/research/report.md +2 -2
  57. package/dist/agent-src/commands/review/changes.md +1 -1
  58. package/dist/agent-src/commands/review/routing.md +1 -1
  59. package/dist/agent-src/commands/roadmap/create.md +4 -3
  60. package/dist/agent-src/commands/roadmap/materialize.md +2 -2
  61. package/dist/agent-src/commands/roadmap/next.md +1 -1
  62. package/dist/agent-src/commands/roadmap/process-full.md +2 -2
  63. package/dist/agent-src/commands/security-audit-config.md +3 -3
  64. package/dist/agent-src/commands/skill/preview.md +1 -1
  65. package/dist/agent-src/commands/skills/discover.md +1 -1
  66. package/dist/agent-src/commands/sync/agent-settings.md +2 -2
  67. package/dist/agent-src/commands/sync/gitignore/fix.md +1 -1
  68. package/dist/agent-src/commands/tests/create.md +1 -1
  69. package/dist/agent-src/commands/tests/e2e-heal.md +1 -1
  70. package/dist/agent-src/commands/tests/e2e-plan.md +1 -1
  71. package/dist/agent-src/contexts/authority/kernel-rule-edits.md +6 -6
  72. package/dist/agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +1 -2
  73. package/dist/agent-src/contexts/communication/rules-auto/think-before-action-mechanics.md +2 -2
  74. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +88 -1
  75. package/dist/agent-src/contexts/communication/rules-auto/user-interaction-mechanics.md +51 -1
  76. package/dist/agent-src/contexts/contracts/frugality-charter.md +1 -1
  77. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +1 -1
  78. package/dist/agent-src/contexts/execution/auto-orchestration-activation.md +1 -1
  79. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +1 -1
  80. package/dist/agent-src/contexts/execution/cheap-question-mechanics.md +1 -1
  81. package/dist/agent-src/contexts/execution/contract-decision-sheet.md +3 -3
  82. package/dist/agent-src/contexts/execution/mandated-lines.md +1 -1
  83. package/dist/agent-src/contexts/execution/non-interactive-contract.md +1 -1
  84. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -1
  85. package/dist/agent-src/contexts/execution/plan-confidence-gate.md +5 -5
  86. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +1 -1
  87. package/dist/agent-src/contexts/execution/subagent-modes-detail.md +1 -1
  88. package/dist/agent-src/contexts/execution/subagent-routing.md +2 -2
  89. package/dist/agent-src/contexts/execution/subagent-spawn-contract.md +1 -1
  90. package/dist/agent-src/contexts/execution/user-memory-channels.md +3 -3
  91. package/dist/agent-src/contexts/execution/verification-mechanics.md +1 -1
  92. package/dist/agent-src/contexts/judges/persona-voice-rubric.md +2 -2
  93. package/dist/agent-src/guidelines/abstraction-thresholds.md +88 -0
  94. package/dist/agent-src/guidelines/agent-infra/5w2h-analysis.md +260 -0
  95. package/dist/agent-src/guidelines/agent-infra/active-remediation-mechanics.md +99 -0
  96. package/dist/agent-src/guidelines/agent-infra/agent-interaction-and-decision-quality.md +325 -0
  97. package/dist/agent-src/guidelines/agent-infra/api-cost-levers.md +177 -0
  98. package/dist/agent-src/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +222 -0
  99. package/dist/agent-src/guidelines/agent-infra/ask-when-uncertain-demos.md +134 -0
  100. package/dist/agent-src/guidelines/agent-infra/asking-and-brevity-examples.md +198 -0
  101. package/dist/agent-src/guidelines/agent-infra/break-glass-usage.md +113 -0
  102. package/dist/agent-src/guidelines/agent-infra/carve-out-predicates.md +17 -0
  103. package/dist/agent-src/guidelines/agent-infra/comparison-matrix.md +179 -0
  104. package/dist/agent-src/guidelines/agent-infra/context-hygiene-mechanics.md +165 -0
  105. package/dist/agent-src/guidelines/agent-infra/corpus-grounding-authoring.md +91 -0
  106. package/dist/agent-src/guidelines/agent-infra/critical-thinking.md +156 -0
  107. package/dist/agent-src/guidelines/agent-infra/cross-source-consistency-mechanics.md +109 -0
  108. package/dist/agent-src/guidelines/agent-infra/developer-judgment.md +82 -0
  109. package/dist/agent-src/guidelines/agent-infra/direct-answers-demos.md +142 -0
  110. package/dist/agent-src/guidelines/agent-infra/domain-adoption-gates.md +112 -0
  111. package/dist/agent-src/guidelines/agent-infra/domain-eval-anti-pattern.md +53 -0
  112. package/dist/agent-src/guidelines/agent-infra/domain-pack-architecture.md +56 -0
  113. package/dist/agent-src/guidelines/agent-infra/downstream-changes-mechanics.md +91 -0
  114. package/dist/agent-src/guidelines/agent-infra/emphasis-budget.md +45 -0
  115. package/dist/agent-src/guidelines/agent-infra/engineering-memory-data-format.md +210 -0
  116. package/dist/agent-src/guidelines/agent-infra/evaluator-independence-mechanics.md +92 -0
  117. package/dist/agent-src/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  118. package/dist/agent-src/guidelines/agent-infra/failure-signatures.md +70 -0
  119. package/dist/agent-src/guidelines/agent-infra/false-green.md +233 -0
  120. package/dist/agent-src/guidelines/agent-infra/first-principles.md +192 -0
  121. package/dist/agent-src/guidelines/agent-infra/framework-neutrality-patterns.md +66 -0
  122. package/dist/agent-src/guidelines/agent-infra/frontier-reasoning-operating-profile.md +169 -0
  123. package/dist/agent-src/guidelines/agent-infra/gate-authoring.md +177 -0
  124. package/dist/agent-src/guidelines/agent-infra/guarded-baseline.md +39 -0
  125. package/dist/agent-src/guidelines/agent-infra/installed-tools-manifest.md +142 -0
  126. package/dist/agent-src/guidelines/agent-infra/inversion-thinking.md +388 -0
  127. package/dist/agent-src/guidelines/agent-infra/ios-simulator-guide.md +378 -0
  128. package/dist/agent-src/guidelines/agent-infra/language-and-tone-examples.md +141 -0
  129. package/dist/agent-src/guidelines/agent-infra/layered-settings.md +317 -0
  130. package/dist/agent-src/guidelines/agent-infra/linked-projects-onboarding-gate.md +80 -0
  131. package/dist/agent-src/guidelines/agent-infra/mcp-request-signing.md +197 -0
  132. package/dist/agent-src/guidelines/agent-infra/memory-access.md +149 -0
  133. package/dist/agent-src/guidelines/agent-infra/mental-models.md +314 -0
  134. package/dist/agent-src/guidelines/agent-infra/minimal-safe-diff-mechanics.md +241 -0
  135. package/dist/agent-src/guidelines/agent-infra/missing-tool-handling.md +66 -0
  136. package/dist/agent-src/guidelines/agent-infra/model-recommendation.md +101 -0
  137. package/dist/agent-src/guidelines/agent-infra/naming.md +69 -0
  138. package/dist/agent-src/guidelines/agent-infra/notes-horizon-mechanics.md +90 -0
  139. package/dist/agent-src/guidelines/agent-infra/output-patterns.md +117 -0
  140. package/dist/agent-src/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  141. package/dist/agent-src/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  142. package/dist/agent-src/guidelines/agent-infra/review-routing-data-format.md +143 -0
  143. package/dist/agent-src/guidelines/agent-infra/roadmap-deferred-resolution-provenance.md +54 -0
  144. package/dist/agent-src/guidelines/agent-infra/roadmap-progress-mechanics.md +274 -0
  145. package/dist/agent-src/guidelines/agent-infra/role-contracts.md +209 -0
  146. package/dist/agent-src/guidelines/agent-infra/role-mode-router.md +89 -0
  147. package/dist/agent-src/guidelines/agent-infra/rule-body-migration-inventory.md +241 -0
  148. package/dist/agent-src/guidelines/agent-infra/rule-type-governance.md +73 -0
  149. package/dist/agent-src/guidelines/agent-infra/runtime-layer.md +89 -0
  150. package/dist/agent-src/guidelines/agent-infra/scqa-framework.md +526 -0
  151. package/dist/agent-src/guidelines/agent-infra/security-lint-containment.md +121 -0
  152. package/dist/agent-src/guidelines/agent-infra/self-improvement-pipeline.md +134 -0
  153. package/dist/agent-src/guidelines/agent-infra/simplicity-and-goal-demos.md +211 -0
  154. package/dist/agent-src/guidelines/agent-infra/six-hats.md +353 -0
  155. package/dist/agent-src/guidelines/agent-infra/size-and-scope.md +229 -0
  156. package/dist/agent-src/guidelines/agent-infra/skill-quality-checklist.md +157 -0
  157. package/dist/agent-src/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  158. package/dist/agent-src/guidelines/agent-infra/symptom-driven-harvest-loop.md +104 -0
  159. package/dist/agent-src/guidelines/agent-infra/systems-thinking.md +220 -0
  160. package/dist/agent-src/guidelines/agent-infra/tool-description-as-policy.md +35 -0
  161. package/dist/agent-src/guidelines/agent-infra/tool-integration.md +73 -0
  162. package/dist/agent-src/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
  163. package/dist/agent-src/guidelines/agent-infra/untrusted-input-spotlighting.md +166 -0
  164. package/dist/agent-src/guidelines/agent-infra/verify-before-complete-demos.md +128 -0
  165. package/dist/agent-src/guidelines/augment-portability-patterns.md +70 -0
  166. package/dist/agent-src/guidelines/code-clarity.md +350 -0
  167. package/dist/agent-src/guidelines/component-oriented-and-oop-development.md +189 -0
  168. package/dist/agent-src/guidelines/cross-role-handoff.md +127 -0
  169. package/dist/agent-src/guidelines/design-antipatterns-triggers.json +18 -0
  170. package/dist/agent-src/guidelines/design-antipatterns.md +327 -0
  171. package/dist/agent-src/guidelines/design-asset-discipline.md +38 -0
  172. package/dist/agent-src/guidelines/design-canon.md +63 -0
  173. package/dist/agent-src/guidelines/design-fidelity-mechanics.md +293 -0
  174. package/dist/agent-src/guidelines/design-fidelity-routing.md +78 -0
  175. package/dist/agent-src/guidelines/design-handover-extraction.md +117 -0
  176. package/dist/agent-src/guidelines/design-modes.md +143 -0
  177. package/dist/agent-src/guidelines/design-reconciliation.md +172 -0
  178. package/dist/agent-src/guidelines/docs/readme-size-and-splitting.md +209 -0
  179. package/dist/agent-src/guidelines/e2e/playwright.md +363 -0
  180. package/dist/agent-src/guidelines/gtm-handoff.md +114 -0
  181. package/dist/agent-src/guidelines/monorepo-antipatterns.md +141 -0
  182. package/dist/agent-src/guidelines/php/api-design.md +115 -0
  183. package/dist/agent-src/guidelines/php/artisan-commands.md +81 -0
  184. package/dist/agent-src/guidelines/php/blade-ui.md +78 -0
  185. package/dist/agent-src/guidelines/php/controllers.md +90 -0
  186. package/dist/agent-src/guidelines/php/database.md +194 -0
  187. package/dist/agent-src/guidelines/php/eloquent.md +208 -0
  188. package/dist/agent-src/guidelines/php/flux.md +80 -0
  189. package/dist/agent-src/guidelines/php/general.md +207 -0
  190. package/dist/agent-src/guidelines/php/git.md +164 -0
  191. package/dist/agent-src/guidelines/php/jobs.md +111 -0
  192. package/dist/agent-src/guidelines/php/livewire.md +71 -0
  193. package/dist/agent-src/guidelines/php/logging.md +79 -0
  194. package/dist/agent-src/guidelines/php/naming.md +89 -0
  195. package/dist/agent-src/guidelines/php/patterns/dependency-injection.md +57 -0
  196. package/dist/agent-src/guidelines/php/patterns/dtos.md +199 -0
  197. package/dist/agent-src/guidelines/php/patterns/events.md +67 -0
  198. package/dist/agent-src/guidelines/php/patterns/factory.md +53 -0
  199. package/dist/agent-src/guidelines/php/patterns/pipelines.md +66 -0
  200. package/dist/agent-src/guidelines/php/patterns/policies.md +66 -0
  201. package/dist/agent-src/guidelines/php/patterns/repositories.md +122 -0
  202. package/dist/agent-src/guidelines/php/patterns/service-layer.md +64 -0
  203. package/dist/agent-src/guidelines/php/patterns/strategy.md +247 -0
  204. package/dist/agent-src/guidelines/php/patterns.md +28 -0
  205. package/dist/agent-src/guidelines/php/performance.md +92 -0
  206. package/dist/agent-src/guidelines/php/php-coding-patterns.md +80 -0
  207. package/dist/agent-src/guidelines/php/resources.md +100 -0
  208. package/dist/agent-src/guidelines/php/security.md +110 -0
  209. package/dist/agent-src/guidelines/php/sql.md +97 -0
  210. package/dist/agent-src/guidelines/php/validations.md +119 -0
  211. package/dist/agent-src/guidelines/php/websocket.md +100 -0
  212. package/dist/agent-src/guidelines/prompt-templates.md +189 -0
  213. package/dist/agent-src/guidelines/redundancy-taxonomy.md +208 -0
  214. package/dist/agent-src/guidelines/wing4-handoff.md +127 -0
  215. package/dist/agent-src/personas/README.md +1 -1
  216. package/dist/agent-src/personas/_template-specialist/persona.md +1 -1
  217. package/dist/agent-src/personas/product-owner.md +1 -1
  218. package/dist/agent-src/rules/active-remediation.md +1 -1
  219. package/dist/agent-src/rules/architecture.md +2 -2
  220. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  221. package/dist/agent-src/rules/ask-when-uncertain.md +2 -2
  222. package/dist/agent-src/rules/brand-source-of-truth.md +9 -7
  223. package/dist/agent-src/rules/code-comment-discipline.md +2 -2
  224. package/dist/agent-src/rules/code-provenance.md +1 -1
  225. package/dist/agent-src/rules/content-quoting-floor.md +1 -1
  226. package/dist/agent-src/rules/context-hygiene.md +5 -5
  227. package/dist/agent-src/rules/cross-source-consistency.md +1 -1
  228. package/dist/agent-src/rules/design-fidelity.md +36 -46
  229. package/dist/agent-src/rules/direct-answers.md +2 -2
  230. package/dist/agent-src/rules/domain-adoption-policy.md +1 -1
  231. package/dist/agent-src/rules/evaluator-independence.md +1 -1
  232. package/dist/agent-src/rules/framework-neutrality-in-generic-skills.md +1 -1
  233. package/dist/agent-src/rules/icon-consistency.md +5 -1
  234. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  235. package/dist/agent-src/rules/language-and-tone.md +3 -3
  236. package/dist/agent-src/rules/minimal-safe-diff.md +1 -1
  237. package/dist/agent-src/rules/notes-first-reasoning.md +2 -2
  238. package/dist/agent-src/rules/recurring-criticism.md +1 -1
  239. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  240. package/dist/agent-src/rules/role-mode-adherence.md +2 -2
  241. package/dist/agent-src/rules/security-sensitive-stop.md +1 -1
  242. package/dist/agent-src/rules/size-enforcement.md +1 -1
  243. package/dist/agent-src/rules/source-confidentiality.md +2 -2
  244. package/dist/agent-src/rules/think-before-action.md +1 -1
  245. package/dist/agent-src/rules/token-efficiency.md +7 -5
  246. package/dist/agent-src/rules/ui-audit-gate.md +3 -2
  247. package/dist/agent-src/rules/untrusted-input-defense.md +3 -3
  248. package/dist/agent-src/rules/user-interaction.md +31 -30
  249. package/dist/agent-src/skills/activation-design/SKILL.md +2 -2
  250. package/dist/agent-src/skills/adr-create/SKILL.md +5 -5
  251. package/dist/agent-src/skills/ai-council/SKILL.md +1 -1
  252. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +1 -1
  253. package/dist/agent-src/skills/blade-ui/SKILL.md +1 -1
  254. package/dist/agent-src/skills/blast-radius-analyzer/SKILL.md +1 -1
  255. package/dist/agent-src/skills/brand-to-tokens/SKILL.md +24 -3
  256. package/dist/agent-src/skills/bug-analyzer/SKILL.md +1 -1
  257. package/dist/agent-src/skills/build-buy-partner/SKILL.md +1 -1
  258. package/dist/agent-src/skills/churn-prevention/SKILL.md +2 -2
  259. package/dist/agent-src/skills/code-refactoring/SKILL.md +3 -3
  260. package/dist/agent-src/skills/code-review/SKILL.md +3 -3
  261. package/dist/agent-src/skills/command-writing/SKILL.md +3 -3
  262. package/dist/agent-src/skills/comp-banding/SKILL.md +1 -1
  263. package/dist/agent-src/skills/competitive-moat-analysis/SKILL.md +1 -1
  264. package/dist/agent-src/skills/competitive-positioning/SKILL.md +2 -2
  265. package/dist/agent-src/skills/complexity-first-planning/SKILL.md +1 -1
  266. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  267. package/dist/agent-src/skills/content-funnel-design/SKILL.md +2 -2
  268. package/dist/agent-src/skills/contracts-cognition/SKILL.md +1 -1
  269. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +2 -2
  270. package/dist/agent-src/skills/corpus-grounding/SKILL.md +2 -2
  271. package/dist/agent-src/skills/customer-research/SKILL.md +2 -2
  272. package/dist/agent-src/skills/dashboard-design/SKILL.md +1 -1
  273. package/dist/agent-src/skills/data-handling-judgment/SKILL.md +1 -1
  274. package/dist/agent-src/skills/deal-qualification-meddic/SKILL.md +2 -2
  275. package/dist/agent-src/skills/decision-record/SKILL.md +3 -3
  276. package/dist/agent-src/skills/decision-review/SKILL.md +8 -8
  277. package/dist/agent-src/skills/deep-reading-analyst/SKILL.md +22 -22
  278. package/dist/agent-src/skills/design-intelligence/SKILL.md +4 -4
  279. package/dist/agent-src/skills/design-intelligence/references/context-and-registers.md +2 -2
  280. package/dist/agent-src/skills/design-review/SKILL.md +4 -4
  281. package/dist/agent-src/skills/design-system-capture/references/design-system-json.md +20 -1
  282. package/dist/agent-src/skills/design-tokens/SKILL.md +17 -2
  283. package/dist/agent-src/skills/design-variations/SKILL.md +2 -2
  284. package/dist/agent-src/skills/developer-like-execution/SKILL.md +2 -2
  285. package/dist/agent-src/skills/discovery-interview/SKILL.md +2 -2
  286. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +3 -3
  287. package/dist/agent-src/skills/editorial-calendar/SKILL.md +2 -2
  288. package/dist/agent-src/skills/error-handling-patterns/SKILL.md +9 -0
  289. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +44 -1
  290. package/dist/agent-src/skills/existing-ui-audit/references/anti-slop-cross-reference.md +2 -2
  291. package/dist/agent-src/skills/expansion-playbook/SKILL.md +2 -2
  292. package/dist/agent-src/skills/experiment-loop/SKILL.md +1 -1
  293. package/dist/agent-src/skills/experiment-loop/references/protocol.md +1 -1
  294. package/dist/agent-src/skills/fe-design/SKILL.md +3 -3
  295. package/dist/agent-src/skills/fe-design/references/design-patterns.md +1 -1
  296. package/dist/agent-src/skills/fe-design/references/design-read-and-memory.md +3 -3
  297. package/dist/agent-src/skills/fe-design/references/source-led-port.md +1 -1
  298. package/dist/agent-src/skills/feature-planning/SKILL.md +1 -1
  299. package/dist/agent-src/skills/flux/SKILL.md +1 -1
  300. package/dist/agent-src/skills/forecast-accuracy/SKILL.md +2 -2
  301. package/dist/agent-src/skills/forecasting/SKILL.md +2 -2
  302. package/dist/agent-src/skills/fundraising-narrative/SKILL.md +2 -2
  303. package/dist/agent-src/skills/funnel-analysis/SKILL.md +2 -2
  304. package/dist/agent-src/skills/gtm-launch/SKILL.md +2 -2
  305. package/dist/agent-src/skills/hiring-loop-design/SKILL.md +1 -1
  306. package/dist/agent-src/skills/html-deck/SKILL.md +5 -5
  307. package/dist/agent-src/skills/humanizer/SKILL.md +1 -1
  308. package/dist/agent-src/skills/humanizer/data/patterns.md +1 -1
  309. package/dist/agent-src/skills/iconography/SKILL.md +3 -3
  310. package/dist/agent-src/skills/judge-synthesis/SKILL.md +1 -1
  311. package/dist/agent-src/skills/laravel-api-endpoint/SKILL.md +2 -2
  312. package/dist/agent-src/skills/launch-readiness/SKILL.md +3 -3
  313. package/dist/agent-src/skills/learning-to-rule-or-skill/SKILL.md +6 -6
  314. package/dist/agent-src/skills/livewire/SKILL.md +1 -1
  315. package/dist/agent-src/skills/market-entry-analysis/SKILL.md +1 -1
  316. package/dist/agent-src/skills/mcp-builder/SKILL.md +1 -1
  317. package/dist/agent-src/skills/memory-consolidation/SKILL.md +3 -3
  318. package/dist/agent-src/skills/messaging-architecture/SKILL.md +2 -2
  319. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +1 -1
  320. package/dist/agent-src/skills/onboarding-design/SKILL.md +2 -2
  321. package/dist/agent-src/skills/onboarding-program/SKILL.md +1 -1
  322. package/dist/agent-src/skills/one-on-one-cadence/SKILL.md +1 -1
  323. package/dist/agent-src/skills/org-design/SKILL.md +1 -1
  324. package/dist/agent-src/skills/overbuild-review-lens/SKILL.md +3 -3
  325. package/dist/agent-src/skills/override-management/SKILL.md +1 -1
  326. package/dist/agent-src/skills/perf-feedback-craft/SKILL.md +1 -1
  327. package/dist/agent-src/skills/persona-writing/SKILL.md +1 -1
  328. package/dist/agent-src/skills/php-coder/SKILL.md +1 -1
  329. package/dist/agent-src/skills/pipeline-strategy/SKILL.md +2 -2
  330. package/dist/agent-src/skills/playwright-testing/SKILL.md +3 -3
  331. package/dist/agent-src/skills/po-discovery/SKILL.md +1 -1
  332. package/dist/agent-src/skills/positioning-strategy/SKILL.md +2 -2
  333. package/dist/agent-src/skills/privacy-review/SKILL.md +1 -1
  334. package/dist/agent-src/skills/prompt-optimizer/SKILL.md +3 -3
  335. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  336. package/dist/agent-src/skills/reasoning-orchestrator/SKILL.md +2 -2
  337. package/dist/agent-src/skills/receiving-code-review/SKILL.md +1 -1
  338. package/dist/agent-src/skills/refine-ticket/SKILL.md +2 -2
  339. package/dist/agent-src/skills/release-comms/SKILL.md +2 -2
  340. package/dist/agent-src/skills/retention-loops/SKILL.md +2 -2
  341. package/dist/agent-src/skills/review-routing/SKILL.md +2 -2
  342. package/dist/agent-src/skills/roadmap-management/SKILL.md +1 -1
  343. package/dist/agent-src/skills/roadmap-management/references/archival.md +1 -1
  344. package/dist/agent-src/skills/roadmap-writing/SKILL.md +5 -5
  345. package/dist/agent-src/skills/rule-writing/SKILL.md +6 -6
  346. package/dist/agent-src/skills/runway-cognition/SKILL.md +2 -2
  347. package/dist/agent-src/skills/scenario-modeling/SKILL.md +2 -2
  348. package/dist/agent-src/skills/skill-writing/SKILL.md +2 -2
  349. package/dist/agent-src/skills/skill-writing/references/procedure.md +1 -1
  350. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +3 -3
  351. package/dist/agent-src/skills/spreadsheet-authoring/SKILL.md +1 -1
  352. package/dist/agent-src/skills/stakeholder-tradeoff/SKILL.md +3 -3
  353. package/dist/agent-src/skills/subagent-orchestration/SKILL.md +1 -1
  354. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +1 -1
  355. package/dist/agent-src/skills/systematic-debugging/SKILL.md +2 -2
  356. package/dist/agent-src/skills/tailwind-engineer/SKILL.md +11 -5
  357. package/dist/agent-src/skills/throughput-vs-morale-tradeoff/SKILL.md +1 -1
  358. package/dist/agent-src/skills/token-optimizer/SKILL.md +1 -1
  359. package/dist/agent-src/skills/typography-system/SKILL.md +2 -2
  360. package/dist/agent-src/skills/ui-component-architect/SKILL.md +28 -8
  361. package/dist/agent-src/skills/unit-economics-modeling/SKILL.md +2 -2
  362. package/dist/agent-src/skills/upstream-contribute/SKILL.md +1 -1
  363. package/dist/agent-src/skills/validate-feature-fit/SKILL.md +2 -2
  364. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +2 -2
  365. package/dist/agent-src/skills/vision-articulation/SKILL.md +1 -1
  366. package/dist/agent-src/skills/voc-extract/SKILL.md +2 -2
  367. package/dist/agent-src/skills/voice-and-tone-design/SKILL.md +2 -2
  368. package/dist/agent-src/skills/wireframe/SKILL.md +1 -1
  369. package/dist/agent-src/skills/workspace-link/SKILL.md +1 -1
  370. package/dist/agent-src/templates/agent-settings.md +6 -6
  371. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  372. package/dist/agent-src/templates/contexts/knowledge-pages.md +2 -3
  373. package/dist/agent-src/templates/copilot-instructions.md +1 -1
  374. package/dist/agent-src/templates/roadmaps.md +1 -1
  375. package/dist/agent-src/templates/scripts/README.md +2 -2
  376. package/dist/agent-src/user-types/_template/user-type.md +1 -1
  377. package/dist/cli-delegate/check_update_banner.js +12 -1
  378. package/dist/cli-delegate/{chunk-NLP54U3J.js → chunk-2XY7ILBT.js} +13 -1
  379. package/dist/cli-delegate/{chunk-IAI3XL43.js → chunk-3FKR64R5.js} +22 -6
  380. package/dist/cli-delegate/{chunk-J3RFNKG4.js → chunk-55ACLDUE.js} +2 -2
  381. package/dist/cli-delegate/{chunk-PKOBQADP.js → chunk-57PN4GYJ.js} +1 -1
  382. package/dist/cli-delegate/{chunk-KCNTUSPI.js → chunk-AK6HODNQ.js} +4 -4
  383. package/dist/cli-delegate/{chunk-2FTMENJL.js → chunk-GYC3VRYN.js} +1 -1
  384. package/dist/cli-delegate/{chunk-LWTYTX6F.js → chunk-H32DGUJH.js} +15 -84
  385. package/dist/cli-delegate/{chunk-6RJA2F5A.js → chunk-IVBPRCQO.js} +1 -1
  386. package/dist/cli-delegate/chunk-NUHLI2RX.js +80 -0
  387. package/dist/cli-delegate/{chunk-TYSY33MD.js → chunk-QJWAUMJW.js} +12 -2
  388. package/dist/cli-delegate/{chunk-2KKXJW25.js → chunk-S3VFXMTM.js} +1 -1
  389. package/dist/cli-delegate/{chunk-I6RHFQEG.js → chunk-YUM5KURG.js} +17 -1
  390. package/dist/cli-delegate/cmd_analyze_session.js +1 -1
  391. package/dist/cli-delegate/cmd_brand_status.js +1 -1
  392. package/dist/cli-delegate/cmd_conformance.js +834 -275
  393. package/dist/cli-delegate/cmd_doctor.js +3 -3
  394. package/dist/cli-delegate/cmd_explain.js +5 -3
  395. package/dist/cli-delegate/cmd_export.js +4 -4
  396. package/dist/cli-delegate/cmd_handoff.js +6 -6
  397. package/dist/cli-delegate/cmd_mcp_available.js +1 -1
  398. package/dist/cli-delegate/cmd_memory_get.js +1 -1
  399. package/dist/cli-delegate/cmd_migrate.js +2 -2
  400. package/dist/cli-delegate/cmd_packs_active.js +3 -2
  401. package/dist/cli-delegate/cmd_prune.js +4 -4
  402. package/dist/cli-delegate/cmd_route_audit.js +3 -3
  403. package/dist/cli-delegate/cmd_route_explain.js +1 -1
  404. package/dist/cli-delegate/cmd_session_recycle.js +3 -3
  405. package/dist/cli-delegate/cmd_settings_get.js +15 -9
  406. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  407. package/dist/cli-delegate/cmd_settings_set.js +54 -11
  408. package/dist/cli-delegate/cmd_sync.js +4 -4
  409. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  410. package/dist/cli-delegate/cmd_update.js +1 -1
  411. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  412. package/dist/cli-delegate/cmd_validate.js +4 -4
  413. package/dist/cli-delegate/cmd_versions.js +1 -1
  414. package/dist/discovery/deprecation-report.md +1 -1
  415. package/dist/discovery/discovery-manifest.json +25 -78
  416. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  417. package/dist/discovery/discovery-manifest.summary.md +3 -3
  418. package/dist/discovery/dormancy-report.md +1 -1
  419. package/dist/discovery/orphan-report.md +1 -1
  420. package/dist/discovery/packs.json +5 -7
  421. package/dist/discovery/trust-report.md +2 -2
  422. package/dist/discovery/workspaces.json +4 -6
  423. package/dist/hooks/dispatch.js +9684 -9304
  424. package/dist/install/install.mjs +36 -8
  425. package/dist/mcp/registry-manifest.json +3 -3
  426. package/dist/mcp/server.json +2 -2
  427. package/dist/mcp/server.mjs +2147 -1470
  428. package/dist/router.json +1 -1
  429. package/dist/scripts/_lib/agent_settings.js +73 -0
  430. package/dist/scripts/_lib/agent_src.js +20 -0
  431. package/dist/scripts/_lib/guidelines_lane.js +158 -0
  432. package/dist/scripts/_lib/installed_lock.js +1 -1
  433. package/dist/scripts/condense.js +2 -5
  434. package/dist/server/io/yamlIO.js +175 -17
  435. package/dist/server/schemas/settings.js +18 -4
  436. package/dist/shared/settingsSurface.js +6 -1
  437. package/docs/contracts/settings-classes.md +18 -9
  438. package/docs/guidelines/abstraction-thresholds.md +35 -0
  439. package/docs/guidelines/agent-infra/active-remediation-mechanics.md +3 -3
  440. package/docs/guidelines/agent-infra/false-green.md +2 -2
  441. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  442. package/docs/guidelines/agent-infra/skill-quality-checklist.md +1 -1
  443. package/docs/guidelines/design-fidelity-mechanics.md +4 -0
  444. package/docs/guidelines/design-fidelity-routing.md +78 -0
  445. package/docs/guidelines/design-reconciliation.md +172 -0
  446. package/docs/guidelines/gtm-handoff.md +2 -2
  447. package/docs/guidelines/wing4-handoff.md +2 -2
  448. package/package.json +7 -3
  449. package/src/config/agent-settings.template.yml +55 -8
  450. package/src/config/ci-local-parity.yml +34 -0
  451. package/src/config/continuity-surface.json +11 -32
  452. package/src/config/gate-coverage.yml +31 -8
  453. package/src/config/gate-reachability-exemptions.json +1 -0
  454. package/src/config/gate-violation-baselines.json +3 -3
  455. package/src/config/hook-token-budget.json +1 -1
  456. package/src/config/host-injection-effect.json +2 -2
  457. package/src/config/pack-size-budget.json +55 -4
  458. package/src/config/platform-anchor.json +47 -0
  459. package/src/config/preamble-payload-budget.json +12 -8
  460. package/src/config/preamble-payload-exceptions.json +28 -0
  461. package/src/config/publish-surface.json +4 -2
  462. package/src/config/ratification-policy.json +7 -0
  463. package/src/config/rule-stub-ceilings.json +16 -9
  464. package/src/scripts/_cli/cmd_settings_get.ts +22 -7
  465. package/src/scripts/_dispatch.bash +3 -1
  466. package/src/scripts/_lib/agent_settings.ts +85 -0
  467. package/src/scripts/_lib/agent_src.ts +21 -0
  468. package/src/scripts/_lib/artifact_maturity.ts +242 -0
  469. package/src/scripts/_lib/base_ref_payload.ts +315 -0
  470. package/src/scripts/_lib/conformance_report.ts +403 -0
  471. package/src/scripts/_lib/continuity_writer.ts +72 -13
  472. package/src/scripts/_lib/design_system_import.ts +20 -0
  473. package/src/scripts/_lib/design_tolerance.ts +281 -0
  474. package/src/scripts/_lib/dropped_decision.ts +142 -0
  475. package/src/scripts/_lib/guidelines_lane.ts +164 -0
  476. package/src/scripts/_lib/installed_lock.ts +1 -1
  477. package/src/scripts/_lib/measured_payload_ceiling.ts +424 -0
  478. package/src/scripts/_lib/obligation_frequency.ts +2 -3
  479. package/src/scripts/_lib/payload_catalogue_completeness.ts +211 -0
  480. package/src/scripts/_lib/platform_anchor.ts +1053 -0
  481. package/src/scripts/_lib/ratification_artifact.ts +278 -0
  482. package/src/scripts/_lib/release_findings_ingest.ts +324 -0
  483. package/src/scripts/_lib/release_tag_dispatch.ts +63 -0
  484. package/src/scripts/_lib/review_baseline.ts +254 -0
  485. package/src/scripts/_lib/review_skipped_record.ts +61 -1
  486. package/src/scripts/_lib/security_lint.ts +23 -2
  487. package/src/scripts/_lib/self_repair.ts +21 -0
  488. package/src/scripts/_lib/session_index_trust.ts +42 -1
  489. package/src/scripts/_lib/standing_bound_ratchet.ts +267 -88
  490. package/src/scripts/_lib/tolerance_shadow.ts +177 -0
  491. package/src/scripts/_lib/turn_end_refusals.ts +51 -4
  492. package/src/scripts/ai_council/redact_low_impact_entry.ts +8 -0
  493. package/src/scripts/autonomy_friction_traffic.ts +379 -0
  494. package/src/scripts/check_beta_review_markers.ts +35 -4
  495. package/src/scripts/check_finding_dispositions.ts +167 -16
  496. package/src/scripts/check_held_object_arrivals.ts +381 -0
  497. package/src/scripts/check_kernel_edit_ratified.ts +462 -0
  498. package/src/scripts/check_loss_class_declared.ts +793 -46
  499. package/src/scripts/check_platform_anchor.ts +390 -0
  500. package/src/scripts/check_preamble_payload_budget.ts +672 -107
  501. package/src/scripts/check_projected_rule_routes.ts +395 -0
  502. package/src/scripts/check_release_published.ts +1 -1
  503. package/src/scripts/check_reply_consistency.ts +86 -17
  504. package/src/scripts/code_graph/cli.ts +6 -0
  505. package/src/scripts/condense.ts +2 -6
  506. package/src/scripts/generate_host_cost_table.ts +354 -0
  507. package/src/scripts/hook_manifest.json +1 -1
  508. package/src/scripts/hook_manifest.yaml +74 -30
  509. package/src/scripts/hooks/block_kernel_rule_writes.ts +12 -2
  510. package/src/scripts/hooks/category_a.ts +1 -1
  511. package/src/scripts/hooks/chain_nudge_hook.ts +311 -25
  512. package/src/scripts/hooks/concern_registry.ts +2 -0
  513. package/src/scripts/hooks/end_review_nudge_hook.ts +101 -21
  514. package/src/scripts/hooks/review_baseline_hook.ts +130 -0
  515. package/src/scripts/hooks/session_eol_hook.ts +68 -154
  516. package/src/scripts/hooks/source_first_gate_hook.ts +12 -0
  517. package/src/scripts/hooks/turn_end_gate_hook.ts +232 -14
  518. package/src/scripts/hooks/ui_route_nudge_hook.ts +52 -15
  519. package/src/scripts/hooks_doctor.ts +4 -1
  520. package/src/scripts/hot_context_hook.ts +41 -401
  521. package/src/scripts/install.ts +1 -1
  522. package/src/scripts/interruption_report.ts +8 -2
  523. package/src/scripts/janitor.ts +8 -1
  524. package/src/scripts/lint_evidence_artifacts.ts +1 -0
  525. package/src/scripts/lint_knowledge_scale.ts +0 -26
  526. package/src/scripts/measure_turn_end_gate.ts +302 -5
  527. package/src/scripts/memory_lookup.ts +9 -9
  528. package/src/scripts/release.ts +52 -64
  529. package/src/scripts/release_drill.ts +193 -14
  530. package/src/scripts/release_env.ts +1 -1
  531. package/src/scripts/release_publication.ts +1 -1
  532. package/src/scripts/report_held_object_arrivals.ts +456 -0
  533. package/src/scripts/report_standing_payload_by_host.ts +7 -7
  534. package/src/scripts/session_memory_index.ts +5 -0
  535. package/src/scripts/sync_agent_settings.ts +394 -12
  536. package/src/server/io/yamlIO.ts +175 -17
  537. package/src/server/schemas/settings.ts +25 -5
  538. package/src/shared/settingsSurface.ts +13 -2
  539. package/src/templates/compact-instructions.md +8 -3
  540. package/dist/agent-src/commands/chat-history/import.md +0 -170
  541. package/dist/agent-src/commands/chat-history.md +0 -63
@@ -18,59 +18,97 @@
18
18
  * bucket has no local source at all — the census reports that one as an explicit
19
19
  * residual rather than pretending to measure it.
20
20
  *
21
- * THE BOUND IS SHRINK-ONLY, AND NOW CHECKED
22
- * ------------------------------------------
23
- * `ci_delivery.why_a_grace_ceiling` says of the grace ceiling *"It may never
24
- * move UP"*, and `grace_ceiling_history` in the same file records it moving up
25
- * twice. ADR-264 resolved that against the practice — the sentence stands — and
26
- * left the sentence unenforced, which is exactly the state that produced both
27
- * raises. `_lib/standing_bound_ratchet.ts` is the enforcement: the effective
28
- * ceiling is compared against the one at the base ref and a rise refuses the run,
29
- * whether it arrived by editing the config or by passing a bigger `--ceiling`.
21
+ * THE CEILING IS MEASURED AT THE BASE REF, NOT STORED
22
+ * ----------------------------------------------------
23
+ * It used to be a stored `ci_delivery.grace_ceiling`, whose own text said *"It
24
+ * may never move UP"* while `grace_ceiling_history` recorded it moving up
25
+ * twice. ADR-264 resolved that against the practice and left the sentence
26
+ * unenforced; `_lib/standing_bound_ratchet.ts` became the enforcement.
30
27
  *
31
- * It is also ALL that `road-to-a-standing-budget-with-headroom` step 1.3 ships.
32
- * That step designed a 128-token Iron Law reserve; an AI council refused to
33
- * activate it 2/2 on 2026-09-08 because the verifier is inside the change under
34
- * review, so a protected approval record grants nothing. ADR-265 carries the
35
- * verdict and the activation prerequisites.
28
+ * `road-to-delivery-for-every-host` 4.4 retires the stored number entirely. An
29
+ * AI council (2/2, 2026-09-10, under a written owner delegation) converged on
36
30
  *
37
- * Exit codes: 0 within budget · 1 over budget or the bound rose · 2 misuse /
38
- * unreadable budget.
31
+ * ceiling = max(design_ceiling, payload_at_base_ref + active grants)
32
+ *
33
+ * for one reason: a measured ceiling captures every merged reduction
34
+ * automatically, where a stored one stays at its last hand-written number — so
35
+ * payload a merge removed can be added straight back into the space it freed.
36
+ * The ordinary path is therefore ZERO NET GROWTH while the tree is over design,
37
+ * and the design ceiling once it is at or below. No per-PR headroom: both seats
38
+ * refused one because a percentage or a fixed allowance against a moving base
39
+ * authorises cumulative growth (138,413 × 1.05^10 ≈ 225,000).
40
+ *
41
+ * Three prerequisites came with the verdict and all three are in the pipeline
42
+ * below. The base measurement FAILS CLOSED under `--require-base`, because a
43
+ * base that cannot be read would otherwise grant an unbounded budget. The
44
+ * shrink-only ratchet moved with the ceiling: `design_ceiling` and every
45
+ * existing exception grant and watermark are now the bounded numbers. And the
46
+ * catalogue exhaustiveness audit refuses payload sitting outside every measured
47
+ * bucket, which defeats a stored ceiling exactly as it would defeat this one.
48
+ *
49
+ * A change whose offsetting reduction is genuinely unsafe takes a recorded,
50
+ * human-approved, dated grant in `src/config/preamble-payload-exceptions.json`.
51
+ * 96.8 % of the last 250 merged pull requests moved this payload by zero or
52
+ * less, so the ordinary path stays autonomous and only the tail reaches a
53
+ * person. `_lib/measured_payload_ceiling.ts` carries the mechanism and the
54
+ * reasoning, including why no numeric cap is enforced.
55
+ *
56
+ * ADR-265 still holds for what this does NOT do: the 128-token Iron Law reserve
57
+ * stays unshipped, because a mechanism that GRANTS budget cannot rest on a
58
+ * verifier the change under review can edit.
59
+ *
60
+ * Exit codes: 0 within budget · 1 over budget, a bound rose, the ceiling could
61
+ * not be measured under `--require-base`, or payload sits outside the catalogue
62
+ * · 2 misuse / unreadable budget.
39
63
  */
40
- import { execFileSync } from 'node:child_process';
41
64
  import * as fs from 'node:fs';
42
- import * as os from 'node:os';
43
65
  import * as path from 'node:path';
44
66
 
67
+ import { asOf } from './_lib/as_of.js';
45
68
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
46
69
  import { censusClaudeMdHierarchy, censusRuleDir, censusSkillsCatalog } from './preamble_byte_census.js';
47
70
  import { PREFIX_STABLE_SURFACES, prefixStableRoots } from './_lib/prefix_stable_surfaces.js';
71
+ import { HOST_SURFACES } from './_lib/host_projection_reach.js';
48
72
  import { attributeGrowth, buildLedger, renderAttribution } from './_lib/asset_delivery_ledger.js';
49
73
  import { resolveBaseRef } from './_lib/ratchet_base_ref.js';
74
+ import { extractSurfacesAtRef, measurePayloadAtRef } from './_lib/base_ref_payload.js';
75
+ import {
76
+ type CeilingReading,
77
+ computeCeiling,
78
+ EXCEPTIONS_CONFIG_PATH,
79
+ readExceptions,
80
+ renderCeiling,
81
+ } from './_lib/measured_payload_ceiling.js';
82
+ import { auditCatalogue, type CatalogueAudit } from './_lib/payload_catalogue_completeness.js';
50
83
  import {
51
84
  assertBoundsDidNotRise,
52
85
  type BoundsRatchetVerdict,
86
+ boundsFrom,
53
87
  type GitRunner,
54
88
  realGit,
55
89
  } from './_lib/standing_bound_ratchet.js';
56
90
 
57
91
  const HERE = path.dirname(new URL(import.meta.url).pathname);
92
+ /**
93
+ * Where this SCRIPT lives — the default tree to measure, and nothing more.
94
+ *
95
+ * Under prerequisite 3 of the measured-ceiling verdict, CI runs this file as it
96
+ * exists at the BASE ref against the HEAD tree, so that a pull request cannot
97
+ * edit the code that measures it. There the two diverge and `--repo-root`
98
+ * carries the tree; everywhere else they are the same directory.
99
+ */
58
100
  const REPO_ROOT = path.resolve(HERE, '..', '..');
59
- const BUDGET_FILE = path.join(REPO_ROOT, 'src', 'config', 'preamble-payload-budget.json');
101
+
102
+ /** The budget config inside a given tree. */
103
+ function budgetFileIn(repoRoot: string): string {
104
+ return path.join(repoRoot, 'src', 'config', 'preamble-payload-budget.json');
105
+ }
106
+ const BUDGET_FILE = budgetFileIn(REPO_ROOT);
60
107
 
61
108
  interface Budget {
62
109
  baseline_tokens: number;
63
110
  headroom_pct: number;
64
111
  target_tokens: { median: number; p95: number };
65
- /**
66
- * `ci_delivery.grace_ceiling`, or `null` when the file carries none.
67
- *
68
- * Read here only so the shrink-only ratchet has a head-side value on a local
69
- * run that passes no `--ceiling`. The number the payload is COMPARED against
70
- * still arrives through the flag, so this does not become a second home for
71
- * the ceiling.
72
- */
73
- grace_ceiling: number | null;
74
112
  }
75
113
 
76
114
  export interface BudgetVerdict {
@@ -93,16 +131,19 @@ export function readBudget(file: string = BUDGET_FILE): Budget {
93
131
  throw new Error(`${file}: baseline_tokens and headroom_pct must both be numbers`);
94
132
  }
95
133
  const target = (raw['target_tokens'] ?? {}) as Record<string, unknown>;
96
- const delivery = (raw['ci_delivery'] ?? {}) as Record<string, unknown>;
97
- const grace = Number(delivery['grace_ceiling']);
98
134
  return {
99
135
  baseline_tokens: baseline,
100
136
  headroom_pct: headroom,
101
137
  target_tokens: { median: Number(target['median']), p95: Number(target['p95']) },
102
- grace_ceiling: Number.isFinite(grace) ? grace : null,
103
138
  };
104
139
  }
105
140
 
141
+ /** The raw budget JSON, for the bound derivation that must see head and base
142
+ * through the SAME function. `readBudget` narrows; this does not. */
143
+ function readBudgetRaw(file: string): unknown {
144
+ return JSON.parse(fs.readFileSync(file, 'utf-8'));
145
+ }
146
+
106
147
  /** Look one surface root up by id. Throws on an unknown id — a renamed surface
107
148
  * must fail loudly here rather than degrade this gate to measuring nothing. */
108
149
  function surfaceRoot(id: string): string {
@@ -149,6 +190,174 @@ export function measureDeterministicPayload(
149
190
  ];
150
191
  }
151
192
 
193
+ /**
194
+ * THE HOST READING — additive, and deliberately not the ratchet's surface.
195
+ *
196
+ * `measureDeterministicPayload` above measures `dist/agent-src/rules`: the
197
+ * projection SOURCE. That is the right surface for the shrink-only ratchet,
198
+ * because the source is what every host tree is written FROM and what a pull
199
+ * request actually edits. It is the wrong surface for one question: how many
200
+ * standing tokens does a session on host X start with? Under a per-host
201
+ * `delivery` projection the two answers diverge by design — measured 2026-09-07,
202
+ * `.claude/rules` went 99,598 tok to 24,166 tok while the source stayed at
203
+ * 138,200 either side of the flip.
204
+ *
205
+ * So this adds a SECOND reading and changes nothing about the first. AI council
206
+ * of 2026-09-09 (2/2 present, converged on option 1A):
207
+ *
208
+ * - the no-argument source measurement, the blocking CI invocation, the
209
+ * `task ci` invocation and the base-ref ratchet are untouched, so no
210
+ * existing baseline or history entry is reinterpreted;
211
+ * - the host reading is reported alongside and NEVER changes the exit code —
212
+ * an informational census, not a second gate.
213
+ *
214
+ * Both seats were explicit that the host id must resolve through the existing
215
+ * projection registry rather than a path map invented here, which is why the
216
+ * roots come from `HOST_SURFACES` in `_lib/host_projection_reach.ts` — the same
217
+ * committed constant `check_host_projection_reach` walks.
218
+ */
219
+ export interface HostPayload {
220
+ /** The host id as given, or `null` when a raw rules-dir override was used. */
221
+ host: string | null;
222
+ /** Repo-relative rules root actually measured. */
223
+ rules_path: string;
224
+ buckets: Array<{ name: string; tokens: number; files: number }>;
225
+ total: number;
226
+ /**
227
+ * Rule files in the host tree, against rule files in the projection source.
228
+ *
229
+ * A maintainer checkout is NOT a consumer install and its host tree is
230
+ * routinely smaller for reasons that have nothing to do with a projection
231
+ * mode: the installer deduplicates a project rule against the same rule
232
+ * already present at user scope, and a dev tree may hold a partial
233
+ * projection. Measured in this repository 2026-09-09: 13 files under
234
+ * `.claude/rules` against 119 in `dist/agent-src/rules`.
235
+ *
236
+ * A bare token total cannot tell a genuine saving from a tree that was never
237
+ * fully written, and those two send a reader to completely different places.
238
+ * So the counts travel with the number, and `complete` is false whenever the
239
+ * host tree holds fewer rule files than the source.
240
+ */
241
+ completeness: { host_rule_files: number; source_rule_files: number; complete: boolean };
242
+ }
243
+
244
+ /** Every host id this reading accepts, in registry order. */
245
+ export function hostPayloadIds(): string[] {
246
+ return HOST_SURFACES.map((h) => h.id);
247
+ }
248
+
249
+ /**
250
+ * Split a host declared projections into the standing-payload buckets.
251
+ *
252
+ * Classification is derived from the registry rather than restated: a projection
253
+ * ending in `/skills` is the skills catalogue, one ending in `/commands` is
254
+ * EXCLUDED because a command is invoked rather than standing, and whatever
255
+ * remains is the rules surface — a directory on the per-rule hosts, a single
256
+ * `.md` file on the single-surface hosts, which is also that host root
257
+ * instruction file.
258
+ *
259
+ * The one conditional is `claude-code`, and it is a conditional rather than a
260
+ * map row: the `CLAUDE.md` / `CLAUDE.local.md` pair is already declared in
261
+ * `PREFIX_STABLE_SURFACES` as `project-claude-md` and `project-claude-local-md`,
262
+ * it is that host root instruction file, and no other host reads it.
263
+ */
264
+ export function hostPayloadRoots(hostId: string): {
265
+ rules: string;
266
+ skills: string | null;
267
+ claudeMd: boolean;
268
+ } {
269
+ const surface = HOST_SURFACES.find((h) => h.id === hostId);
270
+ if (surface === undefined) {
271
+ throw new Error(
272
+ `unknown host '${hostId}' — known ids: ${hostPayloadIds().join(', ')}. ` +
273
+ 'The set is HOST_SURFACES in _lib/host_projection_reach.ts; a host absent there has no ' +
274
+ 'declared projection for this reading to measure.',
275
+ );
276
+ }
277
+ const skills = surface.projections.find((r) => r.endsWith('/skills')) ?? null;
278
+ const rules = surface.projections.find(
279
+ (r) => !r.endsWith('/skills') && !r.endsWith('/commands'),
280
+ );
281
+ if (rules === undefined) {
282
+ throw new Error(
283
+ `host '${hostId}' declares no rules-bearing projection in HOST_SURFACES ` +
284
+ `(projections: ${surface.projections.join(', ') || 'none'}) — nothing to measure`,
285
+ );
286
+ }
287
+ return { rules, skills, claudeMd: hostId === 'claude-code' };
288
+ }
289
+
290
+ /** Char count for one root, whether it is a rules directory or a single file. */
291
+ function charsAtRoot(abs: string): { chars: number; files: number } {
292
+ let st: fs.Stats;
293
+ try {
294
+ st = fs.statSync(abs);
295
+ } catch {
296
+ return { chars: 0, files: 0 };
297
+ }
298
+ if (st.isFile()) return { chars: fs.readFileSync(abs, 'utf-8').length, files: 1 };
299
+ const c = censusRuleDir(abs);
300
+ return { chars: c.chars, files: c.files };
301
+ }
302
+
303
+ /**
304
+ * Measure the standing payload of the tree ONE host loads.
305
+ *
306
+ * `rulesDirOverride` is the low-level escape for a tree no host id names — a
307
+ * fixture, a consumer-shaped root, a comparison against a never-flipped tree.
308
+ * It is mutually exclusive with `host` at the CLI layer.
309
+ */
310
+ export function measureHostPayload(
311
+ repoRoot: string,
312
+ opts: { host?: string; rulesDirOverride?: string },
313
+ ): HostPayload {
314
+ const roots = opts.rulesDirOverride === undefined ? hostPayloadRoots(opts.host ?? '') : null;
315
+ const rulesRel = opts.rulesDirOverride ?? (roots as { rules: string }).rules;
316
+ const rulesAbs = path.isAbsolute(rulesRel) ? rulesRel : path.join(repoRoot, rulesRel);
317
+ if (!fs.existsSync(rulesAbs)) {
318
+ throw new Error(
319
+ `rules root '${rulesRel}' does not exist under ${repoRoot} — a host tree that was never ` +
320
+ 'projected reads as zero tokens, which is indistinguishable from a tiny one, so this ' +
321
+ 'refuses rather than reporting a green nothing',
322
+ );
323
+ }
324
+ const buckets: Array<{ name: string; tokens: number; files: number }> = [];
325
+ const rulesCensus = charsAtRoot(rulesAbs);
326
+ buckets.push({
327
+ name: `rules (${rulesRel})`,
328
+ tokens: tokens(rulesCensus.chars),
329
+ files: rulesCensus.files,
330
+ });
331
+
332
+ if (roots !== null && roots.skills !== null) {
333
+ const sk = censusSkillsCatalog(path.join(repoRoot, roots.skills));
334
+ buckets.push({
335
+ name: `skills catalog (${roots.skills})`,
336
+ tokens: tokens(sk.chars),
337
+ files: sk.skills,
338
+ });
339
+ }
340
+ if (roots !== null && roots.claudeMd) {
341
+ const md = censusClaudeMdHierarchy(repoRoot, path.join(repoRoot, '.no-such-home'));
342
+ const chars = md.project_claude_md_chars + md.project_claude_local_md_chars;
343
+ const files =
344
+ (md.project_claude_md_present ? 1 : 0) + (md.project_claude_local_md_present ? 1 : 0);
345
+ buckets.push({ name: 'CLAUDE.md hierarchy (project only)', tokens: tokens(chars), files });
346
+ }
347
+ const sourceRules = censusRuleDir(path.join(repoRoot, surfaceRoot('project-scope-rules')));
348
+ return {
349
+ host: opts.rulesDirOverride === undefined ? (opts.host ?? null) : null,
350
+ rules_path: rulesRel,
351
+ buckets,
352
+ total: buckets.reduce((n, b) => n + b.tokens, 0),
353
+ completeness: {
354
+ host_rule_files: rulesCensus.files,
355
+ source_rule_files: sourceRules.files,
356
+ complete: rulesCensus.files >= sourceRules.files,
357
+ },
358
+ };
359
+ }
360
+
152
361
  /**
153
362
  * A caller-supplied ceiling, and the one direction it may go.
154
363
  *
@@ -189,97 +398,198 @@ export function evaluate(repoRoot?: string, budgetFile?: string, overrideCeiling
189
398
  export interface Decision {
190
399
  verdict: BudgetVerdict;
191
400
  bounds: BoundsRatchetVerdict;
192
- /** False when the payload is over the ceiling, or the ceiling itself rose. */
401
+ /** How the ceiling was arrived at, and whether it may be trusted. */
402
+ ceiling: CeilingReading;
403
+ /** Payload the census does not enumerate. Empty findings = complete. */
404
+ catalogue: CatalogueAudit;
405
+ /** False when the payload is over the ceiling, a bound rose, the ceiling
406
+ * could not be measured under `--require-base`, or payload escaped the
407
+ * catalogue. */
193
408
  ok: boolean;
194
409
  }
195
410
 
196
411
  export interface DecideOptions {
197
412
  repoRoot?: string;
198
413
  budgetFile?: string;
199
- overrideCeiling?: number;
200
414
  env?: NodeJS.ProcessEnv;
201
415
  git?: GitRunner;
202
416
  /** Test seam: pin the base ref instead of resolving it. `null` = none resolved. */
203
417
  baseRef?: string | null;
418
+ /** Refuse instead of skipping when the base ref cannot be read. */
419
+ requireBase?: boolean;
420
+ /** Test seam: pin today's date for the exception-expiry branch. */
421
+ today?: string;
422
+ /** Test seam: supply the base payload instead of measuring the ref. */
423
+ basePayload?: number | null;
424
+ /**
425
+ * Exception ids whose approval event was VERIFIED against the platform.
426
+ *
427
+ * Empty by default, which is the safe reading: a grant nobody confirmed is
428
+ * a grant the diff asserted about itself. Only a caller with platform
429
+ * access can populate this, which is why it is not read from the tree.
430
+ */
431
+ verifiedApprovals?: readonly string[];
204
432
  }
205
433
 
434
+ /**
435
+ * The measurement, the ceiling it is compared against, and everything that can
436
+ * refuse independently of the size question.
437
+ *
438
+ * `evaluate` above answers "how big is the tree" and touches no ref; this
439
+ * answers "may this tree ship" and needs the base one. They stay separate
440
+ * because a census that silently depended on a remote ref would behave
441
+ * differently in a shallow clone, and the census is the half other callers use.
442
+ *
443
+ * ORDER MATTERS ONLY IN ONE PLACE: the ceiling is established BEFORE the size
444
+ * comparison, because a run that could not measure its ceiling has no
445
+ * business reporting a tree as within one.
446
+ */
206
447
  export function decide(opts: DecideOptions = {}): Decision {
207
448
  const repoRoot = opts.repoRoot ?? REPO_ROOT;
208
449
  const git = opts.git ?? realGit;
209
- const budget = readBudget(opts.budgetFile);
210
- const verdict = evaluate(repoRoot, opts.budgetFile, opts.overrideCeiling);
450
+ const budgetFile = opts.budgetFile ?? budgetFileIn(repoRoot);
451
+ const budget = readBudget(budgetFile);
452
+ const design = Math.round(budget.baseline_tokens * (1 + budget.headroom_pct / 100));
453
+
211
454
  const baseRef =
212
455
  opts.baseRef !== undefined ? opts.baseRef : resolveBaseRef(repoRoot, opts.env ?? process.env, git);
456
+
457
+ // The base payload goes through THIS file's own census, so base and head
458
+ // cannot be measured by two different definitions — the property that keeps
459
+ // a measured ceiling from drifting against the number it bounds.
460
+ const sumPayload = (root: string): number =>
461
+ measureDeterministicPayload(root).reduce((n, b) => n + b.tokens, 0);
462
+ let basePayload: number | null;
463
+ let baseNote: string | null;
464
+ if (opts.basePayload !== undefined) {
465
+ basePayload = opts.basePayload;
466
+ baseNote = basePayload === null ? 'the base payload was pinned to null by the caller' : null;
467
+ } else if (baseRef === null || baseRef.trim() === '') {
468
+ basePayload = null;
469
+ baseNote = 'no base ref resolved';
470
+ } else {
471
+ const reading = measurePayloadAtRef({ repoRoot, ref: baseRef, measure: sumPayload });
472
+ basePayload = reading.tokens;
473
+ baseNote = reading.note;
474
+ }
475
+
476
+ const exceptionsFile = path.join(repoRoot, EXCEPTIONS_CONFIG_PATH);
477
+ const ex = readExceptions(exceptionsFile);
478
+ const ceiling = computeCeiling({
479
+ designCeiling: design,
480
+ basePayload,
481
+ baseNote,
482
+ headPayload: sumPayload(repoRoot),
483
+ exceptions: ex.exceptions,
484
+ exceptionErrors: ex.errors,
485
+ verifiedApprovals: opts.verifiedApprovals ?? [],
486
+ // Through the as-of seam, not the wall clock. An exception expiry is
487
+ // exactly the kind of verdict that must be reproducible from the
488
+ // commit: a grant that expires overnight would make the same tree pass
489
+ // and then fail with nothing in the diff to explain it.
490
+ today: opts.today ?? asOf().toISOString().slice(0, 10),
491
+ requireBase: opts.requireBase === true,
492
+ });
493
+
494
+ const verdict = evaluate(repoRoot, budgetFile, ceiling.ceiling);
495
+
496
+ // The head-side bounds go through `boundsFrom` exactly as the base-side
497
+ // ones do, from the raw configs rather than the narrowed ones — one
498
+ // derivation for both sides, which is what the grace ceiling never had.
499
+ let headBounds: Record<string, number> = { design_ceiling: design };
500
+ try {
501
+ const raw = readBudgetRaw(budgetFile);
502
+ let rawEx: unknown = null;
503
+ try {
504
+ rawEx = JSON.parse(fs.readFileSync(exceptionsFile, 'utf-8'));
505
+ } catch {
506
+ /* absent ledger contributes no bounds */
507
+ }
508
+ headBounds = boundsFrom(raw, rawEx) ?? headBounds;
509
+ } catch {
510
+ /* readBudget above already threw on an unusable file */
511
+ }
213
512
  const bounds = assertBoundsDidNotRise({
214
513
  repoRoot,
215
514
  baseRef,
216
515
  git,
217
- headGraceCeiling: opts.overrideCeiling ?? budget.grace_ceiling ?? 0,
516
+ headBounds,
517
+ requireBase: opts.requireBase === true,
218
518
  });
219
- return { verdict, bounds, ok: bounds.ok && verdict.withinBudget };
519
+
520
+ const catalogue = auditCatalogue(repoRoot);
521
+
522
+ return {
523
+ verdict,
524
+ bounds,
525
+ ceiling,
526
+ catalogue,
527
+ // THE SIZE COMPARISON IS ONLY MADE AGAINST A CEILING THAT WAS
528
+ // ESTABLISHED. An advisory run that could not read the base has no
529
+ // bound to compare against, and falling back to the design ceiling
530
+ // would report a 28 %-over tree as OVER BUDGET for a reason that has
531
+ // nothing to do with the change — the exact "I could not look" /
532
+ // "I looked and it grew" conflation the enforcing refusal spells out
533
+ // in its own message. So it reports and does not gate.
534
+ //
535
+ // This is not a hole: the CI step passes `--require-base`, where an
536
+ // unestablished ceiling REFUSES. It was invisible until the stored
537
+ // ceiling was deleted, because that number was the fallback.
538
+ ok:
539
+ bounds.ok &&
540
+ ceiling.ok &&
541
+ catalogue.findings.length === 0 &&
542
+ (ceiling.verified ? verdict.withinBudget : true),
543
+ };
220
544
  }
221
545
 
222
546
  /**
223
- * Per-asset attribution for a refusal, against the merge-base tree.
547
+ * Per-asset attribution for a refusal, against the base tree.
548
+ *
549
+ * Every failure mode returns `null` — the caller treats attribution as an
550
+ * explanation, never as a precondition for refusing. A gate that failed to
551
+ * refuse because it could not explain itself would be strictly worse than one
552
+ * that refuses without the explanation.
224
553
  *
225
- * Reads the base tree through `git worktree`-free plumbing: the ledger is built
226
- * over a temporary checkout of `git merge-base HEAD origin/main`. Every failure
227
- * mode returns an empty list — the caller treats attribution as an explanation,
228
- * never as a precondition for refusing.
554
+ * It reads the base tree through `_lib/base_ref_payload`, the same
555
+ * materialisation the ceiling uses. It used to shell `git archive` directly,
556
+ * which silently drops `export-ignore` paths — harmless for the two roots this
557
+ * ledger reads, and a live 746-token defect for the ceiling. Both now go
558
+ * through the one reader rather than through two that differ in a way nobody
559
+ * would notice until the numbers disagreed.
229
560
  */
230
- function attributeGrowthAgainstBase(): string[] | null {
561
+ function attributeGrowthAgainstBase(repoRoot: string, baseRef: string | null): string[] | null {
562
+ if (baseRef === null || baseRef.trim() === '') return null;
563
+ const t = extractSurfacesAtRef({ repoRoot, ref: baseRef });
564
+ if (t.tree === null) return null;
231
565
  try {
232
- const base = execFileSync('git', ['merge-base', 'HEAD', 'origin/main'], {
233
- cwd: REPO_ROOT,
234
- encoding: 'utf-8',
235
- stdio: ['ignore', 'pipe', 'ignore'],
236
- }).trim();
237
- if (base.length === 0) return null;
238
-
239
- const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'payload-base-'));
240
- try {
241
- for (const rel of prefixStableRoots()) {
242
- // `git archive` of one subtree, extracted into the scratch root.
243
- // A root absent at the base ref simply yields nothing.
244
- try {
245
- const tar = execFileSync('git', ['archive', base, '--', rel], {
246
- cwd: REPO_ROOT,
247
- maxBuffer: 256 * 1024 * 1024,
248
- stdio: ['ignore', 'pipe', 'ignore'],
249
- });
250
- // `-f -` is not optional: without it BSD tar reads its
251
- // default device rather than stdin, and the extraction
252
- // silently produces nothing — which reads downstream as
253
- // "the base tree was unavailable" rather than as a bug.
254
- execFileSync('tar', ['-x', '-f', '-', '-C', tmp], {
255
- input: tar,
256
- stdio: ['pipe', 'ignore', 'ignore'],
257
- });
258
- } catch {
259
- /* root absent at base — nothing to extract */
260
- }
261
- }
262
- const [rulesRel, skillsRel] = prefixStableRoots();
263
- const before = buildLedger(
264
- path.join(tmp, rulesRel ?? ''),
265
- path.join(tmp, skillsRel ?? ''),
266
- tmp,
267
- );
268
- const after = buildLedger(
269
- path.join(REPO_ROOT, rulesRel ?? ''),
270
- path.join(REPO_ROOT, skillsRel ?? ''),
271
- REPO_ROOT,
272
- );
273
- if (before.rows.length === 0) return null;
274
- return renderAttribution(attributeGrowth(before.rows, after.rows));
275
- } finally {
276
- fs.rmSync(tmp, { recursive: true, force: true });
277
- }
566
+ const [rulesRel, skillsRel] = prefixStableRoots();
567
+ const before = buildLedger(
568
+ path.join(t.tree, rulesRel ?? ''),
569
+ path.join(t.tree, skillsRel ?? ''),
570
+ t.tree,
571
+ );
572
+ const after = buildLedger(
573
+ path.join(repoRoot, rulesRel ?? ''),
574
+ path.join(repoRoot, skillsRel ?? ''),
575
+ repoRoot,
576
+ );
577
+ if (before.rows.length === 0) return null;
578
+ return renderAttribution(attributeGrowth(before.rows, after.rows));
278
579
  } catch {
279
580
  return null;
581
+ } finally {
582
+ t.dispose();
280
583
  }
281
584
  }
282
585
 
586
+ /** The stderr header for a refused bound. Exported so both refusals are testable. */
587
+ export function boundsRefusalHeader(b: BoundsRatchetVerdict): string {
588
+ return b.verified
589
+ ? '❌ a shrink-only standing-payload bound rose in this change:\n'
590
+ : '❌ the standing-payload bounds could not be VERIFIED, and this run requires it:\n';
591
+ }
592
+
283
593
  /**
284
594
  * The bound check, rendered for a human — on BOTH paths, green and red.
285
595
  *
@@ -287,30 +597,149 @@ function attributeGrowthAgainstBase(): string[] | null {
287
597
  * already load-bearing. Printing the compared ref and the earlier bound on the
288
598
  * passing path is also the only way a reader can tell "verified and unchanged"
289
599
  * from "skipped because no base ref resolved", which are different facts.
600
+ *
601
+ * THREE STATES, not two, and the third is why this was rewritten. An
602
+ * unverifiable bound and a risen one are both `ok: false` and need opposite
603
+ * actions — repair the checkout, or lower the addition. The first cut of the
604
+ * enforcing posture rendered both as `ROSE`, which a completion review caught:
605
+ * it sends an operator to shrink a rule over a fetch problem. `SKIPPED` is
606
+ * reserved for the ADVISORY skip, where nothing was refused at all.
290
607
  */
291
- function renderBounds(b: BoundsRatchetVerdict): string {
292
- if (b.note !== null) {
293
- return ` ${'grace ceiling ratchet'.padEnd(38)} ${'SKIPPED'.padStart(8)} — ${b.note}\n`;
608
+ export function renderBounds(b: BoundsRatchetVerdict): string {
609
+ const label = 'shrink-only bound ratchet';
610
+ if (b.note !== null && b.ok) {
611
+ return ` ${label.padEnd(38)} ${'SKIPPED'.padStart(8)} — ${b.note}\n`;
294
612
  }
295
- const base = b.baseGraceCeiling === null ? 'n/a' : String(b.baseGraceCeiling);
613
+ if (!b.verified) {
614
+ return (
615
+ ` ${label.padEnd(38)} ${'UNVERIFIED'.padStart(8)} — ` +
616
+ `${b.note ?? 'the bounds could not be read'} (this run requires it)\n`
617
+ );
618
+ }
619
+ const n = b.baseBounds === null ? 0 : Object.keys(b.baseBounds).length;
296
620
  const state = b.ok ? 'ok' : 'ROSE';
297
621
  return (
298
- ` ${'grace ceiling ratchet'.padEnd(38)} ${state.padStart(8)} — ` +
299
- `${base} at ${b.baseRef ?? 'n/a'}, shrink-only (ADR-264)\n`
622
+ ` ${label.padEnd(38)} ${state.padStart(8)} — ` +
623
+ `${String(n)} bound(s) at ${b.baseRef ?? 'n/a'}, shrink-only (ADR-264)\n`
300
624
  );
301
625
  }
302
626
 
303
627
  export function main(argv: string[] = process.argv.slice(2)): number {
304
628
  const json = argv.includes('--format=json') || argv.includes('--json');
305
- // `--ceiling <n>`: the grace ceiling the CI step reads out of
306
- // `ci_delivery.grace_ceiling`. Read from the budget file there, never written
307
- // in the workflow, so the number has exactly one home. A non-numeric or
308
- // tighter-than-design value is IGNORED rather than honoured — see `evaluate`.
309
- const ci = argv.indexOf('--ceiling');
310
- const override = ci !== -1 && argv[ci + 1] !== undefined ? Number(argv[ci + 1]) : undefined;
629
+
630
+ // `--ceiling <n>` is GONE. It existed to hand the gate the stored grace
631
+ // ceiling, and the ceiling is measured now. Refusing loudly rather than
632
+ // ignoring it is the point: a caller still passing a number believes it is
633
+ // setting the bound, and silently measuring something else would be the
634
+ // most expensive kind of no-op. The replacement for a deliberate, bounded
635
+ // widening is an approved entry in the exceptions ledger.
636
+ if (argv.includes('--ceiling')) {
637
+ process.stderr.write(
638
+ '❌ preamble-payload budget: --ceiling was removed. The ceiling is now MEASURED as\n' +
639
+ ' max(design_ceiling, payload at the base ref + active grants), so a caller-supplied\n' +
640
+ ` number cannot set it. To widen it deliberately, record an approved grant in\n` +
641
+ ` ${EXCEPTIONS_CONFIG_PATH} — it carries an approver, a reason, a watermark and an\n` +
642
+ ' expiry, which a flag never did.\n',
643
+ );
644
+ return 2;
645
+ }
646
+
647
+ // `--require-base`: refuse instead of skipping when the base ref cannot be
648
+ // read. An AI council (2/2, 2026-09-10) made this blocking for the move to
649
+ // a base-measured ceiling, because an unreadable base costs a comparison
650
+ // under a stored ceiling and grants an unbounded budget under a measured
651
+ // one. Opt-in rather than the default, and rather than derived from
652
+ // `GITHUB_ACTIONS`: a shallow clone, a first commit and a detached build
653
+ // all legitimately have no base, and a gate that reds on a developer's
654
+ // machine gets switched off.
655
+ const requireBase = argv.includes('--require-base');
656
+
657
+ // `--approved <id>` (repeatable): this caller VERIFIED that exception's
658
+ // approval event against the platform. Nothing in the tree can establish
659
+ // that — an `approved_by` field in the diff requesting the grant is
660
+ // self-asserted data, which was the 2026-09-11 council's hardest pushback
661
+ // in both seats. So the fact arrives from outside, from a caller that
662
+ // queried the platform, and a grant nobody confirmed contributes zero
663
+ // tokens and refuses the run.
664
+ const verifiedApprovals: string[] = [];
665
+ for (let i = 0; i < argv.length; i += 1) {
666
+ if (argv[i] !== '--approved') continue;
667
+ const id = argv[i + 1];
668
+ if (id === undefined || id.startsWith('--')) {
669
+ process.stderr.write('❌ preamble-payload budget: --approved needs an exception id.\n');
670
+ return 2;
671
+ }
672
+ verifiedApprovals.push(id);
673
+ }
674
+
675
+ // `--repo-root <path>`: measure THIS tree, rather than the one this script
676
+ // happens to sit in. Prerequisite 3 of the measured-ceiling verdict — CI
677
+ // runs the gate as it exists at the BASE ref against the HEAD tree, so a
678
+ // pull request cannot edit the code that measures it. Both seats chose this
679
+ // over code-owner review on the gate, which would put the sole maintainer
680
+ // in the path of every gate-editing pull request. Its honest limit,
681
+ // anthropic's words: "the mechanism does not prevent the exploit; it makes
682
+ // the exploit auditable" — a weakening merged first and exploited second is
683
+ // visible in `git log` and is not blocked.
684
+ const ri = argv.indexOf('--repo-root');
685
+ const repoRootArg = ri !== -1 ? argv[ri + 1] : undefined;
686
+ if (ri !== -1 && (repoRootArg === undefined || repoRootArg.startsWith('--'))) {
687
+ process.stderr.write('❌ preamble-payload budget: --repo-root needs a path.\n');
688
+ return 2;
689
+ }
690
+ const repoRoot = repoRootArg === undefined ? REPO_ROOT : path.resolve(repoRootArg);
691
+ if (!fs.existsSync(budgetFileIn(repoRoot))) {
692
+ process.stderr.write(
693
+ `❌ preamble-payload budget: ${repoRoot} carries no ${'src/config/preamble-payload-budget.json'} — ` +
694
+ 'that is not a tree this gate can measure.\n',
695
+ );
696
+ return 2;
697
+ }
698
+
699
+ // `--host <id>` / `--project-rules-dir <path>`: the additive host reading
700
+ // (AI council 2026-09-09, option 1A). Mutually exclusive on purpose — a call
701
+ // passing both is asking two different questions and would silently get one
702
+ // answer, so it is a usage error rather than a precedence rule nobody reads.
703
+ const hi = argv.indexOf('--host');
704
+ const hostArg = hi !== -1 ? argv[hi + 1] : undefined;
705
+ const pi = argv.indexOf('--project-rules-dir');
706
+ const rulesDirArg = pi !== -1 ? argv[pi + 1] : undefined;
707
+ if (hostArg !== undefined && rulesDirArg !== undefined) {
708
+ process.stderr.write(
709
+ '❌ preamble-payload budget: --host and --project-rules-dir are mutually exclusive. ' +
710
+ 'Pass a host id to measure a declared projection, or a path to measure an ' +
711
+ 'undeclared tree — never both.\n',
712
+ );
713
+ return 2;
714
+ }
715
+ if (hi !== -1 && (hostArg === undefined || hostArg.startsWith('--'))) {
716
+ process.stderr.write(
717
+ `❌ preamble-payload budget: --host needs an id — one of ${hostPayloadIds().join(', ')}.\n`,
718
+ );
719
+ return 2;
720
+ }
721
+ if (pi !== -1 && (rulesDirArg === undefined || rulesDirArg.startsWith('--'))) {
722
+ process.stderr.write('❌ preamble-payload budget: --project-rules-dir needs a path.\n');
723
+ return 2;
724
+ }
725
+ let host: HostPayload | null = null;
726
+ if (hostArg !== undefined || rulesDirArg !== undefined) {
727
+ try {
728
+ host = measureHostPayload(
729
+ repoRoot,
730
+ hostArg !== undefined
731
+ ? { host: hostArg }
732
+ : { rulesDirOverride: rulesDirArg as string },
733
+ );
734
+ } catch (err) {
735
+ process.stderr.write(`❌ preamble-payload budget: ${(err as Error).message}\n`);
736
+ return 2;
737
+ }
738
+ }
739
+
311
740
  let decision: Decision;
312
741
  try {
313
- decision = decide(override === undefined ? {} : { overrideCeiling: override });
742
+ decision = decide({ repoRoot, requireBase, verifiedApprovals });
314
743
  } catch (err) {
315
744
  process.stderr.write(`❌ preamble-payload budget: ${(err as Error).message}\n`);
316
745
  return 2;
@@ -341,11 +770,42 @@ export function main(argv: string[] = process.argv.slice(2)): number {
341
770
  JSON.stringify(
342
771
  {
343
772
  ...verdict,
773
+ // `source_corpus` and `host_payload` are structurally
774
+ // separate, and both seats of the 2026-09-09 council asked
775
+ // for exactly that: until the two are named apart, every
776
+ // ceiling discussion risks comparing unlike quantities. The
777
+ // legacy top-level fields stay so no existing reader breaks.
778
+ measurement_scope: host === null ? 'source-corpus' : 'source-corpus+host-payload',
779
+ source_corpus: {
780
+ measured: verdict.measured,
781
+ baseline: verdict.baseline,
782
+ ceiling: verdict.ceiling,
783
+ buckets: verdict.buckets,
784
+ },
785
+ host_payload: host,
344
786
  ok: decision.ok,
787
+ measured_ceiling: {
788
+ ceiling: decision.ceiling.ceiling,
789
+ design_ceiling: decision.ceiling.designCeiling,
790
+ base_payload: decision.ceiling.basePayload,
791
+ effective_base: decision.ceiling.effectiveBase,
792
+ active_grants: decision.ceiling.activeGrants,
793
+ active_exception_ids: decision.ceiling.activeIds,
794
+ verified: decision.ceiling.verified,
795
+ ok: decision.ceiling.ok,
796
+ note: decision.ceiling.note,
797
+ violations: decision.ceiling.violations,
798
+ },
799
+ catalogue_completeness: {
800
+ ok: decision.catalogue.findings.length === 0,
801
+ trees_seen: decision.catalogue.treesSeen,
802
+ files_scanned: decision.catalogue.filesScanned,
803
+ findings: decision.catalogue.findings,
804
+ },
345
805
  bound_ratchet: {
346
806
  ok: decision.bounds.ok,
347
807
  base_ref: decision.bounds.baseRef,
348
- base_grace_ceiling: decision.bounds.baseGraceCeiling,
808
+ base_bounds: decision.bounds.baseBounds,
349
809
  note: decision.bounds.note,
350
810
  violations: decision.bounds.violations,
351
811
  },
@@ -366,20 +826,92 @@ export function main(argv: string[] = process.argv.slice(2)): number {
366
826
  ` ${'measured total'.padEnd(38)} ${String(verdict.measured).padStart(8)} tok ` +
367
827
  `(baseline ${verdict.baseline}, ${sign}${delta}; ceiling ${verdict.ceiling})\n`,
368
828
  );
829
+ process.stdout.write(renderCeiling(decision.ceiling));
369
830
  process.stdout.write(renderBounds(decision.bounds));
831
+ process.stdout.write(
832
+ ` ${'catalogue completeness'.padEnd(38)} ` +
833
+ `${(decision.catalogue.findings.length === 0 ? 'ok' : 'GAPS').padStart(8)} — ` +
834
+ `${String(decision.catalogue.treesSeen)} projected tree(s), ` +
835
+ `${String(decision.catalogue.filesScanned)} file(s) scanned for stray rule payload\n`,
836
+ );
837
+
838
+ // The host reading prints AFTER the source verdict and never touches the
839
+ // exit code below. The label says which surface each number describes,
840
+ // because the whole defect this reading fixes was two different quantities
841
+ // sharing one name.
842
+ if (host !== null) {
843
+ const label = host.host === null ? host.rules_path : host.host;
844
+ process.stdout.write(`\n host payload — ${label} (informational, not gated)\n`);
845
+ for (const b of host.buckets) {
846
+ process.stdout.write(` ${('· ' + b.name).padEnd(38)} ${String(b.tokens).padStart(8)} tok\n`);
847
+ }
848
+ process.stdout.write(` ${'· host total'.padEnd(38)} ${String(host.total).padStart(8)} tok\n`);
849
+ const c = host.completeness;
850
+ if (!c.complete) {
851
+ process.stdout.write(
852
+ ` ${'· PARTIAL TREE'.padEnd(38)} ${c.host_rule_files} rule file(s) vs ` +
853
+ `${c.source_rule_files} in the source.\n` +
854
+ ' This total is NOT a consumer reading. A maintainer checkout deduplicates a\n' +
855
+ ' project rule against the same rule at user scope, and a dev tree may hold a\n' +
856
+ ' partial projection — both shrink this number for reasons unrelated to the\n' +
857
+ ' projection mode. Measure a clean consumer-shaped root with\n' +
858
+ ' --project-rules-dir <path> to get the number a consumer would load.\n',
859
+ );
860
+ }
861
+ }
862
+
863
+ // THE CEILING IS ESTABLISHED BEFORE THE SIZE QUESTION. A run that could not
864
+ // measure its own ceiling has no business reporting a tree as within one,
865
+ // and an expired grant is a refusal whatever the payload does.
866
+ if (!decision.ceiling.ok) {
867
+ process.stderr.write(
868
+ (decision.ceiling.verified
869
+ ? '❌ the standing-payload exception ledger refuses this run:\n'
870
+ : '❌ the standing-payload ceiling could not be MEASURED, and this run requires it:\n') +
871
+ decision.ceiling.violations.map((v) => ` · ${v}\n`).join(''),
872
+ );
873
+ return 1;
874
+ }
875
+
876
+ // Payload the census cannot see is payload no ceiling bounds. Refused
877
+ // BEFORE the size comparison for the same reason: a green "within budget"
878
+ // over an incomplete catalogue is a measurement of the wrong set.
879
+ if (decision.catalogue.findings.length > 0) {
880
+ process.stderr.write(
881
+ '❌ standing payload sits outside every measured bucket:\n' +
882
+ decision.catalogue.findings.map((v) => ` · ${v}\n`).join(''),
883
+ );
884
+ return 1;
885
+ }
370
886
 
371
887
  // The bound is checked BEFORE the size question and independently of it. A
372
888
  // change that lifts its own ceiling has already defeated the gate, and
373
889
  // reporting that as "within budget" would be the config-weakening move
374
890
  // wearing a green checkmark.
375
891
  if (!decision.bounds.ok) {
892
+ // Two refusals, two different fixes. `verified: false` means the bound
893
+ // could not be READ under `--require-base`; the header must not send the
894
+ // reader to lower a ceiling that never moved.
376
895
  process.stderr.write(
377
- '❌ the standing-payload ceiling rose in this change:\n' +
896
+ boundsRefusalHeader(decision.bounds) +
378
897
  decision.bounds.violations.map((v) => ` · ${v}\n`).join(''),
379
898
  );
380
899
  return 1;
381
900
  }
382
901
 
902
+ // An advisory run that never established a ceiling reports the number and
903
+ // stops. Saying "over budget" against a bound nobody read would send the
904
+ // reader to shrink a rule over a fetch problem — the same misdiagnosis the
905
+ // `--require-base` refusal is worded to prevent, one layer up.
906
+ if (!decision.ceiling.verified) {
907
+ process.stdout.write(
908
+ '⚠️ size comparison SKIPPED — the ceiling was not established in this run, so there is\n' +
909
+ ' nothing to compare the measurement against. This is NOT a pass on the payload: pass\n' +
910
+ ' --require-base (as CI does) to make an unestablished ceiling a refusal instead.\n',
911
+ );
912
+ return 0;
913
+ }
914
+
383
915
  if (!verdict.withinBudget) {
384
916
  // road-to-delivered-cost-truth 2.2 — a gate names its own "no". The
385
917
  // ceiling message alone states a fact and leaves the reader to find the
@@ -392,13 +924,46 @@ export function main(argv: string[] = process.argv.slice(2)): number {
392
924
  // build or a first commit legitimately has none. A gate that failed to
393
925
  // refuse because it could not explain itself would be strictly worse
394
926
  // than one that refuses without the explanation.
395
- const attribution = attributeGrowthAgainstBase();
927
+ const attribution = attributeGrowthAgainstBase(repoRoot, decision.bounds.baseRef);
928
+
929
+ // REJECTION INSTRUMENTATION — prerequisite 4a's converged floor.
930
+ //
931
+ // Both council seats refused to derive an exception cap from the 250-PR
932
+ // delta distribution, for one reason: the sample is CENSORED by the very
933
+ // ratchet a cap would relax, so every percentile describes what got
934
+ // through rather than what was attempted. The thing that uncensors it is
935
+ // recording the deltas that were BLOCKED, which nothing did.
936
+ //
937
+ // This line is that record, and its limits are worth stating rather than
938
+ // implying: it is a log line in a CI job, not a database. It captures
939
+ // attempts that reached this gate and failed; it cannot see a change
940
+ // nobody pushed. It is deliberately machine-greppable from a workflow
941
+ // log so the distribution can be rebuilt later without a schema anybody
942
+ // has to maintain today.
943
+ process.stdout.write(
944
+ 'payload-rejection: ' +
945
+ JSON.stringify({
946
+ measured: verdict.measured,
947
+ ceiling: verdict.ceiling,
948
+ attempted_delta: decision.ceiling.effectiveBase === null
949
+ ? null
950
+ : verdict.measured - decision.ceiling.effectiveBase,
951
+ design_ceiling: decision.ceiling.designCeiling,
952
+ base_payload: decision.ceiling.basePayload,
953
+ base_ref: decision.bounds.baseRef,
954
+ active_grants: decision.ceiling.activeGrants,
955
+ buckets: verdict.buckets.map((b) => ({ name: b.name, tokens: b.tokens })),
956
+ }) +
957
+ '\n',
958
+ );
959
+
396
960
  process.stderr.write(
397
961
  `❌ per-spawn preamble payload grew past the ratchet: ${verdict.measured} > ${verdict.ceiling} tok.\n` +
398
962
  ` Every rule and skill description here is re-written on EVERY subagent spawn, so growth\n` +
399
963
  ` is paid per spawn, not once. Shrink the addition, or migrate the prose out of the\n` +
400
- ` standing rule. The grace ceiling may NOT be raised to fit it: ADR-264, enforced by\n` +
401
- ` the shrink-only ratchet above.\n`,
964
+ ` standing rule. The ceiling may NOT be widened to fit it — it is MEASURED at the base\n` +
965
+ ` ref, so there is no number to edit. A change whose offsetting reduction is genuinely\n` +
966
+ ` unsafe takes an approved, dated grant in ${EXCEPTIONS_CONFIG_PATH}.\n`,
402
967
  );
403
968
  // Three distinct states, and conflating the last two is a diagnostic
404
969
  // defect rather than a cosmetic one: "I could not look" and "I looked