@oneie/claude 0.8.0 → 0.10.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 (230) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/abm-strategist.md +67 -1
  3. package/agents/ads-meta.md +67 -1
  4. package/agents/analyst.md +67 -1
  5. package/agents/animator.md +108 -0
  6. package/agents/architect.md +269 -20
  7. package/agents/brand-guardian.md +67 -1
  8. package/agents/brand-strategist.md +67 -1
  9. package/agents/campaign-content.md +67 -1
  10. package/agents/campaign-email.md +67 -1
  11. package/agents/campaign-sms.md +67 -1
  12. package/agents/campaign-social.md +67 -1
  13. package/agents/cco.md +83 -2
  14. package/agents/ceo.md +108 -11
  15. package/agents/chairman.md +197 -0
  16. package/agents/cmo.md +82 -2
  17. package/agents/community-greeter.md +67 -1
  18. package/agents/community-moderator.md +67 -1
  19. package/agents/compliance.md +67 -1
  20. package/agents/copywriter.md +67 -1
  21. package/agents/creative-strategist.md +67 -1
  22. package/agents/cro.md +81 -1
  23. package/agents/cto.md +266 -28
  24. package/agents/customer-interviewer.md +67 -1
  25. package/agents/customer-researcher.md +67 -1
  26. package/agents/customer-success-manager.md +67 -1
  27. package/agents/customer-trainer.md +67 -1
  28. package/agents/cxo.md +82 -1
  29. package/agents/demand-creator.md +67 -1
  30. package/agents/demo-mover.md +67 -1
  31. package/agents/demo-specialist.md +67 -1
  32. package/agents/demo-thai-family-law.md +67 -1
  33. package/agents/designer.md +67 -1
  34. package/agents/discovery-caller.md +67 -1
  35. package/agents/doctor.md +269 -0
  36. package/agents/educate-coach.md +67 -1
  37. package/agents/elevate-tutor.md +67 -1
  38. package/agents/email-lifecycle-marketer.md +67 -1
  39. package/agents/engage-specialist.md +67 -1
  40. package/agents/events-coordinator.md +67 -1
  41. package/agents/foundation-builder.md +67 -1
  42. package/agents/funnel-architect.md +67 -1
  43. package/agents/gift-creator.md +67 -1
  44. package/agents/google-ads.md +67 -1
  45. package/agents/guide.md +67 -1
  46. package/agents/helpdesk-dispatcher.md +67 -1
  47. package/agents/hook-specialist.md +67 -1
  48. package/agents/identify-optimizer.md +67 -1
  49. package/agents/implementer.md +313 -45
  50. package/agents/incident-commander.md +67 -1
  51. package/agents/insights-lead.md +87 -1
  52. package/agents/journey-runner.md +67 -1
  53. package/agents/linkedin-ads.md +67 -1
  54. package/agents/live-sales-chat.md +67 -1
  55. package/agents/market-researcher.md +67 -1
  56. package/agents/media-buyer.md +67 -1
  57. package/agents/memory-keeper.md +195 -0
  58. package/agents/movers-customer-researcher.md +67 -1
  59. package/agents/movers-foundation-builder.md +67 -1
  60. package/agents/movers-market-researcher.md +67 -1
  61. package/agents/movers-pricing-strategist.md +67 -1
  62. package/agents/nurture-architect.md +67 -1
  63. package/agents/offer-architect.md +67 -1
  64. package/agents/onboarder.md +67 -1
  65. package/agents/onboarding-specialist.md +67 -1
  66. package/agents/operations-dashboard.md +87 -1
  67. package/agents/perf-engineer.md +333 -37
  68. package/agents/playbook-writer.md +67 -1
  69. package/agents/plg-strategist.md +67 -1
  70. package/agents/positioning-architect.md +67 -1
  71. package/agents/press-officer.md +67 -1
  72. package/agents/pricing-strategist.md +67 -1
  73. package/agents/privacy-officer.md +67 -1
  74. package/agents/referral-manager.md +67 -1
  75. package/agents/refine-analyst.md +67 -1
  76. package/agents/release-manager.md +446 -39
  77. package/agents/renewals-upsell-rep.md +67 -1
  78. package/agents/review-engineer.md +319 -45
  79. package/agents/rewards-steward.md +67 -1
  80. package/agents/sales-call-coach.md +67 -1
  81. package/agents/sales-closer.md +67 -1
  82. package/agents/security-auditor.md +343 -48
  83. package/agents/sell-closer.md +67 -1
  84. package/agents/share-amplifier.md +67 -1
  85. package/agents/social-media-manager.md +67 -1
  86. package/agents/storyteller.md +301 -0
  87. package/agents/strategist.md +67 -1
  88. package/agents/strategy-aligner.md +67 -1
  89. package/agents/support-agent.md +67 -1
  90. package/agents/tagger.md +327 -0
  91. package/agents/tech-writer.md +195 -22
  92. package/agents/test-engineer.md +398 -29
  93. package/agents/tiktok-ads.md +67 -1
  94. package/agents/tracking-engineer.md +67 -1
  95. package/agents/trailkeeper.md +181 -0
  96. package/agents/upsell-strategist.md +67 -1
  97. package/agents/voice.md +67 -1
  98. package/agents/w1-recon.md +1 -1
  99. package/agents/w2-decide.md +1 -1
  100. package/agents/w3-edit.md +8 -2
  101. package/agents/w4-verify.md +13 -0
  102. package/agents/workflow-optimiser.md +81 -1
  103. package/commands/close.md +916 -160
  104. package/commands/deploy.md +102 -724
  105. package/commands/do.md +58 -2
  106. package/commands/sweep.md +159 -0
  107. package/commands/tasks.md +222 -0
  108. package/hooks/scripts/dev-only.sh +135 -0
  109. package/hooks/scripts/git-add-guard.sh +37 -2
  110. package/hooks/scripts/session-start.sh +32 -4
  111. package/package.json +1 -1
  112. package/rules/scripts.md +85 -0
  113. package/scripts/CLAUDE.md +315 -0
  114. package/scripts/ad-copy-lint.sh +656 -0
  115. package/scripts/agent-actor-parity.sh +129 -0
  116. package/scripts/blocks-manifest-cached.sh +100 -0
  117. package/scripts/chat-context-check.sh +89 -0
  118. package/scripts/chrome.mjs +18 -0
  119. package/scripts/close-metrics.sh +587 -0
  120. package/scripts/close-owner.sh +326 -0
  121. package/scripts/db-sync-lock-check.sh +116 -0
  122. package/scripts/deploy-emit.sh +311 -0
  123. package/scripts/deploy-gate-check.sh +155 -0
  124. package/scripts/deploy-ready.sh +78 -0
  125. package/scripts/deploy-record.sh +605 -0
  126. package/scripts/deploy-schema-check.sh +58 -0
  127. package/scripts/deploy.sh +393 -243
  128. package/scripts/do-auto.sh +127 -26
  129. package/scripts/do-board.sh +429 -0
  130. package/scripts/do-close.sh +1184 -0
  131. package/scripts/do-consumer-sweep.sh +18 -1
  132. package/scripts/do-decide.sh +476 -0
  133. package/scripts/do-fleet.sh +8 -2
  134. package/scripts/do-plan-json.mjs +110 -12
  135. package/scripts/do-prove-selftest.sh +108 -0
  136. package/scripts/do-prove.sh +86 -10
  137. package/scripts/do-rank.py +200 -3
  138. package/scripts/do-reconcile.sh +73 -12
  139. package/scripts/do-signal.sh +101 -23
  140. package/scripts/do-smoke.sh +18 -1
  141. package/scripts/do-w4-gates.sh +11 -1
  142. package/scripts/do-world-check.sh +153 -0
  143. package/scripts/download-stats.sh +172 -0
  144. package/scripts/factory-brief-check.sh +330 -0
  145. package/scripts/factory-check.sh +18 -1
  146. package/scripts/factory-close-check.sh +257 -0
  147. package/scripts/factory-emit.sh +211 -0
  148. package/scripts/factory-executor-check.mjs +353 -0
  149. package/scripts/factory-peak.sh +301 -0
  150. package/scripts/factory-repo.sh +71 -0
  151. package/scripts/factory-review-check.mjs +61 -0
  152. package/scripts/factory-tasks-check.sh +18 -1
  153. package/scripts/fixtures/factory-brief-real.md +44 -0
  154. package/scripts/flywheel-outcome.sh +63 -0
  155. package/scripts/gate-reaper-check.sh +98 -0
  156. package/scripts/gate-reaper.sh +9 -0
  157. package/scripts/gate-watchdog.sh +619 -0
  158. package/scripts/gc-content-check.sh +142 -0
  159. package/scripts/gh-traffic-capture.sh +153 -0
  160. package/scripts/govern-order-check.sh +202 -0
  161. package/scripts/governor-doors-check.sh +86 -5
  162. package/scripts/health.sh +448 -0
  163. package/scripts/id-inventory.mjs +418 -0
  164. package/scripts/incident.sh +212 -0
  165. package/scripts/land.sh +755 -45
  166. package/scripts/lib/gc-finished.sh +77 -0
  167. package/scripts/livekit-ratchet.sh +18 -1
  168. package/scripts/machine-check.sh +1 -1
  169. package/scripts/memory-index-budget.sh +79 -0
  170. package/scripts/npm-downloads.sh +109 -0
  171. package/scripts/one-agents.mjs +204 -8
  172. package/scripts/one-resume.sh +31 -3
  173. package/scripts/pr-body.sh +335 -0
  174. package/scripts/preview-fd-check.sh +289 -0
  175. package/scripts/redirect-lint.sh +169 -0
  176. package/scripts/release.sh +40 -6
  177. package/scripts/resume-lost-sessions.sh +68 -0
  178. package/scripts/shoot-pages.mjs +140 -0
  179. package/scripts/signal-meta-backfill.ts +451 -0
  180. package/scripts/signal-watch.sh +63 -6
  181. package/scripts/speed-cache-check.sh +12 -2
  182. package/scripts/sweep.sh +426 -0
  183. package/scripts/task-titles-dump.ts +101 -0
  184. package/scripts/test-cached.sh +47 -10
  185. package/scripts/test-lanes.sh +14 -0
  186. package/scripts/thread-name-backfill.ts +215 -0
  187. package/scripts/triage-shape-check.sh +149 -0
  188. package/scripts/tsc-cached.sh +155 -8
  189. package/scripts/typedb-flake-check.sh +3 -1
  190. package/scripts/urls-lint.sh +8 -0
  191. package/scripts/verify-board-doors.sh +80 -0
  192. package/scripts/verify-fast.sh +159 -6
  193. package/scripts/worktree-up.sh +21 -3
  194. package/skills/astro/SKILL.md +9 -3
  195. package/skills/astro/optimize-performance.md +3 -2
  196. package/skills/cloudflare/SKILL.md +3 -2
  197. package/skills/cloudflare-security-audit/AI-AND-LLM.md +83 -0
  198. package/skills/cloudflare-security-audit/ATTACK-CLASSES.md +130 -0
  199. package/skills/cloudflare-security-audit/CLIENT-SIDE.md +83 -0
  200. package/skills/cloudflare-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
  201. package/skills/cloudflare-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
  202. package/skills/cloudflare-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
  203. package/skills/cloudflare-security-audit/HUNTING.md +251 -0
  204. package/skills/cloudflare-security-audit/LICENSE +21 -0
  205. package/skills/cloudflare-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
  206. package/skills/cloudflare-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
  207. package/skills/cloudflare-security-audit/PROVENANCE.md +78 -0
  208. package/skills/cloudflare-security-audit/RECONNAISSANCE.md +156 -0
  209. package/skills/cloudflare-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
  210. package/skills/cloudflare-security-audit/SKILL.md +192 -0
  211. package/skills/cloudflare-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
  212. package/skills/cloudflare-security-audit/VALIDATION-AND-REPORTING.md +186 -0
  213. package/skills/cloudflare-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
  214. package/skills/cloudflare-security-audit/report-schema.json +461 -0
  215. package/skills/cloudflare-security-audit/validate-coverage-ledger.cjs +872 -0
  216. package/skills/cloudflare-security-audit/validate-coverage-ledger.test.cjs +740 -0
  217. package/skills/cloudflare-security-audit/validate-findings.cjs +773 -0
  218. package/skills/cloudflare-security-audit/validate-findings.test.cjs +652 -0
  219. package/skills/deploy/REFERENCE.md +713 -0
  220. package/skills/deploy/SKILL.md +140 -0
  221. package/skills/fleet-audit/SKILL.md +58 -0
  222. package/skills/meeting/SKILL.md +220 -0
  223. package/skills/planning/SKILL.md +256 -0
  224. package/skills/shadcn/SKILL.md +1 -1
  225. package/skills/typedb/SKILL.md +7 -0
  226. package/skills/voice/SKILL.md +94 -6
  227. package/skills/voice/corpus-check.sh +87 -0
  228. package/templates/template-agent.md +7 -1
  229. package/templates/template-feature.md +9 -0
  230. package/templates/template-todo.md +29 -0
