@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
@@ -57,6 +57,16 @@ head_() { printf '\n== %s\n' "$*"; }
57
57
  # that degrade to no-ops when absent → ships
58
58
  # monorepo-only hard-asserts against THIS tree; refuses
59
59
  # without it → never ships
60
+ #
61
+ # Why gc-content-check.sh is `needs-env` and not `portable`: it builds its own
62
+ # sandbox and never reaches into this tree, so it is portable by behaviour — but
63
+ # it must spell `one.ie/web/.astro` literally, because that path is hardcoded in
64
+ # lib/gc-finished.sh's GC_EPHEMERAL default and a sandbox that used a neutral
65
+ # name would stop exercising the filter it exists to test. Rather than teach the
66
+ # matcher an exemption that would also silence a real reach (`$ROOT/one.ie/ai`
67
+ # in close-owner.sh is the same shape), the bucket is the answer: needs-env
68
+ # ships identically and claims less. /vespio § 0 — a misbehaving bucket is a
69
+ # reclassification, not a bug.
60
70
  # ---------------------------------------------------------------------------
61
71
  manifest() {
62
72
  cat <<'MANIFEST'
@@ -64,29 +74,49 @@ portable browser-check.mjs
64
74
  portable chrome.mjs
65
75
  portable do-analyze.sh
66
76
  portable gate-reaper.sh
77
+ portable gate-watchdog.sh
78
+ portable health.sh
67
79
  portable govern-bound-check.sh
68
80
  portable factory-width.sh
81
+ portable factory-executor-check.mjs
82
+ portable factory-peak.sh
69
83
  portable do-learn-loop.sh
70
84
  portable do-promise-lint.sh
85
+ portable do-world-check.sh
71
86
  portable do-recon-cache.sh
72
87
  portable do-cycle-shape-check.sh
73
88
  portable do-next.sh
74
89
  portable do-plan-json.sh
75
90
  portable do-test-gate.sh
76
91
  portable do-tick.sh
92
+ portable do-prove-selftest.sh
77
93
  portable do-validate-armed.py
94
+ portable factory-brief-check.sh
78
95
  portable fixtures/triage-dupe.md
79
96
  portable gate-run.sh
97
+ portable memory-index-budget.sh
98
+ portable gate-reaper-check.sh
80
99
  portable govern-mem-check.sh
81
100
  portable governor-escape-check.sh
101
+ portable lib/gc-finished.sh
82
102
  portable lib/govern.sh
83
103
  portable lib/govern.ts
84
104
  portable package.json
85
105
  portable w1-recon.ts
86
106
  portable wf-check.mjs
87
107
  needs-env cc-connect.sh
108
+ needs-env download-stats.sh
109
+ needs-env gh-traffic-capture.sh
110
+ needs-env verify-board-doors.sh
111
+ needs-env blocks-manifest-cached.sh
112
+ needs-env close-metrics.sh
113
+ needs-env close-owner.sh
114
+ needs-env do-close.sh
115
+ needs-env do-decide.sh
116
+ needs-env gc-content-check.sh
88
117
  needs-env do-accept.sh
89
118
  needs-env do-auto.sh
119
+ needs-env do-board.sh
90
120
  needs-env do-derives-check.sh
91
121
  needs-env do-fleet.sh
92
122
  needs-env do-folder.sh
@@ -125,7 +155,16 @@ needs-env reconcile-allow.txt
125
155
  needs-env rubric-weights.json
126
156
  needs-env w4-rubric.ts
127
157
  needs-env govern-claims-check.sh
158
+ needs-env govern-order-check.sh
128
159
  needs-env signal-watch.sh
160
+ monorepo-only thread-name-backfill.ts
161
+ monorepo-only signal-meta-backfill.ts
162
+ monorepo-only task-titles-dump.ts
163
+ monorepo-only CLAUDE.md
164
+ monorepo-only agent-actor-parity.sh
165
+ monorepo-only chat-context-check.sh
166
+ monorepo-only triage-shape-check.sh
167
+ monorepo-only deploy-ready.sh
129
168
  monorepo-only substrate-env-parity.mjs
130
169
  monorepo-only typedb-flake-check.sh
131
170
  monorepo-only env-sync.sh
@@ -137,14 +176,24 @@ monorepo-only orphan-modules.mjs
137
176
  needs-env worktree-preview.sh
138
177
  needs-env factory-walk.sh
139
178
  needs-env factory-turn.sh
179
+ needs-env factory-emit.sh
180
+ needs-env factory-close-check.sh
181
+ needs-env preview-fd-check.sh
182
+ portable factory-review-check.mjs
183
+ portable pr-body.sh
184
+ monorepo-only deploy-record.sh
185
+ monorepo-only deploy-emit.sh
186
+ needs-env fixtures/factory-brief-real.md
140
187
  monorepo-only agentverse-audit.sh
141
188
  monorepo-only asi-walk.sh
142
189
  monorepo-only cc-events-proof.sh
190
+ monorepo-only db-sync-lock-check.sh
143
191
  monorepo-only skills-publish.sh
144
192
  monorepo-only deploy.sh
145
193
  monorepo-only factory-ship.sh
146
194
  monorepo-only blocks-ratchet.sh
147
195
  monorepo-only blocks-manifest.mjs
196
+ monorepo-only id-inventory.mjs
148
197
  monorepo-only fleet-manifest.mjs
149
198
  monorepo-only one-agents.mjs
150
199
  monorepo-only blocks-render-probe.mjs
@@ -171,7 +220,9 @@ monorepo-only livekit-ratchet.sh
171
220
  monorepo-only outcome-pull.ts
172
221
  monorepo-only promise-manifest.mjs
173
222
  monorepo-only roles-check.sh
223
+ monorepo-only ad-copy-lint.sh
174
224
  monorepo-only spine-canary.sh
225
+ monorepo-only worktree-up.sh
175
226
  monorepo-only subdomains-proof.sh
176
227
  monorepo-only sync-claude-mirror.sh
177
228
  monorepo-only tg-listen.sh
@@ -179,10 +230,12 @@ monorepo-only typedb-cluster-status.sh
179
230
  monorepo-only typedb-env.sh
180
231
  monorepo-only typedb-flap-recorder.sh
181
232
  monorepo-only typedb-scratch.sh
233
+ monorepo-only deploy-schema-check.sh
182
234
  monorepo-only typedb-probes/containment-probe.py
183
235
  monorepo-only typedb-probes/panic-probe-version.py
184
236
  monorepo-only typedb-probes/panic-probe.py
185
237
  monorepo-only urls-lint.sh
238
+ monorepo-only redirect-lint.sh
186
239
  monorepo-only deploy-dev.sh
187
240
  monorepo-only fleet-status.sh
188
241
  monorepo-only gen-dev-config.py
@@ -193,6 +246,8 @@ monorepo-only tasks-claim-race.mjs
193
246
  monorepo-only tasks-loop.sh
194
247
  monorepo-only verify-fast.sh
195
248
  monorepo-only vespio-sync.sh
249
+ monorepo-only sweep.sh
250
+ monorepo-only incident.sh
196
251
  MANIFEST
197
252
  }
