@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,445 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# verify-fast.sh — the DEV lane. Run from a package folder (one.ie/web, channels).
|
|
3
|
+
#
|
|
4
|
+
# Full `bun run verify` is the REVIEW/DEPLOY gate (deploy.sh, /close, --full).
|
|
5
|
+
# During a /do cycle we only need: does the code still typecheck, and do the
|
|
6
|
+
# tests that actually cover what I touched still pass?
|
|
7
|
+
#
|
|
8
|
+
# fast = sdk build + tsc --noEmit + vitest related(<changed>) + PINNED always-run
|
|
9
|
+
#
|
|
10
|
+
# Three rules learned the hard way:
|
|
11
|
+
# 1. EMPTY DIFF ⇒ RUN THE FULL SUITE. Never ⇒ pass. A fast lane that goes
|
|
12
|
+
# green because it selected zero tests is worse than the slow one.
|
|
13
|
+
# 2. PINS. `vitest related` follows imports; config/parity/boundary suites
|
|
14
|
+
# import nothing from what they guard (cron-wrangler-parity reads a .toml).
|
|
15
|
+
# Those are always run — ~seconds, and they are the class of gate that
|
|
16
|
+
# historically went dark.
|
|
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.
|
|
21
|
+
#
|
|
22
|
+
# FULL_VERIFY=1 makes this an alias for `bun run verify`.
|
|
23
|
+
set -euo pipefail
|
|
24
|
+
|
|
25
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
26
|
+
GATE="$ROOT/.claude/scripts/gate-run.sh"
|
|
27
|
+
FOLDER="$(pwd)"
|
|
28
|
+
BASE_REF="${DO_BASE_REF:-main}"
|
|
29
|
+
|
|
30
|
+
# The deferred-pin ledger. It must NOT live under $ROOT: inside a /do cycle $ROOT
|
|
31
|
+
# is .do-worktrees/<slug>, and do-auto.sh --gc deletes that checkout -- so the
|
|
32
|
+
# debt would evaporate with the worktree it was owed from, and the
|
|
33
|
+
# outstanding-debt-on-main backstop would never see it. A deferral that can
|
|
34
|
+
# vanish is a deleted gate wearing a different word, which is the exact thing the
|
|
35
|
+
# ledger exists to prevent. Machine-keyed, like the gate locks, the recon cache
|
|
36
|
+
# and the test memo, so every worktree and session reads ONE ledger.
|
|
37
|
+
DEBT_FILE="${VERIFY_FAST_DEBT_FILE:-${TMPDIR:-/tmp}/one-verify-fast-debt}"
|
|
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
|
+
|
|
96
|
+
if [ "${FULL_VERIFY:-0}" = "1" ]; then
|
|
97
|
+
echo "[verify-fast] FULL_VERIFY=1 — running the full gate"
|
|
98
|
+
# The close gate is where deferred pins come due. The full suite is a superset
|
|
99
|
+
# of every pin, so reaching here GREEN is the payment.
|
|
100
|
+
#
|
|
101
|
+
# Order is load-bearing, and the first version got it wrong: it cleared the
|
|
102
|
+
# ledger and THEN ran the suite, so a RED close wiped the debt on its way to
|
|
103
|
+
# failing and the deferred pins would never run again. Proven wrong by probe,
|
|
104
|
+
# not by reading: a scripted `verify` of `exit 1` cleared the ledger.
|
|
105
|
+
# The debt is settled by a PASS, never by an attempt. `exec` is gone for the
|
|
106
|
+
# same reason -- it replaces the process, leaving no line after the run to
|
|
107
|
+
# settle from. `set -e` is suspended around the run so a red suite reaches the
|
|
108
|
+
# settle logic instead of killing the script first.
|
|
109
|
+
_full_st=0
|
|
110
|
+
set +e
|
|
111
|
+
if jq -e '.scripts.verify' package.json >/dev/null 2>&1; then
|
|
112
|
+
bun run verify; _full_st=$?
|
|
113
|
+
else
|
|
114
|
+
# channels has no `verify` script; its full gate is typecheck + the whole suite.
|
|
115
|
+
bash "$ROOT/.claude/scripts/sdk-build-cached.sh" >/dev/null
|
|
116
|
+
bun run typecheck && bun run test; _full_st=$?
|
|
117
|
+
fi
|
|
118
|
+
set -e
|
|
119
|
+
if [ -f "$DEBT_FILE" ]; then
|
|
120
|
+
if [ "$_full_st" -eq 0 ]; then
|
|
121
|
+
echo "[verify-fast] full gate GREEN — clearing $(wc -l < "$DEBT_FILE" | tr -d ' ') deferred pin run(s)"
|
|
122
|
+
rm -f "$DEBT_FILE"
|
|
123
|
+
else
|
|
124
|
+
echo "[verify-fast] full gate RED — deferred pins stay owed" >&2
|
|
125
|
+
fi
|
|
126
|
+
fi
|
|
127
|
+
exit "$_full_st"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Pinned suites: run on every fast pass regardless of the diff.
|
|
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
|
+
PINS_DEFAULT='parity|wrangler|boundary|authority|roles|signals-parity|receivers|portable|design-dock|render-sites|panel-tabs|person-panel|ad-flow-panel'
|
|
171
|
+
PINS="${VERIFY_FAST_PINS:-$PINS_DEFAULT}"
|
|
172
|
+
|
|
173
|
+
# --- changed files: committed-since-base UNION uncommitted -------------------
|
|
174
|
+
# The BASE the committed half of the diff is measured from.
|
|
175
|
+
#
|
|
176
|
+
# Default `main` is right for a one-off check and wrong for a /do plan. On branch
|
|
177
|
+
# do/<slug> the committed term is "everything this PLAN has landed", so cycle 5
|
|
178
|
+
# re-selects cycles 1-4's files, cycle 6 re-selects five cycles' worth, and the
|
|
179
|
+
# fast lane converges on the full suite exactly as the plan gets long. Measured:
|
|
180
|
+
# 23 changed files after 3 commits, growing monotonically.
|
|
181
|
+
#
|
|
182
|
+
# Those earlier cycles were each verified green when they landed, and the plan's
|
|
183
|
+
# LAST cycle takes the full lane anyway (do-engine escalates on final-batch
|
|
184
|
+
# membership), so integration is still gated -- once, at the end, instead of once
|
|
185
|
+
# per cycle.
|
|
186
|
+
#
|
|
187
|
+
# The cycle's own edits are UNCOMMITTED at W4 time (W4 verifies, then commits),
|
|
188
|
+
# so the uncommitted term below already captures them exactly. Moving the base to
|
|
189
|
+
# the previous cycle's commit just stops the committed term re-adding work that
|
|
190
|
+
# is already proven. Derived from the commit message do-engine writes -- no
|
|
191
|
+
# plumbing, no ref passed through an LLM. Override with VERIFY_FAST_SINCE.
|
|
192
|
+
cycle_base=""
|
|
193
|
+
if [ -n "${VERIFY_FAST_SINCE:-}" ]; then
|
|
194
|
+
cycle_base="$VERIFY_FAST_SINCE"
|
|
195
|
+
elif git rev-parse --git-dir >/dev/null 2>&1; then
|
|
196
|
+
_br="$(git -C "$ROOT" branch --show-current 2>/dev/null || true)"
|
|
197
|
+
case "$_br" in
|
|
198
|
+
do/*)
|
|
199
|
+
_slug="${_br#do/}"
|
|
200
|
+
# do-engine's W4 prompt asks for `do(<slug>): C<n>`, but the agent writing
|
|
201
|
+
# the commit does not always obey it -- the two live plans wrote
|
|
202
|
+
# `do(lifecycle): C1` and `lifecycle-money C2: ...` respectively. Match
|
|
203
|
+
# either shape, and NEVER fall back to main: falling back is what re-selects
|
|
204
|
+
# the whole plan, which is the thing being fixed. With no boundary commit
|
|
205
|
+
# found, HEAD is the correct base -- every commit on this branch is already
|
|
206
|
+
# verified work, and this cycle's own edits are uncommitted at W4 time.
|
|
207
|
+
cycle_base="$(git -C "$ROOT" log -1 --format=%H \
|
|
208
|
+
--grep="^do(${_slug}): C[0-9]" --grep="^${_slug} C[0-9]" 2>/dev/null || true)"
|
|
209
|
+
[ -n "$cycle_base" ] || cycle_base="$(git -C "$ROOT" rev-parse HEAD 2>/dev/null || true)"
|
|
210
|
+
;;
|
|
211
|
+
esac
|
|
212
|
+
fi
|
|
213
|
+
if [ -n "$cycle_base" ]; then
|
|
214
|
+
BASE_REF="$cycle_base"
|
|
215
|
+
echo "[verify-fast] cycle base ${cycle_base:0:9} (previous cycle) - earlier cycles were verified when they landed; the plan's last cycle takes the full lane"
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
changed=""
|
|
219
|
+
if git rev-parse --git-dir >/dev/null 2>&1; then
|
|
220
|
+
# -C "$ROOT" is load-bearing: run from a subdir, git prints paths relative to
|
|
221
|
+
# CWD, and the repo-relative prefix strip below then matches nothing — which
|
|
222
|
+
# silently drops every fast run into the full-suite fallback.
|
|
223
|
+
mb="$(git -C "$ROOT" merge-base HEAD "$BASE_REF" 2>/dev/null || true)"
|
|
224
|
+
{ [ -n "$mb" ] && git -C "$ROOT" diff --name-only "$mb"...HEAD 2>/dev/null || true
|
|
225
|
+
git -C "$ROOT" diff --name-only HEAD 2>/dev/null || true
|
|
226
|
+
git -C "$ROOT" ls-files --others --exclude-standard 2>/dev/null || true
|
|
227
|
+
} > /tmp/.vf-changed.$$ || true
|
|
228
|
+
changed="$(sort -u /tmp/.vf-changed.$$ | grep -E '\.(ts|tsx|astro|js|mjs)$' || true)"
|
|
229
|
+
rm -f /tmp/.vf-changed.$$
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
# Paths are repo-relative; vitest wants them relative to the package folder.
|
|
233
|
+
rel="${FOLDER#"$ROOT"/}"
|
|
234
|
+
scoped="$(printf '%s\n' "$changed" | sed -n "s#^${rel}/##p" || true)"
|
|
235
|
+
|
|
236
|
+
echo "[verify-fast] $rel — $(printf '%s\n' "$scoped" | grep -c . || true) changed file(s)"
|
|
237
|
+
|
|
238
|
+
# --- 1. SDK build (types for tsc) + typecheck --------------------------------
|
|
239
|
+
# Generated-but-gitignored inputs tsc resolves as modules. Missing => a wall of
|
|
240
|
+
# phantom TS2307s on any tree that has not run dev/build yet.
|
|
241
|
+
if [ -f package.json ] && grep -q '"gen:page-modified"' package.json; then
|
|
242
|
+
bun run gen:page-modified >/dev/null || true
|
|
243
|
+
fi
|
|
244
|
+
# Through the fingerprint cache. The raw build is 2.0s of the 2.6s total
|
|
245
|
+
# deterministic cost of a cycle -- 78% -- and on an unchanged src it reproduces
|
|
246
|
+
# byte-identical dist (measured: same digest before and after). Skip it.
|
|
247
|
+
bash "$ROOT/.claude/scripts/sdk-build-cached.sh" || { echo "[verify-fast] sdk build FAILED" >&2; exit 1; }
|
|
248
|
+
# Typecheck through the SHARED fingerprint cache, not a fresh tsc every time.
|
|
249
|
+
#
|
|
250
|
+
# tsc-cached.sh keys on (folder, tree-fingerprint) using do-reconcile's exact key
|
|
251
|
+
# format, so a reconcile and N cycle gates on one unchanged tree cost ONE tsc
|
|
252
|
+
# between them instead of N. Measured on a warm tree: 21.6s -> 0.1s.
|
|
253
|
+
#
|
|
254
|
+
# It was written and proven in isolation and then not wired here, so every /do
|
|
255
|
+
# cycle kept paying full price for a typecheck of a tree that had not changed
|
|
256
|
+
# since the last cycle typechecked it. Proving an artifact is not the same as
|
|
257
|
+
# proving it in place.
|
|
258
|
+
#
|
|
259
|
+
# It is NOT wrapped in gate-run here, and that is now safe rather than a hole:
|
|
260
|
+
# tsc-cached.sh takes its own SLOT internally, around the compute and after the
|
|
261
|
+
# cache double-check, so a HIT costs nothing and a MISS queues like every other
|
|
262
|
+
# gate. Wrapping it out here instead would hold a slot through the up-to-900s
|
|
263
|
+
# lock wait -- two sessions on one folder would occupy both slots while one only
|
|
264
|
+
# waits for the other's answer.
|
|
265
|
+
#
|
|
266
|
+
# The comment this replaces said it "must NOT be nested inside another gate-run
|
|
267
|
+
# slot -- that is a second lock on the same logical gate". That conflated the
|
|
268
|
+
# per-folder dedupe LOCK with the machine-wide SLOT, and it is the instruction
|
|
269
|
+
# that kept the typecheck outside the governor. It prints the error
|
|
270
|
+
# COUNT on stdout and exits non-zero only when the check could not RUN; an unrun
|
|
271
|
+
# check is not a passing check, so both a non-zero exit and a non-zero count fail.
|
|
272
|
+
if [ -x "$ROOT/.claude/scripts/tsc-cached.sh" ] && [ "${VERIFY_FAST_TSC_CACHE:-1}" = "1" ]; then
|
|
273
|
+
_tsc_n=$(bash "$ROOT/.claude/scripts/tsc-cached.sh" "$rel") || {
|
|
274
|
+
echo "[verify-fast] typecheck could NOT RUN (tsc-cached) — treating as RED" >&2; exit 1; }
|
|
275
|
+
_tsc_n=$(printf '%s' "$_tsc_n" | tr -d '[:space:]')
|
|
276
|
+
if [ "${_tsc_n:-1}" != "0" ]; then
|
|
277
|
+
echo "[verify-fast] typecheck FAILED — ${_tsc_n} error(s) in $rel" >&2
|
|
278
|
+
exit 1
|
|
279
|
+
fi
|
|
280
|
+
echo "[verify-fast] typecheck: 0 errors (shared fingerprint cache)"
|
|
281
|
+
else
|
|
282
|
+
bash "$GATE" typecheck -- bun run typecheck || exit 1
|
|
283
|
+
fi
|
|
284
|
+
|
|
285
|
+
# --- 2. tests ----------------------------------------------------------------
|
|
286
|
+
# Tightening the base (above) introduces one way to select nothing that is NOT
|
|
287
|
+
# the dangerous one rule 1 guards. On a do/* branch the cycle's edits are normally
|
|
288
|
+
# uncommitted at W4 time -- but a W3 that commits its own work leaves both terms
|
|
289
|
+
# empty, and rule 1 would then send every cycle to the FULL suite: slower than the
|
|
290
|
+
# lane we replaced. The last commit IS that cycle's work, so retry with it before
|
|
291
|
+
# concluding nothing changed. Rule 1 still has the final word: if even that is
|
|
292
|
+
# empty, nothing was selected and the full suite runs.
|
|
293
|
+
if [ -z "$scoped" ] && [ -n "$cycle_base" ]; then
|
|
294
|
+
last="$(git -C "$ROOT" diff --name-only HEAD~1 HEAD 2>/dev/null | grep -E '\.(ts|tsx|astro|js|mjs)$' || true)"
|
|
295
|
+
scoped="$(printf '%s\n' "$last" | sed -n "s#^${rel}/##p" || true)"
|
|
296
|
+
[ -n "$scoped" ] && echo "[verify-fast] cycle edits were already committed - selecting the last commit's $(printf '%s\n' "$scoped" | grep -c . || true) file(s)"
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
if [ -z "$scoped" ]; then
|
|
300
|
+
echo "[verify-fast] no changed source files in $rel — falling back to the FULL suite"
|
|
301
|
+
exec bash "$GATE" test -- bun run test
|
|
302
|
+
fi
|
|
303
|
+
|
|
304
|
+
# vitest `related` resolves the importers of the changed files.
|
|
305
|
+
# Through test-cached.sh: identical inputs (same selection, same file contents,
|
|
306
|
+
# same working delta) reuse the recorded PASS instead of re-running. Only passes
|
|
307
|
+
# are remembered -- a red gate re-runs every time until it is green.
|
|
308
|
+
# shellcheck disable=SC2086
|
|
309
|
+
# THE THIRD CASE. Rule 1 covers an empty DIFF. This is an empty SELECTION: the
|
|
310
|
+
# diff is non-empty, but `vitest related` resolves no importers, and vitest then
|
|
311
|
+
# prints "No test files found" and exits 1. That is a FALSE RED -- it fails the
|
|
312
|
+
# cycle for a property of the import graph, not of the code. Measured on
|
|
313
|
+
# src/lib/authority.ts, a real file a real cycle edits.
|
|
314
|
+
#
|
|
315
|
+
# It must not become a pass either; selecting zero tests is exactly the shape
|
|
316
|
+
# rule 1 exists to refuse. So an empty selection falls back to the FULL suite,
|
|
317
|
+
# the same answer an empty diff gets. Conservative in the safe direction.
|
|
318
|
+
# `if cmd | tee` would test TEE's status, not the gate's -- the PIPESTATUS trap
|
|
319
|
+
# this repo has a scar for. Capture first, then branch on the real exit code.
|
|
320
|
+
# `set -e` is ON: a bare failing command exits the script BEFORE the next line,
|
|
321
|
+
# so `cmd; rc=$?` never assigns and the fallback below never runs -- the test gate
|
|
322
|
+
# then vanishes silently, which is strictly worse than the false RED being fixed.
|
|
323
|
+
# Measured: the run stopped after "typecheck: 0 errors" and printed no test line
|
|
324
|
+
# at all. Suspend it around the call, exactly as the FULL_VERIFY branch does.
|
|
325
|
+
|
|
326
|
+
# --- memo probe: never queue for a slot you do not need ----------------------
|
|
327
|
+
# Both test legs below go through test-cached.sh, which reuses a recorded PASS.
|
|
328
|
+
# But the SLOT was taken first and the memo consulted second, so a hit still
|
|
329
|
+
# waited in the governor queue. Measured 2026-09-09 on a saturated box: a single
|
|
330
|
+
# acquisition queued 855s and 1324s -- for work that, on a hit, is a stat() of a
|
|
331
|
+
# stamp file. A hit needs no memory, no forks and no slot.
|
|
332
|
+
#
|
|
333
|
+
# _memo_hit asks test-cached.sh itself (TEST_CACHE_PROBE=1, runs nothing, exits 0
|
|
334
|
+
# on a hit) so there is exactly ONE definition of what a hit is. On a MISS we
|
|
335
|
+
# fall through and take the slot exactly as before -- the gate is never skipped,
|
|
336
|
+
# only the WAIT for a gate that had nothing to do.
|
|
337
|
+
_memo_hit() {
|
|
338
|
+
TEST_CACHE_PROBE=1 bash "$ROOT/.claude/scripts/test-cached.sh" "$@" >/dev/null 2>&1
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
_rel_out="$(mktemp)"
|
|
342
|
+
set +e
|
|
343
|
+
if _memo_hit "$rel" -- related --run $(printf '%s ' $scoped); then
|
|
344
|
+
echo "[verify-fast] related: cache HIT — no slot taken"
|
|
345
|
+
_rel_rc=0
|
|
346
|
+
else
|
|
347
|
+
bash "$GATE" test -- bash "$ROOT/.claude/scripts/test-cached.sh" "$rel" -- related --run $(printf '%s ' $scoped) > "$_rel_out" 2>&1
|
|
348
|
+
_rel_rc=$?
|
|
349
|
+
fi
|
|
350
|
+
set -e
|
|
351
|
+
cat "$_rel_out"
|
|
352
|
+
if [ "$_rel_rc" -eq 0 ]; then
|
|
353
|
+
:
|
|
354
|
+
else
|
|
355
|
+
if grep -q 'No test files found' "$_rel_out"; then
|
|
356
|
+
# An empty SELECTION must never read as a pass, and must not silently exit 1
|
|
357
|
+
# either -- vitest prints "No test files found" and exits 1, which fails the
|
|
358
|
+
# cycle for a property of the import graph rather than of the code.
|
|
359
|
+
#
|
|
360
|
+
# HOW I MISREAD THIS, recorded so the next reader does not repeat it: I first
|
|
361
|
+
# hit the empty selection on src/lib/authority.ts and concluded the file was
|
|
362
|
+
# untested. It is not -- `vitest related` finds 338 test files for it. The
|
|
363
|
+
# empty selection was an ARGUMENT-PASSING bug in the test-cached wrapper,
|
|
364
|
+
# fixed separately (c983c45e2). So this branch is a genuine guard against a
|
|
365
|
+
# state that must not be a pass, NOT evidence that any particular file lacks
|
|
366
|
+
# coverage. Do not infer a coverage gap from reaching here without checking
|
|
367
|
+
# `bunx vitest related --run <file>` directly first.
|
|
368
|
+
#
|
|
369
|
+
# The pins still run, so the gate is not skipped, and the files are named so
|
|
370
|
+
# the condition is visible instead of silent.
|
|
371
|
+
echo "[verify-fast] vitest selected NO test files for these changed files:" >&2
|
|
372
|
+
printf '%s\n' $scoped | sed 's/^/ - /' >&2
|
|
373
|
+
echo "[verify-fast] running the pinned gates only. VERIFY the selection by hand before trusting this:" >&2
|
|
374
|
+
echo "[verify-fast] bunx vitest related --run <file> (an empty result here is usually a WRAPPER bug, not a coverage gap)" >&2
|
|
375
|
+
echo "[verify-fast] VERIFY_FAST_UNCOVERED_FULL=1 forces the whole suite instead." >&2
|
|
376
|
+
if [ "${VERIFY_FAST_UNCOVERED_FULL:-0}" = "1" ]; then
|
|
377
|
+
rm -f "$_rel_out"; exec bash "$GATE" test -- bun run test
|
|
378
|
+
fi
|
|
379
|
+
_rel_rc=0
|
|
380
|
+
fi
|
|
381
|
+
if [ "$_rel_rc" -ne 0 ]; then rm -f "$_rel_out"; exit 1; fi
|
|
382
|
+
fi
|
|
383
|
+
rm -f "$_rel_out"
|
|
384
|
+
|
|
385
|
+
# Pinned gates that no import graph reaches. vitest positional filters are
|
|
386
|
+
# SUBSTRINGS, not a regex — one alternation string matches nothing and exits 1
|
|
387
|
+
# ("No test files found"), which reads as a failed gate. Pass one arg per pin.
|
|
388
|
+
#
|
|
389
|
+
# TIER-GATED, and MEMOISED. The pinned block is 44 files / 420 tests / ~20s and it
|
|
390
|
+
# ran on every cycle regardless of the diff -- a six-cycle plan paid it six times
|
|
391
|
+
# for a surface that never moved. Two independent cuts, neither of which checks
|
|
392
|
+
# less:
|
|
393
|
+
#
|
|
394
|
+
# 1. tier. do-tier.sh already sizes the change. A PATCH (a doc line, a comment)
|
|
395
|
+
# cannot reach the authority/receivers/parity surface these pins guard, so it
|
|
396
|
+
# does not pay for them. FIX and above run the full pin set, unchanged.
|
|
397
|
+
# DEFAULT UP here, the opposite of do-tier's own default-down: an unknown
|
|
398
|
+
# tier runs ALL the pins. Skipping a gate on a guess is the failure this
|
|
399
|
+
# harness has the most scars from.
|
|
400
|
+
# 2. memo. Identical pins over an identical tree reuse the recorded PASS.
|
|
401
|
+
#
|
|
402
|
+
# VERIFY_FAST_PINS_ALL=1 forces the whole set.
|
|
403
|
+
#
|
|
404
|
+
# THE TIMING CUT. The pins guard integration surfaces -- parity, boundary,
|
|
405
|
+
# authority, receivers. Integration is a property of the FINISHED plan, not of
|
|
406
|
+
# cycle 3 of 6. Running them per-cycle was testing at the wrong time: six
|
|
407
|
+
# identical answers to a question only the last one can actually decide.
|
|
408
|
+
#
|
|
409
|
+
# So mid-plan they are DEFERRED, not deleted. The debt is written to
|
|
410
|
+
# .verify-fast-debt in the repo root, and the close gate (FULL_VERIFY=1, which
|
|
411
|
+
# /close and ./deploy both export) runs the whole suite and clears it. Accuracy
|
|
412
|
+
# is MOVED to the moment it matters, never dropped: a plan cannot reach a ship
|
|
413
|
+
# gate with the debt outstanding, because the ship gate is the full suite.
|
|
414
|
+
#
|
|
415
|
+
# The deferral applies ONLY on a do/<slug> branch -- a one-off check on main has
|
|
416
|
+
# no later gate to defer to, so it pays now. And an outstanding debt on main means
|
|
417
|
+
# a plan landed without ever reaching its close gate: pay it here, immediately.
|
|
418
|
+
# A deferral that can be forgotten is a deleted gate wearing a different word.
|
|
419
|
+
if [ -f "$DEBT_FILE" ] && { [ -z "${_br:-}" ] || [ "${_br#do/}" = "${_br:-}" ]; }; then
|
|
420
|
+
echo "[verify-fast] outstanding deferred pins from a merged plan — paying now (branch ${_br:-detached})"
|
|
421
|
+
VERIFY_FAST_PINS_ALL=1
|
|
422
|
+
fi
|
|
423
|
+
if [ "${VERIFY_FAST_PINS_ALL:-0}" != "1" ] && [ -n "${_br:-}" ] && [ "${_br#do/}" != "${_br:-}" ]; then
|
|
424
|
+
printf '%s\t%s\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$_br" "$rel" >> "$DEBT_FILE"
|
|
425
|
+
echo "[verify-fast] pins DEFERRED to the close gate (branch $_br) — debt recorded in .verify-fast-debt; FULL_VERIFY=1 clears it"
|
|
426
|
+
echo "[verify-fast] PASS (fast lane, pins deferred — full gate runs at /close and ./deploy)"
|
|
427
|
+
exit 0
|
|
428
|
+
fi
|
|
429
|
+
|
|
430
|
+
_tier="$(printf '%s\n' $scoped | sed "s#^#${rel}/#" | bash "$ROOT/.claude/scripts/do-tier.sh" 2>/dev/null | jq -r '.tier // "UNKNOWN"' 2>/dev/null || echo UNKNOWN)"
|
|
431
|
+
IFS='|' read -r -a _pins <<< "$PINS"
|
|
432
|
+
if [ "${VERIFY_FAST_PINS_ALL:-0}" != "1" ] && [ "$_tier" = "PATCH" ]; then
|
|
433
|
+
echo "[verify-fast] tier=PATCH — pins narrowed to the parity/boundary core (FIX+ runs all $PINS)"
|
|
434
|
+
_pins=(parity boundary)
|
|
435
|
+
else
|
|
436
|
+
echo "[verify-fast] tier=$_tier — running the full pin set"
|
|
437
|
+
fi
|
|
438
|
+
if _memo_hit "$rel" -- run "${_pins[@]}"; then
|
|
439
|
+
echo "[verify-fast] pins: cache HIT — no slot taken"
|
|
440
|
+
elif ! bash "$GATE" test -- bash "$ROOT/.claude/scripts/test-cached.sh" "$rel" -- run "${_pins[@]}"; then
|
|
441
|
+
echo "[verify-fast] pinned gate FAILED (pins: ${_pins[*]})" >&2
|
|
442
|
+
exit 1
|
|
443
|
+
fi
|
|
444
|
+
|
|
445
|
+
echo "[verify-fast] PASS (fast lane — full gate still runs at /close and ./deploy)"
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# vespio-sync.sh — one-way harness sync, one-ie -> apps/vespio.
|
|
3
|
+
#
|
|
4
|
+
# Vespio is an AGENCY repo (clients/, site/, web/, ai/, packages/). It is not
|
|
5
|
+
# the monorepo: no schema/, no pay/, no channels/, no text/ promise layer. So
|
|
6
|
+
# "sync everything" is the wrong instinct — most of one-ie's harness hard-asserts
|
|
7
|
+
# against a tree vespio does not have.
|
|
8
|
+
#
|
|
9
|
+
# THE AUTHORITY IS THE MANIFEST IN factory-repo.sh. It already classifies every
|
|
10
|
+
# script portable | needs-env | monorepo-only. This script reads that manifest
|
|
11
|
+
# rather than keeping a second list that could drift from it. An UNCLASSIFIED
|
|
12
|
+
# script does not ship — silence is never a licence.
|
|
13
|
+
#
|
|
14
|
+
# bash .claude/scripts/vespio-sync.sh --check # what's missing/drifted (read-only)
|
|
15
|
+
# bash .claude/scripts/vespio-sync.sh # copy, then show the diff
|
|
16
|
+
# bash .claude/scripts/vespio-sync.sh --commit # copy + commit (never pushes)
|
|
17
|
+
#
|
|
18
|
+
# Never pushes. Never stages by wildcard — every path is named. The 6 modified
|
|
19
|
+
# clients/*/data/lifecycles/*.toml in vespio belong to someone else's work and
|
|
20
|
+
# must never ride along in a sync commit.
|
|
21
|
+
set -uo pipefail
|
|
22
|
+
|
|
23
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
24
|
+
VESPIO="${VESPIO_ROOT:-$ROOT/../apps/vespio}"
|
|
25
|
+
MODE="${1:-}"
|
|
26
|
+
|
|
27
|
+
[ -d "$VESPIO/.git" ] || { echo "no vespio repo at $VESPIO"; exit 1; }
|
|
28
|
+
|
|
29
|
+
# ROOT is derived from BASH_SOURCE, so invoking this by a RELATIVE path from
|
|
30
|
+
# inside vespio resolves ROOT to vespio and syncs the tree onto itself. Assert
|
|
31
|
+
# the source is really one-ie before touching anything.
|
|
32
|
+
[ -f "$ROOT/schema/one.tql" ] || {
|
|
33
|
+
echo "refusing: \$ROOT ($ROOT) is not the one-ie monorepo (no schema/one.tql)."
|
|
34
|
+
echo "run this from /Users/toc/Server/one-ie, or by absolute path."
|
|
35
|
+
exit 1
|
|
36
|
+
}
|
|
37
|
+
[ "$(cd "$ROOT" && pwd -P)" != "$(cd "$VESPIO" && pwd -P)" ] || {
|
|
38
|
+
echo "refusing: source and destination are the same tree"; exit 1
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# --- the shippable set, read from the single manifest ------------------------
|
|
42
|
+
shippable() {
|
|
43
|
+
sed -n '/^manifest() {/,/^MANIFEST/p' "$ROOT/.claude/scripts/factory-repo.sh" \
|
|
44
|
+
| grep -E '^(portable|needs-env) ' | awk '{print $2}' | sort
|
|
45
|
+
}
|
|
46
|
+
unclassified() {
|
|
47
|
+
bash "$ROOT/.claude/scripts/factory-repo.sh" --check-portability 2>/dev/null \
|
|
48
|
+
| sed -n 's/.*FAIL unclassified: //p' | sort
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Commands that make sense in an agency tree. Deliberately excluded and why:
|
|
52
|
+
# deploy.md db-sync.md release.md -> 5-service monorepo pipeline
|
|
53
|
+
# one.md -> nine fleets over text/ docs vespio lacks
|
|
54
|
+
# oo-push.md rag.md -> monorepo-specific surfaces
|
|
55
|
+
COMMANDS="browser.md cc-connect.md chat.md close.md create.md do.md do-autonomous.md
|
|
56
|
+
do-improve.md do-show.md go.md improve.md kill.md notify.md restart.md
|
|
57
|
+
see.md skill-create.md sync.md"
|
|
58
|
+
|
|
59
|
+
# Skills that are tree-agnostic craft. Excluded: typedb, sdk, mcp, cli, puck,
|
|
60
|
+
# promise-* (need schema/, packages/, or the text/ promise layer).
|
|
61
|
+
SKILLS="astro react19 shadcn writer voice docs"
|
|
62
|
+
|
|
63
|
+
copied=0; missing=0
|
|
64
|
+
say() { printf ' %-14s %s\n' "$1" "$2"; }
|
|
65
|
+
|
|
66
|
+
ship_one() { # ship_one <relpath under .claude>
|
|
67
|
+
local rel="${1:-}"; [ -n "$rel" ] || return 0
|
|
68
|
+
local src="$ROOT/.claude/$rel" dst="$VESPIO/.claude/$rel"
|
|
69
|
+
[ -e "$src" ] || { say "ABSENT" "$rel"; missing=$((missing+1)); return; }
|
|
70
|
+
if [ "$MODE" = "--check" ]; then
|
|
71
|
+
if [ ! -e "$dst" ]; then say "MISSING" "$rel"; missing=$((missing+1))
|
|
72
|
+
elif ! diff -q "$src" "$dst" >/dev/null 2>&1; then say "DRIFTED" "$rel"; missing=$((missing+1)); fi
|
|
73
|
+
return
|
|
74
|
+
fi
|
|
75
|
+
mkdir -p "$(dirname "$dst")"
|
|
76
|
+
# A second run must be identical to the first. `cp -R src dst` NESTS when dst
|
|
77
|
+
# already exists (dst/src), so a re-sync silently built skills/writer/writer.
|
|
78
|
+
# Remove the destination first — this is a mirror, not an accumulation.
|
|
79
|
+
rm -rf "$dst"
|
|
80
|
+
# -L dereferences symlinks: .claude/skills/livekit-agents points outside the
|
|
81
|
+
# tree and would land in vespio as a dangling link.
|
|
82
|
+
cp -RL "$src" "$dst" && copied=$((copied+1))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
echo "== vespio-sync $ROOT -> $VESPIO"
|
|
86
|
+
un="$(unclassified)"
|
|
87
|
+
if [ -n "$un" ]; then
|
|
88
|
+
echo "-- NOT SHIPPING (unclassified in the manifest — classify them to ship):"
|
|
89
|
+
echo "$un" | sed 's/^/ /'
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
echo "-- scripts (manifest: portable + needs-env)"
|
|
93
|
+
while read -r f; do [ -n "$f" ] && ship_one "scripts/$f"; done <<< "$(shippable)"
|
|
94
|
+
|
|
95
|
+
echo "-- rules"
|
|
96
|
+
for f in api.md astro.md design.md documentation.md engine.md react.md ui.md; do ship_one "rules/$f"; done
|
|
97
|
+
|
|
98
|
+
echo "-- agents"
|
|
99
|
+
for f in w1-recon.md w2-decide.md w3-edit.md w4-verify.md; do ship_one "agents/$f"; done
|
|
100
|
+
|
|
101
|
+
echo "-- commands"
|
|
102
|
+
for f in $COMMANDS; do ship_one "commands/$f"; done
|
|
103
|
+
|
|
104
|
+
# /vespio has TWO bodies: the monorepo-side one (sync + push, lives in
|
|
105
|
+
# .claude/commands/vespio.md here) and the vespio-side one (start the fleet).
|
|
106
|
+
# Shipping the monorepo body would tell a vespio clone to run vespio-sync.sh,
|
|
107
|
+
# which is monorepo-only and not there — a command that lies from inside the
|
|
108
|
+
# repo it ships to. So the REMOTE body is authored separately and mapped on.
|
|
109
|
+
ship_mapped() { # ship_mapped <src rel> <dst rel>
|
|
110
|
+
local src="$ROOT/.claude/$1" dst="$VESPIO/.claude/$2"
|
|
111
|
+
[ -f "$src" ] || { say "ABSENT" "$1"; missing=$((missing+1)); return; }
|
|
112
|
+
if [ "$MODE" = "--check" ]; then
|
|
113
|
+
if [ ! -e "$dst" ]; then say "MISSING" "$2"; missing=$((missing+1))
|
|
114
|
+
elif ! diff -q "$src" "$dst" >/dev/null 2>&1; then say "DRIFTED" "$2"; missing=$((missing+1)); fi
|
|
115
|
+
return
|
|
116
|
+
fi
|
|
117
|
+
mkdir -p "$(dirname "$dst")"; rm -rf "$dst"; cp -L "$src" "$dst" && copied=$((copied+1))
|
|
118
|
+
}
|
|
119
|
+
ship_mapped "commands/vespio.remote.md" "commands/vespio.md"
|
|
120
|
+
|
|
121
|
+
echo "-- skills"
|
|
122
|
+
for s in $SKILLS; do ship_one "skills/$s"; done
|
|
123
|
+
|
|
124
|
+
if [ "$MODE" = "--check" ]; then
|
|
125
|
+
echo "== $missing item(s) missing or drifted"
|
|
126
|
+
[ "$missing" -eq 0 ] && echo " vespio is current."
|
|
127
|
+
exit 0
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
echo "== copied $copied item(s)"
|
|
131
|
+
cd "$VESPIO"
|
|
132
|
+
echo "-- vespio diff (.claude only):"
|
|
133
|
+
git status --porcelain .claude | sed 's/^/ /'
|
|
134
|
+
|
|
135
|
+
if [ "$MODE" = "--commit" ]; then
|
|
136
|
+
# explicit paths only — never `git add -A`. A neighbour's uncommitted
|
|
137
|
+
# clients/*/lifecycles edits must not be swept into a harness sync.
|
|
138
|
+
git add .claude
|
|
139
|
+
if git diff --cached --quiet; then echo "nothing to commit"; exit 0; fi
|
|
140
|
+
git commit -q -F - <<'MSG'
|
|
141
|
+
chore(claude): sync harness from one-ie
|
|
142
|
+
|
|
143
|
+
Manifest-driven — the shippable set is read from factory-repo.sh's
|
|
144
|
+
portability manifest, not a second list. Unclassified scripts do not ship.
|
|
145
|
+
Excluded by design: the 5-service deploy pipeline, the text/ promise layer,
|
|
146
|
+
and schema/-dependent skills, none of which exist in this tree.
|
|
147
|
+
MSG
|
|
148
|
+
echo "committed. Review, then push by hand: git -C $VESPIO push origin main"
|
|
149
|
+
fi
|