@@ -1,5 +1,15 @@
1
1
  #!/usr/bin/env bash
2
2
  # tsc-cached.sh <folder> — run `tsc --noEmit` for <folder>, or reuse the answer
3
+ # tsc-cached.sh --probe <folder> — answer from the memo ONLY: prints `green` (exit 0)
4
+ # when this exact tree already passed, `unknown` (exit 1) otherwise. Never
5
+ # computes, never locks, never takes a slot. This is how land.sh learns what a
6
+ # branch knew about itself BEFORE the trunk was merged in, and whether dev's own
7
+ # tree is on record as green — the two facts that turn "fast gate RED" into an
8
+ # attribution (root CLAUDE.md § The dev → prod loop › three owners).
9
+ # TSC_CACHE_ROOT=<dir> fingerprints THAT checkout instead of the one this script
10
+ # lives in. Every door script runs MAIN's copy (a worktree's copy resolves ROOT
11
+ # to the worktree and lands nothing), so main's copy needs a way to ask about a
12
+ # worktree. The key is content, so the memo is shared across checkouts anyway.
3
13
  # someone else already computed for this exact tree. Prints the error COUNT.
4
14
  #
5
15
  # manifest: needs-env
@@ -20,6 +30,30 @@
20
30
  # tree, which is the one thing this harness exists to prevent.
21
31
  #
22
32
  # TSC_CACHE_DISABLE=1 forces a real run (and still records the result).