198
253
 
@@ -302,6 +357,22 @@ build() {
302
357
  echo "refusing: $TARGET exists and is not empty" >&2; return 2
303
358
  fi
304
359
 
360
+ # RUN FROM THE MAIN TREE. ROOT derives from BASH_SOURCE and WS from its
361
+ # parent, so invoked as .claude/worktrees/<x>/.claude/scripts/factory-repo.sh
362
+ # both are wrong: ROOT names the worktree and WS names `worktrees/`. The
363
+ # scrub in portabilise() is written against those two strings, so every
364
+ # literal /Users/<you>/Server/one-ie in a tracked file survives it. Measured
365
+ # 2026-09-14 from .claude/worktrees/dev: the emit refused naming 10 files and
366
+ # 5 paths, NONE of them real — a false RED, and had the scrub been laxer it
367
+ # would have emitted a tree with the maintainer's disk in it. Same trap as
368
+ # land.sh and release.sh, one directory over.
369
+ if [ -f "$ROOT/.git" ]; then
370
+ echo "refusing: $ROOT is a linked worktree, not the main checkout." >&2
371
+ echo " ROOT and WS would both be wrong and the scrub would miss every" >&2
372
+ echo " absolute path. Run the MAIN tree's copy of this script." >&2
373
+ return 2
374
+ fi
375
+
305
376
  local STAGE; STAGE="$(mktemp -d)"
306
377
  # No RETURN trap: bash keeps a RETURN trap set inside a function as the
307
378
  # shell's trap, so it fires again (with STAGE unbound) on every later
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ // classification: portable
3
+ // Red proof for factory-executor.js's Review predicate — and it READS THE FILE.
4
+ //
5
+ // The first version of this checker defined OLD and NEW as two inline lambdas
6
+ // and never opened the executor. It stayed green through two merges on
7
+ // 2026-09-06 while the executor's own line was fail-open (`0*2 > 1` = false
8
+ // for zero survivors). A checker that cannot see its subject proves nothing;
9
+ // this one lifts the predicate out of the source with new Function, drives it
10
+ // over the jury table beside the OLD shape, and fails closed if the lines it
11
+ // expects are not in the file.
12
+ import { readFileSync } from 'node:fs'
13
+ import { fileURLToPath } from 'node:url'
14
+ import { dirname, join } from 'node:path'
15
+
16
+ const here = dirname(fileURLToPath(import.meta.url))
17
+ const file = process.argv[2] || join(here, '..', 'workflows', 'factory-executor.js')
18
+ const src = readFileSync(file, 'utf8')
19
+
20
+ // Lift the two lines that ARE the predicate. Anchored on the const names, not
21
+ // on the arithmetic, so a wrong formula is caught by the table, not by the regex.
22
+ const mAgainst = src.match(/^\s*const against = (.+)$/m)
23
+ const mRefuted = src.match(/^\s*const refuted = (.+)$/m)
24
+ if (!mRefuted) {
25
+ console.log(`RED could not lift the Review predicate from ${file} — expected a \`const refuted = …\` line`)
26
+ process.exit(1)
27
+ }
28
+ // A pre-fix file has no `against` line; derive it so the OLD shape is DRIVEN and
29
+ // fails on the table (a wrong verdict), rather than tripping the regex (a miss).
30
+ const againstExpr = mAgainst ? mAgainst[1] : 'votes.filter((v) => v.refuted).length'
31
+ let LIFTED
32
+ try {
33
+ LIFTED = new Function('votes', `const against = ${againstExpr}; return ${mRefuted[1]};`)
34
+ } catch (e) {
35
+ console.log(`RED lifted predicate does not parse: ${e.message}`); process.exit(1)
36
+ }
37
+ const OLD = (v) => v.filter(x => x.refuted).length * 2 > Math.max(1, v.length)
38
+
39
+ const R = { refuted: true }, A = { refuted: false }
40
+ const cases = [
41
+ ['zero survivors (every lens threw)', [], true, 'THE BUG: nobody voted, so nobody objected'],
42
+ ['1 lens, refutes', [R], true, 'lone lens must bite'],
43
+ ['1 lens, approves', [A], false, 'lone lens approves'],
44
+ ['2 lenses split 1-1', [R, A], true, 'a split jury is not an acquittal'],
45
+ ['2 lenses both refute', [R, R], true, 'unanimous against'],
46
+ ['2 lenses both approve', [A, A], false, 'unanimous for'],
47
+ ['3 lenses, 1 refutes', [R, A, A], false, 'a lone dissenter is not a majority'],
48
+ ['3 lenses, 2 refute', [R, R, A], true, 'majority against'],
49
+ ]
50
+ let oldFails = 0, fileFails = 0
51
+ console.log(`predicate lifted from ${file}\n against = ${againstExpr}${mAgainst ? '' : ' (derived — file has no against line)'}\n refuted = ${mRefuted[1]}\n`)
52
+ console.log('case want OLD FILE')
53
+ for (const [name, votes, want, why] of cases) {
54
+ const o = OLD(votes), f = LIFTED(votes)
55
+ if (o !== want) oldFails++
56
+ if (f !== want) fileFails++
57
+ console.log(`${name.padEnd(36)} ${String(want).padEnd(6)} ${o === want ? ' ok ' : 'RED '} ${f === want ? ' ok' : 'RED'} ${f !== want ? '<- FILE WRONG: ' + why : ''}`)
58
+ }
59
+ console.log(`\nOLD shape: ${oldFails} failure(s) <- must be > 0 or this proof is worthless`)
60
+ console.log(`FILE: ${fileFails} failure(s) <- must be 0`)
61
+ process.exit(oldFails > 0 && fileFails === 0 ? 0 : 1)
@@ -22,6 +22,23 @@
22
22
  # pointed at production writes fabricated rungs into the graph the board reads.
23
23
  set -uo pipefail
24
24
 
25
+ # _GATE — route a heavy compute through the machine governor. A gate_lock only
26
+ # dedupes IDENTICAL work; a SLOT is what bounds N worktrees each running one of
27
+ # these at once (measured 2026-09-07: three concurrent 2.5GB typecheckers, every
28
+ # lock uncontended, load 171). Empty when already inside a gate, so a nested call
29
+ # inherits the outer slot rather than taking a second one.
30
+ #
31
+ # Resolves gate-run.sh from its OWN directory, deliberately: an earlier version
32
+ # keyed off $ROOT and got inserted above the line that sets it, so _GATE was
33
+ # silently empty and every call ran ungoverned -- a fail-OPEN, which is the exact
34
+ # defect this preamble exists to close.
35
+ _GATE=()
36
+ if [ "${GOVERN_IN_GATE:-0}" != "1" ]; then
37
+ _GR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/gate-run.sh"
38
+ [ -f "$_GR" ] && _GATE=( bash "$_GR" "compute:$(basename "${BASH_SOURCE[0]}")" -- )
39
+ fi
40
+
41
+
25
42
  ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
26
43
  MODE="${1:-ladder-live}"
27
44
 
@@ -59,7 +76,7 @@ check_ladder_live() {
59
76
  TYPEDB_USERNAME="$TYPEDB_USERNAME" \
60
77
  TYPEDB_PASSWORD="$TYPEDB_PASSWORD" \
61
78
  TYPEDB_TEST_DB="$TYPEDB_TEST_DB" \
62
- bunx vitest run src/lib/resolvers/factory-ladder-live.test.ts 2>&1)
79
+ "${_GATE[@]}" bunx vitest run src/lib/resolvers/factory-ladder-live.test.ts 2>&1)
63
80
 
