@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.
- package/agents/abm-strategist.md +89 -0
- package/agents/ads-meta.md +97 -0
- package/agents/analyst.md +173 -0
- package/agents/architect.md +280 -0
- package/agents/brand-guardian.md +88 -0
- package/agents/brand-strategist.md +92 -0
- package/agents/campaign-content.md +90 -0
- package/agents/campaign-email.md +88 -0
- package/agents/campaign-sms.md +87 -0
- package/agents/campaign-social.md +87 -0
- package/agents/cco.md +99 -0
- package/agents/ceo.md +106 -0
- package/agents/chairman.md +120 -0
- package/agents/cmo.md +101 -0
- package/agents/community-greeter.md +89 -0
- package/agents/community-moderator.md +92 -0
- package/agents/compliance.md +92 -0
- package/agents/copywriter.md +100 -0
- package/agents/creative-strategist.md +95 -0
- package/agents/cro.md +98 -0
- package/agents/cto.md +267 -0
- package/agents/customer-interviewer.md +93 -0
- package/agents/customer-researcher.md +89 -0
- package/agents/customer-success-manager.md +90 -0
- package/agents/customer-trainer.md +90 -0
- package/agents/cxo.md +100 -0
- package/agents/demand-creator.md +89 -0
- package/agents/demo-mover.md +83 -0
- package/agents/demo-specialist.md +89 -0
- package/agents/demo-thai-family-law.md +87 -0
- package/agents/designer.md +112 -0
- package/agents/discovery-caller.md +98 -0
- package/agents/doctor.md +139 -0
- package/agents/educate-coach.md +100 -0
- package/agents/elevate-tutor.md +83 -0
- package/agents/email-lifecycle-marketer.md +91 -0
- package/agents/engage-specialist.md +99 -0
- package/agents/events-coordinator.md +90 -0
- package/agents/foundation-builder.md +94 -0
- package/agents/funnel-architect.md +89 -0
- package/agents/gift-creator.md +100 -0
- package/agents/google-ads.md +103 -0
- package/agents/guide.md +292 -0
- package/agents/helpdesk-dispatcher.md +88 -0
- package/agents/hook-specialist.md +91 -0
- package/agents/identify-optimizer.md +101 -0
- package/agents/implementer.md +305 -0
- package/agents/incident-commander.md +120 -0
- package/agents/insights-lead.md +93 -0
- package/agents/journey-runner.md +113 -0
- package/agents/linkedin-ads.md +123 -0
- package/agents/live-sales-chat.md +90 -0
- package/agents/market-researcher.md +88 -0
- package/agents/media-buyer.md +96 -0
- package/agents/movers-customer-researcher.md +95 -0
- package/agents/movers-foundation-builder.md +96 -0
- package/agents/movers-market-researcher.md +97 -0
- package/agents/movers-pricing-strategist.md +171 -0
- package/agents/nurture-architect.md +99 -0
- package/agents/offer-architect.md +92 -0
- package/agents/onboarder.md +222 -0
- package/agents/onboarding-specialist.md +92 -0
- package/agents/operations-dashboard.md +98 -0
- package/agents/perf-engineer.md +348 -0
- package/agents/playbook-writer.md +71 -0
- package/agents/plg-strategist.md +91 -0
- package/agents/positioning-architect.md +88 -0
- package/agents/press-officer.md +89 -0
- package/agents/pricing-strategist.md +94 -0
- package/agents/privacy-officer.md +92 -0
- package/agents/referral-manager.md +91 -0
- package/agents/refine-analyst.md +102 -0
- package/agents/release-manager.md +261 -0
- package/agents/renewals-upsell-rep.md +90 -0
- package/agents/review-engineer.md +327 -0
- package/agents/rewards-steward.md +82 -0
- package/agents/sales-call-coach.md +94 -0
- package/agents/sales-closer.md +98 -0
- package/agents/security-auditor.md +313 -0
- package/agents/sell-closer.md +101 -0
- package/agents/share-amplifier.md +99 -0
- package/agents/social-media-manager.md +92 -0
- package/agents/storyteller.md +250 -0
- package/agents/strategist.md +83 -0
- package/agents/strategy-aligner.md +94 -0
- package/agents/support-agent.md +90 -0
- package/agents/tagger.md +245 -0
- package/agents/tech-writer.md +216 -0
- package/agents/test-engineer.md +243 -0
- package/agents/tiktok-ads.md +105 -0
- package/agents/tracking-engineer.md +92 -0
- package/agents/upsell-strategist.md +101 -0
- package/agents/voice.md +85 -0
- package/agents/w4-tools.md +153 -0
- package/agents/w4-verify.md +20 -138
- package/agents/workflow-optimiser.md +84 -0
- package/commands/close.md +814 -160
- package/commands/create.md +2 -2
- package/commands/deploy.md +554 -175
- package/commands/do.md +119 -109
- package/commands/fast.md +67 -0
- package/commands/improve.md +2 -2
- package/commands/one.md +418 -0
- package/commands/see.md +1 -1
- package/commands/sync.md +1 -1
- package/commands/tasks.md +222 -0
- package/commands/vespio.md +110 -0
- package/commands/vespio.remote.md +227 -0
- package/hooks/hooks.json +25 -79
- package/hooks/lib/governor-escape-match.sh +88 -0
- package/hooks/lib/hook.sh +4 -13
- package/hooks/lib/signal.sh +9 -2
- package/hooks/scripts/branch-pin.sh +6 -0
- package/hooks/scripts/config-protect.sh +6 -0
- package/hooks/scripts/do-outcome-gate.sh +19 -2
- package/hooks/scripts/git-add-guard.sh +43 -2
- package/hooks/scripts/governor-escape.sh +96 -0
- package/hooks/scripts/load-guard.sh +127 -0
- package/hooks/scripts/post-edit-check.sh +36 -29
- package/hooks/scripts/session-start.sh +34 -80
- package/hooks/scripts/task-complete-verify.sh +46 -40
- package/package.json +1 -1
- package/rules/documentation.md +9 -0
- package/scripts/ad-copy-lint.sh +656 -0
- package/scripts/agentverse-audit.sh +256 -0
- package/scripts/asi-walk.sh +435 -0
- package/scripts/astro-build-cached.sh +143 -0
- package/scripts/blocks-manifest-cached.sh +100 -0
- package/scripts/blocks-manifest.mjs +497 -0
- package/scripts/blocks-ratchet.sh +116 -0
- package/scripts/blocks-render-probe.mjs +529 -0
- package/scripts/blocks-usage.mjs +334 -0
- package/scripts/chat-context-check.sh +89 -0
- package/scripts/close-metrics.sh +558 -0
- package/scripts/close-owner.sh +268 -0
- package/scripts/db-sync-lock-check.sh +116 -0
- package/scripts/deploy-dev.sh +35 -0
- package/scripts/deploy-emit.sh +298 -0
- package/scripts/deploy-gate-check.sh +128 -0
- package/scripts/deploy-ready.sh +78 -0
- package/scripts/deploy-record.sh +605 -0
- package/scripts/deploy.sh +1273 -0
- package/scripts/do-auto.sh +598 -48
- package/scripts/do-brief.sh +113 -0
- package/scripts/do-close.sh +1137 -0
- package/scripts/do-commit.sh +75 -0
- package/scripts/do-consumer-sweep.sh +18 -1
- package/scripts/do-cycle-shape-check.sh +160 -0
- package/scripts/do-decide.sh +476 -0
- package/scripts/do-derive-check.sh +436 -0
- package/scripts/do-fleet.sh +106 -28
- package/scripts/do-folder.sh +10 -1
- package/scripts/do-next.sh +106 -0
- package/scripts/do-orchestrate.sh +17 -5
- package/scripts/do-plan-json.mjs +201 -0
- package/scripts/do-plan-json.sh +8 -0
- package/scripts/do-preflight.sh +117 -0
- package/scripts/do-project.sh +157 -0
- package/scripts/do-prove-selftest.sh +108 -0
- package/scripts/do-prove.sh +295 -23
- package/scripts/do-rank.py +31 -1
- package/scripts/do-recon-cache.sh +7 -1
- package/scripts/do-recon-pack.sh +196 -0
- package/scripts/do-reconcile.sh +121 -4
- package/scripts/do-signal.sh +280 -23
- package/scripts/do-smoke.sh +18 -1
- package/scripts/do-test-gate.sh +80 -0
- package/scripts/do-tick.sh +102 -0
- package/scripts/do-tier.sh +6 -0
- package/scripts/do-triage.sh +182 -0
- package/scripts/do-ui-gate.sh +1 -1
- package/scripts/do-w4-gates.sh +451 -0
- package/scripts/do-walk.sh +12 -1
- package/scripts/env-sync.sh +173 -0
- package/scripts/factory-brief-check.sh +330 -0
- package/scripts/factory-check.sh +68 -14
- 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 +118 -3
- package/scripts/factory-review-check.mjs +61 -0
- package/scripts/factory-ship.sh +61 -0
- package/scripts/factory-tasks-check.sh +18 -1
- package/scripts/factory-turn.sh +326 -0
- package/scripts/factory-walk.sh +396 -0
- package/scripts/factory-width.sh +57 -0
- package/scripts/fade-toxic.sh +4 -3
- package/scripts/fixtures/factory-brief-real.md +44 -0
- package/scripts/fixtures/triage-dupe.md +5 -0
- package/scripts/fleet-manifest.mjs +108 -0
- package/scripts/fleet-status.sh +110 -0
- package/scripts/full-suite-paths-check.sh +144 -0
- package/scripts/gate-reaper-check.sh +98 -0
- package/scripts/gate-reaper.sh +125 -0
- package/scripts/gate-run.sh +73 -0
- package/scripts/gc-content-check.sh +140 -0
- package/scripts/gen-dev-config.py +20 -0
- package/scripts/govern-bound-check.sh +60 -0
- package/scripts/govern-claims-check.sh +233 -0
- package/scripts/govern-mem-check.sh +290 -0
- package/scripts/governor-doors-check.sh +362 -0
- package/scripts/governor-escape-check.sh +171 -0
- package/scripts/health.sh +413 -0
- package/scripts/id-inventory.mjs +418 -0
- package/scripts/land.sh +551 -0
- package/scripts/lib/gc-finished.sh +77 -0
- package/scripts/lib/govern.sh +361 -0
- package/scripts/lib/govern.ts +756 -0
- package/scripts/lighthouse-run.sh +187 -0
- package/scripts/livekit-live-check.sh +61 -0
- package/scripts/livekit-ratchet.sh +46 -0
- package/scripts/load-guard-check.sh +49 -0
- package/scripts/machine-check.sh +102 -0
- package/scripts/machine-watch.sh +177 -0
- package/scripts/one-agents.mjs +415 -0
- package/scripts/one-resume.sh +78 -0
- package/scripts/orphan-baseline.json +182 -0
- package/scripts/orphan-modules.mjs +179 -0
- package/scripts/pr-body.sh +335 -0
- package/scripts/preview-fd-check.sh +289 -0
- package/scripts/promise-manifest.mjs +24 -1
- package/scripts/release.sh +322 -0
- package/scripts/roles-check.sh +946 -0
- package/scripts/sdk-build-cached.sh +64 -0
- package/scripts/signal-watch.sh +241 -0
- package/scripts/skills-publish.sh +94 -0
- package/scripts/speed-cache-check.sh +173 -0
- package/scripts/speed-check.mjs +907 -0
- package/scripts/speed-parity-check.sh +648 -0
- package/scripts/speed-waterfall-check.sh +355 -0
- package/scripts/substrate-env-parity.mjs +156 -0
- package/scripts/tasks-claim-race.mjs +108 -0
- package/scripts/tasks-loop.sh +185 -0
- package/scripts/test-cached.sh +255 -0
- package/scripts/test-full.sh +87 -0
- package/scripts/test-honesty.mjs +137 -0
- package/scripts/test-lanes.sh +166 -0
- package/scripts/test-speed.sh +94 -0
- package/scripts/triage-shape-check.sh +149 -0
- package/scripts/tsc-cached.sh +179 -0
- package/scripts/typedb-flake-check.sh +197 -0
- package/scripts/urls-lint.sh +15 -0
- package/scripts/verify-fast.sh +445 -0
- package/scripts/vespio-sync.sh +149 -0
- package/scripts/wf-check.mjs +104 -1
- package/scripts/worktree-preview.sh +879 -0
- package/scripts/worktree-up.sh +208 -0
- package/skills/livekit-agents/SKILL.md +285 -0
- package/skills/livekit-agents/references/freshness-rules.md +168 -0
- package/skills/shadcn/SKILL.md +1 -1
- package/skills/signal/SKILL.md +0 -1
- package/skills/voice/SKILL.md +94 -6
- package/skills/voice/corpus-check.sh +87 -0
- package/hooks/scripts/compact-hint.sh +0 -35
- package/hooks/scripts/gate-guard.sh +0 -83
- package/hooks/scripts/read-tracker.sh +0 -26
- package/hooks/scripts/session-end-verify.sh +0 -51
- package/hooks/scripts/stop-reflect.sh +0 -140
- package/hooks/scripts/sync-priority-todo.sh +0 -57
- package/hooks/scripts/sync-todo-docs.sh +0 -46
- package/hooks/scripts/tool-signal.sh +0 -48
- package/scripts/do-tasks-bridge.py +0 -366
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# env-sync.sh — localhost bun dev from the dev worktree, on production data.
|
|
3
|
+
#
|
|
4
|
+
# bash .claude/scripts/env-sync.sh # D1 (if idle) + astro
|
|
5
|
+
# bash .claude/scripts/env-sync.sh --astro-only # start :4321, leave D1 alone
|
|
6
|
+
# bash .claude/scripts/env-sync.sh --d1-only # prod → local mirror, no astro
|
|
7
|
+
#
|
|
8
|
+
# Geography:
|
|
9
|
+
# Code — env-sync-local worktree if it exists, else $ROOT/.dev-stable
|
|
10
|
+
# Data — $ROOT/one.ie/web/.wrangler (prod D1/KV/R2 mirror; worktree links it)
|
|
11
|
+
# Bind — 0.0.0.0:4321 so both http://127.0.0.1:4321 and http://localhost:4321 work
|
|
12
|
+
#
|
|
13
|
+
# Does not kill 8787–8799. Does not start a second `wrangler d1 export`.
|
|
14
|
+
# Does not `git reset --hard` a fleet branch — only the detached .dev-stable tree.
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
ASTRO=1 D1=1
|
|
18
|
+
for a in "$@"; do
|
|
19
|
+
case "$a" in
|
|
20
|
+
--astro-only) D1=0 ;;
|
|
21
|
+
--d1-only) ASTRO=0 ;;
|
|
22
|
+
-h|--help) sed -n '2,16p' "$0"; exit 0 ;;
|
|
23
|
+
-*) echo "env-sync.sh: unknown flag $a" >&2; exit 2 ;;
|
|
24
|
+
esac
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
|
+
# Shared checkout, even when this file is invoked from a linked worktree copy.
|
|
29
|
+
git_common="$(cd "$here/../.." && git rev-parse --git-common-dir)"
|
|
30
|
+
[[ "$git_common" == /* ]] || git_common="$(cd "$here/../.." && cd "$git_common" && pwd)"
|
|
31
|
+
ROOT="$(cd "$git_common/.." && pwd)"
|
|
32
|
+
# Prefer the env-sync-local worktree while that fleet is alive (has the `ai`
|
|
33
|
+
# pin Vite needs when node_modules is a symlink). Else the stable detached tree.
|
|
34
|
+
if [[ -z "${DEV_WT:-}" ]]; then
|
|
35
|
+
if [[ -e "$ROOT/.claude/worktrees/env-sync-local/.git" ]]; then
|
|
36
|
+
DEV_WT="$ROOT/.claude/worktrees/env-sync-local"
|
|
37
|
+
else
|
|
38
|
+
DEV_WT="$ROOT/.dev-stable"
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
WEB_MAIN="$ROOT/one.ie/web"
|
|
42
|
+
WEB_DEV="$DEV_WT/one.ie/web"
|
|
43
|
+
HOST="${ASTRO_HOST:-0.0.0.0}"
|
|
44
|
+
PORT="${ASTRO_PORT:-4321}"
|
|
45
|
+
|
|
46
|
+
say() { printf '%s\n' "$*"; }
|
|
47
|
+
die() { printf 'env-sync.sh: %s\n' "$*" >&2; exit 1; }
|
|
48
|
+
|
|
49
|
+
link_file() {
|
|
50
|
+
local src="$1" dest="$2"
|
|
51
|
+
[[ -f "$src" ]] || return 0
|
|
52
|
+
if [[ -L "$dest" ]]; then
|
|
53
|
+
local now; now="$(readlink "$dest")"
|
|
54
|
+
[[ "$now" == "$src" ]] && return 0
|
|
55
|
+
rm -f "$dest"
|
|
56
|
+
elif [[ -e "$dest" ]]; then
|
|
57
|
+
return 0
|
|
58
|
+
fi
|
|
59
|
+
ln -s "$src" "$dest"
|
|
60
|
+
say " linked ${dest#"$DEV_WT/"} → main"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
link_dir() {
|
|
64
|
+
local src="$1" dest="$2"
|
|
65
|
+
[[ -d "$src" ]] || return 0
|
|
66
|
+
if [[ -L "$dest" ]]; then
|
|
67
|
+
local now; now="$(readlink "$dest")"
|
|
68
|
+
[[ "$now" == "$src" ]] && return 0
|
|
69
|
+
rm -f "$dest"
|
|
70
|
+
elif [[ -d "$dest" ]]; then
|
|
71
|
+
mv "$dest" "${dest}.unlinked.$$"
|
|
72
|
+
say " moved ${dest#"$DEV_WT/"} aside (not production data)"
|
|
73
|
+
fi
|
|
74
|
+
ln -s "$src" "$dest"
|
|
75
|
+
say " linked ${dest#"$DEV_WT/"} → main"
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# --- 0. worktree: production data via links ----------------------------------
|
|
79
|
+
ensure_dev_worktree() {
|
|
80
|
+
git -C "$ROOT" rev-parse --is-inside-work-tree >/dev/null \
|
|
81
|
+
|| die "not a git repo: $ROOT"
|
|
82
|
+
local head; head="$(git -C "$ROOT" rev-parse HEAD)"
|
|
83
|
+
|
|
84
|
+
if [[ ! -d "$DEV_WT/.git" && ! -f "$DEV_WT/.git" ]]; then
|
|
85
|
+
say "creating dev worktree $DEV_WT @ $head"
|
|
86
|
+
git -C "$ROOT" worktree add --detach "$DEV_WT" "$head"
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
local here_sha; here_sha="$(git -C "$DEV_WT" rev-parse HEAD)"
|
|
90
|
+
if [[ "$DEV_WT" == "$ROOT/.dev-stable" && "$here_sha" != "$head" ]]; then
|
|
91
|
+
say "fast-forward $DEV_WT $here_sha → $head"
|
|
92
|
+
git -C "$DEV_WT" reset --hard "$head"
|
|
93
|
+
else
|
|
94
|
+
say "dev worktree $DEV_WT @ $here_sha"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
mkdir -p "$WEB_DEV"
|
|
98
|
+
link_dir "$WEB_MAIN/.wrangler" "$WEB_DEV/.wrangler"
|
|
99
|
+
link_dir "$WEB_MAIN/node_modules" "$WEB_DEV/node_modules"
|
|
100
|
+
link_dir "$ROOT/packages/sdk/node_modules" "$DEV_WT/packages/sdk/node_modules"
|
|
101
|
+
link_file "$WEB_MAIN/.env" "$WEB_DEV/.env"
|
|
102
|
+
link_file "$WEB_MAIN/.dev.vars" "$WEB_DEV/.dev.vars"
|
|
103
|
+
if [[ -f "$WEB_MAIN/src/data/fleets.json" ]]; then
|
|
104
|
+
link_file "$WEB_MAIN/src/data/fleets.json" "$WEB_DEV/src/data/fleets.json"
|
|
105
|
+
fi
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# --- 1. D1: one export at a time ---------------------------------------------
|
|
109
|
+
sync_d1() {
|
|
110
|
+
local pids
|
|
111
|
+
pids="$(pgrep -f 'wrangler d1 export one-owners --remote' || true)"
|
|
112
|
+
if [[ -n "$pids" ]]; then
|
|
113
|
+
say "D1 export already running pid=$pids — not starting a second"
|
|
114
|
+
return 0
|
|
115
|
+
fi
|
|
116
|
+
say "syncing production D1 → $WEB_MAIN/.wrangler"
|
|
117
|
+
( cd "$WEB_MAIN" && bun run db:sync )
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
# --- 2. astro on 4321 from the worktree --------------------------------------
|
|
121
|
+
http_code() {
|
|
122
|
+
curl -sS -o /dev/null -w '%{http_code}' --max-time 3 "$1" 2>/dev/null || echo 000
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
kill_port() {
|
|
126
|
+
local pids
|
|
127
|
+
pids="$(lsof -tiTCP:"$PORT" -sTCP:LISTEN 2>/dev/null || true)"
|
|
128
|
+
[[ -n "$pids" ]] || return 0
|
|
129
|
+
say "killing listeners on $PORT: $pids"
|
|
130
|
+
# shellcheck disable=SC2086
|
|
131
|
+
kill $pids 2>/dev/null || true
|
|
132
|
+
sleep 1
|
|
133
|
+
pids="$(lsof -tiTCP:"$PORT" -sTCP:LISTEN 2>/dev/null || true)"
|
|
134
|
+
[[ -z "$pids" ]] || kill -9 $pids 2>/dev/null || true
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
start_astro() {
|
|
138
|
+
local url_v4="http://127.0.0.1:$PORT"
|
|
139
|
+
if [[ "$(http_code "$url_v4/")" == 200 ]]; then
|
|
140
|
+
say "already 200 $url_v4/"
|
|
141
|
+
return 0
|
|
142
|
+
fi
|
|
143
|
+
kill_port
|
|
144
|
+
mkdir -p "$WEB_DEV/.dev"
|
|
145
|
+
say "starting bun run dev in $WEB_DEV (--host $HOST --port $PORT)"
|
|
146
|
+
(
|
|
147
|
+
cd "$WEB_DEV"
|
|
148
|
+
bun run dev -- --host "$HOST" --port "$PORT"
|
|
149
|
+
) >"$WEB_DEV/.dev/astro.log" 2>&1 &
|
|
150
|
+
echo $! >"$WEB_DEV/.dev/astro.pid"
|
|
151
|
+
say " pid=$(cat "$WEB_DEV/.dev/astro.pid") log=$WEB_DEV/.dev/astro.log"
|
|
152
|
+
|
|
153
|
+
local i code_root code_voice
|
|
154
|
+
for i in $(seq 1 90); do
|
|
155
|
+
code_root="$(http_code "$url_v4/")"
|
|
156
|
+
code_voice="$(http_code "$url_v4/demo/voice")"
|
|
157
|
+
if [[ "$code_root" == 200 && "$code_voice" == 200 ]]; then
|
|
158
|
+
say " ✓ $url_v4/ $code_root"
|
|
159
|
+
say " ✓ $url_v4/demo/voice $code_voice"
|
|
160
|
+
say " ✓ http://localhost:$PORT/ (same process; bound on $HOST)"
|
|
161
|
+
return 0
|
|
162
|
+
fi
|
|
163
|
+
sleep 2
|
|
164
|
+
done
|
|
165
|
+
say "last 40 lines of $WEB_DEV/.dev/astro.log:"
|
|
166
|
+
tail -n 40 "$WEB_DEV/.dev/astro.log" || true
|
|
167
|
+
die "astro did not reach 200 on $url_v4/ and /demo/voice in 180s (got /=$code_root voice=$code_voice)"
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
ensure_dev_worktree
|
|
171
|
+
(( D1 )) && sync_d1
|
|
172
|
+
(( ASTRO )) && start_astro
|
|
173
|
+
say "done. code=$DEV_WT data=$WEB_MAIN/.wrangler"
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# factory-brief-check.sh — pre-flight a factory brief for DEFERRED DECISIONS.
|
|
3
|
+
#
|
|
4
|
+
# manifest: portable
|
|
5
|
+
# Reads no credential and names no monorepo path — every rule is a literal
|
|
6
|
+
# in this file and the brief arrives as an argument or on stdin. The red
|
|
7
|
+
# half of --self-test reads fixtures/factory-brief-real.md, which ships
|
|
8
|
+
# beside it; absent, the self-test goes RED rather than skipping.
|
|
9
|
+
#
|
|
10
|
+
# WHY THIS EXISTS. A brief that hands the doer a decision instead of a decision
|
|
11
|
+
# already made costs a whole run. The first factory run spent ~46 minutes and
|
|
12
|
+
# ended in a refutation because one parenthesis said "verify which is right" —
|
|
13
|
+
# the launching session had two candidate reads of the workspace and shipped
|
|
14
|
+
# both. The doer is the wrong place to settle that: it has no board, no
|
|
15
|
+
# neighbours, and no cheap way to be wrong. This gate reads the brief BEFORE a
|
|
16
|
+
# worktree, a port, or a model call is spent, and refuses.
|
|
17
|
+
#
|
|
18
|
+
# Usage:
|
|
19
|
+
# factory-brief-check.sh <brief-file> check a brief file
|
|
20
|
+
# factory-brief-check.sh - check a brief on stdin
|
|
21
|
+
# cat brief.md | factory-brief-check.sh same
|
|
22
|
+
# factory-brief-check.sh --self-test prove the gate goes RED and GREEN
|
|
23
|
+
#
|
|
24
|
+
# Exit: 0 = brief is launchable · 1 = RED (or self-test failed) · 2 = usage.
|
|
25
|
+
#
|
|
26
|
+
# Env:
|
|
27
|
+
# FACTORY_BRIEF_FIXTURE override the --self-test red fixture (default:
|
|
28
|
+
# fixtures/factory-brief-real.md beside this script)
|
|
29
|
+
|
|
30
|
+
set -uo pipefail
|
|
31
|
+
|
|
32
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
33
|
+
|
|
34
|
+
# ---------------------------------------------------------------------------
|
|
35
|
+
# The rules. Each is a NAMED pattern, matched case-insensitively, one per line
|
|
36
|
+
# of the brief. A rule fires when the brief leaves a decision for the doer.
|
|
37
|
+
#
|
|
38
|
+
# Third field is the input the pattern is matched against: `line` is the raw
|
|
39
|
+
# line, `stripped` is the line with every file-path token removed first.
|
|
40
|
+
#
|
|
41
|
+
# Deliberate deviation, documented: `tbd` and `todo` match against `stripped`,
|
|
42
|
+
# so `text/template-todo.md` and `<slug>-todo.md` — which nearly every real
|
|
43
|
+
# brief in this repo cites — are NOT hits, while a bare `TBD.` at the end of a
|
|
44
|
+
# sentence still is. A gate that goes red on the name of a file it expects you
|
|
45
|
+
# to name is decoration, and gets disabled; a gate that misses `TBD.` because
|
|
46
|
+
# of the full stop is worse.
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
RULES=(
|
|
49
|
+
'verify-which|verify[[:space:]]+which|line'
|
|
50
|
+
'check-whether|check[[:space:]]+whether|line'
|
|
51
|
+
'tbd|(^|[^-_/[:alnum:]])tbd([^-_[:alnum:]]|$)|stripped'
|
|
52
|
+
'todo|(^|[^-_/[:alnum:]])todo([^-_[:alnum:]]|$)|stripped'
|
|
53
|
+
'decide-later|decide[[:space:]]+later|line'
|
|
54
|
+
'or-alternatively|or[[:space:]]+alternatively|line'
|
|
55
|
+
'either-or|(^|[^[:alnum:]])either[^[:alnum:]].*[[:space:]]or[[:space:]]|line'
|
|
56
|
+
'trailing-question|\?[[:space:]]*$|line'
|
|
57
|
+
'if-possible|if[[:space:]]+possible|line'
|
|
58
|
+
'ideally|(^|[^[:alnum:]])ideally([^[:alnum:]]|$)|line'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Rule 'code-span-options': two options joined by ` ?? ` or ` or ` INSIDE a code
|
|
62
|
+
# span. `a ?? b` in prose is a decision the doer has to make; the same string in
|
|
63
|
+
# shipped code is not, so only backtick spans count. Returns 0 when the line has
|
|
64
|
+
# one.
|
|
65
|
+
code_span_options() {
|
|
66
|
+
awk '
|
|
67
|
+
{
|
|
68
|
+
n = split($0, part, "`")
|
|
69
|
+
# odd-indexed parts (2,4,…) are inside a span
|
|
70
|
+
for (i = 2; i <= n; i += 2) {
|
|
71
|
+
s = part[i]
|
|
72
|
+
if (s ~ /[^[:space:]][[:space:]]+\?\?[[:space:]]+[^[:space:]]/) { found = 1 }
|
|
73
|
+
if (s ~ /[^[:space:]][[:space:]]+or[[:space:]]+[^[:space:]]/) { found = 1 }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
END { exit !found }
|
|
77
|
+
' <<< "$1"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# A file path token. The spec class is lowercase; this adds A-Z so the count and
|
|
81
|
+
# any listing read correctly (`ComponentBrowser.tsx`, not `omponentBrowser.tsx`).
|
|
82
|
+
# Presence is identical either way.
|
|
83
|
+
PATH_RE='[A-Za-z0-9_./-]+\.(tsx|astro|ts|sh|md|mjs|js)([^A-Za-z0-9]|$)'
|
|
84
|
+
|
|
85
|
+
# A 'Done' section: a line that STARTS with the word done, optionally behind a
|
|
86
|
+
# markdown heading or bold marker. "DONE LOOKS LIKE", "## Done", "**Done**".
|
|
87
|
+
DONE_RE='^[[:space:]]*(#+[[:space:]]*)?(\*\*)?[[:space:]]*done([^[:alnum:]]|$)'
|
|
88
|
+
|
|
89
|
+
check_brief() {
|
|
90
|
+
local text="$1" label="${2:-brief}"
|
|
91
|
+
local hits=0 line rule name pat
|
|
92
|
+
|
|
93
|
+
if [ -z "${text//[[:space:]]/}" ]; then
|
|
94
|
+
printf 'BRIEF RED: empty-brief — "<%s is empty — a brief that says nothing defers everything>"\n' "$label"
|
|
95
|
+
return 1
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
local rest src stripped
|
|
99
|
+
while IFS= read -r line; do
|
|
100
|
+
[ -z "${line//[[:space:]]/}" ] && continue
|
|
101
|
+
stripped="$(sed -E "s#$PATH_RE# #g" <<< "$line")"
|
|
102
|
+
for rule in ${RULES[@]+"${RULES[@]}"}; do
|
|
103
|
+
name="${rule%%|*}"; rest="${rule#*|}"
|
|
104
|
+
pat="${rest%|*}"; src="${rest##*|}"
|
|
105
|
+
if grep -qiE "$pat" <<< "$([ "$src" = stripped ] && printf '%s' "$stripped" || printf '%s' "$line")"; then
|
|
106
|
+
printf 'BRIEF RED: %s — "%s"\n' "$name" "$line"
|
|
107
|
+
hits=$((hits + 1))
|
|
108
|
+
fi
|
|
109
|
+
done
|
|
110
|
+
if code_span_options "$line"; then
|
|
111
|
+
printf 'BRIEF RED: code-span-options — "%s"\n' "$line"
|
|
112
|
+
hits=$((hits + 1))
|
|
113
|
+
fi
|
|
114
|
+
done <<< "$text"
|
|
115
|
+
|
|
116
|
+
local files
|
|
117
|
+
files="$(grep -oE "$PATH_RE" <<< "$text" | sed -E 's/[^A-Za-z0-9]$//' | sort -u)"
|
|
118
|
+
local nfiles=0
|
|
119
|
+
[ -n "$files" ] && nfiles="$(wc -l <<< "$files" | tr -d ' ')"
|
|
120
|
+
|
|
121
|
+
if [ "$nfiles" -eq 0 ]; then
|
|
122
|
+
printf 'BRIEF RED: no-file-path — "<%s names no file the doer can open>"\n' "$label"
|
|
123
|
+
hits=$((hits + 1))
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
if ! grep -qiE "$DONE_RE" <<< "$text"; then
|
|
127
|
+
printf 'BRIEF RED: no-done-section — "<%s has no Done section — nothing says when to stop>"\n' "$label"
|
|
128
|
+
hits=$((hits + 1))
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
if [ "$hits" -gt 0 ]; then
|
|
132
|
+
return 1
|
|
133
|
+
fi
|
|
134
|
+
printf 'BRIEF OK: %s files named, 0 deferred decisions\n' "$nfiles"
|
|
135
|
+
return 0
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# ---------------------------------------------------------------------------
|
|
139
|
+
# --self-test — the red proof. Four cases; the red half runs against the ACTUAL
|
|
140
|
+
# brief that produced the first run's refutation, copied verbatim, not retyped.
|
|
141
|
+
# ---------------------------------------------------------------------------
|
|
142
|
+
self_test() {
|
|
143
|
+
local fixture="${FACTORY_BRIEF_FIXTURE:-$HERE/fixtures/factory-brief-real.md}"
|
|
144
|
+
local tmp out rc bad=0 cases=0
|
|
145
|
+
|
|
146
|
+
if [ ! -f "$fixture" ]; then
|
|
147
|
+
printf 'SELF-TEST RED: the red fixture is missing at %s — the red half cannot be run, so nothing here is proven. Refusing to pass.\n' "$fixture" >&2
|
|
148
|
+
printf 'SELF-TEST RED: 0 cases — fixture absent\n'
|
|
149
|
+
return 1
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# (a) the real brief MUST go red, and MUST name verify-which on the real line.
|
|
153
|
+
cases=$((cases + 1))
|
|
154
|
+
out="$(check_brief "$(cat "$fixture")" "$fixture")"; rc=$?
|
|
155
|
+
if [ $rc -eq 0 ]; then
|
|
156
|
+
printf ' FAIL (a) the real brief passed — the gate is blind\n' >&2; bad=1
|
|
157
|
+
elif ! grep -q '^BRIEF RED: verify-which — ' <<< "$out"; then
|
|
158
|
+
printf ' FAIL (a) the real brief went red, but not on verify-which:\n%s\n' "$out" >&2; bad=1
|
|
159
|
+
elif ! grep -qi 'verify which is right' <<< "$(grep '^BRIEF RED: verify-which — ' <<< "$out")"; then
|
|
160
|
+
printf ' FAIL (a) verify-which fired on the wrong line:\n%s\n' "$(grep '^BRIEF RED: verify-which' <<< "$out")" >&2; bad=1
|
|
161
|
+
else
|
|
162
|
+
printf ' ok (a) the real brief is RED on verify-which, quoting "verify which is right"\n'
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN
|
|
166
|
+
|
|
167
|
+
# (b) a clean brief MUST pass.
|
|
168
|
+
cat > "$tmp/clean.md" <<'CLEAN'
|
|
169
|
+
BUILD: the picker gate on the component gallery.
|
|
170
|
+
|
|
171
|
+
WHAT TO BUILD
|
|
172
|
+
Add an "Add to page" control to the preview footer in
|
|
173
|
+
src/components/puck/ComponentBrowser.tsx. It lists the workspace pages, takes
|
|
174
|
+
one, appends the block, then offers two exits.
|
|
175
|
+
|
|
176
|
+
THE DECISION, ALREADY MADE
|
|
177
|
+
Read the workspace slug server-side from Astro.locals.slug in
|
|
178
|
+
src/pages/components.astro and pass it down as an optional prop. There is no
|
|
179
|
+
session, so there is no slug, so the control does not render.
|
|
180
|
+
|
|
181
|
+
TEST
|
|
182
|
+
Extend tests/unit/puck/add-to-page.test.tsx with one case that names the wrong
|
|
183
|
+
result: a missing slug renders the control anyway.
|
|
184
|
+
|
|
185
|
+
DONE LOOKS LIKE
|
|
186
|
+
1. The control renders signed in and is absent signed out.
|
|
187
|
+
2. The block lands at the end of the picked page.
|
|
188
|
+
3. bash .claude/scripts/gate-run.sh doer -- bunx vitest related --run is green.
|
|
189
|
+
4. node .claude/scripts/wf-check.mjs is green.
|
|
190
|
+
CLEAN
|
|
191
|
+
cases=$((cases + 1))
|
|
192
|
+
out="$(check_brief "$(cat "$tmp/clean.md")" "$tmp/clean.md")"; rc=$?
|
|
193
|
+
if [ $rc -ne 0 ]; then
|
|
194
|
+
printf ' FAIL (b) the clean brief went red — the gate cries wolf:\n%s\n' "$out" >&2; bad=1
|
|
195
|
+
elif ! grep -q '^BRIEF OK: ' <<< "$out"; then
|
|
196
|
+
printf ' FAIL (b) the clean brief exited 0 without printing BRIEF OK\n' >&2; bad=1
|
|
197
|
+
else
|
|
198
|
+
printf ' ok (b) the clean brief is GREEN — %s\n' "$out"
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# (c) a brief with no file path MUST go red, even with nothing deferred.
|
|
202
|
+
cat > "$tmp/nopath.md" <<'NOPATH'
|
|
203
|
+
BUILD: make the gallery let you put a block on a page.
|
|
204
|
+
|
|
205
|
+
DONE LOOKS LIKE
|
|
206
|
+
1. It works signed in and is absent signed out.
|
|
207
|
+
NOPATH
|
|
208
|
+
cases=$((cases + 1))
|
|
209
|
+
out="$(check_brief "$(cat "$tmp/nopath.md")" "$tmp/nopath.md")"; rc=$?
|
|
210
|
+
if [ $rc -eq 0 ] || ! grep -q '^BRIEF RED: no-file-path' <<< "$out"; then
|
|
211
|
+
printf ' FAIL (c) a brief naming no file passed:\n%s\n' "$out" >&2; bad=1
|
|
212
|
+
else
|
|
213
|
+
printf ' ok (c) a brief naming no file is RED on no-file-path\n'
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
# (d) a brief with no Done section MUST go red.
|
|
217
|
+
cat > "$tmp/nodone.md" <<'NODONE'
|
|
218
|
+
BUILD: the picker gate.
|
|
219
|
+
Edit src/components/puck/ComponentBrowser.tsx and read the slug server-side in
|
|
220
|
+
src/pages/components.astro. Extend tests/unit/puck/add-to-page.test.tsx.
|
|
221
|
+
NODONE
|
|
222
|
+
cases=$((cases + 1))
|
|
223
|
+
out="$(check_brief "$(cat "$tmp/nodone.md")" "$tmp/nodone.md")"; rc=$?
|
|
224
|
+
if [ $rc -eq 0 ] || ! grep -q '^BRIEF RED: no-done-section' <<< "$out"; then
|
|
225
|
+
printf ' FAIL (d) a brief with no Done section passed:\n%s\n' "$out" >&2; bad=1
|
|
226
|
+
else
|
|
227
|
+
printf ' ok (d) a brief with no Done section is RED on no-done-section\n'
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
# (e) EVERY named rule must fire. A declared rule that no case exercises is a
|
|
231
|
+
# rule that can ship broken and pass a brief it exists to refuse — one line
|
|
232
|
+
# per rule, all eleven, and the count asserted so a line tripping two rules
|
|
233
|
+
# (or none) is caught rather than averaged away.
|
|
234
|
+
cat > "$tmp/allrules.md" <<'ALLRULES'
|
|
235
|
+
BUILD: one line per deferred decision, in src/lib/one.ts.
|
|
236
|
+
Verify which read is right.
|
|
237
|
+
Check whether the snapshot is warm.
|
|
238
|
+
The signal name is TBD.
|
|
239
|
+
Leave a TODO where the gate goes.
|
|
240
|
+
Name the signal now and decide later on the payload.
|
|
241
|
+
Append the block, or alternatively insert it at the top.
|
|
242
|
+
Use either the snapshot or a live read.
|
|
243
|
+
Should the picker show archived pages?
|
|
244
|
+
Reuse the existing helper if possible.
|
|
245
|
+
Ideally the control renders in the footer.
|
|
246
|
+
Set the base to `4321 or 4325` first.
|
|
247
|
+
DONE LOOKS LIKE
|
|
248
|
+
1. It renders.
|
|
249
|
+
ALLRULES
|
|
250
|
+
cases=$((cases + 1))
|
|
251
|
+
out="$(check_brief "$(cat "$tmp/allrules.md")" "$tmp/allrules.md")"; rc=$?
|
|
252
|
+
local missing="" r n
|
|
253
|
+
for r in verify-which check-whether tbd todo decide-later or-alternatively \
|
|
254
|
+
either-or trailing-question if-possible ideally code-span-options; do
|
|
255
|
+
grep -q "^BRIEF RED: $r — " <<< "$out" || missing="$missing $r"
|
|
256
|
+
done
|
|
257
|
+
n="$(grep -c '^BRIEF RED: ' <<< "$out" | tr -d ' ')"
|
|
258
|
+
if [ -n "$missing" ]; then
|
|
259
|
+
printf ' FAIL (e) rules declared but never fired:%s\n%s\n' "$missing" "$out" >&2; bad=1
|
|
260
|
+
elif [ "$n" != 11 ]; then
|
|
261
|
+
printf ' FAIL (e) expected 11 hits, one per rule, got %s:\n%s\n' "$n" "$out" >&2; bad=1
|
|
262
|
+
else
|
|
263
|
+
printf ' ok (e) all 11 named rules fire — 11 hits, one per rule, no structural hit\n'
|
|
264
|
+
fi
|
|
265
|
+
|
|
266
|
+
# (f) THE RED PROOF ITSELF. Gut this script — empty the RULES array, keep
|
|
267
|
+
# everything else — and case (a) MUST flip: the real brief that cost ~46
|
|
268
|
+
# minutes now passes. A checker that stays green against its own gutted copy
|
|
269
|
+
# proves nothing, which is the failure this whole script exists to refuse.
|
|
270
|
+
#
|
|
271
|
+
# Gut by STRUCTURE, never by line number, so an edit above cannot quietly turn
|
|
272
|
+
# this into a no-op. Two things were measured before this assertion was
|
|
273
|
+
# written, and both are why it reads the way it does:
|
|
274
|
+
# - `"${RULES[@]}"` on an EMPTY array is an unbound variable under `set -u`
|
|
275
|
+
# in bash 3.2, so the gutted copy used to die with a bash error and exit 1.
|
|
276
|
+
# "exit non-zero" would have looked like proof and measured the crash. The
|
|
277
|
+
# expansion in check_brief is empty-safe for exactly this reason.
|
|
278
|
+
# - code_span_options lives OUTSIDE Rules and still runs in the gutted copy;
|
|
279
|
+
# the real fixture happens to trip none of its spans, so the gutted copy
|
|
280
|
+
# reaches BRIEF OK. Both halves are asserted separately so a future change
|
|
281
|
+
# to either one names itself instead of averaging away.
|
|
282
|
+
cases=$((cases + 1))
|
|
283
|
+
awk '/^RULES=\(/{print "RULES=()"; s=1; next} s&&/^\)/{s=0; next} !s' \
|
|
284
|
+
"${BASH_SOURCE[0]}" > "$tmp/gutted.sh"
|
|
285
|
+
if ! grep -q '^RULES=()$' "$tmp/gutted.sh"; then
|
|
286
|
+
printf ' FAIL (f) the gutting did not take — no empty RULES in the copy\n' >&2; bad=1
|
|
287
|
+
elif ! bash -n "$tmp/gutted.sh" 2>/dev/null; then
|
|
288
|
+
printf ' FAIL (f) the gutted copy does not parse — the proof measures a syntax error, not the rules\n' >&2; bad=1
|
|
289
|
+
else
|
|
290
|
+
out="$(bash "$tmp/gutted.sh" "$fixture" 2>&1)"; rc=$?
|
|
291
|
+
if grep -q '^BRIEF RED: verify-which' <<< "$out"; then
|
|
292
|
+
printf ' FAIL (f) the gutted copy STILL refused the brief on verify-which — the RULES array is not load-bearing:\n%s\n' "$out" >&2; bad=1
|
|
293
|
+
elif [ $rc -ne 0 ]; then
|
|
294
|
+
printf ' FAIL (f) the gutted copy stopped the brief for some OTHER reason (rc=%s) — the red half of (a) is not attributable to the rules:\n%s\n' "$rc" "$out" >&2; bad=1
|
|
295
|
+
else
|
|
296
|
+
printf ' ok (f) rules emptied ⇒ the real brief PASSES (%s) — case (a) is attributable to the rules, not to the structural checks\n' "$out"
|
|
297
|
+
fi
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
if [ $bad -ne 0 ]; then
|
|
301
|
+
printf 'SELF-TEST RED: %s cases — the gate does not hold\n' "$cases"
|
|
302
|
+
return 1
|
|
303
|
+
fi
|
|
304
|
+
printf 'SELF-TEST OK: %s cases — red half red, green half green\n' "$cases"
|
|
305
|
+
return 0
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
main() {
|
|
309
|
+
case "${1:-}" in
|
|
310
|
+
--self-test) self_test; exit $? ;;
|
|
311
|
+
-h|--help)
|
|
312
|
+
awk 'NR==1{next} /^#/{sub(/^# ?/,""); print; next} {exit}' "${BASH_SOURCE[0]}"
|
|
313
|
+
exit 0 ;;
|
|
314
|
+
"")
|
|
315
|
+
if [ -t 0 ]; then
|
|
316
|
+
printf 'usage: factory-brief-check.sh <brief-file> | - | --self-test\n' >&2
|
|
317
|
+
exit 2
|
|
318
|
+
fi
|
|
319
|
+
check_brief "$(cat)" "stdin"; exit $? ;;
|
|
320
|
+
-) check_brief "$(cat)" "stdin"; exit $? ;;
|
|
321
|
+
*)
|
|
322
|
+
if [ ! -f "$1" ]; then
|
|
323
|
+
printf 'factory-brief-check.sh: no such brief file: %s\n' "$1" >&2
|
|
324
|
+
exit 2
|
|
325
|
+
fi
|
|
326
|
+
check_brief "$(cat "$1")" "$1"; exit $? ;;
|
|
327
|
+
esac
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
main "$@"
|
package/scripts/factory-check.sh
CHANGED
|
@@ -37,6 +37,23 @@
|
|
|
37
37
|
# must not assume "broken" — see text/factory.md § A note on "red" vs "cannot
|
|
38
38
|
# run". Never widen a `cannot run` into a `red` to make a chain simpler.
|
|
39
39
|
set -uo pipefail
|
|
40
|
+
|
|
41
|
+
# _GATE — route a heavy compute through the machine governor. A gate_lock only
|
|
42
|
+
# dedupes IDENTICAL work; a SLOT is what bounds N worktrees each running one of
|
|
43
|
+
# these at once (measured 2026-09-07: three concurrent 2.5GB typecheckers, every
|
|
44
|
+
# lock uncontended, load 171). Empty when already inside a gate, so a nested call
|
|
45
|
+
# inherits the outer slot rather than taking a second one.
|
|
46
|
+
#
|
|
47
|
+
# Resolves gate-run.sh from its OWN directory, deliberately: an earlier version
|
|
48
|
+
# keyed off $ROOT and got inserted above the line that sets it, so _GATE was
|
|
49
|
+
# silently empty and every call ran ungoverned -- a fail-OPEN, which is the exact
|
|
50
|
+
# defect this preamble exists to close.
|
|
51
|
+
_GATE=()
|
|
52
|
+
if [ "${GOVERN_IN_GATE:-0}" != "1" ]; then
|
|
53
|
+
_GR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/gate-run.sh"
|
|
54
|
+
[ -f "$_GR" ] && _GATE=( bash "$_GR" "compute:$(basename "${BASH_SOURCE[0]}")" -- )
|
|
55
|
+
fi
|
|
56
|
+
|
|
40
57
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
41
58
|
MODE="${1:-all}"
|
|
42
59
|
VERBOSE=0; [[ "${2:-}" == "--verbose" ]] && VERBOSE=1
|
|
@@ -375,7 +392,7 @@ check_belief_guard() {
|
|
|
375
392
|
TYPEDB_USERNAME="${TYPEDB_USERNAME:-}" \
|
|
376
393
|
TYPEDB_PASSWORD="${TYPEDB_PASSWORD:-}" \
|
|
377
394
|
TYPEDB_TEST_DB="${TYPEDB_TEST_DB:-}" \
|
|
378
|
-
bunx vitest run src/lib/resolvers/learning-evidence.test.ts 2>&1)
|
|
395
|
+
"${_GATE[@]}" bunx vitest run src/lib/resolvers/learning-evidence.test.ts 2>&1)
|
|
379
396
|
# The scratch db needs the schema loaded; the test defines none of its own. An
|
|
380
397
|
# empty db answers "Type label 'hypothesis' not found", which is cannot-run.
|
|
381
398
|
printf '%s' "$out" | grep -qE "Type label '(hypothesis|group|path)' not found" \
|
|
@@ -544,15 +561,36 @@ check_fn_one_allowlist() {
|
|
|
544
561
|
# clean slate is the fail-open trap in visual form — the operator reads "no gaps"
|
|
545
562
|
# when the truth is "nothing seeded". So the component must distinguish the two
|
|
546
563
|
# and the check asserts the empty-state copy exists alongside the query wiring.
|
|
564
|
+
# NAMED FILES, never `ls | head -1`.
|
|
565
|
+
#
|
|
566
|
+
# This check and check_stream both used to glob components/factory/*.tsx and read
|
|
567
|
+
# whichever sorted FIRST. On 2026-09-01 `FactoryFlow.tsx` landed in that directory,
|
|
568
|
+
# sorted before `GapsBoard.tsx`, and silently stole both checks: view-gaps went RED
|
|
569
|
+
# against a canvas that was never the board, and stream went GREEN against the same
|
|
570
|
+
# canvas, because a play loop contains `setInterval` and the word `stop`. A check
|
|
571
|
+
# aimed at "whatever sorts first" is a check anyone can re-aim by adding a file.
|
|
572
|
+
#
|
|
573
|
+
# So each check names the file it means. Adding a component to that directory is now
|
|
574
|
+
# a free action; renaming or deleting one of THESE is what has to fail loudly.
|
|
575
|
+
#
|
|
576
|
+
# RE-AIMED 2026-09-04. Naming the file was the right fix and it was aimed at the
|
|
577
|
+
# wrong file: `IdeaBoard.tsx` was mounted by NO page — `factory.astro` mounts
|
|
578
|
+
# `FactoryFlow` and nothing else — so this check was green against a component a
|
|
579
|
+
# person could not open. Deleted with R3. The surface that ships is the canvas,
|
|
580
|
+
# and the empty-state copy lives in its `ideasNote`.
|
|
547
581
|
check_view_gaps() {
|
|
548
|
-
local
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
grep -
|
|
554
|
-
|| return $(red "
|
|
555
|
-
|
|
582
|
+
local board read
|
|
583
|
+
board="$ROOT/one.ie/web/src/components/factory/FactoryFlow.tsx"
|
|
584
|
+
read="$ROOT/one.ie/web/src/lib/factory/board-read.ts"
|
|
585
|
+
[ -f "$board" ] || return $(red "no FactoryFlow.tsx — /factory has no canvas to render")
|
|
586
|
+
[ -f "$read" ] || return $(red "no board-read.ts — the board has nothing to read the ladder with")
|
|
587
|
+
grep -qE "derived-from|thing-type \"(deliverable|objective|task)\"" "$read" \
|
|
588
|
+
|| return $(red "the board's read does not walk the ladder — it renders nothing real")
|
|
589
|
+
grep -qiE "nothing is seeded yet|no rows yet|not seeded|graph is empty" "$board" \
|
|
590
|
+
|| return $(red "the canvas has no distinct EMPTY state — zero rows would read as 'nothing missing', which is the fail-open trap in visual form")
|
|
591
|
+
grep -qiE "could not read the board" "$board" \
|
|
592
|
+
|| return $(red "the canvas cannot say it failed to read — an outage would render as an empty board")
|
|
593
|
+
say "the board walks the ladder and is honest when empty"; echo "ok view-gaps"
|
|
556
594
|
}
|
|
557
595
|
|
|
558
596
|
# The templates are where every FUTURE plan inherits or repeats this session's
|
|
@@ -598,14 +636,30 @@ print(b)")
|
|
|
598
636
|
# becomes the bottleneck — that is the failure mode of every "just add more
|
|
599
637
|
# review" factory. Streaming + stop is parallel: it never blocks a cycle, and
|
|
600
638
|
# it never lets one run unwatched either.
|
|
639
|
+
# Named, for the reason spelled out above check_view_gaps.
|
|
640
|
+
#
|
|
641
|
+
# RE-AIMED 2026-09-04, same defect as check_view_gaps and worse: this one was
|
|
642
|
+
# GREEN. `RunPanel.tsx` was mounted by no page, so "factory streams and can be
|
|
643
|
+
# stopped" was asserted about a file nobody could open while the canvas that
|
|
644
|
+
# ships had `grep -c 'do:halt\|workflow:stop'` = 0. Deleted with R3; the stop now
|
|
645
|
+
# lives in `RunTrack.tsx` (the panel FactoryFlow renders) over `stop-run.ts`.
|
|
646
|
+
#
|
|
647
|
+
# The three greps are now aimed at three DIFFERENT files on purpose: the stream
|
|
648
|
+
# is the hook, the control is the rendered panel, and the receiver is the
|
|
649
|
+
# resolver. A single file satisfying all three is what let a play loop pass as a
|
|
650
|
+
# stream control.
|
|
601
651
|
check_stream() {
|
|
602
|
-
local
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
652
|
+
local panel hook
|
|
653
|
+
panel="$ROOT/one.ie/web/src/components/factory/RunTrack.tsx"
|
|
654
|
+
hook="$ROOT/one.ie/web/src/lib/use-workflow-stream.ts"
|
|
655
|
+
[ -f "$panel" ] || return $(red "no RunTrack.tsx — nothing shows what is running")
|
|
656
|
+
[ -f "$hook" ] || return $(red "no use-workflow-stream.ts — the panel has nothing to stream from")
|
|
657
|
+
grep -qiE "EventSource|text/event-stream" "$hook" \
|
|
606
658
|
|| return $(red "/factory does not stream — a static page cannot show what is being built RIGHT NOW")
|
|
607
|
-
grep -
|
|
659
|
+
grep -qF "stopRun" "$panel" \
|
|
608
660
|
|| return $(red "/factory has no stop control — the operator can watch but not intervene, which is lights-off with a window")
|
|
661
|
+
grep -qiE "not permitted" "$ROOT/one.ie/web/src/lib/factory/stop-run.ts" 2>/dev/null \
|
|
662
|
+
|| return $(red "the stop control does not render its refusal — a stop that silently no-ops for an anonymous reader tells the operator nothing")
|
|
609
663
|
grep -rqE '"(do:halt|workflow:stop)"' "$ROOT/one.ie/web/src/lib/resolvers/" 2>/dev/null \
|
|
610
664
|
|| return $(red "the stop control is not wired to a receiver that actually halts a run")
|
|
611
665
|
say "factory streams and can be stopped"; echo "ok stream"
|