@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.
- package/.claude-plugin/plugin.json +1 -1
- package/agents/abm-strategist.md +67 -1
- package/agents/ads-meta.md +67 -1
- package/agents/analyst.md +67 -1
- package/agents/animator.md +108 -0
- package/agents/architect.md +269 -20
- package/agents/brand-guardian.md +67 -1
- package/agents/brand-strategist.md +67 -1
- package/agents/campaign-content.md +67 -1
- package/agents/campaign-email.md +67 -1
- package/agents/campaign-sms.md +67 -1
- package/agents/campaign-social.md +67 -1
- package/agents/cco.md +83 -2
- package/agents/ceo.md +108 -11
- package/agents/chairman.md +197 -0
- package/agents/cmo.md +82 -2
- package/agents/community-greeter.md +67 -1
- package/agents/community-moderator.md +67 -1
- package/agents/compliance.md +67 -1
- package/agents/copywriter.md +67 -1
- package/agents/creative-strategist.md +67 -1
- package/agents/cro.md +81 -1
- package/agents/cto.md +266 -28
- package/agents/customer-interviewer.md +67 -1
- package/agents/customer-researcher.md +67 -1
- package/agents/customer-success-manager.md +67 -1
- package/agents/customer-trainer.md +67 -1
- package/agents/cxo.md +82 -1
- package/agents/demand-creator.md +67 -1
- package/agents/demo-mover.md +67 -1
- package/agents/demo-specialist.md +67 -1
- package/agents/demo-thai-family-law.md +67 -1
- package/agents/designer.md +67 -1
- package/agents/discovery-caller.md +67 -1
- package/agents/doctor.md +269 -0
- package/agents/educate-coach.md +67 -1
- package/agents/elevate-tutor.md +67 -1
- package/agents/email-lifecycle-marketer.md +67 -1
- package/agents/engage-specialist.md +67 -1
- package/agents/events-coordinator.md +67 -1
- package/agents/foundation-builder.md +67 -1
- package/agents/funnel-architect.md +67 -1
- package/agents/gift-creator.md +67 -1
- package/agents/google-ads.md +67 -1
- package/agents/guide.md +67 -1
- package/agents/helpdesk-dispatcher.md +67 -1
- package/agents/hook-specialist.md +67 -1
- package/agents/identify-optimizer.md +67 -1
- package/agents/implementer.md +313 -45
- package/agents/incident-commander.md +67 -1
- package/agents/insights-lead.md +87 -1
- package/agents/journey-runner.md +67 -1
- package/agents/linkedin-ads.md +67 -1
- package/agents/live-sales-chat.md +67 -1
- package/agents/market-researcher.md +67 -1
- package/agents/media-buyer.md +67 -1
- package/agents/memory-keeper.md +195 -0
- package/agents/movers-customer-researcher.md +67 -1
- package/agents/movers-foundation-builder.md +67 -1
- package/agents/movers-market-researcher.md +67 -1
- package/agents/movers-pricing-strategist.md +67 -1
- package/agents/nurture-architect.md +67 -1
- package/agents/offer-architect.md +67 -1
- package/agents/onboarder.md +67 -1
- package/agents/onboarding-specialist.md +67 -1
- package/agents/operations-dashboard.md +87 -1
- package/agents/perf-engineer.md +333 -37
- package/agents/playbook-writer.md +67 -1
- package/agents/plg-strategist.md +67 -1
- package/agents/positioning-architect.md +67 -1
- package/agents/press-officer.md +67 -1
- package/agents/pricing-strategist.md +67 -1
- package/agents/privacy-officer.md +67 -1
- package/agents/referral-manager.md +67 -1
- package/agents/refine-analyst.md +67 -1
- package/agents/release-manager.md +446 -39
- package/agents/renewals-upsell-rep.md +67 -1
- package/agents/review-engineer.md +319 -45
- package/agents/rewards-steward.md +67 -1
- package/agents/sales-call-coach.md +67 -1
- package/agents/sales-closer.md +67 -1
- package/agents/security-auditor.md +343 -48
- package/agents/sell-closer.md +67 -1
- package/agents/share-amplifier.md +67 -1
- package/agents/social-media-manager.md +67 -1
- package/agents/storyteller.md +301 -0
- package/agents/strategist.md +67 -1
- package/agents/strategy-aligner.md +67 -1
- package/agents/support-agent.md +67 -1
- package/agents/tagger.md +327 -0
- package/agents/tech-writer.md +195 -22
- package/agents/test-engineer.md +398 -29
- package/agents/tiktok-ads.md +67 -1
- package/agents/tracking-engineer.md +67 -1
- package/agents/trailkeeper.md +181 -0
- package/agents/upsell-strategist.md +67 -1
- package/agents/voice.md +67 -1
- package/agents/w1-recon.md +1 -1
- package/agents/w2-decide.md +1 -1
- package/agents/w3-edit.md +8 -2
- package/agents/w4-verify.md +13 -0
- package/agents/workflow-optimiser.md +81 -1
- package/commands/close.md +916 -160
- package/commands/deploy.md +102 -724
- package/commands/do.md +58 -2
- package/commands/sweep.md +159 -0
- package/commands/tasks.md +222 -0
- package/hooks/scripts/dev-only.sh +135 -0
- package/hooks/scripts/git-add-guard.sh +37 -2
- package/hooks/scripts/session-start.sh +32 -4
- package/package.json +1 -1
- package/rules/scripts.md +85 -0
- package/scripts/CLAUDE.md +315 -0
- package/scripts/ad-copy-lint.sh +656 -0
- package/scripts/agent-actor-parity.sh +129 -0
- package/scripts/blocks-manifest-cached.sh +100 -0
- package/scripts/chat-context-check.sh +89 -0
- package/scripts/chrome.mjs +18 -0
- package/scripts/close-metrics.sh +587 -0
- package/scripts/close-owner.sh +326 -0
- package/scripts/db-sync-lock-check.sh +116 -0
- package/scripts/deploy-emit.sh +311 -0
- package/scripts/deploy-gate-check.sh +155 -0
- package/scripts/deploy-ready.sh +78 -0
- package/scripts/deploy-record.sh +605 -0
- package/scripts/deploy-schema-check.sh +58 -0
- package/scripts/deploy.sh +393 -243
- package/scripts/do-auto.sh +127 -26
- package/scripts/do-board.sh +429 -0
- package/scripts/do-close.sh +1184 -0
- package/scripts/do-consumer-sweep.sh +18 -1
- package/scripts/do-decide.sh +476 -0
- package/scripts/do-fleet.sh +8 -2
- package/scripts/do-plan-json.mjs +110 -12
- package/scripts/do-prove-selftest.sh +108 -0
- package/scripts/do-prove.sh +86 -10
- package/scripts/do-rank.py +200 -3
- package/scripts/do-reconcile.sh +73 -12
- package/scripts/do-signal.sh +101 -23
- package/scripts/do-smoke.sh +18 -1
- package/scripts/do-w4-gates.sh +11 -1
- package/scripts/do-world-check.sh +153 -0
- package/scripts/download-stats.sh +172 -0
- package/scripts/factory-brief-check.sh +330 -0
- package/scripts/factory-check.sh +18 -1
- package/scripts/factory-close-check.sh +257 -0
- package/scripts/factory-emit.sh +211 -0
- package/scripts/factory-executor-check.mjs +353 -0
- package/scripts/factory-peak.sh +301 -0
- package/scripts/factory-repo.sh +71 -0
- package/scripts/factory-review-check.mjs +61 -0
- package/scripts/factory-tasks-check.sh +18 -1
- package/scripts/fixtures/factory-brief-real.md +44 -0
- package/scripts/flywheel-outcome.sh +63 -0
- package/scripts/gate-reaper-check.sh +98 -0
- package/scripts/gate-reaper.sh +9 -0
- package/scripts/gate-watchdog.sh +619 -0
- package/scripts/gc-content-check.sh +142 -0
- package/scripts/gh-traffic-capture.sh +153 -0
- package/scripts/govern-order-check.sh +202 -0
- package/scripts/governor-doors-check.sh +86 -5
- package/scripts/health.sh +448 -0
- package/scripts/id-inventory.mjs +418 -0
- package/scripts/incident.sh +212 -0
- package/scripts/land.sh +755 -45
- package/scripts/lib/gc-finished.sh +77 -0
- package/scripts/livekit-ratchet.sh +18 -1
- package/scripts/machine-check.sh +1 -1
- package/scripts/memory-index-budget.sh +79 -0
- package/scripts/npm-downloads.sh +109 -0
- package/scripts/one-agents.mjs +204 -8
- package/scripts/one-resume.sh +31 -3
- package/scripts/pr-body.sh +335 -0
- package/scripts/preview-fd-check.sh +289 -0
- package/scripts/redirect-lint.sh +169 -0
- package/scripts/release.sh +40 -6
- package/scripts/resume-lost-sessions.sh +68 -0
- package/scripts/shoot-pages.mjs +140 -0
- package/scripts/signal-meta-backfill.ts +451 -0
- package/scripts/signal-watch.sh +63 -6
- package/scripts/speed-cache-check.sh +12 -2
- package/scripts/sweep.sh +426 -0
- package/scripts/task-titles-dump.ts +101 -0
- package/scripts/test-cached.sh +47 -10
- package/scripts/test-lanes.sh +14 -0
- package/scripts/thread-name-backfill.ts +215 -0
- package/scripts/triage-shape-check.sh +149 -0
- package/scripts/tsc-cached.sh +155 -8
- package/scripts/typedb-flake-check.sh +3 -1
- package/scripts/urls-lint.sh +8 -0
- package/scripts/verify-board-doors.sh +80 -0
- package/scripts/verify-fast.sh +159 -6
- package/scripts/worktree-up.sh +21 -3
- package/skills/astro/SKILL.md +9 -3
- package/skills/astro/optimize-performance.md +3 -2
- package/skills/cloudflare/SKILL.md +3 -2
- package/skills/cloudflare-security-audit/AI-AND-LLM.md +83 -0
- package/skills/cloudflare-security-audit/ATTACK-CLASSES.md +130 -0
- package/skills/cloudflare-security-audit/CLIENT-SIDE.md +83 -0
- package/skills/cloudflare-security-audit/CLOUD-AND-DEPLOYMENT.md +86 -0
- package/skills/cloudflare-security-audit/DATA-ISOLATION-AND-LIFECYCLE.md +84 -0
- package/skills/cloudflare-security-audit/DESKTOP-MOBILE-AND-LOCAL-IPC.md +89 -0
- package/skills/cloudflare-security-audit/HUNTING.md +251 -0
- package/skills/cloudflare-security-audit/LICENSE +21 -0
- package/skills/cloudflare-security-audit/MEMORY-SAFETY-AND-BINARY.md +101 -0
- package/skills/cloudflare-security-audit/PROTOCOLS-RPC-AND-MESSAGING.md +81 -0
- package/skills/cloudflare-security-audit/PROVENANCE.md +78 -0
- package/skills/cloudflare-security-audit/RECONNAISSANCE.md +156 -0
- package/skills/cloudflare-security-audit/RESOURCE-EXHAUSTION-AND-AVAILABILITY.md +78 -0
- package/skills/cloudflare-security-audit/SKILL.md +192 -0
- package/skills/cloudflare-security-audit/SUPPLY-CHAIN-AND-RELEASE.md +73 -0
- package/skills/cloudflare-security-audit/VALIDATION-AND-REPORTING.md +186 -0
- package/skills/cloudflare-security-audit/WEB-PROTOCOL-AND-AUTH.md +105 -0
- package/skills/cloudflare-security-audit/report-schema.json +461 -0
- package/skills/cloudflare-security-audit/validate-coverage-ledger.cjs +872 -0
- package/skills/cloudflare-security-audit/validate-coverage-ledger.test.cjs +740 -0
- package/skills/cloudflare-security-audit/validate-findings.cjs +773 -0
- package/skills/cloudflare-security-audit/validate-findings.test.cjs +652 -0
- package/skills/deploy/REFERENCE.md +713 -0
- package/skills/deploy/SKILL.md +140 -0
- package/skills/fleet-audit/SKILL.md +58 -0
- package/skills/meeting/SKILL.md +220 -0
- package/skills/planning/SKILL.md +256 -0
- package/skills/shadcn/SKILL.md +1 -1
- package/skills/typedb/SKILL.md +7 -0
- package/skills/voice/SKILL.md +94 -6
- package/skills/voice/corpus-check.sh +87 -0
- package/templates/template-agent.md +7 -1
- package/templates/template-feature.md +9 -0
- package/templates/template-todo.md +29 -0
package/scripts/factory-repo.sh
CHANGED
|
@@ -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
|
package/scripts/gate-reaper.sh
CHANGED
|
@@ -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
|