@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,64 @@
1
+ #!/usr/bin/env bash
2
+ # sdk-build-cached.sh — build @oneie/sdk, or skip when its sources have not moved.
3
+ #
4
+ # manifest: needs-env
5
+ #
6
+ # WHY. `cd packages/sdk && bun run build` ran on EVERY verify-fast pass, and it is
7
+ # 2.0s of the 2.6s total deterministic gate cost of a /do cycle -- 78%. Measured
8
+ # 2026-09-01: hashing dist before and after a rebuild on an unchanged tree gives
9
+ # the SAME digest. The build is deterministic, so on an unchanged src it is two
10
+ # seconds spent reproducing bytes that were already there.
11
+ #
12
+ # dist is a pure function of src (the same reasoning tsc-cached.sh uses to key on
13
+ # src rather than on dist mtimes, which every rebuild churns). So: fingerprint
14
+ # src, skip when it matches the fingerprint the current dist was built from.
15
+ #
16
+ # SAFETY. The stamp lives INSIDE dist. If dist is deleted, cleaned, or was never
17
+ # built, the stamp goes with it and the build runs -- there is no path where a
18
+ # missing dist reads as cached. A stale-but-present dist cannot survive an src
19
+ # edit either, because the fingerprint covers every tracked file under src.
20
+ #
21
+ # SDK_BUILD_FORCE=1 rebuilds unconditionally. --self-test runs the fixtures.
22
+ set -euo pipefail
23
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
24
+ SDK="$ROOT/packages/sdk"
25
+
26
+ _fp() {
27
+ { git -C "$ROOT" ls-files -s packages/sdk/src packages/sdk/package.json 2>/dev/null
28
+ # uncommitted edits must move the key too -- ls-files -s shows the INDEX,
29
+ # which does not change when a tracked file is edited in the working tree.
30
+ git -C "$ROOT" diff -- packages/sdk/src packages/sdk/package.json 2>/dev/null
31
+ git -C "$ROOT" ls-files --others --exclude-standard packages/sdk/src 2>/dev/null \
32
+ | while IFS= read -r u; do shasum -a 256 "$ROOT/$u" 2>/dev/null; done
33
+ } | shasum -a 256 | cut -d' ' -f1
34
+ }
35
+
36
+ if [ "${1:-}" = "--self-test" ]; then
37
+ fails=0
38
+ b1=$(bash "$0"); b2=$(bash "$0")
39
+ case "$b2" in *"cached"*) echo "ok: second build on an unchanged tree is CACHED";;
40
+ *) echo "FAIL: unchanged tree rebuilt: $b2"; fails=$((fails+1));; esac
41
+ # RED PROOF 1 -- an src edit must force a rebuild
42
+ probe="$SDK/src/.__cache_probe.ts"; echo 'export const __p = 1' > "$probe"
43
+ b3=$(bash "$0")
44
+ case "$b3" in *"cached"*) echo "FAIL: an src edit did NOT invalidate"; fails=$((fails+1));;
45
+ *) echo "ok: an src edit forces a rebuild";; esac
46
+ rm -f "$probe"
47
+ # RED PROOF 2 -- a missing dist must force a rebuild, never read as cached
48
+ rm -f "$SDK/dist/.build-fingerprint"
49
+ b4=$(bash "$0")
50
+ case "$b4" in *"cached"*) echo "FAIL: missing stamp read as cached"; fails=$((fails+1));;
51
+ *) echo "ok: a missing stamp forces a rebuild";; esac
52
+ [ "$fails" -eq 0 ] && { echo "sdk-build-cached: self-test PASS"; exit 0; }
53
+ echo "sdk-build-cached: self-test FAILED ($fails)"; exit 1
54
+ fi
55
+
56
+ STAMP="$SDK/dist/.build-fingerprint"
57
+ want="$(_fp)"
58
+ if [ "${SDK_BUILD_FORCE:-0}" != "1" ] && [ -f "$STAMP" ] && [ "$(cat "$STAMP")" = "$want" ]; then
59
+ echo "[sdk] cached — src unchanged (${want:0:12})"
60
+ exit 0
61
+ fi
62
+ ( cd "$SDK" && bun run build >/dev/null ) || { echo "[sdk] BUILD FAILED" >&2; exit 1; }
63
+ printf '%s' "$want" > "$STAMP"
64
+ echo "[sdk] built (${want:0:12})"
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env bash
2
+ # signal-watch.sh — watch signals travel through the factory's gates, live,
3
+ # with a budget per door and a ledger that tracks speed over time.
4
+ #
5
+ # manifest: needs-env (reads GATEWAY_API_KEY from the shell or one.ie/web/.env;
6
+ # the local lane reads one.ie/web/.dev.vars)
7
+ #
8
+ # USAGE
9
+ # bash .claude/scripts/signal-watch.sh both lanes, once
10
+ # bash .claude/scripts/signal-watch.sh --prod|--local one lane
11
+ # bash .claude/scripts/signal-watch.sh --watch 30 redraw every 30s
12
+ # bash .claude/scripts/signal-watch.sh --json one JSON line per door
13
+ # bash .claude/scripts/signal-watch.sh --self-test the red proofs
14
+ #
15
+ # THE DOORS are the five HTTP hops the factory's own path makes (text/factory-do.md
16
+ # § THE ONE PATH: classify · size · board · claim · close) plus the world door the
17
+ # hooks and do-signal.sh post to, plus the stream the listeners sit on:
18
+ #
19
+ # health GET /api/health the worker answers
20
+ # world:announce POST a canary tagged [signal-watch-wire] on the
21
+ # MARKETPLACE board — intake's door.
22
+ # The wire, and only the wire: zero subscribers matched, so
23
+ # the number is the door's own cost with no fan-out in it.
24
+ # It used to be sent on the caller's own board and the header
25
+ # claimed it "matches nobody by design" — it matched `ceo`,
26
+ # which subscribes to EVERY tag by canon (root CLAUDE.md: the
27
+ # CEO is the default receiver, always listening). Measured
28
+ # 2026-09-08 on prod server-timing, same door, one variable:
29
+ # matched=0 -> data 259/332/401 ms; matched=1 -> data
30
+ # 1535..2066 ms. So ~1.3s per matched subscriber was being
31
+ # read as "the wire". The probe now ASSERTS matched=0 and
32
+ # goes UNRUN if it ever matches — a wire probe that fanned
33
+ # out did not measure the wire, and an unrun door is not a
34
+ # pass. The fan-out's own cost is a separate finding
35
+ # (text/announce-fanout-plan.md), not a budget to widen.
36
+ # BOTH halves are load-bearing and both were measured
37
+ # wrong before: the BOARD (own board -> `ceo`, who
38
+ # follows every tag) and the TAG (`cc` on the marketplace
39
+ # board -> the live `cc-proof-listener`, found 2026-09-08
40
+ # by this very assertion on its first run). Hence a
41
+ # RESERVED tag nobody stakes, on the shared board. If
42
+ # someone ever stakes `signal-watch-wire`, the row goes
43
+ # unrun and says so, rather than quietly reporting a
44
+ # fan-out as the wire.
45
+ # tasks:everywhere POST {workspace:factory-do} the board read
46
+ # factory:size POST {paths:[this file]} the size hop
47
+ # stream GET channels.one.ie/stream/space:vespio time to first byte
48
+ #
49
+ # EVERY ROW CARRIES the server-timing phases the worker itself reports
50
+ # (auth · data · det) and cf-placement, so "slow" is never a single number:
51
+ # you can read WHICH leg paid. Measured 2026-09-05: D1 `one-owners` runs in
52
+ # APAC, TypeDB Cloud in Virginia, and Smart Placement runs one-prod at ORD about
53
+ # one call in three — so every substrate call pays one Pacific leg somewhere.
54
+ #
55
+ # VERDICTS, four states, the same vocabulary as do-w4-gates.sh:
56
+ # pass 200, the receiver answered `outcome:result`, wall <= budget
57
+ # fail dropped (no response inside 15s) · non-200 · a refusal · over budget
58
+ # n/a the door is not on this box (no local server, no listener config)
59
+ # unrun the door could not be TRIED (no key) — never read as a pass
60
+ # Exit 0 = every door pass or n/a · 1 = any fail · 3 = any unrun and no fail.
61
+ #
62
+ # LEDGER: one JSON line per door per run appended to .claude/.signal-watch.jsonl
63
+ # (gitignored). `--no-ledger` skips it. Speed is tracked, never remembered.
64
+ set -uo pipefail
65
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
66
+ PROD_URL="${SIGNAL_WATCH_PROD:-https://one.ie}"
67
+ LOCAL_URL="${SIGNAL_WATCH_LOCAL:-http://localhost:4321}"
68
+ STREAM_URL="${SIGNAL_WATCH_STREAM:-https://channels.one.ie/stream/space:vespio}"
69
+ LEDGER="${SIGNAL_WATCH_LEDGER:-$ROOT/.claude/.signal-watch.jsonl}"
70
+ CURL_MAX="${SIGNAL_WATCH_MAX:-15}"
71
+ BUDGET_SCALE="${SIGNAL_WATCH_BUDGET_SCALE:-1}" # self-test shrinks budgets with this
72
+
73
+ LANES="prod local"; WATCH=0; JSON=0; LEDGER_ON=1
74
+ while [ $# -gt 0 ]; do
75
+ case "$1" in
76
+ --prod) LANES="prod" ;; --local) LANES="local" ;;
77
+ --watch) WATCH="${2:-30}"; shift ;;
78
+ --json) JSON=1 ;; --no-ledger) LEDGER_ON=0 ;;
79
+ --self-test) SELF_TEST=1 ;;
80
+ -h|--help) sed -n 2,45p "$0"; exit 0 ;;
81
+ *) echo "signal-watch: unknown arg $1" >&2; exit 2 ;;
82
+ esac; shift
83
+ done
84
+
85
+ PASS=0; FAIL=0; NA=0; UNRUN=0
86
+ _key() { # $1 = env file; the shell wins; the value is never printed
87
+ local f="$1" v="${GATEWAY_API_KEY:-}"
88
+ [ -n "$v" ] && { printf '%s' "$v"; return; }
89
+ [ -f "$f" ] && grep -E '^GATEWAY_API_KEY=' "$f" | head -1 | cut -d= -f2- | tr -d '"'
90
+ }
91
+ _budget() { awk -v b="$1" -v s="$BUDGET_SCALE" 'BEGIN{printf "%d", b*s}'; }
92
+ _row() { # lane door verdict wall budget placement phases note
93
+ if [ "$JSON" = 1 ]; then
94
+ printf '{"ts":"%s","lane":"%s","door":"%s","verdict":"%s","wall_ms":%s,"budget_ms":%s,"placement":"%s","phases":"%s","note":"%s"}\n' \
95
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$1" "$2" "$3" "${4:-null}" "$5" "$6" "$7" "$8"
96
+ else
97
+ printf ' %-6s %-18s %-5s %7s ms budget %5s %-11s %-34s %s\n' "$1" "$2" "$3" "${4:--}" "$5" "${6:--}" "${7:--}" "$8"
98
+ fi
99
+ if [ "$LEDGER_ON" = 1 ]; then
100
+ printf '{"ts":"%s","lane":"%s","door":"%s","verdict":"%s","wall_ms":%s,"budget_ms":%s,"placement":"%s","phases":"%s"}\n' \
101
+ "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$1" "$2" "$3" "${4:-null}" "$5" "$6" "$7" >> "$LEDGER" 2>/dev/null || true
102
+ fi
103
+ case "$3" in pass) PASS=$((PASS+1));; fail) FAIL=$((FAIL+1));; n/a) NA=$((NA+1));; unrun) UNRUN=$((UNRUN+1));; esac
104
+ }
105
+
106
+ # door <lane> <name> <method> <url> <payload|-> <budget_ms> <key|-> [expect|-]
107
+ # `expect` is a fixed string the RESPONSE BODY must contain for the number to
108
+ # mean what the door claims to measure. Absent it, a door can keep answering 200
109
+ # fast while measuring something else entirely — which is exactly how the
110
+ # announce canary reported "the wire" while paying a full fan-out. A miss is
111
+ # UNRUN, never fail and never pass: the door ran, but not the door we named.
112
+ door() {
113
+ local lane="$1" name="$2" method="$3" url="$4" payload="$5" budget key="$7" expect="${8:--}" hdr body out code wall placement phases verdict note=""
114
+ budget=$(_budget "$6")
115
+ hdr=$(mktemp); body=$(mktemp)
116
+ if [ "$method" = POST ] && [ "$key" = "-" ]; then
117
+ _row "$lane" "$name" unrun "" "$budget" "" "" "no GATEWAY_API_KEY — not tried"; rm -f "$hdr" "$body"; return
118
+ fi
119
+ # bash 3.2 + set -u: an EMPTY array expands as unbound. The ${a[@]+"${a[@]}"} idiom is the only portable form.
120
+ local cfg=""; [ "$key" != "-" ] && { cfg=$(mktemp); chmod 600 "$cfg"; printf 'header = "Authorization: Bearer %s"\n' "$key" > "$cfg"; }
121
+ local -a auth=(); [ -n "$cfg" ] && auth=(--config "$cfg")
122
+ if [ "$method" = POST ]; then
123
+ out=$(curl -s -D "$hdr" -o "$body" --max-time "$CURL_MAX" -X POST "$url" -H 'content-type: application/json' ${auth[@]+"${auth[@]}"} -d "$payload" -w '%{http_code} %{time_total}' 2>/dev/null)
124
+ else
125
+ out=$(curl -s -D "$hdr" -o "$body" --max-time "$CURL_MAX" "$url" ${auth[@]+"${auth[@]}"} -w '%{http_code} %{time_total}' 2>/dev/null)
126
+ fi
127
+ [ -n "$cfg" ] && rm -f "$cfg"
128
+ code="${out%% *}"; wall=$(awk -v t="${out##* }" 'BEGIN{printf "%d", t*1000}')
129
+ placement=$(grep -i '^cf-placement:' "$hdr" | head -1 | cut -d' ' -f2- | tr -d '\r')
130
+ phases=$(grep -i '^server-timing:' "$hdr" | head -1 | grep -oE '(auth|data|det);dur=[0-9]+' | sed -E 's/;dur=/=/' | paste -sd' ' -)
131
+ if [ "$code" = "000" ] || [ -z "$code" ]; then verdict=fail; note="DROPPED — no response inside ${CURL_MAX}s"
132
+ elif [ "$code" != "200" ]; then verdict=fail; note="http $code $(head -c 80 "$body" | tr -d '\n')"
133
+ elif [ "$method" = POST ] && ! grep -q '"outcome":"result"' "$body"; then verdict=fail; note="refused: $(head -c 100 "$body" | tr -d '\n')"
134
+ elif [ "$method" = POST ] && grep -q '"ok":false' "$body"; then verdict=unrun; note="refused before the work: $(grep -oE '"error":"[^"]{0,80}' "$body" | head -1 | cut -d'"' -f4)"
135
+ elif [ "$expect" != "-" ] && ! grep -qF "$expect" "$body"; then verdict=unrun; note="not the door we named: body lacks $expect — $(head -c 60 "$body" | tr -d '\n')"
136
+ elif [ "$wall" -gt "$budget" ]; then verdict=fail; note="over budget by $((wall-budget)) ms"
137
+ else verdict=pass; fi
138
+ _row "$lane" "$name" "$verdict" "$wall" "$budget" "${placement:-}" "${phases:-}" "$note"
139
+ rm -f "$hdr" "$body"
140
+ }
141
+
142
+ stream_door() {
143
+ local budget cfg="$HOME/.cc-connect/.auth.conf" out code ttfb wall verdict note=""
144
+ budget=$(_budget 600)
145
+ [ -f "$cfg" ] || { _row prod stream n/a "" "$budget" "" "" "no ~/.cc-connect/.auth.conf on this box"; return; }
146
+ out=$(curl -s -N -o /dev/null --max-time 4 --config "$cfg" "$STREAM_URL?since=$(date +%s)000" -w '%{http_code} %{time_starttransfer}' 2>/dev/null)
147
+ code="${out%% *}"; ttfb=$(awk -v t="${out##* }" 'BEGIN{printf "%d", t*1000}')
148
+ if [ "$code" != "200" ]; then verdict=fail; note="http ${code:-000}"
149
+ elif [ "$ttfb" -gt "$budget" ]; then verdict=fail; note="first byte over budget"
150
+ else verdict=pass; note="first byte"; fi
151
+ _row prod stream "$verdict" "$ttfb" "$budget" "" "" "$note"
152
+ }
153
+
154
+ listeners() {
155
+ command -v launchctl >/dev/null 2>&1 || { _row prod listeners n/a "" 0 "" "" "no launchctl"; return; }
156
+ local alive; alive=$(launchctl list 2>/dev/null | awk '/ie\.one\.(cc-vespio|cc-oo|tg-listen)$/ && $1 ~ /^[0-9]+$/ {n++} END{print n+0}')
157
+ if [ "$alive" -gt 0 ]; then _row prod listeners pass "" 0 "" "" "$alive listener(s) alive (cc-vespio · cc-oo · tg-listen)"
158
+ else _row prod listeners fail "" 0 "" "" "no ie.one.* listener has a pid"; fi
159
+ }
160
+
161
+ lane() { # prod|local
162
+ local l="$1" base key
163
+ # The prod credential file honours ONE_ENV_FILE / DO_ENV_FILE, like every other
164
+ # credential read in the harness (factory-repo.sh --check-env-indirection).
165
+ # A relative path is taken from $ROOT; the shell's GATEWAY_API_KEY still wins.
166
+ local env_file="${ONE_ENV_FILE:-${DO_ENV_FILE:-one.ie/web/.env}}"
167
+ case "$env_file" in /*) ;; *) env_file="$ROOT/$env_file" ;; esac
168
+ if [ "$l" = prod ]; then base="$PROD_URL"; key=$(_key "$env_file")
169
+ else
170
+ base="$LOCAL_URL"; key=$(_key "$ROOT/one.ie/web/.dev.vars")
171
+ if ! curl -s -o /dev/null --max-time 3 "$base/api/health"; then
172
+ _row local health n/a "" 0 "" "" "no dev server at $base"; return
173
+ fi
174
+ fi
175
+ [ -z "$key" ] && key="-"
176
+ # Budgets are a RATCHET: set at the measured p90 the day the door was first
177
+ # watched (2026-09-05 — announce 1.3-1.8s, board/size 0.8-1.5s), lowered only
178
+ # after a measured improvement ships. Never raised to make a red row green.
179
+ # announce: 2000 → 800 after the parallel-read ship (2026-09-05, measured 149-379 ms).
180
+ # UNCHANGED 2026-09-08 on purpose. The door it describes is now the WIRE door
181
+ # (board=marketplace, matched=0), whose data phase measures 259-401 ms — the
182
+ # same range 800 was set against. The wall it is compared to also carries the
183
+ # CLIENT's egress, which is not the worker's: `health` does det=0 ms of server
184
+ # work and has walked 134 → 72 → 437 → 463 ms across the ledger purely on where
185
+ # the laptop was sitting. So a marginal announce/health miss can be this box's
186
+ # network, not the door. Whether these budgets should be worker-phase budgets
187
+ # rather than wall budgets is a RECALIBRATION — a human decision, deliberately
188
+ # not taken here. A budget moved to fit an observation stops meaning anything.
189
+ local b1 b2 b3; if [ "$l" = prod ]; then b1=400; b2=1500; b3=800; else b1=150; b2=300; b3=300; fi
190
+ door "$l" health GET "$base/api/health" - "$b1" -
191
+ # SIGNAL_WATCH_WIRE_OWN_BOARD=1 exists for --self-test case 4 ONLY: DROPPING
192
+ # the board key sends the canary to the caller's own board, where `ceo` matches
193
+ # every tag by canon — the durable red half of the assertion below. (Setting
194
+ # `board` to an arbitrary slug does NOT work: the receiver's Zod schema rejects
195
+ # it with a 400, which is a different failure and proves nothing.) Never set
196
+ # this in a real run.
197
+ local wire_board='"board":"marketplace",'
198
+ if [ "${SIGNAL_WATCH_WIRE_OWN_BOARD:-0}" = 1 ]; then wire_board=''; fi
199
+ door "$l" world:announce POST "$base/api/ask/world:announce" \
200
+ "{\"data\":{\"tags\":[\"signal-watch-wire\"],${wire_board}\"type\":\"signal:canary\",\"text\":\"signal-watch $(date -u +%H:%M:%SZ)\",\"priority\":\"fyi\",\"slug\":\"one\"}}" "$b3" "$key" '"matched":0'
201
+ door "$l" tasks:everywhere POST "$base/api/ask/tasks:everywhere" '{"data":{"workspace":"factory-do","limit":200}}' "$b2" "$key"
202
+ door "$l" factory:size POST "$base/api/ask/factory:size" '{"data":{"paths":[".claude/scripts/signal-watch.sh"]}}' "$b2" "$key"
203
+ }
204
+
205
+ run_once() {
206
+ PASS=0; FAIL=0; NA=0; UNRUN=0
207
+ [ "$JSON" = 1 ] || { echo "signal-watch · $(date '+%Y-%m-%d %H:%M:%S') · prod=$PROD_URL local=$LOCAL_URL"; echo; }
208
+ for l in $LANES; do lane "$l"; done
209
+ case " $LANES " in *" prod "*) stream_door; listeners ;; esac
210
+ [ "$JSON" = 1 ] || { echo; echo "SIGNAL-WATCH: pass=$PASS fail=$FAIL n/a=$NA unrun=$UNRUN$([ "$LEDGER_ON" = 1 ] && printf ' · ledger %s' "$LEDGER")"; }
211
+ [ "$FAIL" -gt 0 ] && return 1; [ "$UNRUN" -gt 0 ] && return 3; return 0
212
+ }
213
+
214
+ if [ "${SELF_TEST:-0}" = 1 ]; then
215
+ fails=0
216
+ echo "== 1. a dropped door is a fail, and the exit says so"
217
+ out=$(SIGNAL_WATCH_PROD=http://127.0.0.1:1 SIGNAL_WATCH_MAX=2 bash "$0" --prod --no-ledger 2>&1); rc=$?
218
+ [ "$rc" -eq 1 ] && grep -q "DROPPED" <<<"$out" && echo " ok exit 1, DROPPED named" || { echo " FAIL rc=$rc"; echo "$out" | tail -4; fails=$((fails+1)); }
219
+ echo "== 2. a door over budget is a fail, never a slow pass"
220
+ out=$(SIGNAL_WATCH_BUDGET_SCALE=0.0001 bash "$0" --prod --no-ledger 2>&1); rc=$?
221
+ [ "$rc" -eq 1 ] && grep -q "over budget" <<<"$out" && echo " ok exit 1, over budget named" || { echo " FAIL rc=$rc"; echo "$out" | tail -4; fails=$((fails+1)); }
222
+ echo "== 3. no key is UNRUN (exit 3), not a pass — the door was never tried"
223
+ # the .env key resolves on a configured box, so prove the branch from a stub root with no .env
224
+ tmp=$(mktemp -d); mkdir -p "$tmp/.claude/scripts" "$tmp/one.ie/web"; cp "$0" "$tmp/.claude/scripts/"
225
+ out=$(GATEWAY_API_KEY= SIGNAL_WATCH_BUDGET_SCALE=100 bash "$tmp/.claude/scripts/signal-watch.sh" --prod --no-ledger 2>&1); rc=$?
226
+ [ "$rc" -eq 3 ] && grep -q "unrun" <<<"$out" && echo " ok exit 3, unrun rows" || { echo " FAIL rc=$rc"; echo "$out" | tail -4; fails=$((fails+1)); }
227
+ rm -rf "$tmp"
228
+ echo "== 4. a wire probe that MATCHED somebody is unrun (exit 3), not a fast pass"
229
+ # Red half: point the canary back at the caller's own board, where `ceo`
230
+ # subscribes to every tag. The door still answers 200 with outcome=result —
231
+ # only the assertion catches it.
232
+ out=$(SIGNAL_WATCH_WIRE_OWN_BOARD=1 SIGNAL_WATCH_BUDGET_SCALE=100 bash "$0" --prod --no-ledger 2>&1); rc=$?
233
+ [ "$rc" -eq 3 ] && grep -q 'not the door we named' <<<"$out" && echo " ok exit 3, fan-out named as not-the-wire" || { echo " FAIL rc=$rc"; echo "$out" | tail -4; fails=$((fails+1)); }
234
+ echo "signal-watch --self-test: $fails failed"
235
+ exit "$fails"
236
+ fi
237
+
238
+ if [ "$WATCH" -gt 0 ] 2>/dev/null; then
239
+ while :; do clear; run_once; sleep "$WATCH"; done
240
+ fi
241
+ run_once
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env bash
2
+ # Publish the harness skills in .claude/skills/ into the substrate catalog, so the
3
+ # skills /do actually uses are reachable through `skill:run` and `skills:list`
4
+ # instead of only as local files an agent must already be on this disk to read.
5
+ #
6
+ # The two on-disk shapes map 1:1 onto the two shapes db/skills.ts already reads:
7
+ # .claude/skills/<name>/SKILL.md -> R2 <slug>/skills/<name>/SKILL.md
8
+ # .claude/skills/<name>.md -> R2 <slug>/skills/<name>.md
9
+ # So this is a copy, not a conversion — nothing here reformats a skill body.
10
+ #
11
+ # The SECOND source is the shared skill library in one.ie/ai/skills/, which is what
12
+ # an executor actually runs — `foundation:deep` loads each elevate-foundation-*
13
+ # SKILL.md through getSkillOrRef, so a skill that is on disk but not in R2 makes the
14
+ # run fail closed (`skill_not_found:<name>`). Same copy, same key shape:
15
+ # one.ie/ai/skills/<name>/SKILL.md -> R2 <slug>/skills/<name>/SKILL.md
16
+ #
17
+ # That dir holds 140+ skills, so it is filtered by --ai-pattern rather than published
18
+ # wholesale: a routine run of this script must not silently push the whole library to
19
+ # prod R2. The default covers exactly the 10 skills in deep-sequence.ts SKILL_ORDER.
20
+ #
21
+ # Usage:
22
+ # skills-publish.sh [--slug one] [--dry-run] [--bucket one-content]
23
+ # [--ai-pattern 'elevate-foundation-*'] [--no-ai]
24
+ #
25
+ # Re-running is safe: an R2 put is a full overwrite of one key, and the catalog is
26
+ # keyed by name, so a republished skill replaces itself rather than accumulating.
27
+ # Deletions are NOT mirrored — a skill removed from disk stays in the catalog until
28
+ # it is deleted deliberately, because unpublishing is a decision, not a side effect.
29
+ set -euo pipefail
30
+
31
+ SLUG="one"
32
+ BUCKET="one-content"
33
+ DRY=false
34
+ AI_PATTERN='elevate-foundation-*'
35
+ AI=true
36
+ while [ $# -gt 0 ]; do
37
+ case "$1" in
38
+ --slug) SLUG="$2"; shift 2 ;;
39
+ --bucket) BUCKET="$2"; shift 2 ;;
40
+ --ai-pattern) AI_PATTERN="$2"; shift 2 ;;
41
+ --no-ai) AI=false; shift ;;
42
+ --dry-run) DRY=true; shift ;;
43
+ *) echo "unknown arg: $1" >&2; exit 2 ;;
44
+ esac
45
+ done
46
+
47
+ _ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
48
+ SKILLS="$_ROOT/.claude/skills"
49
+ AI_SKILLS="$_ROOT/one.ie/ai/skills"
50
+ [ -d "$SKILLS" ] || { echo "no skills dir at $SKILLS" >&2; exit 1; }
51
+
52
+ # wrangler resolves its account from one.ie/web's config; run from there.
53
+ cd "$_ROOT/one.ie/web"
54
+
55
+ ok=0; fail=0; failed=""
56
+
57
+ _put() { # <r2-key> <local-file>
58
+ if [ "$DRY" = true ]; then echo "DRY $1"; ok=$((ok + 1)); return 0; fi
59
+ # Output captured, then matched — never `| grep -q`. In a pipefail script a
60
+ # matching grep exits first and the producer takes SIGPIPE, which reads as a
61
+ # failure on success (see .claude/CLAUDE.md § TRAP).
62
+ local out
63
+ if out=$(npx wrangler r2 object put "$BUCKET/$1" --file="$2" --remote 2>&1); then
64
+ ok=$((ok + 1))
65
+ else
66
+ fail=$((fail + 1)); failed="$failed $1"
67
+ printf '%s\n' "$out" | tail -2 >&2
68
+ fi
69
+ }
70
+
71
+ for d in "$SKILLS"/*/; do
72
+ [ -f "$d/SKILL.md" ] || continue
73
+ _put "$SLUG/skills/$(basename "$d")/SKILL.md" "$d/SKILL.md"
74
+ done
75
+
76
+ for f in "$SKILLS"/*.md; do
77
+ [ -f "$f" ] || continue
78
+ _put "$SLUG/skills/$(basename "$f")" "$f"
79
+ done
80
+
81
+ ai=0
82
+ if [ "$AI" = true ] && [ -d "$AI_SKILLS" ]; then
83
+ for d in "$AI_SKILLS"/$AI_PATTERN/; do
84
+ [ -f "$d/SKILL.md" ] || continue
85
+ _put "$SLUG/skills/$(basename "$d")/SKILL.md" "$d/SKILL.md"
86
+ ai=$((ai + 1))
87
+ done
88
+ if [ "$ai" -eq 0 ]; then
89
+ echo "skills-publish: WARNING no ai/skills matched --ai-pattern '$AI_PATTERN'" >&2
90
+ fi
91
+ fi
92
+
93
+ echo "skills-publish: $ok published ($ai from ai/skills), $fail failed (slug=$SLUG bucket=$BUCKET)"
94
+ [ "$fail" -eq 0 ] || { echo "failed:$failed" >&2; exit 1; }
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bash
2
+ # speed-cache-check.sh — proves domain-memo.ts's cross-isolate (L2) cache is a
3
+ # real behaviour, not a presence grep.
4
+ #
5
+ # WHY THIS EXISTS: an earlier draft of "prove the cache works" matched the
6
+ # word "CACHED" inside a docblock and passed on nothing — a presence grep
7
+ # proves a SHAPE, never a BEHAVIOUR (text/learnings.md, project_fail_open_aggregate_runners).
8
+ # This check instead runs the real vitest suite twice against two different
9
+ # trees of the SAME file (working tree vs `git show HEAD:<path>`, the shape
10
+ # before this cycle's L2 fix landed) and asserts the exit code differs in the
11
+ # expected direction:
12
+ #
13
+ # RED (pre-fix domain-memo.ts): "a cold isolate ... still skips D1 via L2"
14
+ # fails — a per-isolate Map has no cross-isolate reach, so a fresh
15
+ # `vi.resetModules()` import always re-pays D1.
16
+ # GREEN (this cycle's domain-memo.ts): the same test passes — a fresh
17
+ # module import still finds the row in the shared `caches.default`
18
+ # store the "warm" isolate wrote, and never touches D1.
19
+ #
20
+ # The GREEN half is what a normal CI run enforces (`bun run verify` already
21
+ # runs tests/unit/domain-memo.test.ts). This script exists for the RED half —
22
+ # proving the test can fail, and fails for the SPECIFIC reason claimed (a cold
23
+ # isolate re-pays D1), not some unrelated breakage.
24
+ #
25
+ # Usage: bash .claude/scripts/speed-cache-check.sh
26
+ # Exits 0 only if: RED run fails on the cold-isolate test AND GREEN run
27
+ # (the current working tree) passes the whole file.
28
+
29
+ set -euo pipefail
30
+
31
+ # _GATE — see governor-doors-check.sh "compute sites". A gate_lock dedupes
32
+ # identical work; only a SLOT bounds N worktrees running N computes at once.
33
+ # Empty inside an existing gate so the outer slot is inherited, never doubled.
34
+ _GATE=()
35
+ if [ "${GOVERN_IN_GATE:-0}" != "1" ]; then
36
+ _GR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/gate-run.sh"
37
+ [ -f "$_GR" ] && _GATE=( bash "$_GR" "compute:$(basename "${BASH_SOURCE[0]}")" -- )
38
+ fi
39
+
40
+
41
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
42
+ WEB="$ROOT/one.ie/web"
43
+ REL_MEMO="one.ie/web/src/lib/domain-memo.ts"
44
+ REL_TEST="one.ie/web/tests/unit/domain-memo.test.ts"
45
+ TEST_FILE="tests/unit/domain-memo.test.ts"
46
+ COLD_TEST_NAME="a cold isolate"
47
+
48
+ cd "$ROOT"
49
+
50
+ if [ ! -f "$REL_MEMO" ]; then
51
+ echo "[speed-cache-check] missing $REL_MEMO — nothing to check" >&2
52
+ exit 2
53
+ fi
54
+
55
+ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
56
+ echo "[speed-cache-check] not a git repo — cannot diff RED vs GREEN" >&2
57
+ exit 2
58
+ fi
59
+
60
+ # The RED half needs a tree where domain-memo.ts has NO L2 (Cache API) layer.
61
+ # If HEAD already has the fix (this cycle already committed), fall back to a
62
+ # hand-written broken copy so the check still proves something rather than
63
+ # silently degrading to "n/a".
64
+ HEAD_HAS_L2=0
65
+ if git show HEAD:"$REL_MEMO" 2>/dev/null | grep -q "caches\.default"; then
66
+ HEAD_HAS_L2=1
67
+ fi
68
+
69
+ TMP_BROKEN=""
70
+ cleanup() {
71
+ if [ -n "$TMP_BROKEN" ] && [ -f "$TMP_BROKEN" ]; then
72
+ rm -f "$TMP_BROKEN"
73
+ fi
74
+ if [ "${STASHED:-0}" = "1" ]; then
75
+ git stash pop --quiet
76
+ fi
77
+ }
78
+ trap cleanup EXIT
79
+
80
+ STASHED=0
81
+ RED_SOURCE_DESC=""
82
+
83
+ if [ "$HEAD_HAS_L2" = "0" ]; then
84
+ RED_SOURCE_DESC="git HEAD:$REL_MEMO (pre-fix shape)"
85
+ # Stash ONLY this file's working-tree changes (never a blanket stash —
86
+ # .claude/CLAUDE.md's git-add-guard rule, and just good hygiene: this repo
87
+ # has other unrelated modified files in play from sibling /do cycles).
88
+ if ! git diff --quiet -- "$REL_MEMO"; then
89
+ git stash push --quiet -- "$REL_MEMO"
90
+ STASHED=1
91
+ fi
92
+ else
93
+ # HEAD already carries the L2 fix (e.g. re-run after commit) — synthesize
94
+ # the pre-fix shape by stripping the L2 read/write calls out of a scratch
95
+ # copy, then swap it in the same way (stash, write broken, test, restore).
96
+ RED_SOURCE_DESC="synthesized pre-L2 copy (HEAD already has the fix)"
97
+ TMP_BROKEN="$(mktemp)"
98
+ python3 - "$REL_MEMO" "$TMP_BROKEN" <<'PY'
99
+ import re, sys
100
+ src_path, out_path = sys.argv[1], sys.argv[2]
101
+ with open(src_path) as f:
102
+ src = f.read()
103
+ # Remove the L2 read/write calls from readDomainRowMemo so it behaves exactly
104
+ # like the original per-isolate-only implementation.
105
+ src = src.replace(
106
+ """\tconst edgeRow = await readEdgeCache(host);
107
+ \tif (edgeRow !== undefined) {
108
+ \t\tif (_cache.size >= MAX_ENTRIES) _cache.clear();
109
+ \t\t_cache.set(host, { row: edgeRow, at: Date.now() });
110
+ \t\treturn edgeRow;
111
+ \t}
112
+
113
+ """,
114
+ "",
115
+ )
116
+ src = src.replace("\twriteEdgeCache(host, row);\n", "")
117
+ with open(out_path, "w") as f:
118
+ f.write(src)
119
+ PY
120
+ cp "$REL_MEMO" "${REL_MEMO}.speed-cache-check.bak"
121
+ cp "$TMP_BROKEN" "$REL_MEMO"
122
+ STASHED=2
123
+ cleanup() {
124
+ mv "${REL_MEMO}.speed-cache-check.bak" "$REL_MEMO"
125
+ rm -f "$TMP_BROKEN"
126
+ }
127
+ trap cleanup EXIT
128
+ fi
129
+
130
+ echo "[speed-cache-check] RED run — $RED_SOURCE_DESC"
131
+ cd "$WEB"
132
+ set +e
133
+ RED_OUT="$("${_GATE[@]}" bunx vitest run "$TEST_FILE" -t "$COLD_TEST_NAME" 2>&1)"
134
+ RED_STATUS=$?
135
+ set -e
136
+ cd "$ROOT"
137
+
138
+ if [ $RED_STATUS -eq 0 ]; then
139
+ echo "[speed-cache-check] FAIL: the cold-isolate test PASSED against the pre-fix shape." >&2
140
+ echo " That means the test isn't proving cross-isolate behaviour — it would pass on nothing." >&2
141
+ echo "$RED_OUT" | tail -40 >&2
142
+ exit 1
143
+ fi
144
+ if ! printf '%s' "$RED_OUT" | grep -q "$COLD_TEST_NAME"; then
145
+ echo "[speed-cache-check] FAIL: RED run failed but not on the named test — some other breakage." >&2
146
+ echo "$RED_OUT" | tail -60 >&2
147
+ exit 1
148
+ fi
149
+ echo "[speed-cache-check] RED confirmed — cold-isolate test fails without L2 (as expected)."
150
+
151
+ # Restore the fixed file before the GREEN run.
152
+ trap - EXIT
153
+ cleanup
154
+ STASHED=0
155
+ TMP_BROKEN=""
156
+
157
+ echo "[speed-cache-check] GREEN run — working tree $REL_MEMO"
158
+ cd "$WEB"
159
+ set +e
160
+ GREEN_OUT="$("${_GATE[@]}" bunx vitest run "$TEST_FILE" 2>&1)"
161
+ GREEN_STATUS=$?
162
+ set -e
163
+ cd "$ROOT"
164
+
165
+ if [ $GREEN_STATUS -ne 0 ]; then
166
+ echo "[speed-cache-check] FAIL: the full domain-memo suite does not pass on the fixed file." >&2
167
+ echo "$GREEN_OUT" | tail -60 >&2
168
+ exit 1
169
+ fi
170
+
171
+ echo "[speed-cache-check] GREEN confirmed — full domain-memo.test.ts passes with L2 wired."
172
+ echo "[speed-cache-check] OK — the cross-isolate cache is proven by behaviour, not by grep."
173
+ exit 0