64
81
  # An empty scratch db answers "Type label 'thing' not found" — the schema was never
65
82
  # loaded there. That is an environment gap, not a broken ladder.
@@ -0,0 +1,44 @@
1
+ You are the hand. Build task task:01a07591e5c350a306c93933: "In pages/components add a button > add this component to a page — it shows a list of pages in the workspace, you select the page to add the component, then edit the page or continue adding components".
2
+ Notes from the board:
3
+ SPEC (the title is the whole spec; the row's notes were empty — this brief was assembled by the launching session from a real read of the tree on 2026-09-06, every file:line verified).
4
+
5
+ WHAT TO BUILD
6
+ On /components (the Component Library gallery, ComponentBrowser.tsx), give every block an 'Add to page' affordance. Clicking it opens a picker listing the workspace's pages; choosing one appends that block to that page; after the write, offer two exits — 'Edit page' (link to the page editor) and 'Continue adding components' (dismiss the picker, stay in the gallery).
7
+
8
+ BOTH RECEIVERS ALREADY EXIST — DO NOT WRITE A NEW ONE, DO NOT ADD AN API ROUTE.
9
+ - pages:list — one.ie/web/src/lib/resolvers/pages.ts:670. Request { slug }. Returns { pages: [{ slug, title, status, updated_at }] } ordered by updated_at DESC. This is the picker's list. Returns { pages: [] } on any auth denial.
10
+ - pages:add-block — one.ie/web/src/lib/resolvers/pages.ts:630. Request { slug, page, section: { component, props }, atIndex? }. atIndex omitted = append to end, which is what this feature wants. It already runs normalizeBlockProps(BLOCK_SCHEMA, ...) server-side, so send the block's defaultProps verbatim — do NOT normalize on the client.
11
+
12
+ EXACT CALL-SITE PRECEDENT — copy this shape:
13
+ one.ie/web/src/components/chat/BlockFrame.tsx:112-125. It is the same feature one surface over ('Add to page' from chat). Note its gate: `const canAddToPage = addToPage && !!slug && !!page`, its pending/added state machine, and `emitClick('ui:chat:add-to-page', { component })` before the call. Use `ask` from '@/lib/in/ask'. Emit a sibling signal name, e.g. 'ui:component-browser:add-to-page'.
14
+
15
+ THE ONE DESIGN DECISION, ALREADY SETTLED — DO NOT RE-OPEN IT.
16
+ /components is a genuinely PUBLIC route. pages/components.astro mounts <ComponentBrowser client:only="react" /> with a plain Layout and passes NO props, and ComponentBrowser takes none. It is NOT one of the slugless console pages: those (see pages/tasks.astro) call resolveRoom() and rewrite to /u/[slug]/..., and components.astro does neither. There is also no workspace-scoped mount — ComponentBrowser appears only in pages/components.astro and is referenced by components/puck/BlockFinder.tsx.
17
+
18
+ So: derive the workspace slug SERVER-SIDE in pages/components.astro (from Astro.locals.workspaceContext?.workspace ?? Astro.locals.slug — verify which is right against how another workspace-aware page reads it) and pass it down as an optional `slug` prop to ComponentBrowser. When there is no session there is no slug, and the 'Add to page' button MUST NOT RENDER — same gate shape as BlockFrame's canAddToPage. An anonymous visitor keeps exactly today's public gallery, unchanged. Do NOT invent a client-side workspace read, do NOT add a new route, do NOT make /components members-only.
19
+
20
+ WHERE THE BUTTON GOES
21
+ ComponentBrowser.tsx has two surfaces for a block: the grid card (article, ~line 250) and PreviewModal (~line 143). Put the affordance in the PreviewModal footer at minimum — the modal is the block's detail view and already has a footer row. A card-level quick-add is welcome but must not swallow the card's existing onClick (which opens the preview).
22
+
23
+ DONE LOOKS LIKE
24
+ 1. Signed in, /components → open any block → 'Add to page' → picker lists this workspace's real pages → pick one → success state → 'Edit page' and 'Continue adding components' both present and both work.
25
+ 2. The block actually lands: re-open that page in the editor and the block is there, rendered, at the end.
26
+ 3. Signed out, /components renders exactly as before with no 'Add to page' button anywhere.
27
+ 4. `cd one.ie/web && bun run verify:fast` green. Add a unit test for the picker gate (no slug ⇒ no button).
28
+
29
+ CONSTRAINTS
30
+ - 6-token palette only (hook:design-check blocks otherwise) — follow the existing var(--color-border) / text-font / bg-foreground idiom in this very file.
31
+ - Do not regress the IntersectionObserver lazy-mount or the PreviewErrorBoundary; the gallery renders ~376 blocks.
32
+ - Edit in a worktree, never on shared main.
33
+
34
+ RULES, each one a recorded outage (text/factory-do.md § Concurrency):
35
+ 1. Work in YOUR OWN worktree, never the shared main tree. Slug: task-task:01a07591e5c350a306c93933.
36
+ UI task — run: bash .claude/scripts/worktree-preview.sh up task-task:01a07591e5c350a306c93933 --route /components
37
+ It cuts the worktree from main, links node_modules CONTENTS (never the dir), copies .env, allocates a port (never sweeps), and hands you a URL only after 3 consecutive 200s. Use the path and URL it prints.
38
+ 2. NEVER `bun install` inside the worktree. NEVER symlink node_modules itself.
39
+ 3. Make the change the task describes — minimal, in the worktree. Write or extend the test that names the concrete failure this change prevents (input → wrong result). No test that guards a shape.
40
+ 4. Run only YOUR test file(s) in the worktree: cd <wt>/one.ie/web && bunx vitest related --run <files> — through bash ../../.claude/scripts/gate-run.sh doer -- … . Do NOT run the suite; factory-walk.sh runs the tier's lane after you.
41
+ 5. Commit in the worktree by EXPLICIT PATH (git add <file>...), message: "task(task:01a07591e5c350a306c93933): <what was measured>". Never git add -A.
42
+ 6. Report files from `git status --porcelain` / `git show --stat` in the worktree, never from memory.
43
+ 7. THE BRAIN AND THE EDGE (root CLAUDE.md, LOCKED): if the change adds or touches a receiver, it reads KV / BrainDO JSON — never typedbQuery — and writes to the brain fire-and-forget or via sync/. resolvers/factory.ts is the one exception. Prove the door: bash .claude/scripts/signal-watch.sh --local (with your preview as SIGNAL_WATCH_LOCAL) — a door over budget or reaching for the brain is red, and red closes nothing.
44
+ If the task cannot be done as written, do the part that can, say exactly what you left out and why, and return committed:false rather than inventing scope.
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env bash
2
+ # flywheel-outcome.sh — the kill-switch for text/flywheel-todo.md.
3
+ #
4
+ # manifest: needs-env (reads GATEWAY_API_KEY from one.ie/web/.dev.vars; read-only probes)
5
+ #
6
+ # Exits 0 only when the flywheel plan's goal is TRUE in production:
7
+ # 1. a child's plan is not readable without auth (rung 0)
8
+ # 2. the router warms on the one shape it has learned (read edge)
9
+ # 3. the world routes tagged work to a head, not a model (namespace)
10
+ # 4. a fresh caller with only the workspace key can recall a memory (memory IN)
11
+ # 5. a second promise has settled-kept (the circuit)
12
+ # Every probe is one HTTP call. Each prints its own line; the first red stops nothing —
13
+ # all five run so the report shows which are still owed. Measured RED on 2026-09-15.
14
+ set -u
15
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
16
+ K="$(grep -m1 '^GATEWAY_API_KEY' "$ROOT/one.ie/web/.dev.vars" | cut -d= -f2- | tr -d '"' | tr -d "'" | tr -d ' ')"
17
+ [ -n "$K" ] || { echo "flywheel-outcome: no GATEWAY_API_KEY in one.ie/web/.dev.vars"; exit 2; }
18
+ BASE="${ONE_API_URL:-https://one.ie}"
19
+ ask() { curl -s -m 40 -X POST "$BASE/api/ask/$1" -H "Authorization: Bearer $K" -H 'Content-Type: application/json' -H 'User-Agent: flywheel-outcome/1' -d "$2"; }
20
+ red=0
21
+ say() { printf ' %-4s %s\n' "$1" "$2"; [ "$1" = "RED" ] && red=$((red+1)); }
22
+
23
+ # 1 · rung 0
24
+ code="$(curl -s -o /dev/null -w '%{http_code}' -m 30 -H 'User-Agent: flywheel-outcome/1' "$BASE/ehc/cyp-005/plan?as=cyp-voice")"
25
+ if [ "$code" != "200" ]; then say OK "rung 0: /ehc/cyp-005/plan?as=cyp-voice → $code without auth"; else say RED "rung 0: /ehc/cyp-005/plan?as=cyp-voice → 200 without auth"; fi
26
+
27
+ # 2 · router read edge
28
+ r="$(ask world:pick-model '{"data":{"shape":"do:complex"}}')"
29
+ reason="$(printf '%s' "$r" | python3 -c 'import json,sys
30
+ try:
31
+ d=json.load(sys.stdin); r=d.get("result") or d; print(r.get("reason") or d.get("reason") or "?")
32
+ except Exception: print("?")')"
33
+ if [ "$reason" = "warmed" ]; then say OK "router: world:pick-model do:complex → warmed"; else say RED "router: world:pick-model do:complex → $reason"; fi
34
+
35
+ # 3 · namespace
36
+ a="$(ask world:route '{"data":{"tags":["engineering"],"workspace":"one"}}' | python3 -c 'import json,sys
37
+ try:
38
+ d=json.load(sys.stdin); r=d.get("result") or d; print(r.get("actor") or "?")
39
+ except Exception: print("?")')"
40
+ # world:route is not deterministic across calls (measured 2026-09-15: `chairman` once, `model:sonnet` three
41
+ # times in the same minute), so the actor read alone cannot be the gate. The deterministic half is the
42
+ # count of tag→model rows in the store the verbs write to: 50 rows / 207.5 strength today, must be 0.
43
+ tm="$(cd "$ROOT/one.ie/web" && npx wrangler d1 execute one-owners --remote --json --command "SELECT count(*) AS n FROM claw_paths WHERE source LIKE 'tag:%' AND target LIKE 'model:%'" 2>/dev/null | python3 -c 'import json,sys
44
+ try: print(json.load(sys.stdin)[0]["results"][0]["n"])
45
+ except Exception: print("?")')"
46
+ case "$a" in model:*|factory-turn|"?") say RED "namespace: world:route engineering → $a; tag→model rows = $tm" ;;
47
+ *) if [ "$tm" = "0" ]; then say OK "namespace: world:route engineering → $a; tag→model rows = 0"; else say RED "namespace: world:route engineering → $a, but tag→model rows = $tm (need 0)"; fi ;; esac
48
+
49
+ # 4 · memory IN
50
+ n="$(ask meta:recall '{"data":{"match":"STRIPE_MODE"}}' | python3 -c 'import json,sys
51
+ try:
52
+ d=json.load(sys.stdin); r=d.get("result") or d; print(len(r.get("hypotheses") or []))
53
+ except Exception: print(0)')"
54
+ if [ "${n:-0}" -ge 1 ]; then say OK "memory: meta:recall STRIPE_MODE → $n"; else say RED "memory: meta:recall STRIPE_MODE → ${n:-0}"; fi
55
+
56
+ # 5 · the circuit — promises settled-kept (D1, read-only)
57
+ kept="$(cd "$ROOT/one.ie/web" && npx wrangler d1 execute one-owners --remote --json --command "SELECT count(*) AS n FROM promises WHERE state='settled-kept'" 2>/dev/null | python3 -c 'import json,sys
58
+ try: print(json.load(sys.stdin)[0]["results"][0]["n"])
59
+ except Exception: print("?")')"
60
+ if [ "$kept" != "?" ] && [ "$kept" -ge 2 ] 2>/dev/null; then say OK "circuit: promises settled-kept = $kept"; else say RED "circuit: promises settled-kept = $kept (need ≥ 2)"; fi
61
+
62
+ echo "flywheel-outcome: $red of 5 RED"
63
+ [ "$red" -eq 0 ]
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env bash
2
+ # gate-reaper-check.sh — what gate-reaper.sh reaps, and what it must never touch.
3
+ #
4
+ # manifest: portable
5
+ #
6
+ # WHY THIS EXISTS (measured 2026-09-05). Five `workerd` processes left behind by
7
+ # dead `astro dev` sessions sat at ppid=1 for 33-63 minutes holding ~196MB, while
8
+ # BOTH gate-reaper and machine-check printed "orphans: none". The reaper keys on
9
+ # a gate SHAPE, and `workerd serve` was not one of the shapes, so nothing in the
10
+ # harness could see them. They had to be found and killed by hand.
11
+ #
12
+ # The reaper's danger is symmetric, and this checker holds both ends:
13
+ # C1 an abandoned workerd under node_modules IS reaped
14
+ # C2 a LIVE workerd (parent alive) is NEVER reaped
15
+ # C3 a freshly reparented workerd is spared — the age floor still applies
16
+ # C4 a long-lived ppid=1 daemon that merely NAMES a gate word is spared
17
+ # C5 the pre-existing gate shapes still reap — no regression
18
+ # C6 a workerd outside node_modules is spared — not ours to kill
19
+ # R1 RED-PROOF: drop the workerd arm and C1 must FAIL
20
+ #
21
+ # Drives the REAL script with --once --dry-run against a STUBBED `ps`, so it
22
+ # never reads the live process table and never signals anything.
23
+ #
24
+ # bash .claude/scripts/gate-reaper-check.sh
25
+ set -uo pipefail
26
+
27
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
28
+ REAPER="$ROOT/.claude/scripts/gate-reaper.sh"
29
+ SANDBOX="$(mktemp -d "${TMPDIR:-/tmp}/gate-reaper-check.XXXXXX")"
30
+ trap 'rm -rf "$SANDBOX"' EXIT
31
+
32
+ fails=0
33
+ ok() { printf ' \033[32mPASS\033[0m %s\n' "$1"; }
34
+ bad() { printf ' \033[31mFAIL\033[0m %s\n' "$1"; fails=$((fails + 1)); }
35
+
36
+ WD='node_modules/@cloudflare/workerd-darwin-arm64/bin/workerd serve --binary --experimental'
37
+
38
+ # The fixture process table. Columns match `ps -Ao pid=,ppid=,etime=,command=`.
39
+ cat > "$SANDBOX/table" <<EOF
40
+ 1001 1 45:00 /repo/someapp/web/$WD
41
+ 1002 29457 45:00 /repo/someapp/web/$WD
42
+ 1003 1 01:00 /repo/someapp/web/$WD
43
+ 1004 1 45:00 /repo/bin/cc-connect.sh daemon run verify
44
+ 1005 1 45:00 /usr/local/bin/workerd serve --binary --experimental
45
+ 1006 1 45:00 bash /repo/.claude/scripts/gate-run.sh verify -- bun run verify
46
+ EOF
47
+
48
+ # Stub `ps`: serve the fixture for the sweep's -Ao read, and a pgid for lookups.
49
+ mkdir -p "$SANDBOX/bin"
50
+ cat > "$SANDBOX/bin/ps" <<EOF
51
+ #!/usr/bin/env bash
52
+ for a in "\$@"; do case "\$a" in pgid=) echo " 9999"; exit 0 ;; esac; done
53
+ cat "$SANDBOX/table"
54
+ EOF
55
+ chmod +x "$SANDBOX/bin/ps"
56
+
57
+ run_reaper() { PATH="$SANDBOX/bin:$PATH" bash "$1" --once --dry-run 2>&1; }
58
+
59
+ echo "── gate-reaper: reaps the abandoned, spares the live ──"
60
+ out="$(run_reaper "$REAPER")"
61
+
62
+ reaped() { grep -q "WOULD reap pid=$1 " <<<"$out"; }
63
+
64
+ if reaped 1001; then ok "C1 abandoned workerd under node_modules is reaped"
65
+ else bad "C1 abandoned workerd NOT reaped — the orphan shape is still invisible: $out"; fi
66
+
67
+ if ! reaped 1002; then ok "C2 live workerd (parent alive) spared"
68
+ else bad "C2 LIVE workerd would be reaped — this kills a running dev server"; fi
69
+
70
+ if ! reaped 1003; then ok "C3 freshly reparented workerd spared by the age floor"
71
+ else bad "C3 age floor not applied to workerd"; fi
72
+
73
+ if ! reaped 1004; then ok "C4 ppid=1 daemon naming a gate word is spared"
74
+ else bad "C4 cc-connect daemon would be reaped — exclusions broken"; fi
75
+
76
+ if reaped 1006; then ok "C5 pre-existing gate-run.sh shape still reaps"
77
+ else bad "C5 REGRESSION — gate-run.sh shape no longer reaped: $out"; fi
78
+
79
+ if ! reaped 1005; then ok "C6 workerd outside node_modules spared"
80
+ else bad "C6 would reap a workerd this tree did not spawn"; fi
81
+
82
+ # ── R1 RED-PROOF: without the workerd arm, C1 must fail ─────────────────────
83
+ GUTTED="$SANDBOX/gutted.sh"
84
+ grep -v 'node_modules\*workerd" serve"\*) ;;' "$REAPER" > "$GUTTED"
85
+ if [ "$(wc -l < "$GUTTED")" -eq "$(wc -l < "$REAPER")" ]; then
86
+ bad "R1 could not remove the workerd arm — anchor moved, this checker is blind"
87
+ else
88
+ gout="$(run_reaper "$GUTTED")"
89
+ if grep -q "WOULD reap pid=1001 " <<<"$gout"; then
90
+ bad "R1 gutted reaper STILL reaped 1001 — C1 is not testing the new arm"
91
+ else
92
+ ok "R1 red-proof: without the arm 1001 is missed, so C1 has teeth"
93
+ fi
94
+ fi
95
+
96
+ echo
97
+ if [ $fails -eq 0 ]; then echo "ALL GREEN — the reaper sees orphaned workerd and still spares live work"; exit 0; fi
98
+ echo "RED — $fails check(s) failed"; exit 1
@@ -82,6 +82,15 @@ sweep() {
82
82
  *"tsc --noEmit"*) ;;
83
83
  *"astro check"*) ;;
84
84
  *"run verify"*|*"run test"*|*"run typecheck"*) ;;
85
+ # An `astro dev` / `wrangler dev` that dies leaves its workerd child behind,
86
+ # reparented and holding ~40MB for as long as the box is up. FIVE of them
87
+ # accumulated in one hour on 2026-09-05 (ages 33-63min, ~196MB) while both
88
+ # this reaper and machine-check reported "orphans: none" -- neither knew the
89
+ # shape, so nothing in the harness could see them. A LIVE workerd always has
90
+ # a live parent (astro dev, or wrangler), so the ppid==1 test above already
91
+ # spares it; the node_modules anchor keeps this to runtimes THIS tree spawned
92
+ # and away from any workerd a user runs by hand.
93
+ *node_modules*workerd" serve"*) ;;
85
94
  *) continue ;;
86
95
  esac
87
96
  # Belt and braces: never a daemon, an editor, or anything system-owned, even