@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,108 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# do-prove-selftest.sh — the red proof for do-prove.sh's argument contract.
|
|
3
|
+
# Invoked as `do-prove.sh --self-test`; $1 is the do-prove.sh under test.
|
|
4
|
+
#
|
|
5
|
+
# Asked for by .claude/improvements.queue.md:307 ("it has no --self-test, unlike
|
|
6
|
+
# its sibling gates ... or this regresses silently the way it arrived").
|
|
7
|
+
#
|
|
8
|
+
# Every GREEN check here is paired with a RED one that GUTS the guard it depends
|
|
9
|
+
# on and asserts the check then fails. A checker that stays green against gutted
|
|
10
|
+
# code proves nothing.
|
|
11
|
+
#
|
|
12
|
+
# Needs no live server: the parser half is pure argument handling, and the base
|
|
13
|
+
# half points at a closed port on purpose.
|
|
14
|
+
set -uo pipefail
|
|
15
|
+
|
|
16
|
+
TARGET="${1:-}"
|
|
17
|
+
[ -n "$TARGET" ] && [ -f "$TARGET" ] || { echo "selftest: need the path to do-prove.sh"; exit 2; }
|
|
18
|
+
|
|
19
|
+
pass=0; fail=0
|
|
20
|
+
ok() { echo " ok — $1"; pass=$((pass+1)); }
|
|
21
|
+
no() { echo " FAIL — $1"; fail=$((fail+1)); }
|
|
22
|
+
|
|
23
|
+
# A port nothing is listening on. Verified closed, not assumed.
|
|
24
|
+
DEAD=""
|
|
25
|
+
for p in 45871 45872 45873 45874; do
|
|
26
|
+
if ! curl -sf -o /dev/null --max-time 1 "http://127.0.0.1:$p/" 2>/dev/null; then DEAD="$p"; break; fi
|
|
27
|
+
done
|
|
28
|
+
[ -n "$DEAD" ] || { echo "selftest: could not find a closed port"; exit 2; }
|
|
29
|
+
DEADBASE="http://127.0.0.1:$DEAD"
|
|
30
|
+
|
|
31
|
+
# A gutted copy of do-prove.sh with one guard removed, laid out so its own
|
|
32
|
+
# ROOT-from-BASH_SOURCE derivation still works.
|
|
33
|
+
# A mutant must still PARSE. Deleting the body of an `if` leaves an orphaned
|
|
34
|
+
# `fi`, and bash exits 2 on a syntax error — which is indistinguishable from a
|
|
35
|
+
# usage error and would have let a broken mutant masquerade as a red proof.
|
|
36
|
+
# Measured while writing this file: both base-half mutants "failed" that way.
|
|
37
|
+
# So mutate by SUBSTITUTION (guard → `:`), and refuse a mutant that does not
|
|
38
|
+
# parse rather than scoring it.
|
|
39
|
+
gut() { # $1 = sed program → echoes the path of the mutant, or empty on failure
|
|
40
|
+
local d; d="$(mktemp -d)"
|
|
41
|
+
mkdir -p "$d/.claude/scripts"
|
|
42
|
+
sed "$1" "$TARGET" > "$d/.claude/scripts/do-prove.sh"
|
|
43
|
+
if ! cmp -s "$TARGET" "$d/.claude/scripts/do-prove.sh"; then :; else
|
|
44
|
+
echo "" ; return 0 # sed matched nothing — the guard moved
|
|
45
|
+
fi
|
|
46
|
+
bash -n "$d/.claude/scripts/do-prove.sh" 2>/dev/null || { echo ""; return 0; }
|
|
47
|
+
echo "$d/.claude/scripts/do-prove.sh"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
echo "do-prove --self-test"
|
|
51
|
+
echo "[1/2] parser — an unrecognised FLAG is a hard error"
|
|
52
|
+
|
|
53
|
+
out="$(bash "$TARGET" --route / --bogus </dev/null 2>&1)"; rc=$?
|
|
54
|
+
[ "$rc" -eq 2 ] && ok "unknown flag --bogus exits 2 (got $rc)" \
|
|
55
|
+
|| no "unknown flag --bogus should exit 2, got $rc"
|
|
56
|
+
case "$out" in *"unknown flag '--bogus'"*) ok "…and names the flag" ;;
|
|
57
|
+
*) no "output did not name the flag: $out" ;; esac
|
|
58
|
+
|
|
59
|
+
out="$(bash "$TARGET" --base </dev/null 2>&1)"; rc=$?
|
|
60
|
+
[ "$rc" -eq 2 ] && ok "--base with no value exits 2" || no "--base with no value: rc=$rc"
|
|
61
|
+
out="$(bash "$TARGET" --route </dev/null 2>&1)"; rc=$?
|
|
62
|
+
[ "$rc" -eq 2 ] && ok "--route with no value exits 2" || no "--route with no value: rc=$rc"
|
|
63
|
+
|
|
64
|
+
# The leniency that must SURVIVE: a bare token (cycle slug) is still ignored,
|
|
65
|
+
# not refused. do-w4-gates.sh:210 and do-smoke.sh:85-88 depend on this.
|
|
66
|
+
out="$(bash "$TARGET" some-cycle-slug --route / --base "$DEADBASE" </dev/null 2>&1)"; rc=$?
|
|
67
|
+
[ "$rc" -ne 2 ] && ok "a bare cycle slug is still tolerated (rc=$rc, not a usage error)" \
|
|
68
|
+
|| no "a bare cycle slug was refused as a usage error — this breaks existing callers"
|
|
69
|
+
case "$out" in *"is not a path (cycle slug?)"*) ok "…and still says so" ;;
|
|
70
|
+
*) no "the lenient note is gone" ;; esac
|
|
71
|
+
|
|
72
|
+
# RED: remove the -*) branch and the flag guard must stop biting.
|
|
73
|
+
m="$(gut 's|^ exit 2 ;;$| shift ;;|')"
|
|
74
|
+
if [ -z "$m" ]; then no "RED PROOF FAILED: could not build the flag-guard mutant"; else
|
|
75
|
+
out="$(bash "$m" --route / --bogus --base "$DEADBASE" </dev/null 2>&1)"; rc=$?
|
|
76
|
+
[ "$rc" -ne 2 ] && ok "RED PROOF: gutted flag guard no longer exits 2 (got $rc) — check 1 is live" \
|
|
77
|
+
|| no "RED PROOF FAILED: mutant still exits 2; check 1 proves nothing"
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
echo "[2/2] base — --base pins the leg, and an unrun proof is not a pass"
|
|
81
|
+
|
|
82
|
+
out="$(bash "$TARGET" --route / --base "$DEADBASE" </dev/null 2>&1)"; rc=$?
|
|
83
|
+
[ "$rc" -ne 0 ] && ok "explicit --base that answers nothing exits non-zero (got $rc)" \
|
|
84
|
+
|| no "explicit --base answered nothing and still exited 0 — the fail-open is back"
|
|
85
|
+
case "$out" in *"an unrun proof is not a pass"*) ok "…and says why" ;;
|
|
86
|
+
*) no "no unrun message: $out" ;; esac
|
|
87
|
+
case "$out" in *"https://one.ie"*) no "--base did not pin the fallback — it reached for https://one.ie" ;;
|
|
88
|
+
*) ok "--base pinned the fallback (production never named)" ;; esac
|
|
89
|
+
|
|
90
|
+
# RED: remove the fallback pin → the mutant must reach for https://one.ie.
|
|
91
|
+
m="$(gut 's|^ PROD_URL="\$BASE_URL"$| :|')"
|
|
92
|
+
if [ -z "$m" ]; then no "RED PROOF FAILED: could not build the pin mutant"; else
|
|
93
|
+
out="$(bash "$m" --route / --base "$DEADBASE" </dev/null 2>&1)"
|
|
94
|
+
case "$out" in *"https://one.ie"*) ok "RED PROOF: unpinned mutant reaches production — the pin is load-bearing" ;;
|
|
95
|
+
*) no "RED PROOF FAILED: mutant did not reach production; the pin check proves nothing" ;; esac
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# RED: remove the unrun-is-not-a-pass block → the mutant must go back to exit 0.
|
|
99
|
+
m="$(gut 's|^ exit 1$| :|')"
|
|
100
|
+
if [ -z "$m" ]; then no "RED PROOF FAILED: could not build the fail-open mutant"; else
|
|
101
|
+
out="$(bash "$m" --route / --base "$DEADBASE" </dev/null 2>&1)"; rc=$?
|
|
102
|
+
if [ "$rc" -eq 0 ]; then ok "RED PROOF: gutted mutant exits 0 on an unreachable base — the guard is live"
|
|
103
|
+
else no "RED PROOF FAILED: mutant still exits $rc; the fail-open check proves nothing"; fi
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
echo
|
|
107
|
+
echo "do-prove --self-test: $pass passed, $fail failed"
|
|
108
|
+
[ "$fail" -eq 0 ] || exit 1
|
package/scripts/do-prove.sh
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
# (chrome-headless-shell page check via chrome.mjs, curl fallback against prod).
|
|
5
5
|
#
|
|
6
6
|
# Usage:
|
|
7
|
-
# do-prove.sh [--route <path>]... [<changed-path>|<cycle-slug>]...
|
|
7
|
+
# do-prove.sh [--route <path>]... [--base <url>] [<changed-path>|<cycle-slug>]...
|
|
8
|
+
# do-prove.sh --self-test
|
|
8
9
|
# git diff --name-only | do-prove.sh
|
|
9
10
|
#
|
|
10
11
|
# Arg contract:
|
|
@@ -12,16 +13,68 @@
|
|
|
12
13
|
# - Positional args that do NOT exist on disk (e.g. a cycle slug) are ignored
|
|
13
14
|
# for surface detection; changed paths then come from `git diff --name-only HEAD`.
|
|
14
15
|
# - --route <path> (repeatable) forces frontend surface + names the route(s) to prove.
|
|
16
|
+
# - --base <url> proves against <url> instead of the default localhost base.
|
|
15
17
|
# - stdin (non-tty) supplies changed paths when no positional paths are given.
|
|
18
|
+
# - AN UNRECOGNISED FLAG IS A HARD ERROR (exit 2). It was not, until 2026-09-07,
|
|
19
|
+
# and that is how the launch promise came to prove a laptop. `text/bring-one-to-life.md`
|
|
20
|
+
# deliverable 6 read `--route /keys --base https://one.ie`; `--base` did not
|
|
21
|
+
# exist, so BOTH tokens fell through the lenient `*)` branch as "not a path
|
|
22
|
+
# (cycle slug?)" and the run silently used the localhost default. Measured that
|
|
23
|
+
# morning with a dev server up on :4321:
|
|
24
|
+
# PROVE: note — '--base' is not a path (cycle slug?); …
|
|
25
|
+
# PROVE: ok / — http=200, 0 console/js errors (dev http://localhost:4321)
|
|
26
|
+
# PROVE: pass (1 route(s) proven) ← exit 0, prod never contacted
|
|
27
|
+
# The leniency is deliberate for BARE tokens (a cycle slug is passed
|
|
28
|
+
# legitimately — do-w4-gates.sh:210, do-smoke.sh:85-88). It is never correct
|
|
29
|
+
# for a token starting with `-`: nobody passes a flag they do not mean.
|
|
30
|
+
#
|
|
31
|
+
# --base semantics (matches land.sh:344-345, which pins both bases by hand and
|
|
32
|
+
# says why): --base PINS THE FALLBACK TOO, unless PROVE_PROD_URL is explicitly
|
|
33
|
+
# exported. Setting only the dev base would rebuild the same defect one layer
|
|
34
|
+
# down — an unreachable `--base https://staging.x` would fall through to
|
|
35
|
+
# PROD_URL and prove PRODUCTION while reporting it as staging.
|
|
36
|
+
# And an explicit --base that ANSWERS NOTHING exits non-zero rather than
|
|
37
|
+
# `PROVE: skipped` (exit 0): do-promise-settle.sh runs a promise's proof: string
|
|
38
|
+
# verbatim and reads the exit code, so a skipped prod probe would settle the
|
|
39
|
+
# promise KEPT with the site down. An unrun gate is not a pass. Bare invocations
|
|
40
|
+
# keep the old skip-is-0 semantics — land.sh:346-350 reads the ROUTE COUNT and
|
|
41
|
+
# factory-walk.sh:294 matches `PROVE: skipped` → unrun, and both rely on it.
|
|
16
42
|
#
|
|
17
43
|
# Env:
|
|
18
|
-
# PROVE_BASE_URL dev base for browser check (default http://localhost:4321)
|
|
44
|
+
# PROVE_BASE_URL dev base for browser check (default http://localhost:4321).
|
|
45
|
+
# `--base <url>` is the flag form of exactly this, and wins.
|
|
19
46
|
# PROVE_PROD_URL prod fallback base (default https://one.ie)
|
|
20
47
|
# PROVE_CHECK_CMD optional check command for non-frontend surfaces; if set and
|
|
21
48
|
# it fails, do-prove.sh exits nonzero.
|
|
49
|
+
# PROVE_SESSION_COOKIE
|
|
50
|
+
# `name=value` session cookie, sent on BOTH legs — chrome.mjs
|
|
51
|
+
# already reads this env var itself; the curl leg now sends it
|
|
52
|
+
# as a Cookie header. Needed to prove any authed route
|
|
53
|
+
# (anything under /u/<slug>/…). Against a LOCAL dev base it is
|
|
54
|
+
# acquired automatically via one.ie/web/scripts/dev-sign-in.ts
|
|
55
|
+
# so a promise's proof: still runs in a bare shell; set it by
|
|
56
|
+
# hand for a remote base. Sent to a localhost base only — the
|
|
57
|
+
# prod fallback leg never carries it.
|
|
58
|
+
# PROVE_NO_SESSION=1
|
|
59
|
+
# skip session acquisition — the documented way to drive the
|
|
60
|
+
# landing rule red on demand (`--route /u/one/tasks` then fails
|
|
61
|
+
# with "landed on /signin"). Without it the red state is only
|
|
62
|
+
# reachable when sign-in itself fails.
|
|
63
|
+
#
|
|
64
|
+
# LANDING RULE (2026-08-04): a route is proven only if the browser/curl ENDED UP
|
|
65
|
+
# on the path that was asked for. Measured: `--route /u/one/tasks` signed-out
|
|
66
|
+
# 302s to /signin, which renders 200 with zero console errors — so do-prove
|
|
67
|
+
# reported "ok" and a promise's proof clause went green on the sign-in page. The
|
|
68
|
+
# tasks page was never loaded. Every authed `/u/one/*` clause in the corpus had
|
|
69
|
+
# the same hole. Path is compared without query or trailing slash, so
|
|
70
|
+
# `/u/one/in?dest=tasks` still proves itself.
|
|
22
71
|
#
|
|
23
72
|
# Exit codes: 0 = pass or skipped (no reachable environment) · 1 = a reachable
|
|
24
|
-
# page failed (HTTP >= 500 / status 0 / console+JS errors
|
|
73
|
+
# page failed (HTTP >= 500 / 404 / status 0 / console+JS errors / landed on a
|
|
74
|
+
# different path than requested), a declared check failed, or an explicit --base
|
|
75
|
+
# answered nothing · 2 = usage error (unknown flag, or a flag missing its value).
|
|
76
|
+
#
|
|
77
|
+
# --self-test drives both halves red and green with no live server required.
|
|
25
78
|
set -euo pipefail
|
|
26
79
|
|
|
27
80
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
@@ -31,11 +84,34 @@ BROWSER_CHECK="$ROOT/.claude/scripts/chrome.mjs"
|
|
|
31
84
|
|
|
32
85
|
routes=()
|
|
33
86
|
paths=()
|
|
87
|
+
base_explicit=0
|
|
88
|
+
self_test=0
|
|
89
|
+
|
|
90
|
+
prove_usage() {
|
|
91
|
+
echo "PROVE: usage: do-prove.sh [--route <path>]... [--base <url>] [--self-test] [<changed-path>|<cycle-slug>]..."
|
|
92
|
+
}
|
|
93
|
+
|
|
34
94
|
while [ "$#" -gt 0 ]; do
|
|
35
95
|
case "$1" in
|
|
36
96
|
--route)
|
|
37
|
-
[ "$#" -ge 2 ] || { echo "PROVE: --route requires a value"; exit
|
|
97
|
+
[ "$#" -ge 2 ] || { echo "PROVE: --route requires a value"; exit 2; }
|
|
38
98
|
routes+=("$2"); shift 2 ;;
|
|
99
|
+
--base)
|
|
100
|
+
# The flag form of PROVE_BASE_URL. Trailing slash stripped so
|
|
101
|
+
# "$BASE_URL$route" never produces a double slash.
|
|
102
|
+
[ "$#" -ge 2 ] || { echo "PROVE: --base requires a value"; exit 2; }
|
|
103
|
+
BASE_URL="${2%/}"; base_explicit=1; shift 2 ;;
|
|
104
|
+
--self-test)
|
|
105
|
+
self_test=1; shift ;;
|
|
106
|
+
-h|--help)
|
|
107
|
+
prove_usage; exit 0 ;;
|
|
108
|
+
-*)
|
|
109
|
+
# THE ROOT CAUSE, closed. A token that looks like a flag and is not one is
|
|
110
|
+
# a caller asking for something this script cannot do — never a cycle slug.
|
|
111
|
+
# Silently continuing is how `--base https://one.ie` became a no-op.
|
|
112
|
+
echo "PROVE: unknown flag '$1'" >&2
|
|
113
|
+
prove_usage >&2
|
|
114
|
+
exit 2 ;;
|
|
39
115
|
*)
|
|
40
116
|
# A real path (exists on disk relative to root or cwd) counts as a changed
|
|
41
117
|
# path; anything else (a cycle slug) is noted and ignored for detection.
|
|
@@ -48,6 +124,17 @@ while [ "$#" -gt 0 ]; do
|
|
|
48
124
|
esac
|
|
49
125
|
done
|
|
50
126
|
|
|
127
|
+
# An explicit --base means "prove HERE, nowhere else". Only an explicitly
|
|
128
|
+
# exported PROVE_PROD_URL may name a different fallback (land.sh does exactly
|
|
129
|
+
# that, pinning both to the dev URL).
|
|
130
|
+
if [ "$base_explicit" -eq 1 ] && [ -z "${PROVE_PROD_URL:-}" ]; then
|
|
131
|
+
PROD_URL="$BASE_URL"
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
if [ "$self_test" -eq 1 ]; then
|
|
135
|
+
exec bash "$ROOT/.claude/scripts/do-prove-selftest.sh" "$ROOT/.claude/scripts/do-prove.sh"
|
|
136
|
+
fi
|
|
137
|
+
|
|
51
138
|
# stdin (piped) paths
|
|
52
139
|
if [ "${#paths[@]}" -eq 0 ] && [ ! -t 0 ]; then
|
|
53
140
|
while IFS= read -r l; do [ -n "$l" ] && paths+=("$l"); done || true
|
|
@@ -130,9 +217,122 @@ routes=("${deduped[@]}")
|
|
|
130
217
|
dev_up=0
|
|
131
218
|
if curl -sf -o /dev/null --max-time 4 "$BASE_URL/" 2>/dev/null; then dev_up=1; fi
|
|
132
219
|
|
|
133
|
-
|
|
134
|
-
|
|
220
|
+
# A session turns "the sign-in page rendered" into "the page under test rendered".
|
|
221
|
+
# chrome.mjs reads PROVE_SESSION_COOKIE from the environment on its own (it is
|
|
222
|
+
# inherited by the `node` call below); the curl leg needs it passed explicitly.
|
|
223
|
+
#
|
|
224
|
+
# Auto-acquire against a LOCAL dev server only. A promise's proof: has to run in
|
|
225
|
+
# a bare shell — that is the whole point of the kill-switch — so requiring a
|
|
226
|
+
# human to export a cookie first would just move the fail-open one level up.
|
|
227
|
+
# Strictly gated: localhost/127.0.0.1 base, dev-sign-in.ts present, no cookie
|
|
228
|
+
# already set. Never against a remote host, and the value is never echoed.
|
|
229
|
+
_prove_local_base() {
|
|
230
|
+
case "$BASE_URL" in
|
|
231
|
+
http://localhost:*|http://localhost|http://127.0.0.1:*|http://127.0.0.1) return 0 ;;
|
|
232
|
+
*) return 1 ;;
|
|
233
|
+
esac
|
|
135
234
|
}
|
|
235
|
+
# LAZY, and only on a /signin bounce. Signing in up front changes the answer for
|
|
236
|
+
# routes that were already fine: locally, DEV_SLUG lets a signed-out request
|
|
237
|
+
# render /u/one/* as workspace `one`, while a real session is tony@one.ie — so
|
|
238
|
+
# an eager session turned `--route /u/one/workflows` from a genuine pass into
|
|
239
|
+
# "landed on /u/tony/workflows". Measured 2026-08-04. Try signed-out first; only
|
|
240
|
+
# a bounce to the login wall is worth a second attempt.
|
|
241
|
+
#
|
|
242
|
+
# PROVE_NO_SESSION=1 disables the retry entirely. Without it the landing rule's
|
|
243
|
+
# red half is only reachable when sign-in itself fails, i.e. by accident — and a
|
|
244
|
+
# gate nobody can drive red on demand is what this whole change exists to
|
|
245
|
+
# prevent. The documented two-line matrix:
|
|
246
|
+
# PROVE_NO_SESSION=1 do-prove.sh --route /u/one/tasks → FAIL, landed on /signin
|
|
247
|
+
# do-prove.sh --route /u/one/tasks → ok (retried with a session)
|
|
248
|
+
_session_tried=0
|
|
249
|
+
prove_acquire_session() { # → 0 if a cookie is now available, 1 otherwise
|
|
250
|
+
[ -n "${PROVE_SESSION_COOKIE:-}" ] && return 0
|
|
251
|
+
[ -n "${PROVE_NO_SESSION:-}" ] && return 1
|
|
252
|
+
[ "$_session_tried" -eq 1 ] && return 1
|
|
253
|
+
_session_tried=1
|
|
254
|
+
_prove_local_base || return 1
|
|
255
|
+
local c=""
|
|
256
|
+
# Preferred: the repo's own script. It seeds the credential in local D1 first,
|
|
257
|
+
# so it only works from a tree that has .wrangler/state — i.e. the main tree,
|
|
258
|
+
# which is where promise proofs actually run.
|
|
259
|
+
if [ -f "$ROOT/one.ie/web/scripts/dev-sign-in.ts" ] && command -v bun >/dev/null 2>&1; then
|
|
260
|
+
c="$( (cd "$ROOT/one.ie/web" && bun scripts/dev-sign-in.ts 2>/dev/null) \
|
|
261
|
+
| sed -n 's/^Set-Cookie: //p' | head -1 || true)"
|
|
262
|
+
fi
|
|
263
|
+
# Fallback for a worktree (no local D1 state): plain HTTP sign-in, but only
|
|
264
|
+
# with credentials the caller supplied. No password is hardcoded here —
|
|
265
|
+
# one.ie/web/scripts/dev-sign-in.ts stays the single source of the dev creds.
|
|
266
|
+
if [ -z "$c" ] && [ -n "${OWNER_EMAIL:-}" ] && [ -n "${DEV_PASSWORD:-}" ]; then
|
|
267
|
+
c="$(curl -s -D - -o /dev/null --max-time 20 -X POST \
|
|
268
|
+
-H 'Content-Type: application/json' -H "Origin: $BASE_URL" \
|
|
269
|
+
--data "{\"email\":\"${OWNER_EMAIL}\",\"password\":\"${DEV_PASSWORD}\"}" \
|
|
270
|
+
"$BASE_URL/api/auth/sign-in/email" 2>/dev/null \
|
|
271
|
+
| sed -n 's/^[Ss]et-[Cc]ookie: \(better-auth\.session_token=[^;]*\).*/\1/p' | head -1 || true)"
|
|
272
|
+
fi
|
|
273
|
+
[ -z "$c" ] && return 1
|
|
274
|
+
export PROVE_SESSION_COOKIE="$c"
|
|
275
|
+
curl_auth=(-H "Cookie: $c")
|
|
276
|
+
echo "PROVE: signed-out run hit the login wall — retrying with a dev session"
|
|
277
|
+
return 0
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# A login wall is the one landing worth a retry; anything else is a real answer.
|
|
281
|
+
is_signin_path() {
|
|
282
|
+
case "$1" in /signin|/login|/sign-in) return 0 ;; *) return 1 ;; esac
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
curl_auth=()
|
|
286
|
+
[ -n "${PROVE_SESSION_COOKIE:-}" ] && curl_auth=(-H "Cookie: ${PROVE_SESSION_COOKIE}")
|
|
287
|
+
|
|
288
|
+
check_route_curl() { # $1 = base, $2 = route → echoes "<http_code> <final_url>"
|
|
289
|
+
# -L on purpose: a redirect is followed so the LANDING RULE can see where it
|
|
290
|
+
# ended up. Without it every 302 read as a bare 3xx and the old code scored
|
|
291
|
+
# that as "ok — not >=500, not 404", which is how a signed-out authed route
|
|
292
|
+
# proved itself green.
|
|
293
|
+
# The session cookie goes to a LOCAL base only. Auto-acquire is already
|
|
294
|
+
# localhost-gated, but a hand-exported PROVE_SESSION_COOKIE is not — and this
|
|
295
|
+
# same function serves the prod fallback below, so without this check a dev
|
|
296
|
+
# server being down would send a live session cookie to $PROD_URL.
|
|
297
|
+
local auth=()
|
|
298
|
+
case "$1" in
|
|
299
|
+
http://localhost|http://localhost:*|http://127.0.0.1|http://127.0.0.1:*)
|
|
300
|
+
auth=("${curl_auth[@]+"${curl_auth[@]}"}") ;;
|
|
301
|
+
esac
|
|
302
|
+
curl -sL -o /dev/null --max-time 20 "${auth[@]+"${auth[@]}"}" \
|
|
303
|
+
-w '%{http_code} %{url_effective}' "$1$2" 2>/dev/null || echo "000 "
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
# Pathname only — no scheme/host, no query, no fragment, no trailing slash.
|
|
307
|
+
# The landing rule compares these, so `/u/one/in?dest=tasks` matches its own
|
|
308
|
+
# redirect-free landing and a bounce to /signin does not.
|
|
309
|
+
path_of() {
|
|
310
|
+
local u="$1" rest
|
|
311
|
+
case "$u" in
|
|
312
|
+
*://*) rest="${u#*://}"
|
|
313
|
+
case "$rest" in
|
|
314
|
+
*/*) u="/${rest#*/}" ;;
|
|
315
|
+
*) u="/" ;;
|
|
316
|
+
esac ;;
|
|
317
|
+
esac
|
|
318
|
+
u="${u%%\?*}"; u="${u%%#*}"
|
|
319
|
+
case "$u" in ""|"/") printf '/' ;; *) printf '%s' "${u%/}" ;; esac
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
# One place decides what a wrong landing means, so both legs say the same thing.
|
|
323
|
+
report_redirect() { # $1 = route, $2 = landed path, $3 = leg label
|
|
324
|
+
echo "PROVE: FAIL $1 — landed on $2, not $(path_of "$1") ($3) — the page under test never rendered"
|
|
325
|
+
case "$2" in
|
|
326
|
+
/signin|/login|/sign-in)
|
|
327
|
+
echo "PROVE: hint: authed route — export PROVE_SESSION_COOKIE='better-auth.session_token=…'"
|
|
328
|
+
echo "PROVE: (cd one.ie/web && bun scripts/dev-sign-in.ts prints one)" ;;
|
|
329
|
+
esac
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
# The result line used to hardcode the word "dev" — so a production run
|
|
333
|
+
# printed "(dev https://one.ie)" on the very receipt someone reads to decide
|
|
334
|
+
# whether the site is live. Name the leg for what it is.
|
|
335
|
+
if _prove_local_base; then LEG="dev $BASE_URL"; else LEG="base $BASE_URL"; fi
|
|
136
336
|
|
|
137
337
|
fail=0
|
|
138
338
|
checked=0
|
|
@@ -154,47 +354,112 @@ for route in "${routes[@]}"; do
|
|
|
154
354
|
# "Failed to load resource: … 401", which curl had always passed. Everything
|
|
155
355
|
# else still counts — uncaught JS, real console.error, and subresource
|
|
156
356
|
# 404/5xx, which are genuine breakage.
|
|
157
|
-
|
|
357
|
+
# 400 joins the same carve-out for the same reason: Layout.astro fires a
|
|
358
|
+
# fire-and-forget tracking beacon (/api/follow) on every page, and it
|
|
359
|
+
# answers 400 missing_slug on any page outside a tenant workspace — measured
|
|
360
|
+
# on /, /components and prod one.ie/components identically (2026-08-07,
|
|
361
|
+
# livekit C5). The beacon's failure has no bearing on the page; it is
|
|
362
|
+
# gated-by-context the same way 401/403 is gated-by-session.
|
|
363
|
+
counted='((.jsErrors // []) + ((.consoleErrors // []) | map(select(test("status of (400|401|403)") | not))))'
|
|
364
|
+
# Against a LOCAL base only, a subresource 503 joins that list. Plain
|
|
365
|
+
# `astro dev` binds no Durable Objects, so /api/analytics answers 503
|
|
366
|
+
# intermittently — measured 2026-08-04 at roughly 1 load in 4, which made the
|
|
367
|
+
# types-views proof flip GREEN/GREEN/RED across three identical sweeps. Same
|
|
368
|
+
# reasoning as the 401/403 policy above: the environment is limited, the page
|
|
369
|
+
# is not broken. Scoped to localhost so a 503 in prod still fails, and every
|
|
370
|
+
# ignored one is PRINTED below rather than silently dropped. `dev:wrangler`
|
|
371
|
+
# binds the DOs and makes this moot.
|
|
372
|
+
if _prove_local_base; then
|
|
373
|
+
counted='((.jsErrors // []) + ((.consoleErrors // []) | map(select(test("status of (400|401|403|503)") | not))))'
|
|
374
|
+
ignored='((.consoleErrors // []) | map(select(test("status of 503"))) | length)'
|
|
375
|
+
else
|
|
376
|
+
ignored='0'
|
|
377
|
+
fi
|
|
158
378
|
errs="$(printf '%s' "$out" | jq -r "$counted | length" 2>/dev/null || echo "")"
|
|
379
|
+
final="$(printf '%s' "$out" | jq -r '.finalUrl // ""' 2>/dev/null || echo "")"
|
|
380
|
+
# Hit the login wall signed-out? That is the one case a session can change,
|
|
381
|
+
# so retry once. Any other landing is the real answer and is left alone.
|
|
382
|
+
if is_signin_path "$(path_of "${final:-$route}")" && prove_acquire_session; then
|
|
383
|
+
out="$(node "$BROWSER_CHECK" "$BASE_URL$route" 2>/dev/null || true)"
|
|
384
|
+
status="$(printf '%s' "$out" | jq -r '.httpStatus // 0' 2>/dev/null || echo 0)"
|
|
385
|
+
errs="$(printf '%s' "$out" | jq -r "$counted | length" 2>/dev/null || echo "")"
|
|
386
|
+
final="$(printf '%s' "$out" | jq -r '.finalUrl // ""' 2>/dev/null || echo "")"
|
|
387
|
+
fi
|
|
388
|
+
# One retry when the ONLY complaint is console errors on an otherwise correct
|
|
389
|
+
# landing. Vite's first load after it pulls a new dep throws `useState of
|
|
390
|
+
# null` / "more than one copy of React" and they vanish once the optimizer
|
|
391
|
+
# settles (learnings 2026-08-02). Measured 2026-08-04: the same /u/one/tasks
|
|
392
|
+
# proof came back exit=1 then exit=0 with no edit in between — a gate that
|
|
393
|
+
# flips on a re-run cannot settle a promise. Status and landing failures are
|
|
394
|
+
# NOT retried; a genuinely broken page fails both runs, so this kills the
|
|
395
|
+
# flake without buying a flaky pass.
|
|
396
|
+
landed="$(path_of "${final:-$route}")"
|
|
397
|
+
if [ -n "$status" ] && [ "$status" != "0" ] && [ -n "$errs" ] && [ "$errs" -gt 0 ] \
|
|
398
|
+
&& [ "$status" -lt 500 ] && [ "$status" -ne 404 ] && [ "$landed" = "$(path_of "$route")" ]; then
|
|
399
|
+
out="$(node "$BROWSER_CHECK" "$BASE_URL$route" 2>/dev/null || true)"
|
|
400
|
+
status="$(printf '%s' "$out" | jq -r '.httpStatus // 0' 2>/dev/null || echo 0)"
|
|
401
|
+
errs="$(printf '%s' "$out" | jq -r "$counted | length" 2>/dev/null || echo "")"
|
|
402
|
+
final="$(printf '%s' "$out" | jq -r '.finalUrl // ""' 2>/dev/null || echo "")"
|
|
403
|
+
fi
|
|
159
404
|
if [ -n "$status" ] && [ "$status" != "0" ] && [ -n "$errs" ]; then
|
|
160
405
|
proved=1; checked=$((checked+1))
|
|
406
|
+
landed="$(path_of "${final:-$route}")"
|
|
407
|
+
# LANDING RULE first — a bounce to /signin renders 200 with zero errors, so
|
|
408
|
+
# every check below it would pass on a page that is not the one requested.
|
|
161
409
|
# 404 IS A FAIL here too. The curl leg below learned this on 2026-07-29;
|
|
162
410
|
# the browser leg never did, so a nonexistent route proved itself green
|
|
163
411
|
# whenever the page also logged no errors. 401/403 stay ok — gated, not gone.
|
|
164
|
-
if [ "$
|
|
165
|
-
|
|
412
|
+
if [ -n "$final" ] && [ "$landed" != "$(path_of "$route")" ]; then
|
|
413
|
+
report_redirect "$route" "$landed" "$LEG"
|
|
414
|
+
fail=1
|
|
415
|
+
elif [ "$status" -ge 500 ] || [ "$status" -eq 404 ] || [ "$errs" -gt 0 ]; then
|
|
416
|
+
echo "PROVE: FAIL $route — http=$status console/js errors=$errs ($LEG)"
|
|
166
417
|
printf '%s' "$out" | jq -r "$counted[]" 2>/dev/null | head -5 | sed 's/^/PROVE: error: /'
|
|
167
418
|
fail=1
|
|
168
419
|
else
|
|
169
|
-
echo "PROVE: ok $route — http=$status, 0 console/js errors (
|
|
420
|
+
echo "PROVE: ok $route — http=$status, 0 console/js errors ($LEG)"
|
|
170
421
|
fi
|
|
422
|
+
# Never silent: an ignored error is still an error someone should see.
|
|
423
|
+
ign="$(printf '%s' "$out" | jq -r "$ignored" 2>/dev/null || echo 0)"
|
|
424
|
+
[ "${ign:-0}" -gt 0 ] 2>/dev/null && \
|
|
425
|
+
echo "PROVE: note — $ign subresource 503(s) ignored (no DO bindings in vite dev; dev:wrangler for DO parity)"
|
|
171
426
|
fi
|
|
172
427
|
# status 0 / unparsable = environmental (browser-check couldn't run) → fall through
|
|
173
428
|
fi
|
|
174
429
|
if [ "$proved" -eq 0 ] && [ "$dev_up" -eq 1 ]; then
|
|
175
430
|
# dev reachable but playwright unavailable → curl the dev route
|
|
176
|
-
code
|
|
431
|
+
read -r code effective <<< "$(check_route_curl "$BASE_URL" "$route")"
|
|
432
|
+
if is_signin_path "$(path_of "${effective:-$route}")" && prove_acquire_session; then
|
|
433
|
+
read -r code effective <<< "$(check_route_curl "$BASE_URL" "$route")"
|
|
434
|
+
fi
|
|
177
435
|
if [ "$code" != "000" ]; then
|
|
178
436
|
proved=1; checked=$((checked+1))
|
|
179
|
-
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
|
|
185
|
-
|
|
437
|
+
landed="$(path_of "${effective:-$route}")"
|
|
438
|
+
# LANDING RULE, then 404. 404 IS A FAIL: it used to report `ok` — only >=500
|
|
439
|
+
# failed — so a route that does not exist proved itself. Measured 2026-07-29:
|
|
440
|
+
# `--route /factory` returned "ok /factory — http=404" against a dev server
|
|
441
|
+
# running a tree without the page, and that line was the 17th leg of a
|
|
442
|
+
# promise's proof. 401/403 stay ok: the route answered, it is merely gated.
|
|
443
|
+
if [ -n "$effective" ] && [ "$landed" != "$(path_of "$route")" ]; then
|
|
444
|
+
report_redirect "$route" "$landed" "$LEG, curl"; fail=1
|
|
445
|
+
elif [ "$code" -ge 500 ] || [ "$code" -eq 404 ]; then
|
|
446
|
+
echo "PROVE: FAIL $route — http=$code ($LEG, curl)"; fail=1
|
|
186
447
|
else
|
|
187
|
-
echo "PROVE: ok $route — http=$code (
|
|
448
|
+
echo "PROVE: ok $route — http=$code ($LEG, curl)"
|
|
188
449
|
fi
|
|
189
450
|
fi
|
|
190
451
|
fi
|
|
191
452
|
if [ "$proved" -eq 0 ]; then
|
|
192
|
-
code
|
|
453
|
+
read -r code effective <<< "$(check_route_curl "$PROD_URL" "$route")"
|
|
193
454
|
if [ "$code" != "000" ]; then
|
|
194
455
|
checked=$((checked+1))
|
|
195
|
-
# Same
|
|
196
|
-
#
|
|
197
|
-
|
|
456
|
+
# Same rules as the dev branch above — a redirect off the requested path
|
|
457
|
+
# proves the wrong page, and a 404 in production is the clearest possible
|
|
458
|
+
# "not shipped". Neither may read as proven.
|
|
459
|
+
landed="$(path_of "${effective:-$route}")"
|
|
460
|
+
if [ -n "$effective" ] && [ "$landed" != "$(path_of "$route")" ]; then
|
|
461
|
+
report_redirect "$route" "$landed" "prod $PROD_URL"; fail=1
|
|
462
|
+
elif [ "$code" -ge 500 ] || [ "$code" -eq 404 ]; then
|
|
198
463
|
echo "PROVE: FAIL $route — http=$code (prod $PROD_URL)"; fail=1
|
|
199
464
|
else
|
|
200
465
|
echo "PROVE: ok $route — http=$code (prod $PROD_URL)"
|
|
@@ -209,6 +474,13 @@ if [ "$fail" -eq 1 ]; then
|
|
|
209
474
|
echo "PROVE: fail"; exit 1
|
|
210
475
|
fi
|
|
211
476
|
if [ "$checked" -eq 0 ]; then
|
|
477
|
+
# An explicitly named base that answered nothing is an UNRUN PROOF, and
|
|
478
|
+
# do-promise-settle.sh reads this exit code verbatim. Exit 0 here would settle
|
|
479
|
+
# a promise KEPT because the site was unreachable.
|
|
480
|
+
if [ "$base_explicit" -eq 1 ]; then
|
|
481
|
+
echo "PROVE: FAIL — --base $BASE_URL answered nothing; an unrun proof is not a pass"
|
|
482
|
+
exit 1
|
|
483
|
+
fi
|
|
212
484
|
echo "PROVE: skipped (no reachable environment)"; exit 0
|
|
213
485
|
fi
|
|
214
486
|
echo "PROVE: pass ($checked route(s) proven)"; exit 0
|
package/scripts/do-rank.py
CHANGED
|
@@ -96,6 +96,19 @@ def deliverable_dirs(text):
|
|
|
96
96
|
dirs = set()
|
|
97
97
|
for tok in deliverable_paths(text):
|
|
98
98
|
parts = tok.split("/")
|
|
99
|
+
# `text/` is the ONE family where the containing-dir rule is wrong. The
|
|
100
|
+
# coupling argument above holds for code (two plans in one component family
|
|
101
|
+
# clobber each other); it does not hold here, because text/ is one flat dir
|
|
102
|
+
# of per-slug documents — `text/<slug>-docs.md` is named after the plan that
|
|
103
|
+
# owns it, so two plans there edit two different files BY CONSTRUCTION and
|
|
104
|
+
# cannot collide. Keying them to the shared `text` dir made every plan with a
|
|
105
|
+
# `doc:` deliverable mutually exclusive with every other: measured 2026-08-31,
|
|
106
|
+
# it serialized all four lifecycle children (and voice-agents, identity,
|
|
107
|
+
# playbook-run, agent-wallet-guardian) behind one another for no real conflict.
|
|
108
|
+
# File granularity here, containing-dir everywhere else.
|
|
109
|
+
if parts[0] == "text" and len(parts) == 2 and "." in parts[-1]:
|
|
110
|
+
dirs.add(tok)
|
|
111
|
+
continue
|
|
99
112
|
# Drop the leaf if it names a file (has an extension); else the path IS a dir.
|
|
100
113
|
sub = "/".join(parts[:-1]) if "." in parts[-1] else tok
|
|
101
114
|
if sub:
|
|
@@ -121,7 +134,12 @@ def deliverable_paths(text):
|
|
|
121
134
|
"""Every repo-root path token in the `deliverables:` block (full path, not the
|
|
122
135
|
top/second dir). The granularity-independent source — deliverable_dirs() and the
|
|
123
136
|
linter both derive from it. Path column only (before the em-dash), REPO_DIRS-rooted."""
|
|
124
|
-
|
|
137
|
+
# The key line may carry a trailing YAML comment — `deliverables: # note`.
|
|
138
|
+
# It legally does in 12 tracked plans INCLUDING text/template-todo.md, the
|
|
139
|
+
# file every new plan is copied from, so a `\s*$` anchor here made plans
|
|
140
|
+
# born unscoped: the block never matched, zero paths came back, and the
|
|
141
|
+
# fleet read that as "declares no dirs" and refused to pack them.
|
|
142
|
+
m = re.search(r"^deliverables:[ \t]*(?:#[^\n]*)?$(.*?)(?=^[a-z_]+:|^---\s*$|\Z)",
|
|
125
143
|
text, re.MULTILINE | re.DOTALL)
|
|
126
144
|
if not m:
|
|
127
145
|
return []
|
|
@@ -1122,6 +1140,18 @@ def selftest():
|
|
|
1122
1140
|
check("dirs: filename dropped",
|
|
1123
1141
|
"one.ie/web/src/lib/billing/expiry.ts" not in deliverable_dirs(fm_sub))
|
|
1124
1142
|
check("dirs: bare dir kept", "channels/src" in deliverable_dirs(fm_sub))
|
|
1143
|
+
# text/ file granularity — two plans' docs must NOT collapse to one `text` lock.
|
|
1144
|
+
fm_t1 = "deliverables:\n - doc: text/alpha-docs.md — x\n"
|
|
1145
|
+
fm_t2 = "deliverables:\n - doc: text/beta-docs.md — x\n"
|
|
1146
|
+
check("dirs: text/ keeps the filename",
|
|
1147
|
+
"text/alpha-docs.md" in deliverable_dirs(fm_t1))
|
|
1148
|
+
check("dirs: text/ does not collapse to the bare dir",
|
|
1149
|
+
"text" not in deliverable_dirs(fm_t1))
|
|
1150
|
+
check("dirs: two text/ docs are disjoint",
|
|
1151
|
+
not (deliverable_dirs(fm_t1) & deliverable_dirs(fm_t2)))
|
|
1152
|
+
# RED half — the old behaviour must be genuinely gone, not merely untested.
|
|
1153
|
+
check("dirs: text/ nested path still uses its containing dir",
|
|
1154
|
+
"text/world" in deliverable_dirs("deliverables:\n - doc: text/world/homepage-text.md — x\n"))
|
|
1125
1155
|
|
|
1126
1156
|
# 6. transitive leverage: a→b→c chain ⇒ a has 2 dependents (b and c), not 1.
|
|
1127
1157
|
direct = {"a": {"b"}, "b": {"c"}, "c": set()}
|
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
# prune → delete entries older than MAX_AGE_DAYS
|
|
12
12
|
set -euo pipefail
|
|
13
13
|
|
|
14
|
-
CACHE_DIR
|
|
14
|
+
# CACHE_DIR must NOT be CWD-relative. Every /do cycle runs in a fresh
|
|
15
|
+
# .do-worktrees/<slug> checkout, so a relative `.w1-cache` was born empty on every
|
|
16
|
+
# single cycle -- the "0 tokens on hit, ~12k saved/recon" lever this script exists
|
|
17
|
+
# to provide had never once fired in a worktree run (measured 2026-09-01: no
|
|
18
|
+
# .w1-cache directory existed anywhere in the tree). Key it to the MACHINE, the
|
|
19
|
+
# same way the gate governor keys its locks, so worktrees share one warm store.
|
|
20
|
+
CACHE_DIR="${CACHE_DIR:-${TMPDIR:-/tmp}/one-w1-cache}"
|
|
15
21
|
MAX_AGE_DAYS=14
|
|
16
22
|
BASE_URL="${ONEIE_BASE_URL:-${ONE_BASE_URL:-}}"
|
|
17
23
|
API_KEY="${WAVE_CACHE_SECRET:-${ONEIE_API_KEY:-${ONE_API_KEY:-}}}"
|