33
+ #
34
+ # ── SLOT BEFORE LOCK — the 2026-09-13 deadlock ──────────────────────────────
35
+ # This script used to take the per-folder dedupe LOCK and then, still holding
36
+ # it, queue for a governor SLOT. Any caller already inside a gate arrives in the
37
+ # opposite order: `bun run verify:fast` IS `gate-run.sh verify-fast -- …`, so it
38
+ # holds a SLOT and its child here waits for the LOCK. Two orders, one cycle:
39
+ #
40
+ # A: gate-run(verify-fast) holds slot-1 -> its tsc-cached waits for lock-tsc-one.ie_web
41
+ # B: tsc-cached holds lock-tsc-one.ie_web -> its inner gate-run waits for a slot
42
+ #
43
+ # Measured three times in ~35 minutes on 2026-09-13, each stalling EVERY session
44
+ # on the box for 8-28 minutes at 0% CPU — one of them a production release gate.
45
+ # Owner pairs: 22173/68920, 15762/97557, 87579. Nothing reaps it: both owners are
46
+ # alive, and `reapLock`/gate-reaper only reap a DEAD owner.
47
+ #
48
+ # KILLING THE LOCK HOLDER DOES NOT FIX IT (observed twice): the lock passes
49
+ # straight to the next waiter, which is itself inside a gate holding a slot, and
50
+ # the cycle re-forms within seconds. Killing the SLOT holder is what breaks it.
51
+ #
52
+ # So the order is now global: SLOT, then LOCK, never the reverse. A cache HIT
53
+ # and `--probe` still take NEITHER — a memo lookup must never join a queue.
54
+ # Proof, both halves: `bash .claude/scripts/govern-order-check.sh`.
55
+ # do-reconcile.sh takes the SAME lock name and carries the same fix; one
56
+ # inverted participant is enough to re-form the cycle.
23
57
  set -uo pipefail
24
58
 
25
59
  # --self-test — the RED half. A cache that has never been seen to refuse is not
@@ -69,29 +103,82 @@ EOF
69
103
  out6=$(bash "$0" .tsc-cache-probe 2>&1 >/dev/null)
70
104
  case "$out6" in *"cache HIT"*) echo "FAIL: a content change replayed as a HIT — the key does not read the bytes"; fails=$((fails+1));;
71
105
  *) echo "ok: a content change MISSes (key covers the bytes)";; esac
106
+ # --probe answers from the memo and NEVER computes. The tree is green and
107
+ # memoised here (out6 computed it); a probe must say so. Then break it: a
108
+ # never-checked tree must read `unknown`, exit 1, and leave no stamp behind —
109
+ # a probe that computed would stamp the green half and hide the cost it exists
110
+ # to avoid; a probe that said `green` for an unchecked tree would let land.sh
111
+ # call a branch "green alone" on no evidence.
112
+ if pr=$(bash "$0" --probe .tsc-cache-probe 2>/dev/null) && [ "$pr" = "green" ]; then echo "ok: --probe reads the memoised PASS as green"
113
+ else echo "FAIL: --probe missed a memoised PASS (got '${pr:-}')"; fails=$((fails+1)); fi
114
+ echo 'export const y: string = 1;' > "$_P/src/b.ts" # red, and never checked
115
+ _stamps_before=$(ls "$GOVERN_DIR" | wc -l | tr -d ' ')
116
+ if pr=$(bash "$0" --probe .tsc-cache-probe 2>/dev/null); then echo "FAIL: --probe reported '$pr' for a tree never checked"; fails=$((fails+1))
117
+ elif [ "$pr" != "unknown" ]; then echo "FAIL: --probe exit 1 but said '$pr', not 'unknown'"; fails=$((fails+1))
118
+ else echo "ok: --probe says unknown for an unchecked tree"; fi
119
+ _stamps_after=$(ls "$GOVERN_DIR" | wc -l | tr -d ' ')
120
+ [ "$_stamps_before" = "$_stamps_after" ] && echo "ok: --probe wrote nothing" \
121
+ || { echo "FAIL: --probe left a stamp ($_stamps_before -> $_stamps_after) — it computed"; fails=$((fails+1)); }
122
+ rm -f "$_P/src/b.ts"
123
+ # TSC_CACHE_ROOT: the same bytes in ANOTHER checkout share the memo. This is
124
+ # the property land.sh leans on — main's copy asking about a worktree's tree.
125
+ _C="$(mktemp -d)"; cp -R "$_P" "$_C/.tsc-cache-probe"
126
+ if pr=$(TSC_CACHE_ROOT="$_C" bash "$0" --probe .tsc-cache-probe 2>/dev/null) && [ "$pr" = "green" ]; then
127
+ echo "ok: TSC_CACHE_ROOT reads the same memo for identical bytes in another checkout"
128
+ else echo "FAIL: TSC_CACHE_ROOT did not share the memo (got '${pr:-}')"; fails=$((fails+1)); fi
129
+ rm -rf "$_C"
72
130
  # RED PROOF — an unrun tsc must NOT read as 0 errors. A child that cannot
73
131
  # finish inside the bound is killed by run_bounded, leaving the count file
74
132
  # EMPTY -- exactly the shape a real 600s timeout produces. The old
75
133
  # `n=${n:-0}` turned that empty file into "0 errors" AND cached it, so a
76
134
  # typecheck that never ran was replayed forever as a PASS.
77
135
  rm -rf "$GOVERN_DIR"; export GOVERN_DIR="$(mktemp -d)"
78
- if TSC_CACHE_TIMEOUT=1 TSC_CACHE_CMD='sleep 30' bash "$0" .tsc-cache-probe >/dev/null 2>&1; then
136
+ if out7=$(TSC_CACHE_TIMEOUT=1 TSC_CACHE_CMD='sleep 30' bash "$0" .tsc-cache-probe 2>&1 >/dev/null); then
79
137
  echo "FAIL: a timed-out tsc exited 0 — an unrun gate read as a pass"; fails=$((fails+1))
80
138
  else echo "ok: a tsc that could not finish exits non-zero"; fi
139
+ # AND it must be the EMPTY-COUNT branch that refused, not merely some non-zero
140
+ # exit. Since 2026-09-13 the compute runs inside a slot this script bought
141
+ # itself, so there are now TWO bounds — the inner run_bounded and gate-run's
142
+ # outer one — and if the outer ever fires first, the count file is never even
143
+ # read and this red proof silently degrades into "the outer bound works".
144
+ # Pinned by the message the inner branch prints.
145
+ case "$out7" in *"no error count"*) echo "ok: the refusal came from the empty-count branch" ;;
146
+ *) echo "FAIL: a timed-out tsc did not reach the empty-count branch — got: ${out7:-<nothing>}"; fails=$((fails+1)) ;; esac
81
147
  rm -rf "$_P" "$GOVERN_DIR"
82
148
  [ "$fails" -eq 0 ] && { echo "tsc-cached: self-test PASS"; exit 0; }
83
149
  echo "tsc-cached: self-test FAILED ($fails)"; exit 1
84
150
  fi
85
151
 
86
- folder="${1:-}"
87
- [ -n "$folder" ] || { echo "usage: tsc-cached.sh <folder>" >&2; exit 2; }
152
+ PROBE=0 LOCKED=0 folder=""
153
+ for _a in "$@"; do
154
+ case "$_a" in
155
+ --probe) PROBE=1 ;;
156
+ # INTERNAL. Set only by this script's own re-invocation through gate-run.sh
157
+ # (see § SLOT BEFORE LOCK): "a slot is held — take the lock and compute".
158
+ # It is also what stops the re-invocation recursing: under CI=1 or
159
+ # GOVERN_DISABLE=1, gate-run.sh execs straight through BEFORE it exports
160
+ # GOVERN_IN_GATE, so the child would otherwise see no gate and re-invoke
161
+ # itself forever. The mode flag is checked first, and never GOVERN_IN_GATE
162
+ # alone.
163
+ --locked-compute) LOCKED=1 ;;
164
+ -*) echo "tsc-cached: unknown flag '$_a'" >&2; exit 2 ;;
165
+ *) folder="$_a" ;;
166
+ esac
167
+ done
168
+ [ -n "$folder" ] || { echo "usage: tsc-cached.sh [--probe] <folder>" >&2; exit 2; }
88
169
 
