Files
miti99bot-js/scripts/wrangler-delete-guard.sh
tiennm99 3f03521e84 feat(scripts): phase 07 — reverse-backfill scripts + delete guard
Pre-execution prerequisites for the Phase 07 cutover. Stage 2 of the
cutover keeps DUAL_WRITE=0 for ~6 days; if anything regresses during
that window the operator MUST be able to roll back to KV/D1 with the
last N days of Mongo-only writes recovered. Pre-building these scripts
(per code-reviewer #4) eliminates "draft a backfill under outage
pressure" — the anti-pattern of writing untested code at 4am.

Reverse-backfill
- scripts/backfill-mongo-to-kv.js: full-scan Mongo collection per module,
  PUT each doc back to CF KV via REST. expiresAt → expirationTtl (clamped
  to 60s minimum per CF KV); already-expired docs are skipped (won't
  resurrect dead state). 50 ops/sec throttle. --dry-run + --module flags.
- scripts/backfill-mongo-to-d1.js: full-scan trading_trades, build INSERT
  SQL preserving legacy_id where present (round-trips D1 autoincrement IDs
  preserved by phase-05 forward backfill). Sequential int generation for
  any docs without legacy_id. Pipes through wrangler d1 execute.
- scripts/lib/migration-helpers.js: cfKvPut helper added.

Delete guard (debugger #12)
- scripts/wrangler-delete-guard.sh: interactive CONFIRM wrapper around
  wrangler kv namespace delete + wrangler d1 delete. Exits 3 when stdin
  is not a tty so it cannot run in CI. Documented: never run in CI.

package.json: backfill:mongo:kv[:dry] + backfill:mongo:d1[:dry] scripts
wired.

Tests: 697 → 733 (+36).
- 7 cfKvPut tests (REST URL, querystring, body, expiration_ttl param).
- 10 reverse-KV TTL math tests (expired sentinel, future seconds, no-TTL,
  CF 60s minimum clamp).
- 9 reverse-D1 SQL construction tests (escaping, legacy_id preservation,
  sequential generation).

Lint clean. No Worker code touched. Stage 1 cutover, 7-day soak,
snapshots, and Stage 3 cleanup (delete CFKVStore + simplify factories +
edit package.json deploy chain) remain operator-driven and will be
committed separately after binding deletion.
2026-04-26 09:29:14 +07:00

60 lines
1.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# wrangler-delete-guard.sh — interactive CONFIRM wrapper around irreversible
# wrangler delete commands. NEVER use in CI.
#
# Usage:
# bash scripts/wrangler-delete-guard.sh kv <namespace-id>
# bash scripts/wrangler-delete-guard.sh d1 <database-name>
#
# Exits:
# 0 — command executed successfully
# 1 — user aborted (did not type CONFIRM)
# 2 — bad arguments
# 3 — stdin not a tty (CI safety)
set -euo pipefail
if [[ $# -lt 2 ]]; then
echo "usage: $0 {kv|d1} <id-or-name>" >&2
exit 2
fi
KIND="$1"
TARGET="$2"
case "$KIND" in
kv)
DESC="KV namespace $TARGET"
CMD=(npx wrangler kv namespace delete --namespace-id "$TARGET")
;;
d1)
DESC="D1 database $TARGET"
CMD=(npx wrangler d1 delete "$TARGET")
;;
*)
echo "unknown kind: $KIND (expected 'kv' or 'd1')" >&2
exit 2
;;
esac
# Refuse to run non-interactively — prevents accidental CI execution.
if [[ ! -t 0 ]]; then
echo "stdin not a tty — refusing to run non-interactively (CI safety)" >&2
exit 3
fi
echo ""
echo "ABOUT TO DELETE: $DESC"
echo "This is IRREVERSIBLE. Backup files must already be on local disk."
echo ""
read -r -p "Type CONFIRM to proceed: " CONFIRM
if [[ "$CONFIRM" != "CONFIRM" ]]; then
echo "aborted" >&2
exit 1
fi
echo ""
echo "executing: ${CMD[*]}"
"${CMD[@]}"