@oneie/claude 0.7.0 → 0.9.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 (263) hide show
  1. package/agents/abm-strategist.md +89 -0
  2. package/agents/ads-meta.md +97 -0
  3. package/agents/analyst.md +173 -0
  4. package/agents/architect.md +280 -0
  5. package/agents/brand-guardian.md +88 -0
  6. package/agents/brand-strategist.md +92 -0
  7. package/agents/campaign-content.md +90 -0
  8. package/agents/campaign-email.md +88 -0
  9. package/agents/campaign-sms.md +87 -0
  10. package/agents/campaign-social.md +87 -0
  11. package/agents/cco.md +99 -0
  12. package/agents/ceo.md +106 -0
  13. package/agents/chairman.md +120 -0
  14. package/agents/cmo.md +101 -0
  15. package/agents/community-greeter.md +89 -0
  16. package/agents/community-moderator.md +92 -0
  17. package/agents/compliance.md +92 -0
  18. package/agents/copywriter.md +100 -0
  19. package/agents/creative-strategist.md +95 -0
  20. package/agents/cro.md +98 -0
  21. package/agents/cto.md +267 -0
  22. package/agents/customer-interviewer.md +93 -0
  23. package/agents/customer-researcher.md +89 -0
  24. package/agents/customer-success-manager.md +90 -0
  25. package/agents/customer-trainer.md +90 -0
  26. package/agents/cxo.md +100 -0
  27. package/agents/demand-creator.md +89 -0
  28. package/agents/demo-mover.md +83 -0
  29. package/agents/demo-specialist.md +89 -0
  30. package/agents/demo-thai-family-law.md +87 -0
  31. package/agents/designer.md +112 -0
  32. package/agents/discovery-caller.md +98 -0
  33. package/agents/doctor.md +139 -0
  34. package/agents/educate-coach.md +100 -0
  35. package/agents/elevate-tutor.md +83 -0
  36. package/agents/email-lifecycle-marketer.md +91 -0
  37. package/agents/engage-specialist.md +99 -0
  38. package/agents/events-coordinator.md +90 -0
  39. package/agents/foundation-builder.md +94 -0
  40. package/agents/funnel-architect.md +89 -0
  41. package/agents/gift-creator.md +100 -0
  42. package/agents/google-ads.md +103 -0
  43. package/agents/guide.md +292 -0
  44. package/agents/helpdesk-dispatcher.md +88 -0
  45. package/agents/hook-specialist.md +91 -0
  46. package/agents/identify-optimizer.md +101 -0
  47. package/agents/implementer.md +305 -0
  48. package/agents/incident-commander.md +120 -0
  49. package/agents/insights-lead.md +93 -0
  50. package/agents/journey-runner.md +113 -0
  51. package/agents/linkedin-ads.md +123 -0
  52. package/agents/live-sales-chat.md +90 -0
  53. package/agents/market-researcher.md +88 -0
  54. package/agents/media-buyer.md +96 -0
  55. package/agents/movers-customer-researcher.md +95 -0
  56. package/agents/movers-foundation-builder.md +96 -0
  57. package/agents/movers-market-researcher.md +97 -0
  58. package/agents/movers-pricing-strategist.md +171 -0
  59. package/agents/nurture-architect.md +99 -0
  60. package/agents/offer-architect.md +92 -0
  61. package/agents/onboarder.md +222 -0
  62. package/agents/onboarding-specialist.md +92 -0
  63. package/agents/operations-dashboard.md +98 -0
  64. package/agents/perf-engineer.md +348 -0
  65. package/agents/playbook-writer.md +71 -0
  66. package/agents/plg-strategist.md +91 -0
  67. package/agents/positioning-architect.md +88 -0
  68. package/agents/press-officer.md +89 -0
  69. package/agents/pricing-strategist.md +94 -0
  70. package/agents/privacy-officer.md +92 -0
  71. package/agents/referral-manager.md +91 -0
  72. package/agents/refine-analyst.md +102 -0
  73. package/agents/release-manager.md +261 -0
  74. package/agents/renewals-upsell-rep.md +90 -0
  75. package/agents/review-engineer.md +327 -0
  76. package/agents/rewards-steward.md +82 -0
  77. package/agents/sales-call-coach.md +94 -0
  78. package/agents/sales-closer.md +98 -0
  79. package/agents/security-auditor.md +313 -0
  80. package/agents/sell-closer.md +101 -0
  81. package/agents/share-amplifier.md +99 -0
  82. package/agents/social-media-manager.md +92 -0
  83. package/agents/storyteller.md +250 -0
  84. package/agents/strategist.md +83 -0
  85. package/agents/strategy-aligner.md +94 -0
  86. package/agents/support-agent.md +90 -0
  87. package/agents/tagger.md +245 -0
  88. package/agents/tech-writer.md +216 -0
  89. package/agents/test-engineer.md +243 -0
  90. package/agents/tiktok-ads.md +105 -0
  91. package/agents/tracking-engineer.md +92 -0
  92. package/agents/upsell-strategist.md +101 -0
  93. package/agents/voice.md +85 -0
  94. package/agents/w4-tools.md +153 -0
  95. package/agents/w4-verify.md +20 -138
  96. package/agents/workflow-optimiser.md +84 -0
  97. package/commands/close.md +814 -160
  98. package/commands/create.md +2 -2
  99. package/commands/deploy.md +554 -175
  100. package/commands/do.md +119 -109
  101. package/commands/fast.md +67 -0
  102. package/commands/improve.md +2 -2
  103. package/commands/one.md +418 -0
  104. package/commands/see.md +1 -1
  105. package/commands/sync.md +1 -1
  106. package/commands/tasks.md +222 -0
  107. package/commands/vespio.md +110 -0
  108. package/commands/vespio.remote.md +227 -0
  109. package/hooks/hooks.json +25 -79
  110. package/hooks/lib/governor-escape-match.sh +88 -0
  111. package/hooks/lib/hook.sh +4 -13
  112. package/hooks/lib/signal.sh +9 -2
  113. package/hooks/scripts/branch-pin.sh +6 -0
  114. package/hooks/scripts/config-protect.sh +6 -0
  115. package/hooks/scripts/do-outcome-gate.sh +19 -2
  116. package/hooks/scripts/git-add-guard.sh +43 -2
  117. package/hooks/scripts/governor-escape.sh +96 -0
  118. package/hooks/scripts/load-guard.sh +127 -0
  119. package/hooks/scripts/post-edit-check.sh +36 -29
  120. package/hooks/scripts/session-start.sh +34 -80
  121. package/hooks/scripts/task-complete-verify.sh +46 -40
  122. package/package.json +1 -1
  123. package/rules/documentation.md +9 -0
  124. package/scripts/ad-copy-lint.sh +656 -0
  125. package/scripts/agentverse-audit.sh +256 -0
  126. package/scripts/asi-walk.sh +435 -0
  127. package/scripts/astro-build-cached.sh +143 -0
  128. package/scripts/blocks-manifest-cached.sh +100 -0
  129. package/scripts/blocks-manifest.mjs +497 -0
  130. package/scripts/blocks-ratchet.sh +116 -0
  131. package/scripts/blocks-render-probe.mjs +529 -0
  132. package/scripts/blocks-usage.mjs +334 -0
  133. package/scripts/chat-context-check.sh +89 -0
  134. package/scripts/close-metrics.sh +558 -0
  135. package/scripts/close-owner.sh +268 -0
  136. package/scripts/db-sync-lock-check.sh +116 -0
  137. package/scripts/deploy-dev.sh +35 -0
  138. package/scripts/deploy-emit.sh +298 -0
  139. package/scripts/deploy-gate-check.sh +128 -0
  140. package/scripts/deploy-ready.sh +78 -0
  141. package/scripts/deploy-record.sh +605 -0
  142. package/scripts/deploy.sh +1273 -0
  143. package/scripts/do-auto.sh +598 -48
  144. package/scripts/do-brief.sh +113 -0
  145. package/scripts/do-close.sh +1137 -0
  146. package/scripts/do-commit.sh +75 -0
  147. package/scripts/do-consumer-sweep.sh +18 -1
  148. package/scripts/do-cycle-shape-check.sh +160 -0
  149. package/scripts/do-decide.sh +476 -0
  150. package/scripts/do-derive-check.sh +436 -0
  151. package/scripts/do-fleet.sh +106 -28
  152. package/scripts/do-folder.sh +10 -1
  153. package/scripts/do-next.sh +106 -0
  154. package/scripts/do-orchestrate.sh +17 -5
  155. package/scripts/do-plan-json.mjs +201 -0
  156. package/scripts/do-plan-json.sh +8 -0
  157. package/scripts/do-preflight.sh +117 -0
  158. package/scripts/do-project.sh +157 -0
  159. package/scripts/do-prove-selftest.sh +108 -0
  160. package/scripts/do-prove.sh +295 -23
  161. package/scripts/do-rank.py +31 -1
  162. package/scripts/do-recon-cache.sh +7 -1
  163. package/scripts/do-recon-pack.sh +196 -0
  164. package/scripts/do-reconcile.sh +121 -4
  165. package/scripts/do-signal.sh +280 -23
  166. package/scripts/do-smoke.sh +18 -1
  167. package/scripts/do-test-gate.sh +80 -0
  168. package/scripts/do-tick.sh +102 -0
  169. package/scripts/do-tier.sh +6 -0
  170. package/scripts/do-triage.sh +182 -0
  171. package/scripts/do-ui-gate.sh +1 -1
  172. package/scripts/do-w4-gates.sh +451 -0
  173. package/scripts/do-walk.sh +12 -1
  174. package/scripts/env-sync.sh +173 -0
  175. package/scripts/factory-brief-check.sh +330 -0
  176. package/scripts/factory-check.sh +68 -14
  177. package/scripts/factory-close-check.sh +257 -0
  178. package/scripts/factory-emit.sh +211 -0
  179. package/scripts/factory-executor-check.mjs +353 -0
  180. package/scripts/factory-peak.sh +301 -0
  181. package/scripts/factory-repo.sh +118 -3
  182. package/scripts/factory-review-check.mjs +61 -0
  183. package/scripts/factory-ship.sh +61 -0
  184. package/scripts/factory-tasks-check.sh +18 -1
  185. package/scripts/factory-turn.sh +326 -0
  186. package/scripts/factory-walk.sh +396 -0
  187. package/scripts/factory-width.sh +57 -0
  188. package/scripts/fade-toxic.sh +4 -3
  189. package/scripts/fixtures/factory-brief-real.md +44 -0
  190. package/scripts/fixtures/triage-dupe.md +5 -0
  191. package/scripts/fleet-manifest.mjs +108 -0
  192. package/scripts/fleet-status.sh +110 -0
  193. package/scripts/full-suite-paths-check.sh +144 -0
  194. package/scripts/gate-reaper-check.sh +98 -0
  195. package/scripts/gate-reaper.sh +125 -0
  196. package/scripts/gate-run.sh +73 -0
  197. package/scripts/gc-content-check.sh +140 -0
  198. package/scripts/gen-dev-config.py +20 -0
  199. package/scripts/govern-bound-check.sh +60 -0
  200. package/scripts/govern-claims-check.sh +233 -0
  201. package/scripts/govern-mem-check.sh +290 -0
  202. package/scripts/governor-doors-check.sh +362 -0
  203. package/scripts/governor-escape-check.sh +171 -0
  204. package/scripts/health.sh +413 -0
  205. package/scripts/id-inventory.mjs +418 -0
  206. package/scripts/land.sh +551 -0
  207. package/scripts/lib/gc-finished.sh +77 -0
  208. package/scripts/lib/govern.sh +361 -0
  209. package/scripts/lib/govern.ts +756 -0
  210. package/scripts/lighthouse-run.sh +187 -0
  211. package/scripts/livekit-live-check.sh +61 -0
  212. package/scripts/livekit-ratchet.sh +46 -0
  213. package/scripts/load-guard-check.sh +49 -0
  214. package/scripts/machine-check.sh +102 -0
  215. package/scripts/machine-watch.sh +177 -0
  216. package/scripts/one-agents.mjs +415 -0
  217. package/scripts/one-resume.sh +78 -0
  218. package/scripts/orphan-baseline.json +182 -0
  219. package/scripts/orphan-modules.mjs +179 -0
  220. package/scripts/pr-body.sh +335 -0
  221. package/scripts/preview-fd-check.sh +289 -0
  222. package/scripts/promise-manifest.mjs +24 -1
  223. package/scripts/release.sh +322 -0
  224. package/scripts/roles-check.sh +946 -0
  225. package/scripts/sdk-build-cached.sh +64 -0
  226. package/scripts/signal-watch.sh +241 -0
  227. package/scripts/skills-publish.sh +94 -0
  228. package/scripts/speed-cache-check.sh +173 -0
  229. package/scripts/speed-check.mjs +907 -0
  230. package/scripts/speed-parity-check.sh +648 -0
  231. package/scripts/speed-waterfall-check.sh +355 -0
  232. package/scripts/substrate-env-parity.mjs +156 -0
  233. package/scripts/tasks-claim-race.mjs +108 -0
  234. package/scripts/tasks-loop.sh +185 -0
  235. package/scripts/test-cached.sh +255 -0
  236. package/scripts/test-full.sh +87 -0
  237. package/scripts/test-honesty.mjs +137 -0
  238. package/scripts/test-lanes.sh +166 -0
  239. package/scripts/test-speed.sh +94 -0
  240. package/scripts/triage-shape-check.sh +149 -0
  241. package/scripts/tsc-cached.sh +179 -0
  242. package/scripts/typedb-flake-check.sh +197 -0
  243. package/scripts/urls-lint.sh +15 -0
  244. package/scripts/verify-fast.sh +445 -0
  245. package/scripts/vespio-sync.sh +149 -0
  246. package/scripts/wf-check.mjs +104 -1
  247. package/scripts/worktree-preview.sh +879 -0
  248. package/scripts/worktree-up.sh +208 -0
  249. package/skills/livekit-agents/SKILL.md +285 -0
  250. package/skills/livekit-agents/references/freshness-rules.md +168 -0
  251. package/skills/shadcn/SKILL.md +1 -1
  252. package/skills/signal/SKILL.md +0 -1
  253. package/skills/voice/SKILL.md +94 -6
  254. package/skills/voice/corpus-check.sh +87 -0
  255. package/hooks/scripts/compact-hint.sh +0 -35
  256. package/hooks/scripts/gate-guard.sh +0 -83
  257. package/hooks/scripts/read-tracker.sh +0 -26
  258. package/hooks/scripts/session-end-verify.sh +0 -51
  259. package/hooks/scripts/stop-reflect.sh +0 -140
  260. package/hooks/scripts/sync-priority-todo.sh +0 -57
  261. package/hooks/scripts/sync-todo-docs.sh +0 -46
  262. package/hooks/scripts/tool-signal.sh +0 -48
  263. package/scripts/do-tasks-bridge.py +0 -366