89
- ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
170
+ # _HERE is where the SCRIPTS live (main's copy); ROOT is the tree being checked.
171
+ # They differ exactly when TSC_CACHE_ROOT names a worktree.
172
+ _HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
173
+ # Resolved BEFORE the cd below, and by basename rather than a literal name, so
174
+ # the re-invocation survives both a relative $0 and a rename of this file.
175
+ _SELF="$_HERE/$(basename "${BASH_SOURCE[0]}")"
176
+ ROOT="${TSC_CACHE_ROOT:-$(cd "$_HERE/../.." && pwd)}"
90
177
  cd "$ROOT" || exit 2
91
178
  [ -d "$folder" ] || { echo "tsc-cached: no such folder: $folder" >&2; exit 2; }
92
179
 
93
180
  # shellcheck source=lib/govern.sh
94
- . "$(dirname "${BASH_SOURCE[0]}")/lib/govern.sh"
181
+ . "$_HERE/lib/govern.sh"
95
182
 
96
183
  # The key is tsc_tree_fingerprint (lib/govern.sh) — CONTENT, never mtime, over
97
184
  # everything tsc reads. It used to live here as an mtime stat over src/tests +
@@ -118,13 +205,57 @@ _cache_ok() { # <file> — 0 when it holds a reusable PASS
118
205
  [ -s "$1" ] || return 1
119
206
  [ "$(tr -d '[:space:]' < "$1")" = "0" ]
120
207
  }
208
+ if [ "$PROBE" = "1" ]; then
209
+ # A memo lookup and nothing else. `unknown` is not `red`: it means this exact
210
+ # tree has no recorded PASS — never checked, or checked and found red (a red
211
+ # is never written). The caller decides what an unknown is worth.
212
+ if _cache_ok "$_cache"; then echo green; exit 0; fi
213
+ echo unknown; exit 1
214
+ fi
121
215
  if [ "${TSC_CACHE_DISABLE:-0}" != "1" ] && _cache_ok "$_cache"; then
122
216
  echo "[tsc-cached] $folder — cache HIT (tree unchanged since it was checked)" >&2
123
217
  echo 0
124
218
  exit 0
125
219
  fi
126
220
 
127
- if gate_lock "$_key" "${TSC_CACHE_WAIT:-900}"; then
221
+ # The two bounds, read once and validated: a non-numeric override would make the
222
+ # arithmetic below a hard error rather than a slow gate.
223
+ _num() { case "${1:-}" in ''|*[!0-9]*) printf '%s' "$2" ;; *) printf '%s' "$1" ;; esac; }
224
+ _timeout=$(_num "${TSC_CACHE_TIMEOUT:-}" 600)
225
+ _lockwait=$(_num "${TSC_CACHE_WAIT:-}" 900)
226
+ # ZERO IS NOT A BOUND, it is a kill: run_bounded's timer is `setTimeout(secs *
227
+ # 1000)` (govern.ts:256), so 0 fires on the next tick and SIGTERMs the compute
228
+ # before tsc can start — every run would read RED through the empty-count
229
+ # branch. Treat it the way `${x:-600}` treats an empty string.
230
+ [ "$_timeout" -lt 1 ] && _timeout=600
231
+
232
+ # ── SLOT BEFORE LOCK ────────────────────────────────────────────────────────
233
+ # A miss from here on. Buy the SLOT first, by re-entering this same script
234
+ # through gate-run.sh; the child then takes the lock and computes. Everything
235
+ # above this line — the memo lookup and --probe — still costs neither.
236
+ #
237
+ # WHY THE SELF-INVOCATION rather than a bare gate_slot: gate-run.sh is the one
238
+ # definition of what a slot is (the queue announcement, min(config, headroom),
239
+ # the pressure warning, and the re-entrancy rule that makes a nested gate
240
+ # INHERIT the outer slot instead of taking a second one). A second copy of that
241
+ # contract here is a second thing to drift. It also keeps the hard wall-clock
242
+ # BOUND on the compute: `run_bounded` is what turns a wedged tsc into an empty
243
+ # count, and an empty count is RED (see the case below).
244
+ #
245
+ # GOVERN_IN_GATE=1 means the CALLER already holds a slot — `bun run verify:fast`
246
+ # is exactly that. Then the order is already SLOT -> LOCK, so take the lock right
247
+ # here and compute inline. Re-invoking would only add a process; gate-run.sh
248
+ # would exec straight through anyway.
249
+ if [ "$LOCKED" != "1" ] && [ "${GOVERN_IN_GATE:-0}" != "1" ]; then
250
+ # The outer bound must be LARGER than the inner one, or it fires first and the
251
+ # empty-count RED below stops being reachable: lock wait + compute + slack.
252
+ TSC_CACHE_ROOT="$ROOT" TSC_CACHE_TIMEOUT="$_timeout" TSC_CACHE_WAIT="$_lockwait" \
253
+ GOVERN_GATE_TIMEOUT=$(( _timeout + _lockwait + 60 )) \
254
+ exec bash "$_HERE/gate-run.sh" "tsc-cache:$folder" -- \
255
+ bash "$_SELF" --locked-compute "$folder"
256
+ fi
257
+
258
+ if gate_lock "$_key" "$_lockwait"; then
128
259
  trap 'gate_release_all' EXIT INT TERM
129
260
  # Someone may have computed it while we queued for the lock.
130
261
  if [ "${TSC_CACHE_DISABLE:-0}" != "1" ] && _cache_ok "$_cache"; then
@@ -137,9 +268,25 @@ if gate_lock "$_key" "${TSC_CACHE_WAIT:-900}"; then
137
268
  # TSC_CACHE_CMD exists for --self-test only (the `__probe__` idiom from
138
269
  # test-cached.sh): it substitutes a child that cannot finish inside the bound,
139
270
  # so the timeout branch below can be driven deterministically instead of raced.
140
- run_bounded "${TSC_CACHE_TIMEOUT:-600}" \
271
+ #
272
+ # THE SLOT IS ALREADY HELD when we get here — either the caller's (they were
273
+ # inside a gate) or the one this script's own re-invocation bought above. The
274
+ # gate_lock we hold dedupes by FOLDER: it stops two sessions computing the SAME
275
+ # answer twice. It does not cap concurrency across DIFFERENT folders, and N
276
+ # worktrees are N folders. Measured 2026-09-07: three worktrees each ran a
277
+ # 2.5GB tsc at once, every lock uncontended and doing its job, load hit 171 and
278
+ # localhost served a page in 8.4s. A lock DEDUPES; only a SLOT BOUNDS THE
279
+ # MACHINE — which is why both exist and why the order between them is fixed.
280
+ #
281
+ # run_bounded, not a nested gate-run.sh: gate-run under GOVERN_IN_GATE=1 execs
282
+ # straight through, which correctly declines a SECOND slot but also drops the
283
+ # wall-clock BOUND. So every call from inside a gate — i.e. every
284
+ # `bun run verify:fast` — ran an unbounded tsc until 2026-09-13. Calling
285
+ # run_bounded directly keeps the slot contract (we hold one) and restores the
286
+ # bound on the path that had none. It kills the whole process group.
287
+ run_bounded "$_timeout" \
141
288
  bash -c "cd '$folder' && ${TSC_CACHE_CMD:-bunx tsc --noEmit} 2>&1 | grep -c 'error TS' > '$_tmp'" \
