← back to Rentv Slideshow Canary
check.sh
100 lines
#!/bin/bash
# rentv-slideshow-canary — READ-ONLY revert watch for the /consulting/slideshow fix.
#
# WHY: the fix (fetch fallback resolves the deliverable at /consulting) is live on prod
# via single-file rsync + committed as d70fac6 in ~/Projects/rentv. But rsync ships the
# WORKING TREE not HEAD (fleet gotcha, TK-10295) — if claude-rentv deploys from a separate
# checkout whose working tree still has the old /portal-only line, the next deploy SILENTLY
# reverts prod and nothing would notice until a human hits the broken URL. This canary GETs
# the live page and greps for the fix marker; on an OK->REVERTED transition it alerts.
#
# Touches nothing but an outbound HTTPS GET. No prod shell, no worktree, no writes anywhere
# except this dir's data/. Baseline-aware: alerts ONLY on the worsening transition (prev=OK),
# never on first run, steady state, recovery, or a transient non-200 (UNKNOWN). Single-shot
# (won't re-nag) so a sustained revert can't spam.
set -uo pipefail
# launchd runs with a minimal PATH — make tk/curl resolvable.
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"
# Env overrides (for testing): CANARY_URL, CANARY_MARKER, CANARY_DRYRUN=1 (print, don't alert).
URL="${CANARY_URL:-https://rentv.agentabrams.com/consulting/slideshow}"
CRED="admin:DW2024!"
MARKER="${CANARY_MARKER:-return load('/consulting')}"
DIR="$(cd "$(dirname "$0")" && pwd)"
LATEST="$DIR/data/latest.json"
NOW="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
NOW_EPOCH="$(date +%s)"
RETIRE_HOURS="${CANARY_RETIRE_HOURS:-48}" # auto-retire after this many hours of continuous OK
RETIRE_AT_FILE="$DIR/data/retire_at"
JOB="${CANARY_JOB:-com.steve.rentv-slideshow-canary}"
# Already retired? Ensure the launchd job is really gone, then exit (belt-and-suspenders).
if [ -f "$DIR/data/RETIRED" ]; then
nohup bash -c "launchctl bootout gui/$(id -u)/$JOB 2>/dev/null; launchctl disable gui/$(id -u)/$JOB 2>/dev/null" >/dev/null 2>&1 &
echo "[$NOW] already RETIRED — ensuring launchd job removed"; exit 0
fi
prev="NONE"
[ -f "$LATEST" ] && prev="$(grep -o '"status":"[A-Z]*"' "$LATEST" | head -1 | cut -d'"' -f4)"
[ -z "$prev" ] && prev="NONE"
resp="$(curl -s -m 20 -u "$CRED" -w $'\n%{http_code}' "$URL" 2>/dev/null)"
code="$(printf '%s' "$resp" | tail -1)"
html="$(printf '%s' "$resp" | sed '$d')"
if [ "$code" != "200" ]; then
status="UNKNOWN" # transient reachability blip — never alert on this
elif printf '%s' "$html" | grep -qF "$MARKER"; then
status="OK"
else
status="REVERTED" # page loads but the fix marker is gone = broken deck again
fi
mkdir -p "$DIR/data"
# A transient UNKNOWN (unreachable/non-200) must NOT erase the last-known-good baseline,
# or a real revert right after a blip (UNKNOWN->REVERTED) would be missed. Carry prev forward.
persist="$status"
[ "$status" = "UNKNOWN" ] && persist="$prev"
printf '{"status":"%s","http":"%s","at":"%s","observed":"%s","prev":"%s","url":"%s"}\n' \
"$persist" "$code" "$NOW" "$status" "$prev" "$URL" > "$LATEST"
# Worsening transition only: OK -> REVERTED (first run prev=NONE is silent by design).
if [ "$status" = "REVERTED" ] && [ "$prev" = "OK" ]; then
MSG="⚠️ rentv /consulting/slideshow REVERTED at $NOW (http $code): live page lost the fix marker \"$MARKER\" — the slideshow is broken again (falls back to news-homepage scrape). A deploy overwrote the fix. Re-apply commit d70fac6 to the prod deploy source's WORKING TREE. Ref TK-10357."
if [ "${CANARY_DRYRUN:-0}" = "1" ]; then
echo "[$NOW] DRYRUN: WOULD ALERT (OK->REVERTED). MSG: $MSG"
echo "[$NOW] status=$status http=$code prev=$prev"; exit 0
fi
export TK_AGENT=canary-rentv-slideshow
tk comment TK-10357 "$MSG" >/dev/null 2>&1 || true
tk dm claude-rentv "$MSG" -t TK-10357 >/dev/null 2>&1 || true
# CNCP parking-lot card (best-effort; never fail the canary if CNCP is down)
curl -s -m 5 -o /dev/null -X POST http://127.0.0.1:3333/api/parking-lot \
-H 'Content-Type: application/json' \
-d "$(printf '{"project":"rentv","title":"slideshow fix REVERTED on prod","note":%s}' "$(printf '%s' "$MSG" | sed 's/\\/\\\\/g; s/"/\\"/g' | awk '{printf "\"%s\"", $0}')")" 2>/dev/null || true
echo "[$NOW] ALERT sent: OK->REVERTED (http $code)"
fi
echo "[$NOW] status=$status http=$code prev=$prev"
# ── Auto-retire: a standing guard for a resolved fix is stale cruft. Retire after
# RETIRE_HOURS of continuous OK (the fix has already survived a real deploy). A
# REVERTED scare EXTENDS the window (keep guarding after trouble). Skip in dryrun.
if [ "${CANARY_DRYRUN:-0}" != "1" ]; then
[ -f "$RETIRE_AT_FILE" ] || echo $((NOW_EPOCH + RETIRE_HOURS*3600)) > "$RETIRE_AT_FILE"
if [ "$status" = "REVERTED" ]; then
echo $((NOW_EPOCH + RETIRE_HOURS*3600)) > "$RETIRE_AT_FILE" # reset the clock after a scare
elif [ "$status" = "OK" ]; then
deadline="$(cat "$RETIRE_AT_FILE" 2>/dev/null || echo 0)"
if [ "$NOW_EPOCH" -ge "$deadline" ]; then
touch "$DIR/data/RETIRED"
MSG2="✅ rentv-slideshow-canary AUTO-RETIRED at $NOW — the /consulting/slideshow fix held OK continuously for ${RETIRE_HOURS}h across >=1 real prod deploy (TK-10356). Guard no longer needed; launchd job booted out + disabled. Re-arm anytime: launchctl bootstrap gui/\$(id -u) ~/Library/LaunchAgents/$JOB.plist"
export TK_AGENT=canary-rentv-slideshow
tk comment TK-10357 "$MSG2" >/dev/null 2>&1 || true
# tear down our own launchd job from a detached child so this run exits cleanly first
nohup bash -c "sleep 3; launchctl bootout gui/$(id -u)/$JOB 2>/dev/null; launchctl disable gui/$(id -u)/$JOB 2>/dev/null" >/dev/null 2>&1 &
echo "[$NOW] AUTO-RETIRED (${RETIRE_HOURS}h clean) — launchd bootout scheduled"
fi
fi
fi