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