142
- 2>/dev/null || true
289
+ || true
143
290
  n=$(cat "$_tmp" 2>/dev/null | tr -d '[:space:]'); rm -f "$_tmp"
144
291
  gate_release_all; trap - EXIT INT TERM
145
292
  # AN EMPTY COUNT IS NOT ZERO. run_bounded kills tsc at the bound and its `|| true`
@@ -60,7 +60,9 @@ classify() {
60
60
  return 1
61
61
  fi
62
62
  # How many tests vitest itself says failed. No line ⇒ we cannot classify ⇒ RED.
63
- fails=$(grep -Eo 'Tests +[0-9]+ failed' "$log" | tail -1 | grep -Eo '[0-9]+' || true)
63
+ # Strip ANSI escape codes first vitest 4.x wraps its summary in colour codes
64
+ # that break the regex ("Tests \x1b[1m\x1b[31m12 failed\x1b[39m" → no match).
65
+ fails=$(sed 's/\x1b\[[0-9;]*m//g' "$log" | grep -Eo 'Tests +[0-9]+ failed' | tail -1 | grep -Eo '[0-9]+' || true)
64
66
  if [ -z "$fails" ]; then
65
67
  # A green log has "Tests N passed" and no "failed" — that is not our business.
66
68
  if grep -qE 'Tests +[0-9]+ passed' "$log" && ! grep -qE '[0-9]+ failed' "$log"; then
@@ -29,6 +29,14 @@ FROZEN_ROOT_PAGES=(
29
29
  # declared in RESERVED_PREFIXES (src/lib/urls/law.ts) and added to
30
30
  # RESERVED_SLUGS so no future workspace can claim them.
31
31
  tasks w
32
+ # platform — AMENDMENT 2026-09-05 (ad front door). `ad` is a paid-traffic
33
+ # landing page, not a door: it renders one `auraHeroes` split-test variant
34
+ # full-bleed and resolves nothing about the viewer. It is listed in
35
+ # ASTRO_PORTABLE (src/lib/urls/law.ts) so one host's brand is the only thing
36
+ # that changes between one.ie/ad, app.one.ie/ad and a tenant domain — which
37
+ # is a routing BYPASS, and takes the bare word away from workspace `one`'s
38
+ # published page of the same slug (still served at /p/ad and /u/one/p/ad).
39
+ ad
32
40
  # identity
33
41
  signin signup recover "recovery-codes" "auth-security" unsubscribe
34
42
  # system
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bash
2
+ # verify-board-doors.sh — did the tasks:board / tasks:bulk ship actually land in prod?
3
+ #
4
+ # Run BEFORE the ship to capture RED, and AFTER to confirm GREEN. A checker never shown
5
+ # to fail proves nothing — running it twice IS the instrument proof.
6
+ #
7
+ # bash .claude/scripts/verify-board-doors.sh
8
+ #
9
+ # Gate row: task:01a09b3e3c8564b1eabb984a (p0.97, blocker)
10
+ # Honest sibling: task:01a09b7497bdd80ac761b825 — tasks:board has NEVER been called
11
+ # against a real substrate. These probes are the first time it ever will be.
12
+ set -uo pipefail
13
+ BASE="${ONE_API_URL:-https://one.ie}"
14
+ ENVF="${ONE_ENV_FILE:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/one.ie/web/.dev.vars}"
15
+ KEY="${GATEWAY_API_KEY:-$(grep -m1 '^GATEWAY_API_KEY' "$ENVF" 2>/dev/null | cut -d= -f2- | tr -d '"')}"
16
+ red=0; green=0
17
+
18
+ # WITHOUT a key every door answers 403 "direct substrate access not permitted" and every
19
+ # line below reads RED for the wrong reason. The first version of this script did exactly
20
+ # that; the CONTROL is what caught it.
21
+ [ -n "$KEY" ] || { echo "NO KEY — set GATEWAY_API_KEY or ONE_ENV_FILE. Refusing to report."; exit 2; }
22
+
23
+ probe() { # name · expect-regex · receiver · payload
24
+ local name="$1" expect="$2" rcv="$3" payload="$4" body
25
+ body=$(curl -s -m 25 -X POST "$BASE/api/ask/$rcv" -H "Authorization: Bearer $KEY" \
26
+ -H 'content-type: application/json' -d "$payload" 2>&1 | head -c 400)
27
+ if printf '%s' "$body" | grep -qE "$expect"; then
28
+ printf ' GREEN %-36s\n' "$name"; green=$((green+1))
29
+ else
30
+ printf ' RED %-36s %s\n' "$name" "$(printf '%s' "$body" | tr -d '\n' | head -c 130)"; red=$((red+1))
31
+ fi
32
+ }
33
+
34
+ echo "== board doors, against $BASE =="
35
+
36
+ # CONTROL FIRST. If this is RED the key or the host is wrong and every other line is
37
+ # meaningless rather than informative. Never read the results above a red control.
38
+ probe "CONTROL tasks:everywhere" '"ok":true' 'tasks:everywhere' '{"data":{"workspace":"one","limit":1}}'
39
+
40
+ # 1. tasks:board — answers `unknown_receiver` until this ships.
41
+ probe "tasks:board summary" '"total"' 'tasks:board' '{"data":{"workspace":"one","view":"summary"}}'
42
+
43
+ # 2. tasks:bulk where+set — prod takes `edits` only until this ships.
44
+ probe "tasks:bulk where+set dryRun" '"ok":true|matched|dryRun' 'tasks:bulk' \
45
+ '{"data":{"workspace":"one","where":{"status":"open"},"set":{"addTags":["_probe"]},"dryRun":true}}'
46
+
47
+ # 3. tasks:bulk `creates` with a priority — the ONLY door that can file a row the
48
+ # priority-sorted board can see. tasks:create still has no priority parameter, which
49
+ # is why 407 of 730 open rows carry none and the count grows with every filing.
50
+ # IT CLEANS UP AFTER ITSELF. The first version of this script left a _probe row on
51
+ # every run — which made the checker a source of exactly the orphan exhaust it was
52
+ # written to measure. A probe that litters the thing it measures is not a probe.
53
+ body=$(curl -s -m 25 -X POST "$BASE/api/ask/tasks:bulk" -H "Authorization: Bearer $KEY" \
54
+ -H 'content-type: application/json' \
55
+ -d '{"data":{"workspace":"one","creates":[{"ref":"p","title":"_probe verify-board-doors — auto-dissolved","priority":0.01}]}}' 2>&1 | head -c 400)
56
+ ptid=$(printf '%s' "$body" | grep -oE 'task:[0-9a-f]{24}' | head -1)
57
+ if printf '%s' "$body" | grep -q '"ok":true'; then
58
+ printf ' GREEN %-36s\n' "tasks:bulk creates takes priority"; green=$((green+1))
59
+ else
60
+ printf ' RED %-36s %s\n' "tasks:bulk creates takes priority" "$(printf '%s' "$body" | tr -d '\n' | head -c 130)"; red=$((red+1))
61
+ fi
62
+ if [ -n "$ptid" ]; then
63
+ swept=$(curl -s -m 20 -X POST "$BASE/api/ask/tasks:bulk" -H "Authorization: Bearer $KEY" \
64
+ -H 'content-type: application/json' \
65
+ -d "{\"data\":{\"workspace\":\"one\",\"edits\":[{\"tid\":\"$ptid\",\"status\":\"dissolved\"}]}}" | grep -c '"ok":true')
66
+ [ "$swept" -ge 1 ] && printf ' swept %s\n' "$ptid" || printf ' WARN could not sweep %s — dissolve it by hand\n' "$ptid"
67
+ fi
68
+
69
+ # 4. Single-row read door. Expected RED even AFTER this ship — "tasks:get" is 0 hits in
70
+ # dev's receivers.ts. Listed so its absence stays visible instead of being forgotten.
71
+ code=$(curl -s -o /dev/null -m 15 -w '%{http_code}' "$BASE/api/things/task:01a09b3e3c8564b1eabb984a")
72
+ if [ "$code" = "200" ]; then printf ' GREEN %-36s\n' "GET /api/things/<tid>"; green=$((green+1))
73
+ else printf ' RED %-36s HTTP %s — no single-row read door (EXPECTED, not a ship failure)\n' "GET /api/things/<tid>" "$code"; red=$((red+1)); fi
74
+
75
+ echo
76
+ echo " green=$green red=$red"
77
+ echo " BEFORE the ship: CONTROL green · doors 1-3 RED · door 4 RED"
78
+ echo " AFTER the ship: CONTROL green · doors 1-3 GREEN · door 4 still RED"
79
+ echo " CONTROL red => the probe is broken, not the ship. Ignore every other line."
80
+ [ "$red" -gt 0 ] && exit 1 || exit 0
@@ -15,6 +15,9 @@
15
15
  # Those are always run — ~seconds, and they are the class of gate that
16
16
  # historically went dark.
17
17
  # 3. Everything heavy goes through gate-run.sh (machine governor + load-guard).
18
+ # This was ASSERTED here and false until 2026-09-07: tsc-cached.sh was called
19
+ # outside the governor on purpose (see below), so a typecheck escaped the
20
+ # slot cap entirely. It now takes its own slot internally.
18
21
  #
19
22
  # FULL_VERIFY=1 makes this an alias for `bun run verify`.
20
23
  set -euo pipefail
@@ -33,6 +36,63 @@ BASE_REF="${DO_BASE_REF:-main}"
33
36
  # and the test memo, so every worktree and session reads ONE ledger.
34
37
  DEBT_FILE="${VERIFY_FAST_DEBT_FILE:-${TMPDIR:-/tmp}/one-verify-fast-debt}"
35
38
 
39
+ # --- 0. generated-artifact drift ---------------------------------------------
40
+ # `blocks-manifest.mjs` builds THREE COMMITTED artifacts from one registry:
41
+ # one.ie/web/src/lib/puck/block-manifest.json what tooling reads
42
+ # channels/src/generated/block-enum.ts what the model is told
43
+ # one.ie/web/src/lib/puck/block-schema.generated.ts what the browser
44
+ # normalises against
45
+ # Until 2026-09-09 NOTHING ran it: `grep -c blocks-manifest verify-fast.sh
46
+ # deploy.sh` was 0 and 0, and no test shells out to it. Three committed files
47
+ # behind an ungated generator are three files that rot silently -- the registry
48
+ # moves, the artifacts do not, and the first symptom is a model being told about
49
+ # a block the browser cannot render.
50
+ #
51
+ # IT IS A STEP, NOT A PIN, and that distinction is the entire gate. `PINS` below
52
+ # are vitest POSITIONAL SUBSTRING filters. Adding `blocks-manifest` there would
53
+ # select zero test files, the other pins would still match, the pinned gate would
54
+ # exit 0 -- and `grep -q blocks-manifest .claude/scripts/verify-fast.sh` would be
55
+ # TRUE. A green grep over a check that never ran is worse than no gate at all.
56
+ #
57
+ # It runs BEFORE the FULL_VERIFY branch on purpose: every lane below has an exit
58
+ # of its own (FULL_VERIFY exits at the top; an empty selection `exec`s the full
59
+ # suite; a do/* branch exits 0 after deferring the pins), so anywhere lower is a
60
+ # lane that can skip it. Repo-scoped, not folder-scoped -- one of the three
61
+ # artifacts lives in channels/ and one in one.ie/web/, so both folders check both.
62
+ #
63
+ # NOT wrapped in gate-run.sh: one node process, ~2.5s of CPU. Most of its ~16s
64
+ # wall is `bunx tsx` resolving a dependency this repo does not vendor
65
+ # (`one.ie/web/node_modules/.bin/tsx` does not exist -- measured 2026-09-09), and
66
+ # holding a machine-wide slot through a network round-trip is the anti-pattern
67
+ # the tsc-cached note further down records.
68
+ #
69
+ # Capture-then-branch, per rule 3 at the top of this file: `set -e` would kill the
70
+ # script with no message, and `node ... | grep` is the PIPESTATUS scar recorded at
71
+ # the vitest call below. `--check` writes `ok (no drift)` to stdout and `drift
72
+ # detected` to stderr; both are shown. A rc it cannot explain is still RED --
73
+ # an unrun check is not a passing check.
74
+ # MEMOISED since 2026-09-09. The raw --check is ~7s WARM (measured 8.19s then
75
+ # 6.98s back-to-back on this box), and this lane runs on every edit, so a
76
+ # doc-only or test-only cycle was paying 7s for a registry nobody touched.
77
+ # blocks-manifest-cached.sh keys on the whole of one.ie/web/src -- a superset
78
+ # of the check's declared inputs AND of the three artifacts it compares --
79
+ # so any src edit still runs it. Only a PASS is stamped; drift is never
80
+ # memoised. deploy.sh Step 0.5 deliberately keeps calling the RAW check: the
81
+ # ship gate runs once and should not depend on a stamp. BLOCKS_MANIFEST_FORCE=1
82
+ # bypasses the memo; --self-test proves the miss.
83
+ _bm_out="$(mktemp)"
84
+ set +e
85
+ bash "$ROOT/.claude/scripts/blocks-manifest-cached.sh" > "$_bm_out" 2>&1
86
+ _bm_rc=$?
87
+ set -e
88
+ cat "$_bm_out"; rm -f "$_bm_out"
89
+ if [ "$_bm_rc" -ne 0 ]; then
90
+ echo "[verify-fast] block manifest DRIFT (or --check could not run) - rc=$_bm_rc" >&2
91
+ echo "[verify-fast] regenerate and commit all three artifacts:" >&2
92
+ echo "[verify-fast] node .claude/scripts/blocks-manifest.mjs" >&2
93
+ exit 1
94
+ fi
95
+
36
96
  if [ "${FULL_VERIFY:-0}" = "1" ]; then
37
97
  echo "[verify-fast] FULL_VERIFY=1 — running the full gate"
38
98
  # The close gate is where deferred pins come due. The full suite is a superset
@@ -68,7 +128,55 @@ if [ "${FULL_VERIFY:-0}" = "1" ]; then
68
128
  fi
69
129
 
70
130
  # Pinned suites: run on every fast pass regardless of the diff.
71
- PINS_DEFAULT='parity|wrangler|boundary|authority|roles|signals-parity|receivers'
131
+ #
132
+ # `portable` and `design-dock` were added 2026-09-05, after both went red at the
133
+ # ship gate on a change whose fast pass was green. They belong here for the
134
+ # reason the whole list exists — they import NOTHING from what they guard:
135
+ #
136
+ # astro-portable reads the pages DIRECTORY. Adding a root `*.astro` puts it in
137
+ # neither ASTRO_PORTABLE nor ASTRO_NON_PORTABLE, and the new
138
+ # page then 404s on every tenant host. No import graph reaches
139
+ # a file that was just created, so `vitest related` cannot ever
140
+ # select this — the one edit that trips it is invisible to it.
141
+ # design-dock reads `Layout.astro` and every page as STRINGS, to hold "one
142
+ # BrandingSection per document". An edit to Layout.astro selects
143
+ # nothing that imports Layout.astro.
144
+ # render-sites reads MessageList/ShowcaseMessageList as STRINGS to hold that
145
+ # both approval states route to the approval card. Added
146
+ # 2026-09-06, after both sites gated on `approval-requested`
147
+ # alone: the answered card — the whole celebration — was
148
+ # unreachable through the wire, and the component suite covering
149
+ # that state was green the entire time, because it handed the
150
+ # card a state no render site ever passes it.
151
+ # panel-tabs reads `PanelPanes.tsx` as a STRING to hold that every tab a
152
+ # person-panel strip can emit resolves to a rendered pane. Both import only
153
+ # `panels/tabs`, so editing ONLY PanelPanes -- which is where a
154
+ # pane is DELETED -- selects neither. Measured 2026-09-09:
155
+ # with `pane('task', …)` removed, all 79 tests passed.
156
+ # ad-flow-panel reads `pages/ad/index.astro` and `AdFunnel.tsx` as STRINGS.
157
+ # Same class as design-dock: nothing imports an .astro page.
158
+ #
159
+ # Deliberately NOT pinned: `page-chat-meta`, which imports everything it guards,
160
+ # so `vitest related` already reaches it. A pin for a suite the import graph
161
+ # covers is cost with no coverage.
162
+ #
163
+ # These three cost SECONDS, not the milliseconds the two above cost: measured
164
+ # 2026-09-09, 2.34s for 49 tests, most of it `ad-flow-panel.test.tsx` building a
165
+ # jsdom to render AdFlowPanel. That is the price of the only check that can see
166
+ # a deleted pane, and it is paid on every fast lane.
167
+ #
168
+ # Cost measured on the run that motivated this: 7ms and 46ms. The failure they
169
+ # catch costs an 18-minute deploy gate and a red ship.
170
+ #
171
+ # sweep-self-test shells out to `sweep.sh --self-test`. A .sh file is in no
172
+ # import graph at all, so `vitest related` can never select
173
+ # it — not "usually misses", CANNOT. It is the most expensive
174
+ # pin here (2.4s, minting throwaway git estates) and it buys
175
+ # the only check on a script that runs `git reset --hard` on
176
+ # `dev`: a red gate and a conflict must each put the trunk
177
+ # back where they found it. Deleting the reset line takes it
178
+ # RED on exactly that assertion — verified, not asserted.
179
+ PINS_DEFAULT='parity|wrangler|boundary|authority|roles|signals-parity|receivers|portable|design-dock|render-sites|panel-tabs|person-panel|ad-flow-panel|ehc-tone|vantage-a-first|sweep-self-test|incident-ledger'
72
180
  PINS="${VERIFY_FAST_PINS:-$PINS_DEFAULT}"
73
181
 
74
182
  # --- changed files: committed-since-base UNION uncommitted -------------------
@@ -157,8 +265,30 @@ bash "$ROOT/.claude/scripts/sdk-build-cached.sh" || { echo "[verify-fast] sdk bu
157
265
  # since the last cycle typechecked it. Proving an artifact is not the same as
158
266
  # proving it in place.
159
267
  #
160
- # It takes its own gate lock, so it must NOT be nested inside another gate-run
161
- # slot -- that is a second lock on the same logical gate. It prints the error
268
+ # It is NOT wrapped in gate-run here, and that is now safe rather than a hole:
269
+ # tsc-cached.sh takes its own SLOT internally on a MISS, and takes the folder
270
+ # lock only once that slot is held, so a HIT costs nothing and a MISS queues like
271
+ # every other gate.
272
+ #
273
+ # THE ORDER IS THE POINT, and this comment used to argue the other way: it said
274
+ # wrapping the call out here "would hold a slot through the up-to-900s lock
275
+ # wait". That reasoning is what left tsc-cached taking the LOCK first and the
276
+ # SLOT second -- while THIS script always runs inside `gate-run.sh verify-fast`,
277
+ # i.e. holding a slot already. Two orders, one cycle, and on 2026-09-13 it
278
+ # deadlocked every session on the box three times in ~35 minutes, one of them a
279
+ # production release gate (tsc-cached.sh § SLOT BEFORE LOCK).
280
+ #
281
+ # The trade is real and it is the right way round: a waiter can now burn a slot
282
+ # while the lock holder computes. But the holder is ALWAYS computing and ALWAYS
283
+ # holds a slot itself, so that wait is bounded by one tsc and ends in a cache HIT
284
+ # for the waiter. The old order was bounded by nothing -- it stalled the machine
285
+ # until a human found the right process to kill, and killing the LOCK holder did
286
+ # not even work.
287
+ #
288
+ # The comment this replaces said it "must NOT be nested inside another gate-run
289
+ # slot -- that is a second lock on the same logical gate". That conflated the
290
+ # per-folder dedupe LOCK with the machine-wide SLOT, and it is the instruction
291
+ # that kept the typecheck outside the governor. It prints the error
162
292
  # COUNT on stdout and exits non-zero only when the check could not RUN; an unrun
163
293
  # check is not a passing check, so both a non-zero exit and a non-zero count fail.
164
294
  if [ -x "$ROOT/.claude/scripts/tsc-cached.sh" ] && [ "${VERIFY_FAST_TSC_CACHE:-1}" = "1" ]; then
@@ -214,10 +344,31 @@ fi
214
344
  # then vanishes silently, which is strictly worse than the false RED being fixed.
215
345
  # Measured: the run stopped after "typecheck: 0 errors" and printed no test line
216
346
  # at all. Suspend it around the call, exactly as the FULL_VERIFY branch does.
347
+
348
+ # --- memo probe: never queue for a slot you do not need ----------------------
349
+ # Both test legs below go through test-cached.sh, which reuses a recorded PASS.
350
+ # But the SLOT was taken first and the memo consulted second, so a hit still
351
+ # waited in the governor queue. Measured 2026-09-09 on a saturated box: a single
352
+ # acquisition queued 855s and 1324s -- for work that, on a hit, is a stat() of a
353
+ # stamp file. A hit needs no memory, no forks and no slot.
354
+ #
355
+ # _memo_hit asks test-cached.sh itself (TEST_CACHE_PROBE=1, runs nothing, exits 0
356
+ # on a hit) so there is exactly ONE definition of what a hit is. On a MISS we
357
+ # fall through and take the slot exactly as before -- the gate is never skipped,
358
+ # only the WAIT for a gate that had nothing to do.
359
+ _memo_hit() {
360
+ TEST_CACHE_PROBE=1 bash "$ROOT/.claude/scripts/test-cached.sh" "$@" >/dev/null 2>&1
361
+ }
362
+
217
363
  _rel_out="$(mktemp)"
218
364
  set +e
219
- bash "$GATE" test -- bash "$ROOT/.claude/scripts/test-cached.sh" "$rel" -- related --run $(printf '%s ' $scoped) > "$_rel_out" 2>&1
220
- _rel_rc=$?
365
+ if _memo_hit "$rel" -- related --run $(printf '%s ' $scoped); then
366
+ echo "[verify-fast] related: cache HIT — no slot taken"
367
+ _rel_rc=0
368
+ else
369
+ bash "$GATE" test -- bash "$ROOT/.claude/scripts/test-cached.sh" "$rel" -- related --run $(printf '%s ' $scoped) > "$_rel_out" 2>&1
370
+ _rel_rc=$?
371
+ fi
221
372
  set -e
222
373
  cat "$_rel_out"
223
374
  if [ "$_rel_rc" -eq 0 ]; then
@@ -306,7 +457,9 @@ if [ "${VERIFY_FAST_PINS_ALL:-0}" != "1" ] && [ "$_tier" = "PATCH" ]; then
306
457
  else
307
458
  echo "[verify-fast] tier=$_tier — running the full pin set"
308
459
  fi
309
- if ! bash "$GATE" test -- bash "$ROOT/.claude/scripts/test-cached.sh" "$rel" -- run "${_pins[@]}"; then
460
+ if _memo_hit "$rel" -- run "${_pins[@]}"; then
461
+ echo "[verify-fast] pins: cache HIT — no slot taken"
462
+ elif ! bash "$GATE" test -- bash "$ROOT/.claude/scripts/test-cached.sh" "$rel" -- run "${_pins[@]}"; then
310
463
  echo "[verify-fast] pinned gate FAILED (pins: ${_pins[*]})" >&2
311
464
  exit 1
312
465
  fi
@@ -57,12 +57,15 @@
57
57
  set -uo pipefail
58
58
 
59
59
  ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
60
- NAME=""; PORT=""; BASE="main"; MODE="up"
60
+ # Branches are cut from `dev`, not main: dev is the integration branch every
61
+ # branch lands into, so a branch cut from main starts life missing whatever
62
+ # dev has already integrated. `--base main` still does the old thing.
63
+ NAME=""; PORT=""; BASE="dev"; MODE="up"
61
64
 
62
65
  while [ $# -gt 0 ]; do
63
66
  case "$1" in
64
67
  --port) PORT="${2:-}"; shift 2 ;;
65
- --base) BASE="${2:-main}"; shift 2 ;;
68
+ --base) BASE="${2:-dev}"; shift 2 ;;
66
69
  --no-dev) MODE="setup"; shift ;;