@@ -0,0 +1,290 @@
1
+ #!/usr/bin/env bash
2
+ # govern-mem-check.sh — prove the machine governor's memory probe can say NO.
3
+ #
4
+ # bash .claude/scripts/govern-mem-check.sh # all checks
5
+ # bash .claude/scripts/govern-mem-check.sh --self-test # same, explicit
6
+ # bash .claude/scripts/govern-mem-check.sh --live # just read this box
7
+ #
8
+ # WHY THIS EXISTS
9
+ # gate_headroom used to compute availability as
10
+ # hw.memsize * (memory_pressure "free percentage") / 100
11
+ # and that percentage counts reclaimable memory — file cache, purgeable, and
12
+ # already-compressed pages — as free. It is a PRESSURE signal, not a quantity.
13
+ # Measured three times on one 24GB box, all while ~1% of RAM was actually free
14
+ # and 9-12 GB sat in swap, the old probe answered "room for 2 / 7 / 7 more
15
+ # 2GB cycles". A governor that cannot say no is not a governor.
16
+ #
17
+ # Every check below drives a SYNTHETIC machine state — a fake vm_stat, a fake
18
+ # memory_pressure block and a fake vm.swapusage line, together, so the old
19
+ # formula and the new one see the SAME input and the comparison is honest.
20
+ # Stubbing is done by overriding _gv_vm_stat / _gv_swapusage / _gv_memsize,
21
+ # the same idiom govern-claims-check.sh uses to stub _gv_alive.
22
+ #
23
+ # Nothing here touches the real machine, the real $GOVERN_DIR, or any gate.
24
+ set -uo pipefail
25
+
26
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
27
+ cd "$ROOT" || exit 1
28
+
29
+ # Sandbox: never touch the machine-wide governor dir.
30
+ export GOVERN_DIR="${TMPDIR:-/tmp}/one-govern-memcheck.$$"
31
+ mkdir -p "$GOVERN_DIR"
32
+ trap 'rm -rf "$GOVERN_DIR"' EXIT
33
+
34
+ # shellcheck source=lib/govern.sh
35
+ . "$ROOT/.claude/scripts/lib/govern.sh"
36
+
37
+ PASS=0; FAIL=0
38
+ ok() { PASS=$((PASS+1)); printf ' \033[32mPASS\033[0m %s\n' "$*"; }
39
+ bad() { FAIL=$((FAIL+1)); printf ' \033[31mFAIL\033[0m %s\n' "$*"; }
40
+ hdr() { printf '\n\033[1m%s\033[0m\n' "$*"; }
41
+
42
+ # ── the pre-fix arithmetic, VERBATIM ────────────────────────────────────────
43
+ # Copied unchanged from lib/govern.sh before 2026-09-03 (the `deploy-gate-check.sh`
44
+ # idiom: carry the old code so the red proof is a real comparison, not a story).
45
+ _old_gate_headroom() {
46
+ local total_gb free_pct avail_gb usable_gb per_cycle reserve slots
47
+ total_gb=$(( $(_gv_memsize 2>/dev/null || echo 0) / 1073741824 ))
48
+ [ "$total_gb" -lt 1 ] && { echo 99; return 0; }
49
+ free_pct=$(_gv_memory_pressure 2>/dev/null | awk -F': ' '/free percentage/{gsub(/%/,"",$2); print int($2)}')
50
+ [ -z "$free_pct" ] && { echo 99; return 0; }
51
+ per_cycle="${GOVERN_GB_PER_CYCLE:-2}"
52
+ reserve="${GOVERN_RESERVE_GB:-2}"
53
+ avail_gb=$(( total_gb * free_pct / 100 ))
54
+ usable_gb=$(( avail_gb - reserve ))
55
+ [ "$usable_gb" -lt 0 ] && usable_gb=0
56
+ slots=$(( usable_gb / per_cycle ))
57
+ [ "$slots" -lt 1 ] && slots=1
58
+ echo "$slots"
59
+ }
60
+ _old_gate_pressure() {
61
+ local free_pct
62
+ free_pct=$(_gv_memory_pressure 2>/dev/null | awk -F': ' '/free percentage/{gsub(/%/,"",$2); print $2}')
63
+ [ -z "$free_pct" ] && return 0
64
+ [ "$free_pct" -lt "${GOVERN_MIN_FREE_PCT:-12}" ] && return 1
65
+ return 0
66
+ }
67
+
68
+ # ── synthetic machine states ────────────────────────────────────────────────
69
+ # All on a 24 GB / 16384-byte-page box, so hw.memsize is constant and only the
70
+ # page counts move. FIX_* are set by fixture(); the stubs read them.
71
+ FIX_FREE=0; FIX_PURGE=0; FIX_INACT=0; FIX_FILEBK=0; FIX_ACTIVE=0; FIX_WIRED=0
72
+ FIX_COMPRESSOR=0; FIX_PCT=0; FIX_SWAP_USED="0.00"; FIX_SWAP_TOTAL="0.00"
73
+ FIX_MODE=normal # normal | empty | garbage | nopagesize
74
+
75
+ _gv_memsize() { [ "$FIX_MODE" = "nomemsize" ] && return 1; echo 25769803776; }
76
+ _gv_swapusage() { echo "total = ${FIX_SWAP_TOTAL}M used = ${FIX_SWAP_USED}M free = 0.00M (encrypted)"; }
77
+ _gv_memory_pressure() {
78
+ cat <<PRESSURE
79
+ Swapins: 1614739
80
+ Swapouts: 2928367
81
+
82
+ Page Q counts:
83
+ Pages active: $FIX_ACTIVE
84
+ Pages inactive: $FIX_INACT
85
+ Pages speculative: 6772
86
+ Pages throttled: 0
87
+ Pages wired down: $FIX_WIRED
88
+
89
+ Compressor Stats:
90
+ Pages used by compressor: $FIX_COMPRESSOR
91
+
92
+ System-wide memory free percentage: ${FIX_PCT}%
93
+ PRESSURE
94
+ }
95
+ _gv_vm_stat() {
96
+ case "$FIX_MODE" in
97
+ empty) return 0 ;;
98
+ garbage) echo "vm_stat: command not found"; return 0 ;;
99
+ nopagesize) echo "Mach Virtual Memory Statistics:" ;;
100
+ *) echo "Mach Virtual Memory Statistics: (page size of 16384 bytes)" ;;
101
+ esac
102
+ cat <<VMSTAT
103
+ Pages free: $FIX_FREE.
104
+ Pages active: $FIX_ACTIVE.
105
+ Pages inactive: $FIX_INACT.
106
+ Pages speculative: 6772.
107
+ Pages throttled: 0.
108
+ Pages wired down: $FIX_WIRED.
109
+ Pages purgeable: $FIX_PURGE.
110
+ File-backed pages: $FIX_FILEBK.
111
+ Anonymous pages: 893951.
112
+ Pages occupied by compressor: $FIX_COMPRESSOR.
113
+ Swapins: 1614739.
114
+ Swapouts: 2928367.
115
+ VMSTAT
116
+ }
117
+
118
+ fixture() {
119
+ FIX_MODE=normal
120
+ case "$1" in
121
+ # ── The live reading taken 2026-09-03 at load 8, verbatim from vm_stat and
122
+ # memory_pressure on the box the operator was complaining about. It
123
+ # reproduces Receipt B: 1.3% of RAM free, 9.4 GB in swap, probe says 7.
124
+ thrash-now)
125
+ FIX_FREE=21032; FIX_PURGE=646; FIX_INACT=547837; FIX_FILEBK=216477
126
+ FIX_ACTIVE=555819; FIX_WIRED=250202; FIX_COMPRESSOR=135982
127
+ FIX_PCT=74; FIX_SWAP_USED="9400.56"; FIX_SWAP_TOTAL="10240.00" ;;
128
+ # ── Receipt A: the verifier's sample at load 27, with hook:load-guard itself
129
+ # reporting the machine saturated. free 15798 pages, compressor 8.7 GB,
130
+ # swap 11997/13312 M, memory_pressure 32%. Old probe answered 2.
131
+ thrash-A)
132
+ FIX_FREE=15798; FIX_PURGE=500; FIX_INACT=137812; FIX_FILEBK=100000
133
+ FIX_ACTIVE=600000; FIX_WIRED=250000; FIX_COMPRESSOR=569254
134
+ FIX_PCT=32; FIX_SWAP_USED="11997.44"; FIX_SWAP_TOTAL="13312.00" ;;
135
+ # ── The row that kills a swap-subtraction design: genuinely idle NOW
136
+ # (8 GB free, 6 GB cache) but macOS has not released the 9.4 GB swapfile
137
+ # it grew an hour ago. A probe that charges for history serialises this.
138
+ recovered-idle)
139
+ FIX_FREE=524288; FIX_PURGE=1000; FIX_INACT=655360; FIX_FILEBK=393216
140
+ FIX_ACTIVE=200000; FIX_WIRED=200000; FIX_COMPRESSOR=50000
141
+ FIX_PCT=85; FIX_SWAP_USED="9400.56"; FIX_SWAP_TOTAL="10240.00" ;;
142
+ # ── Fresh idle: 12 GB free, swap never grown.
143
+ fresh-idle)
144
+ FIX_FREE=786432; FIX_PURGE=500; FIX_INACT=65536; FIX_FILEBK=131072
145
+ FIX_ACTIVE=100000; FIX_WIRED=150000; FIX_COMPRESSOR=20000
146
+ FIX_PCT=90; FIX_SWAP_USED="0.00"; FIX_SWAP_TOTAL="0.00" ;;
147
+ # ── Absurd: nothing available at all. Must floor to 1, never 0 —
148
+ # do-fleet.sh clamps its slot count to this with no floor of its own.
149
+ starved)
150
+ FIX_FREE=0; FIX_PURGE=0; FIX_INACT=0; FIX_FILEBK=0
151
+ FIX_ACTIVE=1000000; FIX_WIRED=500000; FIX_COMPRESSOR=72864
152
+ FIX_PCT=1; FIX_SWAP_USED="16000.00"; FIX_SWAP_TOTAL="16384.00" ;;
153
+ *) echo "unknown fixture $1" >&2; exit 2 ;;
154
+ esac
155
+ }
156
+
157
+ # The environment the checks are scored in: the box's real settings.json values
158
+ # minus the stale GOVERN_GB_PER_CYCLE pin, so the derived price is live.
159
+ unset GOVERN_GB_PER_CYCLE
160
+ export GOVERN_RESERVE_GB=3
161
+ export VITEST_MAX_FORKS=4 # what a Claude Code session actually sets
162
+
163
+ [ "${1:-}" = "--live" ] && { echo "live: $(gate_mem_report)"; exit 0; }
164
+
165
+ # ═══════════════════════════════════════════════════════════════════════════
166
+ hdr "1. THRASH — the new probe says no, and the OLD one says yes (red proof)"
167
+ for st in thrash-now thrash-A; do
168
+ fixture "$st"
169
+ new=$(gate_headroom); old=$(_old_gate_headroom)
170
+ avail=$(gate_mem_avail_mb)
171
+ oldpct=$FIX_PCT
172
+ if _old_gate_pressure; then oldp="0 (has headroom)"; else oldp="1 (thrashing)"; fi
173
+ if gate_pressure; then newp="0 (has headroom)"; else newp="1 (thrashing)"; fi
174
+ echo " [$st] memory_pressure says ${oldpct}% free · vm_stat says $((FIX_FREE*16384/1048576))MB free · swap ${FIX_SWAP_USED}M used"
175
+ echo " OLD: headroom=$old pressure=$oldp NEW: avail=${avail}MB headroom=$new pressure=$newp"
176
+ [ "$new" -eq 1 ] && ok "$st: new cap FELL to 1" || bad "$st: new cap is $new, expected 1"
177
+ [ "$old" -gt 1 ] && ok "$st: OLD arithmetic authorised $old cycles on this same state (red proof)" \
178
+ || bad "$st: OLD arithmetic did not over-authorise — red proof is inert"
179
+ _old_gate_pressure && ok "$st: OLD gate_pressure called it healthy (red proof)" \
180
+ || bad "$st: OLD gate_pressure already fired — red proof is inert"
181
+ gate_pressure && bad "$st: NEW gate_pressure still calls it healthy" \
182
+ || ok "$st: NEW gate_pressure fires"
183
+ done
184
+
185
+ hdr "2. HEALTHY — not replaced by a serialising bug"
186
+ for st in recovered-idle fresh-idle; do
187
+ fixture "$st"
188
+ new=$(gate_headroom); avail=$(gate_mem_avail_mb)
189
+ echo " [$st] avail=${avail}MB swap ${FIX_SWAP_USED}M used -> headroom=$new"
190
+ [ "$new" -ge 2 ] && ok "$st: healthy box still funds $new cycles (>=2)" \
191
+ || bad "$st: healthy box collapsed to $new — this is the serialising bug"
192
+ gate_pressure && ok "$st: gate_pressure stays quiet" || bad "$st: gate_pressure fired on a healthy box"
193
+ done
194
+ echo " (recovered-idle is the row that refutes any design subtracting vm.swapusage:"
195
+ echo " 9.4GB of stale swap would drive it to 1 while 8GB of RAM sits free.)"
196
+
197
+ hdr "3. BROKEN SENSOR — 99, never 0, never 1"
198
+ for mode in empty garbage nopagesize; do
199
+ fixture thrash-now; FIX_MODE="$mode"
200
+ h=$(gate_headroom)
201
+ [ "$h" = "99" ] && ok "vm_stat '$mode' -> headroom=99 (do not constrain)" \
202
+ || bad "vm_stat '$mode' -> headroom=$h, expected 99"
203
+ gate_pressure && ok "vm_stat '$mode' -> gate_pressure does not block" \
204
+ || bad "vm_stat '$mode' -> gate_pressure blocked on a broken probe"
205
+ done
206
+
207
+ hdr "4. FLOOR — a starved box slows down, it never stops"
208
+ fixture starved
209
+ h=$(gate_headroom); a=$(gate_mem_avail_mb)
210
+ echo " avail=${a}MB, reserve=$((GOVERN_RESERVE_GB*1024))MB, price=$(gate_price_mb)MB -> headroom=$h"
211
+ [ "$h" = "1" ] && ok "starved box -> 1 (do-fleet.sh clamps to this with no floor of its own; 0 would launch nothing)" \
212
+ || bad "starved box -> $h, expected 1"
213
+
214
+ hdr "5. PRICE — derived from the live fork count, not a stale constant"
215
+ p4=$(VITEST_MAX_FORKS=4 gate_price_mb)
216
+ p8=$(VITEST_MAX_FORKS=8 gate_price_mb)
217
+ pdef=$(unset VITEST_MAX_FORKS; gate_price_mb)
218
+ povr=$(GOVERN_GB_PER_CYCLE=2 gate_price_mb)
219
+ echo " forks=4 -> ${p4}MB · forks=8 -> ${p8}MB · unset -> ${pdef}MB · GOVERN_GB_PER_CYCLE=2 -> ${povr}MB"
220
+ [ "$p8" -gt "$p4" ] && ok "price tracks fork count (8 forks cost more than 4)" || bad "price ignores fork count"
221
+ [ "$p4" -gt 2048 ] && ok "a 4-fork slot is priced above the old flat 2048MB" || bad "4-fork slot still priced at or below the stale constant ($p4)"
222
+ [ "$pdef" = "$p8" ] && ok "unset VITEST_MAX_FORKS prices the config default of 8" || bad "unset != 8-fork price"
223
+ [ "$povr" = "2048" ] && ok "explicit GOVERN_GB_PER_CYCLE still wins (operator override)" || bad "override ignored"
224
+ if grep -q '"GOVERN_GB_PER_CYCLE"' "$ROOT/.claude/settings.json" 2>/dev/null; then
225
+ bad "settings.json still pins GOVERN_GB_PER_CYCLE — the derivation is dead code in every Claude Code session"
226
+ else
227
+ ok "settings.json no longer pins GOVERN_GB_PER_CYCLE"
228
+ fi
229
+
230
+ hdr "6. SELF-RED — gut the probe and the checks above MUST go red"
231
+ # A checker that stays green against a gutted probe proves nothing
232
+ # (govern-claims-check.sh stubs _gv_alive for exactly this reason). Here we
233
+ # put the OLD arithmetic back behind the new name and re-run section 1's
234
+ # assertions: they have to fail.
235
+ _saved_headroom=$(declare -f gate_headroom)
236
+ _saved_pressure=$(declare -f gate_pressure)
237
+ gate_headroom() { _old_gate_headroom; }
238
+ gate_pressure() { _old_gate_pressure; }
239
+ red=0
240
+ for st in thrash-now thrash-A; do
241
+ fixture "$st"
242
+ h=$(gate_headroom)
243
+ [ "$h" -eq 1 ] || red=$((red+1))
244
+ gate_pressure && red=$((red+1))
245
+ done
246
+ if [ "$red" -ge 4 ]; then
247
+ ok "with the old arithmetic restored, all 4 thrash assertions fail ($red/4) — the checks have power"
248
+ else
249
+ bad "gutted probe still satisfied $(( 4 - red ))/4 thrash assertions — this checker proves nothing"
250
+ fi
251
+ eval "$_saved_headroom"; eval "$_saved_pressure"
252
+
253
+ hdr "7. LOAD-GUARD's MEMORY ARM — the one site that actually BLOCKS"
254
+ # load-guard-check.sh exercises the regex classifier (which commands count as
255
+ # heavy), never the memory state. This drives the real hook against the REAL
256
+ # box with only the memory threshold moving, so the arm is seen firing AND
257
+ # staying silent — a guard only ever seen to fire is an unproven guard. The load
258
+ # and running-gate arms are pinned out of the way so nothing else can explain
259
+ # the verdict.
260
+ _lg_run() { # _lg_run <GUARD_MIN_FREE_PCT> -> prints "deny" or "allow"
261
+ local out
262
+ out=$(CLAUDE_PROJECT_DIR="$ROOT" GUARD_MIN_FREE_PCT="$1" \
263
+ GUARD_LOAD_FACTOR=100000 GUARD_MAX_RUNNING=100000 \
264
+ bash "$ROOT/.claude/hooks/load-guard.sh" \
265
+ '{"tool_name":"Bash","tool_input":{"command":"bunx vitest run"}}' 2>/dev/null)
266
+ case "$out" in *'"deny"'*) echo deny ;; *) echo allow ;; esac
267
+ }
268
+ _lg_hi=$(_lg_run 101) # threshold above any possible reading -> must deny
269
+ _lg_lo=$(_lg_run 0) # threshold below any possible reading -> must allow
270
+ echo " GUARD_MIN_FREE_PCT=101 -> $_lg_hi · GUARD_MIN_FREE_PCT=0 -> $_lg_lo"
271
+ [ "$_lg_hi" = "deny" ] && ok "memory arm FIRES (hook emits a deny decision, does not crash open)" \
272
+ || bad "memory arm did not fire — the blocking hook failed OPEN"
273
+ [ "$_lg_lo" = "allow" ] && ok "memory arm stays silent on a satisfied threshold" \
274
+ || bad "memory arm fires unconditionally — it is not reading memory"
275
+ # And it must survive a probe that cannot be read at all: point the hook at a
276
+ # project dir with no govern.sh. FREE falls back to 100, so the arm goes quiet
277
+ # rather than taking the hook down with it.
278
+ _lg_nolib=$(CLAUDE_PROJECT_DIR="$GOVERN_DIR" GUARD_MIN_FREE_PCT=101 \
279
+ GUARD_LOAD_FACTOR=100000 GUARD_MAX_RUNNING=100000 \
280
+ bash "$ROOT/.claude/hooks/load-guard.sh" \
281
+ '{"tool_name":"Bash","tool_input":{"command":"bunx vitest run"}}' 2>/dev/null; echo "rc=$?")
282
+ case "$_lg_nolib" in
283
+ *rc=0*) ok "missing govern.sh -> hook still exits 0 (FREE=100, arm silent, nothing crashes)" ;;
284
+ *) bad "missing govern.sh -> hook exited non-zero: $_lg_nolib" ;;
285
+ esac
286
+
287
+ hdr "RESULT"
288
+ echo " $PASS passed, $FAIL failed"
289
+ [ "$FAIL" -eq 0 ] || { echo " GOVERN-MEM-CHECK: RED"; exit 1; }
290
+ echo " GOVERN-MEM-CHECK: GREEN"
@@ -0,0 +1,362 @@
1
+ #!/usr/bin/env bash
2
+ # governor-doors-check.sh — the DOORS half of the governor guard.
3
+ #
4
+ # bash .claude/scripts/governor-doors-check.sh # audit + reentrancy
5
+ # bash .claude/scripts/governor-doors-check.sh --list # every heavy script
6
+ # bash .claude/scripts/governor-doors-check.sh --self-test
7
+ #
8
+ # hook:governor-escape guards what an executor TYPES. This guards what the tree
9
+ # OFFERS. They are different holes and only the second one explains the real
10
+ # failure: `cd channels && bun run test` is an ungoverned 135-file two-runner
11
+ # suite, and nothing about that command string looks like an escape. The hole
12
+ # was the package script, not the command.
13
+ #
14
+ # Enumerated from `git ls-files` at run time, never from a hardcoded package
15
+ # list -- the rot test-lanes.sh explicitly avoided. A NEW package, or a new
16
+ # heavy script in an existing one, is therefore a failure the day it lands
17
+ # rather than the day someone remembers to look.
18
+ #
19
+ # WHAT COUNTS AS A DOOR: a package.json script that reaches a runner pool --
20
+ # vitest / bun test / playwright / astro check -- directly, or one hop through
21
+ # `bash <script>.sh`. `channels`' test is the one-hop case and the reason the
22
+ # hop is followed: its own file, not its package.json, holds the two runners.
23
+ #
24
+ # WHAT IS DELIBERATELY NOT A DOOR is in SKIP below, each with its reason. That
25
+ # list is the argument, not an allowlist of convenience.
26
+ #
27
+ # A LOCK IS NOT A SLOT. Until 2026-09-07 the typecheck skip below read "tsc
28
+ # already has its own lock via tsc-cached.sh", and that reasoning is wrong in a
29
+ # way that cost the machine: gate_lock is keyed by FOLDER and dedupes identical
30
+ # work, while a SLOT caps concurrent heavy work machine-wide. N worktrees are N
31
+ # folders, so N locks are all uncontended while N typecheckers run. Measured that
32
+ # day: three 2.5GB tsc processes at once, load 171, localhost at 8.4s a page, and
33
+ # THIS CHECKER REPORTING "0 open". The "2-second typecheck" half was wrong too --
34
+ # the measured runs were 2.5GB and 7+ minutes. The compute sites now take a slot
35
+ # (see the `compute sites` section below, which is what would have caught it).
36
+ # SHIPS (needs-env). In a generated factory clone this enumerates THAT repo
37
+ # package.json files, while every line in the skip list names a monorepo path
38
+ # that can never match there -- so it may report open doors it has no opinion
39
+ # about. That is loud rather than wrong: the doors it names really are
40
+ # ungoverned in that tree. Read the skip list as this repo argument, not as a
41
+ # universal one.
42
+ set -uo pipefail
43
+ # GOV_DOORS_ROOT lets --self-test point the REAL audit at a sandbox tree.
44
+ # Without it the red proof has to duplicate the classifier, and a duplicated
45
+ # classifier is the drift this file exists to avoid.
46
+ ROOT="${GOV_DOORS_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)}"
47
+ cd "$ROOT" || exit 1
48
+
49
+ HEAVY_RE='vitest|tsc[[:space:]]+--noEmit|astro[[:space:]]+check|playwright[[:space:]]+test|(^|[^a-zA-Z0-9_-])bun[[:space:]]+test([^a-zA-Z0-9_:-]|$)'
50
+
51
+ # ── the reasoned skips ──────────────────────────────────────────────────────
52
+ # <pkg-relpath>::<script> why
53
+ skips() {
54
+ cat <<'SKIP'
55
+ *::typecheck routes through tsc-cached.sh, which since 2026-09-07 takes a real SLOT around its compute (gate-run.sh), not merely its dedupe lock -- enforced by the `compute sites` section, not asserted here
56
+ *::test:watch a watch never exits; a wall-clock bound would kill it
57
+ *::test:raw an escape hatch by definition -- ungoverned is the whole point
58
+ *::verify:raw an escape hatch by definition
59
+ *::test:coverage watch-mode vitest (no `run`); a bound would kill it
60
+ one.ie/web::test:e2e:pw opt-in e2e needing a live server; a 1800s bound could kill a legitimate long run
61
+ one.ie/web::test:e2e:pw:ui interactive -- a bound would kill a human's session
62
+ one.ie/web::test:e2e:pw:debug interactive -- a bound would kill a human's session
63
+ backup::test 2 test files under `bun test`, no fork pool -- cannot be the memory driver
64
+ packages/evals::test 1 test file -- cannot be the memory driver
65
+ packages/plugin-pages::test 1 test file -- cannot be the memory driver
66
+ packages/plugin-pages::build tsc --noEmit wearing a build's name; same reason as typecheck
67
+ pay/packages/one-protocol::test watch-mode vitest (no `run`) AND 0 test files -- see FINDINGS
68
+ pay/packages/sdk::test 0 test files
69
+ oo-brain::typecheck not a deployed service
70
+ template/site::typecheck Astro 7 template, not a deployed service
71
+ template-release::test a release template, not a live package
72
+ template-release::verify a TEMPLATE: it is copied out to users WITHOUT .claude/, so wrapping it would bake in a gate-run.sh path that does not exist downstream and break the template itself
73
+ SKIP
74
+ }
75
+
76
+ is_skipped() { # is_skipped <pkgdir> <script>
77
+ local pkg="$1" name="$2" k v
78
+ while read -r k v; do
79
+ [ -z "$k" ] && continue
80
+ case "$k" in
81
+ "*::$name") return 0 ;;
82
+ "$pkg::$name") return 0 ;;
83
+ esac
84
+ done < <(skips)
85
+ return 1
86
+ }
87
+
88
+ # ── enumerate ───────────────────────────────────────────────────────────────
89
+ # Emits: <state> <pkgdir> <script> <command> state = GOVERNED|OPEN|SKIP
90
+ # Tracked files in a repo; a plain walk in a sandbox. Never node_modules.
91
+ _list_package_jsons() {
92
+ if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
93
+ git ls-files '*package.json' | grep -v node_modules
94
+ else
95
+ find . -name package.json -not -path '*/node_modules/*' | sed 's|^\./||'
96
+ fi
97
+ }
98
+
99
+ enumerate() {
100
+ local pj
101
+ while IFS= read -r pj; do
102
+ [ -f "$pj" ] || continue
103
+ node -e '
104
+ const fs=require("fs"), path=require("path");
105
+ const pj=process.argv[1], dir=path.dirname(pj);
106
+ let j; try{ j=JSON.parse(fs.readFileSync(pj,"utf8")); }catch(e){ process.exit(0); }
107
+ const heavy=/vitest|tsc\s+--noEmit|astro\s+check|playwright\s+test|(^|[^\w-])bun\s+test([^\w:-]|$)/;
108
+ const scripts=j.scripts||{};
109
+ for(const [k,v] of Object.entries(scripts)){
110
+ let reaches=heavy.test(v), via="", hopGoverned=false;
111
+ // ONE HOP: `bash scripts/test.sh` hides its runners in its own file.
112
+ // Two traps, both hit on the FIRST run of this checker:
113
+ // - install-hooks.sh only NAMES tsc, in a comment and an echo. A bare
114
+ // mention is not an invocation, so the hop is position-anchored the
115
+ // same way hook:governor-escape is. It is the same scar
116
+ // this repo already carries under "a hook greps the whole
117
+ // command"; reproducing it here made the checker cry wolf
118
+ // on six innocent scripts.
119
+ // - verify-fast.sh IS governed: it routes everything through
120
+ // gate-run.sh internally. Governance can live in the HOPPED file,
121
+ // so it has to be read there too, not only in package.json.
122
+ if(!reaches){
123
+ // Take EVERY `bash <x>.sh` in the value and skip gate-run.sh itself:
124
+ // once a one-hop script is wrapped, the first .sh in the string is the
125
+ // wrapper, and matching only that made channels and the three demos
126
+ // vanish from this audit the moment they were fixed. A guard that goes
127
+ // blind on the thing it just repaired cannot detect a later regression.
128
+ const all=[...v.matchAll(/bash\s+([^\s;&|]+\.sh)/g)].map(function(x){return x[1];});
129
+ const wrapped=all.some(function(x){return /gate-run\.sh$/.test(x);});
130
+ const m=all.filter(function(x){return !/gate-run\.sh$/.test(x);}).map(function(x){return [null,x];})[0];
131
+ if(m){
132
+ const hp=path.join(dir,m[1]);
133
+ try{
134
+ // Comments are prose, never invocations. install-hooks.sh
135
+ // line 2 reads "(astro check + tsc)" -- the bare paren made
136
+ // it look like a command position. Strip comments first.
137
+ const body=fs.readFileSync(hp,"utf8")
138
+ .split("\n").filter(function(l){return !/^\s*#/.test(l);}).join("\n");
139
+ const invoked=new RegExp(
140
+ "(^|[;&|(]|&&|\\|\\|)[ \\t]*([A-Za-z_][A-Za-z0-9_]*=[^ \\t]*[ \\t]+)*"+
141
+ "((bunx|npx|bun|npm|xargs)[ \\t]+)*"+
142
+ "(vitest|tsc[ \\t]+--noEmit|astro[ \\t]+check|playwright[ \\t]+test|bun[ \\t]+test)","m");
143
+ if(invoked.test(body)){
144
+ reaches=true; via=" [via "+m[1]+"]";
145
+ // governed either by the wrapper in package.json, or because the
146
+ // hopped file routes through gate-run.sh internally (verify-fast).
147
+ if(wrapped || /gate-run\.sh/.test(body)) hopGoverned=true;
148
+ }
149
+ }catch(e){}
150
+ }
151
+ }
152
+ if(!reaches) continue;
153
+ const governed=/gate-run\.sh/.test(v) || hopGoverned;
154
+ console.log((governed?"GOVERNED":"OPEN")+"\t"+dir+"\t"+k+"\t"+v+via);
155
+ }
156
+ ' "$pj"
157
+ done < <(_list_package_jsons)
158
+ }
159
+
160
+ bad=0
161
+ ok() { printf ' ok %s\n' "$*"; }
162
+ nope() { printf ' FAIL %s\n' "$*"; bad=$((bad + 1)); }
163
+
164
+ audit() {
165
+ echo "== doors — every heavy package script is governed, or skipped for a stated reason"
166
+ local state pkg name cmd n_gov=0 n_skip=0
167
+ while IFS=$'\t' read -r state pkg name cmd; do
168
+ [ -z "${state:-}" ] && continue
169
+ if [ "$state" = "GOVERNED" ]; then n_gov=$((n_gov+1)); continue; fi
170
+ if is_skipped "$pkg" "$name"; then n_skip=$((n_skip+1)); continue; fi
171
+ nope "UNGOVERNED heavy script: (cd $pkg && bun run $name) -> $cmd"
172
+ printf ' fix: wrap it — bash <rel>/.claude/scripts/gate-run.sh %s -- %s\n' "$name" "$cmd"
173
+ done < <(enumerate)
174
+ [ "$bad" -eq 0 ] && ok "$n_gov governed, $n_skip skipped with a reason, 0 open"
175
+ }
176
+
177
+ # ── the wrapped paths must actually resolve ────────────────────────────────
178
+ # Every wrap names gate-run.sh RELATIVELY, resolved from the package dir that
179
+ # `bun run` cd's into. A wrong `../` count is the one way wrapping can break a
180
+ # script, and it would surface only when somebody ran it -- months later, as a
181
+ # "test command is broken" that nobody connects to this change. Derived from the
182
+ # enumeration, never from a list, so a package wrapped tomorrow is checked too.
183
+ paths() {
184
+ echo "== wrapped paths — every relative gate-run.sh resolves from its package dir"
185
+ local state pkg name cmd rel n=0
186
+ while IFS=$'\t' read -r state pkg name cmd; do
187
+ [ "${state:-}" = "GOVERNED" ] || continue
188
+ rel=$(printf '%s' "$cmd" | sed -nE 's|.*bash ([^ ]*gate-run\.sh) .*|\1|p' | head -1)
189
+ [ -n "$rel" ] || continue
190
+ case "$rel" in /*) [ -f "$rel" ] && { n=$((n+1)); continue; } ;; esac
191
+ if [ -f "$pkg/$rel" ]; then
192
+ n=$((n+1))
193
+ else
194
+ nope "$pkg :: $name names $rel, which does NOT resolve from $pkg"
195
+ fi
196
+ done < <(enumerate)
197
+ [ "$bad" -eq 0 ] && ok "$n wrapped scripts, every relative path resolves"
198
+ }
199
+
200
+ # ── re-entrancy: the one way wrapping could make things WORSE ───────────────
201
+ # gate-run is re-entrant by design (GOVERN_IN_GATE), so a wrapped `test` called
202
+ # from a wrapped `verify` must inherit the outer slot rather than queue behind
203
+ # it. With the cap at 1 a non-re-entrant nest DEADLOCKS -- which is exactly what
204
+ # the red half below forces, so this check is not taking re-entrancy on trust.
205
+ reentrancy() {
206
+ echo "== re-entrancy — a wrapped gate nested in a wrapped gate must not deadlock"
207
+ local sandbox G o e
208
+ sandbox="$(mktemp -d)"
209
+ G="$ROOT/.claude/scripts/gate-run.sh"
210
+ o="$sandbox/out"; e="$sandbox/err"
211
+ local T=30 # bound the whole experiment; the commands under test are echoes
212
+
213
+ # NEVER capture a gate with `out=$(gate-run ... 2>&1)`. run_bounded
214
+ # (govern.sh:130-134) forks a watchdog holding `sleep $GOVERN_GATE_TIMEOUT`,
215
+ # deliberately detached from STDOUT on 2026-09-01 so a command substitution
216
+ # would not block on it -- but `2>&1` reattaches it to the captured pipe, and
217
+ # the substitution then hangs for the FULL timeout after the command has
218
+ # already finished. Measured here: 1800s of nothing, killed at 144.
219
+ # Redirect to files and read the files.
220
+
221
+ # GREEN: the nested gate inherits the outer slot even with the cap at 1.
222
+ GOVERN_DIR="$sandbox" GOVERN_MAX_GATES=1 GOVERN_QUEUE_WAIT=8 GOVERN_GATE_TIMEOUT=$T \
223
+ bash "$G" outer -- bash -c \
224
+ "GOVERN_DIR='$sandbox' GOVERN_MAX_GATES=1 GOVERN_QUEUE_WAIT=8 GOVERN_GATE_TIMEOUT=$T bash '$G' inner -- echo NESTED_OK" \
225
+ >"$o" 2>"$e"
226
+ if grep -q NESTED_OK "$o"; then
227
+ ok "nested gate inherited the outer slot at cap 1 (no deadlock)"
228
+ else
229
+ nope "nested gate did NOT complete at cap 1 — deadlock. out=[$(cat "$o")] err=[$(cat "$e")]"
230
+ fi
231
+
232
+ # RED: clear GOVERN_IN_GATE inside, so the nest asks for a SECOND slot at cap
233
+ # 1. It must starve -- proving the green above was re-entrancy doing the work
234
+ # and not merely a cap that never bound.
235
+ : > "$o"; : > "$e"
236
+ GOVERN_DIR="$sandbox" GOVERN_MAX_GATES=1 GOVERN_QUEUE_WAIT=4 GOVERN_GATE_TIMEOUT=$T \
237
+ bash "$G" outer2 -- bash -c \
238
+ "unset GOVERN_IN_GATE; GOVERN_DIR='$sandbox' GOVERN_MAX_GATES=1 GOVERN_QUEUE_WAIT=4 GOVERN_GATE_TIMEOUT=$T bash '$G' inner2 -- echo SHOULD_NOT_RUN" \
239
+ >"$o" 2>"$e"
240
+ if grep -q SHOULD_NOT_RUN "$o"; then
241
+ nope "a second slot was granted at cap 1 — the cap does not bind, so the green proves nothing"
242
+ elif grep -q "no slot after" "$e"; then
243
+ ok "without re-entrancy the same nest starves at cap 1 (the cap really binds)"
244
+ else
245
+ nope "unexpected red-half output. out=[$(cat "$o")] err=[$(cat "$e")]"
246
+ fi
247
+ # RED PROOF for `compute sites`: a script that spawns a heavy compute with no
248
+ # gate-run.sh must turn compute_sites red. This is the exact shape tsc-cached.sh
249
+ # had before 2026-09-07 -- a gate_lock, and a bare bunx tsc inside it.
250
+ local probe_dir probe
251
+ probe_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
252
+ # NOT a dotfile: `for f in "$d"/*.sh` does not glob dotfiles, so a probe named
253
+ # .zz-*.sh is invisible to the very check it is supposed to drive red -- the
254
+ # proof would pass by never being seen. Named plainly, and rm'd below.
255
+ probe="$probe_dir/zz-compute-probe.sh"
256
+ cat > "$probe" <<'PROBE'
257
+ #!/usr/bin/env bash
258
+ # a lock, and a heavy compute with no slot -- the 2026-09-07 defect, in miniature
259
+ gate_lock "probe" 10 && bunx tsc --noEmit
260
+ PROBE
261
+ local b0=$bad
262
+ compute_sites >/dev/null 2>&1
263
+ if [ "$bad" -gt "$b0" ]; then
264
+ ok "a lock-without-slot compute site turns the audit RED"
265
+ bad=$b0
266
+ else
267
+ nope "compute_sites stayed green against a bare 'bunx tsc --noEmit' with no gate-run"
268
+ fi
269
+ rm -f "$probe"
270
+
271
+ rm -rf "$sandbox"
272
+ }
273
+
274
+ # ── compute sites — a gate_lock is not a slot ───────────────────────────────
275
+ #
276
+ # The `doors` section above audits PACKAGE SCRIPTS. It cannot see the defect
277
+ # that actually cost the machine on 2026-09-07, because that one lived one layer
278
+ # down: tsc-cached.sh held a per-folder gate_lock and spawned `bunx tsc` with no
279
+ # slot at all. Every door was green, the skip list had a stated reason, and three
280
+ # 2.5GB typecheckers ran concurrently while the governor reported 1 of 2 slots.
281
+ #
282
+ # The rule this enforces: ANY script here that spawns a heavy compute must also
283
+ # reference gate-run.sh. Not "takes a lock" -- a lock dedupes identical work, a
284
+ # slot bounds the machine, and only one of those is a concurrency cap.
285
+ compute_sites() {
286
+ echo "== compute sites — a heavy compute behind a lock still needs a SLOT"
287
+ local d f n_ok=0 hits
288
+ d="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
289
+ for f in "$d"/*.sh; do
290
+ case "$(basename "$f")" in
291
+ gate-run.sh|governor-doors-check.sh|governor-escape-check.sh|machine-check.sh) continue ;;
292
+ # FIXTURES — these NAME a heavy command as test data and spawn nothing:
293
+ # load-guard-check.sh passes command STRINGS to the hook ( check 1 "bunx ..." )
294
+ # govern-mem-check.sh embeds them in JSON tool_input payloads
295
+ # deploy-gate-check.sh greps deploy.sh for the command as a PATTERN
296
+ # Each was verified by reading the matching lines, not assumed.
297
+ load-guard-check.sh|govern-mem-check.sh|deploy-gate-check.sh) continue ;;
298
+ esac
299
+ # PRESENCE, not command-position. The first version of this asked "is the
300
+ # compute in command position", blanking quoted regions -- and it could not
301
+ # see the very defect it was written for: tsc-cached.sh spawned its tsc from
302
+ # inside a quoted `bash -c "... ${TSC_CACHE_CMD:-bunx tsc --noEmit} ..."`.
303
+ # Reverting tsc-cached.sh to its pre-fix state left that check GREEN, which
304
+ # is the only test of a checker that matters.
305
+ #
306
+ # So the rule is blunt on purpose: if a heavy token appears outside a comment,
307
+ # this file must reference gate-run.sh somewhere. Scripts that only NAME a
308
+ # command as a test fixture are handled by FIXTURES below, by name and with a
309
+ # reason -- the same "the skip list is the argument" doctrine as the doors.
310
+ hits=$(grep -nE '(bunx|npx|bun x) +(tsc +--noEmit|vitest +run)' "$f" 2>/dev/null \
311
+ | grep -vE '^[0-9]+:[[:space:]]*#' || true)
312
+ [ -n "$hits" ] || continue
313
+ if grep -q 'gate-run\.sh' "$f"; then
314
+ n_ok=$((n_ok+1))
315
+ else
316
+ nope "$(basename "$f") spawns a heavy compute with no gate-run.sh anywhere:
317
+ $(printf '%s' "$hits" | head -3 | sed 's/^/ /')"
318
+ fi
319
+ done
320
+ [ "$bad" -eq 0 ] && ok "$n_ok script(s) spawn a heavy compute, every one routes through gate-run.sh"
321
+ }
322
+
323
+ # ── red proof ───────────────────────────────────────────────────────────────
324
+ self_test() {
325
+ echo "== self-test — plant an open door, the REAL audit must go RED"
326
+ local sandbox out rc
327
+ sandbox="$(mktemp -d)"
328
+ mkdir -p "$sandbox/planted"
329
+ cat > "$sandbox/planted/package.json" <<'PKG'
330
+ { "name": "planted", "scripts": { "test": "vitest run" } }
331
+ PKG
332
+ # Drive audit() itself, in a sandbox tree, through the same enumerate().
333
+ out=$(GOV_DOORS_ROOT="$sandbox" GOV_DOORS_INNER=1 bash "${BASH_SOURCE[0]}" 2>&1); rc=$?
334
+ if [ $rc -ne 0 ] && printf '%s' "$out" | grep -q 'UNGOVERNED heavy script'; then
335
+ ok "a planted ungoverned test makes the real audit go RED"
336
+ else
337
+ nope "planted open door did not turn the audit red (rc=$rc): $out"
338
+ fi
339
+
340
+ # And the inverse: wrapping the SAME script must clear the SAME audit.
341
+ cat > "$sandbox/planted/package.json" <<'PKG'
342
+ { "name": "planted", "scripts": { "test": "bash ../.claude/scripts/gate-run.sh t -- vitest run" } }
343
+ PKG
344
+ out=$(GOV_DOORS_ROOT="$sandbox" GOV_DOORS_INNER=1 bash "${BASH_SOURCE[0]}" 2>&1); rc=$?
345
+ if [ $rc -eq 0 ]; then
346
+ ok "wrapping the same script clears the same audit"
347
+ else
348
+ nope "wrapped script still reads open: $out"
349
+ fi
350
+ rm -rf "$sandbox"
351
+ }
352
+
353
+ case "${1:-}" in
354
+ --list) enumerate | sort | column -t -s$'\t' 2>/dev/null || enumerate | sort; exit 0 ;;
355
+ --self-test) self_test ;;
356
+ *) if [ -n "${GOV_DOORS_INNER:-}" ]; then audit
357
+ else audit; echo; paths; echo; compute_sites; echo; reentrancy; echo; self_test; fi ;;
358
+ esac
359
+
360
+ echo
361
+ if [ "$bad" -eq 0 ]; then echo "RESULT: PASS — no ungoverned heavy door, and nesting does not deadlock"
362
+ else echo "RESULT: RED — $bad failure(s)"; exit 1; fi