67
70
  --check) MODE="check"; shift ;;
68
71
  --down) MODE="down"; shift ;;
@@ -81,8 +84,21 @@ _port_file() { echo "$WT/.worktree-port"; }
81
84
  # one.ie/web/node_modules is deliberately ABSENT here — it is built below as a
82
85
  # farm of per-package links so that .vite can be worktree-local. A wholesale
83
86
  # symlink would drag main's .vite in with it, which is the corruption above.
87
+ # api/.dev.vars was MISSING from this list until 2026-09-15, and its absence does
88
+ # not read as an absence: the gateway starts, answers 401, and the seven
89
+ # real-TypeDB suites die in mustWrite at fixture setup — so the typedb lane reads
90
+ # as a broken key or a flaky substrate rather than as an unlinked file. It holds
91
+ # GATEWAY_API_KEY and the four TYPEDB_* vars; without it that lane cannot run at all.
92
+ # api/ and sync/ were MISSING until 2026-09-17, and their absence does not read as
93
+ # an absence either: `deploy.sh` typechecks all five services (:181-182), so both
94
+ # died on `TS2688: Cannot find type definition file for '@cloudflare/workers-types'`
95
+ # — a TypeScript error naming TypeScript, caused by an unlinked directory. Measured
96
+ # that day at the ship gate: two of five typechecks red at t≈290s, in a tree whose
97
+ # code was fine, in all four existing worktrees at once.
84
98
  LINKS="node_modules
85
99
  packages/node_modules
100
+ api/node_modules
101
+ sync/node_modules
86
102
  packages/sdk/dist
87
103
  packages/sdk/node_modules
88
104
  pay/backend/node_modules
@@ -91,8 +107,10 @@ one.ie/web/.env
91
107
  one.ie/web/.dev.vars
92
108
  one.ie/web/.wrangler
93
109
  one.ie/web/.astro
110
+ one.ie/web/src/data/fleets.json
94
111
  pay/backend/.env
95
- channels/.env"
112
+ channels/.env
113
+ api/.dev.vars"
96
114
 
97
115
  # Ports are ALLOCATED, never assumed: several worktrees run at once, and a
98
116
  # hardcoded port is how two of them come to think they serve each other's code.
@@ -71,7 +71,7 @@ export default defineConfig({
71
71
  ```
72
72
 
73
73
  **Don't copy a `vite.ssr` list out of this skill.** `astro.config.mjs` §
74
- `vite.ssr.external` is the authority (`.claude/commands/deploy.md` Rule 2 says so
74
+ `vite.ssr.external` is the authority (`.claude/skills/deploy/REFERENCE.md` Rule 2 says so
75
75
  explicitly: *never reconcile that file to a doc*). Note the direction — `recharts`,
76
76
  Stripe, `@xyflow/react`, `motion`, `media-chrome` and the 100ms packages are
77
77
  **external**; `react`, `react-dom`, `@astrojs/react`, `better-auth` and `kysely` are
@@ -224,7 +224,7 @@ The documented ceiling is **3 MiB gzipped** free tier / 10 MiB paid, but this
224
224
  account's real ceiling is **unconfirmed**: deploys at 3.22 MiB (2026-07-08) and
225
225
  4.43 MiB (2026-07-19) both succeeded. Treat the current number as a floor to watch,
226
226
  not a hard gate, and re-run the diagnosis if it keeps climbing.
227
- `.claude/commands/deploy.md § Bundle Size Rules` + § Verified Bundle Numbers is the
227
+ `.claude/skills/deploy/REFERENCE.md § Bundle Size Rules` + § Verified Bundle Numbers is the
228
228
  authority — reconcile to it, not to this table.
229
229
 
230
230
  | Rule | Where | Saves |
@@ -350,6 +350,12 @@ Five sub-workflows live beside this file: `create-page.md`, `create-component.md
350
350
  - **`output: "hybrid"`** throws in Astro 6. Replace with `"server"` + per-page `prerender = true`.
351
351
  - **Never delete a `vite.ssr.external` entry to match a doc snippet** — the config file is
352
352
  the authority and the list is longer than any snippet.
353
+ - **A `{/* … */}` comment in ATTRIBUTE position inside an opening tag is parsed as
354
+ an expression.** Any backtick in the prose opens a template literal, and
355
+ `astro check` then reports `Unterminated string literal` **at EOF**, blaming the
356
+ closing tag while the source looks fine. `tsc` ignores `.astro`, so
357
+ `check:ratchet` is the only gate that catches this class (measured 2026-09-14).
358
+ Put such prose in the frontmatter as `//` comments.
353
359
  - **`platformProxy: { enabled: true }`** is wrong here. This tree uses
354
360
  `{ environment: undefined }` so `astro build` doesn't make Miniflare evaluate the
355
361
  Durable Object before `durableObjectExportsPlugin` has run.
@@ -358,7 +364,7 @@ Five sub-workflows live beside this file: `create-page.md`, `create-component.md
358
364
 
359
365
  - [Astro Cloudflare adapter](https://docs.astro.build/en/guides/integrations-guide/cloudflare/) — authoritative for v13
360
366
  - [CF Workers framework guide — Astro](https://developers.cloudflare.com/workers/frameworks/framework-guides/astro/)
361
- - `.claude/commands/deploy.md` — 8-step pipeline, 5 LOCKED bundle rules, verified bundle numbers, rollback
367
+ - `.claude/commands/deploy.md` — the pipeline, the gates, rollback · `.claude/skills/deploy/REFERENCE.md` — the 5 LOCKED bundle rules + verified numbers (split out 2026-09-17)
362
368
  - `.claude/rules/astro.md` — auto-loaded on `*.astro` edits
363
369
  - `one.ie/web/astro.config.mjs` — the authority for adapter options and every `vite.ssr` list
364
370