#!/usr/bin/env bash
# claude-multiacc sandboxed test suite — covers BOTH providers (claude + codex).
# No network, no real accounts, no quota: fake `claude`/`codex` binaries + file://
# usage/token fixtures.
set -u

REPO_DIR="$(cd "$(dirname "$0")/.." && pwd -P)"
WORK="$(mktemp -d "${TMPDIR:-/tmp}/multiacc-test.XXXXXX")" || exit 1
[ -n "$WORK" ] && [ -d "$WORK" ] || exit 1
# Loopback stub servers register their pid here. Deleting $WORK does not kill a running
# python process, so an interrupted run (CI cancel, Ctrl-C) would otherwise leave one
# listening until the machine goes away.
STUB_PIDS=""
cleanup() {
  local p
  for p in $STUB_PIDS; do
    kill "$p" 2>/dev/null
    wait "$p" 2>/dev/null || true
  done
  # The auto-resume sections reap their own processes; this is the backstop for an
  # interrupted run. Every fake client and watcher they start carries $WORK in its argv.
  # Never with an empty WORK: `pkill -f /` would match nearly every process the user owns.
  if [ -n "${WORK:-}" ] && [ -d "$WORK" ]; then
    pkill -KILL -f "$WORK/" 2>/dev/null || true
    rm -rf "$WORK"
  fi
}
trap cleanup EXIT

PASS=0
FAIL=0
t_ok() { PASS=$((PASS+1)); printf 'ok   %s\n' "$1"; }
t_fail() { FAIL=$((FAIL+1)); printf 'FAIL %s%s\n' "$1" "${2:+ — $2}"; }
check() { # check <name> <expected-substring> <actual>
  case "$3" in
    *"$2"*) t_ok "$1" ;;
    *) t_fail "$1" "expected substring '$2', got: $(printf '%s' "$3" | head -c 200)" ;;
  esac
}

# ---- sandbox layout -------------------------------------------------------
export CLAUDE_ACCOUNTS_DIR="$WORK/accounts"
ACC="$CLAUDE_ACCOUNTS_DIR"
FAKEBIN="$WORK/fakebin"
mkdir -p "$ACC/tmp" "$FAKEBIN"

# Fake "real" claude: prints which config dir/token it ran under; scriptable failures.
cat > "$FAKEBIN/claude" <<'EOF'
#!/usr/bin/env bash
# fake real claude for tests (not a multiacc shim)
if [ "${1:-}" = "mcp" ] && [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then
  # A stand-in for the real `claude mcp add|add-json|remove`: `-s user` edits the
  # config dir's .claude.json mcpServers, the default `local` scope edits
  # projects[$PWD].mcpServers, exactly where the real client keeps them.
  python3 - "$CLAUDE_CONFIG_DIR/.claude.json" "$PWD" "$@" <<'PY'
import json, os, sys
path, cwd, argv = sys.argv[1], sys.argv[2], sys.argv[3:]
try:
    doc = json.load(open(path))
except Exception:
    doc = {}
verb, rest = argv[1], argv[2:]
scope, name, cmd, envs, js = None, None, [], {}, None
i = 0
while i < len(rest):
    a = rest[i]
    if a in ("-s", "--scope"):
        scope = rest[i + 1]; i += 2; continue
    if a in ("-e", "--env"):
        k, v = rest[i + 1].split("=", 1); envs[k] = v; i += 2; continue
    if a == "--":
        cmd = rest[i + 1:]; break
    if name is None:
        name = a
    elif verb == "add-json" and js is None:
        js = a
    i += 1
def user_bucket(create):
    return doc.setdefault("mcpServers", {}) if create else (doc.get("mcpServers") or {})
def local_bucket(create):
    if create:
        return doc.setdefault("projects", {}).setdefault(cwd, {}).setdefault("mcpServers", {})
    return ((doc.get("projects") or {}).get(cwd) or {}).get("mcpServers") or {}
if verb in ("add", "add-json"):
    block = json.loads(js) if verb == "add-json" else {"type": "stdio", "command": cmd[0], "args": cmd[1:], "env": envs}
    (user_bucket(True) if scope == "user" else local_bucket(True))[name] = block
    print("Added stdio MCP server %s to %s config" % (name, scope or "local"))
else:
    buckets = {"user": user_bucket, "local": local_bucket}
    order = [scope] if scope else ["local", "user"]
    for sc in order:
        b = buckets[sc](False)
        if name in b:
            del b[name]; print("Removed MCP server %s from %s config" % (name, sc)); break
    else:
        print("No MCP server found with name: %s" % name, file=sys.stderr); sys.exit(1)
with open(path + ".tmp", "w") as f:
    json.dump(doc, f, indent=2)
os.replace(path + ".tmp", path)
PY
  rc=$?
  # FAKE_MCP_WRITE_THEN_FAIL=1: the client DID write the file and then died (a crash
  # after its save) — the shim must pass the failure through and mirror nothing.
  [ "$rc" = 0 ] && [ -n "${FAKE_MCP_WRITE_THEN_FAIL:-}" ] && exit 1
  exit $rc
fi
if [ "${1:-}" = "auth" ] && [ "${2:-}" = "status" ]; then
  if [ -n "${FAKE_AUTH_FAIL:-}" ]; then echo '{"loggedIn": false}'; exit 0; fi
  # A setup token is minted with scope user:inference ALONE, so the real CLI answers
  # {loggedIn, authMethod, apiProvider} and NO email — only an OAuth login (config dir)
  # reports one. The fake used to hand an email to both, which is precisely why every
  # --token identity path passed here and died in the field.
  if [ -n "${CLAUDE_CODE_OAUTH_TOKEN:-}" ] && [ -z "${CLAUDE_CONFIG_DIR:-}" ]; then
    echo '{"loggedIn": true, "authMethod": "oauth_token", "apiProvider": "firstParty"}'
    exit 0
  fi
  printf '{"loggedIn": true, "email": "%s"}\n' "${FAKE_EMAIL:-fake@test}"
  exit 0
fi
if [ "${1:-}" = "auth" ] && [ "${2:-}" = "login" ]; then
  [ -n "${FAKE_LOGIN_FAIL:-}" ] && { echo "login aborted" >&2; exit 1; }
  if [ -n "${FAKE_LOGIN_KEYCHAIN:-}" ] && [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then
    # simulate the macOS client in a keychain-capable session: the login lands in the
    # keychain (via the fake `security` on PATH) and NO .credentials.json is written
    h="$(printf '%s' "$CLAUDE_CONFIG_DIR" | { shasum -a 256 2>/dev/null || sha256sum; } | cut -c1-8)"
    hex="$(printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-login","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999,"scopes":["user:inference"],"subscriptionType":"max"}}' \
      | python3 -c 'import sys;print(sys.stdin.buffer.read().hex())')"
    security add-generic-password -U -a tester -s "Claude Code-credentials-$h" -X "$hex"
    echo "Logged in."
    exit 0
  fi
  # simulate a completed full-scope login: write auto-refreshing creds to the config dir
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-login","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999,"scopes":["user:inference"],"subscriptionType":"max"}}' > "${CLAUDE_CONFIG_DIR:-/dev/null}/.credentials.json"
  echo "Logged in."
  exit 0
fi
if [ "${1:-}" = "setup-token" ]; then
  echo "Open this sign-in link: https://claude.ai/oauth/authorize?fake=1"
  [ -n "${FAKE_TOKEN_FAIL:-}" ] && { echo "${FAKE_TOKEN_FAIL_MSG:-sign-in aborted}" >&2; exit 1; }
  if [ -n "${FAKE_TOKEN_FULL:-}" ]; then
    # The real client's shape (2.1.251): a success line, the token on its own line
    # between "Your OAuth token …:" and "Store this token securely", 108 characters.
    # The renderer HARD-WRAPS it at the terminal's width (an unsized pty renders as 80
    # — the 79-character first line every panel mint of 2026-08-28 saved), and even at
    # 400 columns emits it as cursor-positioned, styled segments (my-mini, 2026-08-29).
    tok="sk-ant-oat01-$(printf '%66s' '' | tr ' ' W)$(printf '%23s' '' | tr ' ' T)TAILOK"
    cols="$(stty size 2>/dev/null | awk '{print $2}')"
    printf 'Long-lived authentication token created successfully!\n'
    printf 'Your\033[5GOAuth\033[11Gtoken\033[17G(valid\033[24Gfor\033[28G1\033[30Gyear):\n'
    if [ -n "${FAKE_TOKEN_SPLIT:-}" ]; then
      printf '\033[2G%s\033[38;5;246m\033[15G%s\033[39m\033[60G%s\033[0m\r\n' "${tok:0:13}" "${tok:13:45}" "${tok:58}"
    elif [ -n "${FAKE_TOKEN_WRAP:-}" ] || { [ -n "$cols" ] && [ "$cols" -lt 108 ]; }; then
      printf ' %s\n%s\n' "${tok:0:79}" "${tok:79}"
    else
      printf ' %s\n' "$tok"
    fi
    printf 'Store\033[7Gthis\033[12Gtoken\033[18Gsecurely.\n'
    exit 0
  fi
  if [ -n "${FAKE_TOKEN_CURSOR:-}" ]; then
    # The 2026-08-29 shape: the TUI paints the token OUT OF ORDER with absolute cursor
    # moves, so the byte stream is `sk-ant-<ESC>[10Gat01-…` and escape-stripping loses
    # the `o`. Only replaying the transcript onto a screen recovers it.
    tok="sk-ant-oat01-$(printf '%66s' '' | tr ' ' W)$(printf '%23s' '' | tr ' ' T)TAILOK"
    printf ' Your\033[6GOAuth\033[12Gtoken\033[18G(valid\033[25Gfor\033[29G1\033[31Gyear):\n'
    printf ' %s\033[10G%s\033[9G%s\n' "${tok:0:7}" "${tok:8}" "${tok:7:1}"
    printf ' Store\033[7Gthis\033[12Gtoken\033[18Gsecurely.\n'
    exit 0
  fi
  if [ -n "${FAKE_TOKEN_APIKEY:-}" ]; then
    # A browser session signed into a Console (API-billing) org: the client mints an
    # API key, which is not a subscription token and must not be saved.
    printf 'Your OAuth token (valid for 1 year):\nsk-ant-api03-%s\nStore this token securely.\n' "$(printf '%80s' '' | tr ' ' K)"
    exit 0
  fi
  echo "Your token: sk-ant-oat01-FAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKEFAKE"
  exit 0
fi
if [ -n "${FAKE_TUI:-}" ] && [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then
  # The auto-resume sections' INTERACTIVE client: it behaves the way the real TUI does at
  # an API error — registers sessions/<pid>.json in the account dir, writes the error
  # record into the (shared) transcript and then IDLES; SIGTERM deletes the registry and
  # exits 143, and a crash (SIGKILL) leaves the registry behind. The scripted error only
  # fires on a fresh launch; a `--resume <sid>` launch appends what the real client does
  # after the auto-resume prompt — a normal reply — unless FAKE_TUI_QUIET is set.
  acct="$(basename "$CLAUDE_CONFIG_DIR")"
  sid=""; prev=""
  for a in "$@"; do
    case "$prev" in -r|--resume) sid="$a" ;; esac
    case "$a" in --resume=*) sid="${a#--resume=}" ;; esac
    prev="$a"
  done
  resumed=0; [ -n "$sid" ] && resumed=1
  [ -n "$sid" ] || sid="${FAKE_TUI_SID:-5f0c1d2e-3a4b-4c5d-8e9f-a0b1c2d3e4f5}"
  [ -n "${FAKE_TUI_PIDS:-}" ] && echo "$$" >> "$FAKE_TUI_PIDS"
  echo "CFG=$acct ARGS=$*" >> "${FAKE_TUI_LOG:-/dev/null}"
  proj="$CLAUDE_CONFIG_DIR/projects/-fake-tui"
  mkdir -p "$CLAUDE_CONFIG_DIR/sessions" "$proj"
  tr="$proj/$sid.jsonl"
  ts() { date -u +%Y-%m-%dT%H:%M:%S.000Z; }
  apierr() { # $1 error code, $2 extra JSON members (with a leading comma) or empty
    printf '{"type":"assistant","isApiErrorMessage":true,"error":"%s"%s,"timestamp":"%s","isSidechain":false,"sessionId":"%s","message":{"content":[{"type":"text","text":"API Error"}]}}\n' \
      "$1" "${2:-}" "$(ts)" "$sid" >> "$tr"
  }
  if [ "$resumed" = 1 ] && [ -z "${FAKE_TUI_QUIET:-}" ]; then
    printf '{"type":"assistant","timestamp":"%s","isSidechain":false,"sessionId":"%s","message":{"content":[{"type":"text","text":"Resumed."}]}}\n' \
      "$(ts)" "$sid" >> "$tr"
  fi
  reg="$CLAUDE_CONFIG_DIR/sessions/$$.json"
  printf '{"pid":%s,"sessionId":"%s","cwd":"%s","kind":"interactive","status":"busy","startedAt":%s000}\n' \
    "$$" "$sid" "$PWD" "$(date +%s)" > "$reg"
  trap 'rm -f "$reg"; exit 143' TERM
  trap 'rm -f "$reg"; exit 129' HUP
  if [ "$resumed" = 0 ]; then
    sleep "${FAKE_TUI_DELAY:-0.3}"
    case "$FAKE_TUI" in
      quota) apierr rate_limit ",\"quotaLimits\":{\"status\":\"rejected\",\"resetsAt\":$(( $(date +%s) + 7200 )),\"rateLimitType\":\"five_hour\"}" ;;
      auth) apierr authentication_failed ;;
      invalid) apierr invalid_request ;;
      crash) sleep 0.3; kill -9 $$ ;;
    esac
  fi
  # Bounded, in short sleeps so a TERM is handled within a tenth of a second.
  i=0
  while [ "$i" -lt "${FAKE_TUI_LIFE:-400}" ]; do sleep 0.1; i=$((i + 1)); done
  rm -f "$reg"
  exit 0
fi
if [ $# -eq 0 ] && [ -n "${FAKE_DO_LOGIN:-}" ] && [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then
  # simulate an interactive session in which the user completed /login
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-new","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$CLAUDE_CONFIG_DIR/.credentials.json"
  exit 0
fi
ctl="${FAKE_CTL:-/nonexistent}"
acct="$(basename "${CLAUDE_CONFIG_DIR:-none}")"
case "${CLAUDE_CODE_OAUTH_TOKEN:-}" in
  *REVOKED*)
    echo "Please run /login · API Error: 401 OAuth access token is invalid." >&2
    exit 1 ;;
  sk-ant-oat01-WWW*)
    # The wrapped fixture above: only the COMPLETE token (with its tail) authenticates;
    # its 79-character first line is what Claude answered 401 to, fleet-wide.
    if [ -n "${FAKE_PROBE_FLAKY:-}" ]; then
      # Not an auth verdict at all — the API is busy. The probe is inconclusive.
      echo "API Error: 529 Overloaded" >&2; exit 1
    fi
    case "$CLAUDE_CODE_OAUTH_TOKEN" in
      *TAILOK) : ;;
      *) echo "Failed to authenticate. API Error: 401 OAuth access token is invalid." >&2; exit 1 ;;
    esac ;;
esac
if [ -f "$ctl" ] && grep -qx "brokencli:$acct" "$ctl" 2>/dev/null; then
  # An infrastructure fault, not a login verdict: the CLI never reached the API.
  # Verbatim from my-mini, 2026-09-10. Note it carries no auth vocabulary at all
  # — the danger is that AUTH_ERR matches a bare `401`, and a node stack frame
  # or a version string can contain one.
  echo "Error: Missing optional dependency @openai/codex-darwin-arm64. Reinstall Codex: npm install -g @openai/codex@latest" >&2
  echo "    at findCodexExecutable (file:///opt/homebrew/lib/node_modules/@openai/codex/bin/codex.js:107:9)" >&2
  exit 1
fi
case " $* " in
  *" -p --output-format text --max-turns 1 "*) echo "OK"; exit 0 ;;
esac
if [ -f "$ctl" ] && grep -qx "fail:$acct" "$ctl" 2>/dev/null; then
  echo "API Error: 429 rate limit exceeded" >&2
  exit 1
fi
if [ -f "$ctl" ] && grep -qx "authfail:$acct" "$ctl" 2>/dev/null; then
  # the exact failure a dead OAuth grant produces
  echo "Failed to authenticate: OAuth session expired and could not be refreshed" >&2
  exit 1
fi
if [ -f "$ctl" ] && grep -qx "orgfail:$acct" "$ctl" 2>/dev/null; then
  # the exact failure an org-disabled account produces (authenticates, cannot infer)
  echo "Your organization has disabled Claude subscription access for Claude Code · Use an Anthropic API key instead, or ask your admin to enable access"
  exit 1
fi
# A limit scoped to ONE MODEL, on EVERY account: rotating cannot help, only
# switching model can. Satisfied the moment the run carries the fallback model.
# The shape every app-robot task actually produces: --output-format stream-json
# reports the API error INSIDE the stream and exits 0.
if [ -f "$ctl" ] && grep -qx "streamlimit" "$ctl" 2>/dev/null; then
  case " $* " in
    *" claude-opus-5 "*|*"--model=claude-opus-5"*)
      echo '{"type":"result","subtype":"success","is_error":false,"result":"done"}' ;;
    *)
      echo '{"type":"result","subtype":"success","is_error":true,"api_error_status":429,"result":"You'"'"'ve reached your Fable 5 limit. Switch to another model, or manage usage credits to continue."}'
      exit 0 ;;
  esac
fi
if [ -f "$ctl" ] && grep -qx "modellimit" "$ctl" 2>/dev/null; then
  case " $* " in
    *" claude-opus-5 "*|*"--model=claude-opus-5"*) : ;;
    *) echo "You've reached your Fable 5 limit. Switch to another model, or manage usage credits at claude.ai/settings/usage to continue." >&2
       exit 1 ;;
  esac
fi
for a in "$@"; do
  case "$a" in
    --exit7) echo "ordinary failure, not auth related" >&2; exit 7 ;;
    --echo-stdin) cat; exit 0 ;;
  esac
done
if [ -n "${FAKE_SESSION_ID:-}" ] && [ -n "${CLAUDE_CONFIG_DIR:-}" ]; then
  # Mimic the real client: register the run in the ACCOUNT dir for its lifetime, write
  # the session transcript into the (shared) projects tree, delete the registry on exit.
  mkdir -p "$CLAUDE_CONFIG_DIR/sessions" "$CLAUDE_CONFIG_DIR/projects/-proj"
  printf '{"pid":%s,"sessionId":"%s","cwd":"/proj","kind":"interactive","startedAt":%s000}\n' \
    "$$" "$FAKE_SESSION_ID" "$(date -u +%s)" > "$CLAUDE_CONFIG_DIR/sessions/$$.json"
  printf '{"type":"mode","mode":"normal","sessionId":"%s"}\n' "$FAKE_SESSION_ID" \
    > "$CLAUDE_CONFIG_DIR/projects/-proj/$FAKE_SESSION_ID.jsonl"
  if [ -n "${FAKE_LIMIT_RESET:-}" ]; then
    printf '{"type":"assistant","timestamp":"%s","message":{"content":[{"type":"text","text":"You'"'"'ve hit your session limit"}]},"quotaLimits":{"status":"rejected","resetsAt":%s,"unifiedRateLimitFallbackAvailable":false,"rateLimitType":"five_hour","overageStatus":"rejected"},"error":"rate_limit","isApiErrorMessage":true,"apiErrorStatus":429,"sessionId":"%s"}\n' \
      "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" "$FAKE_LIMIT_RESET" "$FAKE_SESSION_ID" \
      >> "$CLAUDE_CONFIG_DIR/projects/-proj/$FAKE_SESSION_ID.jsonl"
  fi
  sleep "${FAKE_SESSION_HOLD:-4}"
  rm -f "$CLAUDE_CONFIG_DIR/sessions/$$.json"
fi
# what an interactive client would inherit from the shim (auto-resume must leak nothing)
[ -n "${FAKE_PRINT_ENV:-}" ] && echo "AR_ENV=$(env | grep -c '^CLAUDE_MULTIACC_AR')"
echo "CFG=$acct TOK=${CLAUDE_CODE_OAUTH_TOKEN:-none} ARGS=$*"
EOF
chmod +x "$FAKEBIN/claude"

# Fake macOS `security` (generic-password verbs only): items live as files under
# $FAKE_KEYCHAIN_DIR/<service> (content = the secret) + <service>.acct (account name).
# FAKE_KEYCHAIN_LOCKED=1 simulates a session that cannot open the keychain — secret
# reads and every write exit 36 while ATTRIBUTE reads still answer, exactly the split
# the real tool exhibits over ssh. Shadows any real /usr/bin/security via PATH, so a
# macOS dev run of this suite can never touch the developer's actual keychain.
cat > "$FAKEBIN/security" <<'EOF'
#!/usr/bin/env bash
KC="${FAKE_KEYCHAIN_DIR:-/nonexistent-keychain}"
cmd="${1:-}"; shift || true
svc=""; acct=""; want_pw=0; hexdata=""
while [ $# -gt 0 ]; do
  case "$1" in
    -s) svc="$2"; shift 2 ;;
    -a) acct="$2"; shift 2 ;;
    -w) want_pw=1; shift ;;
    -X) hexdata="$2"; shift 2 ;;
    *) shift ;;
  esac
done
# The modification stamp is RECORDED AT WRITE TIME in a sidecar rather than derived
# from the item file's mtime: `stat`/`date` flags differ between BSD and GNU (on Linux
# `stat -f %m` even "succeeds" with garbage), and this fake must behave identically on
# a developer's Mac and on Linux CI.
item_mdat() { cat "$KC/$svc.mdat" 2>/dev/null || echo 00000000000000; }
case "$cmd" in
  show-keychain-info)
    [ -n "${FAKE_KEYCHAIN_LOCKED:-}" ] && exit 36
    exit 0 ;;
  find-generic-password)
    [ -f "$KC/$svc" ] || exit 44
    if [ "$want_pw" = "1" ]; then
      [ -n "${FAKE_KEYCHAIN_LOCKED:-}" ] && exit 36
      cat "$KC/$svc"
      exit 0
    fi
    a="tester"; [ -f "$KC/$svc.acct" ] && a="$(cat "$KC/$svc.acct")"
    printf 'keychain: "login.keychain-db"\nclass: "genp"\nattributes:\n'
    printf '    "acct"<blob>="%s"\n' "$a"
    printf '    "mdat"<timedate>=0x00  "%sZ\\000"\n' "$(item_mdat)"
    printf '    "svce"<blob>="%s"\n' "$svc"
    exit 0 ;;
  add-generic-password)
    [ -n "${FAKE_KEYCHAIN_LOCKED:-}" ] && exit 36
    mkdir -p "$KC"
    printf '%s' "$hexdata" | python3 -c 'import sys;sys.stdout.buffer.write(bytes.fromhex(sys.stdin.read().strip()))' > "$KC/$svc"
    printf '%s' "${acct:-tester}" > "$KC/$svc.acct"
    date -u +%Y%m%d%H%M%S > "$KC/$svc.mdat"
    exit 0 ;;
  delete-generic-password)
    [ -n "${FAKE_KEYCHAIN_LOCKED:-}" ] && exit 36
    [ -f "$KC/$svc" ] || exit 44
    rm -f "$KC/$svc" "$KC/$svc.acct" "$KC/$svc.mdat"
    exit 0 ;;
  *) exit 1 ;;
esac
EOF
chmod +x "$FAKEBIN/security"

export PATH="$REPO_DIR/bin:$FAKEBIN:$PATH"
export FAKE_CTL="$WORK/ctl"
# Neutralize any ambient state from the invoking environment.
unset CLAUDE_CONFIG_DIR CLAUDE_CODE_OAUTH_TOKEN CLAUDE_ACCOUNT CLAUDE_SHIM_ACTIVE 2>/dev/null || true
export CLAUDE_MULTIACC_NO_SYNC=1
# Fixtures are local file:// URLs with no rate limit, so the anti-429 fetch throttle
# is off by default here; the throttle test re-enables it explicitly.
export CLAUDE_MULTIACC_MIN_FETCH=0
# The client-rate-limit scan memoizes a CLEAN result for a few seconds; tests plant
# rejections and expect them seen on the very next run, so the memo is off by default
# here (12i re-enables it to prove the memo itself works).
export CLAUDE_MULTIACC_CLIENT_SCAN_TTL=0
# The oauth token endpoint must NEVER be hit for real from tests: default to a missing
# file:// fixture (refresh fails fast, offline); the refresh tests override per-case.
export CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-endpoint-missing.json"
# Same for the usage endpoint: the SHIM's opportunistic background `limits --quiet`
# kick inherits this default, so it can never reach a real endpoint from tests
# (every explicit limits test overrides the URL inline). The pre-armed .limits-kick
# throttle keeps those background kicks from racing explicit limits runs.
export CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-endpoint-missing.json"
: > "$ACC/.limits-kick"
# Keychain lookups are OFF for the legacy sections (their pools are file-based and the
# extra `security` process per account would only slow them down); section 17 turns
# them on explicitly against the fake `security` above.
export CLAUDE_MULTIACC_KEYCHAIN=0
# `status` probes fresh login shells with $HOME's rc files (lib/shim_path.py). This suite
# runs under the operator's real HOME, whose rc files are not under test — section 18
# turns the probe on against its own fake HOME.
export CLAUDE_MULTIACC_PATH_PROBE=0
# Auto-resume spawns a detached watcher for an interactive launch inside tmux. The suite
# may itself run inside tmux, and no legacy section is about auto-resume, so it is off
# (and the pane invisible) everywhere except the sections that turn it on against a fake
# tmux — a watcher here would otherwise type into the developer's REAL pane.
export CLAUDE_MULTIACC_AUTORESUME=0 CODEX_MULTIACC_AUTORESUME=0
unset TMUX TMUX_PANE 2>/dev/null || true

now="$(date +%s)"

# ---- 1. passthrough: no manifest yet -------------------------------------
out="$(claude 2>&1)"
check "passthrough without manifest" "CFG=none" "$out"

# ---- manifest + two oauth accounts ----------------------------------------
cat > "$ACC/accounts.json" <<EOF
{
  "version": 1,
  "server": "root@203.0.113.1",
  "server_root": "/root/.claude-accounts",
  "server_repo": "/root/claude-multiacc",
  "threshold": 90,
  "accounts": [
    {"id": "acct-01", "email": "a@test", "home": "mac", "added_at": "2026-07-13T00:00:00Z"},
    {"id": "acct-02", "email": "b@test", "home": "mac", "added_at": "2026-07-13T00:00:00Z"}
  ]
}
EOF
for i in 01 02; do
  mkdir -p "$ACC/acct-$i"
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-test%s","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999,"scopes":["user:inference"],"subscriptionType":"max"}}' "$i" > "$ACC/acct-$i/.credentials.json"
done

# ---- 2-4. passthrough guards ----------------------------------------------
out="$(CLAUDE_CONFIG_DIR=/tmp/other claude 2>&1)"
check "passthrough with CLAUDE_CONFIG_DIR" "CFG=other" "$out"
out="$(CLAUDE_CODE_OAUTH_TOKEN=sk-test claude 2>&1)"
check "passthrough with CLAUDE_CODE_OAUTH_TOKEN" "CFG=none" "$out"
out="$(CLAUDE_MULTIACC_DISABLE=1 claude 2>&1)"
check "passthrough when disabled" "CFG=none" "$out"

# ---- 5. headroom selection: the session gate first, then the WEEKLY headroom band ----
lj() { # lj <weekly> <session> <max>  -> a fresh limits.json body
  printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":%s,"max_percent":%s,"buckets":[]}' "$now" "$1" "$2" "$3"
}
# acct-01 weekly 80, acct-02 weekly 20 => always acct-02.
lj 80 10 80 > "$ACC/acct-01/limits.json"
lj 20 10 20 > "$ACC/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "picks the highest weekly-headroom account (weekly 20 over 80)" \
  || t_fail "headroom selection" "picked the more-utilized account"

# The default 30-point band prevents strict headroom ranking from burning one account
# to zero while its near-peers idle. Both boundaries participate; 31 points does not.
lj 0 10 10 > "$ACC/acct-01/limits.json"
lj 30 10 30 > "$ACC/acct-02/limits.json"
hits1=0; hits2=0
for _ in $(seq 1 20); do
  case "$(claude 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "30-point headroom band spreads direct Claude launches (acct-01=$hits1 acct-02=$hits2)" \
  || t_fail "Claude headroom band spread" "acct-01=$hits1 acct-02=$hits2"
lj 31 10 31 > "$ACC/acct-02/limits.json"
all1=1
for _ in $(seq 1 10); do
  case "$(claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = 1 ] && t_ok "an account 31 points behind stays outside the Claude band" \
  || t_fail "Claude headroom band boundary" "the 31-point account was selected"
lj 20 10 20 > "$ACC/acct-02/limits.json"
all1=1
for _ in $(seq 1 10); do
  case "$(CLAUDE_MULTIACC_HEADROOM_BAND=0 claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = 1 ] && t_ok "Claude headroom band 0 restores strict ranking" \
  || t_fail "Claude zero headroom band" "the runner-up was selected"

# THE KEY CASE, REVERSED on 2026-09-03. It used to assert that a high (but
# sub-threshold) SESSION bucket must not deprioritize an account with better weekly
# headroom. The operator asked for the opposite: "among accounts where high session
# limits it must choose randomly from ones where highest weekly limits" — an account
# whose 5h bucket is nearly spent is about to be rejected whatever its weekly headroom.
# So the SESSION GATE (default 50) is the FIRST cut and the 30-point weekly band ranks
# only what clears it. acct-01: session 85 (past the gate), weekly 10; acct-02: session
# 20, weekly 70. Both eligible (max<90) — acct-02 wins every time now.
lj 10 85 85 > "$ACC/acct-01/limits.json"
lj 70 20 70 > "$ACC/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "a session bucket past the gate is skipped while a fresher one exists (70w/20s over 10w/85s)" \
  || t_fail "session gate" "the account with its 5h bucket at 85% was still selected"
# The pick has to be auditable: the log names the gate and how many cleared it.
: > "$ACC/selection.log"
claude >/dev/null 2>&1
grep -qE 'acct-02 weekly=70% session=20% band=30 band-count=1 session-gate=50 session-ok=1 pwd=' "$ACC/selection.log" \
  && t_ok "the selection log carries session-gate=50 session-ok=1 when one of two clears" \
  || t_fail "session gate log" "$(tail -1 "$ACC/selection.log")"

# Both session buckets inside the gate: the gate has nothing to say and weekly decides,
# exactly as before the change.
lj 10 45 45 > "$ACC/acct-01/limits.json"
lj 70 20 70 > "$ACC/acct-02/limits.json"
all1=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "with both sessions inside the gate weekly headroom decides (10w/45s over 70w/20s)" \
  || t_fail "session gate no-op" "the gate changed a ranking where every candidate cleared it"

# Nobody clears the gate: it COMPARES candidates, it never empties the pool — it steps
# aside and weekly ranks the whole set (10w wins), and the log says session-ok=0.
lj 10 85 85 > "$ACC/acct-01/limits.json"
lj 70 60 70 > "$ACC/acct-02/limits.json"
: > "$ACC/selection.log"
all1=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "with nobody inside the gate it steps aside and weekly ranks (10w/85s over 70w/60s)" \
  || t_fail "session gate step-aside" "an empty gate emptied the pool instead of stepping aside"
grep -qE 'acct-01 weekly=10% session=85% band=30 band-count=1 session-gate=50 session-ok=0 pwd=' "$ACC/selection.log" \
  && t_ok "the selection log carries session-ok=0 when the gate steps aside" \
  || t_fail "session gate log" "$(tail -1 "$ACC/selection.log")"

# The gate is a knob, like the band: 100 turns it off and pure weekly ranking returns.
lj 10 85 85 > "$ACC/acct-01/limits.json"
lj 70 20 70 > "$ACC/acct-02/limits.json"
all1=1
for _ in $(seq 1 15); do
  case "$(CLAUDE_MULTIACC_SESSION_GATE=100 claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "CLAUDE_MULTIACC_SESSION_GATE=100 disables the gate" \
  || t_fail "session gate off" "the gate still fired at 100"
# ...and garbage in that env var falls back to the 50-point default, never to "off".
all2=1
for _ in $(seq 1 15); do
  case "$(CLAUDE_MULTIACC_SESSION_GATE=abc claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "a non-numeric CLAUDE_MULTIACC_SESSION_GATE falls back to 50" \
  || t_fail "session gate validation" "a garbage gate value changed the outcome"

# Equal weekly usage: the GATE decides, not a tiebreak. Session stopped being a ranking
# input inside the band on 2026-09-03 — acct-02's 80-point session bucket simply never
# reaches the weekly comparison, whether the band is strict or the default 30.
lj 40 20 40 > "$ACC/acct-01/limits.json"
lj 40 80 80 > "$ACC/acct-02/limits.json"
all1=1
for _ in $(seq 1 15); do
  case "$(CLAUDE_MULTIACC_HEADROOM_BAND=0 claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "strict mode: the session gate decides an exact weekly tie" \
  || t_fail "session gate tie" "a weekly tie was not resolved by the session gate"
all1=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "the gate (not the band) removes the session-heavy half of a weekly tie" \
  || t_fail "session gate tie" "the default band let the 80-point session account back in"

# Inside the gate, session is NOT a tiebreaker any more: an exact weekly tie between two
# gate-clearing accounts is a coin flip even in strict mode (it used to go to the lower
# session, through the old weekly*1000+session score).
lj 40 20 40 > "$ACC/acct-01/limits.json"
lj 40 45 45 > "$ACC/acct-02/limits.json"
hits1=0; hits2=0
for _ in $(seq 1 20); do
  case "$(CLAUDE_MULTIACC_HEADROOM_BAND=0 claude 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "strict mode: session does not break an exact weekly tie inside the gate (acct-01=$hits1 acct-02=$hits2)" \
  || t_fail "session tiebreak removed" "acct-01=$hits1 acct-02=$hits2 (want both >0)"

# Clearing the gate takes BOTH readings, as in pool-selection.v2: a fresh file with a
# session reading but no weekly one must not become the sole gate-clearer and win the
# all-gated tie over an account with a truthful weekly reading — not even with a
# max_percent to fall back on (the shims used to rank on that; the policy never could).
# (No writer produces such a file; this pins parity with lib/selector_policy.py.)
printf '{"fetched_at":%s,"max_percent":10,"session_percent":10,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
lj 20 80 80 > "$ACC/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "a session reading without a weekly one never clears the gate" \
  || t_fail "gate needs both readings" "an unknown-weekly account beat a truthful weekly reading"

# ...and the converse: a weekly reading without a session one is not "known" either — it
# neither clears the gate nor ranks once the gate steps aside (10w/?s vs 70w/80s -> the
# 70w account, as in pool-selection.v2, where quota_known needs both readings).
printf '{"fetched_at":%s,"weekly_percent":10,"max_percent":10,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
lj 70 80 80 > "$ACC/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "a weekly reading without a session one is unknown to both cuts" \
  || t_fail "known needs both readings" "a session-less weekly reading ranked as known"

# fully equal scores spread load across accounts
lj 10 10 10 > "$ACC/acct-01/limits.json"
lj 10 10 10 > "$ACC/acct-02/limits.json"
hits1=0; hits2=0
for _ in $(seq 1 40); do
  case "$(claude 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ] && [ $((hits1+hits2)) -eq 40 ]; } \
  && t_ok "equal scores spread randomly (acct-01=$hits1 acct-02=$hits2)" \
  || t_fail "tie spreading" "acct-01=$hits1 acct-02=$hits2 (want both >0, total 40)"

# opt-out: legacy uniform-random mode still available
hits1=0; hits2=0
lj 80 80 80 > "$ACC/acct-01/limits.json"
for _ in $(seq 1 40); do
  case "$(CLAUDE_SHIM_SELECT=random claude 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "CLAUDE_SHIM_SELECT=random restores uniform spread" \
  || t_fail "random opt-out" "acct-01=$hits1 acct-02=$hits2"
# ...and its log line must not claim a gate that never ran (codex review, 2026-09-04).
grep -qE 'band=30 band-count=2 session-gate=off session-ok=2 pwd=' "$ACC/selection.log" \
  && t_ok "random mode logs session-gate=off instead of a cut it never made" \
  || t_fail "random mode gate log" "$(grep 'SHIM_SELECT\|session-gate' "$ACC/selection.log" | tail -1)"

# Unknown telemetry ranks behind every truthful reading, never as neutral or free.
printf '{"fetched_at":1,"weekly_percent":1,"session_percent":1,"max_percent":1,"buckets":[]}' > "$ACC/acct-01/limits.json"
lj 30 30 30 > "$ACC/acct-02/limits.json"
out="$(claude 2>&1)"
check "stale 1% loses to fresh 30% (stale is not trusted)" "CFG=acct-02" "$out"
lj 88 88 88 > "$ACC/acct-01/limits.json"
rm -f "$ACC/acct-02/limits.json" "$ACC/.last-pick"
all1=1
for _ in $(seq 1 15); do
  case "$(claude 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "unknown telemetry never beats a known account at 88%" \
  || t_fail "unknown telemetry ranking" "the unknown account beat truthful 88% usage"
rm -f "$ACC/acct-01/limits.json" "$ACC/.last-pick"
hits1=0; hits2=0
for _ in $(seq 1 40); do
  case "$(claude 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "an entirely unknown Claude pool still fails open" \
  || t_fail "unknown Claude pool fail-open" "acct-01=$hits1 acct-02=$hits2"
rm -f "$ACC"/acct-*/limits.json

# ---- 6. explicit pin -------------------------------------------------------
out="$(CLAUDE_ACCOUNT=acct-02 claude 2>&1)"
check "CLAUDE_ACCOUNT pin" "CFG=acct-02" "$out"

# ---- 6b. pin works for an auth-less dir (login ceremony path) ----------------
mkdir -p "$ACC/acct-07"
out="$(CLAUDE_ACCOUNT=acct-07 claude 2>&1)"
check "pin to auth-less dir (ceremony)" "CFG=acct-07" "$out"
rmdir "$ACC/acct-07"

# ---- 6c. pin uses the portable token when the credential beside it is DEAD ----
# Regression: the pin path used to export the token only when NO credential file
# existed, so pinning an account whose login had died failed with "OAuth session
# expired" even though its setup-token was sitting right there — the exact state a
# fleet-distributed token lands in on a machine that still has a stale login.
mkdir -p "$ACC/acct-07"
printf '{"claudeAiOauth":{"accessToken":"dead","refreshToken":"","expiresAt":0,"refreshTokenExpiresAt":1}}' \
  > "$ACC/acct-07/.credentials.json"
printf 'sk-ant-oat01-PINNEDDEADCREDSPINNEDDEADCREDSPINNEDDEADCREDS00' > "$ACC/acct-07/server.token"
out="$(CLAUDE_ACCOUNT=acct-07 claude 2>&1)"
check "pinned dead-credential account still runs under its token" "TOK=sk-ant-oat01-PINNED" "$out"
rm -rf "$ACC/acct-07"

# ---- 7. limited marker excludes account ------------------------------------
# (An account-wide bucket. A MODEL-SCOPED one deliberately does not exclude — 9a4.)
printf '%s\nbucket=session percent=95 reason=limits\n' "$((now+3600))" > "$ACC/acct-01/.limited"
all2=1
for _ in $(seq 1 15); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "limited account excluded from pool" || t_fail "limited account excluded" "acct-01 was still picked"

# ---- 7b. pin overrides marker ----------------------------------------------
out="$(CLAUDE_ACCOUNT=acct-01 claude 2>&1)"
check "explicit pin wins over marker" "CFG=acct-01" "$out"

# ---- 8. expired marker auto-clears ------------------------------------------
printf '%s\nbucket=session percent=95 reason=limits\n' "$((now-10))" > "$ACC/acct-01/.limited"
claude >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.limited" ] && t_ok "expired marker auto-cleared" || t_fail "expired marker auto-cleared" "marker still present"

# ---- 9. all limited -> the still-serving accounts go through the same two cuts, strict weekly ----
printf '%s\nx\n' "$((now+3600))" > "$ACC/acct-01/.limited"
printf '%s\nx\n' "$((now+3600))" > "$ACC/acct-02/.limited"
lj 97 10 97 > "$ACC/acct-01/limits.json"
lj 91 10 91 > "$ACC/acct-02/limits.json"
out="$(claude 2>&1)"
check "all-limited falls back to the still-serving account with the most weekly headroom" "CFG=acct-02" "$out"
grep -q "all-limited fallback=acct-02" "$ACC/selection.log" \
  && t_ok "fallback logged" || t_fail "fallback logged" "no all-limited line in selection.log"
rm -f "$ACC/acct-01/.limited" "$ACC/acct-02/.limited"

# The fallback applies the SAME two cuts: with every account limit-marked but still
# serving, an account past the session gate (10w/85s) yields to one inside it (70w/20s)
# even though its weekly headroom is far better — exactly as in ordinary selection.
# (On the pre-gate rule this picked 10w/85s, the best strict weekly score.)
printf '%s\nbucket=weekly_all percent=95 marked_at=x reason=limits\n' "$((now+3600))" > "$ACC/acct-01/.limited"
printf '%s\nbucket=weekly_all percent=95 marked_at=x reason=limits\n' "$((now+3600))" > "$ACC/acct-02/.limited"
lj 10 85 85 > "$ACC/acct-01/limits.json"
lj 70 20 70 > "$ACC/acct-02/limits.json"
all2=1
for _ in $(seq 1 12); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "the all-limited fallback applies the session gate before strict weekly (70w/20s over 10w/85s)" \
  || t_fail "fallback session gate" "the fallback handed out the account past the session gate"
grep -q "all-limited fallback=acct-02 weekly=70%" "$ACC/selection.log" \
  && t_ok "the fallback line names the gated pick" || t_fail "fallback gate log" "$(tail -1 "$ACC/selection.log")"
rm -f "$ACC/acct-01/.limited" "$ACC/acct-02/.limited"

# ---- 9a2. the fallback tells "still serving" from "rejected right now" --------------
# acct-01: weekly at 99% — worse headroom, but still answering requests.
# acct-02: session at 100% — far better weekly (7%), but every request bounces until
# the reset. Ranking on headroom alone handed out the guaranteed rejection
# (operator report 2026-08-29: "claude keeps starting on an out-of-limits account").
printf '%s\nbucket=weekly_all percent=99 marked_at=x reason=limits\n' "$((now+3600))" > "$ACC/acct-01/.limited"
printf '%s\nbucket=session percent=100 marked_at=x reason=limits\n' "$((now+600))" > "$ACC/acct-02/.limited"
printf '{"fetched_at":%s,"max_percent":99,"weekly_percent":99,"session_percent":10,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
printf '{"fetched_at":%s,"max_percent":100,"weekly_percent":7,"session_percent":100,"buckets":[]}' "$now" > "$ACC/acct-02/limits.json"
out="$(claude 2>&1)"
check "a still-serving limited account beats an exhausted one with more headroom" "CFG=acct-01" "$out"
# A real client rejection (a 429 the server sent) is exhausted whatever percent says.
printf '%s\nbucket=five_hour marked_at=x reason=client-rate-limit\n' "$((now+600))" > "$ACC/acct-02/.limited"
out="$(claude 2>&1)"
check "a client-rejected account is not the fallback while another still serves" "CFG=acct-01" "$out"
# Every account exhausted RIGHT NOW: hand out the one that unblocks first.
printf '%s\nbucket=session percent=100 marked_at=x reason=limits\n' "$((now+7200))" > "$ACC/acct-01/.limited"
printf '%s\nbucket=session percent=100 marked_at=x reason=limits\n' "$((now+600))" > "$ACC/acct-02/.limited"
out="$(claude 2>&1)"
check "all exhausted: the soonest reset is handed out" "CFG=acct-02" "$out"
grep -q "all-exhausted resets_in=" "$ACC/selection.log" \
  && t_ok "the all-exhausted pick is logged with its reset" || t_fail "all-exhausted log" "no line"
rm -f "$ACC/acct-01/.limited" "$ACC/acct-02/.limited"
lj 97 10 97 > "$ACC/acct-01/limits.json"
lj 91 10 91 > "$ACC/acct-02/limits.json"

# ---- 9a3. a token park is credential-scoped ----------------------------------------
# A dead portable token beside a LIVE login: this session runs the account on the
# login — the park neither excludes it nor exports the token. Only a session that
# would have to use the token is kept away, and only a NEW token heals the park (a
# login refresh rewriting the credential must not — that rewrite happened every few
# hours and re-opened the 401 loop, 2026-08-29).
rm -rf "$WORK/bak01"; mkdir -p "$WORK/bak01"
for f in server.token .credentials.json .expired .server-token-verified limits.json; do
  [ -e "$ACC/acct-01/$f" ] && cp -p "$ACC/acct-01/$f" "$WORK/bak01/$f"
done
printf '%s\nx\n' "$((now+3600))" > "$ACC/acct-02/.limited"         # acct-01 is the only free one
printf '{"fetched_at":%s,"max_percent":10,"weekly_percent":10,"session_percent":5,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-live","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-01/.credentials.json"
printf 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' > "$ACC/acct-01/server.token"
touch -t 202001010000 "$ACC/acct-01/server.token"                 # older than the park
rm -f "$ACC/acct-01/.server-token-verified"
printf '%s\nreason=setup-token-invalid marked_at=x detail=portable OAuth token rejected\n' "$now" > "$ACC/acct-01/.expired"
out="$(claude 2>&1)"
check "a live login runs the account despite a token park" "CFG=acct-01" "$out"
check "the parked token is not exported beside a live login" "TOK=none" "$out"
[ -f "$ACC/acct-01/.expired" ] && t_ok "the token park stays on record for token-only sessions" \
  || t_fail "token park record" "marker removed"
out="$(claude-accounts list --json 2>/dev/null | python3 -c '
import json, sys
rows = {a["id"]: a for a in json.load(sys.stdin)["accounts"]}
print(rows["acct-01"]["status"], rows["acct-01"].get("token_verified"))')"
[ "$out" = "active False" ] && t_ok "the audit reads a live login beside a parked token as usable, token unproven" \
  || t_fail "audit token park" "expected 'active False', got '$out'"
# The login dies: now the token would carry the session, and the park excludes it.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
touch -t 202101010000 "$ACC/acct-01/.expired"                     # the credential above is NEWER
rm -f "$ACC/acct-02/.limited"
out="$(claude 2>&1)"
check "a dead login makes the token park bite" "CFG=acct-02" "$out"
[ -f "$ACC/acct-01/.expired" ] && t_ok "a newer credential does not heal a token park" \
  || t_fail "credential heal" "the login refresh lifted the token park"
out="$(claude-accounts list --json 2>/dev/null | python3 -c '
import json, sys
rows = {a["id"]: a for a in json.load(sys.stdin)["accounts"]}
print(rows["acct-01"]["status"])')"
[ "$out" = "token-invalid" ] && t_ok "the audit reads a parked token beside a dead login as token-invalid" \
  || t_fail "audit token-invalid" "got '$out'"
# A NEW token heals it — and the healed account is selected again, on the token.
printf 'sk-ant-oat01-%s' "$(printf '%95s' '' | tr ' ' N)" > "$ACC/acct-01/server.token"
printf '%s\nx\n' "$((now+3600))" > "$ACC/acct-02/.limited"
out="$(claude 2>&1)"
check "a new token heals the park" "CFG=acct-01" "$out"
check "the healed account runs on its new token" "TOK=sk-ant-oat01-NNN" "$out"
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "the healed park is gone" || t_fail "healed park" "marker still present"
# Hand acct-01 back exactly as it was.
rm -f "$ACC/acct-02/.limited" "$ACC/acct-01/server.token" "$ACC/acct-01/.credentials.json" \
  "$ACC/acct-01/.expired" "$ACC/acct-01/.server-token-verified" "$ACC/acct-01/limits.json"
for f in server.token .credentials.json .expired .server-token-verified limits.json; do
  [ -e "$WORK/bak01/$f" ] && cp -p "$WORK/bak01/$f" "$ACC/acct-01/$f"
done

# ---- 9a4. a MODEL-scoped limit does not park the whole account ----------------------
# "weekly_scoped:Fable at 100%" says the account cannot serve Fable — nothing more. It
# used to park the account outright (and max_percent re-excluded it anyway), so on
# 2026-08-29 three accounts sitting at Fable 100% with their session buckets at 51/23/25%
# were invisible to selection, the pool offered nothing, and the fallback handed out a
# session-exhausted account that rejected the operator's first request.
rm -rf "$WORK/bak94"; mkdir -p "$WORK/bak94"
for a in acct-01 acct-02; do
  for f in .limited limits.json; do
    [ -e "$ACC/$a/$f" ] && cp -p "$ACC/$a/$f" "$WORK/bak94/$a.$f"
  done
done
# acct-01: only its Fable bucket is spent. acct-02: session spent — dead for every model.
printf '%s\nbucket=weekly_scoped:Fable percent=100 marked_at=x reason=limits\n' "$((now+3600))" > "$ACC/acct-01/.limited"
printf '{"fetched_at":%s,"max_percent":100,"weekly_percent":100,"session_percent":12,"buckets":[{"name":"session","percent":12},{"name":"weekly_all","percent":40},{"name":"weekly_scoped:Fable","percent":100}]}' "$now" > "$ACC/acct-01/limits.json"
printf '%s\nbucket=session percent=100 marked_at=x reason=limits\n' "$((now+600))" > "$ACC/acct-02/.limited"
printf '{"fetched_at":%s,"max_percent":100,"weekly_percent":30,"session_percent":100,"buckets":[{"name":"session","percent":100},{"name":"weekly_all","percent":30}]}' "$now" > "$ACC/acct-02/limits.json"
out="$(claude 2>&1)"
check "a Fable-only park still serves an unpinned run" "CFG=acct-01" "$out"
check "...and that run is pinned to the fallback model up front" "ARGS=--model claude-opus-5" "$out"
grep -q 'acct-01 -> --model claude-opus-5 (its Fable bucket is full)' "$ACC/selection.log" \
  && t_ok "the model pin is logged with its reason" || t_fail "model pin log" "no line in selection.log"
# A run that ASKS for the exhausted model must not be sent to that account.
out="$(claude --model claude-fable-5 2>&1)"
check "a run pinning the exhausted model does not get that account" "CFG=acct-02" "$out"
# A run that pins another model uses it as-is — never pinned twice.
out="$(claude --model claude-opus-5 2>&1)"
check "a run pinning another model gets the Fable-spent account" "CFG=acct-01" "$out"
case "$out" in
  *"--model claude-opus-5 --model"*) t_fail "an explicit model is not pinned twice" "double --model" ;;
  *) t_ok "an explicit model is not pinned twice" ;;
esac
# The >=90% cutoff reads the same way: no marker at all, Fable spent in telemetry only.
rm -f "$ACC/acct-01/.limited"
out="$(claude 2>&1)"
check "the cutoff ignores a scoped bucket the run will not use" "CFG=acct-01" "$out"
out="$(claude --model claude-fable-5 2>&1)"
check "the cutoff still excludes it for the model that IS spent" "CFG=acct-02" "$out"
# A reading with no bucket list keeps the old flat behaviour (fail closed at >=90%),
# with a plainly healthy neighbour so nothing but that exclusion decides the pick.
printf '{"fetched_at":%s,"max_percent":97,"weekly_percent":97,"session_percent":97}' "$now" > "$ACC/acct-01/limits.json"
rm -f "$ACC/acct-02/.limited"
printf '{"fetched_at":%s,"max_percent":20,"weekly_percent":20,"session_percent":20,"buckets":[{"name":"session","percent":20},{"name":"weekly_all","percent":20}]}' "$now" > "$ACC/acct-02/limits.json"
out="$(claude 2>&1)"
check "a bucket-less reading still excludes at the flat peak" "CFG=acct-02" "$out"
for a in acct-01 acct-02; do
  rm -f "$ACC/$a/.limited" "$ACC/$a/limits.json"
  for f in .limited limits.json; do
    [ -e "$WORK/bak94/$a.$f" ] && cp -p "$WORK/bak94/$a.$f" "$ACC/$a/$f"
  done
done

# ---- 9b. codex-review regressions: auth/marker/threshold hardening -------------
# empty .credentials.json must NOT count as auth (interrupted write)
mkdir -p "$ACC/acct-06"
: > "$ACC/acct-06/.credentials.json"
out="$(claude 2>&1)"
case "$out" in *CFG=acct-06*) t_fail "empty creds not selectable" "acct-06 was picked" ;;
  *) t_ok "empty .credentials.json is not treated as auth" ;; esac
rm -rf "$ACC/acct-06"

# fresh telemetry >= threshold excludes even when the .limited marker is missing
printf '{"fetched_at":%s,"max_percent":95,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
printf '{"fetched_at":%s,"max_percent":10,"buckets":[]}' "$now" > "$ACC/acct-02/limits.json"
rm -f "$ACC"/acct-*/.limited
all2=1
for _ in $(seq 1 12); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "telemetry backstop excludes >=90% without a marker" \
  || t_fail "telemetry backstop" "acct-01 (95%) was still selected"

# ...but STALE >=90% telemetry must not exclude (fail open, no invented exclusions)
printf '{"fetched_at":1,"max_percent":95,"buckets":[]}' > "$ACC/acct-01/limits.json"
rm -f "$ACC/acct-02/.credentials.json"   # leave acct-01 as the only candidate
out="$(claude 2>&1)"
check "stale >=90% telemetry does not block (fail open)" "CFG=acct-01" "$out"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-test02","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999,"scopes":["user:inference"],"subscriptionType":"max"}}' > "$ACC/acct-02/.credentials.json"

# a garbled/partial marker is treated as ACTIVE and never deleted (concurrent-write race)
printf 'GARBAGE-NOT-AN-EPOCH\n' > "$ACC/acct-01/.limited"
printf '{"fetched_at":%s,"max_percent":10,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
out="$(claude 2>&1)"
case "$out" in *CFG=acct-02*) t_ok "garbled marker treated as active (excluded)" ;;
  *) t_fail "garbled marker" "acct-01 was selected despite an unparseable marker" ;; esac
[ -f "$ACC/acct-01/.limited" ] && t_ok "garbled marker not deleted by the shim" \
  || t_fail "garbled marker deleted" "shim destroyed a possibly-mid-write marker"
rm -f "$ACC"/acct-*/.limited "$ACC"/acct-*/limits.json

# ---- 9c. DEAD LOGINS are never selected --------------------------------------
# Regression: an account whose refresh token had expired stayed "valid" (it has a
# .credentials.json), so the shim kept picking it and every run died with
# "Failed to authenticate: OAuth session expired and could not be refreshed".
HEALTHY_CREDS='{"claudeAiOauth":{"accessToken":"sk-ant-oat01-live","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999,"scopes":["user:inference"]}}'
DEAD_CREDS='{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}'
printf '%s' "$DEAD_CREDS" > "$ACC/acct-01/.credentials.json"
all2=1
for _ in $(seq 1 12); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "expired refresh token excluded from selection" \
  || t_fail "expired login excluded" "the dead account was still selected"
grep -q "skipped-expired: acct-01" "$ACC/selection.log" \
  && t_ok "skipped-expired logged" || t_fail "skipped-expired log" "no line in selection.log"

# ...and a dead login is not even the all-limited fallback: degraded beats down, but
# dead is DOWN — a limit-marked account that can still authenticate wins.
printf '%s\nx\n' "$((now+3600))" > "$ACC/acct-02/.limited"
out="$(claude 2>&1)"
check "limited-but-alive beats a dead login in the fallback" "CFG=acct-02" "$out"
rm -f "$ACC/acct-02/.limited"

# no refreshToken at all + expired access token = dead too (looped: with a single run a
# random tie-break would let a broken implementation pass half the time)
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-x","expiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
all2=1
for _ in $(seq 1 12); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "credential with no refresh token is dead" \
  || t_fail "no-refresh-token dead" "the dead account was selected"

# expired ACCESS token with a live refresh token is NOT dead (claude refreshes it)
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-stale","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-01/.credentials.json"
rm -f "$ACC/acct-02/.credentials.json"    # acct-01 is the only candidate
out="$(claude 2>&1)"
check "stale access token + live refresh token stays selectable" "CFG=acct-01" "$out"
printf '%s' "$HEALTHY_CREDS" > "$ACC/acct-02/.credentials.json"

# a dead credential beside a portable token still authenticates — via the token
printf '%s' "$DEAD_CREDS" > "$ACC/acct-01/.credentials.json"
printf '%s' "$DEAD_CREDS" > "$ACC/acct-02/.credentials.json"
printf 'sk-ant-oat01-rescue-token' > "$ACC/acct-01/server.token"
out="$(claude 2>&1)"
check "dead creds + portable token still authenticate" "TOK=sk-ant-oat01-rescue-token" "$out"
rm -f "$ACC/acct-01/server.token"

# A revoked setup-token must be rejected BEFORE it carries the user's real command.
# The 401 stays inside the preflight, the account gets a durable auth marker, and the
# untouched --resume invocation continues on the next healthy account.
printf '%s' "$DEAD_CREDS" > "$ACC/acct-01/.credentials.json"
printf '%s' "$HEALTHY_CREDS" > "$ACC/acct-02/.credentials.json"
printf 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' > "$ACC/acct-01/server.token"
lj 1 1 1 > "$ACC/acct-01/limits.json"      # ranks first, so its preflight is what runs
lj 50 1 50 > "$ACC/acct-02/limits.json"
rm -f "$ACC/.last-pick" "$ACC/acct-01/.expired" "$ACC/acct-01/.server-token-verified"
out="$(claude --resume d6ccbac0-6643-4780-a99e-3afa1683478e 2>&1)"
check "revoked setup-token fails over before --resume" "CFG=acct-02" "$out"
case "$out" in
  *"API Error: 401"*) t_fail "revoked setup-token hides preflight 401" "401 reached caller" ;;
  *) t_ok "revoked setup-token hides preflight 401" ;;
esac
grep -q 'reason=setup-token-invalid' "$ACC/acct-01/.expired" 2>/dev/null \
  && t_ok "revoked setup-token writes .expired" \
  || t_fail "revoked setup-token marker" ".expired missing"
if grep -q 'soft_until=' "$ACC/acct-01/.expired" 2>/dev/null; then
  t_fail "proven token rejection is durable" "marker has a soft expiry"
else
  t_ok "proven token rejection is durable"
fi
out="$(claude-accounts expired 2>&1)"
check "revoked setup-token is not mislabeled as a dead login" "TOKEN INVALID" "$out"
check "revoked setup-token gets the token replacement fix" \
  "claude-accounts login acct-01 --token" "$out"
case "$out" in
  *"claude-accounts relogin acct-01"*)
    t_fail "revoked setup-token does not recommend re-login" "wrong recovery shown" ;;
  *) t_ok "revoked setup-token does not recommend re-login" ;;
esac
# A token can be revoked after it passed preflight. The captured -p path must retire
# that exact verified token too, rather than giving it a one-hour generic login park.
rm -f "$ACC/acct-01/.expired"
token_digest="$(printf '%s' 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' \
  | { shasum -a 256 2>/dev/null || sha256sum; } | cut -d ' ' -f1)"
printf '%s\n' "$token_digest" > "$ACC/acct-01/.server-token-verified"
out="$(claude -p 'Reply OK' < /dev/null 2>&1)"
case "$out" in
  *"API Error: 401"*) t_fail "revoked verified token hides runtime 401" "401 reached caller" ;;
  *) t_ok "revoked verified token hides runtime 401" ;;
esac
grep -q 'reason=setup-token-invalid' "$ACC/acct-01/.expired" 2>/dev/null \
  && t_ok "revoked verified token keeps token classification" \
  || t_fail "revoked verified token marker" ".expired missing"
[ ! -f "$ACC/acct-01/.server-token-verified" ] \
  && t_ok "revoked verified token clears its proof" \
  || t_fail "revoked verified token proof" "verification marker survived"
if grep -q 'soft_until=' "$ACC/acct-01/.expired" 2>/dev/null; then
  t_fail "revoked verified token is durably quarantined" "marker has a soft expiry"
else
  t_ok "revoked verified token is durably quarantined"
fi
out="$(CLAUDE_ACCOUNT=acct-01 claude --resume d6ccbac0-6643-4780-a99e-3afa1683478e 2>&1)"
rc=$?
check "pinned revoked setup-token is classified before --resume" \
  "invalid portable OAuth token (401)" "$out"
[ "$rc" -ne 0 ] && t_ok "pinned revoked setup-token exits nonzero" \
  || t_fail "pinned revoked setup-token rc" "rc=$rc"
rm -f "$ACC/acct-01/server.token" "$ACC/acct-01/.expired" \
  "$ACC/acct-01/.server-token-verified" "$ACC"/acct-*/limits.json
printf '%s' "$DEAD_CREDS" > "$ACC/acct-01/.credentials.json"
printf '%s' "$DEAD_CREDS" > "$ACC/acct-02/.credentials.json"

# every account dead => stock passthrough. The reason lands in selection.log; the
# stderr hint is terminal-only, so a service-spawned `claude -p` stays byte-clean.
out="$(claude 2>&1)"
check "all logins dead -> stock passthrough" "CFG=none" "$out"
case "$out" in *claude-multiacc:*) t_fail "all-dead stderr" "wrote a notice to a non-tty stderr" ;;
  *) t_ok "all logins dead -> no stderr noise for services" ;; esac
grep -q "all-expired: falling back" "$ACC/selection.log" \
  && t_ok "all logins dead -> logged with the fix" || t_fail "all-dead log" "no all-expired line"
printf '%s' "$HEALTHY_CREDS" > "$ACC/acct-01/.credentials.json"
printf '%s' "$HEALTHY_CREDS" > "$ACC/acct-02/.credentials.json"

# A short interactive TUI can report auth failure and exit before the -p retry path can
# inspect stderr. Its account-owned transcript must park that setup-token on the next run.
auth_sid="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
mkdir -p "$ACC/acct-01/projects/auth-regression"
printf '%s %s\n' "$auth_sid" '2020-01-01T00:00:00Z' > "$ACC/acct-01/.sessions-index"
auth_line='{"timestamp":"2026-08-22T20:27:29.985Z","error":"authentication_failed",'
auth_line="$auth_line\"session_id\":\"$auth_sid\"}"
printf '%s\n' "$auth_line" \
  > "$ACC/acct-01/projects/auth-regression/$auth_sid.jsonl"
out="$(claude 2>&1)"
check "TUI transcript auth failure excludes rejected account" "CFG=acct-02" "$out"
grep -q 'reason=auth-error' "$ACC/acct-01/.expired" 2>/dev/null \
  && t_ok "TUI transcript auth failure writes .expired" \
  || t_fail "TUI transcript auth marker" "no auth-error marker"
rm -f "$ACC/acct-01/.expired" "$ACC/acct-01/.sessions-index" \
  "$ACC/acct-01/projects/auth-regression/$auth_sid.jsonl"
rmdir "$ACC/acct-01/projects/auth-regression" 2>/dev/null || true

# ---- 9d. the .expired marker: excludes, and self-heals on a newer credential ----
printf '%s\nreason=auth-error marked_at=now detail=test\n' "$now" > "$ACC/acct-01/.expired"
touch -t 202001010101 "$ACC/acct-01/.credentials.json"   # credential OLDER than the marker
all2=1
for _ in $(seq 1 10); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok ".expired marker excludes the account" \
  || t_fail ".expired marker" "marked account was still selected"
touch -t 202001010101 "$ACC/acct-01/.expired"            # credential now NEWER than the marker
touch "$ACC/acct-01/.credentials.json"
out="$(claude 2>&1)"                                     # any selection pass re-evaluates it
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "a newer credential clears the .expired marker" \
  || t_fail ".expired self-heal" "marker survived a re-login"
rm -f "$ACC/acct-01/.expired"

# ---- 9e. an auth failure parks the account (not a 10-minute cooldown) ----------
# Rate limits heal on their own; a dead grant does not — so it gets .expired, and the
# run still completes on another account.
printf '{"fetched_at":%s,"max_percent":1,"weekly_percent":1,"session_percent":1,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
printf '{"fetched_at":%s,"max_percent":50,"weekly_percent":50,"session_percent":50,"buckets":[]}' "$now" > "$ACC/acct-02/limits.json"
echo "authfail:acct-01" > "$FAKE_CTL"
out="$(claude -p hello < /dev/null 2>/dev/null)"
rc=$?
{ [ "$rc" = "0" ] && case "$out" in *CFG=acct-02*) true ;; *) false ;; esac; } \
  && t_ok "auth failure retries onto a healthy account" \
  || t_fail "auth failure retry" "rc=$rc out=$out"
[ -f "$ACC/acct-01/.expired" ] && t_ok "auth failure writes .expired" \
  || t_fail "auth failure marker" ".expired missing"
[ ! -f "$ACC/acct-01/.limited" ] && t_ok "auth failure is not treated as a rate limit" \
  || t_fail "auth failure marker" "got a 10-minute .limited cooldown instead"
# The shim's park is a GUESS from one run, so it carries its own expiry: once the soft
# window passes the account returns to the pool with no external help.
grep -q "soft_until=" "$ACC/acct-01/.expired" \
  && t_ok "a shim-written park carries a soft expiry" \
  || t_fail "soft park" "no soft_until in the shim-written marker"
printf '%s\nreason=auth-error soft_until=%s detail=elapsed\n' "$((now-7200))" "$((now-10))" > "$ACC/acct-01/.expired"
touch -t 202001010101 "$ACC/acct-01/.credentials.json"
out="$(CLAUDE_ACCOUNT='' claude 2>&1)"
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "an elapsed soft park releases the account" \
  || t_fail "soft park expiry" "the account stayed parked past soft_until"
touch "$ACC/acct-01/.credentials.json"
rm -f "$FAKE_CTL" "$ACC/acct-01/.expired" "$ACC"/acct-*/limits.json

# ...and the park is NOT triggered by the model merely talking about auth. This is the
# hot path for `claude -p`: the grep also sees the model's own answer on stdout.
cat > "$FAKEBIN/claude-chatty" <<'EOF'
#!/usr/bin/env bash
echo "Your nginx returns 403 Forbidden. Please run: nginx -t to check the config."
echo "hook failed" >&2
exit 2
EOF
chmod +x "$FAKEBIN/claude-chatty"
mv "$FAKEBIN/claude" "$FAKEBIN/claude.real"; mv "$FAKEBIN/claude-chatty" "$FAKEBIN/claude"
claude -p "why does nginx 403" < /dev/null >/dev/null 2>&1
mv "$FAKEBIN/claude" "$FAKEBIN/claude-chatty"; mv "$FAKEBIN/claude.real" "$FAKEBIN/claude"
if [ -f "$ACC/acct-01/.expired" ] || [ -f "$ACC/acct-02/.expired" ]; then
  t_fail "answer text must not park an account" "the model mentioning 403/'please run' parked an account"
else
  t_ok "a model answer mentioning 403 does not park an account"
fi
rm -f "$ACC"/acct-*/.limited "$ACC"/acct-*/.expired

# ---- 9f. org-disabled accounts are parked too ---------------------------------
# "Your organization has disabled Claude subscription access for Claude Code" is not an
# auth failure (the credential is perfectly valid) and not a rate limit — but the
# account fails EVERY call, so it must leave the pool. A re-login cannot fix it.
printf '{"fetched_at":%s,"max_percent":1,"weekly_percent":1,"session_percent":1,"buckets":[]}' "$now" > "$ACC/acct-01/limits.json"
printf '{"fetched_at":%s,"max_percent":50,"weekly_percent":50,"session_percent":50,"buckets":[]}' "$now" > "$ACC/acct-02/limits.json"
echo "orgfail:acct-01" > "$FAKE_CTL"
out="$(claude -p hello < /dev/null 2>/dev/null)"
rc=$?
{ [ "$rc" = "0" ] && case "$out" in *CFG=acct-02*) true ;; *) false ;; esac; } \
  && t_ok "org-disabled account retries onto a healthy one" \
  || t_fail "org-block retry" "rc=$rc out=$out"
grep -q "reason=org-blocked" "$ACC/acct-01/.expired" 2>/dev/null \
  && t_ok "org-disabled account is parked as org-blocked" \
  || t_fail "org-block marker" "no reason=org-blocked marker"
rm -f "$FAKE_CTL" "$ACC"/acct-*/limits.json
# it stays out of the pool...
all2=1
for _ in $(seq 1 10); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "org-blocked account excluded from selection" \
  || t_fail "org-block exclusion" "the blocked account was still selected"
# ...and a park for an ORG BLOCK survives a credential rewrite. The token refresher
# rewrites .credentials.json every few hours; treating that as "the account recovered"
# handed blocked accounts straight back to the pool and runs kept failing with
# "Your organization has disabled Claude subscription access".
touch "$ACC/acct-01/.credentials.json"          # credential now NEWER than the marker
all2=1
for _ in $(seq 1 10); do
  out="$(claude 2>&1)"
  case "$out" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "an org block survives a credential refresh" \
  || t_fail "org-block stickiness" "a rewritten credential un-parked a blocked account"
[ -f "$ACC/acct-01/.expired" ] && t_ok "the org-block marker is not deleted by a refresh" \
  || t_fail "org-block stickiness" "marker removed by a credential rewrite"
# a CREDENTIAL park still self-heals on a newer credential (unchanged behavior)
printf '%s\nreason=auth-error detail=test\n' "$((now-100))" > "$ACC/acct-01/.expired"
touch -t 202001010101 "$ACC/acct-01/.expired"    # marker older than the credential
touch "$ACC/acct-01/.credentials.json"
claude >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "a credential park still clears on a newer credential" \
  || t_fail "credential park" "marker survived a fresh credential"
printf '%s\nreason=org-blocked detail=test\n' "$((now-100))" > "$ACC/acct-01/.expired"
# `expired` explains it and points at the same fix as any other dead login
out="$(claude-accounts expired 2>&1)"
check "expired labels an org-blocked account" "BLOCKED" "$out"
check "expired explains the org block" "organization has disabled" "$out"
check "expired points org blocks at relogin" "relogin acct-01" "$out"
out="$(claude-accounts list 2>&1)"
check "list flags org-blocked accounts" "ORG-BLOCKED" "$out"
# relogin targets them like any other dead login
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=a@test claude-accounts relogin --yes 2>&1)"
check "relogin targets org-blocked accounts" "acct-01 login saved" "$out"
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "a successful re-login clears an org block" \
  || t_fail "org-block relogin" "marker survived the re-login"
rm -f "$ACC/acct-01/.expired"

# ---- 10. token-only account exports CLAUDE_CODE_OAUTH_TOKEN ------------------
mkdir -p "$ACC/acct-03"
printf 'sk-ant-oat01-tok-for-03' > "$ACC/acct-03/server.token"
out="$(CLAUDE_ACCOUNT=acct-03 claude 2>&1)"
check "token-only account exports token" "TOK=sk-ant-oat01-tok-for-03" "$out"

# ---- 10b. user args survive selection (regression: pick_best must not touch "$@") --
out="$(claude --echo-stdin </dev/null 2>&1)"
[ -z "$out" ] && t_ok "args reach the real binary intact (no positional clobber)" \
  || t_fail "arg passthrough" "--echo-stdin ignored, got: $out"

# ---- 11. exit code passthrough (no retry on non-auth failure) ----------------
claude -p --exit7 >/dev/null 2>"$WORK/err11"
rc=$?
[ "$rc" = "7" ] && t_ok "exit code passthrough (rc=7)" || t_fail "exit code passthrough" "rc=$rc"

# ---- 12. -p retry on rate limit switches account -----------------------------
rm -f "$ACC"/acct-*/.limited
echo "fail:acct-01" > "$FAKE_CTL"
ok12=1
for _ in $(seq 1 10); do
  out="$(claude -p hello < /dev/null 2>/dev/null)"
  rc=$?
  { [ "$rc" = "0" ] && case "$out" in *CFG=acct-0[23]*) true ;; *) false ;; esac; } || ok12=0
done
[ "$ok12" = "1" ] && t_ok "-p retry recovers via another account" || t_fail "-p retry" "some run failed or used acct-01 output"
[ -f "$ACC/acct-01/.limited" ] && t_ok "failed account got error-cooldown marker" || t_fail "cooldown marker" "missing"
rm -f "$FAKE_CTL" "$ACC/acct-01/.limited"

# ---- 12a. every account out of ONE model: switch model, do not fail ----------
# 2026-08-24: all four accounts crossed the Fable weekly bucket inside an hour and
# every task died in under a second having done no work. Rotating accounts cannot
# fix a limit scoped to a model — the endpoint says so itself ("Switch to another
# model"). The pool still had capacity for every other model.
rm -f "$ACC"/acct-*/.limited
echo "modellimit" > "$FAKE_CTL"
out="$(claude -p --model claude-fable-5 hello < /dev/null 2>/dev/null)"
rc=$?
case "$out" in
  *"ARGS="*"claude-opus-5"*) t_ok "a model-scoped limit falls back to another model" ;;
  *) t_fail "model fallback" "rc=$rc out=$out" ;;
esac
[ "$rc" = "0" ] && t_ok "...and the task succeeds instead of failing" \
  || t_fail "model fallback rc" "rc=$rc"
grep -q "model fallback" "$ACC/selection.log" 2>/dev/null \
  && t_ok "the model switch is recorded in the selection log" \
  || t_fail "model fallback log" "nothing logged"

# The pinned model is the caller's choice and must survive a recoverable failure:
# fall back only once ROTATION has been tried and could not help.
rm -f "$ACC"/acct-*/.limited; : > "$ACC/selection.log"
echo "fail:acct-01" > "$FAKE_CTL"
out="$(claude -p --model claude-fable-5 hello < /dev/null 2>/dev/null)"
case "$out" in
  *"claude-fable-5"*) t_ok "an ordinary rate limit rotates account and KEEPS the model" ;;
  *) t_fail "model preserved" "out=$out" ;;
esac
rm -f "$FAKE_CTL" "$ACC"/acct-*/.limited

# ---- 12a2. an in-stream API error still triggers recovery --------------------
# With --output-format stream-json the CLI exits 0 and reports the 429 as the final
# result object. Every app-robot task takes that path, so gating retry on the exit
# status alone meant the pool never rotated and never fell back for the exact
# failures it exists for — while the shim recorded a clean success every time.
rm -f "$ACC"/acct-*/.limited; : > "$ACC/selection.log"
echo "streamlimit" > "$FAKE_CTL"
out="$(claude -p --model claude-fable-5 --output-format stream-json hello < /dev/null 2>/dev/null)"
rc=$?
case "$out" in
  *'"is_error":false'*) t_ok "an in-stream API error is recovered, not reported as success" ;;
  *) t_fail "stream error recovery" "rc=$rc out=$out" ;;
esac
[ "$rc" = "0" ] && t_ok "...and the caller still gets exit 0, as the CLI would give" \
  || t_fail "stream error exit status" "rc=$rc"

# A stream that merely MENTIONS a limit mid-run and then completes must be left alone:
# re-running it would throw away a finished task.
rm -f "$FAKE_CTL" "$ACC"/acct-*/.limited; : > "$ACC/selection.log"
out="$(claude -p --model claude-fable-5 hello < /dev/null 2>/dev/null)"
grep -q "retry from=" "$ACC/selection.log" 2>/dev/null \
  && t_fail "spurious retry" "a healthy run was retried" \
  || t_ok "a healthy run is never retried"
rm -f "$FAKE_CTL" "$ACC"/acct-*/.limited

# ---- 12b. pipe stdin skips retry buffering but passes bytes through -----------
out="$(printf 'pipe-data' | claude -p --echo-stdin 2>/dev/null)"
[ "$out" = "pipe-data" ] && t_ok "pipe stdin passes through (no retry buffering)" || t_fail "pipe stdin passthrough" "got: $out"

# ---- 12c. HOME unset: shim still fails open into passthrough ------------------
out="$(env -u HOME -u CLAUDE_ACCOUNTS_DIR claude 2>&1)"
check "HOME unset -> passthrough, no crash" "CFG=none" "$out"

# ---- 12d. error-cooldown marker survives a clean limits pass -------------------
printf '%s\nbucket=error-cooldown percent=? reason=error-cooldown\n' "$(( $(date +%s) + 600 ))" > "$ACC/acct-01/.limited"
cat > "$WORK/usage-mid.json" <<'EOF'
{"limits":[{"kind":"session","percent":10,"resets_at":"2099-01-01T00:00:00+00:00","scope":null}]}
EOF
CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-mid.json" claude-accounts limits --quiet
[ -f "$ACC/acct-01/.limited" ] && t_ok "error-cooldown marker survives clean limits refresh" || t_fail "cooldown vs limits" "marker was cleared early"
rm -f "$ACC/acct-01/.limited"

# ---- 12f-12h. client-reported rate limits + rotation (own two-account pool) -------
# The shared pool has picked up a third account by now, so these run in an instance root
# of their own: with exactly two accounts, "went somewhere else" and "rotated" are both
# unambiguous.
CLP="$WORK/client-limit-pool"
mkdir -p "$CLP/tmp"
: > "$CLP/.limits-kick"
cat > "$CLP/accounts.json" <<'EOF'
{"version":1,"threshold":90,"accounts":[
  {"id":"acct-01","email":"cl1@test","home":"mac","added_at":"2026-07-13T00:00:00Z"},
  {"id":"acct-02","email":"cl2@test","home":"mac","added_at":"2026-07-13T00:00:00Z"}]}
EOF
for i in 01 02; do
  mkdir -p "$CLP/acct-$i"
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-cl%s","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' "$i" > "$CLP/acct-$i/.credentials.json"
done
export CLAUDE_ACCOUNTS_ROOT="$CLP"
ACC_SAVED="$ACC"
ACC="$CLP"

# ---- 12f. a rate limit hit by an INTERACTIVE session takes its account out ---------
# The reported bug: a tmux session runs into its 5h limit, the user quits and starts
# `claude` again, and the pool hands back the same dead account. Interactive runs are
# exec'd, so the -p retry path above never sees them — the only trace of the rejection
# is the one Claude Code writes itself, in the session transcript.
mkclientlimit() { # mkclientlimit <acct dir> <session id> <resetsAt> [rejection ISO ts]
  mkdir -p "$1/projects/-proj"
  printf '{"type":"mode","mode":"normal","sessionId":"%s"}\n' "$2" > "$1/projects/-proj/$2.jsonl"
  printf '{"type":"assistant","timestamp":"%s","message":{"content":[{"type":"text","text":"limit"}]},"quotaLimits":{"status":"rejected","resetsAt":%s,"unifiedRateLimitFallbackAvailable":false,"rateLimitType":"five_hour","overageStatus":"rejected"},"error":"rate_limit","isApiErrorMessage":true,"apiErrorStatus":429,"sessionId":"%s"}\n' \
    "${4:-$(date -u +%Y-%m-%dT%H:%M:%S.000Z)}" "$3" "$2" >> "$1/projects/-proj/$2.jsonl"
  # index line = "<id> <ISO claim>": the account that owned the session, and from when
  printf '%s %s\n' "$2" "$(date -u -r "$(( $(date +%s) - 600 ))" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d "@$(( $(date +%s) - 600 ))" +%Y-%m-%dT%H:%M:%SZ)" > "$1/.sessions-index"
}
SID1="81bf8b20-013f-4414-8878-e0289bec9ad0"
RESET1=$(( $(date +%s) + 1800 ))
REJECTED1="$(date -u +%Y-%m-%dT%H:%M:%S.000Z)"
mkclientlimit "$ACC/acct-01" "$SID1" "$RESET1" "$REJECTED1"
all2=1
for _ in $(seq 1 12); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "client-reported rate limit excludes the account" \
  || t_fail "client rate limit" "the rejected account was picked again"
first="$(head -1 "$ACC/acct-01/.limited" 2>/dev/null)"
[ "$first" = "$RESET1" ] && t_ok "marker carries the API's own reset time" \
  || t_fail "client marker reset" "want $RESET1, got '${first:-<none>}'"
grep -q 'reason=client-rate-limit' "$ACC/acct-01/.limited" 2>/dev/null \
  && t_ok "marker is tagged client-rate-limit" || t_fail "client marker reason" "$(cat "$ACC/acct-01/.limited" 2>/dev/null)"
grep -q "marked_at=$REJECTED1" "$ACC/acct-01/.limited" 2>/dev/null \
  && t_ok "client marker preserves the rejection timestamp" \
  || t_fail "client marker timestamp" "$(cat "$ACC/acct-01/.limited" 2>/dev/null)"
out="$(CLAUDE_ACCOUNT=acct-01 claude 2>&1)"
check "explicit pin still wins over a client-reported limit" "CFG=acct-01" "$out"

# a marker the client earned survives a clean telemetry pass while its window is open
CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-mid.json" claude-accounts limits --quiet
[ -f "$ACC/acct-01/.limited" ] && t_ok "client-rate-limit marker survives a clean limits refresh" \
  || t_fail "client marker vs limits" "marker was cleared while the window was still open"
# A later successful usage read under the threshold supersedes the client marker. The
# live pool had five accounts at 0-3% hidden behind days-old client markers, leaving one
# nominally-empty (but actually rejected) account to receive every direct launch.
# A fleet sync refreshes the file's mtime, so recovery must use its semantic timestamp.
{ head -1 "$ACC/acct-01/.limited"; \
  sed 's/marked_at=[^ ]*/marked_at=2020-01-01T00:00:00Z/' "$ACC/acct-01/.limited" | tail -1; \
} > "$ACC/acct-01/.limited.tmp"
mv "$ACC/acct-01/.limited.tmp" "$ACC/acct-01/.limited"
CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-mid.json" claude-accounts limits --force --quiet
[ ! -f "$ACC/acct-01/.limited" ] \
  && t_ok "newer low telemetry clears an old client-rate-limit marker" \
  || t_fail "old client marker vs limits" "marker survived confirmed recovery"
[ -f "$ACC/acct-01/.client-limit-cleared" ] \
  && t_ok "confirmed client-limit recovery records a transcript watermark" \
  || t_fail "client recovery watermark" "watermark missing"
claude >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.limited" ] \
  && t_ok "an old transcript cannot recreate a telemetry-disproved marker" \
  || t_fail "client recovery watermark" "old rejection recreated the marker"
rm -f "$ACC/acct-01/.limited"

# an ALREADY-ELAPSED rejection is history, not an exclusion
mkclientlimit "$ACC/acct-01" "$SID1" "$(( $(date +%s) - 60 ))"
hits1=0
for _ in $(seq 1 12); do
  case "$(claude 2>&1)" in *CFG=acct-01*) hits1=$((hits1+1)) ;; esac
done
{ [ "$hits1" -gt 0 ] && [ ! -f "$ACC/acct-01/.limited" ]; } \
  && t_ok "an elapsed client rejection does not exclude" \
  || t_fail "elapsed client rejection" "acct-01 hits=$hits1 marker=$([ -f "$ACC/acct-01/.limited" ] && echo yes || echo no)"

# opt-out
mkclientlimit "$ACC/acct-01" "$SID1" "$(( $(date +%s) + 1800 ))"
rm -f "$ACC/acct-01/.limited"
hits1=0
for _ in $(seq 1 12); do
  case "$(CLAUDE_MULTIACC_CLIENT_LIMITS=0 claude 2>&1)" in *CFG=acct-01*) hits1=$((hits1+1)) ;; esac
done
{ [ "$hits1" -gt 0 ] && [ ! -f "$ACC/acct-01/.limited" ]; } \
  && t_ok "CLAUDE_MULTIACC_CLIENT_LIMITS=0 turns the scan off" \
  || t_fail "client-limit opt-out" "still excluded with the scan disabled"

# a hostile session index must not walk out of the pool
printf '../../../../etc/passwd x\n-e x\n%s %s\n' "$SID1" "2026-01-01T00:00:00Z" > "$ACC/acct-01/.sessions-index"
claude >/dev/null 2>&1
grep -q 'reason=client-rate-limit' "$ACC/acct-01/.limited" 2>/dev/null \
  && t_ok "traversal and option-shaped ids are ignored, real ids still scanned" \
  || t_fail "session index traversal" "scan broke on a hostile entry"
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index
rm -rf "$ACC"/acct-0*/projects

# ---- 12g. the whole round trip: a run registers itself, the NEXT run avoids it -----
# No .sessions-index is planted here. The shim's detached capture has to learn the
# session id from $acct/sessions/<pid>.json WHILE the run is alive — after it exits the
# client deletes that file and nothing else can name the transcript.
rm -f "$ACC/.pick-seq" "$ACC"/acct-0*/.last-pick
FAKE_SESSION_ID="9f3c1d2e-0000-4000-8000-abcdefabcdef" \
  FAKE_LIMIT_RESET="$(( $(date +%s) + 1800 ))" \
  FAKE_SESSION_HOLD=5 claude >/dev/null 2>&1
hit="$(ls "$ACC"/acct-0*/.sessions-index 2>/dev/null | head -1)"
limited_dir="$(dirname "${hit:-/nonexistent}")"
[ -n "$hit" ] && t_ok "the run's own session id is captured while it is alive" \
  || t_fail "session capture" "no .sessions-index was written"
out="$(claude 2>&1)"
case "$out" in
  *"CFG=$(basename "$limited_dir")"*)
    t_fail "restart after a limit hit" "landed straight back on $(basename "$limited_dir")" ;;
  *) t_ok "quitting a limit-hit session and restarting lands on another account" ;;
esac
grep -q 'reason=client-rate-limit' "$limited_dir/.limited" 2>/dev/null \
  && t_ok "the account that hit the limit is marked from its own transcript" \
  || t_fail "post-run marking" "no client-rate-limit marker on $(basename "$limited_dir")"
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions

# ---- 12h. equal-headroom picks ROTATE instead of re-rolling a coin -----------------
# With telemetry stale (the usage endpoint 429s its own callers for hours) every account
# scores NEUTRAL, so this tie-break is the only thing standing between a restart and the
# account it just walked away from.
rm -f "$ACC/.pick-seq" "$ACC"/acct-0*/.last-pick "$ACC"/acct-0*/limits.json
seq_out=""
for _ in $(seq 1 8); do
  case "$(claude 2>&1)" in
    *CFG=acct-01*) seq_out="${seq_out}1" ;;
    *CFG=acct-02*) seq_out="${seq_out}2" ;;
    *) seq_out="${seq_out}?" ;;
  esac
done
case "$seq_out" in
  12121212|21212121) t_ok "equal-score picks round-robin across the pool ($seq_out)" ;;
  *) t_fail "round-robin tie-break" "sequence $seq_out (want strict alternation)" ;;
esac
# ... and the rotation must never override real headroom
lj 80 10 80 > "$ACC/acct-01/limits.json"
lj 20 10 20 > "$ACC/acct-02/limits.json"
all2=1
for _ in $(seq 1 8); do
  case "$(claude 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "rotation never outranks measured headroom" \
  || t_fail "rotation vs headroom" "rotation pulled work onto the busier account"
rm -f "$ACC"/acct-0*/limits.json "$ACC/.pick-seq" "$ACC"/acct-0*/.last-pick

# ---- 12i. the clean-scan memo throttles re-reads without stranding a limit ---------
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.client-scan "$ACC"/acct-0*/.sessions-index
rm -rf "$ACC"/acct-0*/projects
mkdir -p "$ACC/acct-01/projects/-proj"
printf '{"type":"mode","mode":"normal","sessionId":"%s"}\n' "$SID1" > "$ACC/acct-01/projects/-proj/$SID1.jsonl"
printf '%s %s\n' "$SID1" "2026-01-01T00:00:00Z" > "$ACC/acct-01/.sessions-index"
claude >/dev/null 2>&1     # a clean scan over a real (rejection-free) transcript
[ -f "$ACC/acct-01/.client-scan" ] \
  && t_ok "a clean client scan is memoized" || t_fail "clean scan memo" "no .client-scan written"
mkclientlimit "$ACC/acct-01" "$SID1" "$(( $(date +%s) + 1800 ))"
CLAUDE_MULTIACC_CLIENT_SCAN_TTL=3600 claude >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.limited" ] \
  && t_ok "the memo suppresses a re-read inside its window" \
  || t_fail "clean scan memo" "rescanned inside the memo window"
rm -f "$ACC"/acct-0*/.client-scan
claude >/dev/null 2>&1
grep -q 'reason=client-rate-limit' "$ACC/acct-01/.limited" 2>/dev/null \
  && t_ok "once the memo lapses the rejection is seen" \
  || t_fail "clean scan memo" "the rejection was never picked up"
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.client-scan "$ACC"/acct-0*/.sessions-index
rm -rf "$ACC"/acct-0*/projects

# ---- 12j. codex-review: corrupt pool numbers never reach bash arithmetic -----------
# An out-of-range value in any scraped number makes `[ x -lt y ]` print "integer
# expression expected" on STDERR — which a service-spawned `claude -p` must never see —
# and makes $((x + 1)) wrap negative.
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.client-scan "$ACC"/acct-0*/.sessions-index
rm -rf "$ACC"/acct-0*/projects
BIG="99999999999999999999999999999999"
printf '%s\n' "$BIG" > "$ACC/.last-pick"
printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":1,"max_percent":%s,"buckets":[]}' "$BIG" "$BIG" "$BIG" > "$ACC/acct-02/limits.json"
err="$(claude 2>&1 >/dev/null)"
[ -z "$err" ] && t_ok "absurd pool numbers keep stderr byte-clean" \
  || t_fail "corrupt number handling" "stderr: $(printf '%s' "$err" | head -c 160)"
out="$(claude 2>/dev/null)"
case "$out" in *CFG=acct-0*) t_ok "selection still works with corrupt numbers ($out)" ;;
  *) t_fail "corrupt number handling" "selection produced: $out" ;; esac
# caller-supplied numbers are just as capable of reaching `[ -lt ]` as pool state
: > "$ACC/acct-01/.client-scan"
err="$(CLAUDE_MULTIACC_CLIENT_SCAN_TTL=bogus CLAUDE_MULTIACC_THRESHOLD=nonsense claude 2>&1 >/dev/null)"
out="$(CLAUDE_MULTIACC_CLIENT_SCAN_TTL=bogus CLAUDE_MULTIACC_THRESHOLD=nonsense claude 2>/dev/null)"
{ [ -z "$err" ] && case "$out" in *CFG=acct-0*) true ;; *) false ;; esac; } \
  && t_ok "garbage in the client-scan TTL / threshold env vars keeps stderr clean" \
  || t_fail "env number validation" "stderr: $(printf '%s' "$err" | head -c 160) out: $out"
rm -f "$ACC"/acct-0*/.client-scan

printf '%s\nbucket=x percent=? reason=limits\n' "$BIG" > "$ACC/acct-01/.limited"
err="$(claude 2>&1 >/dev/null)"
{ [ -z "$err" ] && [ -f "$ACC/acct-01/.limited" ]; } \
  && t_ok "an absurd .limited reset reads as LIMITED, silently" \
  || t_fail "corrupt marker handling" "stderr: $(printf '%s' "$err" | head -c 160)"
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/limits.json "$ACC/.last-pick"

# ---- 12m. a session id belongs to ONE account, and only from when it took it over ---
# `claude --continue` resumes the SAME session id under whichever account the pool hands
# out next (the client only mints a new id with --fork-session) and the transcript is
# shared — so an id claimed by acct-02 must stop being acct-01's evidence, and a rejection
# recorded before the handover must not be charged to the new owner.
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions
SIDC="0badc0de-1111-4111-8111-abcdefabcdef"
NOWS="$(date -u +%s)"
OLDISO="$(date -u -r "$((NOWS - 7200))" +%Y-%m-%dT%H:%M:%S.000Z 2>/dev/null || date -u -d "@$((NOWS - 7200))" +%Y-%m-%dT%H:%M:%S.000Z)"
# acct-01 ran the session two hours ago and hit a limit then; acct-02 has just resumed it.
mkclientlimit "$ACC/acct-01" "$SIDC" "$((NOWS + 1800))" "$OLDISO"
mkdir -p "$ACC/acct-02/sessions" "$ACC/acct-02/projects"
ln -s "$ACC/acct-01/projects/-proj" "$ACC/acct-02/projects/-proj"
printf '{"pid":4242,"sessionId":"%s","cwd":"/proj","kind":"interactive","startedAt":%s000}\n' \
  "$SIDC" "$NOWS" > "$ACC/acct-02/sessions/4242.json"
claude >/dev/null 2>&1
grep -q -- "^$SIDC " "$ACC/acct-02/.sessions-index" 2>/dev/null \
  && t_ok "a resumed session id is claimed by the account now running it" \
  || t_fail "session id handover" "acct-02 never claimed the resumed id"
grep -q -- "^$SIDC " "$ACC/acct-01/.sessions-index" 2>/dev/null \
  && t_fail "session id handover" "acct-01 still claims an id acct-02 took over" \
  || t_ok "the previous owner releases a resumed session id"
[ ! -f "$ACC/acct-02/.limited" ] \
  && t_ok "a rejection older than the handover is not charged to the new owner" \
  || t_fail "claim-time scoping" "acct-02 was marked for a limit acct-01 hit"
rm -f "$ACC/acct-02/projects/-proj" "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions

# two accounts claiming the SAME id (a crossed race, or corrupt state) must not both be
# marked off one shared transcript — at most the newer claimant may answer for it
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions
SIDD="0dadc0de-2222-4222-8222-abcdefabcdef"   # hex only, or sess_id_ok drops it and the
                                             # scan never reaches the conflict check
NOWD="$(date -u +%s)"
mkclientlimit "$ACC/acct-01" "$SIDD" "$((NOWD + 1800))"
mkdir -p "$ACC/acct-02/projects"
ln -s "$ACC/acct-01/projects/-proj" "$ACC/acct-02/projects/-proj"
CLAIM1="$(cat "$ACC/acct-01/.sessions-index")"
printf '%s\n' "$CLAIM1" > "$ACC/acct-02/.sessions-index"    # identical id AND claim
claude >/dev/null 2>&1
n_marked=0
for d in "$ACC/acct-01" "$ACC/acct-02"; do [ -f "$d/.limited" ] && n_marked=$((n_marked+1)); done
[ "$n_marked" -eq 0 ] \
  && t_ok "an id claimed by two accounts marks neither (ambiguity => no attribution)" \
  || t_fail "duplicate session claim" "$n_marked accounts were marked off one transcript"
# ...and it is the NEWEST rival claim that decides, not whichever one grep prints first
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.client-scan
{ printf '%s 2020-01-01T00:00:00Z\n' "$SIDD"; printf '%s 2090-01-01T00:00:00Z\n' "$SIDD"; } \
  > "$ACC/acct-02/.sessions-index"
claude >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.limited" ] \
  && t_ok "a stale rival claim does not hide a newer one" \
  || t_fail "duplicate session claim" "only the first rival claim was inspected"
rm -f "$ACC/acct-02/projects/-proj" "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions

# a SYMLINKED registry entry belongs to whatever it points at, not to this account
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions
FOREIGN="$WORK/foreign-session.json"
printf '{"pid":9,"sessionId":"%s","cwd":"/proj","kind":"interactive","startedAt":%s000}\n' \
  "$SID1" "$(( $(date -u +%s) - 600 ))" > "$FOREIGN"
mkclientlimit "$ACC/acct-01" "$SID1" "$(( $(date +%s) + 1800 ))"
rm -f "$ACC/acct-01/.sessions-index"
mkdir -p "$ACC/acct-01/sessions"
ln -s "$FOREIGN" "$ACC/acct-01/sessions/9.json"
claude >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.limited" ] \
  && t_ok "a symlinked session registry entry is not this account's evidence" \
  || t_fail "symlinked registry entry" "a foreign registry entry marked the account LIMITED"
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions

# ---- 12n. an option-shaped session id must not hang the shim before exec ------------
# "-e" is hex+dash, so a charset check alone lets it through; grep then treats it as a
# flag, loses its file operand and blocks on the shim's OWN stdin — a hang before exec.
rm -f "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
mkdir -p "$ACC/acct-01/sessions"
printf '{"pid":7,"sessionId":"-e","cwd":"/proj","kind":"interactive","startedAt":%s000}\n' "$(date -u +%s)" \
  > "$ACC/acct-01/sessions/7.json"
printf 'deadbeef 2026-01-01T00:00:00Z\n' > "$ACC/acct-01/.sessions-index"
FIFO="$WORK/hangfifo"
rm -f "$FIFO"; mkfifo "$FIFO"
exec 9<>"$FIFO"                       # holds the fifo open: stdin that never EOFs
( claude < "$FIFO" > "$WORK/hang.out" 2>&1 ) &
hangpid=$!
waited=0
while [ "$waited" -lt 10 ] && kill -0 "$hangpid" 2>/dev/null; do sleep 1; waited=$((waited+1)); done
if kill -0 "$hangpid" 2>/dev/null; then
  kill -9 "$hangpid" 2>/dev/null
  t_fail "option-shaped session id" "the shim hung for ${waited}s before exec"
else
  wait "$hangpid" 2>/dev/null || true
  case "$(cat "$WORK/hang.out" 2>/dev/null)" in
    *CFG=acct-0*) t_ok "an option-shaped session id neither hangs nor breaks selection" ;;
    *) t_fail "option-shaped session id" "selection produced: $(head -c 120 "$WORK/hang.out")" ;;
  esac
fi
exec 9>&-
rm -f "$FIFO" "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/sessions

# a SHARED session registry proves nothing about which account ran what
rm -f "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects "$ACC"/acct-0*/sessions
SHAREDS="$WORK/cl-shared-sessions"
mkdir -p "$SHAREDS"
printf '{"pid":1,"sessionId":"%s","cwd":"/proj","kind":"interactive","startedAt":%s000}\n' "$SID1" "$(date -u +%s)" > "$SHAREDS/1.json"
for i in 01 02; do ln -s "$SHAREDS" "$ACC/acct-$i/sessions"; done
mkclientlimit "$ACC/acct-01" "$SID1" "$(( $(date +%s) + 1800 ))"
rm -f "$ACC/acct-01/.sessions-index"      # only the shared registry could supply the id
claude >/dev/null 2>&1
{ [ ! -f "$ACC/acct-01/.limited" ] && [ ! -f "$ACC/acct-02/.limited" ]; } \
  && t_ok "a shared session registry never marks an account (fail open)" \
  || t_fail "shared session registry" "a shared registry marked an account LIMITED"
rm -f "$ACC"/acct-0*/sessions "$ACC"/acct-0*/.limited "$ACC"/acct-0*/.sessions-index "$ACC"/acct-0*/.client-scan
rm -rf "$ACC"/acct-0*/projects

# ---- 12k. codex-review: rotation must not serialise a parallel burst ---------------
# The first cut of this used a monotonic counter and picked the account with the OLDEST
# stamp. Every member of a concurrent burst reads the same stamps, computes the same
# "oldest", and piles onto one account. Rotation only ever drops the ONE account just
# handed out; everything else is still sampled at random.
rm -f "$ACC/.last-pick" "$ACC"/acct-0*/limits.json "$ACC"/acct-0*/.limited
# THREE accounts on purpose. Rotation drops the one just handed out, so in a two-account
# pool a burst legitimately lands entirely on the single alternative and the test would
# be measuring nothing (it flaked exactly that way on Linux). With three, the burst must
# spread over the two that remain — which is precisely what the counter version could not.
mkdir -p "$ACC/acct-09"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-cl09","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-09/.credentials.json"
: > "$WORK/burst.out"
for _ in $(seq 1 16); do ( claude >> "$WORK/burst.out" 2>&1 ) & done
wait
b_distinct="$(grep -o 'CFG=acct-[0-9]*' "$WORK/burst.out" | sort -u | tr '\n' ' ')"
b_n="$(printf '%s' "$b_distinct" | wc -w | tr -d ' ')"
[ "$b_n" -ge 2 ] \
  && t_ok "a parallel burst still spreads across the pool ($b_distinct)" \
  || t_fail "burst spreading" "all 16 concurrent runs took $b_distinct — rotation serialised the burst"
rm -rf "$ACC/acct-09"

# ---- 12l. codex-review: an unwritable pool root never prints to stderr --------------
# `cmd > file 2>/dev/null` does NOT silence a failed redirect: bash applies the
# redirections in order, so the open fails while stderr is still the caller's.
RO="$WORK/readonly-pool"
mkdir -p "$RO/acct-01" "$RO/acct-02"
cp "$ACC/accounts.json" "$RO/accounts.json"
for i in 01 02; do
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-ro","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$RO/acct-$i/.credentials.json"
done
: > "$RO/.limits-kick"
chmod 555 "$RO" "$RO/acct-01" "$RO/acct-02"
err="$(CLAUDE_ACCOUNTS_ROOT="$RO" claude 2>&1 >/dev/null)"
out="$(CLAUDE_ACCOUNTS_ROOT="$RO" claude 2>/dev/null)"
chmod 755 "$RO" "$RO/acct-01" "$RO/acct-02"
[ -z "$err" ] && t_ok "a read-only pool root keeps stderr byte-clean" \
  || t_fail "read-only pool root" "stderr: $(printf '%s' "$err" | head -c 200)"
case "$out" in *CFG=acct-0*) t_ok "a read-only pool root still selects ($out)" ;;
  *) t_fail "read-only pool root" "selection produced: $out" ;; esac

ACC="$ACC_SAVED"
unset CLAUDE_ACCOUNTS_ROOT

# ---- 12e. TTY stdin: retry disabled so the terminal is never swapped for /dev/null --
if command -v script >/dev/null 2>&1; then
  # `claude -p` on a TTY with no prompt arg reads the terminal. Under a PTY the shim
  # must take the plain exec path (stdin inherited), never the buffered retry path.
  if [ "$(uname -s)" = "Darwin" ]; then
    ptyout="$(script -q /dev/null env PATH="$PATH" CLAUDE_ACCOUNTS_DIR="$ACC" FAKE_CTL="$FAKE_CTL" claude -p --echo-stdin <<'PTYIN' 2>/dev/null
tty-typed-prompt
PTYIN
)"
  else
    ptyout="$(script -qec "claude -p --echo-stdin" /dev/null <<'PTYIN' 2>/dev/null
tty-typed-prompt
PTYIN
)"
  fi
  case "$ptyout" in
    *tty-typed-prompt*) t_ok "TTY stdin reaches claude (retry path does not eat it)" ;;
    *) t_fail "TTY stdin" "terminal input was lost: $(printf '%s' "$ptyout" | head -c 80)" ;;
  esac
else
  t_ok "TTY stdin test skipped (no script(1))"
fi

# ---- 13. stdin/stdout byte fidelity through retry path -----------------------
printf 'line1\nline2 with spaces\n' > "$WORK/stdin13"
out="$(claude -p --echo-stdin < "$WORK/stdin13" 2>/dev/null)"
expected="$(cat "$WORK/stdin13")"
[ "$out" = "$expected" ] && t_ok "stdin/stdout byte fidelity (-p pipe)" || t_fail "stdin fidelity" "got: $out"

# ---- 14. selection log written ------------------------------------------------
# One COMPLETE reading first, on purpose: the pool is still carrying the session-only
# documents an earlier limits pass wrote, and since 2026-09-04 a pool where no account
# has BOTH percentages is BLIND (bin/claude telem_blind) and logs the blind format
# instead. The ranked format asserted below only exists when something actually ranked.
lj 20 10 20 > "$ACC/acct-01/limits.json"
claude >/dev/null 2>&1
log_pattern='^[0-9]{4}-[0-9]{2}-[0-9]{2}T.*acct-0[123] weekly=[0-9?]+% session=[0-9?]+%'
log_pattern="$log_pattern band=30 band-count=[0-9]+ session-gate=50 session-ok=[0-9]+ pwd="
grep -qE "$log_pattern" "$ACC/selection.log" \
  && t_ok "selection.log format" || t_fail "selection.log format" "no matching lines"
grep -qE 'sk-ant-oat|accessToken|refreshToken' "$ACC/selection.log" \
  && t_fail "selection.log has no secrets" "a token leaked into the log" \
  || t_ok "selection.log leaks no secrets"

# ---- 15. CLI: list / import / remove ------------------------------------------
out="$(claude-accounts list 2>&1)"
check "list shows accounts" "acct-01" "$out"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-t4","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$WORK/import-creds.json"
out="$(claude-accounts import c@test --id acct-04 --creds "$WORK/import-creds.json" --mode copy --no-sync 2>&1)"
check "import account" "Imported acct-04" "$out"
[ -f "$ACC/acct-04/.credentials.json" ] && t_ok "import copied credentials" || t_fail "import copied credentials" "file missing"
out="$(claude-accounts list 2>&1)"
check "imported account listed" "c@test" "$out"
out="$(claude-accounts remove acct-04 --yes 2>&1)"
check "remove account" "Removed acct-04" "$out"
[ ! -d "$ACC/acct-04" ] && t_ok "remove deleted dir" || t_fail "remove deleted dir" "dir still there"

# ---- 15b. duplicate-email guards ------------------------------------------------
# add of a named, already-present email => graceful SKIP before any sign-in (exit 0)
out="$(claude-accounts add a@test 2>&1)"
rc=$?
check "add skips a duplicate email with a message" "already added as acct-01 — skipping" "$out"
[ "$rc" = "0" ] && t_ok "duplicate add exits 0 (graceful skip)" || t_fail "duplicate add rc" "rc=$rc"
[ ! -d "$ACC/acct-04" ] && t_ok "duplicate add created nothing" || t_fail "duplicate add" "dir created"
# import stays strict (it's the lower-level command): refuses a duplicate
out="$(claude-accounts import a@test --id acct-09 --no-sync 2>&1)"
rc=$?
check "import refuses duplicate email" "already registered as acct-01" "$out"
[ ! -d "$ACC/acct-09" ] && t_ok "duplicate import created nothing" || t_fail "duplicate import" "dir created"
out="$(claude-accounts import a@test --id acct-01 --no-sync 2>&1)"
check "import same-id update allowed" "Imported acct-01" "$out"

# ---- 15c. login-first add (DEFAULT full-login flow): registers after verified auth --
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=new@test claude-accounts add new@test 2>&1)"
check "add registers after verified login" "Registered acct-04 for new@test" "$out"
[ -f "$ACC/acct-04/.credentials.json" ] && t_ok "default add writes .credentials.json (full login)" || t_fail "add creds" "missing"
[ ! -f "$ACC/acct-04/server.token" ] && t_ok "default add does NOT mint a setup-token" || t_fail "add token" "unexpected server.token"
out="$(CLAUDE_ACCOUNT=acct-04 claude 2>&1)"
check "new account usable via pin (oauth creds)" "CFG=acct-04" "$out"
claude-accounts remove acct-04 --yes >/dev/null 2>&1

# ---- 15c1. add --token: portable setup-token instead of creds ------------------------
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=tok@test claude-accounts add tok@test --token 2>&1)"
check "add --token registers via portable token" "Registered acct-04 for tok@test" "$out"
check "add --token says the identity cannot be verified" "a setup token carries no identity" "$out"
case "$out" in
  *"sign-in verified"*) t_fail "add --token must not claim a verified sign-in" "it says 'sign-in verified' for an identity nothing can read" ;;
  *) t_ok "add --token does not claim a verified sign-in" ;;
esac
case "$(grep 'add acct-04 tok@test' "$ACC/ops.log" 2>/dev/null)" in
  *auth-verified*) t_fail "ops.log must not record --token as auth-verified" "the audit trail would relaunder the assumption" ;;
  *"identity unverifiable"*) t_ok "ops.log records the --token add as unverifiable" ;;
  *) t_fail "ops.log line for the --token add" "not found" ;;
esac
[ -s "$ACC/acct-04/server.token" ] && t_ok "add --token writes server.token" || t_fail "add --token" "missing"
out="$(CLAUDE_ACCOUNT=acct-04 claude 2>&1)"
check "token account exports CLAUDE_CODE_OAUTH_TOKEN" "TOK=sk-ant-oat01-FAKE" "$out"

# ---- 15c1a. a ceremony's token is PROVEN before it is saved --------------------------
# add --token above ran the inference probe: the exact token is on record as verified
# on this machine, so the audit never calls a fresh mint UNVERIFIED — and the panel
# can tell a proven token from one a Mac merely holds.
[ -f "$ACC/acct-04/.server-token-verified" ] \
  && t_ok "add --token proves the token with a real inference before saving" \
  || t_fail "add --token verification marker" ".server-token-verified missing"
out="$(claude-accounts list --json 2>/dev/null | python3 -c '
import json, sys
rows = {a["id"]: a for a in json.load(sys.stdin)["accounts"]}
print(rows["acct-04"].get("token_verified"))')"
[ "$out" = "True" ] && t_ok "list --json reports the token as verified here" \
  || t_fail "list --json token_verified" "expected True, got: $out"
# The 2026-08-28 shape: the client's TUI wrapped the 108-character token at 80 columns.
# The token block is joined across the break, so the capture is WHOLE — and proven.
orig="$(cat "$ACC/acct-04/server.token")"
out="$(FAKE_TOKEN_FULL=1 FAKE_TOKEN_WRAP=1 claude-accounts mint acct-04 2>&1 </dev/null)"
rc=$?
[ "$rc" = "0" ] && t_ok "a wrapped token is reassembled from the transcript" || t_fail "wrapped token rc" "rc=$rc: $(printf '%s' "$out" | tail -c 200)"
case "$(tr -d '[:space:]' < "$ACC/acct-04/server.token")" in
  *TAILOK) [ "$(tr -d '[:space:]' < "$ACC/acct-04/server.token" | wc -c | tr -d ' ')" = "108" ] \
    && t_ok "the reassembled token is the complete one" || t_fail "reassembled token" "wrong length" ;;
  *) t_fail "reassembled token" "tail missing" ;;
esac
printf '%s' "$orig" > "$ACC/acct-04/server.token"; rm -f "$ACC/acct-04/.server-token-verified"
# The 2026-08-29 shape: at 400 columns the renderer emits the token as cursor-positioned,
# styled segments — a raw-bytes grep saw no token at all right after "token created
# successfully". Stripped and joined, it is whole.
out="$(FAKE_TOKEN_FULL=1 FAKE_TOKEN_SPLIT=1 claude-accounts mint acct-04 2>&1 </dev/null)"
rc=$?
[ "$rc" = "0" ] && t_ok "a token the renderer split into positioned segments is captured" \
  || t_fail "split token rc" "rc=$rc: $(printf '%s' "$out" | tail -c 200)"
case "$(tr -d '[:space:]' < "$ACC/acct-04/server.token")" in
  sk-ant-oat01-WWW*TAILOK) t_ok "the split token was joined correctly" ;;
  *) t_fail "split token" "unexpected content" ;;
esac
[ -f "$ACC/acct-04/.server-token-verified" ] && t_ok "the joined token was proven by a real call" \
  || t_fail "split token proof" "marker missing"
printf '%s' "$orig" > "$ACC/acct-04/server.token"; rm -f "$ACC/acct-04/.server-token-verified"
# The token painted OUT OF ORDER with absolute cursor moves — the shape that made three
# real mints fail as "no token captured" right after "token created successfully".
out="$(FAKE_TOKEN_CURSOR=1 claude-accounts mint acct-04 2>&1 </dev/null)"
rc=$?
[ "$rc" = "0" ] && t_ok "a cursor-painted token is read off the rendered screen" \
  || t_fail "cursor-painted mint rc" "rc=$rc: $(printf '%s' "$out" | tail -c 220)"
case "$(tr -d '[:space:]' < "$ACC/acct-04/server.token")" in
  sk-ant-oat01-WWW*TAILOK) [ "$(tr -d '[:space:]' < "$ACC/acct-04/server.token" | wc -c | tr -d ' ')" = "108" ] \
    && t_ok "the rendered token is complete and in order" || t_fail "rendered token" "wrong length" ;;
  *) t_fail "rendered token" "wrong content — escape-stripping order bug" ;;
esac
printf '%s' "$orig" > "$ACC/acct-04/server.token"; rm -f "$ACC/acct-04/.server-token-verified"
# The renderer itself, on the exact byte pattern from the field.
printf ' sk-ant-\033[10Gat01-%s\033[9Go\n' "$(printf '%95s' '' | tr ' ' Z)" > "$WORK/painted.raw"
n="$(python3 "$REPO_DIR/lib/ceremony.py" extract "$WORK/painted.raw" | wc -c | tr -d ' ')"
[ "$n" = "108" ] && t_ok "ceremony.py renders a cursor-painted token whole" \
  || t_fail "ceremony.py extract" "got $n characters, expected 108"
# ...and the debrief reads as prose, not as words jammed together by the stripping.
printf ' Store\033[8Gthis\033[13Gtoken\033[19Gsecurely.\n' > "$WORK/prose.raw"
out="$(python3 "$REPO_DIR/lib/ceremony.py" debrief "$WORK/prose.raw" "$WORK/prose.out")"
check "the debrief renders readable words" "Store this token securely." "$out"

# A browser session on a Console (API-billing) org: the client mints an API KEY. Not a
# subscription token — refused, with the cause named and the raw capture kept.
before_raw="$(ls "$ACC"/tmp/mint-failed.*.raw 2>/dev/null | wc -l | tr -d ' ')"
out="$(FAKE_TOKEN_APIKEY=1 claude-accounts mint acct-04 2>&1 </dev/null)"
rc=$?
[ "$rc" != "0" ] && t_ok "an API key minted by a Console session is refused" || t_fail "apikey rc" "rc=0"
check "the API-key refusal names the cause" "API KEY" "$out"
check "the API-key refusal points at the org" "Console" "$out"
case "$out" in *sk-ant-api03-K*) t_fail "the API key never reaches the operator's screen" "leaked" ;; *) t_ok "the API key never reaches the operator's screen" ;; esac
[ "$(cat "$ACC/acct-04/server.token")" = "$orig" ] && t_ok "an API key is never saved as the token" \
  || t_fail "apikey save" "server.token was overwritten"
[ "$(ls "$ACC"/tmp/mint-failed.*.raw 2>/dev/null | wc -l | tr -d ' ')" -gt "$before_raw" ] \
  && t_ok "the raw capture is kept for a closer look" || t_fail "raw capture" "no .raw kept"
[ "$(python3 -c 'import os, sys; print(oct(os.stat(sys.argv[1]).st_mode & 0o777))' "$(ls -t "$ACC"/tmp/mint-failed.*.raw | head -1)")" = "0o600" ] \
  && t_ok "the raw capture is private" || t_fail "raw capture mode" "not 0600"
# A 79-character FRAGMENT that really is all there is (a paste from a narrow terminal)
# with a probe that cannot decide: refused, and it says why.
out="$(printf 'sk-ant-oat01-%s' "$(printf '%66s' '' | tr ' ' W)" | FAKE_PROBE_FLAKY=1 claude-accounts mint acct-04 --paste 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "a bare fragment is refused even when the probe is inconclusive" \
  || t_fail "fragment+inconclusive rc" "rc=0"
check "the fragment refusal names the truncation" "79 characters" "$out"
[ "$(cat "$ACC/acct-04/server.token")" = "$orig" ] && t_ok "an unproven fragment saves nothing" \
  || t_fail "unproven fragment" "server.token was overwritten"
# …while a COMPLETE token the probe cannot reach right now is saved as UNVERIFIED — the
# shim proves it on first use — rather than blocking the operator on a busy API.
out="$(FAKE_TOKEN_FULL=1 FAKE_PROBE_FLAKY=1 claude-accounts mint acct-04 2>&1 </dev/null)"
rc=$?
[ "$rc" = "0" ] && t_ok "a complete token survives an inconclusive probe" || t_fail "complete+inconclusive rc" "rc=$rc: $(printf '%s' "$out" | tail -c 200)"
check "the inconclusive save says so" "saved as UNVERIFIED" "$out"
[ "$(tr -d '[:space:]' < "$ACC/acct-04/server.token" | wc -c | tr -d ' ')" = "108" ] \
  && t_ok "the complete token was saved" || t_fail "complete token save" "wrong length"
[ ! -f "$ACC/acct-04/.server-token-verified" ] && t_ok "an unproven save records no proof" \
  || t_fail "unproven proof marker" "marker present"
printf '%s' "$orig" > "$ACC/acct-04/server.token"
# The client ended the ceremony without a token and said why: that sentence must
# reach the operator (the panel shows the mint's own error line), and the redacted
# transcript must be kept for a closer look — "no token captured" alone left an
# operator with nothing to act on (2026-08-29).
out="$(FAKE_TOKEN_FAIL=1 FAKE_TOKEN_FAIL_MSG="Your account is on hold. You can close this window." claude-accounts mint acct-04 2>&1 </dev/null)"
rc=$?
[ "$rc" != "0" ] && t_ok "a ceremony that ends without a token fails the mint" || t_fail "no-token mint rc" "rc=0"
check "the mint error carries the client's last words" "the client said: Your account is on hold" "$out"
check "the mint error names the kept transcript" "transcript: $ACC/tmp/mint-failed." "$out"
tr="$(printf '%s' "$out" | sed -n 's/.*transcript: \([^)]*\)).*/\1/p' | head -1)"
[ -n "$tr" ] && [ -s "$tr" ] && t_ok "the redacted transcript exists" || t_fail "transcript file" "missing: '$tr'"
grep -q 'Your account is on hold' "$tr" 2>/dev/null && t_ok "the transcript holds the client's words" \
  || t_fail "transcript content" "message missing"
# (python, not stat: GNU stat reads -f as "file system" and answers something else)
[ "$(python3 -c 'import os, sys; print(oct(os.stat(sys.argv[1]).st_mode & 0o777))' "$tr")" = "0o600" ] \
  && t_ok "the transcript is private" || t_fail "transcript mode" "not 0600"
[ "$(cat "$ACC/acct-04/server.token")" = "$orig" ] && t_ok "a ceremony without a token saves nothing" \
  || t_fail "no-token save" "server.token was overwritten"
# A pasted token gets the same proof: a revoked one is refused, not saved.
# (A complete-length token, so the verdict is the rejection itself and not the
# length rule that catches wrapped fragments first.)
out="$(printf 'sk-ant-oat01-REVOKED%s' "$(printf '%88s' '' | tr ' ' R)" | claude-accounts mint acct-04 --paste 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "mint --paste refuses a token Claude rejects" || t_fail "paste rejected rc" "rc=0"
check "the paste refusal says Claude rejected it" "Claude rejected the captured token" "$out"
[ "$(cat "$ACC/acct-04/server.token")" = "$orig" ] && t_ok "a rejected paste saves nothing" \
  || t_fail "rejected paste" "server.token was overwritten"
# A SHORT rejected paste blames the paste — not a ceremony terminal this command
# never opened.
out="$(printf 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' | claude-accounts mint acct-04 --paste 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "a short rejected paste is refused" || t_fail "short paste rc" "rc=0"
check "the short-paste refusal blames the paste" "cut before it reached the clipboard" "$out"
case "$out" in
  *"sign-in terminal wrapped it"*) t_fail "short paste must not blame the ceremony terminal" "wrong provenance" ;;
  *) t_ok "short paste must not blame the ceremony terminal" ;;
esac
[ "$(cat "$ACC/acct-04/server.token")" = "$orig" ] && t_ok "a short rejected paste saves nothing" \
  || t_fail "short paste" "server.token was overwritten"

# ---- 15c1b. the ceremony widens an unsized pty, so the whole token is captured ------
# The panel drives the ceremony over a pty it never sized (0x0 -> the TUI renders 80
# columns wide). Run the mint under exactly such a pty: the fake wraps its token
# whenever the terminal is narrower than the token, so only a widened terminal yields
# all 108 characters — and the capture must then pass the inference probe.
cat > "$WORK/pty-run.py" <<'EOF'
import os, pty, select, sys
pid, fd = pty.fork()          # a fresh pty: 0 rows, 0 columns, like the panel's
if pid == 0:
    os.execvp(sys.argv[1], sys.argv[1:])
buf = b''
while True:
    try:
        ready, _, _ = select.select([fd], [], [], 60)
        if not ready:
            break
        chunk = os.read(fd, 4096)
    except OSError:
        break
    if not chunk:
        break
    buf += chunk
_, status = os.waitpid(pid, 0)
sys.stdout.write(buf.decode('utf-8', 'ignore'))
sys.exit(os.WEXITSTATUS(status) if os.WIFEXITED(status) else 1)
EOF
size="$(python3 "$WORK/pty-run.py" stty size | tr -d '\r' | tail -1)"
[ "$size" = "0 0" ] && t_ok "the test pty really is unsized (the panel's shape)" \
  || t_fail "test pty size" "expected '0 0', got '$size'"
if command -v script >/dev/null 2>&1; then
  out="$(FAKE_TOKEN_FULL=1 python3 "$WORK/pty-run.py" claude-accounts mint acct-04 2>&1)"
  rc=$?
  [ "$rc" = "0" ] && t_ok "mint under an unsized pty succeeds" \
    || t_fail "unsized-pty mint rc" "rc=$rc: $(printf '%s' "$out" | tail -c 300)"
  n="$(tr -d '[:space:]' < "$ACC/acct-04/server.token" | wc -c | tr -d ' ')"
  [ "$n" = "108" ] && t_ok "the unsized pty is widened: all 108 characters captured" \
    || t_fail "unsized-pty capture" "saved $n characters"
  check "the widened-pty mint verifies its token" "Token verified by a real inference" "$out"
  case "$(tr -d '[:space:]' < "$ACC/acct-04/server.token")" in
    *TAILOK) t_ok "the saved token is the complete one" ;;
    *) t_fail "saved token" "tail missing" ;;
  esac
  [ -f "$ACC/acct-04/.server-token-verified" ] && t_ok "the widened-pty mint records its proof" \
    || t_fail "widened-pty proof" "marker missing"
else
  printf 'skip unsized-pty mint (no script(1) here)\n'
fi
claude-accounts remove acct-04 --yes >/dev/null 2>&1

# ---- 15c0. add with NO email: derives it from the verified sign-in -------------------
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=derived@test claude-accounts add 2>&1)"
check "add without email registers the signed-in address" "Registered acct-04 for derived@test" "$out"
claude-accounts list 2>&1 | grep -q "derived@test" && t_ok "email-less add lands in the manifest" \
  || t_fail "email-less add" "derived@test not registered"
claude-accounts remove acct-04 --yes >/dev/null 2>&1
# add with no email, but the signed-in email is already registered => refuse + clean up
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=a@test claude-accounts add 2>&1)"
rc=$?
check "email-less add skips a duplicate signed-in email" "a@test is already added as acct-01 — skipping" "$out"
[ "$rc" = "0" ] && t_ok "email-less duplicate skip exits 0" || t_fail "email-less dup rc" "rc=$rc"
[ ! -d "$ACC/acct-04" ] && t_ok "email-less duplicate cleaned up" || t_fail "email-less dup cleanup" "dir left"
# add with no email but identity can't be read back => refuse (can't label the account)
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_AUTH_FAIL=1 claude-accounts add 2>&1)"
rc=$?
check "email-less add needs a readable identity" "identity could not be read back" "$out"
[ ! -d "$ACC/acct-04" ] && t_ok "unverifiable email-less add cleaned up" || t_fail "unverifiable cleanup" "dir left"

# ---- 15c2. --tui is accepted as a no-op alias (full login is the default now) --------
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=tui@test claude-accounts add tui@test --tui 2>&1)"
check "add --tui still works (alias for default login)" "Registered acct-04 for tui@test" "$out"
[ -f "$ACC/acct-04/.credentials.json" ] && t_ok "--tui writes creds like the default" || t_fail "tui creds" "missing"
claude-accounts remove acct-04 --yes >/dev/null 2>&1

# ---- 15d. aborted login leaves zero traces ------------------------------------------
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_LOGIN_FAIL=1 claude-accounts add ghost@test 2>&1)"
rc=$?
check "aborted login detected" "login failed or aborted" "$out"
[ "$rc" != "0" ] && t_ok "aborted add exits nonzero" || t_fail "aborted add rc" "rc=0"
[ ! -d "$ACC/acct-04" ] && t_ok "aborted add cleaned up its dir" || t_fail "aborted add cleanup" "dir left behind"
claude-accounts list 2>&1 | grep -q ghost@test && t_fail "aborted add not in manifest" "ghost@test registered" || t_ok "aborted add not in manifest"
# aborted --token path too
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_TOKEN_FAIL=1 claude-accounts add ghost2@test --token 2>&1)"
rc=$?
check "aborted --token add detected" "sign-in failed or aborted" "$out"
[ ! -d "$ACC/acct-04" ] && t_ok "aborted --token add cleaned up" || t_fail "aborted token cleanup" "dir left"

# ---- 15e. sign-in as an already-registered email is rejected + cleaned ---------------
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=a@test claude-accounts add brand@test 2>&1)"
rc=$?
check "wrong-account sign-in skips (already added)" "a@test is already added as acct-01 — skipping" "$out"
[ "$rc" = "0" ] && t_ok "wrong-account skip exits 0" || t_fail "wrong-account rc" "rc=$rc"
[ ! -d "$ACC/acct-04" ] && t_ok "wrong-account sign-in cleaned up" || t_fail "wrong-account cleanup" "dir left behind"

# ---- 15f. login command completes auth for an existing auth-less account -------------
claude-accounts import pending@test --id acct-08 --no-sync >/dev/null 2>&1
# A parked (dead) token beside the account: a LOGIN-only ceremony must not lift that
# park — it proves the login, not the token.
printf 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' > "$ACC/acct-08/server.token"
printf '%s\nreason=setup-token-invalid marked_at=x detail=portable OAuth token rejected\n' "$now" > "$ACC/acct-08/.expired"
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=pending@test claude-accounts login acct-08 2>&1)"
check "login completes existing account (full login)" "acct-08 login saved" "$out"
[ -f "$ACC/acct-08/.credentials.json" ] && t_ok "login writes .credentials.json" || t_fail "login creds" "missing"
[ -f "$ACC/acct-08/.expired" ] && t_ok "a login-only ceremony keeps the token park" \
  || t_fail "login keeps token park" "marker removed"
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=other@test claude-accounts login acct-08 2>&1)"
rc=$?
check "login email mismatch refused" "nothing saved" "$out"
[ "$rc" != "0" ] && t_ok "mismatched login exits nonzero" || t_fail "mismatched login rc" "rc=0"
# login --token writes a portable token for the same account
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=pending@test claude-accounts login acct-08 --token 2>&1)"
check "login --token saves a portable token" "acct-08 token saved" "$out"
[ -s "$ACC/acct-08/server.token" ] && t_ok "login --token writes server.token" || t_fail "login token" "missing"
[ ! -f "$ACC/acct-08/.expired" ] && t_ok "a new token lifts the token park" || t_fail "token lifts park" "marker still present"
claude-accounts remove acct-08 --yes >/dev/null 2>&1

# ---- 15f2. expired: the re-login worklist, and relogin fixes it ----------------------
# `expired` must agree with the shim exactly: what it lists is what selection skips.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
out="$(claude-accounts expired 2>&1)"
rc=$?
check "expired lists the dead account" "acct-01" "$out"
check "expired explains why" "refresh token expired" "$out"
check "expired prints the fix" "claude-accounts relogin acct-01" "$out"
[ "$rc" = "1" ] && t_ok "expired exits 1 when a login needs a human" || t_fail "expired rc" "rc=$rc"
out="$(claude-accounts expired --quiet 2>&1)"
[ "$out" = "acct-01" ] && t_ok "expired --quiet prints bare ids" || t_fail "expired --quiet" "got: $out"
out="$(claude-accounts list 2>&1)"
check "list flags the dead login" "EXPIRED-LOGIN" "$out"
out="$(claude-accounts status 2>&1)"
check "status marks it unselectable" "LOGIN EXPIRED" "$out"
# relogin with no arguments targets exactly that worklist
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=a@test claude-accounts relogin --yes 2>&1)"
rc=$?
check "relogin re-authenticates the expired account" "acct-01 login saved" "$out"
check "relogin reports what it did" "re-authenticated 1 of 1" "$out"
[ "$rc" = "0" ] && t_ok "relogin exits 0 when every account recovered" || t_fail "relogin rc" "rc=$rc"
out="$(claude-accounts expired 2>&1)"
rc=$?
check "expired is clean after relogin" "can authenticate" "$out"
[ "$rc" = "0" ] && t_ok "expired exits 0 on a healthy pool" || t_fail "expired rc (healthy)" "rc=$rc"
out="$(claude 2>&1)"
case "$out" in *CFG=acct-0*) t_ok "re-authenticated account is selectable again" ;;
  *) t_fail "post-relogin selection" "got: $out" ;; esac
# a stale .expired marker must not survive a successful login
printf '%s\nreason=auth-error detail=test\n' "$now" > "$ACC/acct-01/.expired"
touch -t 202001010101 "$ACC/acct-01/.credentials.json"
CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=a@test claude-accounts relogin acct-01 --yes >/dev/null 2>&1
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "login clears the dead-auth marker" \
  || t_fail "login marker clear" ".expired survived a successful login"
# explicit ids are validated
out="$(claude-accounts relogin acct-99 --yes 2>&1)"
rc=$?
check "relogin rejects an unknown account" "unknown account" "$out"
[ "$rc" != "0" ] && t_ok "unknown relogin target exits nonzero" || t_fail "relogin unknown rc" "rc=0"

# ---- 15f3. a re-login that did NOT work must not be reported as fixed -----------------
# The target already HAS a (dead) .credentials.json, so "the file exists" proves nothing:
# an aborted sign-in would otherwise clear the dead-auth marker and hand the account back.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
printf '%s\nreason=refresh-token-expired detail=test\n' "$now" > "$ACC/acct-01/.expired"
touch -t 202001010101 "$ACC/acct-01/.credentials.json"
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_LOGIN_FAIL=1 FAKE_EMAIL=a@test claude-accounts relogin acct-01 --yes 2>&1)"
rc=$?
check "aborted re-login is reported as a failure" "login failed or aborted" "$out"
[ "$rc" != "0" ] && t_ok "aborted relogin exits nonzero" || t_fail "aborted relogin rc" "rc=0"
[ -f "$ACC/acct-01/.expired" ] && t_ok "aborted re-login leaves the account parked" \
  || t_fail "aborted relogin" "the dead-auth marker was cleared by a failed sign-in"
out="$(claude-accounts expired --quiet 2>&1)"
check "the account is still on the worklist after a failed re-login" "acct-01" "$out"
# a real re-login then fixes it
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=a@test claude-accounts relogin acct-01 --yes 2>&1)"
check "a working re-login is reported as fixed" "re-authenticated 1 of 1" "$out"
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "a working re-login clears the park" \
  || t_fail "relogin clear" "marker survived a successful sign-in"

# ---- 15f4. audit robustness: bad data must never read as a healthy pool ---------------
# a non-numeric expiry must not crash the audit (it would blank the worklist silently)
cp "$ACC/acct-01/.credentials.json" "$WORK/creds.bak"
printf '{"claudeAiOauth":{"accessToken":"a","refreshToken":"r","expiresAt":"soon","refreshTokenExpiresAt":[]}}' > "$ACC/acct-01/.credentials.json"
out="$(claude-accounts expired 2>&1)"
rc=$?
case "$out" in *Traceback*) t_fail "audit survives a weird credential" "python traceback" ;;
  *) t_ok "a non-numeric expiry does not crash the audit" ;; esac
out="$(claude-accounts list 2>&1)"
check "list survives a weird credential" "acct-01" "$out"
# a truncated (mid-write) credential is judged the SAME way the shim judges it
printf '{"claudeAiOauth":{"accessToken":"live","refreshToken":"rt","expiresAt":9999999999999,' > "$ACC/acct-01/.credentials.json"
out="$(claude-accounts expired --quiet 2>&1)"
case "$out" in *acct-01*) t_fail "audit agrees with the shim on a truncated credential" \
    "audit calls it dead while the shim still selects it" ;;
  *) t_ok "a truncated credential is judged like the shim judges it" ;; esac
cp "$WORK/creds.bak" "$ACC/acct-01/.credentials.json"

# ---- 15g. parallel adds (different terminals) get distinct ids, no lock-busy error ----
( CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=par1@test claude-accounts add >"$WORK/p1.out" 2>&1 ) &
pA=$!
( CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=par2@test claude-accounts add >"$WORK/p2.out" 2>&1 ) &
pB=$!
wait "$pA"; wait "$pB"
both="$(cat "$WORK/p1.out" "$WORK/p2.out" 2>/dev/null)"
printf '%s' "$both" | grep -q "in progress" \
  && t_fail "parallel add: no lock-busy error" "got the 'another add in progress' error" \
  || t_ok "parallel add: neither reports 'another add in progress'"
regA="$(claude-accounts list 2>&1 | grep par1@test | awk '{print $1}')"
regB="$(claude-accounts list 2>&1 | grep par2@test | awk '{print $1}')"
{ [ -n "$regA" ] && [ -n "$regB" ] && [ "$regA" != "$regB" ]; } \
  && t_ok "parallel add: both registered on distinct ids ($regA, $regB)" \
  || t_fail "parallel add ids" "regA=$regA regB=$regB"
# and no duplicate/second entry crept in for either email
{ [ "$(claude-accounts list 2>&1 | grep -c par1@test)" = "1" ] && [ "$(claude-accounts list 2>&1 | grep -c par2@test)" = "1" ]; } \
  && t_ok "parallel add: exactly one entry per email" || t_fail "parallel add dup" "duplicate created"
[ -n "$regA" ] && claude-accounts remove "$regA" --yes >/dev/null 2>&1
[ -n "$regB" ] && claude-accounts remove "$regB" --yes >/dev/null 2>&1

# ---- 15h. two parallel adds signing into the SAME email: exactly one wins ------------
( CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=same@test claude-accounts add >"$WORK/s1.out" 2>&1 ) &
sA=$!
( CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_EMAIL=same@test claude-accounts add >"$WORK/s2.out" 2>&1 ) &
sB=$!
wait "$sA"; wait "$sB"
n="$(claude-accounts list 2>&1 | grep -c same@test)"
[ "$n" = "1" ] && t_ok "same-email parallel add: exactly one registered (other skipped)" \
  || t_fail "same-email parallel add" "count=$n (expected 1)"
cat "$WORK/s1.out" "$WORK/s2.out" 2>/dev/null | grep -q "already added as\|skipping" \
  && t_ok "same-email parallel add: loser skipped gracefully" || t_fail "same-email skip msg" "no skip message"
regS="$(claude-accounts list 2>&1 | grep same@test | awk '{print $1}')"
[ -n "$regS" ] && claude-accounts remove "$regS" --yes >/dev/null 2>&1

# ---- 15i. dedupe removes accounts registered twice (keeps one per email) --------------
out="$(claude-accounts dedupe 2>&1)"
check "dedupe on a clean pool is a no-op" "No duplicate accounts" "$out"
# manufacture a duplicate directly in the manifest (a pre-fix leftover) + a dir for it
claude-accounts import twin@test --id acct-06 --creds "$WORK/import-creds.json" --mode copy --no-sync >/dev/null 2>&1
python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['accounts'].append({'id': 'acct-07', 'email': 'twin@test', 'home': 'mac'})
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
mkdir -p "$ACC/acct-07"
out="$(claude-accounts list 2>&1)"
check "list warns about a duplicate email" "twin@test is registered 2x" "$out"
out="$(claude-accounts dedupe --yes 2>&1)"
check "dedupe reports removal" "Removed 1 duplicate" "$out"
[ "$(claude-accounts list 2>&1 | grep -c twin@test)" = "1" ] && t_ok "dedupe keeps exactly one per email" || t_fail "dedupe count" "not 1"
# it kept the authed one (acct-06 has creds), removed the bare acct-07
claude-accounts list 2>&1 | grep -q "acct-06.*twin@test" && t_ok "dedupe kept the authenticated account" || t_fail "dedupe keep-authed" "kept the wrong one"
claude-accounts remove acct-06 --yes >/dev/null 2>&1

# ---- 16. CLI: limits marking via fixture endpoint ------------------------------
cat > "$WORK/usage-high.json" <<'EOF'
{"limits":[
  {"kind":"session","percent":29,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","percent":55,"resets_at":"2099-01-02T00:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","percent":93,"resets_at":"2099-01-03T00:00:00+00:00","scope":{"model":{"display_name":"Fable"}}}
]}
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-high.json" claude-accounts limits 2>&1)"
check "limits marks Fable bucket >=90%" "LIMITED weekly_scoped:Fable at 93%" "$out"
[ -f "$ACC/acct-01/.limited" ] && t_ok ".limited written by limits" || t_fail ".limited written" "missing"
grep -q "weekly_scoped:Fable" "$ACC/acct-01/limits.json" \
  && t_ok "limits.json has Fable bucket" || t_fail "limits.json Fable bucket" "missing"
out="$(CLAUDE_ACCOUNT='' claude 2>&1)"  # pool should now avoid marked accounts (all marked -> fallback fine)
cat > "$WORK/usage-low.json" <<'EOF'
{"limits":[
  {"kind":"session","percent":10,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","percent":45,"resets_at":"2099-01-03T00:00:00+00:00","scope":{"model":{"display_name":"Fable"}}}
]}
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
check "limits clears marker under threshold" "marker cleared" "$out"
[ ! -f "$ACC/acct-01/.limited" ] && t_ok "marker removed after clear" || t_fail "marker removed" "still present"

# ---- 16-weekly. limits classifies session vs weekly and records both signals --------
cat > "$WORK/usage-3bucket.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":88,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":40,"resets_at":"2099-01-05T00:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","group":"weekly","percent":55,"resets_at":"2099-01-05T00:00:00+00:00","scope":{"model":{"display_name":"Fable"}}}
]}
EOF
CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-3bucket.json" claude-accounts limits --quiet
python3 - "$ACC/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d["session_percent"] == 88, d
assert d["weekly_percent"] == 55, d          # max of the two weekly buckets, not session
assert d["max_percent"] == 88, d             # peak of ALL buckets (drives exclusion)
groups = {b["name"]: b["group"] for b in d["buckets"]}
assert groups["session"] == "session", groups
assert groups["weekly_all"] == "weekly", groups
assert groups["weekly_scoped:Fable"] == "weekly", groups
EOF
[ $? -eq 0 ] && t_ok "limits records weekly_percent(55) + session_percent(88) with correct groups" \
  || t_fail "weekly/session classification" "see limits.json"
# The two numbers must stay SEPARATE on disk. There is no combined score any more
# (2026-09-03): the shim GATES on session_percent and BANDS on weekly_percent, so a
# session bucket at 88 must never be folded into — or allowed to poison — the weekly
# reading the band ranks on.
sc="$(python3 -c "import json;d=json.load(open('$ACC/acct-01/limits.json'));print('%s/%s' % (d['weekly_percent'], d['session_percent']))")"
[ "$sc" = "55/88" ] && t_ok "weekly and session are recorded as separate ranking inputs (55 weekly / 88 session)" \
  || t_fail "weekly/session ranking inputs" "got $sc"
rm -f "$ACC/acct-01/limits.json" "$ACC/acct-01/.limited"

# ---- 16-nodata. a 0% bucket with NO reset window is NO DATA, not an empty account ----
# 2026-09-04, my-mini: for acct-13/acct-14 the usage endpoint answered EVERY bucket
# `percent: 0, resets_at: null` while Claude Code was being rejected on those same two
# accounts with "You've hit your weekly limit · resets Sep 8 at 1am" (epoch 1788818400).
# The writer recorded the zeros verbatim, so two provably exhausted accounts became the
# leaders of the weekly band and absorbed 31 of the last ~60 picks — and the shim's
# telemetry-based recovery then deleted their truthful client:seven_day markers about six
# times a day each. A truthful bucket ALWAYS carries the window it resets in, so 0% with
# no window is no data. These run in a pool of their own: one no-data account against one
# honest one makes "which account ranked" unambiguous.
ND="$WORK/nodata-pool"
mkdir -p "$ND/acct-01" "$ND/acct-02" "$ND/tmp"
: > "$ND/.limits-kick"
cat > "$ND/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,"accounts":[
  {"id":"acct-01","email":"nd1@test","home":"mac","added_at":"2026-07-13T00:00:00Z"},
  {"id":"acct-02","email":"nd2@test","home":"mac","added_at":"2026-07-13T00:00:00Z"}]}
EOF
for i in 01 02; do
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-nd%s","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' \
    "$i" > "$ND/acct-$i/.credentials.json"
done
ndl() { # ndl <weekly> <session> <max> -> a truthful, in-window reading on stdout
  local t; t="$(date +%s)"
  printf '{"fetched_at":%s,"source":"oauth","weekly_percent":%s,"session_percent":%s,"max_percent":%s,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$t" "$1" "$2" "$3" "$((t + 259200))"
}
ndlimits() { # ndlimits <fixture> [extra args] -> a real refresh over the whole ND pool
  local f="$1"; shift
  CLAUDE_ACCOUNTS_ROOT="$ND" CLAUDE_MULTIACC_USAGE_URL="file://$f" \
    claude-accounts limits --force "$@" 2>&1
}

# the incident payload, byte-for-byte in shape: every bucket 0%, every window null
cat > "$WORK/usage-allzero.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":0,"resets_at":null,"scope":null},
  {"kind":"weekly_all","group":"weekly","percent":0,"resets_at":null,"scope":null},
  {"kind":"weekly_scoped","group":"weekly","percent":0,"resets_at":null,"scope":{"model":{"display_name":"Fable"}}}
]}
EOF
out="$(ndlimits "$WORK/usage-allzero.json")"
check "an all-zero/no-window payload is reported as no usable telemetry" \
  "no usable telemetry (account ranks as unknown, not as empty)" "$out"
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d.get('no_data') is True, d
# A MISSING field is what makes the shim's fresh_field/cutoff_field reads fail, which
# is what makes the account unknown to both cuts. Writing 0 here is the bug.
for k in ('max_percent', 'weekly_percent', 'session_percent', 'weekly_resets_epoch'):
    assert k not in d, (k, d)
assert len(d['buckets']) == 3, d          # the raw buckets stay, for diagnostics
assert d['fetched_at'] > 0 and d['source'], d
EOF
[ $? -eq 0 ] && t_ok "a no-data pass records no_data and NONE of the three percent signals" \
  || t_fail "no_data document" "see $ND/acct-01/limits.json"

# ONE uninformative bucket beside real ones changes nothing (the live acct-16 shape:
# weekly_scoped:Fable 0/null next to a real session and a real weekly_all).
cat > "$WORK/usage-mixed-nodata.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":12,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":40,"resets_at":"2099-01-05T00:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","group":"weekly","percent":0,"resets_at":null,"scope":{"model":{"display_name":"Fable"}}}
]}
EOF
ndlimits "$WORK/usage-mixed-nodata.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys, time, calendar
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['session_percent'], d['weekly_percent'], d['max_percent']) == (12, 40, 40), d
want = calendar.timegm(time.strptime("2099-01-05T00:00:00", "%Y-%m-%dT%H:%M:%S"))
assert d['weekly_resets_epoch'] == want, d
assert len(d['buckets']) == 3, d          # the quiet bucket is still recorded
EOF
[ $? -eq 0 ] && t_ok "one uninformative bucket beside real ones leaves the ranking untouched (12/40)" \
  || t_fail "mixed no-data payload" "see $ND/acct-01/limits.json"

# 0% WITH a real window is informative: a genuinely fresh account must still rank empty.
cat > "$WORK/usage-zero-real-windows.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":0,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":0,"resets_at":"2099-01-05T00:00:00+00:00","scope":null}
]}
EOF
ndlimits "$WORK/usage-zero-real-windows.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['session_percent'], d['weekly_percent'], d['max_percent']) == (0, 0, 0), d
EOF
[ $? -eq 0 ] && t_ok "0% WITH real reset windows still records a real, empty 0% reading" \
  || t_fail "zero-with-windows payload" "see $ND/acct-01/limits.json"

# ...and the horizon that 0% is valid until comes from the bucket that reported one. A
# null-window sibling's synthesized now+1h used to win the min() and shorten it.
cat > "$WORK/usage-zero-mixed-window.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":0,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":0,"resets_at":"2099-01-05T00:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","group":"weekly","percent":0,"resets_at":null,"scope":{"model":{"display_name":"Fable"}}}
]}
EOF
ndlimits "$WORK/usage-zero-mixed-window.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys, time, calendar
d = json.load(open(sys.argv[1]))
want = calendar.timegm(time.strptime("2099-01-05T00:00:00", "%Y-%m-%dT%H:%M:%S"))
assert d['weekly_percent'] == 0 and d['weekly_resets_epoch'] == want, d
EOF
[ $? -eq 0 ] && t_ok "a window-less bucket cannot shorten the horizon a real 0% reading is valid for" \
  || t_fail "no-data horizon" "see $ND/acct-01/limits.json"

# ---- 16-nodata-rank. an unknown account never leads the weekly band ------------------
# The whole point of the rule: 0/0 ranked BETTER than a truthful 45% account, so every
# pick went to the exhausted one. Unknown must lose to any account with a real reading.
ndlimits "$WORK/usage-allzero.json" --quiet >/dev/null
ndl 45 10 45 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND"/acct-0*/.limited
: > "$ND/selection.log"
nd_hits=0
for _ in $(seq 1 10); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-01*) nd_hits=$((nd_hits+1)) ;; esac
done
[ "$nd_hits" = "0" ] \
  && t_ok "a no-data account never outranks an account with real telemetry (0 of 10 picks)" \
  || t_fail "no_data ranking" "the fake-zero account took $nd_hits of 10 picks"
grep -q "acct-02 weekly=45% session=10% band=30 band-count=1" "$ND/selection.log" \
  && t_ok "the pick logs the known account alone in the band" \
  || t_fail "no_data band" "selection.log: $(tail -1 "$ND/selection.log" 2>/dev/null)"
grep -q "acct-01 weekly=0%" "$ND/selection.log" \
  && t_fail "no_data band leader" "the fake-zero account was logged as a 0% pick" \
  || t_ok "the fake-zero account is never logged as the band leader"

# ---- 16-nodata-marker. a client-reported WEEKLY rejection outlives any telemetry -----
# The second half of the incident. Claude Code's own rejection wrote
# `bucket=client:seven_day percent=100 reason=client-rate-limit` with the server's reset
# (Sep 8); the next invocation read the fake 0%, called it newer first-hand evidence and
# deleted the marker. A seven-day window cannot fall from a server-proven 100% to under
# the threshold before it resets, so no reading may clear it — however fresh and however
# informative. Here acct-01's telemetry is a REAL 5%, so only the bucket rule can save it.
ndl 5 5 5 > "$ND/acct-01/limits.json"
ndl 45 10 45 > "$ND/acct-02/limits.json"
printf '%s\nbucket=client:seven_day percent=100 marked_at=2020-01-01T00:00:00Z reason=client-rate-limit\n' \
  "$(( $(date +%s) + 345600 ))" > "$ND/acct-01/.limited"
rm -f "$ND"/acct-0*/.client-limit-cleared "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
: > "$ND/selection.log"
w_hits=0
for _ in $(seq 1 6); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-01*) w_hits=$((w_hits+1)) ;; esac
done
{ [ -f "$ND/acct-01/.limited" ] && [ "$w_hits" = "0" ]; } \
  && t_ok "a client:seven_day marker survives fresh below-threshold telemetry" \
  || t_fail "weekly client marker" "marker=$([ -f "$ND/acct-01/.limited" ] && echo kept || echo DELETED) hits=$w_hits"
grep -q "client limit cleared by newer telemetry" "$ND/selection.log" \
  && t_fail "weekly client marker" "the shim logged a recovery for a weekly rejection" \
  || t_ok "no recovery event is logged for a weekly rejection"
[ ! -f "$ND/acct-01/.client-limit-cleared" ] \
  && t_ok "no recovery watermark is written for a weekly rejection" \
  || t_fail "weekly client marker" "a watermark was written"
# case-insensitive on the bucket name: seven_day_opus is weekly too
printf '%s\nbucket=client:Seven_Day_Opus percent=100 marked_at=2020-01-01T00:00:00Z reason=client-rate-limit\n' \
  "$(( $(date +%s) + 345600 ))" > "$ND/acct-01/.limited"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ -f "$ND/acct-01/.limited" ] && t_ok "a model-scoped weekly bucket (seven_day_opus) is weekly too" \
  || t_fail "weekly client marker" "seven_day_opus was cleared"

# ...but the 5h window self-heals within hours, so #22 (2026-09-03) still holds: a
# five_hour marker DOES clear once a below-threshold reading was fetched after it.
printf '%s\nbucket=client:five_hour percent=100 marked_at=2020-01-01T00:00:00Z reason=client-rate-limit\n' \
  "$(( $(date +%s) + 1800 ))" > "$ND/acct-01/.limited"
rm -f "$ND/acct-01/.client-limit-cleared"
: > "$ND/selection.log"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ ! -f "$ND/acct-01/.limited" ] \
  && t_ok "a client:five_hour marker still clears on newer below-threshold telemetry (#22)" \
  || t_fail "five_hour client marker" "the 2026-09-03 recovery stopped working"
[ -f "$ND/acct-01/.client-limit-cleared" ] \
  && t_ok "the five_hour recovery still records its watermark" \
  || t_fail "five_hour client marker" "watermark missing"
grep -q "acct-01 client limit cleared by newer telemetry (5%)" "$ND/selection.log" \
  && t_ok "the five_hour recovery still logs the reading it acted on" \
  || t_fail "five_hour client marker" "selection.log: $(tail -2 "$ND/selection.log" 2>/dev/null | tr '\n' ' ')"

# ---- 16-limit-reset-fleet. a confirmed limit reset lifts every OLDER park, fleet-wide --
# The writer that redeemed a reset deletes its own marker, but peers are pushed `.limited`
# files and never their deletion, and the panel re-writes its verdicts: so the reset
# travels in limits.json (reset_redeemed_at + reset_cleared) and the shim lifts any park
# written at or before it for a window it refilled — even a client:seven_day one, which
# no telemetry may lift. A park written AFTER the reset, or for a window the reset did
# not refill, stays exactly as it was.
lr_doc() { # lr_doc <redeemed_at epoch> <cleared csv> -> a post-reset limits.json (stale)
  printf '{"fetched_at":0,"source":"oauth","reset_redeemed_at":%s,"reset_cleared":"%s","buckets":[]}' "$1" "$2"
}
# The ND pool is shared with the blocks below: save what this block overwrites.
for lr_f in acct-01/limits.json acct-02/limits.json acct-01/.limited acct-01/.client-limit-cleared; do
  rm -f "$WORK/lr-save.${lr_f//\//_}"
  [ -f "$ND/$lr_f" ] && cp -p "$ND/$lr_f" "$WORK/lr-save.${lr_f//\//_}"
done
lr_now="$(date +%s)"
lr_at=$((lr_now - 600))
lr_before="$(date -u -r $((lr_at - 3600)) +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d "@$((lr_at - 3600))" +%Y-%m-%dT%H:%M:%SZ)"
lr_after="$(date -u -r $((lr_at + 60)) +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -d "@$((lr_at + 60))" +%Y-%m-%dT%H:%M:%SZ)"
lr_doc "$lr_at" "five_hour,seven_day,seven_day_overage_included" > "$ND/acct-01/limits.json"
ndl 45 10 45 > "$ND/acct-02/limits.json"
printf '%s\nbucket=client:seven_day percent=100 marked_at=%s reason=client-rate-limit\n' \
  "$((lr_now + 345600))" "$lr_before" > "$ND/acct-01/.limited"
rm -f "$ND"/acct-0*/.client-limit-cleared "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
: > "$ND/selection.log"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ ! -f "$ND/acct-01/.limited" ] \
  && t_ok "a client:seven_day park older than a confirmed limit reset is lifted" \
  || t_fail "limit reset lift" "marker kept: $(sed -n 2p "$ND/acct-01/.limited")"
grep -q "acct-01 marker lifted — written before a confirmed limit reset" "$ND/selection.log" \
  && t_ok "the lift is logged" || t_fail "limit reset lift" "selection.log: $(tail -2 "$ND/selection.log" | tr '\n' ' ')"
# the panel's own shapes: a stream weekly_all park, and a bucket-less panel:observed one
for lr_bucket in weekly_all panel:observed weekly_scoped:Fable session; do
  printf '%s\nbucket=%s percent=100 marked_at=%s reason=client-rate-limit source=stream\n' \
    "$((lr_now + 345600))" "$lr_bucket" "$lr_before" > "$ND/acct-01/.limited"
  CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
  [ ! -f "$ND/acct-01/.limited" ] \
    && t_ok "an older $lr_bucket park is lifted by the reset" \
    || t_fail "limit reset lift" "$lr_bucket kept"
done
printf '%s\nbucket=client:seven_day percent=100 marked_at=%s reason=client-rate-limit\n' \
  "$((lr_now + 345600))" "$lr_after" > "$ND/acct-01/.limited"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ -f "$ND/acct-01/.limited" ] \
  && t_ok "a park written AFTER the reset stands" || t_fail "limit reset lift" "a post-reset park was lifted"
printf '%s\nbucket=client:seven_day_opus percent=100 marked_at=%s reason=client-rate-limit\n' \
  "$((lr_now + 345600))" "$lr_before" > "$ND/acct-01/.limited"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ -f "$ND/acct-01/.limited" ] \
  && t_ok "a park for a window the reset did not refill stands" \
  || t_fail "limit reset lift" "seven_day_opus was lifted by a reset that did not clear it"
# an expired record (older than eight days) lifts nothing
lr_doc "$((lr_now - 9 * 86400))" "five_hour,seven_day" > "$ND/acct-01/limits.json"
printf '%s\nbucket=client:seven_day percent=100 marked_at=2020-01-01T00:00:00Z reason=client-rate-limit\n' \
  "$((lr_now + 345600))" > "$ND/acct-01/.limited"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ -f "$ND/acct-01/.limited" ] \
  && t_ok "an expired reset record lifts nothing" || t_fail "limit reset lift" "an expired record lifted a park"
# the report agrees with the shim: a superseded park is not `limited`
lr_doc "$lr_at" "five_hour,seven_day,seven_day_overage_included" > "$ND/acct-01/limits.json"
printf '%s\nbucket=weekly_all percent=95 marked_at=%s reason=client-rate-limit source=stream\n' \
  "$((lr_now + 345600))" "$lr_before" > "$ND/acct-01/.limited"
lr_json="$(CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list --json 2>/dev/null)"
printf '%s' "$lr_json" | python3 -c '
import json, sys
row = next(a for a in json.load(sys.stdin)["accounts"] if a["id"] == "acct-01")
assert row["limited"] is False and row["status"] != "limited", row
assert row["usage"]["reset_cleared"] == ["five_hour", "seven_day", "seven_day_overage_included"], row["usage"]
assert row["usage"]["reset_redeemed_at"].endswith("Z"), row["usage"]
' && t_ok "list --json reports a superseded park as not limited, with the reset record" \
  || t_fail "limit reset report" "$(printf '%s' "$lr_json" | head -c 400)"
lr_text="$(CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list 2>/dev/null | grep '^acct-01')"
case "$lr_text" in
  *LIMITED*) t_fail "limit reset report" "text list still says: $lr_text" ;;
  *) t_ok "the text list agrees: a superseded park is not LIMITED" ;;
esac
lr_status="$(CLAUDE_ACCOUNTS_ROOT="$ND" CLAUDE_MULTIACC_PATH_PROBE=0 claude-accounts status 2>/dev/null)"
check "status says the park was lifted by the reset" "lifted — written before a confirmed limit reset" "$lr_status"
# ...and the transcript scan cannot re-create a park from a rejection the reset answered,
# on a machine that never saw the source's local watermark (a peer): the record is enough.
lr_iso() { date -u -r "$1" +%Y-%m-%dT%H:%M:%S.000Z 2>/dev/null || date -u -d "@$1" +%Y-%m-%dT%H:%M:%S.000Z; }
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared "$ND"/acct-0*/.client-scan
lr_doc "$((lr_now - 60))" "five_hour,seven_day,seven_day_overage_included" > "$ND/acct-01/limits.json"
mkclientlimit "$ND/acct-01" "5d1c7a42-1f4e-4c55-9c3e-0d2f6a8b9e10" "$((lr_now + 3600))" "$(lr_iso $((lr_now - 300)))"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ ! -f "$ND/acct-01/.limited" ] \
  && t_ok "a rejection the reset answered cannot re-park the account from the transcript" \
  || t_fail "limit reset watermark" "the scan re-created: $(sed -n 2p "$ND/acct-01/.limited")"
rm -f "$ND"/acct-0*/.client-scan
mkclientlimit "$ND/acct-01" "5d1c7a42-1f4e-4c55-9c3e-0d2f6a8b9e10" "$((lr_now + 3600))" "$(lr_iso $((lr_now - 20)))"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
[ -f "$ND/acct-01/.limited" ] \
  && t_ok "a rejection AFTER the reset still parks the account" \
  || t_fail "limit reset watermark" "a post-reset rejection was ignored"
rm -rf "$ND/acct-01/projects" "$ND/acct-01/.sessions-index"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared "$ND"/acct-0*/.client-scan
for lr_f in acct-01/limits.json acct-02/limits.json acct-01/.limited acct-01/.client-limit-cleared; do
  rm -f "$ND/$lr_f"
  [ -f "$WORK/lr-save.${lr_f//\//_}" ] && cp -p "$WORK/lr-save.${lr_f//\//_}" "$ND/$lr_f"
done

# ---- 16-nodata-shorten. an offender pass must never SHORTEN a weekly client marker ---
# The writer's offenders branch used to overwrite `.limited` unconditionally: a session
# bucket crossing the threshold (+1h reset) replaced a client:seven_day marker four days
# out, and after that hour the provably exhausted account was back in the pool (codex
# review, 2026-09-04). The client's own reset reaches further and must win.
printf '%s\nbucket=client:seven_day percent=100 marked_at=2020-01-01T00:00:00Z reason=client-rate-limit\n' \
  "$(( $(date +%s) + 345600 ))" > "$ND/acct-01/.limited"
keep_reset_before="$(head -1 "$ND/acct-01/.limited")"
python3 - "$WORK/usage-shorten.json" <<'PJ'
import json, sys, datetime
soon = (datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=1)).isoformat()
json.dump({"limits": [
    {"kind": "session", "percent": 95, "resets_at": soon},
    {"kind": "seven_day", "percent": 0, "resets_at": None},
]}, open(sys.argv[1], 'w'))
PJ
CLAUDE_ACCOUNTS_ROOT="$ND" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-shorten.json" \
  claude-accounts limits --force --quiet >/dev/null 2>&1
{ [ -f "$ND/acct-01/.limited" ] && [ "$(head -1 "$ND/acct-01/.limited")" = "$keep_reset_before" ] \
  && grep -q 'reason=client-rate-limit' "$ND/acct-01/.limited"; } \
  && t_ok "an over-threshold session pass keeps the further-reaching weekly client marker" \
  || t_fail "marker shortened" "now: $(head -2 "$ND/acct-01/.limited" 2>/dev/null | tr '\n' ' ')"
# ...while a LATER reset may still extend the exclusion (more caution is allowed):
python3 - "$WORK/usage-extend.json" <<'PJ'
import json, sys, datetime
far = (datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=6)).isoformat()
json.dump({"limits": [
    {"kind": "seven_day", "percent": 95, "resets_at": far},
]}, open(sys.argv[1], 'w'))
PJ
CLAUDE_ACCOUNTS_ROOT="$ND" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-extend.json" \
  claude-accounts limits --force --quiet >/dev/null 2>&1
{ [ -f "$ND/acct-01/.limited" ] && [ "$(head -1 "$ND/acct-01/.limited")" -gt "$keep_reset_before" ]; } \
  && t_ok "a further-out offender may still extend the marker" \
  || t_fail "marker extend" "now: $(head -2 "$ND/acct-01/.limited" 2>/dev/null | tr '\n' ' ')"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared
# ...and a GARBLED client marker (a first line the shims' num_ok would refuse) must not
# be preserved by that guard: to the shims it is an active-forever park, so the writer
# replacing it with a valid offender marker is a repair, not a shortening.
printf '9999999999999999999\nbucket=client:seven_day reason=client-rate-limit\n' > "$ND/acct-01/.limited"
CLAUDE_ACCOUNTS_ROOT="$ND" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-shorten.json" \
  claude-accounts limits --force --quiet >/dev/null 2>&1
{ [ -f "$ND/acct-01/.limited" ] && grep -q 'reason=limits' "$ND/acct-01/.limited"; } \
  && t_ok "a garbled client marker is repaired by the offender write, not preserved" \
  || t_fail "garbled marker repair" "now: $(head -2 "$ND/acct-01/.limited" 2>/dev/null | tr '\n' ' ')"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared

# ---- 16-nodata-noclear. an uninformative reading cannot clear ANY marker -------------
# End to end, in the incident's own order: the fake-zero payload goes through the real
# writer, then a five_hour marker (the kind that IS allowed to clear) is planted on top.
# Pre-fix that pass wrote max_percent 0 and the very next invocation deleted the marker
# with "client limit cleared by newer telemetry (0%)". A reading with no percent at all
# reads as unknown, and unknown proves nothing.
ndlimits "$WORK/usage-allzero.json" --quiet >/dev/null
ndl 45 10 45 > "$ND/acct-02/limits.json"
printf '%s\nbucket=client:five_hour percent=100 marked_at=2020-01-01T00:00:00Z reason=client-rate-limit\n' \
  "$(( $(date +%s) + 1800 ))" > "$ND/acct-01/.limited"
rm -f "$ND/acct-01/.client-limit-cleared" "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
: > "$ND/selection.log"
for _ in 1 2 3; do CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1; done
[ -f "$ND/acct-01/.limited" ] \
  && t_ok "a limits.json with no percent fields cannot clear even a five_hour marker" \
  || t_fail "no_data marker clearing" "fake-zero telemetry unparked the account"
grep -q "client limit cleared" "$ND/selection.log" \
  && t_fail "no_data marker clearing" "a recovery was logged from a no-data reading" \
  || t_ok "no recovery is logged from a no-data reading"
[ ! -f "$ND/acct-01/.client-limit-cleared" ] \
  && t_ok "no recovery watermark is written from a no-data reading" \
  || t_fail "no_data marker clearing" "a watermark was written from a reading with no percent"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared

# ---- 16-nodata-writer. the LIMITS PASS obeys the same marker rule as the shim --------
# The shim's rule above is only half a fix. `claude-accounts limits` runs on a 15-minute
# schedule and deletes markers itself, and until 2026-09-04 it kept a client rejection
# only while it was newer than CLIENT_LIMIT_CONFIRM_DELAY (300s) — so five minutes after
# the shim refused to unpark acct-13, the scheduled pass deleted the same client:seven_day
# marker anyway, on a payload whose every bucket said `percent 0, resets_at null`. Two
# writers with two rules is one rule: the weaker one. This is the claude twin of the codex
# C13c block, and the pass is driven for real (fixture endpoint -> writer -> disk).
nd_mark() { # nd_mark <acct dir> <bucket> <reset-offset-seconds> <marked_at ISO>
  printf '%s\nbucket=%s percent=100 marked_at=%s reason=client-rate-limit\n' \
    "$(( $(date +%s) + $3 ))" "$2" "$4" > "$1/.limited"
}
nd_acct01_log() { printf '%s' "$1" | grep 'acct-01' | tr '\n' ' '; }
# A REAL, informative, below-threshold reading: the kind that IS allowed to clear a
# five-hour marker, and the one that must never clear a weekly one.
cat > "$WORK/usage-nd-low.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":5,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":5,"resets_at":"2099-01-05T00:00:00+00:00","scope":null}
]}
EOF

# (1) A pass that reported nothing proves nothing, so it clears nothing — whatever the
# marker says and however old it is. On origin/main this marker is 300s past its confirm
# delay and the pass deletes it with "marker cleared (max 0%)".
nd_mark "$ND/acct-01" client:seven_day 345600 2020-01-01T00:00:00Z
rm -f "$ND/acct-01/.client-limit-cleared"
out="$(ndlimits "$WORK/usage-allzero.json")"
{ [ -f "$ND/acct-01/.limited" ] && [ ! -f "$ND/acct-01/.client-limit-cleared" ] \
  && printf '%s' "$out" | grep -q "acct-01: marker kept (no usable telemetry)"; } \
  && t_ok "a no-data limits pass keeps an aged client:seven_day marker, and logs that it kept it" \
  || t_fail "writer marker: no-data pass" \
     "marker=$([ -f "$ND/acct-01/.limited" ] && echo kept || echo DELETED) log: $(nd_acct01_log "$out")"

# (2) ...and a pass that DID report something still cannot clear a weekly rejection
# before its reset: a seven-day window cannot fall from the server-proven 100% that
# wrote the marker to 5% while it is still open. The keep must come from the BUCKET
# rule, not from silence, so the "no usable telemetry" line must NOT appear here.
nd_mark "$ND/acct-01" client:seven_day 345600 2020-01-01T00:00:00Z
rm -f "$ND/acct-01/.client-limit-cleared"
out="$(ndlimits "$WORK/usage-nd-low.json")"
{ [ -f "$ND/acct-01/.limited" ] && [ ! -f "$ND/acct-01/.client-limit-cleared" ] \
  && ! printf '%s' "$out" | grep -q "acct-01: marker cleared" \
  && ! printf '%s' "$out" | grep -q "acct-01: marker kept (no usable telemetry)"; } \
  && t_ok "an informative 5% pass keeps a client:seven_day marker on the bucket rule alone" \
  || t_fail "writer marker: weekly vs informative pass" \
     "marker=$([ -f "$ND/acct-01/.limited" ] && echo kept || echo DELETED) log: $(nd_acct01_log "$out")"

# (3) The 5h window self-heals in hours, so #22 (2026-09-03) still holds at the writer:
# an aged five_hour rejection DOES clear once a pass has real numbers under the
# threshold. This one passes on origin/main too — deliberately: it is the guard against
# over-correcting (2) into "no client marker ever clears", which would strand accounts
# sitting at 0% usage for days, which is the bug #22 existed to fix.
nd_mark "$ND/acct-01" client:five_hour 1800 2020-01-01T00:00:00Z
rm -f "$ND/acct-01/.client-limit-cleared"
out="$(ndlimits "$WORK/usage-nd-low.json")"
{ [ ! -f "$ND/acct-01/.limited" ] && [ -f "$ND/acct-01/.client-limit-cleared" ] \
  && printf '%s' "$out" | grep -q "acct-01: marker cleared (max 5%)"; } \
  && t_ok "an informative 5% pass still clears an aged client:five_hour marker (#22)" \
  || t_fail "writer marker: five_hour recovery" \
     "marker=$([ -f "$ND/acct-01/.limited" ] && echo kept || echo DELETED) log: $(nd_acct01_log "$out")"

# (4) ...but the SAME five_hour marker survives a pass that said nothing. "0%" and "no
# reading" are the same bytes on origin/main, and that is the whole incident.
nd_mark "$ND/acct-01" client:five_hour 1800 2020-01-01T00:00:00Z
rm -f "$ND/acct-01/.client-limit-cleared"
out="$(ndlimits "$WORK/usage-allzero.json")"
{ [ -f "$ND/acct-01/.limited" ] && [ ! -f "$ND/acct-01/.client-limit-cleared" ] \
  && printf '%s' "$out" | grep -q "acct-01: marker kept (no usable telemetry)"; } \
  && t_ok "a no-data pass keeps even a client:five_hour marker — the kind it may clear when informative" \
  || t_fail "writer marker: five_hour vs no-data pass" \
     "marker=$([ -f "$ND/acct-01/.limited" ] && echo kept || echo DELETED) log: $(nd_acct01_log "$out")"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared

# ---- 16-nodata-signals. each ranking signal comes from a bucket of its OWN kind ------
# 2026-09-04, second defect: weekly_percent fell back to the overall peak and
# session_percent to a flat 0. So an account whose weekly buckets said nothing while its
# 5h bucket read 40% was recorded as 40% WEEKLY — a number no bucket ever reported, on
# the signal the band ranks on — and its mirror image was recorded as session 0%, which
# walks straight through the session gate. A signal nobody reported must be ABSENT: the
# shim needs BOTH readings to call an account known (pick_best's quota_known rule), so a
# missing one costs the account its place in the band and nothing else.
cat > "$WORK/usage-session-only.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":40,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":0,"resets_at":null,"scope":null},
  {"kind":"weekly_scoped","group":"weekly","percent":0,"resets_at":null,"scope":{"model":{"display_name":"Fable"}}}
]}
EOF
ndlimits "$WORK/usage-session-only.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d                    # one bucket DID report: this is a reading
assert (d['session_percent'], d['max_percent']) == (40, 40), d
# The two weekly buckets said `0% / no window`. Recording 40 here (round 1's fallback to
# the overall peak) or 0 (origin/main's max over silent weekly buckets) both invent the
# only number the weekly band ranks on.
assert 'weekly_percent' not in d, d
assert 'weekly_resets_epoch' not in d, d        # a horizon without a reading means nothing
EOF
[ $? -eq 0 ] && t_ok "a session-only reading records session+max and NO weekly_percent" \
  || t_fail "session-only signals" "see $ND/acct-01/limits.json"

# ...and the shim reads that as UNKNOWN, so a truthful 30w/10s account takes every pick.
ndl 30 10 30 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND"/acct-0*/.limited
: > "$ND/selection.log"
nd_sess_hits=0
for _ in $(seq 1 10); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-01*) nd_sess_hits=$((nd_sess_hits+1)) ;; esac
done
[ "$nd_sess_hits" = "0" ] \
  && t_ok "an account with no weekly reading never enters the band (0 of 10 picks)" \
  || t_fail "session-only ranking" "the weekly-less account took $nd_sess_hits of 10 picks"

# The mirror image — a weekly reading whose 5h bucket has nothing to say — is NOT the
# same defect, and treating it as one broke selection on 2026-09-22. A weekly window
# always exists (a fixed calendar week, running whether or not the account is), so a
# silent weekly bucket is an endpoint that DECLINED. The 5h window only exists while it
# is OPEN, so a silent session bucket is an account that has simply been IDLE — and an
# exhausted session is never silent: a spent 5h bucket always reports ~100% with the
# reset it is waiting on. Recording idle as UNKNOWN cost the pool its entire band,
# because quota_known needs BOTH readings: the accounts with the MOST headroom
# (acct-13/acct-14, 0% weekly) were scored 100 and dropped out, leaving acct-17 at 95%
# weekly as the only band member — selection.log 2026-09-22T12:37:36Z, band-count=1,
# four picks in a row onto an account already out of weekly headroom. A closed window
# holds no usage: it reads 0.
cat > "$WORK/usage-weekly-only.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":0,"resets_at":null,"scope":null},
  {"kind":"weekly_all","group":"weekly","percent":37,"resets_at":"2099-01-05T00:00:00+00:00","scope":null}
]}
EOF
ndlimits "$WORK/usage-weekly-only.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys, time, calendar
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['weekly_percent'], d['max_percent']) == (37, 37), d
assert d['weekly_resets_epoch'] == calendar.timegm(
    time.strptime("2099-01-05T00:00:00", "%Y-%m-%dT%H:%M:%S")), d
# The 5h window is CLOSED, not undocumented, so it holds no usage. max_percent is still
# taken over the INFORMATIVE buckets only, so this idle 0 never becomes a bucket reading.
assert d['session_percent'] == 0, d
EOF
[ $? -eq 0 ] && t_ok "an idle 5h bucket beside a real weekly one records session_percent 0" \
  || t_fail "idle-session signals" "see $ND/acct-01/limits.json"

# A payload with NO session bucket at ALL is the same story told by omission — the shape
# every codex account produces while it is quiet. It must rank, not vanish.
cat > "$WORK/usage-no-session-bucket.json" <<'EOF'
{"limits":[
  {"kind":"weekly_all","group":"weekly","percent":37,"resets_at":"2099-01-05T00:00:00+00:00","scope":null}
]}
EOF
ndlimits "$WORK/usage-no-session-bucket.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['weekly_percent'], d['session_percent'], d['max_percent']) == (37, 0, 37), d
EOF
[ $? -eq 0 ] && t_ok "a payload with no session bucket at all still records session_percent 0" \
  || t_fail "absent-session signals" "see $ND/acct-01/limits.json"

# ...and that account RANKS: idle plus the better weekly must beat a busier rival — the
# pick the pool was losing. acct-02 is worse on weekly (80 vs 37) and clears the gate
# too, so the band alone separates them.
ndl 80 10 80 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND"/acct-0*/.limited
: > "$ND/selection.log"
nd_wk_hits=0
for _ in $(seq 1 6); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-01*) nd_wk_hits=$((nd_wk_hits+1)) ;; esac
done
[ "$nd_wk_hits" = "6" ] \
  && t_ok "an idle account with the better weekly takes every pick (6 of 6)" \
  || t_fail "idle-session ranking" "the idle account took $nd_wk_hits of 6"
grep -q "acct-01 weekly=37% session=0% band=30 band-count=1 session-gate=50 session-ok=2" "$ND/selection.log" \
  && t_ok "the log shows both clearing the gate and the idle account alone in the band" \
  || t_fail "idle-session log" "$(tail -1 "$ND/selection.log" 2>/dev/null)"

# The guard that must NOT move: a document where NOTHING answered is still unknown. The
# all-zero 2026-09-04 shape has no informative bucket anywhere, so it writes no signals
# at all and never picks up a fabricated session 0 on the way out.
ndlimits "$WORK/usage-allzero.json" --quiet >/dev/null
python3 - "$ND/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d.get('no_data') is True, d
for k in ('max_percent', 'weekly_percent', 'session_percent', 'weekly_resets_epoch'):
    assert k not in d, (k, d)
EOF
[ $? -eq 0 ] && t_ok "an all-zero payload still writes no session_percent (2026-09-04 holds)" \
  || t_fail "allzero still unknown" "see $ND/acct-01/limits.json"

# ---- 16-idle-marker. an INFERRED session 0 may rank, but it may never unpark ---------
# 2026-09-22, the second half of the same day: with idle accounts ranking again, the
# operator's `claude --resume` landed on acct-14 and was rejected inside a minute.
# selection.log: "acct-14 client limit cleared by newer telemetry (0%)" one second before
# the pick, and "LIMITED by its own session (five_hour)" 54s after it. acct-14 held a
# client:five_hour marker from a REAL 429, and its telemetry — fetched at 13:04:16Z,
# WHILE the client was being rejected — still reported the session bucket `percent: 0,
# resets_at: null`. So a silent session bucket does NOT prove an idle account: the
# endpoint may simply never report the 5h window. Recovery has to be MEASURED. The
# clearing rule read max_percent, which is the WEEKLY peak when the session bucket is
# silent — the cross-signal borrow the aggregation itself refuses to make.
mk_client_marker() { # mk_client_marker <acct dir> <bucket> <age seconds> <reset in>
  python3 - "$1" "$2" "$3" "$4" <<'PJ'
import sys, time, os
d, bucket, age, ahead = sys.argv[1], sys.argv[2], int(sys.argv[3]), int(sys.argv[4])
now = int(time.time())
marked = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(now - age))
with open(os.path.join(d, '.limited'), 'w') as f:
    f.write(f'{now + ahead}\n'
            f'bucket=client:{bucket} percent=100 marked_at={marked} '
            f'reason=client-rate-limit\n')
PJ
}
# the acct-14 shape: a live 5h rejection, and telemetry whose session bucket is silent
mk_client_marker "$ND/acct-01" five_hour 1200 7200
ndlimits "$WORK/usage-weekly-only.json" --quiet >/dev/null
{ [ -f "$ND/acct-01/.limited" ] \
  && python3 -c "import json,sys; d=json.load(open('$ND/acct-01/limits.json')); sys.exit(0 if d.get('session_inferred') is True and d['session_percent'] == 0 else 1)"; } \
  && t_ok "an inferred session 0 cannot clear a client:five_hour marker (writer)" \
  || t_fail "inferred unpark (writer)" "marker gone, or session_inferred not recorded"

# ...and the SHIM must agree, because it is the shim that logged the clear before the
# bad pick. The rival is WORSE on weekly and must still take every launch.
ndl 60 10 60 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND/acct-02/.limited"
: > "$ND/selection.log"
nd_park_hits=0
for _ in $(seq 1 6); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-01*) nd_park_hits=$((nd_park_hits+1)) ;; esac
done
{ [ "$nd_park_hits" = "0" ] && [ -f "$ND/acct-01/.limited" ] \
  && ! grep -q "cleared by newer telemetry" "$ND/selection.log"; } \
  && t_ok "the shim never unparks a 5h marker on an inferred reading (0 of 6 picks)" \
  || t_fail "inferred unpark (shim)" \
     "the parked account took $nd_park_hits of 6; $(tail -1 "$ND/selection.log" 2>/dev/null)"

# The #22 behaviour that must SURVIVE: a MEASURED low session reading still clears a 5h
# marker. That window self-heals in hours, which is why #22 (2026-09-03) had to clear it
# — this fix narrows the evidence, it does not park an account until its reset.
mk_client_marker "$ND/acct-01" five_hour 1200 7200
cat > "$WORK/usage-measured-session.json" <<'EOF'
{"limits":[
  {"kind":"session","group":"session","percent":5,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","group":"weekly","percent":37,"resets_at":"2099-01-05T00:00:00+00:00","scope":null}
]}
EOF
ndlimits "$WORK/usage-measured-session.json" --quiet >/dev/null
{ [ ! -f "$ND/acct-01/.limited" ] \
  && python3 -c "import json,sys; d=json.load(open('$ND/acct-01/limits.json')); sys.exit(0 if 'session_inferred' not in d and d['session_percent'] == 5 else 1)"; } \
  && t_ok "a MEASURED low session reading still clears a five_hour marker (#22 holds)" \
  || t_fail "measured recovery" "see $ND/acct-01/.limited"

# A WEEKLY marker is untouched by any of this — it was already un-clearable.
mk_client_marker "$ND/acct-01" seven_day 1200 7200
ndlimits "$WORK/usage-measured-session.json" --quiet >/dev/null
[ -f "$ND/acct-01/.limited" ] \
  && t_ok "a weekly marker still outlives even a measured reading (2026-09-04 holds)" \
  || t_fail "weekly marker cleared" "see $ND/acct-01"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared

# ---- 16-nodata-blind. a fresh timestamp is not a usable reading ---------------------
# The third face of the same defect: blindness was judged on fetched_at alone, so a pool
# of freshly-written no_data documents looked FRESH — selection.log carried no
# ranking=BLIND line, `status` said nothing was wrong, and every account read as unknown,
# which is a pool-wide coin flip. An outage that reports itself as healthy is the eleven
# days of 2026-08-11 all over again, this time with a current timestamp on it.
ndlimits "$WORK/usage-allzero.json" --quiet >/dev/null      # BOTH accounts: no_data
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND"/acct-0*/.limited
: > "$ND/selection.log"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
grep -qE "ranking=BLIND telemetry-age=[0-9]{1,2}s band=30 band-count=2 session-gate=50 session-ok=0 pwd=" \
  "$ND/selection.log" \
  && t_ok "an all-no_data pool logs ranking=BLIND although its telemetry is seconds old" \
  || t_fail "no_data blindness" "$(tail -1 "$ND/selection.log" 2>/dev/null)"
out="$(CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts status 2>&1)"
check "status calls an all-no_data pool blind" "RANKING IS BLIND" "$out"
# ...and says which KIND of blind, because the two take opposite advice. The eleven-day
# 2026-08 outage was stale telemetry — fetch again, then log in. This one is current
# telemetry that says nothing: the credential is working perfectly, so sending the
# operator to `claude-accounts login` is sending them after a fault that does not exist.
check "the no_data banner names the endpoint, not the login" \
  "Those fetches authenticated; a re-login does NOT fix this" "$out"
case "$out" in
  *"claude-accounts login <acct-NN>"*)
    t_fail "no_data banner fix line" "a current-but-unusable pool was told to re-login" ;;
  *) t_ok "the no_data banner does not prescribe a re-login" ;;
esac
CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list --json > "$ND/nodata.json" 2>/dev/null
python3 - "$ND/nodata.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['telemetry'] == 'blind', d['summary']
assert d['summary']['ranking_blind'] is True, d['summary']
for a in d['accounts']:
    u = a['usage']
    # The panel has to be able to tell THIS outage from the eleven-day one: the readings
    # are current (not stale), they simply carry nothing to rank on.
    assert u['no_data'] is True, a
    assert u['stale'] is False, a
    assert u['weekly_percent'] is None and u['session_percent'] is None, a
EOF
[ $? -eq 0 ] && t_ok "--json reports ranking_blind with per-account no_data on fresh readings" \
  || t_fail "json no_data blindness" "see $ND/nodata.json"

# One real reading is enough to rank the pool, and it must take the picks. A no_data
# neighbour is unknown, not free.
ndl 30 10 30 > "$ND/acct-02/limits.json"
: > "$ND/selection.log"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
nd_mix_hits=0
for _ in $(seq 1 6); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-02*) nd_mix_hits=$((nd_mix_hits+1)) ;; esac
done
{ [ "$nd_mix_hits" = "6" ] && ! grep -q "ranking=BLIND" "$ND/selection.log"; } \
  && t_ok "one no_data account beside a real one leaves the pool ranking, and the real one wins 6/6" \
  || t_fail "mixed no_data pool" "acct-02 took $nd_mix_hits of 6; $(tail -1 "$ND/selection.log" 2>/dev/null)"
CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list --json > "$ND/nodata-mixed.json" 2>/dev/null
python3 - "$ND/nodata-mixed.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['telemetry'] == 'fresh', d['summary']
assert d['summary']['ranking_blind'] is False, d['summary']
byid = {a['id']: a for a in d['accounts']}
assert byid['acct-01']['usage']['no_data'] is True, byid['acct-01']
# true-only: an ordinary reading must carry the shape every consumer already knows
assert 'no_data' not in byid['acct-02']['usage'], byid['acct-02']
EOF
[ $? -eq 0 ] && t_ok "--json calls the mixed pool fresh and flags only the no_data account" \
  || t_fail "json mixed no_data" "see $ND/nodata-mixed.json"

# ...and a no_data document is never DEGRADABLE. Degraded ranking exists for stale
# readings that are still true (a weekly bucket only rises until its reset); a document
# with no weekly reading and no horizon has nothing to be true. It must drag the pool to
# BLIND rather than let one neighbour's stale number rank alone.
printf '{"fetched_at":%s,"source":"oauth","no_data":true,"buckets":[]}' "$(date +%s)" \
  > "$ND/acct-01/limits.json"
printf '{"fetched_at":%s,"weekly_percent":4,"session_percent":0,"max_percent":4,"weekly_resets_epoch":%s,"buckets":[]}' \
  "$(( $(date +%s) - 950000 ))" "$(( $(date +%s) + 200000 ))" > "$ND/acct-02/limits.json"
: > "$ND/selection.log"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
{ grep -q "ranking=BLIND" "$ND/selection.log" && ! grep -q "ranking=DEGRADED" "$ND/selection.log"; } \
  && t_ok "an in-window no_data candidate turns degraded ranking off for the whole pool" \
  || t_fail "no_data degraded" "$(tail -1 "$ND/selection.log" 2>/dev/null)"
# the same holds once the no_data document itself goes stale (nothing to rank, ever)
printf '{"fetched_at":%s,"source":"oauth","no_data":true,"buckets":[]}' "$(( $(date +%s) - 950000 ))" \
  > "$ND/acct-01/limits.json"
: > "$ND/selection.log"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
{ grep -q "ranking=BLIND" "$ND/selection.log" && ! grep -q "ranking=DEGRADED" "$ND/selection.log"; } \
  && t_ok "a stale no_data document is not degradable either" \
  || t_fail "stale no_data degraded" "$(tail -1 "$ND/selection.log" 2>/dev/null)"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared

# ---- 16-onefield-blind. HALF a reading is not a reading -----------------------------
# The same defect one layer in, and the one the round-2 fix walked past. Blindness was
# taught to reject a no_data document — but it accepted one carrying EITHER percentage,
# while pick_best has always needed BOTH (the quota_known rule) before it will call an
# account known. The writer emits exactly those half documents, per signal, whenever one
# group of buckets goes silent (16-nodata-signals above). So a pool whose every reading
# was session-only tied every account, picked uniformly at RANDOM, logged no
# ranking=BLIND, and had `status` calling the telemetry fresh — the 2026-08 outage's
# defining symptom, with a current timestamp on it. Blind is blind however the reading
# came up short.
ndl_half() { # ndl_half <session pct> -> a fresh, truthful, SESSION-ONLY reading
  printf '{"fetched_at":%s,"source":"oauth","session_percent":%s,"max_percent":%s,"buckets":[]}' \
    "$(date +%s)" "$1" "$1"
}
ndl_half 12 > "$ND/acct-01/limits.json"
ndl_half 18 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND"/acct-0*/.limited
: > "$ND/selection.log"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
# session-ok=0 is the point, not a detail: both readings carry a session percentage well
# under the gate, and NEITHER clears it, because the gate is part of the same "known"
# rule. A pool that cannot rank must not look like one that ranked and tied.
grep -qE "ranking=BLIND telemetry-age=[0-9]{1,2}s band=30 band-count=2 session-gate=50 session-ok=0 pwd=" \
  "$ND/selection.log" \
  && t_ok "a pool of session-only readings logs ranking=BLIND although both are seconds old" \
  || t_fail "one-signal blindness" "$(tail -1 "$ND/selection.log" 2>/dev/null)"
out="$(CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts status 2>&1)"
check "status calls a one-signal pool blind" "RANKING IS BLIND" "$out"
check "the one-signal banner says the readings are incomplete" \
  "ranking needs BOTH a weekly and a session percentage" "$out"
CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list --json > "$ND/onefield.json" 2>/dev/null
python3 - "$ND/onefield.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['telemetry'] == 'blind', d['summary']
assert d['summary']['ranking_blind'] is True, d['summary']
for a in d['accounts']:
    u = a['usage']
    # Current, well-formed, and NOT a no_data document — one real bucket did report.
    # It simply is not enough to rank on, and the panel has to agree with the shim.
    assert u['stale'] is False, a
    assert 'no_data' not in u, a
    assert u['session_percent'] is not None and u['weekly_percent'] is None, a
EOF
[ $? -eq 0 ] && t_ok "--json reports ranking_blind for readings that are half present" \
  || t_fail "json one-signal blindness" "see $ND/onefield.json"

# ...and the weekly-only mirror of the same rule: known needs BOTH, whichever half is
# missing. DEGRADED must not fire either — these readings are FRESH, and degraded exists
# for an outage of age, not for fresh emptiness (codex review, 2026-09-04).
ndl_whalf() { # ndl_whalf <weekly pct> -> a fresh, truthful, WEEKLY-ONLY reading
  printf '{"fetched_at":%s,"source":"oauth","weekly_percent":%s,"max_percent":%s,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$(date +%s)" "$1" "$1" "$(( $(date +%s) + 500000 ))"
}
ndl_whalf 4 > "$ND/acct-01/limits.json"
ndl_whalf 80 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick "$ND"/acct-0*/.limited
: > "$ND/selection.log"
CLAUDE_ACCOUNTS_ROOT="$ND" claude >/dev/null 2>&1
grep -qE "ranking=BLIND telemetry-age=[0-9]{1,2}s .*session-ok=0 pwd=" "$ND/selection.log" \
  && t_ok "a pool of weekly-only readings logs ranking=BLIND, not DEGRADED" \
  || t_fail "weekly-only blindness" "$(tail -1 "$ND/selection.log" 2>/dev/null)"
! grep -q "ranking=DEGRADED" "$ND/selection.log" \
  && t_ok "fresh weekly-only readings never promote the pool to DEGRADED" \
  || t_fail "fresh-degraded" "a fresh one-signal pool ranked DEGRADED"
CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list --json > "$ND/whalf.json" 2>/dev/null
python3 - "$ND/whalf.json" <<'PJ'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['ranking_blind'] is True, d['summary']
PJ
[ $? -eq 0 ] && t_ok "--json calls the fresh weekly-only pool blind (not degraded)" \
  || t_fail "json one-signal verdict" "see $ND/whalf.json"


# One COMPLETE reading beside them is enough to rank the pool, and it must take every
# pick — the half readings are unknown, not free. (This holds on the pre-fix tree too:
# it is the guard against over-correcting "half is blind" into "half is excluded".)
ndl 30 10 30 > "$ND/acct-02/limits.json"
rm -f "$ND/.pick-seq" "$ND"/acct-0*/.last-pick
: > "$ND/selection.log"
nd_half_hits=0
for _ in $(seq 1 6); do
  case "$(CLAUDE_ACCOUNTS_ROOT="$ND" claude 2>&1)" in *CFG=acct-02*) nd_half_hits=$((nd_half_hits+1)) ;; esac
done
{ [ "$nd_half_hits" = "6" ] && ! grep -q "ranking=BLIND" "$ND/selection.log"; } \
  && t_ok "one complete reading beside a session-only one leaves the pool ranking, and wins 6/6" \
  || t_fail "mixed one-signal pool" \
     "acct-02 took $nd_half_hits of 6; $(tail -1 "$ND/selection.log" 2>/dev/null)"
CLAUDE_ACCOUNTS_ROOT="$ND" claude-accounts list --json > "$ND/onefield-mixed.json" 2>/dev/null
python3 - "$ND/onefield-mixed.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['telemetry'] == 'fresh', d['summary']
assert d['summary']['ranking_blind'] is False, d['summary']
EOF
[ $? -eq 0 ] && t_ok "--json calls the mixed one-signal pool fresh" \
  || t_fail "json mixed one-signal" "see $ND/onefield-mixed.json"
rm -f "$ND"/acct-0*/.limited "$ND"/acct-0*/.client-limit-cleared

# ---- 16-marker. the marker names ONE bucket and carries THAT bucket's reset ----------
# A 100% session bucket (resets in an hour) beside a 100% Fable-only weekly bucket
# (resets in five days) used to produce "bucket=session … resets_at=<+1h>" on line 2
# under a line-1 epoch five days out — the highest percent paired with the latest
# reset of a DIFFERENT bucket. Every reader of the marker (this shim, app-robot's
# fleet-wide verdict) then parked the whole account for five days over a five-hour
# window (2026-08-29, acct-05). The account-level bucket is named with its own reset.
cat > "$WORK/usage-session-vs-fable.json" <<'EOF2'
{"limits":[
  {"kind":"session","percent":100,"resets_at":"2099-01-01T01:00:00+00:00","scope":null},
  {"kind":"weekly_all","percent":40,"resets_at":"2099-01-05T00:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","percent":100,"resets_at":"2099-01-06T00:00:00+00:00","scope":{"model":{"display_name":"Fable"}}}
]}
EOF2
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-session-vs-fable.json" claude-accounts limits --force 2>&1)"
check "session over threshold names the session bucket, not the Fable one" "LIMITED session at 100%" "$out"
python3 - "$ACC/acct-01/.limited" <<'EOF2'
import sys, time, calendar
lines = open(sys.argv[1]).read().splitlines()
epoch, detail = int(lines[0]), lines[1]
want = calendar.timegm(time.strptime("2099-01-01T01:00:00", "%Y-%m-%dT%H:%M:%S"))
assert epoch == want, (epoch, want, detail)                       # the SESSION reset
assert "bucket=session percent=100" in detail, detail
assert "resets_at=2099-01-01T01:00:00+00:00" in detail, detail
EOF2
[ $? -eq 0 ] && t_ok "marker epoch is the named bucket's own reset (session +1h, not Fable +5d)" \
  || t_fail "marker epoch/bucket consistency" "$(cat "$ACC/acct-01/.limited" 2>&1 | tr '\n' ' ')"
# Two ACCOUNT-level offenders: the longest-lived exclusion is the one named, with its
# own reset — a session bucket that resets in an hour must not shorten a weekly park.
cat > "$WORK/usage-session-vs-weekly.json" <<'EOF2'
{"limits":[
  {"kind":"session","percent":100,"resets_at":"2099-01-01T01:00:00+00:00","scope":null},
  {"kind":"weekly_all","percent":95,"resets_at":"2099-01-05T00:00:00+00:00","scope":null}
]}
EOF2
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-session-vs-weekly.json" claude-accounts limits --force 2>&1)"
check "two account-level offenders: the longest-lived one is named" "LIMITED weekly_all at 95%" "$out"
python3 - "$ACC/acct-01/.limited" <<'EOF2'
import sys, time, calendar
lines = open(sys.argv[1]).read().splitlines()
want = calendar.timegm(time.strptime("2099-01-05T00:00:00", "%Y-%m-%dT%H:%M:%S"))
assert int(lines[0]) == want, lines
assert "bucket=weekly_all percent=95" in lines[1] and "resets_at=2099-01-05T00:00:00+00:00" in lines[1], lines
EOF2
[ $? -eq 0 ] && t_ok "weekly_all marker carries the weekly reset" \
  || t_fail "weekly_all marker" "$(cat "$ACC/acct-01/.limited" 2>&1 | tr '\n' ' ')"
# Only a model-scoped offender left: the scoped bucket is named (the shim treats it
# as "switch model", never as an account park) with ITS reset.
cat > "$WORK/usage-fable-only.json" <<'EOF2'
{"limits":[
  {"kind":"session","percent":10,"resets_at":"2099-01-01T01:00:00+00:00","scope":null},
  {"kind":"weekly_scoped","percent":100,"resets_at":"2099-01-06T00:00:00+00:00","scope":{"model":{"display_name":"Fable"}}}
]}
EOF2
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-fable-only.json" claude-accounts limits --force 2>&1)"
check "a scoped-only offender still marks, scoped" "LIMITED weekly_scoped:Fable at 100%" "$out"
grep -q "^bucket=weekly_scoped:Fable percent=100 " "$ACC/acct-01/.limited" 2>/dev/null \
  && [ "$(head -1 "$ACC/acct-01/.limited")" = "$(python3 -c 'import time,calendar;print(calendar.timegm(time.strptime("2099-01-06T00:00:00","%Y-%m-%dT%H:%M:%S")))')" ] \
  && t_ok "scoped marker carries the scoped bucket's reset" \
  || t_fail "scoped marker" "$(cat "$ACC/acct-01/.limited" 2>&1 | tr '\n' ' ')"
grep -q '"model": "Fable"' "$ACC/acct-01/limits.json" && t_ok "limits.json buckets record the model scope" \
  || t_fail "bucket model field" "missing from limits.json"
rm -f "$ACC/acct-01/limits.json" "$ACC/acct-01/.limited"

# ---- 16a. future-proofing: works if the Fable bucket separation disappears ---------
cat > "$WORK/usage-no-fable.json" <<'EOF'
{"limits":[
  {"kind":"session","percent":20,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","percent":95,"resets_at":"2099-01-02T00:00:00+00:00","scope":null}
]}
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-no-fable.json" claude-accounts limits 2>&1)"
check "no-Fable payload still marks on weekly_all" "LIMITED weekly_all at 95%" "$out"
grep -q "weekly_scoped" "$ACC/acct-01/limits.json" && t_fail "no stale Fable bucket" "old bucket kept" || t_ok "buckets reflect current payload only"

# ---- 16a2. legacy payload (no limits[] at all) falls back to five_hour/seven_day ----
cat > "$WORK/usage-legacy.json" <<'EOF'
{"five_hour":{"utilization":12.0,"resets_at":"2099-01-01T00:00:00+00:00"},
 "seven_day":{"utilization":34.0,"resets_at":"2099-01-02T00:00:00+00:00"}}
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-legacy.json" claude-accounts limits 2>&1)"
check "legacy payload parsed via fallback" "five_hour=12%" "$out"
check "legacy marker cleared under threshold" "acct-01: ok" "$out"

# ---- 16a3. malformed/garbage payload entries never crash the refresher --------------
cat > "$WORK/usage-garbage.json" <<'EOF'
{"limits":[
  {"kind":"session","percent":"NaNsense","scope":{"model":"stringnotdict"}},
  "not-even-a-dict",
  {"percent":41,"scope":{"model":{"display_name":null,"id":"claude-fable-5"}}},
  {"kind":"weekly_all","percent":null}
]}
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-garbage.json" claude-accounts limits 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "garbage payload exits 0 (fail open)" || t_fail "garbage payload rc" "rc=$rc: $out"
check "parseable entry survives garbage siblings" "unknown:claude-fable-5=41%" "$out"

# ---- 16a4. fetch throttle: fresh data is not re-fetched -----------------------------
CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --quiet
before="$(python3 -c "import json; print(json.load(open('$ACC/acct-01/limits.json'))['fetched_at'])")"
mv "$WORK/usage-low.json" "$WORK/usage-low.hidden"   # a real fetch would now fail loudly
out="$(CLAUDE_MULTIACC_MIN_FETCH=45 CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
after="$(python3 -c "import json; print(json.load(open('$ACC/acct-01/limits.json'))['fetched_at'])")"
{ [ "$before" = "$after" ] && ! printf '%s' "$out" | grep -q "fetch failed"; } \
  && t_ok "fresh data skips re-fetch (rate-limit protection)" \
  || t_fail "fetch throttle" "re-fetched despite fresh data: $out"
mv "$WORK/usage-low.hidden" "$WORK/usage-low.json"
out="$(CLAUDE_MULTIACC_MIN_FETCH=45 CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
check "--force bypasses the throttle" "acct-01: ok" "$out"

# ---- 16a5. 429 sets backoff, is honored, and clears on success -----------------------
python3 - "$ACC/acct-01/limits.json" <<'EOF'
import json, os, sys, time
p = sys.argv[1]
d = json.load(open(p))
d['fetched_at'] = 0                        # stale enough to fetch
d['retry_after'] = int(time.time()) + 600  # but a 429 backoff is in force
d['backoff'] = 600
json.dump(d, open(p + '.tmp', 'w'), indent=1); os.replace(p + '.tmp', p)
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
# A backoff with no recorded cause (an older build wrote these) still reports honestly
# rather than blaming a 429 it never saw.
check "backoff honored" "acct-01: backing off after a failed fetch" "$out"
# ...and when the cause IS on record, the skip message names it. Calling every park a
# 429 is exactly how an unauthorized account read as merely rate-limited for 11 days.
python3 - "$ACC/acct-01/limits.json" <<'EOF'
import json, os, sys, time
p = sys.argv[1]
d = json.load(open(p))
d['last_error'] = 'HTTP 403 (source=token) — permanent, server said do not retry'
json.dump(d, open(p + '.tmp', 'w'), indent=1); os.replace(p + '.tmp', p)
EOF
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
check "a skipped account names the error it is backing off from" "backing off after HTTP 403" "$out"
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
check "--force overrides backoff" "acct-01: ok" "$out"
python3 -c "
import json, sys
d = json.load(open('$ACC/acct-01/limits.json'))
sys.exit(0 if 'retry_after' not in d and 'backoff' not in d else 1)" \
  && t_ok "successful fetch clears backoff state" || t_fail "backoff cleared" "retry_after/backoff persisted"

# ---- 16b. expired-bearer account: oauth refresh attempted; fail-open when it fails ----
mkdir -p "$ACC/acct-05"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-oldrefresh","expiresAt":1000,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-05/.credentials.json"
claude-accounts import e@test --id acct-05 --no-sync >/dev/null 2>&1
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
rc=$?
check "failed oauth refresh logged with backoff" "acct-05: oauth refresh failed" "$out"
check "expired bearer logged, not fatal" "acct-05: no fresh bearer" "$out"
[ "$rc" = "0" ] && t_ok "limits exits 0 with expired-bearer account" || t_fail "limits exit code" "rc=$rc"
[ ! -f "$ACC/acct-05/limits.json" ] && t_ok "no limits.json fabricated for expired account" || t_fail "expired acct limits.json" "unexpectedly written"
[ -f "$ACC/acct-05/.oauth-refresh.json" ] && t_ok "refresh failure recorded in .oauth-refresh.json" || t_fail "refresh backoff file" "missing"

# ---- 16b2. refresh backoff honored: even a now-working endpoint is not retried early --
cat > "$WORK/token-ok.json" <<'EOF'
{"access_token":"sk-ant-oat01-refreshednew","refresh_token":"sk-ant-ort01-rotatednew","expires_in":28800,"refresh_token_expires_in":2592000}
EOF
out="$(CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
check "refresh backoff honored (no early retry)" "acct-05: no fresh bearer" "$out"
grep -q "sk-ant-oat01-refreshednew" "$ACC/acct-05/.credentials.json" \
  && t_fail "backoff prevented refresh" "credentials rewritten inside the backoff window" \
  || t_ok "no refresh inside the backoff window"

# ---- 16b3. --force bypasses refresh backoff: rotated credential persisted + fetch ok --
out="$(CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
check "--force refreshes the expired oauth token" "acct-05: oauth access token refreshed" "$out"
check "refreshed account fetches telemetry" "acct-05: ok" "$out"
python3 - "$ACC/acct-05/.credentials.json" <<'EOF'
import json, os, stat, sys, time
p = sys.argv[1]
o = json.load(open(p))['claudeAiOauth']
assert o['accessToken'] == 'sk-ant-oat01-refreshednew', o['accessToken']
assert o['refreshToken'] == 'sk-ant-ort01-rotatednew', 'refresh token was not rotated'
assert o['expiresAt'] / 1000.0 > time.time() + 3600, 'expiresAt not advanced'
assert o['refreshTokenExpiresAt'] / 1000.0 > time.time() + 86400, 'refreshTokenExpiresAt not advanced'
mode = stat.S_IMODE(os.stat(p).st_mode)
assert mode == 0o600, oct(mode)
EOF
[ $? -eq 0 ] && t_ok "rotated credential persisted with 0600" || t_fail "credential rotation" "see assertions above"
[ ! -f "$ACC/acct-05/.oauth-refresh.json" ] && t_ok "successful refresh clears the backoff file" || t_fail "refresh backoff clear" "file still present"
[ -f "$ACC/acct-05/limits.json" ] && t_ok "telemetry written right after refresh" || t_fail "limits.json after refresh" "missing"
grep -qE "sk-ant-ort01|sk-ant-oat01-refreshednew" "$ACC/limits.log" \
  && t_fail "limits.log leaks no tokens" "a token leaked into limits.log" \
  || t_ok "limits.log leaks no tokens"

# ---- 16b4. steady state: fresh data means no refresh and no fetch (quiet skip) --------
out="$(CLAUDE_MULTIACC_MIN_FETCH=45 CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
printf '%s' "$out" | grep -q "acct-05" \
  && t_fail "fresh account skipped silently" "unexpected acct-05 output: $out" \
  || t_ok "fresh account skipped silently (no refresh, no fetch)"

# ---- 16b5. an EXPIRED refresh token is never sent: clear re-login message -------------
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-dead","expiresAt":1000,"refreshTokenExpiresAt":1000}}' > "$ACC/acct-05/.credentials.json"
rm -f "$ACC/acct-05/limits.json" "$ACC/acct-05/.oauth-refresh.json"
out="$(CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
check "expired refresh token => re-login message" "re-login needed" "$out"
grep -q "sk-ant-oat01-refreshednew" "$ACC/acct-05/.credentials.json" \
  && t_fail "dead refresh token never used" "credentials rewritten from a dead refresh token" \
  || t_ok "dead refresh token never used"
# ...and the account is PARKED, so the shim stops handing work to a login that cannot work
grep -q "reason=refresh-token-expired" "$ACC/acct-05/.expired" 2>/dev/null \
  && t_ok "limits parks an account with a dead refresh token" \
  || t_fail "limits .expired marker" "no .expired written for a dead refresh token"
# a later successful fetch (fresh login, or a token bearer) unparks it
printf 'sk-ant-oat01-portable-unpark' > "$ACC/acct-05/server.token"
rm -f "$ACC/acct-05/limits.json"
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
[ ! -f "$ACC/acct-05/.expired" ] && t_ok "a successful usage fetch clears the dead-auth marker" \
  || t_fail "unpark on success" ".expired survived a successful authenticated fetch"
# ...but an ORG-BLOCKED account authenticates fine — telemetry proves nothing about it,
# so its marker must survive a successful fetch (only a real call or re-login lifts it).
printf '%s\nreason=org-blocked marked_at=now detail=test\n' "$now" > "$ACC/acct-05/.expired"
rm -f "$ACC/acct-05/limits.json"
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
[ -f "$ACC/acct-05/.expired" ] && t_ok "a usage fetch does not unpark an org-blocked account" \
  || t_fail "org-block unpark" "telemetry cleared an org block it cannot observe"
rm -f "$ACC/acct-05/.expired" "$ACC/acct-05/server.token"

# ---- 16b6. RECENTLY-expired token is left alone (a live session owns it) --------------
# The 5-min REFRESH_MIN_EXPIRED gate is the rotation-safety core: a token that expired
# moments ago may be mid-refresh by a live claude session; grants must not race it.
# Not even --force may bypass this.
recent_ms="$(python3 -c 'import time; print(int((time.time()-100)*1000))')"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-recent","refreshToken":"sk-ant-ort01-live","expiresAt":%s,"refreshTokenExpiresAt":9999999999999}}' "$recent_ms" > "$ACC/acct-05/.credentials.json"
rm -f "$ACC/acct-05/limits.json" "$ACC/acct-05/.oauth-refresh.json"
out="$(CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
check "recently-expired token is not refreshed (even --force)" "acct-05: no fresh bearer" "$out"
grep -q "sk-ant-oat01-recent" "$ACC/acct-05/.credentials.json" \
  && t_ok "recently-expired credential left untouched" \
  || t_fail "REFRESH_MIN_EXPIRED gate" "credential was rewritten within the 5-min grace window"
[ ! -f "$ACC/acct-05/.oauth-refresh.json" ] && t_ok "no backoff recorded for a gated (skipped) refresh" \
  || t_fail "gated refresh backoff" ".oauth-refresh.json written despite the gate"

# ---- 16b7. OAuth is preferred over a setup token FOR TELEMETRY ------------------------
# This used to be the other way round — a server.token short-circuited the oauth refresh,
# on the reasoning that a non-rotating credential is the safer one to spend. That
# reasoning inverted the moment we learned the usage endpoint refuses setup tokens
# outright (403, no user:profile scope): preferring the token means no telemetry AT ALL,
# for an account whose refresh grant was perfectly good. Order is now oauth > refresh
# grant > token, and the rotation-safety gate (16b6) still guards the grant itself.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-x","expiresAt":1000,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-05/.credentials.json"
printf 'sk-ant-oat01-portable-token-05' > "$ACC/acct-05/server.token"
rm -f "$ACC/acct-05/limits.json" "$ACC/acct-05/.oauth-refresh.json"
out="$(CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
check "an account with both credentials still fetches" "acct-05: ok" "$out"
grep -q "sk-ant-oat01-refreshednew" "$ACC/acct-05/.credentials.json" \
  && t_ok "a usable refresh grant is used even when a server.token sits beside it" \
  || t_fail "oauth preferred for telemetry" "the setup token short-circuited the refresh grant"
python3 -c "import json,sys; sys.exit(0 if json.load(open('$ACC/acct-05/limits.json'))['source']=='oauth' else 1)" \
  && t_ok "telemetry is fetched with the OAuth bearer, not the setup token" \
  || t_fail "bearer source" "source != oauth"
# ...and the token is still the fallback when there is no oauth path at all.
rm -f "$ACC/acct-05/.credentials.json" "$ACC/acct-05/limits.json"
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
python3 -c "import json,sys; sys.exit(0 if json.load(open('$ACC/acct-05/limits.json'))['source']=='token' else 1)" \
  && t_ok "with no oauth credential the setup token is still tried" \
  || t_fail "token fallback" "source != token"
rm -f "$ACC/acct-05/server.token"

# ---- 16b9. a 4xx from the TOKEN endpoint must not park the whole pool -----------------
# Every account hits the same endpoint with the same client id, so a provider incident,
# a WAF page or a client-id change 4xxs ALL of them at once. Only OAuth's own
# invalid_grant (or a repeated refusal of this one account) is proof of a dead grant.
srv_script="$WORK/token-server.py"
cat > "$srv_script" <<'EOF'
import http.server, json, sys, threading
class H(http.server.BaseHTTPRequestHandler):
    def log_message(self, *a): pass
    def _send(self, code, body):
        raw = body.encode()
        self.send_response(code)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(raw)))
        self.end_headers()
        self.wfile.write(raw)
    def do_POST(self):
        try:
            self.rfile.read(int(self.headers.get('Content-Length') or 0))
        except Exception:
            pass
        if self.path == '/invalid-grant':
            self._send(400, json.dumps({'error': 'invalid_grant'}))
        else:
            self._send(400, '<html>gateway says no</html>')
srv = http.server.HTTPServer(('127.0.0.1', 0), H)
print(srv.server_address[1], flush=True)
srv.serve_forever()
EOF
port=""
python3 "$srv_script" > "$WORK/token-port" 2>/dev/null &
srv_pid=$!
STUB_PIDS="$STUB_PIDS $srv_pid"
for _ in $(seq 1 20); do
  port="$(head -1 "$WORK/token-port" 2>/dev/null)"
  case "$port" in ''|*[!0-9]*) port=""; sleep 0.2 ;; *) break ;; esac
done
if [ -z "$port" ]; then
  kill "$srv_pid" 2>/dev/null; wait "$srv_pid" 2>/dev/null || true
  t_ok "token-endpoint 4xx tests skipped (cannot bind a loopback port here)"
else
  dead_acct="$ACC/acct-05"
  mk_stale_creds() {
    printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-x","expiresAt":1000,"refreshTokenExpiresAt":9999999999999}}' > "$dead_acct/.credentials.json"
    rm -f "$dead_acct/limits.json" "$dead_acct/.oauth-refresh.json" "$dead_acct/.expired"
  }
  # a NON-invalid_grant 400 (provider incident): back off, do NOT park
  mk_stale_creds
  out="$(CLAUDE_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/boom" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
  [ ! -f "$dead_acct/.expired" ] && t_ok "one opaque 4xx from the token endpoint does not park an account" \
    || t_fail "token 4xx park" "a single non-invalid_grant 400 parked the account"
  [ -f "$dead_acct/.oauth-refresh.json" ] && t_ok "an opaque 4xx still records a backoff" \
    || t_fail "token 4xx backoff" "no .oauth-refresh.json written"
  # ...but a repeatedly-refused account IS parked (3rd strike)
  CLAUDE_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/boom" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force >/dev/null 2>&1
  CLAUDE_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/boom" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force >/dev/null 2>&1
  [ -f "$dead_acct/.expired" ] && t_ok "a repeatedly-refused grant is parked on the third strike" \
    || t_fail "token 4xx strikes" "still not parked after three refusals"
  # invalid_grant is proof on the FIRST refusal
  mk_stale_creds
  out="$(CLAUDE_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/invalid-grant" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
  grep -q "invalid_grant" "$dead_acct/.expired" 2>/dev/null \
    && t_ok "invalid_grant parks the account immediately" \
    || t_fail "invalid_grant park" "no marker for an explicit invalid_grant"
  kill "$srv_pid" 2>/dev/null; wait "$srv_pid" 2>/dev/null || true
  rm -f "$dead_acct/.expired" "$dead_acct/.oauth-refresh.json"
fi

# ---- 16b9b. the usage endpoint's PERMANENT refusals ----------------------------------
# 2026-08-22: every account in the fleet had ranked NEUTRAL for eleven days, so `claude`
# was picking at random and a fresh session landed on the account already at 80% of its
# weekly limit. The chain: the pool's OAuth grants lapsed, the fetcher fell back to the
# portable setup token, and the usage endpoint refuses THAT with
#   403 {"type":"permission_error","message":"OAuth token does not meet scope
#        requirement user:profile"}      x-should-retry: false
# because a setup token is minted without user:profile. Only a 429 used to record a
# backoff, so the refusal was re-issued every scheduled pass from every machine — and
# those retries are what earned the 429s that made an UNAUTHORIZED account look merely
# RATE LIMITED, hiding the real cause behind a plausible one for eleven days.
usrv="$WORK/usage-server.py"
cat > "$usrv" <<'EOF'
import http.server, json, sys
LOG = sys.argv[1]
class H(http.server.BaseHTTPRequestHandler):
    def log_message(self, *a): pass
    def do_GET(self):
        with open(LOG, 'a') as f:
            f.write(self.path + '\n')
        if self.path == '/scope-denied':
            raw = json.dumps({'type': 'error', 'error': {
                'type': 'permission_error',
                'message': 'OAuth token does not meet scope requirement user:profile'}}).encode()
            self.send_response(403)
            self.send_header('x-should-retry', 'false')
        elif self.path == '/boom':
            raw = b'{"error":"server"}'
            self.send_response(500)
        elif self.path == '/multibucket':
            # weekly_percent is the MAX durable bucket (80, five days out). The cheap
            # monthly bucket resets in an hour and says nothing about it.
            import time as _t
            def iso(dt):
                return _t.strftime('%Y-%m-%dT%H:%M:%S+00:00', _t.gmtime(_t.time() + dt))
            raw = json.dumps({'limits': [
                {'kind': 'session', 'percent': 1, 'resets_at': iso(3600), 'scope': None},
                {'kind': 'weekly_all', 'percent': 80, 'resets_at': iso(432000), 'scope': None},
                {'kind': 'monthly_all', 'percent': 10, 'resets_at': iso(3600), 'scope': None}]}).encode()
            self.send_response(200)
        else:
            raw = json.dumps({'limits': [
                {'kind': 'session', 'percent': 3, 'resets_at': '2099-01-01T00:00:00+00:00', 'scope': None},
                {'kind': 'weekly_all', 'percent': 7, 'resets_at': '2099-01-01T00:00:00+00:00', 'scope': None}]}).encode()
            self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(raw)))
        self.end_headers()
        self.wfile.write(raw)
srv = http.server.HTTPServer(('127.0.0.1', 0), H)
print(srv.server_address[1], flush=True)
srv.serve_forever()
EOF
uhits="$WORK/usage-hits"
: > "$uhits"
uport=""
python3 "$usrv" "$uhits" > "$WORK/usage-port" 2>/dev/null &
usrv_pid=$!
STUB_PIDS="$STUB_PIDS $usrv_pid"
for _ in $(seq 1 20); do
  uport="$(head -1 "$WORK/usage-port" 2>/dev/null)"
  case "$uport" in ''|*[!0-9]*) uport=""; sleep 0.2 ;; *) break ;; esac
done
if [ -z "$uport" ]; then
  kill "$usrv_pid" 2>/dev/null; wait "$usrv_pid" 2>/dev/null || true
  t_ok "usage-endpoint refusal tests skipped (cannot bind a loopback port here)"
else
  # A pool in exactly the incident's shape: a portable setup token and NO OAuth grant.
  SD="$WORK/scope-denied-pool"
  mkdir -p "$SD/acct-01" "$SD/acct-02" "$SD/tmp"
  : > "$SD/.limits-kick"
  cat > "$SD/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,"accounts":[
  {"id":"acct-01","email":"sd1@test","home":"mac","added_at":"2026-07-13T00:00:00Z"},
  {"id":"acct-02","email":"sd2@test","home":"mac","added_at":"2026-07-13T00:00:00Z"}]}
EOF
  for i in 01 02; do
    printf 'sk-ant-oat01-SETUPTOKEN%s\n' "$i" > "$SD/acct-$i/server.token"
    chmod 600 "$SD/acct-$i/server.token"
    # Telemetry frozen eleven days ago — exactly what the incident left on disk.
    printf '{"fetched_at":%s,"source":"oauth","max_percent":2,"weekly_percent":2,"session_percent":0,"buckets":[]}' \
      "$((now - 950000))" > "$SD/acct-$i/limits.json"
  done

  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
         claude-accounts limits --force 2>&1)"
  check "a scope-denied 403 names the missing scope" "user:profile" "$out"
  check "a scope-denied 403 names the ceremony that fixes it" "claude-accounts login acct-01" "$out"
  # The CREDENTIAL is refused for good (the digest below stops it being offered
  # again); the ACCOUNT is deliberately NOT parked, because parking it also blocked
  # the OAuth path and froze telemetry for hours on accounts whose login was fine.
  check "a scope-denied 403 retires the token, not the account" \
    "This token will not be offered again" "$out"
  python3 - "$SD/acct-01/limits.json" "$now" <<'EOF'
import json, sys
lim = json.load(open(sys.argv[1]))
now = int(sys.argv[2])
assert lim.get('token_scope_denied'), lim            # THIS token is retired
assert not lim.get('retry_after'), lim               # ...but the account is not parked
assert lim['fetched_at'] == now - 950000, lim        # a FAILURE never invents freshness
EOF
  [ $? -eq 0 ] && t_ok "a refused token is retired without parking the account, keeping its stale fetched_at" \
    || t_fail "403 credential-scoped state" "see $SD/acct-01/limits.json"

  # The whole point: the next scheduled pass must NOT spend another request. Before the
  # fix this retried every five minutes, from every machine, forever.
  before="$(wc -l < "$uhits")"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
         claude-accounts limits 2>&1)"
  after="$(wc -l < "$uhits")"
  [ "$before" = "$after" ] && t_ok "a retired token is not re-offered on the next pass" \
    || t_fail "403 retry storm" "endpoint hit again ($before -> $after requests)"
  # It is the CREDENTIAL that is spent, so the message names the ceremony that
  # replaces it rather than a clock the operator would otherwise sit and watch.
  check "and says what would fix it, not how long to wait" \
    "telemetry stays dark until: claude-accounts login acct-01" "$out"

  # Any other non-2xx backs off too — a 5xx retried every pass is the same storm.
  rm -f "$SD/acct-01/limits.json"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/boom" \
         claude-accounts limits --force 2>&1)"
  check "a 500 backs off as well" "backing off" "$out"
  python3 - "$SD/acct-01/limits.json" <<'EOF'
import json, sys
lim = json.load(open(sys.argv[1]))
assert lim.get('retry_after', 0) > 0 and 'HTTP 500' in lim.get('last_error', ''), lim
assert 'fetched_at' not in lim or not lim['fetched_at'], lim   # never fetched != fresh
EOF
  [ $? -eq 0 ] && t_ok "a 5xx records a backoff without faking a fetch" \
    || t_fail "500 backoff state" "see $SD/acct-01/limits.json"

  # ---- the blind-ranking guard -------------------------------------------------
  # Stale telemetry scores every account the same NEUTRAL value, so pick_best sees one
  # pool-wide tie and selection silently becomes uniform random. It must say so.
  for i in 01 02; do
    printf '{"fetched_at":%s,"source":"oauth","max_percent":2,"weekly_percent":2,"session_percent":0,"buckets":[]}' \
      "$((now - 950000))" > "$SD/acct-$i/limits.json"
  done
  : > "$SD/selection.log"
  CLAUDE_ACCOUNTS_ROOT="$SD" claude >/dev/null 2>&1
  grep -q "ranking=BLIND" "$SD/selection.log" \
    && t_ok "selection.log records that ranking ran blind" \
    || t_fail "blind ranking log" "no ranking=BLIND line: $(tail -1 "$SD/selection.log")"
  grep -qE "ranking=BLIND telemetry-age=[0-9]+s band=30 band-count=[0-9]+ session-gate=50 session-ok=0 pwd=" "$SD/selection.log" \
    && t_ok "the blind line carries both cuts in the standard field order" \
    || t_fail "blind line fields" "$(tail -1 "$SD/selection.log")"
  grep -q "telemetry-age=9[0-9]\{5\}s" "$SD/selection.log" \
    && t_ok "the blind line carries the age of the outage" \
    || t_fail "blind ranking age" "$(tail -1 "$SD/selection.log")"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" claude-accounts status 2>&1)"
  check "status calls a blind pool blind" "RANKING IS BLIND" "$out"
  check "status names the scope that is missing" "user:profile" "$out"
  check "status flags the stale reading itself" "<< STALE" "$out"
  # A panel drives off --json, so the outage has to be a FIELD, not just prose.
  CLAUDE_ACCOUNTS_ROOT="$SD" claude-accounts list --json > "$SD/blind.json" 2>/dev/null
  python3 - "$SD/blind.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['ranking_blind'] is True, d['summary']
assert all(a['usage']['stale'] is True for a in d['accounts']), d['accounts']
EOF
  [ $? -eq 0 ] && t_ok "--json reports the pool-wide blindness and per-account staleness" \
    || t_fail "json blindness" "see $SD/blind.json"

  # ...and telemetry INSIDE the window must still rank. 900s used to be the window,
  # which is below the ~3600s floor the endpoint itself enforces (Retry-After: 3600),
  # so a healthy pool spent most of every hour ranking neutral for no reason.
  # acct-02 is put OUTSIDE the 30-point band (weekly 40 against acct-01's 4) on purpose:
  # inside the band the two are peers and the pick is a coin flip, which would make this
  # assertion about the freshness window flaky for reasons that have nothing to do with it.
  printf '{"fetched_at":%s,"source":"oauth","max_percent":4,"weekly_percent":4,"session_percent":1,"buckets":[]}' \
    "$((now - 1200))" > "$SD/acct-01/limits.json"
  printf '{"fetched_at":%s,"source":"oauth","max_percent":40,"weekly_percent":40,"session_percent":1,"buckets":[]}' \
    "$((now - 1200))" > "$SD/acct-02/limits.json"
  : > "$SD/selection.log"
  CLAUDE_ACCOUNTS_ROOT="$SD" claude >/dev/null 2>&1
  ! grep -q "ranking=BLIND" "$SD/selection.log" \
    && t_ok "20-minute-old telemetry still ranks (window matches the endpoint's own floor)" \
    || t_fail "stale window" "20-minute-old data was treated as blind"
  grep -q "acct-01 weekly=4%" "$SD/selection.log" \
    && t_ok "the pool ranks on real numbers and picks the account with more headroom (4% over 40%)" \
    || t_fail "headroom ranking" "$(tail -1 "$SD/selection.log")"

  # ---- blind does not mean neutral --------------------------------------------
  # Ranking everything NEUTRAL when nothing is fresh throws away information that is
  # still TRUE: a weekly bucket only rises until its reset, so before that moment an
  # old weekly reading remains a valid lower bound. Neutral is only the right answer
  # while some other account has fresh data to be neutral against.
  printf '{"fetched_at":%s,"weekly_percent":81,"session_percent":0,"max_percent":81,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$((now - 950000))" "$((now + 200000))" > "$SD/acct-01/limits.json"
  printf '{"fetched_at":%s,"weekly_percent":4,"session_percent":0,"max_percent":4,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$((now - 950000))" "$((now + 200000))" > "$SD/acct-02/limits.json"
  : > "$SD/selection.log"
  rm -f "$SD/.last-pick"
  for _ in 1 2 3 4 5 6; do CLAUDE_ACCOUNTS_ROOT="$SD" claude >/dev/null 2>&1; done
  if grep -q "acct-01 " "$SD/selection.log"; then
    t_fail "blind ranking still avoids a nearly-exhausted account" \
      "the account stale-reported at 81% weekly was picked: $(grep -c 'acct-01 ' "$SD/selection.log")/6 runs"
  else
    t_ok "blind ranking still avoids a nearly-exhausted account"
  fi
  # DEGRADED, not BLIND: the pool IS still ranking, on readings that remain true. An
  # operator told "random" would go hunting a bug that is not there.
  grep -q "ranking=DEGRADED" "$SD/selection.log" \
    && t_ok "a degraded pick is logged as degraded, not as blind" \
    || t_fail "degraded log" "$(tail -1 "$SD/selection.log")"
  # Session is unknown in a degraded pool, so nobody clears the gate: session-ok=0.
  grep -qE "ranking=DEGRADED telemetry-age=[0-9]+s band=30 band-count=[0-9]+ session-gate=50 session-ok=0 pwd=" "$SD/selection.log" \
    && t_ok "the degraded line carries both cuts in the standard field order" \
    || t_fail "degraded line fields" "$(tail -1 "$SD/selection.log")"
  grep -q "acct-02 weekly=4% .*ranking=DEGRADED" "$SD/selection.log" \
    && t_ok "the degraded line reports the stale reading it actually ranked on" \
    || t_fail "degraded weekly" "$(tail -1 "$SD/selection.log")"

  # ...but a reading whose week has ALREADY reset describes a week that is over. It is
  # worth nothing, and must not be mistaken for a low-usage account.
  printf '{"fetched_at":%s,"weekly_percent":81,"session_percent":0,"max_percent":81,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$((now - 950000))" "$((now + 200000))" > "$SD/acct-01/limits.json"
  printf '{"fetched_at":%s,"weekly_percent":4,"session_percent":0,"max_percent":4,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$((now - 950000))" "$((now - 100))" > "$SD/acct-02/limits.json"
  : > "$SD/selection.log"
  rm -f "$SD/.last-pick"
  for _ in 1 2 3 4 5 6; do CLAUDE_ACCOUNTS_ROOT="$SD" claude >/dev/null 2>&1; done
  grep -q "acct-02 " "$SD/selection.log" \
    && t_ok "an expired weekly reading falls back to neutral instead of reading as 4%" \
    || t_fail "expired weekly reading" "acct-02 never picked, so 81% still outranked an unknown"

  # ---- the recorded horizon belongs to the bucket weekly_percent came from -----
  # Taking the earliest reset across ALL durable buckets would let a 10% monthly bucket
  # resetting in an hour throw away an 80% weekly reading that is good for five days —
  # and that account would then score neutral 50 and beat a neighbour honestly at 60%.
  rm -f "$SD/acct-01/limits.json"
  CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/multibucket" \
    claude-accounts limits --force >/dev/null 2>&1
  python3 - "$SD/acct-01/limits.json" <<'EOF'
import json, sys, time
lim = json.load(open(sys.argv[1]))
assert lim['weekly_percent'] == 80, lim
horizon = lim['weekly_resets_epoch'] - time.time()
assert horizon > 86400, lim   # the 80% bucket's five days, not the monthly bucket's hour
EOF
  [ $? -eq 0 ] && t_ok "the stale-reading horizon tracks the bucket weekly_percent came from" \
    || t_fail "weekly horizon" "see $SD/acct-01/limits.json"

  # ---- an unknown horizon is not comparable, so nobody gets degraded ranking ----
  # A limits.json written before weekly_resets_epoch existed scores NEUTRAL 50 — which
  # would beat a neighbour's true-but-worse 70 and make the degraded path actively
  # wrong. Degraded ranking is therefore all-or-nothing across the candidates.
  printf '{"fetched_at":%s,"weekly_percent":70,"session_percent":0,"max_percent":70,"weekly_resets_epoch":%s,"buckets":[]}' \
    "$((now - 950000))" "$((now + 200000))" > "$SD/acct-01/limits.json"
  printf '{"fetched_at":%s,"weekly_percent":85,"session_percent":0,"max_percent":85,"buckets":[]}' \
    "$((now - 950000))" > "$SD/acct-02/limits.json"     # legacy file: no horizon
  : > "$SD/selection.log"
  rm -f "$SD/.last-pick"
  for _ in 1 2 3 4 5 6; do CLAUDE_ACCOUNTS_ROOT="$SD" claude >/dev/null 2>&1; done
  grep -q "ranking=BLIND" "$SD/selection.log" && ! grep -q "ranking=DEGRADED" "$SD/selection.log" \
    && t_ok "one horizon-less candidate turns degraded ranking off for the whole pool" \
    || t_fail "mixed degraded ranking" "$(tail -1 "$SD/selection.log")"
  grep -q "acct-02 " "$SD/selection.log" \
    && t_ok "with degraded ranking off, the legacy account is still reachable" \
    || t_fail "legacy starvation" "acct-02 never picked in 6 runs"

  # ---- status/--json must agree with the shim, not just with each other --------
  # A status that says "picking at RANDOM" while the shim is ranking on valid stale
  # readings sends an operator after a bug that is not there; a status that says
  # "fine" while the shim is blind is how eleven days went by.
  for i in 01 02; do
    printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":0,"max_percent":%s,"weekly_resets_epoch":%s,"buckets":[]}' \
      "$((now - 950000))" "$((i + 3))" "$((i + 3))" "$((now + 200000))" > "$SD/acct-$i/limits.json"
  done
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" claude-accounts status 2>&1)"
  check "status reports DEGRADED when the shim is degraded" "RANKING IS DEGRADED" "$out"
  CLAUDE_ACCOUNTS_ROOT="$SD" claude-accounts list --json > "$SD/degraded.json" 2>/dev/null
  python3 - "$SD/degraded.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['summary']['telemetry'] == 'degraded', d['summary']
assert d['summary']['ranking_blind'] is False, d['summary']
EOF
  [ $? -eq 0 ] && t_ok "--json reports degraded, and ranking_blind stays false" \
    || t_fail "json degraded" "see $SD/degraded.json"

  # ---- a refused setup token is never spent on this endpoint again -------------
  # The 6h park expires; the refusal does not. Asking again can only 403 and only
  # burns the account's ~1-per-hour budget, which is what made an authorization
  # problem look like a rate limit.
  rm -f "$SD/acct-02/limits.json"
  CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
    claude-accounts limits --force >/dev/null 2>&1
  python3 - "$SD/acct-01/limits.json" <<'EOF'
import json, os, sys
p = sys.argv[1]
d = json.load(open(p))
assert d.get('token_scope_denied'), d             # WHICH token was refused (digest)
d['retry_after'] = 0                             # the park has since expired
json.dump(d, open(p + '.tmp', 'w')); os.replace(p + '.tmp', p)
EOF
  before="$(wc -l < "$uhits")"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
         claude-accounts limits 2>&1)"
  after="$(wc -l < "$uhits")"
  [ "$before" = "$after" ] && t_ok "a token already refused for scope is not offered again" \
    || t_fail "token re-offered" "endpoint hit again ($before -> $after)"
  check "and the message says what would fix it" "claude-accounts login acct-01" "$out"
  # ---- an OAuth account NEVER spends its setup token here, and a token refusal
  # ---- never parks the ACCOUNT ------------------------------------------------
  # Live symptom (my-mini, 2026-08-28): acct-02/acct-05 sat 1-5 HOURS stale with
  # "backing off after HTTP 403 (source=token) — permanent" while their OAuth
  # credentials were fine. The chain: the access token had expired minutes ago, so
  # refresh_oauth declined (REFRESH_MIN_EXPIRED proves no live session owns it),
  # the probe fell through to the setup token, the endpoint refused it for scope,
  # and that parked the whole ACCOUNT for six hours — blocking the OAuth path that
  # would have worked on the very next pass. The shim then ranked the pool on
  # hour-old readings and said so ("usage telemetry is 1h old").
  SD2="$WORK/token-poison"
  mkdir -p "$SD2/acct-01" "$SD2/tmp"
  : > "$SD2/.limits-kick"
  cat > "$SD2/accounts.json" <<EOF
{ "version": 1, "server": "root@203.0.113.1", "server_root": "/root/.claude-accounts",
  "server_repo": "/root/claude-multiacc", "threshold": 90,
  "accounts": [ {"id": "acct-01", "email": "poison@test", "home": "mac",
                 "added_at": "2026-08-28T00:00:00Z"} ] }
EOF
  # An OAuth credential whose ACCESS token expired a moment ago: too recent for
  # refresh_oauth to touch, so this pass has no bearer it may use.
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-justexpired","refreshToken":"r","expiresAt":%s000,"refreshTokenExpiresAt":9999999999999}}' \
    "$((now - 30))" > "$SD2/acct-01/.credentials.json"
  printf 'sk-ant-oat01-PORTABLE0001\n' > "$SD2/acct-01/server.token"
  before="$(wc -l < "$uhits")"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD2" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
         claude-accounts limits 2>&1)"
  after="$(wc -l < "$uhits")"
  [ "$before" = "$after" ] \
    && t_ok "an OAuth account never spends its setup token on the usage endpoint" \
    || t_fail "token spent" "the endpoint was called ($before -> $after) with a token that can only 403"
  check "and it says it will simply retry" "retrying next pass" "$out"
  [ ! -f "$SD2/acct-01/limits.json" ] \
    && t_ok "no six-hour park is written for an account that merely missed a refresh" \
    || t_fail "account parked" "$(cat "$SD2/acct-01/limits.json")"

  # A token-only account still tries once (that is the only way to learn), but the
  # refusal must park the CREDENTIAL, not the account: the digest is remembered and
  # no retry_after is written, so a later OAuth login is free to work immediately.
  rm -f "$SD2/acct-01/.credentials.json" "$SD2/acct-01/limits.json"
  CLAUDE_ACCOUNTS_ROOT="$SD2" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
    claude-accounts limits >/dev/null 2>&1
  python3 - "$SD2/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d.get('token_scope_denied'), d
assert not d.get('retry_after'), f"the account was parked by a credential refusal: {d}"
EOF
  [ $? -eq 0 ] && t_ok "a token scope refusal parks the credential, never the account" \
    || t_fail "token refusal parked the account" "see $SD2/acct-01/limits.json"

  # Re-minting the token is a new credential, so it earns a fresh try.
  printf 'sk-ant-oat01-REMINTED01\n' > "$SD/acct-01/server.token"
  before="$(wc -l < "$uhits")"
  CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/ok" \
    claude-accounts limits >/dev/null 2>&1
  after="$(wc -l < "$uhits")"
  [ "$before" != "$after" ] && t_ok "a newly minted token is tried again" \
    || t_fail "remint not retried" "the new token was never offered"

  # ---- a dead OAuth grant must not park an account whose TOKEN still works -----
  # This is the whole pool's shape after the incident: a working setup token beside a
  # lapsed grant. The shim's auth_dead() reads .expired BEFORE server.token, so parking
  # here would take every working account out of the pool at once — over a credential
  # the pool needs only for telemetry, never for work.
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-x","expiresAt":1000,"refreshTokenExpiresAt":1000}}' \
    > "$SD/acct-01/.credentials.json"
  rm -f "$SD/acct-01/limits.json" "$SD/acct-01/.expired" "$SD/acct-01/.oauth-refresh.json"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-endpoint-missing.json" \
         claude-accounts limits --force 2>&1)"
  [ ! -f "$SD/acct-01/.expired" ] \
    && t_ok "a dead grant never parks an account that still has a working setup token" \
    || t_fail "portable account parked" "$(tail -1 "$SD/acct-01/.expired")"
  check "...and it says telemetry is what is broken, not the account" "TELEMETRY is dead" "$out"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" claude-accounts status 2>&1)"
  check "status keeps it selectable" "selectable  : yes" "$out"
  # ...but with NO token, the same dead grant DOES park it: then nothing can authenticate.
  mv "$SD/acct-01/server.token" "$SD/acct-01/server.token.bak"
  rm -f "$SD/acct-01/limits.json" "$SD/acct-01/.oauth-refresh.json"
  CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-endpoint-missing.json" \
    claude-accounts limits --force >/dev/null 2>&1
  grep -q "reason=refresh-token-expired" "$SD/acct-01/.expired" 2>/dev/null \
    && t_ok "with no token to fall back on, a dead grant still parks the account" \
    || t_fail "dead grant not parked" "no .expired for an account with nothing that authenticates"
  mv "$SD/acct-01/server.token.bak" "$SD/acct-01/server.token"
  rm -f "$SD/acct-01/.expired" "$SD/acct-01/.credentials.json" "$SD/acct-01/.oauth-refresh.json"

  # ---- a live refresh token recovers even from a husk credential ---------------
  # A credential whose ACCESS token was cleared but whose REFRESH token is alive is
  # exactly what a grant exists to recover from. Requiring the dead half to be present
  # meant such an account could never come back — and with a setup token beside it, it
  # went dark for telemetry permanently.
  printf '{"claudeAiOauth":{"accessToken":"","refreshToken":"sk-ant-ort01-live","expiresAt":0,"refreshTokenExpiresAt":9999999999999}}' \
    > "$SD/acct-01/.credentials.json"
  rm -f "$SD/acct-01/limits.json" "$SD/acct-01/.oauth-refresh.json" "$SD/acct-01/.expired"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" \
         CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/ok" claude-accounts limits --force 2>&1)"
  check "a husk credential with a live refresh token is refreshed" "refreshed via refresh-token grant" "$out"
  python3 -c "import json,sys; sys.exit(0 if json.load(open('$SD/acct-01/limits.json'))['source']=='oauth' else 1)" \
    && t_ok "...and telemetry comes back on the OAuth bearer" \
    || t_fail "husk recovery" "source != oauth"

  # ---- a credential rotated mid-flight by someone else is never overwritten -----
  # The grant rotates; a live claude session refreshes the same file. Losing that race
  # by overwriting destroys the session's newer credential and strands the account.
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-MINE","expiresAt":1000,"refreshTokenExpiresAt":9999999999999}}' \
    > "$SD/acct-01/.credentials.json"
  rm -f "$SD/acct-01/limits.json" "$SD/acct-01/.oauth-refresh.json"
  # token-ok.json is a file:// fixture, so the "other writer" can land while the grant
  # is in flight simply by writing a different refresh token first.
  cat > "$SD/racer.sh" <<'RACER'
#!/usr/bin/env bash
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-SESSION","refreshToken":"sk-ant-ort01-THEIRS","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$1"
RACER
  chmod +x "$SD/racer.sh"
  "$SD/racer.sh" "$SD/acct-01/.credentials.json.race"
  # simulate: the grant was issued against MINE, but THEIRS is what is on disk now
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-old","refreshToken":"sk-ant-ort01-MINE","expiresAt":1000,"refreshTokenExpiresAt":9999999999999}}' \
    > "$SD/acct-01/.credentials.json"
  ( sleep 0.1; cp "$SD/acct-01/.credentials.json.race" "$SD/acct-01/.credentials.json" ) &
  racer_pid=$!
  CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" \
    CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/ok" claude-accounts limits --force >/dev/null 2>&1
  wait "$racer_pid" 2>/dev/null || true
  grep -q "sk-ant-ort01-THEIRS" "$SD/acct-01/.credentials.json" \
    && t_ok "a credential rotated by another writer survives our refresh" \
    || t_ok "refresh committed before the other writer landed (race not exercised)"
  rm -f "$SD/acct-01/.credentials.json" "$SD/acct-01/.credentials.json.race" "$SD/racer.sh" \
        "$SD/acct-01/.oauth-refresh.json" "$SD/acct-01/.expired"

  # ---- an org block is never downgraded by a weaker reason ---------------------
  # clear_expired refuses to lift an org block, but nothing stopped mark_expired from
  # REWRITING its reason — after which the next successful fetch lifts it happily.
  printf '%s\nreason=org-blocked marked_at=now detail=test\n' "$now" > "$SD/acct-01/.expired"
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-x","refreshToken":"sk-ant-ort01-x","expiresAt":1000,"refreshTokenExpiresAt":1000}}' \
    > "$SD/acct-01/.credentials.json"
  rm -f "$SD/acct-01/limits.json"
  CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/ok" \
    claude-accounts limits --force >/dev/null 2>&1
  grep -q "reason=org-blocked" "$SD/acct-01/.expired" 2>/dev/null \
    && t_ok "a dead refresh grant never overwrites an org-blocked marker" \
    || t_fail "org block downgraded" "marker is now: $(cat "$SD/acct-01/.expired" 2>/dev/null | tail -1)"
  rm -f "$SD/acct-01/.expired" "$SD/acct-01/.credentials.json"

  # ---- the >=90% cutoff keeps the TIGHT window --------------------------------
  # Ranking may trust an hour-old number; declaring an account UNUSABLE may not. The
  # cutoff window is EXCLUDE_STALE_AFTER (900s), so this is tested on both sides of it.
  # acct-01 is deliberately the BEST-RANKING account (weekly 1%) while being over the
  # threshold on its session bucket (max 91%). So it is picked whenever it is eligible,
  # and skipped only when the cutoff actually fires — which isolates the cutoff window
  # from the ranking window instead of conflating "excluded" with "outranked".
  # BOTH sessions sit above the 50-point session gate (91 and 55) deliberately: with
  # acct-02 inside the gate it would be the only gated candidate and win on the gate
  # alone, and these assertions would then be measuring the gate instead of the cutoff
  # window. Nobody clearing the gate makes it step aside, so weekly alone ranks here.
  mk_cutoff_pool() { # $1 = age of both readings, in seconds
    # A FRESH clock, not the suite-wide $now captured at startup: the 800s case leaves
    # only 100s of headroom inside the 900s cutoff window, and the suite takes longer
    # than that to get here — under load (2026-09-04, parallel review agents) the reading
    # aged past the window and the assertion flipped. Ages here must mean age AT THE
    # SHIM'S OWN CLOCK, whenever this test happens to run.
    local now; now="$(date -u +%s)"
    printf '{"fetched_at":%s,"weekly_percent":1,"session_percent":91,"max_percent":91,"weekly_resets_epoch":%s,"buckets":[]}' \
      "$((now - $1))" "$((now + 200000))" > "$SD/acct-01/limits.json"
    printf '{"fetched_at":%s,"weekly_percent":50,"session_percent":55,"max_percent":55,"weekly_resets_epoch":%s,"buckets":[]}' \
      "$((now - $1))" "$((now + 200000))" > "$SD/acct-02/limits.json"
    : > "$SD/selection.log"
    rm -f "$SD/.last-pick"
    local _i
    for _i in 1 2 3 4; do CLAUDE_ACCOUNTS_ROOT="$SD" claude >/dev/null 2>&1; done
  }
  mk_cutoff_pool 800     # inside the 900s cutoff window
  ! grep -q "acct-01 " "$SD/selection.log" \
    && t_ok "a 91% reading inside the cutoff window excludes the account" \
    || t_fail "threshold exclusion" "a 91% account was selected on 800s-old data"
  mk_cutoff_pool 1000    # past the cutoff window, still inside the RANKING window
  grep -q "acct-01 " "$SD/selection.log" \
    && t_ok "past the cutoff window a 91% reading no longer excludes (fail open)" \
    || t_fail "cutoff fail-open" "a 1000s-old 91% reading still excluded the account"
  ! grep -qE "ranking=(BLIND|DEGRADED)" "$SD/selection.log" \
    && t_ok "...but it is still fresh enough to RANK on (the two windows differ)" \
    || t_fail "ranking window" "1000s-old data was treated as unrankable"
  grep -q "acct-01 weekly=1%" "$SD/selection.log" \
    && t_ok "and ranking still prefers the account with more weekly headroom" \
    || t_fail "ranking preference" "$(tail -1 "$SD/selection.log")"

  # ---- one corrupt limits.json costs exactly one account ----------------------
  # `[]` is valid JSON. Every prev.get() in the refresher would raise on it, OUTSIDE
  # the per-account try — starving every account after it, which is the same pool-wide
  # telemetry blackout this whole section is about.
  printf '[]' > "$SD/acct-01/limits.json"
  rm -f "$SD/acct-02/limits.json"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/ok" \
         claude-accounts limits --force 2>&1)"
  rc=$?
  [ "$rc" = "0" ] && t_ok "a limits.json that is not an object exits 0" || t_fail "corrupt limits rc" "rc=$rc: $out"
  [ -s "$SD/acct-02/limits.json" ] \
    && t_ok "accounts after a corrupt limits.json still refresh" \
    || t_fail "corrupt limits starves the loop" "acct-02 was never fetched"

  # status must survive the same file — it is the one command that reports the outage.
  printf '{"fetched_at":"yesterday"}' > "$SD/acct-01/limits.json"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" claude-accounts status 2>&1)"
  rc=$?
  [ "$rc" = "0" ] && t_ok "status survives a limits.json with a non-numeric fetched_at" \
    || t_fail "status crash" "rc=$rc: $(printf '%s' "$out" | tail -3)"
  check "status still reaches the accounts after the corrupt one" "acct-02" "$out"

  # A successful fetch must clear the whole backoff record, or one bad hour would keep
  # an account parked long after the endpoint came back.
  printf '{"fetched_at":%s,"weekly_percent":2,"session_percent":0,"max_percent":2,"buckets":[]}' \
    "$((now - 950000))" > "$SD/acct-01/limits.json"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/scope-denied" \
         claude-accounts limits --force 2>&1)"
  out="$(CLAUDE_ACCOUNTS_ROOT="$SD" CLAUDE_MULTIACC_USAGE_URL="http://127.0.0.1:$uport/ok" \
         claude-accounts limits --force 2>&1)"
  python3 - "$SD/acct-01/limits.json" <<'EOF'
import json, sys
lim = json.load(open(sys.argv[1]))
assert 'retry_after' not in lim and 'last_error' not in lim, lim
assert lim['weekly_percent'] == 7 and lim['session_percent'] == 3, lim
EOF
  [ $? -eq 0 ] && t_ok "a successful fetch drops every trace of the backoff" \
    || t_fail "backoff cleared" "see $SD/acct-01/limits.json"
  kill "$usrv_pid" 2>/dev/null; wait "$usrv_pid" 2>/dev/null || true
fi

# ---- 16b8. malformed claudeAiOauth (null) degrades that account ONLY (fail open) -------
# {"claudeAiOauth": null} is valid JSON from an interrupted/reset credential write; it
# must not abort the refresher — accounts AFTER it in the manifest must still be fetched.
# acct-01 is first in the manifest, so corrupting it exercises the loop guarantee.
cp "$ACC/acct-01/.credentials.json" "$WORK/acct01-creds.bak"
printf '{"claudeAiOauth": null}' > "$ACC/acct-01/.credentials.json"
rm -f "$ACC/acct-01/limits.json" "$ACC/acct-01/.oauth-refresh.json" "$ACC/acct-02/limits.json"
out="$(CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "null claudeAiOauth exits 0 (fail open)" || t_fail "null claudeAiOauth rc" "rc=$rc: $out"
check "null claudeAiOauth degrades only that account" "acct-01: no fresh bearer" "$out"
[ -f "$ACC/acct-02/limits.json" ] && t_ok "accounts after a malformed one still refresh" \
  || t_fail "fail-open loop guarantee" "acct-02 was starved by acct-01's malformed creds"
cp "$WORK/acct01-creds.bak" "$ACC/acct-01/.credentials.json"
claude-accounts remove acct-05 --yes >/dev/null 2>&1

# ---- 16c. codex-review: security hardening -----------------------------------------
# path traversal via a hand-edited manifest id must never touch the filesystem
mkdir -p "$WORK/canary" && : > "$WORK/canary/DO_NOT_DELETE"
cp "$ACC/accounts.json" "$WORK/manifest.bak"
python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['accounts'].append({'id': '../canary', 'email': 'evil@test', 'home': 'mac'})
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
out="$(claude-accounts remove ../canary --yes 2>&1)"
rc=$?
[ -f "$WORK/canary/DO_NOT_DELETE" ] && t_ok "remove refuses path-traversal id (no deletion)" \
  || t_fail "path traversal" "remove ../canary DELETED files outside the pool"
[ "$rc" != "0" ] && t_ok "traversal id rejected nonzero" || t_fail "traversal rc" "rc=0"
claude-accounts list 2>&1 | grep -q "\.\./canary" \
  && t_fail "invalid ids filtered from listings" "traversal id surfaced" \
  || t_ok "invalid manifest ids are filtered out"
cp "$WORK/manifest.bak" "$ACC/accounts.json"

# sync is Mac-only (source of truth); its input-validation guards can only be exercised
# on Darwin. On Linux `sync` refuses up front, so skip with a note rather than fail.
if [ "$(uname -s)" = "Darwin" ]; then
  # remote command injection via manifest server_root
  python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['server_root'] = "/tmp/x'; touch /tmp/multiacc_PWNED; #"
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  rm -f /tmp/multiacc_PWNED
  out="$(CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  [ ! -f /tmp/multiacc_PWNED ] && t_ok "sync rejects injected server_root (no command executed)" \
    || { t_fail "command injection" "server_root injection EXECUTED"; rm -f /tmp/multiacc_PWNED; }
  check "injected server_root refused" "not a plain absolute path" "$out"
  cp "$WORK/manifest.bak" "$ACC/accounts.json"

  # accountless manifest must not blank the server pool
  python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1])); d['accounts'] = []
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  out="$(CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  check "empty manifest refuses to sync" "refusing to blank the target pools" "$out"
  [ "$rc" != "0" ] && t_ok "empty-manifest sync exits nonzero" || t_fail "empty sync rc" "rc=0"
  cp "$WORK/manifest.bak" "$ACC/accounts.json"

  # a REPLICA pool never pushes (side file, not manifest — the manifest is what
  # gets pushed TO replicas)
  printf 'replica\n' > "$ACC/sync-role"
  out="$(CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  check "replica pool refuses to push" "sync replica" "$out"
  [ "$rc" = "0" ] && t_ok "replica sync exits 0 (informational, not an error)" || t_fail "replica sync rc" "rc=$rc"
  # ...and auto_sync (after a mutation) is silent about it
  out="$(CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts import replica-test@x --id acct-31 --no-sync 2>&1
         CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts remove acct-31 --yes 2>&1)"
  case "$out" in *"sync failed"*) t_fail "replica auto_sync" "a replica mutation warned about sync: $out" ;;
    *) t_ok "replica auto_sync is silent (no push, no warning)" ;; esac
  rm -f "$ACC/sync-role"

  # peer targets are validated with the same injection guards as the primary.
  # A fake ssh/rsync harness (prepended to PATH only for these calls) records every
  # remote invocation, so "nothing pushed" and "both targets pushed, in order" are
  # verified from the actual command stream, not inferred from silence.
  SSHFAKE="$WORK/sshfake"
  SSHLOG="$WORK/sshfake.log"
  mkdir -p "$SSHFAKE"
  # Both fakes DRAIN stdin like the real tools do: ssh forwards it to the remote
  # command and rsync's transport reads it. A fake that left stdin alone hid the
  # bug where the peer loop fed them its own peer list.
  cat > "$SSHFAKE/ssh" <<'EOF'
#!/usr/bin/env bash
printf 'ssh %s\n' "$*" >> "${SSHLOG:?}"
[ -t 0 ] || cat >/dev/null
case "$*" in *"${SSH_FAIL_HOST:-@@none@@}"*) exit 1 ;; esac
exit 0
EOF
  cat > "$SSHFAKE/rsync" <<'EOF'
#!/usr/bin/env bash
printf 'rsync %s\n' "$*" >> "${SSHLOG:?}"
[ -t 0 ] || cat >/dev/null
exit 0
EOF
  chmod +x "$SSHFAKE/ssh" "$SSHFAKE/rsync"
  export SSHLOG

  python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['peers'] = [{'target': "gas@peer; touch /tmp/multiacc_PEER_PWNED", 'root': '/tmp/x', 'repo': '/tmp/y'}]
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  rm -f /tmp/multiacc_PEER_PWNED
  : > "$SSHLOG"
  out="$(PATH="$SSHFAKE:$PATH" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  check "injected peer target refused" "peer target is not a plain user@host" "$out"
  [ "$rc" != "0" ] && t_ok "bad peer exits nonzero" || t_fail "peer validation rc" "rc=0"
  [ ! -s "$SSHLOG" ] && t_ok "bad peer: nothing pushed anywhere (no ssh/rsync ran)" \
    || t_fail "peer pre-validation" "remote commands ran before peer validation: $(head -2 "$SSHLOG")"
  [ ! -f /tmp/multiacc_PEER_PWNED ] && t_ok "peer injection never executed" \
    || { t_fail "peer injection" "peer target injection EXECUTED"; rm -f /tmp/multiacc_PEER_PWNED; }
  cp "$WORK/manifest.bak" "$ACC/accounts.json"

  # a MALFORMED peer entry (missing fields / not an object) is fatal, never skipped
  python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['peers'] = [{'root': '/tmp/x', 'repo': '/tmp/y'}]   # no target
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  out="$(PATH="$SSHFAKE:$PATH" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  check "peer with missing field is fatal, not skipped" "incomplete" "$out"
  [ "$rc" != "0" ] && t_ok "incomplete peer exits nonzero" || t_fail "incomplete peer rc" "rc=0"
  python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['peers'] = ["gas@peer"]   # not an object
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  out="$(PATH="$SSHFAKE:$PATH" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  check "non-object peer entry is fatal" "malformed" "$out"
  cp "$WORK/manifest.bak" "$ACC/accounts.json"

  # a SUCCESSFUL multi-target sync pushes primary first, then the peer — verified
  # from the recorded command stream
  python3 - "$ACC/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['peers'] = [{'target': 'gas@peer1', 'root': '/Users/gas/.claude-accounts', 'repo': '/Users/gas/claude-multiacc'},
              {'target': 'gas@peer2', 'root': '/Users/gas/.claude-accounts', 'repo': '/Users/gas/claude-multiacc'},
              {'target': 'gas@peer3', 'root': '/Users/gas/.claude-accounts', 'repo': '/Users/gas/claude-multiacc'}]
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  : > "$SSHLOG"
  out="$(PATH="$SSHFAKE:$PATH" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  [ "$rc" = "0" ] && t_ok "multi-target sync succeeds" || t_fail "multi-target sync" "rc=$rc: $out"
  check "multi-target sync reports every peer" "+ 3 peer(s)" "$out"
  # EVERY peer is pushed, not just the first: the ssh/rsync inside the loop must not
  # be allowed to eat the peer list off stdin (mini-3..8 got nothing for 18 days).
  grep -q "rsync.*gas@peer2:/Users/gas/.claude-accounts/accounts.json" "$SSHLOG" \
    && grep -q "rsync.*gas@peer3:/Users/gas/.claude-accounts/accounts.json" "$SSHLOG" \
    && t_ok "the second and third peers are pushed too (stdin not eaten by the first)" \
    || t_fail "later peers skipped" "$(grep -c 'accounts.json' "$SSHLOG") manifest pushes: $(grep accounts.json "$SSHLOG" | tr '\n' '|')"
  grep -q "rsync.*root@203.0.113.1:/root/.claude-accounts/accounts.json" "$SSHLOG" \
    && grep -q "rsync.*gas@peer1:/Users/gas/.claude-accounts/accounts.json" "$SSHLOG" \
    && t_ok "manifest pushed to BOTH targets" \
    || t_fail "multi-target pushes" "missing a manifest push: $(grep accounts.json "$SSHLOG")"
  first_primary="$(grep -n "root@203.0.113.1" "$SSHLOG" | head -1 | cut -d: -f1)"
  first_peer="$(grep -n "gas@peer1" "$SSHLOG" | head -1 | cut -d: -f1)"
  [ -n "$first_primary" ] && [ -n "$first_peer" ] && [ "$first_primary" -lt "$first_peer" ] \
    && t_ok "primary target pushed before the peer" \
    || t_fail "target order" "primary=$first_primary peer=$first_peer"
  n_remov="$(grep -c "for dd in acct-" "$SSHLOG")"
  [ "$n_remov" = "4" ] && t_ok "removal propagation ran on each target" \
    || t_fail "per-target removal" "expected 4 removal sweeps, saw $n_remov"
  grep -q "post-sync" "$SSHLOG" && t_ok "post-sync hooks invoked" || t_fail "post-sync hooks" "none recorded"
  # The MCP registry rides with the manifest to EVERY target; the machine-local overlay
  # (a runner daemon's view of THIS Mac) never leaves. Without a registry file nothing
  # about it is pushed, so a target's own registry is never blanked.
  grep -q "mcp-servers" "$SSHLOG" \
    && t_fail "registry push without a registry" "pushed a registry that does not exist: $(grep mcp-servers "$SSHLOG")" \
    || t_ok "no registry file => no registry push"
  printf '{"version":1,"mcpServers":{"regsync":{"type":"stdio","command":"echo","args":["hi"],"env":{}}},"retired":[],"projects":{}}\n' \
    > "$ACC/mcp-servers.json"
  printf '{"version":1,"owners":{"panel":{"mcpServers":{"local-only":{"type":"stdio","command":"true","args":[],"env":{}}},"retired":[]}}}\n' \
    > "$ACC/mcp-servers.local.json"
  : > "$SSHLOG"
  out="$(PATH="$SSHFAKE:$PATH" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  [ "$rc" = "0" ] && t_ok "sync with a registry succeeds" || t_fail "registry sync" "rc=$rc: $out"
  grep -q "rsync.*mcp-servers.json root@203.0.113.1:/root/.claude-accounts/mcp-servers.json" "$SSHLOG" \
    && grep -q "rsync.*mcp-servers.json gas@peer1:/Users/gas/.claude-accounts/mcp-servers.json" "$SSHLOG" \
    && t_ok "the MCP registry is pushed to BOTH targets" \
    || t_fail "registry push" "$(grep mcp-servers "$SSHLOG")"
  grep -q "mcp-servers.local.json" "$SSHLOG" \
    && t_fail "overlay push" "the machine-local overlay was pushed: $(grep local.json "$SSHLOG")" \
    || t_ok "the machine-local overlay is never pushed"
  rm -f "$ACC/mcp-servers.json" "$ACC/mcp-servers.local.json"
  for _d in "$ACC"/acct-*; do rm -f "$_d/.mcp-applied"; done
  # a primary failure aborts the WHOLE sync: the peer is never contacted
  : > "$SSHLOG"
  out="$(PATH="$SSHFAKE:$PATH" SSH_FAIL_HOST="root@203.0.113.1" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  rc=$?
  [ "$rc" != "0" ] && t_ok "primary failure fails the sync" || t_fail "fail-fast rc" "rc=0"
  check "primary failure is loud" "cannot reach" "$out"
  grep -q "gas@peer1" "$SSHLOG" \
    && t_fail "fail-fast" "the peer was contacted after the primary failed" \
    || t_ok "peer not contacted after a primary failure"
  cp "$WORK/manifest.bak" "$ACC/accounts.json"

  # only an EXACT 'replica' value suppresses sync ('not-replica' must still push)
  printf 'not-replica\n' > "$ACC/sync-role"
  out="$(PATH="$SSHFAKE:$PATH" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
  case "$out" in *"sync replica"*) t_fail "replica anchor" "'not-replica' suppressed sync" ;;
    *"sync ok"*) t_ok "only an exact 'replica' value suppresses sync" ;;
    *) t_fail "replica anchor" "unexpected: $out" ;; esac
  rm -f "$ACC/sync-role"
else
  t_ok "sync validation tests skipped (Mac-only feature; server refuses sync by design)"
fi

# ---- 16d. every limits pass fans telemetry out to the manifest's peers ---------------
# Why this has teeth (2026-09-04): the runner Macs mini-3..mini-8 hold only portable
# setup tokens, and the usage endpoint refuses those for good (403, no user:profile), so
# the ONLY telemetry they can ever rank on is the source machine's. limits_distribute
# pushes limits.json + .limited to the manifest's `server` AND to every entry in `peers`
# — nothing had ever proven the peer half, and it is the half that decides whether six
# machines rank blind. Not Mac-gated like `sync`: a fake rsync on PATH records the argv
# and the --files-from list (the caller deletes that list as soon as the last push
# returns, so it is read at invocation time, not afterwards).
DPOOL="$WORK/distribute-pool"
mkdir -p "$DPOOL/acct-01" "$DPOOL/acct-02" "$DPOOL/tmp"
: > "$DPOOL/.limits-kick"
cat > "$DPOOL/accounts.json" <<'EOF'
{"version":1,"server":"root@203.0.113.9","server_root":"/root/.claude-accounts",
 "server_repo":"/root/claude-multiacc","threshold":90,
 "peers":[
   {"target":"gas@mini-3","root":"/Users/gas/.claude-accounts","repo":"/Users/gas/claude-multiacc"},
   {"target":"gas@mini-4","root":"/Users/gas/.claude-accounts","repo":"/Users/gas/claude-multiacc"}],
 "accounts":[
   {"id":"acct-01","email":"dp1@test","home":"mac","added_at":"2026-07-13T00:00:00Z"},
   {"id":"acct-02","email":"dp2@test","home":"mac","added_at":"2026-07-13T00:00:00Z"}]}
EOF
for i in 01 02; do
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dp%s","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' \
    "$i" > "$DPOOL/acct-$i/.credentials.json"
done
# an exclusion marker rides along with the readings (this one survives a clean pass)
printf '%s\nbucket=error-cooldown percent=? reason=error-cooldown\n' "$(( $(date +%s) + 600 ))" \
  > "$DPOOL/acct-02/.limited"
RSFAKE="$WORK/rsyncfake"
export RSLOG="$WORK/rsync-push.log"
mkdir -p "$RSFAKE"
cat > "$RSFAKE/rsync" <<'EOF'
#!/usr/bin/env bash
printf 'RSYNC %s\n' "$*" >> "${RSLOG:?}"
printf 'PGID %s\n' "$(ps -o pgid= -p $$ | tr -d ' ')" >> "$RSLOG"
for a in "$@"; do
  case "$a" in
    --files-from=*)
      while IFS= read -r l; do printf 'FILE %s\n' "$l" >> "$RSLOG"; done < "${a#--files-from=}" ;;
  esac
done
exit 0
EOF
chmod +x "$RSFAKE/rsync"
: > "$RSLOG"
PATH="$RSFAKE:$PATH" CLAUDE_ACCOUNTS_ROOT="$DPOOL" \
  CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force --quiet
# The push is deliberately DETACHED — a sleeping peer must never delay the next refresh —
# so wait for it instead of assuming it finished.
waited=0
while [ "$waited" -lt 50 ] && [ "$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)" -lt 3 ]; do
  sleep 0.2; waited=$((waited + 1))
done
# The pushes are serialized by a lock dir, so a slow peer can never stack them up. Let
# it drain before the next case, or that case's push would be dropped, not made.
dp_drain() {
  local w=0
  while [ "$w" -lt 50 ] && [ -d "$DPOOL/tmp/limits-push.lock" ]; do sleep 0.2; w=$((w + 1)); done
}
dp_drain
n_push="$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)"
[ "$n_push" = "3" ] && t_ok "a limits pass pushes once per target (server + 2 peers)" \
  || t_fail "limits distribute" "expected 3 rsync calls, saw $n_push: $(tr '\n' '|' < "$RSLOG")"
grep -q "^RSYNC .*root@203.0.113.9:/root/.claude-accounts/" "$RSLOG" \
  && t_ok "telemetry is pushed to the manifest server" \
  || t_fail "limits distribute server" "$(grep '^RSYNC' "$RSLOG")"
for peer in gas@mini-3 gas@mini-4; do
  grep -q "^RSYNC .*$peer:/Users/gas/.claude-accounts/" "$RSLOG" \
    && t_ok "telemetry is pushed to manifest peer $peer" \
    || t_fail "limits distribute peer" "$peer never received a push: $(grep '^RSYNC' "$RSLOG")"
done
# The push must run OUTSIDE the calling job's process group: launchd kills that group
# the moment `limits` exits, and a `( … & )` subshell is still in it — on 2026-09-08 the
# source Mac refreshed every 15 minutes while every scheduled push died before its first
# rsync, and the seven runner Macs ranked on 21:13Z readings until 01:10Z the next day.
own_pgid="$(ps -o pgid= -p $$ | tr -d ' ')"
push_pgids="$(grep '^PGID ' "$RSLOG" | sort -u | sed 's/^PGID //' | tr '\n' ' ')"
case " $push_pgids " in
  *" $own_pgid "*) t_fail "detached push session" "a push ran inside the caller's process group $own_pgid (launchd would kill it)" ;;
  *) [ -n "$push_pgids" ] && t_ok "the telemetry push runs in its own session, outside the job's process group" \
       || t_fail "detached push session" "no push recorded a process group" ;;
esac
grep -q "limits distributed to 3 target(s), 0 failed" "$DPOOL/sync.log" \
  && t_ok "every distribute pass records its outcome in sync.log" \
  || t_fail "distribute summary" "sync.log: $(tail -3 "$DPOOL/sync.log" 2>/dev/null | tr '\n' '|')"
[ "$(grep -c '<key>AbandonProcessGroup</key><true/>' "$REPO_DIR/install.sh")" = "2" ] \
  && t_ok "install.sh abandons the process group of both limits agents" \
  || t_fail "AbandonProcessGroup" "expected both limits plists to carry AbandonProcessGroup"
# ...and every target gets the SAME list: each account's reading, plus any marker.
for f in "acct-01/limits.json" "acct-02/limits.json" "acct-02/.limited"; do
  [ "$(grep -c "^FILE $f\$" "$RSLOG")" = "3" ] \
    && t_ok "the pushed file list names $f for all three targets" \
    || t_fail "limits distribute file list" "$f appears $(grep -c "^FILE $f\$" "$RSLOG")x, want 3"
done

# A REPLICA receives telemetry and must never push it back: two writers racing over one
# pool is last-writer-wins chaos, and a manifest carrying `peers` is itself pushed TO the
# replicas — so the role marker is a machine-local side file, checked before anything else.
printf 'replica\n' > "$DPOOL/sync-role"
: > "$RSLOG"
PATH="$RSFAKE:$PATH" CLAUDE_ACCOUNTS_ROOT="$DPOOL" \
  CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force --quiet
sleep 1
[ ! -s "$RSLOG" ] && t_ok "a replica pool never pushes telemetry (limits_distribute is a no-op)" \
  || t_fail "replica distribute" "a replica pushed: $(tr '\n' '|' < "$RSLOG")"
# only an EXACT 'replica' suppresses it — same anchor as sync
printf 'not-replica\n' > "$DPOOL/sync-role"
: > "$RSLOG"
PATH="$RSFAKE:$PATH" CLAUDE_ACCOUNTS_ROOT="$DPOOL" \
  CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force --quiet
waited=0
while [ "$waited" -lt 50 ] && [ "$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)" -lt 3 ]; do
  sleep 0.2; waited=$((waited + 1))
done
dp_drain
[ "$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)" = "3" ] \
  && t_ok "only an exact 'replica' value suppresses the telemetry push" \
  || t_fail "replica anchor (distribute)" "'not-replica' suppressed the push"
rm -f "$DPOOL/sync-role"
# The MCP registry rides along with the telemetry, so a server the shim mirrored from a
# stock 'claude mcp add' reaches every peer within one limits cadence. The overlay does not.
printf '{"version":1,"mcpServers":{"ride":{"type":"stdio","command":"echo","args":["hi"],"env":{}}},"retired":[],"projects":{}}\n' \
  > "$DPOOL/mcp-servers.json"
printf '{"version":1,"owners":{"panel":{"mcpServers":{},"retired":[]}}}\n' > "$DPOOL/mcp-servers.local.json"
: > "$RSLOG"
PATH="$RSFAKE:$PATH" CLAUDE_ACCOUNTS_ROOT="$DPOOL" \
  CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force --quiet
waited=0
while [ "$waited" -lt 50 ] && [ "$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)" -lt 3 ]; do
  sleep 0.2; waited=$((waited + 1))
done
dp_drain
[ "$(grep -c '^FILE mcp-servers.json$' "$RSLOG")" = "3" ] \
  && t_ok "the MCP registry rides along with the telemetry push to all three targets" \
  || t_fail "registry in limits push" "mcp-servers.json listed $(grep -c '^FILE mcp-servers.json$' "$RSLOG")x, want 3: $(grep FILE "$RSLOG" | tr '\n' '|')"
grep -q '^FILE mcp-servers.local.json$' "$RSLOG" \
  && t_fail "overlay in limits push" "the machine-local overlay was pushed" \
  || t_ok "the machine-local overlay never rides along"
rm -f "$DPOOL/mcp-servers.json" "$DPOOL/mcp-servers.local.json"

# ---- 16d-lock. a distribute lock is honored while it is alive, broken once it is not -
# The push serializes on a lock DIRECTORY, and a detached push that is killed (logout,
# reboot, pkill) never runs its EXIT trap. `mkdir "$lock" || return 0` can then never
# succeed again: on the live pool one stranded lock stopped ALL telemetry distribution
# from 2026-09-03 00:29 until it was removed by hand on 2026-09-04 — 32 hours in which
# every peer ranked on whatever limits.json it happened to already have, which is the
# blindness this push exists to prevent, and nothing anywhere said so. A push is seconds
# of rsync under hard timeouts, so a lock older than ten minutes belongs to a process
# that is gone.
: > "$RSLOG"
: > "$DPOOL/sync.log"
rm -rf "$DPOOL/tmp/limits-push.lock"
mkdir -p "$DPOOL/tmp/limits-push.lock"
touch -t 202001010000 "$DPOOL/tmp/limits-push.lock"      # abandoned in 2020, not busy
PATH="$RSFAKE:$PATH" CLAUDE_ACCOUNTS_ROOT="$DPOOL" \
  CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force --quiet
waited=0
while [ "$waited" -lt 50 ] && [ "$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)" -lt 3 ]; do
  sleep 0.2; waited=$((waited + 1))
done
dp_drain
[ "$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)" = "3" ] \
  && t_ok "a stale limits-push lock is broken and the pass distributes anyway" \
  || t_fail "stale distribute lock" "expected 3 rsync calls, saw $(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null)"
grep -q "stale limits-push lock broken" "$DPOOL/sync.log" \
  && t_ok "breaking the lock is recorded, so a recurrence is visible instead of silent" \
  || t_fail "stale lock log" "sync.log: $(tail -3 "$DPOOL/sync.log" 2>/dev/null | tr '\n' '|')"
[ ! -d "$DPOOL/tmp/limits-push.lock" ] \
  && t_ok "the retaken lock is released at the end of the push, not leaked again" \
  || t_fail "stale lock retake" "the lock dir is still present after the push"

# ...and a lock that a LIVE push is holding is still absolute: two rsyncs racing into one
# peer is exactly what the lock exists to stop, so a fresh one skips this pass entirely.
: > "$RSLOG"
mkdir -p "$DPOOL/tmp/limits-push.lock"                   # mtime = now: someone is pushing
PATH="$RSFAKE:$PATH" CLAUDE_ACCOUNTS_ROOT="$DPOOL" \
  CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force --quiet
sleep 1
{ [ ! -s "$RSLOG" ] && [ -d "$DPOOL/tmp/limits-push.lock" ]; } \
  && t_ok "a fresh distribute lock is honored: no push, and the lock is left where it was" \
  || t_fail "live distribute lock" "pushes=$(grep -c '^RSYNC ' "$RSLOG" 2>/dev/null) lock=$([ -d "$DPOOL/tmp/limits-push.lock" ] && echo held || echo REMOVED)"
rm -rf "$DPOOL/tmp/limits-push.lock"
unset RSLOG

# API keys are never accepted as credentials (subscription-only requirement)
printf 'sk-ant-api03-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' > "$WORK/apikey.txt"
out="$(claude-accounts import apikey@test --id acct-11 --token-file "$WORK/apikey.txt" --no-sync 2>&1)"
rc=$?
check "import rejects an API key as token" "not a subscription setup-token" "$out"
[ ! -d "$ACC/acct-11" ] && t_ok "API-key import created nothing" || t_fail "apikey import" "acct-11 created"
out="$(printf 'sk-ant-api03-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ' | claude-accounts mint acct-01 --paste 2>&1)"
check "mint --paste rejects an API key" "not a subscription setup-token" "$out"

# ---- 17a2. a CLI that cannot run is not a dead login ----------------------------------
# health.log 2026-08-24T06:37:02Z: all four accounts FAIL rc=127
# err='env: node: No such file or directory'. One broken PATH reddened the whole
# verify matrix, and it escaped parking only because that string happens not to
# match AUTH_ERR — which matches a bare `401`, so a node stack frame carrying one
# is enough. `mark_expired` writes no soft stamp, so such a park is permanent,
# and the panel then refuses to re-import the token until its fingerprint changes.
rm -f "$ACC/acct-01/.expired"
printf 'brokencli:acct-01\n' > "$WORK/ctl-brokencli"
out="$(FAKE_CTL="$WORK/ctl-brokencli" claude-accounts verify 2>&1)"
check "a broken CLI is reported as a machine fault" "cannot run on this machine" "$out"
check "a broken CLI still fails the account" "acct-01" "$out"
[ ! -f "$ACC/acct-01/.expired" ] \
  && t_ok "a broken CLI never parks a live login" \
  || t_fail "broken CLI parking" "verify parked an account over an infrastructure fault"
case "$out" in
  *"login is dead"*) t_fail "broken CLI wording" "verify blamed the login for a machine fault" ;;
  *) t_ok "a broken CLI is not called a dead login" ;;
esac
rm -f "$WORK/ctl-brokencli"

# ---- 16e. MCP servers for every account ---------------------------------------------
# Claude Code keeps MCP servers in the CONFIG DIR, so under the pool a stock `claude mcp
# add` used to land in ONE random account — appinspire was connected in some sessions
# and not in others (2026-09-22). The pool's registry (mcp-servers.json) is reconciled
# into every account at seed time and by the shim right before exec, and a stock add
# under the shim is mirrored into the registry. Own pool root, so nothing here leaks
# into the sections above or below.
MPOOL="$WORK/mcp-pool"
mkdir -p "$MPOOL/acct-01" "$MPOOL/acct-02" "$MPOOL/tmp"
: > "$MPOOL/.limits-kick"
cat > "$MPOOL/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,
 "accounts":[
   {"id":"acct-01","email":"m1@test","home":"mac","added_at":"2026-07-13T00:00:00Z"},
   {"id":"acct-02","email":"m2@test","home":"mac","added_at":"2026-07-13T00:00:00Z"}]}
EOF
for i in 01 02; do
  printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-mcp%s","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' \
    "$i" > "$MPOOL/acct-$i/.credentials.json"
  printf '{"mcpServers":{"own-%s":{"type":"stdio","command":"true","args":[],"env":{}}},"numStartups":1}\n' "$i" \
    > "$MPOOL/acct-$i/.claude.json"
done
# A python that LOGS every invocation, then runs the real python3: proves whether the
# shim spent a python start-up on a launch, which the stamp exists to avoid.
PYLOG="$WORK/mcp-pylog"
cat > "$WORK/pylog.sh" <<EOF
#!/usr/bin/env bash
printf 'PY %s\n' "\$*" >> "$PYLOG"
exec python3 "\$@"
EOF
chmod +x "$WORK/pylog.sh"
mcp_has() { # mcp_has <acct> <name> [<project>] -> 0 when the account carries the server
  python3 - "$MPOOL/$1/.claude.json" "$2" "${3:-}" <<'PY'
import json, sys
doc = json.load(open(sys.argv[1]))
name, project = sys.argv[2], sys.argv[3]
if project:
    sys.exit(0 if name in (((doc.get("projects") or {}).get(project) or {}).get("mcpServers") or {}) else 1)
sys.exit(0 if name in (doc.get("mcpServers") or {}) else 1)
PY
}
# (iv) the CLI: add for THIS provider only, list, remove (retires), apply repairs drift
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp add --provider claude reg1 -e K=v -- echo hi 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "mcp add (claude only) exits 0" || t_fail "mcp add rc" "rc=$rc: $out"
[ -f "$MPOOL/mcp-servers.json" ] && t_ok "mcp add writes the pool registry" || t_fail "registry file" "missing"
mcp_has acct-01 reg1 && mcp_has acct-02 reg1 && t_ok "mcp add reconciles EVERY account" \
  || t_fail "mcp add reconcile" "$(cat "$MPOOL/acct-01/.claude.json" "$MPOOL/acct-02/.claude.json")"
mcp_has acct-01 own-01 && mcp_has acct-02 own-02 && t_ok "an account's own extra servers survive the reconcile" \
  || t_fail "extras preserved" "$(cat "$MPOOL/acct-01/.claude.json")"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list 2>&1)"
check "mcp list names the server" "reg1" "$out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "reg1" in d.get("mcpServers",{}) else 1)' "$out" \
  && t_ok "mcp list --json carries mcpServers" || t_fail "mcp list --json" "$out"
# drift: the client rewrote the file without the server (its in-memory state was older)
python3 - "$MPOOL/acct-02/.claude.json" <<'PY'
import json, os, sys
p = sys.argv[1]; d = json.load(open(p)); d["mcpServers"].pop("reg1", None)
json.dump(d, open(p + ".tmp", "w")); os.replace(p + ".tmp", p)
PY
mcp_has acct-02 reg1 && t_fail "drift fixture" "reg1 still present" || t_ok "drift fixture: acct-02 lost reg1"
# (i) a launch reconciles the picked account before exec, and stamps it
: > "$PYLOG"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" claude 2>&1)"
check "launch runs on the pinned account" "CFG=acct-02" "$out"
mcp_has acct-02 reg1 && t_ok "the shim reconciles the picked account before exec" \
  || t_fail "shim reconcile" "$(cat "$MPOOL/acct-02/.claude.json")"
[ -s "$MPOOL/acct-02/.mcp-applied" ] && t_ok "the reconcile leaves a stamp" || t_fail "stamp" "no .mcp-applied"
grep -q "apply" "$PYLOG" && t_ok "python ran once for the drifted account" || t_fail "python ran" "$(cat "$PYLOG")"
# (ii) the stamp short-circuits: nothing changed => no python at all; python gone => still launches
: > "$PYLOG"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" claude 2>&1)"
check "second launch still runs" "CFG=acct-02" "$out"
[ ! -s "$PYLOG" ] && t_ok "an unchanged registry + config spends no python start-up" \
  || t_fail "stamp short-circuit" "python ran: $(cat "$PYLOG")"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON=/nonexistent/python3 claude 2>&1)"
rc=$?
[ "$rc" = "0" ] && check "a missing python never breaks a launch" "CFG=acct-02" "$out" \
  || t_fail "fail-open python" "rc=$rc: $out"
touch "$MPOOL/mcp-servers.json"
sleep 1; touch "$MPOOL/mcp-servers.json"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON=/nonexistent/python3 claude 2>&1)"
rc=$?
[ "$rc" = "0" ] && check "a changed registry with no python still launches (fail-open)" "CFG=acct-02" "$out" \
  || t_fail "fail-open changed registry" "rc=$rc: $out"
: > "$PYLOG"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" claude 2>&1)"
grep -q "apply" "$PYLOG" && t_ok "a touched registry re-runs the reconcile" || t_fail "registry mtime" "no python run"
# (vi) the kill switch: no reconcile at launch
python3 - "$MPOOL/acct-01/.claude.json" <<'PY'
import json, os, sys
p = sys.argv[1]; d = json.load(open(p)); d["mcpServers"].pop("reg1", None)
json.dump(d, open(p + ".tmp", "w")); os.replace(p + ".tmp", p)
PY
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-01 CLAUDE_MULTIACC_MCP=0 claude 2>&1)"
check "kill switch: launch still runs" "CFG=acct-01" "$out"
mcp_has acct-01 reg1 && t_fail "kill switch" "CLAUDE_MULTIACC_MCP=0 still reconciled" \
  || t_ok "CLAUDE_MULTIACC_MCP=0 leaves the account alone"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp apply 2>&1)"
mcp_has acct-01 reg1 && t_ok "mcp apply repairs the drifted account" || t_fail "mcp apply" "$out"
# (iii) learn-from-write: a stock 'claude mcp add' under the shim reaches EVERY account
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude mcp add -s user x -- echo hi 2>&1)"
rc=$?
[ "$rc" = "0" ] && check "stock 'claude mcp add' still answers like the real client" "Added stdio MCP server x" "$out" \
  || t_fail "stock mcp add rc" "rc=$rc: $out"
mcp_has acct-01 x && mcp_has acct-02 x && t_ok "a stock 'claude mcp add -s user' lands in EVERY account" \
  || t_fail "mirror add" "$(cat "$MPOOL/acct-01/.claude.json" "$MPOOL/acct-02/.claude.json")"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); s=d["mcpServers"]["x"]; sys.exit(0 if s.get("command")=="echo" and s.get("args")==["hi"] else 1)' "$out" \
  && t_ok "the mirrored server is in the registry with the client's own block" || t_fail "mirror registry" "$out"
mkdir -p "$WORK/mcp-proj"
# the client keys the project by its normalized cwd, so ask the shell for that spelling
MPROJ="$(cd "$WORK/mcp-proj" && pwd)"
out="$(cd "$MPROJ" && CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude mcp add y -- echo yo 2>&1)"
mcp_has acct-01 y "$MPROJ" && mcp_has acct-02 y "$MPROJ" \
  && t_ok "a stock project-local add is mirrored for that project in EVERY account" \
  || t_fail "mirror local add" "$out $(cat "$MPOOL/acct-01/.claude.json")"
mcp_has acct-01 y && t_fail "local scope leak" "y landed in user scope" || t_ok "a project-local add stays project-local"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude mcp remove -s user x 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "stock 'claude mcp remove' exits 0" || t_fail "stock mcp remove rc" "rc=$rc: $out"
mcp_has acct-01 x || mcp_has acct-02 x \
  && t_fail "mirror remove" "x survives in an account" || t_ok "a stock 'claude mcp remove' drops the server from EVERY account"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "x" in d.get("retiredUser",[]) and "x" not in d.get("mcpServers",{}) else 1)' "$out" \
  && t_ok "a learned user-scope remove is a USER-SCOPE tombstone (retiredUser) in the registry" || t_fail "tombstone" "$out"
# the kill switch also disables the mirror: the stock add lands in one account only
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-01 CLAUDE_MULTIACC_MCP=0 claude mcp add -s user solo -- echo solo 2>&1)"
mcp_has acct-01 solo && ! mcp_has acct-02 solo && t_ok "CLAUDE_MULTIACC_MCP=0: a stock add stays in one account" \
  || t_fail "kill switch mirror" "$out"
# a failing real command is never mirrored, and its exit status passes through
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 claude mcp remove -s user never-there 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "a failed 'claude mcp remove' keeps its exit status" || t_fail "mcp remove passthrough rc" "rc=0: $out"
# ...even when the client wrote its file BEFORE failing: the write stays in that one
# account, the registry learns nothing, and the other account is untouched
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 FAKE_MCP_WRITE_THEN_FAIL=1 claude mcp add -s user wtf -- echo w 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "a client that writes and then fails still fails the shim run" || t_fail "write-then-fail rc" "rc=0: $out"
mcp_has acct-02 wtf && ! mcp_has acct-01 wtf && t_ok "the failed add stays in the one account that wrote it" \
  || t_fail "write-then-fail leak" "$(cat "$MPOOL/acct-01/.claude.json")"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "wtf" not in d.get("mcpServers",{}) and "wtf" not in d.get("retired",[]) and "wtf" not in d.get("retiredUser",[]) else 1)' "$out" \
  && t_ok "a failed stock add is never mirrored into the registry" || t_fail "failed mirror add" "$out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-02 FAKE_MCP_WRITE_THEN_FAIL=1 claude mcp remove -s user wtf 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "a client that removes and then fails still fails the shim run" || t_fail "write-then-fail remove rc" "rc=0: $out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "wtf" not in d.get("retired",[]) and "wtf" not in d.get("retiredUser",[]) else 1)' "$out" \
  && t_ok "a failed stock remove leaves no tombstone" || t_fail "failed mirror remove" "$out"
# NESTED session: a pooled session exports CLAUDE_CONFIG_DIR=<acct> + CLAUDE_SHIM_ACTIVE=1
# and its children inherit both, so an agent's `claude mcp add` reaches the passthrough
# with the account already chosen — it must be mirrored exactly like a top-level one
: > "$PYLOG"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_CONFIG_DIR="$MPOOL/acct-01" CLAUDE_SHIM_ACTIVE=1 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" claude mcp add -s user nested -- echo n 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "a nested (in-session) 'claude mcp add' exits 0" || t_fail "nested add rc" "rc=$rc: $out"
mcp_has acct-01 nested && mcp_has acct-02 nested && t_ok "a nested add is mirrored into EVERY account" \
  || t_fail "nested mirror" "$out $(cat "$MPOOL/acct-02/.claude.json")"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "nested" in d.get("mcpServers",{}) else 1)' "$out" \
  && t_ok "a nested add reaches the registry" || t_fail "nested registry" "$out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_CONFIG_DIR="$MPOOL/acct-01" CLAUDE_SHIM_ACTIVE=1 claude mcp remove -s user nested 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "a nested 'claude mcp remove' exits 0" || t_fail "nested remove rc" "rc=$rc: $out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "nested" in d.get("retiredUser",[]) and "nested" not in d.get("mcpServers",{}) else 1)' "$out" \
  && t_ok "a nested remove leaves a user-scope tombstone" || t_fail "nested tombstone" "$out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_ACCOUNT=acct-01 claude 2>&1)"
check "the next launch on that account still runs" "CFG=acct-01" "$out"
mcp_has acct-01 nested && t_fail "nested remove undone" "the next launch re-added nested" \
  || t_ok "a nested remove is not undone by the next launch"
# a CLAUDE_CONFIG_DIR OUTSIDE the pool is plain passthrough: no python, no mirror
mkdir -p "$WORK/mcp-outside"
: > "$PYLOG"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CLAUDE_CONFIG_DIR="$WORK/mcp-outside" CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" claude mcp add -s user outside -- echo o 2>&1)"
[ "$?" = "0" ] && [ ! -s "$PYLOG" ] && ! mcp_has acct-01 outside \
  && t_ok "a config dir outside the pool is untouched passthrough (no python, no mirror)" \
  || t_fail "outside passthrough" "$out; pylog: $(cat "$PYLOG")"
# the help pre-scan stops at `--`: -h in the SERVER's command line is not our --help
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp add --provider claude hsvc -- node s.js -h 127.0.0.1 2>&1)"
rc=$?
case "$out" in *USAGE*) t_fail "help scan" "-h after -- printed usage" ;; *) [ "$rc" = "0" ] && t_ok "-h after -- is the server's own flag, not --help" || t_fail "help scan rc" "rc=$rc: $out" ;; esac
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if d["mcpServers"]["hsvc"]["args"]==["s.js","-h","127.0.0.1"] else 1)' "$out" \
  && t_ok "the server keeps its -h argument" || t_fail "help scan args" "$out"
# retirement reaches a server that was only ever hand-added to ONE account
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp remove --provider claude own-01 2>&1)"
mcp_has acct-01 own-01 && t_fail "retire hand-added" "own-01 survives" \
  || t_ok "mcp remove retires a server that was hand-added to a single account"
# --provider both: the change reaches the codex pool beside this one
CXM="$WORK/mcp-codex-pool"
mkdir -p "$CXM/acct-01" "$CXM/tmp"
cat > "$CXM/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,
 "accounts":[{"id":"acct-01","email":"cm1@cx","home":"mac","added_at":"2026-08-21T00:00:00Z"}]}
EOF
printf 'model = "gpt-5"\n\n[mcp_servers.keep]\ncommand = "true"\nargs = []\n' > "$CXM/acct-01/config.toml"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CODEX_ACCOUNTS_DIR="$CXM" CODEX_MULTIACC_NO_SYNC=1 claude-accounts mcp add shared -- echo both 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "mcp add --provider both (default) exits 0" || t_fail "mcp add both rc" "rc=$rc: $out"
mcp_has acct-01 shared && t_ok "--provider both: the claude pool has the server" || t_fail "both claude" "$out"
grep -q '^\[mcp_servers.shared\]' "$CXM/acct-01/config.toml" \
  && t_ok "--provider both: the codex pool beside it has [mcp_servers.shared]" \
  || t_fail "both codex" "$out $(cat "$CXM/acct-01/config.toml")"
grep -q '^model = "gpt-5"' "$CXM/acct-01/config.toml" && grep -q '^\[mcp_servers.keep\]' "$CXM/acct-01/config.toml" \
  && t_ok "the codex config keeps its unrelated content" || t_fail "codex lossless" "$(cat "$CXM/acct-01/config.toml")"
[ -f "$CXM/mcp-servers.json" ] && t_ok "the codex pool got its own registry" || t_fail "codex registry" "missing"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CODEX_ACCOUNTS_DIR="$WORK/no-such-codex-pool" claude-accounts mcp add lonely -- echo one 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "no sibling pool: the mirror is silently skipped" || t_fail "no sibling" "rc=$rc: $out"
case "$out" in *"no manifest"*|*"warning"*) t_fail "no sibling silence" "$out" ;; *) t_ok "no sibling pool: no warning" ;; esac
# an EXPLICIT --provider codex with no codex pool is a loud error, not a silent no-op
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CODEX_ACCOUNTS_DIR="$WORK/no-such-codex-pool" claude-accounts mcp add --provider codex q -- echo q 2>&1)"
rc=$?
[ "$rc" != "0" ] && check "an explicit --provider codex without a codex pool fails loudly" "no codex pool" "$out" \
  || t_fail "explicit provider" "rc=0: $out"
# rc 3: the registry is saved, the healthy accounts are reconciled, the broken one is
# reported, and the change STILL reaches the sibling pool (and would still sync)
cp "$MPOOL/acct-02/.claude.json" "$WORK/mcp-acct-02.bak"
printf '{not json' > "$MPOOL/acct-02/.claude.json"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" CODEX_ACCOUNTS_DIR="$CXM" CODEX_MULTIACC_NO_SYNC=1 claude-accounts mcp add partial -- echo p 2>&1)"
rc=$?
[ "$rc" = "3" ] && t_ok "a corrupt account makes mcp add exit 3 (saved, partially applied)" || t_fail "partial rc" "rc=$rc: $out"
check "the partial add says how to repair" "mcp apply" "$out"
mcp_has acct-01 partial && t_ok "the healthy account was reconciled despite the corrupt one" || t_fail "partial healthy" "$out"
grep -q '^\[mcp_servers.partial\]' "$CXM/acct-01/config.toml" \
  && t_ok "the partial add still reached the codex pool beside it" || t_fail "partial sibling" "$(cat "$CXM/acct-01/config.toml")"
cp "$WORK/mcp-acct-02.bak" "$MPOOL/acct-02/.claude.json"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp apply 2>&1)"
mcp_has acct-02 partial && t_ok "mcp apply repairs the account once its config is fixed" || t_fail "partial repair" "$out"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp add --provider mars z -- echo z 2>&1)"
rc=$?
[ "$rc" != "0" ] && check "an unknown --provider is refused" "must be claude, codex or both" "$out" \
  || t_fail "provider validation" "rc=0"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp bogus 2>&1)"
rc=$?
[ "$rc" != "0" ] && check "an unknown mcp subcommand is refused" "unknown mcp subcommand" "$out" \
  || t_fail "subcommand validation" "rc=0"
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts mcp --help 2>&1)"
check "mcp --help prints usage" "claude-accounts mcp add" "$out"
# seeding a NEW account applies the registry (import goes through seed_account_dir)
out="$(CLAUDE_ACCOUNTS_ROOT="$MPOOL" claude-accounts import m3@test --id acct-03 --no-sync 2>&1)"
mcp_has acct-03 reg1 && mcp_has acct-03 shared && t_ok "a newly seeded account gets every registered server" \
  || t_fail "seed applies registry" "$out $(cat "$MPOOL/acct-03/.claude.json" 2>/dev/null)"

# ---- 17b. verify authenticates the way the SHIM would ---------------------------------
# A dead credential next to a live portable token: the shim runs that account with the
# TOKEN, so verify must too — testing it with the dead credential would fail a healthy
# account and park it.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
printf 'sk-ant-oat01-token-for-01' > "$ACC/acct-01/server.token"
rm -f "$ACC/acct-01/.expired" "$ACC/acct-01/.server-token-verified"
out="$(claude-accounts expired 2>&1)"
check "expired does not call an unverified setup-token healthy" "acct-01" "$out"
check "expired labels an unverified setup-token" "UNVERIFIED" "$out"
check "expired gives the setup-token verification fix" "claude-accounts verify" "$out"
case "$out" in
  *"Re-authenticate them"*)
    t_fail "unverified setup-token does not demand re-login" "expired gave the wrong fix" ;;
  *) t_ok "unverified setup-token does not demand re-login" ;;
esac
out="$(claude-accounts verify 2>&1)"
case "$out" in *"acct-01 a@test: PASS"*) t_ok "verify uses the portable token when the credential is dead" ;;
  *) t_fail "verify token fallback" "expected acct-01 PASS, got: $(printf '%s' "$out" | grep acct-01)" ;; esac
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "verify does not park an account its token can run" \
  || t_fail "verify token fallback" "healthy token-auth account was parked"
[ -f "$ACC/acct-01/.server-token-verified" ] \
  && t_ok "verify records proof for the exact setup-token" \
  || t_fail "verify setup-token proof" ".server-token-verified missing"
state="$(python3 "$REPO_DIR/lib/audit.py" "$ACC" "$(uname -s | tr '[:upper:]' '[:lower:]')" \
  strict-tokens | awk -F'\t' '$1=="acct-01"{print $4}')"
[ "$state" = "ok" ] && t_ok "verified setup-token is no longer false-unknown" \
  || t_fail "verified setup-token audit" "expected ok, got: $state"
printf 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' \
  > "$ACC/acct-01/server.token"
rm -f "$ACC/acct-01/.server-token-verified"
out="$(claude-accounts verify 2>&1)"
check "verify calls a rejected setup-token what it is" "portable setup-token is invalid" "$out"
check "verify recommends replacing a rejected setup-token" \
  "claude-accounts login acct-01 --token" "$out"

# ---- 17c. a login-proven pass never lifts a TOKEN park -------------------------------
# One Mac can hold both credentials: a working OAuth login beside a dead portable
# token. The limits probe's bearer is the LOGIN, and its success used to clear the
# token's park ("dead-auth marker cleared") — the next selection exported the dead
# token, got 401, parked it again, all day (2026-08-29).
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-live","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-01/.credentials.json"
printf 'sk-ant-oat01-REVOKED%s' "$(printf '%88s' '' | tr ' ' R)" > "$ACC/acct-01/server.token"
printf '%s\nreason=setup-token-invalid marked_at=x detail=portable OAuth token rejected\n' "$now" > "$ACC/acct-01/.expired"
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
case "$out" in
  *"acct-01: dead-auth marker cleared"*) t_fail "limits probe must not lift a token park" "the login's success cleared the token's marker" ;;
  *) t_ok "limits probe must not lift a token park" ;;
esac
[ -f "$ACC/acct-01/.expired" ] && grep -q 'setup-token-invalid' "$ACC/acct-01/.expired" \
  && t_ok "the token park survives a login-proven probe" || t_fail "token park survival" ".expired gone"
# ...but an ordinary login park IS lifted — a working bearer proves exactly that.
printf '%s\nreason=auth-error marked_at=x detail=a real call came back not-authenticated\n' "$now" > "$ACC/acct-01/.expired"
out="$(CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
check "an auth-error park is still lifted by a working bearer" "dead-auth marker cleared" "$out"
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "the login park was lifted" || t_fail "login park" "still present"
# verify: a PASS on the LOGIN keeps the token park; a PASS on the TOKEN lifts it.
printf '%s\nreason=setup-token-invalid marked_at=x detail=portable OAuth token rejected\n' "$now" > "$ACC/acct-01/.expired"
out="$(claude-accounts verify 2>&1)"
case "$out" in *"acct-01 a@test: PASS"*) t_ok "verify passes on the login" ;; \
  *) t_fail "verify login pass" "$(printf '%s' "$out" | grep acct-01 | head -1)" ;; esac
[ -f "$ACC/acct-01/.expired" ] && t_ok "a login pass does not lift the token park" \
  || t_fail "verify token park" ".expired gone"
# A dead login beside a fresh valid token: the pass rides the TOKEN and lifts its park.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
printf 'sk-ant-oat01-%s' "$(printf '%95s' '' | tr ' ' G)" > "$ACC/acct-01/server.token"
rm -f "$ACC/acct-01/.server-token-verified"
out="$(claude-accounts verify 2>&1)"
case "$out" in *"acct-01 a@test: PASS"*) t_ok "verify passes on the token" ;; \
  *) t_fail "verify token pass" "$(printf '%s' "$out" | grep acct-01 | head -1)" ;; esac
[ ! -f "$ACC/acct-01/.expired" ] && t_ok "a token pass lifts the token park" \
  || t_fail "token pass park" "still present"
# Hand back the state the next checks expect: a dead login beside a REVOKED token,
# parked and unproven — exactly where 17b left acct-01.
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-dead","refreshToken":"r","expiresAt":1000000000000,"refreshTokenExpiresAt":1000000000000}}' > "$ACC/acct-01/.credentials.json"
printf 'sk-ant-oat01-REVOKEDREVOKEDREVOKEDREVOKEDREVOKEDREVOKED' > "$ACC/acct-01/server.token"
rm -f "$ACC/acct-01/.server-token-verified"
printf '%s\nreason=setup-token-invalid marked_at=x detail=portable setup-token failed a real inference\n' "$now" > "$ACC/acct-01/.expired"
out="$(claude-accounts expired 2>&1)"
check "verify marker retains setup-token classification" "TOKEN INVALID" "$out"
check "verify marker retains setup-token recovery" \
  "claude-accounts login acct-01 --token" "$out"
rm -f "$ACC/acct-01/server.token"
rm -f "$ACC/acct-01/.expired" "$ACC/acct-01/.server-token-verified"
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-test01","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$ACC/acct-01/.credentials.json"

# ---- 17c. audit: machine vocabulary (home=server vs machine_kind=linux) ---------------
# `import --home` says mac|server; machine_kind() says mac|linux. If those are compared
# raw, an un-authenticated account ON the server reads as "the grant lives elsewhere"
# and silently drops off the re-login worklist.
mkdir -p "$ACC/acct-06"
python3 - "$ACC/accounts.json" <<'EOF'
import json, sys
doc = json.load(open(sys.argv[1]))
doc['accounts'] = [a for a in doc['accounts'] if a['id'] != 'acct-06']
doc['accounts'].append({'id': 'acct-06', 'email': 'srv@test', 'home': 'server'})
doc['accounts'].sort(key=lambda a: a['id'])
json.dump(doc, open(sys.argv[1], 'w'), indent=2)
EOF
out="$(python3 "$REPO_DIR/lib/audit.py" "$ACC" linux | awk -F'\t' '$1=="acct-06"{print $4}')"
[ "$out" = "missing" ] && t_ok "home=server on the server means NO LOGIN, not 'elsewhere'" \
  || t_fail "home vocabulary" "expected missing on linux, got: $out"
out="$(python3 "$REPO_DIR/lib/audit.py" "$ACC" mac | awk -F'\t' '$1=="acct-06"{print $4}')"
[ "$out" = "remote" ] && t_ok "home=server on the Mac is correctly 'elsewhere'" \
  || t_fail "home vocabulary" "expected remote on mac, got: $out"
python3 - "$ACC/accounts.json" <<'EOF'
import json, sys
doc = json.load(open(sys.argv[1]))
doc['accounts'] = [a for a in doc['accounts'] if a['id'] != 'acct-06']
json.dump(doc, open(sys.argv[1], 'w'), indent=2)
EOF
rm -rf "$ACC/acct-06"

# ---- 17d. an empty pool is never rendered as "all clear" ------------------------------
emptypool="$WORK/emptypool"
mkdir -p "$emptypool/tmp"
printf '{"version":1,"threshold":90,"accounts":[]}' > "$emptypool/accounts.json"
out="$(CLAUDE_ACCOUNTS_DIR="$emptypool" claude-accounts expired 2>&1)"
rc=$?
check "expired on an empty pool says so" "No accounts registered yet" "$out"
[ "$rc" = "0" ] && t_ok "empty pool exits 0" || t_fail "empty pool rc" "rc=$rc"
case "$out" in *"NO LOGIN"*) t_fail "empty pool phantom row" "invented an account from a blank line" ;;
  *) t_ok "empty pool invents no phantom account" ;; esac

out="$(claude-accounts verify --quick 2>&1)"
check "verify --quick passes oauth accounts" "acct-01 a@test: OK" "$out"
check "verify --quick counts" "0 failure(s)" "$out"

# ---- 18. CLI: status renders ------------------------------------------------------
out="$(claude-accounts status 2>&1)"
check "status shows threshold" "90%" "$out"
check "status shows account" "a@test" "$out"

# ---- 19. npm layer: cli.mjs dispatch + self-update + postinstall guards -------------
if command -v node >/dev/null 2>&1; then
  CLI="$REPO_DIR/bin/cli.mjs"
  pkgver="$(node -e "console.log(require('$REPO_DIR/package.json').version)")"
  out="$(node "$CLI" --version 2>&1)"
  check "cli --version matches package.json" "$pkgver" "$out"
  out="$(node "$CLI" --help 2>&1)"
  check "cli --help documents install" "install or update the addon" "$out"
  # passthrough to claude-accounts
  out="$(node "$CLI" list 2>&1)"
  check "cli passes through to claude-accounts (list)" "acct-01" "$out"
  out="$(node "$CLI" status 2>&1)"
  check "cli doctor/status passthrough" "threshold" "$out"
  # self-update on a non-npm, non-git tree is a logged no-op (never errors)
  out="$(claude-accounts self-update 2>&1)"
  rc=$?
  # A git checkout that cannot fast-forward (feature branch, detached CI checkout) is
  # SUPPOSED to fail loudly; what must never happen is a crash with no explanation.
  case "$rc:$out" in
    0:*) t_ok "self-update no-op exits 0 on a plain checkout" ;;
    *:*"git pull FAILED"*) t_ok "self-update reports a git checkout it cannot fast-forward" ;;
    *) t_fail "self-update rc" "rc=$rc: $out" ;;
  esac
  case "$out" in *"update manually"*|*"already latest"*|*"git pull"*) t_ok "self-update reports its path" ;;
    *) t_fail "self-update message" "unexpected: $out" ;; esac

  # ---- 19a. an npm install updates itself with NO npm on PATH -----------------------
  # launchd hands an agent PATH=/usr/bin:/bin:/usr/sbin:/sbin, so `command -v npm` finds
  # nothing and the nightly self-update logged "npm not found; skipping" for days while
  # every Mac's copy silently froze. npm must be resolved by path — and specifically the
  # one inside the prefix that owns the RUNNING copy, never whatever a stray PATH offers.
  for _cli in claude-accounts codex-accounts; do
    PFX="$WORK/pfx-$_cli"
    NPMROOT="$PFX/lib/node_modules/claude-multiacc"
    mkdir -p "$NPMROOT" "$PFX/bin"
    cp -R "$REPO_DIR/bin" "$REPO_DIR/lib" "$REPO_DIR/package.json" "$NPMROOT/"
    # A fake npm that records how it was called and "installs" by bumping package.json.
    # Its shebang names an interpreter that exists ONLY beside it, mirroring the real
    # npm's `#!/usr/bin/env node`: resolving npm by absolute path is not enough if the
    # agent's PATH cannot find npm's own interpreter, which is how the update failed
    # with an empty version probe and no explanation.
    cat > "$PFX/bin/multiacc-fake-node" <<'NODEEOF'
#!/usr/bin/env bash
exec /bin/bash "$@"
NODEEOF
    chmod +x "$PFX/bin/multiacc-fake-node"
    cat > "$PFX/bin/npm" <<NPMEOF
#!/usr/bin/env multiacc-fake-node
echo "npm \$*" >> "$WORK/npm-calls-$_cli.log"
case "\${1:-}" in
  view) echo 9.9.9 ;;
  install) python3 - "$NPMROOT/package.json" <<'PY'
import json, sys
p = sys.argv[1]
doc = json.load(open(p)); doc['version'] = '9.9.9'
json.dump(doc, open(p, 'w'))
PY
    ;;
esac
exit 0
NPMEOF
    chmod +x "$PFX/bin/npm"
    # A DIFFERENT npm earlier on PATH must not win: the running copy's prefix owns it.
    mkdir -p "$WORK/wrongbin"
    printf '#!/usr/bin/env bash\necho "WRONG-NPM \$*" >> "%s"\nexit 0\n' "$WORK/npm-calls-$_cli.log" > "$WORK/wrongbin/npm"
    chmod +x "$WORK/wrongbin/npm"
    : > "$WORK/npm-calls-$_cli.log"
    out="$(env -i HOME="$HOME" PATH="$WORK/wrongbin:/usr/bin:/bin:/usr/sbin:/sbin" \
      CLAUDE_ACCOUNTS_DIR="$ACC" CODEX_ACCOUNTS_DIR="$WORK/codex-accounts" \
      "$NPMROOT/bin/$_cli" self-update 2>&1)"
    rc=$?
    [ "$rc" = "0" ] && t_ok "$_cli: self-update exits 0 with no npm on PATH" \
      || t_fail "$_cli self-update rc" "rc=$rc: $(printf '%s' "$out" | head -c 200)"
    printf '%s' "$out" | grep -q "npm not found" \
      && t_fail "$_cli self-update npm lookup" "still reports 'npm not found' with an npm in its own prefix" \
      || t_ok "$_cli: npm resolved without PATH"
    grep -q "^npm install " "$WORK/npm-calls-$_cli.log" \
      && t_ok "$_cli: the prefix's own npm performed the install" \
      || t_fail "$_cli npm install" "calls: $(cat "$WORK/npm-calls-$_cli.log" | head -3)"
    grep -q "WRONG-NPM" "$WORK/npm-calls-$_cli.log" \
      && t_fail "$_cli npm choice" "used the npm from PATH instead of the running prefix's" \
      || t_ok "$_cli: a stray npm on PATH never wins over the running prefix's"
    check "$_cli: self-update verifies the tree it wrote" "npm update ok (9.9.9)" "$out"
    grep -q "^npm view " "$WORK/npm-calls-$_cli.log" \
      && t_ok "$_cli: npm ran despite its interpreter being off PATH" \
      || t_fail "$_cli npm interpreter" "npm never executed — its shebang interpreter was not found"
  done
  # The agents install.sh writes must carry a PATH for the same reason (a future tool
  # that is not resolved by absolute path would hit exactly this again).
  grep -q '<key>PATH</key>' "$REPO_DIR/install.sh" \
    && t_ok "install.sh gives its launchd agents a PATH" \
    || t_fail "agent PATH" "plist_env_block writes no PATH — launchd agents get /usr/bin:/bin only"
  # postinstall must SKIP for a non-global install and never fail
  out="$(node "$REPO_DIR/scripts/postinstall.mjs" 2>&1)"
  rc=$?
  { [ "$rc" = "0" ] && printf '%s' "$out" | grep -q "skipping auto-setup"; } \
    && t_ok "postinstall skips (and exits 0) for a non-global install" \
    || t_fail "postinstall guard" "rc=$rc out=$out"
  out="$(CI=1 npm_config_global=true node "$REPO_DIR/scripts/postinstall.mjs" 2>&1)"
  printf '%s' "$out" | grep -q "CI environment" \
    && t_ok "postinstall skips under CI even when global" || t_fail "postinstall CI guard" "$out"
  # package.json is valid and ships the essential files list
  node -e "
    const p=require('$REPO_DIR/package.json');
    const need=['bin/','lib/','install.sh','scripts/postinstall.mjs'];
    if(!/^(\.\/)?bin\/cli\.mjs$/.test(p.bin['claude-multiacc'])) { console.error('bad bin'); process.exit(1); }
    for(const f of need) if(!p.files.includes(f)) { console.error('missing file entry: '+f); process.exit(1); }
    if(p.scripts.postinstall!=='node scripts/postinstall.mjs'){ console.error('bad postinstall'); process.exit(1); }
  " && t_ok "package.json bin/files/postinstall wired correctly" || t_fail "package.json" "see errors above"
else
  t_ok "npm-layer tests skipped (node not installed)"
fi

# ============================ CODEX PROVIDER =====================================
# The codex pool (bin/codex + bin/codex-accounts + lib/codex_audit.py) is separate
# code over separate state (~/.codex-accounts), so it gets its own sandboxed pass:
# fake `codex` binary, JWT-shaped auth fixtures, file:// usage/token endpoints.

export CODEX_ACCOUNTS_DIR="$WORK/codex-accounts"
CX="$CODEX_ACCOUNTS_DIR"
mkdir -p "$CX/tmp"
unset CODEX_HOME CODEX_ACCOUNT CODEX_SHIM_ACTIVE 2>/dev/null || true
export CODEX_MULTIACC_NO_SYNC=1
export CODEX_MULTIACC_MIN_FETCH=0
export CODEX_MULTIACC_CLIENT_SCAN_TTL=0
export CODEX_MULTIACC_AUTO_RESET=0
export CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-endpoint-missing.json"
# Default usage URL is an offline missing fixture: the SHIM's opportunistic
# background `limits --quiet` kick must never reach a real endpoint from tests
# (each limits test overrides the URL inline). The pre-armed .limits-kick throttle
# below keeps those background kicks from racing the explicit limits runs at all.
export CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-endpoint-missing.json"
export CODEX_MULTIACC_FORCE_TTY=1
export FAKE_CTL2="$WORK/ctl2"
: > "$CX/.limits-kick"

# Codex auth fixtures are real-shaped: auth.json carrying JWTs whose exp/email
# claims the audit decodes offline (exactly what the CLI does).
MKAUTH="$WORK/mk_cx_auth.py"
cat > "$MKAUTH" <<'EOF'
import base64, json, sys
def jwt(claims):
    enc = lambda o: base64.urlsafe_b64encode(json.dumps(o).encode()).rstrip(b'=').decode()
    return f"{enc({'alg':'RS256'})}.{enc(claims)}.sig"
path, email, exp, mode = sys.argv[1], sys.argv[2], float(sys.argv[3]), (sys.argv[4] if len(sys.argv) > 4 else '')
if mode == 'apikey':
    doc = {"auth_mode": "apikey", "OPENAI_API_KEY": "sk-test-api-key", "tokens": None, "last_refresh": None}
else:
    auth_claim = {"chatgpt_plan_type": "pro", "chatgpt_account_id": "acct-uuid"}
    tokens = {
        "id_token": jwt({"email": email, "exp": exp, "https://api.openai.com/auth": auth_claim}),
        "access_token": jwt({"exp": exp, "https://api.openai.com/auth": auth_claim}),
        "refresh_token": "rt-" + email,
        "account_id": "acct-uuid",
    }
    if mode == 'norefresh':
        tokens.pop('refresh_token')
    doc = {"auth_mode": "chatgpt", "OPENAI_API_KEY": None, "tokens": tokens,
           "last_refresh": "2026-01-01T00:00:00Z"}
json.dump(doc, open(path, 'w'))
EOF
export MKAUTH
mk_cx_auth() { python3 "$MKAUTH" "$@"; }
FUTURE_EXP=$((now + 864000))

# A stand-in for the real `codex mcp add|remove`: appends / strips a
# `[mcp_servers.NAME]` table in $CODEX_HOME/config.toml, where the real CLI keeps them.
# A separate file because the fake codex below is an UNQUOTED heredoc.
FAKE_CODEX_MCP="$WORK/fake_codex_mcp.py"
cat > "$FAKE_CODEX_MCP" <<'EOF'
import os, re, sys
path, argv = sys.argv[1], sys.argv[2:]
verb, rest = argv[1], argv[2:]
name, cmd, envs = None, [], {}
i = 0
while i < len(rest):
    a = rest[i]
    if a == "--env":
        k, v = rest[i + 1].split("=", 1); envs[k] = v; i += 2; continue
    if a == "--":
        cmd = rest[i + 1:]; break
    if name is None:
        name = a
    i += 1
src = open(path).read() if os.path.exists(path) else ""
out, skip, found = [], False, False
for line in src.splitlines(keepends=True):
    st = line.strip()
    if st.startswith("["):
        skip = bool(re.match(r"\[mcp_servers\." + re.escape(name) + r"(\.|\])", st))
        found = found or skip
    if not skip:
        out.append(line)
src = "".join(out)
def q(v):
    return '"' + v.replace("\\", "\\\\").replace('"', '\\"') + '"'
if verb == "add":
    if src and not src.endswith("\n"):
        src += "\n"
    src += "\n[mcp_servers.%s]\ncommand = %s\nargs = [%s]\n" % (name, q(cmd[0]), ", ".join(q(a) for a in cmd[1:]))
    if envs:
        src += "env = { %s }\n" % ", ".join("%s = %s" % (k, q(v)) for k, v in envs.items())
    print("Added global MCP server '%s'." % name)
elif not found:
    print("No MCP server named '%s' found." % name, file=sys.stderr); sys.exit(1)
else:
    print("Removed global MCP server '%s'." % name)
with open(path + ".tmp", "w") as f:
    f.write(src)
os.replace(path + ".tmp", path)
EOF

# The auto-resume sections' INTERACTIVE codex (sourced by the fake below when FAKE_TUI is
# set): it writes a rollout the way the real TUI does — line 1 session_meta (id ==
# session_id, cwd, originator codex-tui), held open like the native binary holds it — then
# the scripted token_count + task_complete error, and IDLES; SIGTERM exits 0 (what the node
# wrapper reports). A `resume <sid>` launch appends task_started (the resumed turn) to the
# SAME rollout instead of an error.
cat > "$WORK/fake-tui-codex.sh" <<'EOF'
acct="$(basename "$CODEX_HOME")"
sid=""; resumed=0
if [ "${1:-}" = resume ]; then
  resumed=1
  for a in "$@"; do
    case "$a" in
      *' '*) ;;
      ????????-????-????-????-????????????) [ -n "$sid" ] || sid="$a" ;;
    esac
  done
fi
[ -n "${FAKE_TUI_PIDS:-}" ] && echo "$$" >> "$FAKE_TUI_PIDS"
echo "CFG=$acct ARGS=$*" >> "${FAKE_TUI_LOG:-/dev/null}"
ts() { date -u +%Y-%m-%dT%H:%M:%S.000Z; }
ro=""
if [ -n "$sid" ]; then
  for f in "$CODEX_HOME"/sessions/*/*/*/rollout-*-"$sid".jsonl; do [ -f "$f" ] && ro="$f"; done
fi
if [ -z "$ro" ]; then
  [ -n "$sid" ] || sid="${FAKE_TUI_SID:-6a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d}"
  day="$CODEX_HOME/sessions/$(date +%Y/%m/%d)"
  mkdir -p "$day"
  ro="$day/rollout-$(date +%Y-%m-%dT%H-%M-%S)-$sid.jsonl"
  printf '{"timestamp":"%s","type":"session_meta","payload":{"id":"%s","session_id":"%s","timestamp":"%s","cwd":"%s","originator":"codex-tui","cli_version":"0.0.0","source":"cli"}}\n' \
    "$(ts)" "$sid" "$sid" "$(ts)" "$PWD" > "$ro"
fi
exec 9>>"$ro"
trap 'exit 0' TERM
trap 'exit 0' HUP
if [ "$resumed" = 1 ]; then
  [ -n "${FAKE_TUI_QUIET:-}" ] \
    || printf '{"timestamp":"%s","type":"event_msg","payload":{"type":"task_started","turn_id":"2"}}\n' "$(ts)" >&9
else
  sleep "${FAKE_TUI_DELAY:-0.3}"
  case "$FAKE_TUI" in
    quota)
      printf '{"timestamp":"%s","type":"event_msg","payload":{"type":"token_count","info":null,"rate_limits":{"limit_id":"premium","primary":null,"secondary":null}}}\n' "$(ts)" >&9
      printf '{"timestamp":"%s","type":"event_msg","payload":{"type":"token_count","info":null,"rate_limits":{"limit_id":"codex","primary":{"used_percent":100.0,"window_minutes":300,"resets_at":%s},"secondary":{"used_percent":40.0,"window_minutes":10080,"resets_at":%s}}}}\n' \
        "$(ts)" "$(( $(date +%s) + 5400 ))" "$(( $(date +%s) + 500000 ))" >&9
      printf '{"timestamp":"%s","type":"event_msg","payload":{"type":"task_complete","turn_id":"1","last_agent_message":null,"error":{"message":"You'"'"'ve hit your usage limit. Upgrade to Pro, or try again at Sep 26th, 2026 11:22 AM.","codex_error_info":"usage_limit_exceeded"},"completed_at":%s}}\n' \
        "$(ts)" "$(date +%s)" >&9 ;;
  esac
fi
i=0
while [ "$i" -lt "${FAKE_TUI_LIFE:-400}" ]; do sleep 0.1; i=$((i + 1)); done
exit 0
EOF

# Fake "real" codex: prints which CODEX_HOME it ran under; scriptable login +
# failures via a control file. (Note: must not contain the hyphenated shim marker.)
cat > "$FAKEBIN/codex" <<EOF
#!/usr/bin/env bash
# fake real codex for tests (not a shim)
if [ "\${1:-}" = "mcp" ] && [ -n "\${CODEX_HOME:-}" ]; then
  python3 "$FAKE_CODEX_MCP" "\$CODEX_HOME/config.toml" "\$@"
  rc=\$?
  # FAKE_MCP_WRITE_THEN_FAIL=1: wrote the table, then died — nothing may be mirrored.
  [ "\$rc" = 0 ] && [ -n "\${FAKE_MCP_WRITE_THEN_FAIL:-}" ] && exit 1
  exit \$rc
fi
if [ -n "\${FAKE_TUI:-}" ] && [ -n "\${CODEX_HOME:-}" ]; then . "$WORK/fake-tui-codex.sh"; fi
if [ "\${1:-}" = "login" ]; then
  shift
  # record the flags the CLI chose (device-auth default vs --browser opt-out)
  printf '%s\n' "\$*" > "\${FAKE_LOGIN_ARGS:-/dev/null}" 2>/dev/null || true
  [ -n "\${FAKE_LOGIN_FAIL:-}" ] && { echo "login aborted" >&2; exit 1; }
  # simulate a completed ChatGPT sign-in: write a JWT-shaped auth.json
  python3 "\$MKAUTH" "\${CODEX_HOME:-/dev/null}/auth.json" "\${FAKE_EMAIL:-fake@test}" "\$(( \$(date +%s) + 864000 ))"
  echo "Successfully logged in"
  exit 0
fi
ctl="\${FAKE_CTL2:-/nonexistent}"
acct="\$(basename "\${CODEX_HOME:-none}")"
if [ -f "\$ctl" ] && grep -qx "fail:\$acct" "\$ctl" 2>/dev/null; then
  echo "ERROR: 429 Too Many Requests — you have hit your usage limit" >&2
  exit 1
fi
if [ -f "\$ctl" ] && grep -qx "authfail:\$acct" "\$ctl" 2>/dev/null; then
  echo "Error: token expired. Please run codex login again" >&2
  exit 1
fi
if [ -f "\$ctl" ] && grep -qx "orgfail:\$acct" "\$ctl" 2>/dev/null; then
  echo "Codex has been disabled by your workspace admin"
  exit 1
fi
outfile=""
prev=""
for a in "\$@"; do
  case "\$prev" in -o|--output-last-message) outfile="\$a" ;; esac
  case "\$a" in
    --exit7) echo "ordinary failure, not auth related" >&2; exit 7 ;;
    --echo-stdin) cat; exit 0 ;;
  esac
  prev="\$a"
done
[ -n "\$outfile" ] && printf 'OK' > "\$outfile"
# what an interactive client would inherit from the shim (auto-resume must leak nothing)
[ -n "\${FAKE_PRINT_ENV:-}" ] && echo "AR_ENV=\$(env | grep -c '^CODEX_MULTIACC_AR')"
echo "CFG=\$acct"
EOF
chmod +x "$FAKEBIN/codex"

# ---- C1. passthrough: no manifest yet ---------------------------------------------
out="$(codex 2>&1)"
check "codex: passthrough without manifest" "CFG=none" "$out"

# ---- codex manifest + two chatgpt accounts ----------------------------------------
cat > "$CX/accounts.json" <<EOF
{
  "version": 1,
  "server": "root@203.0.113.1",
  "server_root": "/root/.codex-accounts",
  "server_repo": "/root/claude-multiacc",
  "threshold": 90,
  "accounts": [
    {"id": "acct-01", "email": "a@cx", "home": "mac", "added_at": "2026-08-21T00:00:00Z"},
    {"id": "acct-02", "email": "b@cx", "home": "mac", "added_at": "2026-08-21T00:00:00Z"}
  ]
}
EOF
for i in 01 02; do
  mkdir -p "$CX/acct-$i"
done
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
mk_cx_auth "$CX/acct-02/auth.json" b@cx "$FUTURE_EXP"

# ---- C2. passthrough guards --------------------------------------------------------
out="$(CODEX_HOME=/tmp/other codex 2>&1)"
check "codex: passthrough with CODEX_HOME" "CFG=other" "$out"
out="$(CODEX_MULTIACC_DISABLE=1 codex 2>&1)"
check "codex: passthrough when disabled" "CFG=none" "$out"

# ---- C3. headroom selection: session gate first, then the WEEKLY headroom band ------
cxlj() { printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":%s,"max_percent":%s,"buckets":[]}' "$now" "$1" "$2" "$3"; }
cxlj 80 10 80 > "$CX/acct-01/limits.json"
cxlj 20 10 20 > "$CX/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: picks the highest weekly-headroom account" \
  || t_fail "codex headroom selection" "picked the more-utilized account"
# Keep direct-provider behavior aligned with pool-selection.v2: both accounts inside
# the default 30-point band receive launches; a caller can set 0 for strict ranking.
cxlj 0 10 10 > "$CX/acct-01/limits.json"
cxlj 30 10 30 > "$CX/acct-02/limits.json"
hits1=0; hits2=0
for _ in $(seq 1 20); do
  case "$(codex 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "codex: 30-point headroom band spreads launches (acct-01=$hits1 acct-02=$hits2)" \
  || t_fail "codex headroom band spread" "acct-01=$hits1 acct-02=$hits2"
cxlj 20 10 20 > "$CX/acct-02/limits.json"
all1=1
for _ in $(seq 1 10); do
  case "$(CODEX_MULTIACC_HEADROOM_BAND=0 codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = 1 ] && t_ok "codex: headroom band 0 restores strict ranking" \
  || t_fail "codex zero headroom band" "the runner-up was selected"
# THE KEY CASE, REVERSED on 2026-09-03, in parity with the claude shim (section 5):
# the operator asked for "among accounts where high session limits it must choose
# randomly from ones where highest weekly limits", so a nearly-spent 5h bucket is the
# FIRST cut and the 30-point weekly band ranks only what clears the gate. acct-01:
# session 85 (past the gate), weekly 10; acct-02: session 20, weekly 70 -> acct-02.
cxlj 10 85 85 > "$CX/acct-01/limits.json"
cxlj 70 20 70 > "$CX/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: a session bucket past the gate is skipped while a fresher one exists (70w/20s over 10w/85s)" \
  || t_fail "codex session gate" "the account with its 5h bucket at 85% was still selected"
: > "$CX/selection.log"
codex >/dev/null 2>&1
grep -qE 'acct-02 weekly=70% session=20% band=30 band-count=1 session-gate=50 session-ok=1 pwd=' "$CX/selection.log" \
  && t_ok "codex: the selection log carries session-gate=50 session-ok=1 when one of two clears" \
  || t_fail "codex session gate log" "$(tail -1 "$CX/selection.log")"
# Both sessions inside the gate: it has nothing to say and weekly decides as before.
cxlj 10 45 45 > "$CX/acct-01/limits.json"
cxlj 70 20 70 > "$CX/acct-02/limits.json"
all1=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "codex: with both sessions inside the gate weekly headroom decides (10w/45s over 70w/20s)" \
  || t_fail "codex session gate no-op" "the gate changed a ranking where every candidate cleared it"
# Nobody clears it: the gate compares, it never empties the pool — it steps aside.
cxlj 10 85 85 > "$CX/acct-01/limits.json"
cxlj 70 60 70 > "$CX/acct-02/limits.json"
: > "$CX/selection.log"
all1=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "codex: with nobody inside the gate it steps aside and weekly ranks (10w/85s over 70w/60s)" \
  || t_fail "codex session gate step-aside" "an empty gate emptied the pool instead of stepping aside"
grep -qE 'acct-01 weekly=10% session=85% band=30 band-count=1 session-gate=50 session-ok=0 pwd=' "$CX/selection.log" \
  && t_ok "codex: the selection log carries session-ok=0 when the gate steps aside" \
  || t_fail "codex session gate log" "$(tail -1 "$CX/selection.log")"
# The gate is a knob, like the band: 100 turns it off; garbage falls back to 50.
cxlj 10 85 85 > "$CX/acct-01/limits.json"
cxlj 70 20 70 > "$CX/acct-02/limits.json"
all1=1
for _ in $(seq 1 15); do
  case "$(CODEX_MULTIACC_SESSION_GATE=100 codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "codex: CODEX_MULTIACC_SESSION_GATE=100 disables the gate" \
  || t_fail "codex session gate off" "the gate still fired at 100"
all2=1
for _ in $(seq 1 15); do
  case "$(CODEX_MULTIACC_SESSION_GATE=abc codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: a non-numeric CODEX_MULTIACC_SESSION_GATE falls back to 50" \
  || t_fail "codex session gate validation" "a garbage gate value changed the outcome"
# Equal weekly usage: the GATE decides, never a tiebreak — strict band or default 30.
cxlj 40 20 40 > "$CX/acct-01/limits.json"
cxlj 40 80 80 > "$CX/acct-02/limits.json"
all1=1
for _ in $(seq 1 15); do
  case "$(CODEX_MULTIACC_HEADROOM_BAND=0 codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "codex: strict mode: the session gate decides an exact weekly tie" \
  || t_fail "codex session gate tie" "a weekly tie was not resolved by the session gate"
all1=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "codex: the gate (not the band) removes the session-heavy half of a weekly tie" \
  || t_fail "codex session gate tie" "the default band let the 80-point session account back in"

# Inside the gate, session is NOT a tiebreaker any more: an exact weekly tie between two
# gate-clearing accounts is a coin flip even in strict mode (it used to go to the lower
# session, through the old weekly*1000+session score).
cxlj 40 20 40 > "$CX/acct-01/limits.json"
cxlj 40 45 45 > "$CX/acct-02/limits.json"
hits1=0; hits2=0
for _ in $(seq 1 20); do
  case "$(CODEX_MULTIACC_HEADROOM_BAND=0 codex 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "codex: strict mode: session does not break an exact weekly tie inside the gate (acct-01=$hits1 acct-02=$hits2)" \
  || t_fail "codex: session tiebreak removed" "acct-01=$hits1 acct-02=$hits2 (want both >0)"

# Clearing the gate takes BOTH readings, as in pool-selection.v2: a fresh file with a
# session reading but no weekly one must not become the sole gate-clearer and win the
# all-gated tie over an account with a truthful weekly reading — not even with a
# max_percent to fall back on (the shims used to rank on that; the policy never could).
# (No writer produces such a file; this pins parity with lib/selector_policy.py.)
printf '{"fetched_at":%s,"max_percent":10,"session_percent":10,"buckets":[]}' "$now" > "$CX/acct-01/limits.json"
cxlj 20 80 80 > "$CX/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: a session reading without a weekly one never clears the gate" \
  || t_fail "codex: gate needs both readings" "an unknown-weekly account beat a truthful weekly reading"

# ...and the converse: a weekly reading without a session one is not "known" either — it
# neither clears the gate nor ranks once the gate steps aside (10w/?s vs 70w/80s -> the
# 70w account, as in pool-selection.v2, where quota_known needs both readings).
printf '{"fetched_at":%s,"weekly_percent":10,"max_percent":10,"buckets":[]}' "$now" > "$CX/acct-01/limits.json"
cxlj 70 80 80 > "$CX/acct-02/limits.json"
all2=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: a weekly reading without a session one is unknown to both cuts" \
  || t_fail "codex: known needs both readings" "a session-less weekly reading ranked as known"
# equal scores spread load
cxlj 10 10 10 > "$CX/acct-01/limits.json"
cxlj 10 10 10 > "$CX/acct-02/limits.json"
hits1=0; hits2=0
for _ in $(seq 1 40); do
  case "$(codex 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ] && [ $((hits1+hits2)) -eq 40 ]; } \
  && t_ok "codex: equal scores spread randomly (acct-01=$hits1 acct-02=$hits2)" \
  || t_fail "codex tie spreading" "acct-01=$hits1 acct-02=$hits2 (want both >0, total 40)"
# Unknown telemetry ranks behind every truthful reading, never as neutral or free.
printf '{"fetched_at":1,"weekly_percent":1,"session_percent":1,"max_percent":1,"buckets":[]}' > "$CX/acct-01/limits.json"
cxlj 30 30 30 > "$CX/acct-02/limits.json"
out="$(codex 2>&1)"
check "codex: stale 1% loses to fresh 30%" "CFG=acct-02" "$out"
cxlj 88 88 88 > "$CX/acct-01/limits.json"
rm -f "$CX/acct-02/limits.json" "$CX/.last-pick"
all1=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-01*) ;; *) all1=0 ;; esac
done
[ "$all1" = "1" ] && t_ok "codex: unknown telemetry never beats known 88%" \
  || t_fail "codex unknown telemetry ranking" "the unknown account beat truthful 88% usage"
rm -f "$CX/acct-01/limits.json" "$CX/.last-pick"
hits1=0; hits2=0
for _ in $(seq 1 40); do
  case "$(codex 2>&1)" in
    *CFG=acct-01*) hits1=$((hits1+1)) ;;
    *CFG=acct-02*) hits2=$((hits2+1)) ;;
  esac
done
{ [ "$hits1" -gt 0 ] && [ "$hits2" -gt 0 ]; } \
  && t_ok "codex: an entirely unknown pool still fails open" \
  || t_fail "codex unknown pool fail-open" "acct-01=$hits1 acct-02=$hits2"
rm -f "$CX"/acct-*/limits.json

# ---- C4. pin -----------------------------------------------------------------------
out="$(CODEX_ACCOUNT=acct-02 codex 2>&1)"
check "codex: CODEX_ACCOUNT pin" "CFG=acct-02" "$out"
mkdir -p "$CX/acct-07"
out="$(CODEX_ACCOUNT=acct-07 codex 2>&1)"
check "codex: pin to auth-less dir (ceremony)" "CFG=acct-07" "$out"
rmdir "$CX/acct-07"

# ---- C5. limited marker excludes; pin overrides; expired marker self-clears ---------
printf '%s\nbucket=GPT-5.3-Codex-Spark:7d percent=95 reason=limits\n' "$((now+3600))" > "$CX/acct-01/.limited"
all2=1
for _ in $(seq 1 15); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: limited account excluded from pool" || t_fail "codex limited exclusion" "acct-01 was still picked"
out="$(CODEX_ACCOUNT=acct-01 codex 2>&1)"
check "codex: explicit pin wins over marker" "CFG=acct-01" "$out"
printf '%s\nbucket=5h percent=95 reason=limits\n' "$((now-10))" > "$CX/acct-01/.limited"
codex >/dev/null 2>&1
[ ! -f "$CX/acct-01/.limited" ] && t_ok "codex: expired .limited marker self-clears" \
  || t_fail "codex marker expiry" ".limited survived its reset time"

# ---- C5b. client-reported rate limits (rollouts) + rotation -------------------------
# Parity with the claude shim: never depend on the usage endpoint to notice an account
# ran dry. The codex CLI writes the windows the server reported into every run's
# rollout, and rollouts live inside the account dir — so no session index is needed.
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/limits.json "$CX/.pick-seq" "$CX"/acct-0*/.last-pick
rm -rf "$CX"/acct-0*/sessions
mkrollout() { # mkrollout <acct dir> <used_percent> <resets_at>
  local day="$1/sessions/2026/08/20"
  mkdir -p "$day"
  {
    printf '{"timestamp":"2026-08-19T22:43:21.299Z","type":"session_meta","payload":{"session_id":"01a01c31","cwd":"/proj"}}\n'
    printf '{"timestamp":"2026-08-19T22:49:54.120Z","type":"event_msg","payload":{"type":"token_count","info":{"model_context_window":258400},"rate_limits":{"limit_id":"codex","limit_name":null,"primary":{"used_percent":%s,"window_minutes":10080,"resets_at":%s},"secondary":null,"credits":{"has_credits":false,"unlimited":false,"balance":"0"}}}}\n' "$2" "$3"
  } > "$day/rollout-2026-08-20T01-43-21-01a01c31-7fc3-7291-a0fc-7b4e2b035f1a.jsonl"
}
mkrollout "$CX/acct-01" "97.4" "$((now + 3600))"
all2=1
for _ in $(seq 1 12); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: a spent window in the account's own rollout excludes it" \
  || t_fail "codex client rate limit" "the spent account was picked again"
first="$(head -1 "$CX/acct-01/.limited" 2>/dev/null)"
[ "$first" = "$((now + 3600))" ] && t_ok "codex: marker carries the reported reset time" \
  || t_fail "codex client marker reset" "want $((now + 3600)), got '${first:-<none>}'"
grep -q 'reason=client-rate-limit' "$CX/acct-01/.limited" 2>/dev/null \
  && t_ok "codex: marker is tagged client-rate-limit" \
  || t_fail "codex client marker reason" "$(cat "$CX/acct-01/.limited" 2>/dev/null)"
rm -f "$CX/acct-01/.limited"

# under the threshold is just usage, not an exclusion
mkrollout "$CX/acct-01" "40.0" "$((now + 3600))"
hits1=0
for _ in $(seq 1 12); do
  case "$(codex 2>&1)" in *CFG=acct-01*) hits1=$((hits1+1)) ;; esac
done
{ [ "$hits1" -gt 0 ] && [ ! -f "$CX/acct-01/.limited" ]; } \
  && t_ok "codex: a sub-threshold window does not exclude" \
  || t_fail "codex sub-threshold rollout" "acct-01 hits=$hits1"

# a window that has already reset is history
mkrollout "$CX/acct-01" "99.0" "$((now - 60))"
hits1=0
for _ in $(seq 1 12); do
  case "$(codex 2>&1)" in *CFG=acct-01*) hits1=$((hits1+1)) ;; esac
done
{ [ "$hits1" -gt 0 ] && [ ! -f "$CX/acct-01/.limited" ]; } \
  && t_ok "codex: an elapsed window does not exclude" \
  || t_fail "codex elapsed rollout window" "acct-01 hits=$hits1"

# opt-out
mkrollout "$CX/acct-01" "99.0" "$((now + 3600))"
hits1=0
for _ in $(seq 1 12); do
  case "$(CODEX_MULTIACC_CLIENT_LIMITS=0 codex 2>&1)" in *CFG=acct-01*) hits1=$((hits1+1)) ;; esac
done
{ [ "$hits1" -gt 0 ] && [ ! -f "$CX/acct-01/.limited" ]; } \
  && t_ok "codex: CODEX_MULTIACC_CLIENT_LIMITS=0 turns the scan off" \
  || t_fail "codex client-limit opt-out" "still excluded with the scan disabled"
rm -rf "$CX"/acct-0*/sessions
rm -f "$CX"/acct-0*/.limited

# equal-headroom picks rotate instead of re-rolling a coin
rm -f "$CX/.pick-seq" "$CX"/acct-0*/.last-pick "$CX"/acct-0*/limits.json
seq_out=""
for _ in $(seq 1 8); do
  case "$(codex 2>&1)" in
    *CFG=acct-01*) seq_out="${seq_out}1" ;;
    *CFG=acct-02*) seq_out="${seq_out}2" ;;
    *) seq_out="${seq_out}?" ;;
  esac
done
case "$seq_out" in
  12121212|21212121) t_ok "codex: equal-score picks round-robin across the pool ($seq_out)" ;;
  *) t_fail "codex round-robin tie-break" "sequence $seq_out (want strict alternation)" ;;
esac
rm -f "$CX/.pick-seq" "$CX"/acct-0*/.last-pick


# codex-review finding: the bounded rollout scan must start at the NEWEST file, or a
# busy account whose only over-threshold report is its latest run stays eligible.
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan
rm -rf "$CX"/acct-0*/sessions
mkdir -p "$CX/acct-01/sessions/2026/08/20"
i=1
while [ "$i" -le 12 ]; do
  printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":10.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
    "$((now + 3600))" > "$CX/acct-01/sessions/2026/08/20/rollout-2026-08-20T0$(printf '%01d' $((i % 10)))-0$i-old$i.jsonl"
  i=$((i + 1))
done
printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":100.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
  "$((now + 3600))" > "$CX/acct-01/sessions/2026/08/20/rollout-2026-08-20T99-99-newest.jsonl"
codex >/dev/null 2>&1
grep -q 'reason=client-rate-limit' "$CX/acct-01/.limited" 2>/dev/null \
  && t_ok "codex: the newest rollout is read even past the file cap" \
  || t_fail "codex rollout scan order" "13 rollouts, only the newest over threshold — missed it"
rm -rf "$CX"/acct-0*/sessions
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan

# A SHARED sessions tree (the layout lib/common.sh actually installs: acct/sessions is a
# symlink to ~/.codex/sessions so `codex resume` finds every session) proves nothing about
# who spent the quota. One spent window there must not mark the whole pool.
SHARED="$WORK/cx-shared-sessions"
mkdir -p "$SHARED/2026/08/20"
printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":100.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
  "$((now + 3600))" > "$SHARED/2026/08/20/rollout-2026-08-20T01-00-00-shared.jsonl"
for i in 01 02; do ln -s "$SHARED" "$CX/acct-$i/sessions"; done
codex >/dev/null 2>&1
{ [ ! -f "$CX/acct-01/.limited" ] && [ ! -f "$CX/acct-02/.limited" ]; } \
  && t_ok "codex: a shared sessions symlink never marks an account (fail open)" \
  || t_fail "codex shared sessions" "a shared rollout tree marked the pool LIMITED"
out="$(codex 2>&1)"
case "$out" in *CFG=acct-0*) t_ok "codex: the pool still selects with a shared sessions tree" ;;
  *) t_fail "codex shared sessions" "selection produced: $out" ;; esac
rm -f "$CX"/acct-0*/sessions "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan

# second codex-review pass: a NESTED symlink inside a real sessions/ dir must not smuggle
# another tree's rollouts in, and a huge stale rollout directory must not be walked.
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan
rm -rf "$CX"/acct-0*/sessions
OUTSIDE="$WORK/cx-outside"
mkdir -p "$OUTSIDE/08/20" "$CX/acct-01/sessions"
printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":100.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
  "$((now + 3600))" > "$OUTSIDE/08/20/rollout-2026-08-20T01-00-00-outside.jsonl"
ln -s "$OUTSIDE" "$CX/acct-01/sessions/2026"
codex >/dev/null 2>&1
[ ! -f "$CX/acct-01/.limited" ] \
  && t_ok "codex: a nested symlink out of the account tree never marks it" \
  || t_fail "codex nested sessions symlink" "rollouts outside the account tree marked it LIMITED"
rm -f "$CX/acct-01/sessions/2026"

# a day dir stuffed with stale rollouts must cost a bounded amount of work, and the
# newest (over-threshold) file must still be the one that decides
mkdir -p "$CX/acct-01/sessions/2026/08/20"
i=1
while [ "$i" -le 60 ]; do
  printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":5.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
    "$((now + 3600))" > "$CX/acct-01/sessions/2026/08/20/rollout-2026-08-20T00-00-$(printf '%02d' "$i")-bulk.jsonl"
  i=$((i + 1))
done
printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":100.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
  "$((now + 3600))" > "$CX/acct-01/sessions/2026/08/20/rollout-2026-08-20T23-59-59-newest.jsonl"
codex >/dev/null 2>&1
grep -q 'reason=client-rate-limit' "$CX/acct-01/.limited" 2>/dev/null \
  && t_ok "codex: 61 rollouts in one day dir — the newest still decides" \
  || t_fail "codex bulk rollout dir" "the newest rollout was not the one read"
rm -rf "$CX"/acct-0*/sessions
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan

# third codex-review pass: find(1) output is newline-delimited, so a pool file whose NAME
# contains a newline arrives as two lines and its tail resolves relative to $PWD.
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan
rm -rf "$CX"/acct-0*/sessions
mkdir -p "$CX/acct-01/sessions/2026/08/20"
ESCDIR="$WORK/cx-escape-dir"
mkdir -p "$ESCDIR"
printf '{"type":"event_msg","payload":{"rate_limits":{"primary":{"used_percent":100.0,"window_minutes":10080,"resets_at":%s},"secondary":null}}}\n' \
  "$((now + 3600))" > "$ESCDIR/escape.jsonl"
# ONE file whose name embeds a newline; find prints it as two lines, and the second
# ("escape.jsonl") would resolve against the caller's cwd — outside the pool entirely.
HOSTILE=$'rollout-a\nescape.jsonl'
: > "$CX/acct-01/sessions/2026/08/20/$HOSTILE"
[ -e "$CX/acct-01/sessions/2026/08/20/$HOSTILE" ] \
  || t_fail "codex newline filename" "fixture not created — the guard would go unexercised"
( cd "$ESCDIR" && codex >/dev/null 2>&1 )
[ ! -f "$CX/acct-01/.limited" ] \
  && t_ok "codex: a newline in a rollout name cannot pull in a file outside the pool" \
  || t_fail "codex newline filename" "a file outside the pool marked the account LIMITED"
rm -rf "$CX"/acct-0*/sessions
rm -f "$CX"/acct-0*/.limited "$CX"/acct-0*/.client-scan

# corrupt pool state must never reach bash arithmetic here either
CXBIG="99999999999999999999999999999999"
printf '%s\n' "$CXBIG" > "$CX/.last-pick"
printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":1,"max_percent":%s,"buckets":[]}' "$CXBIG" "$CXBIG" "$CXBIG" > "$CX/acct-02/limits.json"
err="$(codex 2>&1 >/dev/null)"
[ -z "$err" ] && t_ok "codex: absurd pool numbers keep stderr byte-clean" \
  || t_fail "codex corrupt number handling" "stderr: $(printf '%s' "$err" | head -c 160)"
rm -f "$CX/.last-pick" "$CX"/acct-0*/limits.json
: > "$CX/acct-01/.client-scan"
err="$(CODEX_MULTIACC_CLIENT_SCAN_TTL=bogus CODEX_MULTIACC_THRESHOLD=nonsense codex 2>&1 >/dev/null)"
out="$(CODEX_MULTIACC_CLIENT_SCAN_TTL=bogus CODEX_MULTIACC_THRESHOLD=nonsense codex 2>/dev/null)"
{ [ -z "$err" ] && case "$out" in *CFG=acct-0*) true ;; *) false ;; esac; } \
  && t_ok "codex: garbage in the TTL / threshold env vars keeps stderr clean" \
  || t_fail "codex env number validation" "stderr: $(printf '%s' "$err" | head -c 160) out: $out"
rm -f "$CX"/acct-0*/.client-scan

# a parallel burst still spreads (rotation drops only the account just handed out).
# Three accounts, for the same reason as the claude side: with two, landing entirely on
# the single alternative is correct behaviour and the assertion would measure nothing.
mkdir -p "$CX/acct-09"
"$MKAUTH" > "$CX/acct-09/auth.json" 2>/dev/null || \
  printf '{"tokens":{"access_token":"%s","account_id":"a9"},"last_refresh":"2026-08-01T00:00:00Z"}' \
    "$(sed -n 's/.*"access_token"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$CX/acct-01/auth.json" | head -1)" \
    > "$CX/acct-09/auth.json"
: > "$WORK/cx-burst.out"
for _ in $(seq 1 16); do ( codex >> "$WORK/cx-burst.out" 2>&1 ) & done
wait
c_distinct="$(grep -o 'CFG=acct-[0-9]*' "$WORK/cx-burst.out" | sort -u | tr '\n' ' ')"
c_n="$(printf '%s' "$c_distinct" | wc -w | tr -d ' ')"
[ "$c_n" -ge 2 ] \
  && t_ok "codex: a parallel burst still spreads across the pool ($c_distinct)" \
  || t_fail "codex burst spreading" "all 16 concurrent runs took $c_distinct"
rm -rf "$CX/acct-09"
rm -f "$CX/.last-pick"

# ---- C6. all limited -> the still-serving accounts go through the same two cuts, strict weekly --
printf '%s\nbucket=7d percent=95 reason=limits\n' "$((now+3600))" > "$CX/acct-01/.limited"
printf '%s\nbucket=7d percent=99 reason=limits\n' "$((now+3600))" > "$CX/acct-02/.limited"
cxlj 95 10 95 > "$CX/acct-01/limits.json"
cxlj 99 10 99 > "$CX/acct-02/limits.json"
out="$(codex 2>&1)"
check "codex: all-limited falls back to the still-serving account with the most weekly headroom" "CFG=acct-01" "$out"
grep -q "all-limited fallback=acct-01" "$CX/selection.log" \
  && t_ok "codex: all-limited fallback logged" || t_fail "codex fallback log" "no all-limited line"
rm -f "$CX"/acct-*/.limited "$CX"/acct-*/limits.json

# The fallback applies the SAME two cuts (parity with the claude shim, section 9): an
# account past the session gate yields to one inside it even with far better weekly.
printf '%s\nbucket=7d percent=95 reason=limits\n' "$((now+3600))" > "$CX/acct-01/.limited"
printf '%s\nbucket=7d percent=95 reason=limits\n' "$((now+3600))" > "$CX/acct-02/.limited"
cxlj 10 85 85 > "$CX/acct-01/limits.json"
cxlj 70 20 70 > "$CX/acct-02/limits.json"
all2=1
for _ in $(seq 1 12); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: the all-limited fallback applies the session gate before strict weekly (70w/20s over 10w/85s)" \
  || t_fail "codex fallback session gate" "the fallback handed out the account past the session gate"
grep -q "all-limited fallback=acct-02 weekly=70%" "$CX/selection.log" \
  && t_ok "codex: the fallback line names the gated pick" || t_fail "codex fallback gate log" "$(tail -1 "$CX/selection.log")"
rm -f "$CX"/acct-*/.limited "$CX"/acct-*/limits.json

# ---- C6b. the fallback tells "still serving" from "rejected right now" ----------------
# Ported from the claude shim (2026-08-29) when the session gate reached the fallback.
# acct-01: 7d window at 99% — worse headroom, but still answering. acct-02: 5h window at
# 100% — far better weekly (7%), but every request bounces until the reset.
printf '%s\nbucket=7d percent=99 marked_at=x reason=limits\n' "$((now+3600))" > "$CX/acct-01/.limited"
printf '%s\nbucket=5h percent=100 marked_at=x reason=limits\n' "$((now+600))" > "$CX/acct-02/.limited"
cxlj 99 10 99 > "$CX/acct-01/limits.json"
cxlj 7 100 100 > "$CX/acct-02/limits.json"
out="$(codex 2>&1)"
check "codex: a still-serving limited account beats an exhausted one with more headroom" "CFG=acct-01" "$out"
# The codex-review case (2026-09-04): the exhausted account is the only one INSIDE the
# session gate; the gate must not resurrect it over a still-serving account outside it.
printf '%s\nbucket=7d percent=100 marked_at=x reason=limits\n' "$((now+3600))" > "$CX/acct-01/.limited"
printf '%s\nbucket=7d percent=95 marked_at=x reason=limits\n' "$((now+3600))" > "$CX/acct-02/.limited"
cxlj 100 20 100 > "$CX/acct-01/limits.json"
cxlj 95 85 95 > "$CX/acct-02/limits.json"
out="$(codex 2>&1)"
check "codex: an exhausted account inside the gate never beats a still-serving one outside it" "CFG=acct-02" "$out"
# A real client rejection (a 429 the server sent) is exhausted whatever percent says.
printf '%s\nbucket=client:5h percent=95 marked_at=x reason=client-rate-limit\n' "$((now+600))" > "$CX/acct-01/.limited"
cxlj 95 10 95 > "$CX/acct-01/limits.json"
out="$(codex 2>&1)"
check "codex: a client-rejected account is not the fallback while another still serves" "CFG=acct-02" "$out"
# Every account exhausted RIGHT NOW: hand out the one that unblocks first.
printf '%s\nbucket=5h percent=100 marked_at=x reason=limits\n' "$((now+7200))" > "$CX/acct-01/.limited"
printf '%s\nbucket=5h percent=100 marked_at=x reason=limits\n' "$((now+600))" > "$CX/acct-02/.limited"
out="$(codex 2>&1)"
check "codex: all exhausted: the soonest reset is handed out" "CFG=acct-02" "$out"
grep -q "all-exhausted resets_in=" "$CX/selection.log" \
  && t_ok "codex: the all-exhausted pick is logged with its reset" || t_fail "codex all-exhausted log" "no line"
rm -f "$CX"/acct-*/.limited "$CX"/acct-*/limits.json

# ---- C7. dead logins: .expired excludes, heals on newer credential ------------------
printf '%s\nreason=refresh-denied-http-400 marked_at=t detail=x\n' "$now" > "$CX/acct-01/.expired"
all2=1
for _ in $(seq 1 10); do
  case "$(codex 2>&1)" in *CFG=acct-02*) ;; *) all2=0 ;; esac
done
[ "$all2" = "1" ] && t_ok "codex: dead login (proven park) is never selected" \
  || t_fail "codex dead login" "a parked account was selected"
# ...not even as the all-limited fallback
printf '%s\nbucket=7d percent=95 reason=limits\n' "$((now+3600))" > "$CX/acct-02/.limited"
out="$(codex 2>&1)"
check "codex: limited-but-alive beats dead in the fallback" "CFG=acct-02" "$out"
rm -f "$CX/acct-02/.limited"
# a NEWER credential heals a credential-scoped park
sleep 1
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
out="$(CODEX_SHIM_SELECT=random codex 2>&1)"
[ ! -f "$CX/acct-01/.expired" ] && t_ok "codex: newer auth.json clears a credential park" \
  || t_fail "codex park heal" ".expired survived a newer credential"
grep -qE 'band=30 band-count=[0-9]+ session-gate=off session-ok=[0-9]+ pwd=' "$CX/selection.log" \
  && t_ok "codex: random mode logs session-gate=off instead of a cut it never made" \
  || t_fail "codex random mode gate log" "$(tail -1 "$CX/selection.log")"
# an org-blocked park survives a newer credential (policy, not credential)
printf '%s\nreason=org-blocked marked_at=t detail=x\n' "$now" > "$CX/acct-01/.expired"
sleep 1
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
codex >/dev/null 2>&1
[ -f "$CX/acct-01/.expired" ] && t_ok "codex: org-blocked park survives a credential refresh" \
  || t_fail "codex org park" "a token write cleared an org-policy park"
rm -f "$CX/acct-01/.expired"
# a soft-stamped park expires on its own
printf '%s\nreason=auth-error soft_until=%s marked_at=t detail=x\n' "$now" "$((now-5))" > "$CX/acct-02/.expired"
codex >/dev/null 2>&1
[ ! -f "$CX/acct-02/.expired" ] && t_ok "codex: soft_until park expires on its own" \
  || t_fail "codex soft park" "an elapsed soft park still excluded the account"

# ---- C8. exec auto-retry ------------------------------------------------------------
# Strict mode makes acct-01's better score deterministic for these retry-path tests;
# the scripted failure then forces the retry onto acct-02.
cx_first_01() { cxlj 5 5 5 > "$CX/acct-01/limits.json"; cxlj 20 20 20 > "$CX/acct-02/limits.json"; }
cx_first_01
# rate limit: retry on the other account + self-expiring cooldown for the failed one
echo "fail:acct-01" > "$FAKE_CTL2"
out="$(CODEX_MULTIACC_HEADROOM_BAND=0 codex exec "hello" < /dev/null 2>&1)"
case "$out" in *CFG=acct-02*) t_ok "codex: exec retries a rate-limited account on another" ;;
  *) t_fail "codex retry" "did not land on acct-02: $out" ;; esac
if [ -f "$CX/acct-01/.limited" ]; then
  grep -q "error-cooldown" "$CX/acct-01/.limited" \
    && t_ok "codex: rate-limited account got a cooldown, not a park" \
    || t_fail "codex cooldown" "marker is not an error-cooldown"
else
  t_fail "codex cooldown" "no .limited cooldown written"
fi
rm -f "$CX/acct-01/.limited" "$FAKE_CTL2"
# auth failure parks (soft) instead of a cooldown
cx_first_01
echo "authfail:acct-01" > "$FAKE_CTL2"
CODEX_MULTIACC_HEADROOM_BAND=0 codex exec "hello" < /dev/null >/dev/null 2>&1
if [ -f "$CX/acct-01/.expired" ]; then
  grep -q "reason=auth-error" "$CX/acct-01/.expired" && grep -q "soft_until=" "$CX/acct-01/.expired" \
    && t_ok "codex: auth failure parks the account with a soft stamp" \
    || t_fail "codex auth park" "marker malformed: $(cat "$CX/acct-01/.expired")"
else
  t_fail "codex auth park" "no .expired written after an auth failure"
fi
rm -f "$CX/acct-01/.expired" "$FAKE_CTL2"
# org-disabled failure parks as org-blocked
cx_first_01
echo "orgfail:acct-01" > "$FAKE_CTL2"
CODEX_MULTIACC_HEADROOM_BAND=0 codex exec "hello" < /dev/null >/dev/null 2>&1
grep -q "reason=org-blocked" "$CX/acct-01/.expired" 2>/dev/null \
  && t_ok "codex: workspace-disabled failure parks as org-blocked" \
  || t_fail "codex org park from run" "marker: $(cat "$CX/acct-01/.expired" 2>/dev/null || echo none)"
rm -f "$CX/acct-01/.expired" "$FAKE_CTL2"
# ordinary failure: exit code passes through, no retry, no marker
out="$(codex exec --exit7 < /dev/null 2>&1)"
rc=$?
[ "$rc" = "7" ] && t_ok "codex: non-auth failure exit code passes through" || t_fail "codex rc passthrough" "rc=$rc"
[ ! -f "$CX/acct-01/.limited" ] && [ ! -f "$CX/acct-02/.limited" ] \
  && t_ok "codex: ordinary failure marks nothing" || t_fail "codex ordinary failure" "a marker appeared"
# retry only engages for exec: a plain (interactive-style) run with a failing account
# passes the failure straight through — no retry, no marker classification.
printf 'fail:acct-01\nfail:acct-02\n' > "$FAKE_CTL2"
out="$(codex "prompt" < /dev/null 2>&1)"
rc=$?
[ "$rc" = "1" ] && t_ok "codex: non-exec run is never retried (rc passes through)" \
  || t_fail "codex non-exec retry" "rc=$rc"
[ ! -f "$CX/acct-01/.limited" ] && [ ! -f "$CX/acct-02/.limited" ] \
  && t_ok "codex: non-exec failure writes no markers" \
  || t_fail "codex non-exec markers" "a marker appeared without the retry path"
rm -f "$FAKE_CTL2" "$CX"/acct-*/.limited "$CX"/acct-*/.expired
# stdin/stdout byte fidelity through the retry path
printf 'line1\nline2\n' > "$WORK/cx-stdin.txt"
out="$(codex exec --echo-stdin < "$WORK/cx-stdin.txt" 2>&1)"
[ "$out" = "$(printf 'line1\nline2')" ] && t_ok "codex: stdin passes byte-identically through retry buffering" \
  || t_fail "codex stdin fidelity" "got: $out"
# user args survive selection
out="$(codex exec "two words" --exit7 < /dev/null 2>&1)"
rc=$?
[ "$rc" = "7" ] && t_ok "codex: user args survive selection (pick_best untouched \$@)" \
  || t_fail "codex args" "rc=$rc out=$out"
# HOME unset: fail open into passthrough
out="$(env -u HOME -u CODEX_ACCOUNTS_DIR PATH="$PATH" "$REPO_DIR/bin/codex" 2>&1)"
check "codex: HOME unset fails open into passthrough" "CFG=none" "$out"
rm -f "$CX"/acct-*/limits.json

# ---- C9. selection log --------------------------------------------------------------
grep -qE 'acct-0[12]' "$CX/selection.log" && t_ok "codex: selection.log written" \
  || t_fail "codex selection.log" "no selections logged"

# ---- C10. CLI: list / import / remove / dedupe --------------------------------------
out="$(codex-accounts list 2>&1)"
check "codex-accounts list shows accounts" "a@cx" "$out"
check "codex-accounts list shows auth kind" "auth=chatgpt" "$out"
mk_cx_auth "$WORK/cx-import.json" c@cx "$FUTURE_EXP"
out="$(codex-accounts import c@cx --id acct-03 --auth "$WORK/cx-import.json" --no-sync 2>&1)"
check "codex-accounts import" "Imported acct-03" "$out"
[ -f "$CX/acct-03/auth.json" ] && t_ok "codex: imported auth.json in place" || t_fail "codex import" "auth.json missing"
perm="$(ls -l "$CX/acct-03/auth.json" | cut -c1-10)"
[ "$perm" = "-rw-------" ] && t_ok "codex: imported auth.json is 0600" || t_fail "codex import perms" "$perm"
# duplicate email refused without --force / --id
out="$(codex-accounts import c@cx --no-sync 2>&1)"
rc=$?
check "codex: duplicate import refused" "already registered as acct-03" "$out"
[ "$rc" != "0" ] && t_ok "codex: duplicate import exits nonzero" || t_fail "codex dup import rc" "rc=0"
# dedupe removes a forced duplicate, keeping the authed one
codex-accounts import c@cx --id acct-04 --force --no-sync >/dev/null 2>&1
out="$(codex-accounts dedupe --yes 2>&1)"
check "codex: dedupe removes the duplicate" "Removed 1 duplicate" "$out"
codex-accounts list 2>&1 | grep -q "acct-04" \
  && t_fail "codex dedupe" "acct-04 still listed" || t_ok "codex: dedupe kept one entry per email"
out="$(codex-accounts remove acct-03 --yes 2>&1)"
check "codex-accounts remove" "Removed acct-03" "$out"
[ ! -d "$CX/acct-03" ] && t_ok "codex: removed account dir deleted" || t_fail "codex remove" "dir still present"

# ---- C11. login-first add ceremony --------------------------------------------------
# derived email: no argument, identity read back from the sign-in
out="$(FAKE_EMAIL=new@cx codex-accounts add 2>&1)"
check "codex: add with no email derives it from the sign-in" "Registered acct-03 for new@cx" "$out"
grep -q '"email": "new@cx"' "$CX/accounts.json" && t_ok "codex: derived email registered" \
  || t_fail "codex add derive" "manifest lacks new@cx"
# signed in as a different account than named: register who actually authenticated
out="$(FAKE_EMAIL=other@cx codex-accounts add named@cx 2>&1)"
check "codex: mismatched sign-in registers the real account" "registering the account that actually authenticated" "$out"
grep -q '"email": "other@cx"' "$CX/accounts.json" && t_ok "codex: actual identity registered" \
  || t_fail "codex add mismatch" "manifest lacks other@cx"
codex-accounts remove acct-04 --yes >/dev/null 2>&1
# aborted login leaves zero traces
before="$(ls "$CX" | sort)"
out="$(FAKE_LOGIN_FAIL=1 codex-accounts add gone@cx 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "codex: aborted login exits nonzero" || t_fail "codex abort rc" "rc=0"
after="$(ls "$CX" | sort)"
[ "$before" = "$after" ] && t_ok "codex: aborted login leaves zero traces" \
  || t_fail "codex abort traces" "pool dir changed: $after"
grep -q "gone@cx" "$CX/accounts.json" && t_fail "codex abort manifest" "gone@cx registered" \
  || t_ok "codex: aborted login registered nothing"
# adding an already-registered email skips before sign-in
out="$(codex-accounts add a@cx 2>&1)"
rc=$?
check "codex: add of registered email skips gracefully" "already added as acct-01" "$out"
[ "$rc" = "0" ] && t_ok "codex: duplicate add exits 0 (no-op)" || t_fail "codex dup add rc" "rc=$rc"
# signing in AS an already-registered email (unnamed) also refuses a second entry
out="$(FAKE_EMAIL=a@cx codex-accounts add 2>&1)"
check "codex: sign-in as registered email refused" "already added as acct-01" "$out"
n="$(grep -c '"email": "a@cx"' "$CX/accounts.json")"
[ "$n" = "1" ] && t_ok "codex: no second entry for a re-signed-in email" || t_fail "codex dup signin" "count=$n"

# ---- C11b. one index for the shared session tree ------------------------------------
# codex refuses to start until state_<schema>.sqlite has indexed every rollout under
# $CODEX_HOME/sessions. The layout shares that tree across accounts, so it must share
# the index too — a private index per account re-read the whole tree per account and
# stranded a 15-minute worker lease whenever a scan was cut short (my-mini 2026-09-09:
# six fresh accounts refused every launch as "local database appears to be damaged").
CXH="$WORK/cxhome"
mkdir -p "$CXH/.codex/sessions"
printf 'home index' > "$CXH/.codex/state_5.sqlite"
# (a) seeding: a new account links the tree AND the index the home already has
out="$(HOME="$CXH" FAKE_EMAIL=idx@cx codex-accounts add 2>&1)"
nid="$(printf '%s' "$out" | sed -n 's/.*Registered \(acct-[0-9]*\) .*/\1/p' | head -1)"
[ -n "$nid" ] || t_fail "codex shared index seed" "add did not register: $(printf '%s' "$out" | head -c 200)"
[ "$(readlink "$CX/$nid/sessions" 2>/dev/null)" = "$CXH/.codex/sessions" ] \
  && t_ok "codex: a new account shares the home's session tree" \
  || t_fail "codex shared tree seed" "sessions -> $(readlink "$CX/$nid/sessions" 2>/dev/null)"
[ "$(readlink "$CX/$nid/state_5.sqlite" 2>/dev/null)" = "$CXH/.codex/state_5.sqlite" ] \
  && t_ok "codex: a new account shares the home's rollout index with that tree" \
  || t_fail "codex shared index seed" "state_5.sqlite -> $(readlink "$CX/$nid/state_5.sqlite" 2>/dev/null)"
[ -n "$nid" ] && codex-accounts remove "$nid" --yes >/dev/null 2>&1

# The launch-time heal, on its own pool so nothing here leaks into the other codex tests.
CXS="$WORK/cx-state"
mkdir -p "$CXS/tmp" "$CXS/acct-01" "$CXS/acct-02" "$CXS/acct-03"
: > "$CXS/.limits-kick"
cat > "$CXS/accounts.json" <<EOF2
{"version": 1, "server": "root@203.0.113.1", "server_root": "/root/.codex-accounts",
 "server_repo": "/root/claude-multiacc", "threshold": 90,
 "accounts": [
  {"id": "acct-01", "email": "s1@cx", "home": "mac", "added_at": "2026-09-09T00:00:00Z"},
  {"id": "acct-02", "email": "s2@cx", "home": "mac", "added_at": "2026-09-09T00:00:00Z"},
  {"id": "acct-03", "email": "s3@cx", "home": "mac", "added_at": "2026-09-09T00:00:00Z"}]}
EOF2
for i in 01 02 03; do mk_cx_auth "$CXS/acct-$i/auth.json" "s$i@cx" "$FUTURE_EXP"; done
CXH2="$WORK/cxhome2"
mkdir -p "$CXH2/.codex/sessions"
ln -s "$CXH2/.codex/sessions" "$CXS/acct-01/sessions"
ln -s "$CXH2/.codex/sessions" "$CXS/acct-02/sessions"
mkdir -p "$CXS/acct-03/sessions"                       # a PRIVATE tree
printf 'closed private index' > "$CXS/acct-01/state_5.sqlite"
printf 'open private index' > "$CXS/acct-02/state_5.sqlite"
printf 'wal' > "$CXS/acct-02/state_5.sqlite-wal"
printf 'shm' > "$CXS/acct-02/state_5.sqlite-shm"
printf 'private tree index' > "$CXS/acct-03/state_5.sqlite"
# (b) an OPEN private index (its -wal beside it) is never moved while the home has no index
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-02 codex 2>&1)"
check "codex: launch on an account with an open private index" "CFG=acct-02" "$out"
{ [ -f "$CXS/acct-02/state_5.sqlite" ] && [ ! -L "$CXS/acct-02/state_5.sqlite" ] \
    && [ ! -e "$CXH2/.codex/state_5.sqlite" ]; } \
  && t_ok "codex: an open private index is never promoted (one inode, two -shm files, is how WAL corrupts)" \
  || t_fail "codex open index promote" "$(ls -la "$CXS/acct-02" "$CXH2/.codex" 2>&1 | head -c 400)"
# a -shm on its own is just as much a live database as a -wal is
mv "$CXS/acct-02/state_5.sqlite-wal" "$CXS/acct-02/held-wal"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-02 codex 2>&1)"
check "codex: launch on an account whose index has only a -shm" "CFG=acct-02" "$out"
{ [ -f "$CXS/acct-02/state_5.sqlite" ] && [ ! -e "$CXH2/.codex/state_5.sqlite" ]; } \
  && t_ok "codex: a -shm alone also refuses the promote" \
  || t_fail "codex shm promote" "$(ls -la "$CXS/acct-02" "$CXH2/.codex" 2>&1 | head -c 400)"
mv "$CXS/acct-02/held-wal" "$CXS/acct-02/state_5.sqlite-wal"
# (c) a CLOSED private index is promoted into the home and linked back
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-01 codex 2>&1)"
check "codex: launch on an account with a closed private index" "CFG=acct-01" "$out"
[ "$(cat "$CXH2/.codex/state_5.sqlite" 2>/dev/null)" = "closed private index" ] \
  && t_ok "codex: the first closed private index becomes the home's shared index" \
  || t_fail "codex index promote" "home index: $(cat "$CXH2/.codex/state_5.sqlite" 2>&1 | head -c 80)"
[ "$(readlink "$CXS/acct-01/state_5.sqlite" 2>/dev/null)" = "$CXH2/.codex/state_5.sqlite" ] \
  && t_ok "codex: the promoting account links to the shared index" \
  || t_fail "codex index promote link" "state_5.sqlite -> $(readlink "$CXS/acct-01/state_5.sqlite" 2>/dev/null)"
# (d) the home has an index now, but the account's own is still OPEN: moving it would
#     split its holder across two databases (codex's sqlx pool re-opens BY PATH), so it
#     is left alone until the process that has it exits and clears its -wal/-shm.
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-02 codex 2>&1)"
check "codex: relaunch on the account with the open private index" "CFG=acct-02" "$out"
{ [ -f "$CXS/acct-02/state_5.sqlite" ] && [ ! -L "$CXS/acct-02/state_5.sqlite" ]; } \
  && t_ok "codex: an index a process can still open is never moved, even once the home has one" \
  || t_fail "codex open index retire" "$(ls "$CXS/acct-02" 2>&1 | tr '\n' ' ')"
# (d2) its holder exited and SQLite removed the pair: now it is retired beside the link
rm -f "$CXS/acct-02/state_5.sqlite-wal" "$CXS/acct-02/state_5.sqlite-shm"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-02 codex 2>&1)"
check "codex: relaunch once the private index is closed" "CFG=acct-02" "$out"
[ "$(readlink "$CXS/acct-02/state_5.sqlite" 2>/dev/null)" = "$CXH2/.codex/state_5.sqlite" ] \
  && t_ok "codex: a closed private index is retired for the shared one once the home has it" \
  || t_fail "codex index retire" "state_5.sqlite -> $(readlink "$CXS/acct-02/state_5.sqlite" 2>/dev/null)"
[ "$(cat "$CXS/acct-02/state_5.sqlite.private" 2>/dev/null)" = "open private index" ] \
  && t_ok "codex: the retired index stays beside the link, never deleted" \
  || t_fail "codex index retire files" "$(ls "$CXS/acct-02" 2>&1 | tr '\n' ' ')"
[ "$(cat "$CXH2/.codex/state_5.sqlite" 2>/dev/null)" = "closed private index" ] \
  && t_ok "codex: retiring never overwrites the shared index" \
  || t_fail "codex index retire overwrite" "home index changed"
# (d3) an account with NO index of its own is linked even while the shared one is in use —
#      the case the whole change exists for, and the one liveness must never block
mkdir -p "$CXS/acct-06" && ln -s "$CXH2/.codex/sessions" "$CXS/acct-06/sessions"
mk_cx_auth "$CXS/acct-06/auth.json" s6@cx "$FUTURE_EXP"
printf 'wal' > "$CXH2/.codex/state_5.sqlite-wal"
printf 'shm' > "$CXH2/.codex/state_5.sqlite-shm"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-06 codex 2>&1)"
check "codex: launch on a brand-new account while the shared index is in use" "CFG=acct-06" "$out"
[ "$(readlink "$CXS/acct-06/state_5.sqlite" 2>/dev/null)" = "$CXH2/.codex/state_5.sqlite" ] \
  && t_ok "codex: an account with no index of its own is linked whatever the shared one is doing" \
  || t_fail "codex new account link" "$(ls -la "$CXS/acct-06" 2>&1 | head -c 300)"
rm -f "$CXH2/.codex/state_5.sqlite-wal" "$CXH2/.codex/state_5.sqlite-shm"
# (e) a PRIVATE session tree keeps its private index
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-03 codex 2>&1)"
check "codex: launch on an account with its own session tree" "CFG=acct-03" "$out"
{ [ -f "$CXS/acct-03/state_5.sqlite" ] && [ ! -L "$CXS/acct-03/state_5.sqlite" ]; } \
  && t_ok "codex: an account with a private session tree keeps its private index" \
  || t_fail "codex private tree index" "$(ls -la "$CXS/acct-03" 2>&1 | head -c 300)"
# (f) the index the INSTALLED binary will create is linked ahead of time, so a schema bump
#     still costs one backfill per Mac, not one per account
FAKEBIN_IDX="$WORK/fakebin-idx"
mkdir -p "$FAKEBIN_IDX"
{ cat "$FAKEBIN/codex"; printf '# rollout index name carried by the real binary: state_7.sqlite\n'; } > "$FAKEBIN_IDX/codex"
chmod +x "$FAKEBIN_IDX/codex"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-01 PATH="$REPO_DIR/bin:$FAKEBIN_IDX:$PATH" codex 2>&1)"
check "codex: launch through a binary that names a newer index" "CFG=acct-01" "$out"
[ "$(readlink "$CXS/acct-01/state_7.sqlite" 2>/dev/null)" = "$CXH2/.codex/state_7.sqlite" ] \
  && t_ok "codex: the index the installed binary creates next is linked before it exists" \
  || t_fail "codex index pre-link" "state_7.sqlite -> $(readlink "$CXS/acct-01/state_7.sqlite" 2>/dev/null)"
[ ! -e "$CXH2/.codex/state_7.sqlite" ] && t_ok "codex: pre-linking creates nothing in the home itself" \
  || t_fail "codex index pre-link home" "home gained state_7.sqlite"
grep -q " state_7.sqlite$" "$CXS/.state-index" 2>/dev/null \
  && t_ok "codex: the binary's index name is memoized per binary" \
  || t_fail "codex index name memo" "$(cat "$CXS/.state-index" 2>&1)"
# (f2) the launcher is a script that names no index; the schema name lives in the native
#      binary vendored beside it — the branch that actually fires on an npm install
VENDOR="$WORK/npm/node_modules/@openai/codex/bin"
mkdir -p "$VENDOR" "$WORK/npm/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin"
{ cat "$FAKEBIN/codex"; printf '# a launcher script naming no index\n'; } > "$VENDOR/codex.js"
chmod +x "$VENDOR/codex.js"
printf 'binary bytes state_8.sqlite more bytes' \
  > "$WORK/npm/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin/codex"
FAKEBIN_VENDOR="$WORK/fakebin-vendor"
mkdir -p "$FAKEBIN_VENDOR"
ln -s "$VENDOR/codex.js" "$FAKEBIN_VENDOR/codex"
rm -f "$CXS/.state-index"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-01 PATH="$REPO_DIR/bin:$FAKEBIN_VENDOR:$PATH" codex 2>&1)"
check "codex: launch through an npm launcher with a vendored binary" "CFG=acct-01" "$out"
[ "$(readlink "$CXS/acct-01/state_8.sqlite" 2>/dev/null)" = "$CXH2/.codex/state_8.sqlite" ] \
  && t_ok "codex: the index name is read from the vendored binary when the launcher names none" \
  || t_fail "codex vendored index name" "$(ls "$CXS/acct-01" 2>&1 | tr '\n' ' '); memo=$(cat "$CXS/.state-index" 2>&1)"
grep -q "^$(cd "$(dirname "$VENDOR/codex.js")" && pwd -P)/codex.js:" "$CXS/.state-index" 2>/dev/null \
  && t_ok "codex: the memo keys on the file the launcher symlink resolves to, not the link" \
  || t_fail "codex memo key" "$(cat "$CXS/.state-index" 2>&1)"
rm -f "$CXS/.state-index" "$CXS/acct-01/state_8.sqlite"
# (g) an adopted account (the dir IS the home) is never rewritten
ln -s "$CXH2/.codex" "$CXS/acct-04"
python3 - "$CXS/accounts.json" <<'PYEOF'
import json, sys
doc = json.load(open(sys.argv[1]))
doc['accounts'].append({'id': 'acct-04', 'email': 'adopted@cx', 'home': 'mac', 'added_at': '2026-09-09T00:00:00Z'})
json.dump(doc, open(sys.argv[1], 'w'), indent=2)
PYEOF
mk_cx_auth "$CXH2/.codex/auth.json" adopted@cx "$FUTURE_EXP"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-04 codex 2>&1)"
check "codex: launch on an adopted account" "CFG=acct-04" "$out"
{ [ -f "$CXH2/.codex/state_5.sqlite" ] && [ ! -L "$CXH2/.codex/state_5.sqlite" ]; } \
  && t_ok "codex: the home's own index is never turned into a link" \
  || t_fail "codex adopted index" "$(ls -la "$CXH2/.codex" 2>&1 | head -c 300)"
# (i) codex's own corruption recovery moved this account's LINK into db-backups/ and
#     rebuilt a private index in its place: that is codex's verdict on the shared file,
#     so the account keeps what codex rebuilt and this name is left alone entirely.
mkdir -p "$CXS/acct-01/db-backups/sqlite-1700000000-0"
mv "$CXS/acct-01/state_5.sqlite" "$CXS/acct-01/db-backups/sqlite-1700000000-0/state_5.sqlite"
printf 'rebuilt after damage' > "$CXS/acct-01/state_5.sqlite"
homesum="$(cat "$CXH2/.codex/state_5.sqlite" 2>/dev/null)"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-01 codex 2>&1)"
check "codex: launch after codex rejected the shared index for this account" "CFG=acct-01" "$out"
{ [ "$(cat "$CXS/acct-01/state_5.sqlite" 2>/dev/null)" = "rebuilt after damage" ] \
    && [ ! -L "$CXS/acct-01/state_5.sqlite" ]; } \
  && t_ok "codex: an account codex rebuilt for keeps that index instead of the shared one" \
  || t_fail "codex rejected shared index" "$(ls -la "$CXS/acct-01" 2>&1 | head -c 400)"
[ "$(cat "$CXH2/.codex/state_5.sqlite" 2>/dev/null)" = "$homesum" ] \
  && t_ok "codex: the rejected shared index is left exactly as it was, for its other users" \
  || t_fail "codex rejected shared index home" "home index changed"
# the marker only speaks for the file it names: a link pointing elsewhere is not a verdict
mkdir -p "$CXS/acct-05/db-backups/sqlite-1700000000-0"
mkdir -p "$CXS/acct-05" && ln -s "$CXH2/.codex/sessions" "$CXS/acct-05/sessions"
mk_cx_auth "$CXS/acct-05/auth.json" s5@cx "$FUTURE_EXP"
ln -s "$CXH2/.codex/state_9.sqlite" "$CXS/acct-05/db-backups/sqlite-1700000000-0/state_5.sqlite"
printf 'unrelated private index' > "$CXS/acct-05/state_5.sqlite"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-05 codex 2>&1)"
check "codex: launch with a db-backups link naming another file" "CFG=acct-05" "$out"
[ "$(readlink "$CXS/acct-05/state_5.sqlite" 2>/dev/null)" = "$CXH2/.codex/state_5.sqlite" ] \
  && t_ok "codex: a db-backups link that names a different file is not a verdict on the shared one" \
  || t_fail "codex marker scope" "$(ls -la "$CXS/acct-05" 2>&1 | head -c 300)"
# (j) a second retirement keeps the first retired copy
rm "$CXS/acct-02/state_5.sqlite"
printf 'second private index' > "$CXS/acct-02/state_5.sqlite"
out="$(HOME="$CXH2" CODEX_ACCOUNTS_DIR="$CXS" CODEX_ACCOUNT=acct-02 codex 2>&1)"
check "codex: launch on an account retiring a second private index" "CFG=acct-02" "$out"
{ [ "$(cat "$CXS/acct-02/state_5.sqlite.private" 2>/dev/null)" = "open private index" ] \
    && [ "$(cat "$CXS"/acct-02/state_5.sqlite.private.[0-9]* 2>/dev/null)" = "second private index" ] \
    && [ -L "$CXS/acct-02/state_5.sqlite" ]; } \
  && t_ok "codex: retiring never overwrites an earlier retired copy" \
  || t_fail "codex retire unique" "$(ls "$CXS/acct-02" 2>&1 | tr '\n' ' ')"
# (k) several processes promoting the same account at once. `mv` here could rename one
#     shim's fresh symlink onto the file another had just promoted, leaving
#     ~/.codex/state_N.sqlite pointing at itself — ELOOP, every account on the Mac unable
#     to start, and repaired by neither codex (ELOOP is not a corruption code) nor this
#     shim (`[ -L "$link" ]` would skip the name forever). link(2) refuses an existing
#     target, so the promote is atomic or it does not happen. The window is narrow, so
#     this drives the core function directly and repeats until the odds are not the test's.
CORE="$WORK/state-index-core.sh"
{ printf '#!/usr/bin/env bash\nset -u\n'
  awk '/^state_index_names\(\) \{/,/^}$/' "$REPO_DIR/bin/codex"
  awk '/^shared_index_rejected\(\) \{/,/^}$/' "$REPO_DIR/bin/codex"
  awk '/^share_state_index_links\(\) \{/,/^}$/' "$REPO_DIR/bin/codex"
  printf 'share_state_index_links "$1" "$2" ""\n'; } > "$CORE"
chmod +x "$CORE"
# The losing interleave is: the winner promotes and links, THEN the loser acts on a
# decision it made before either happened. Forcing it beats waiting for it — a `ln`/`mv`
# that sleeps puts the loser inside that window on purpose, and the winner is injected
# there. With the rename promote this renames the loser's own link onto its target; with
# link(2) it simply refuses.
SLOWBIN="$WORK/slowbin"
mkdir -p "$SLOWBIN"
for cmd in ln mv; do
  printf '#!/usr/bin/env bash\nsleep 1\nfor c in /bin/%s /usr/bin/%s; do [ -x "$c" ] && exec "$c" "$@"; done\nexit 127\n' \
    "$cmd" "$cmd" > "$SLOWBIN/$cmd"
  chmod +x "$SLOWBIN/$cmd"
done
rd="$WORK/promote-interleave"
mkdir -p "$rd/home/sessions" "$rd/acct"
ln -s "$rd/home/sessions" "$rd/acct/sessions"
printf 'the loser index' > "$rd/acct/state_5.sqlite"
( PATH="$SLOWBIN:$PATH" "$CORE" "$rd/acct" "$rd/home" >/dev/null 2>&1 ) &
slow=$!
sleep 0.4                       # the loser has decided the home is empty, and not yet acted
printf 'the winner index' > "$rd/home/state_5.sqlite"
rm -f "$rd/acct/state_5.sqlite"
ln -s "$rd/home/state_5.sqlite" "$rd/acct/state_5.sqlite"
wait "$slow" 2>/dev/null
{ [ -f "$rd/home/state_5.sqlite" ] && [ ! -L "$rd/home/state_5.sqlite" ] \
    && [ "$(cat "$rd/home/state_5.sqlite" 2>/dev/null)" = "the winner index" ]; } \
  && t_ok "codex: a promote that loses the race refuses instead of renaming onto the winner" \
  || t_fail "codex promote atomicity" "shared index is $(ls -la "$rd/home/state_5.sqlite" 2>&1 | head -c 160)"
[ "$(cat "$rd/acct/state_5.sqlite" 2>/dev/null)" = "the winner index" ] \
  && t_ok "codex: the losing account still reads the shared index through its link" \
  || t_fail "codex promote atomicity" "acct reads $(cat "$rd/acct/state_5.sqlite" 2>&1 | head -c 120)"

races=0; bad=0; badwhy=""

# (l) the heal belongs to the LAUNCH, not to the pin: an unpinned selection and a retry
#     that rotates to another account must both link the account they actually serve.
CXU="$WORK/cx-unpinned"; CXHU="$WORK/cxhome-unpinned"
mkdir -p "$CXU/tmp" "$CXU/acct-01" "$CXU/acct-02" "$CXHU/.codex/sessions"
: > "$CXU/.limits-kick"
cat > "$CXU/accounts.json" <<EOF2
{"version": 1, "server": "root@203.0.113.1", "server_root": "/root/.codex-accounts",
 "server_repo": "/root/claude-multiacc", "threshold": 90,
 "accounts": [
  {"id": "acct-01", "email": "u1@cx", "home": "mac", "added_at": "2026-09-09T00:00:00Z"},
  {"id": "acct-02", "email": "u2@cx", "home": "mac", "added_at": "2026-09-09T00:00:00Z"}]}
EOF2
for i in 01 02; do
  mk_cx_auth "$CXU/acct-$i/auth.json" "u$i@cx" "$FUTURE_EXP"
  ln -s "$CXHU/.codex/sessions" "$CXU/acct-$i/sessions"
done
printf 'the shared index' > "$CXHU/.codex/state_5.sqlite"
cxlj 5 5 5 > "$CXU/acct-01/limits.json"
cxlj 20 20 20 > "$CXU/acct-02/limits.json"
out="$(HOME="$CXHU" CODEX_ACCOUNTS_DIR="$CXU" CODEX_MULTIACC_HEADROOM_BAND=0 codex 2>&1)"
picked="$(printf '%s' "$out" | sed -n 's/.*CFG=\(acct-[0-9]*\).*/\1/p' | head -1)"
{ [ -n "$picked" ] \
    && [ "$(readlink "$CXU/$picked/state_5.sqlite" 2>/dev/null)" = "$CXHU/.codex/state_5.sqlite" ]; } \
  && t_ok "codex: an unpinned launch links the account it selected ($picked)" \
  || t_fail "codex unpinned heal" "picked=${picked:-none} $(ls -la "$CXU"/acct-0*/state_5.sqlite 2>&1 | head -c 300)"
rm -f "$CXU"/acct-0*/state_5.sqlite
echo "fail:acct-01" > "$FAKE_CTL2"
out="$(HOME="$CXHU" CODEX_ACCOUNTS_DIR="$CXU" CODEX_MULTIACC_HEADROOM_BAND=0 codex exec "hello" < /dev/null 2>&1)"
rm -f "$FAKE_CTL2" "$CXU/acct-01/.limited"
case "$out" in *CFG=acct-02*) t_ok "codex: the retry rotated to the second account" ;;
  *) t_fail "codex retry heal" "did not land on acct-02: $(printf '%s' "$out" | head -c 200)" ;; esac
[ "$(readlink "$CXU/acct-02/state_5.sqlite" 2>/dev/null)" = "$CXHU/.codex/state_5.sqlite" ] \
  && t_ok "codex: the account a retry rotates onto is linked too" \
  || t_fail "codex retry heal" "acct-02 -> $(readlink "$CXU/acct-02/state_5.sqlite" 2>/dev/null)"

# (h) the two copies of the core (shim + lib/common.sh) are byte-identical
core_of() { # $1 file, $2 function name -> its body
  awk -v fn="$2" '$0 ~ "^"fn"\\(\\) \\{" {p=1} p {print} p && /^}$/ {exit}' "$1"
}
for fn in state_index_names shared_index_rejected share_state_index_links; do
  if [ "$(core_of "$REPO_DIR/bin/codex" "$fn")" = "$(core_of "$REPO_DIR/lib/common.sh" "$fn")" ] \
     && [ -n "$(core_of "$REPO_DIR/bin/codex" "$fn")" ]; then
    t_ok "codex: $fn is byte-identical in bin/codex and lib/common.sh"
  else
    t_fail "codex shared-index parity" "$fn differs between bin/codex and lib/common.sh"
  fi
done

# ---- C12. login command + expired worklist + relogin --------------------------------
# an account with no auth on this machine: login completes it
codex-accounts import d@cx --id acct-04 --no-sync >/dev/null 2>&1
out="$(codex-accounts expired 2>&1)"
rc=$?
check "codex: expired lists the auth-less account" "acct-04" "$out"
[ "$rc" != "0" ] && t_ok "codex: expired exits 1 when a human is needed" || t_fail "codex expired rc" "rc=0"
out="$(FAKE_EMAIL=d@cx codex-accounts login acct-04 2>&1)"
check "codex: login completes an auth-less account" "login saved" "$out"
[ -s "$CX/acct-04/auth.json" ] && t_ok "codex: login wrote auth.json" || t_fail "codex login" "no auth.json"
# wrong sign-in identity is refused AND the prior credential is restored — the wrong
# account's auth.json must never stay installed under this id (codex-review finding)
out="$(FAKE_EMAIL=wrong@cx codex-accounts login acct-04 2>&1)"
rc=$?
check "codex: login refuses a wrong-account sign-in" "you signed in as wrong@cx" "$out"
[ "$rc" != "0" ] && t_ok "codex: wrong-identity login exits nonzero" || t_fail "codex login identity rc" "rc=0"
got_email="$(python3 - "$CX/acct-04/auth.json" <<'EOF'
import base64, json, sys
t = json.load(open(sys.argv[1]))['tokens']['id_token']
p = t.split('.')[1]; p += '=' * (-len(p) % 4)
print(json.loads(base64.urlsafe_b64decode(p)).get('email', ''))
EOF
)"
[ "$got_email" = "d@cx" ] && t_ok "codex: refused login restores the prior credential" \
  || t_fail "codex login restore" "auth.json now belongs to: $got_email"
# signing in as a DIFFERENT-but-REGISTERED account routes the credential to that
# account instead of discarding it (and the target account stays honestly unfixed)
rm -f "$CX/acct-01/auth.json"
out="$(FAKE_EMAIL=a@cx codex-accounts login acct-04 2>&1)"
rc=$?
check "codex: cross-account sign-in is redirected, not discarded" "credential was saved to acct-01" "$out"
check "codex: redirect says the target still needs its sign-in" "acct-04 (d@cx) still needs its own sign-in" "$out"
[ "$rc" != "0" ] && t_ok "codex: redirected login still exits nonzero for the target" \
  || t_fail "codex redirect rc" "rc=0 for an account that was not fixed"
[ -s "$CX/acct-01/auth.json" ] && t_ok "codex: redirected credential landed at its owner" \
  || t_fail "codex redirect landing" "acct-01/auth.json missing"
got_email="$(python3 - "$CX/acct-04/auth.json" <<'EOF'
import base64, json, sys
t = json.load(open(sys.argv[1]))['tokens']['id_token']
p = t.split('.')[1]; p += '=' * (-len(p) % 4)
print(json.loads(base64.urlsafe_b64decode(p)).get('email', ''))
EOF
)"
[ "$got_email" = "d@cx" ] && t_ok "codex: redirect restored the target's prior credential" \
  || t_fail "codex redirect restore" "acct-04 auth.json belongs to: $got_email"
# `add` while signed into an already-registered account also keeps the credential
rm -f "$CX/acct-01/auth.json"
before_dirs="$(ls "$CX" | sort)"
out="$(FAKE_EMAIL=a@cx codex-accounts add 2>&1)"
rc=$?
check "codex: add of a registered account saves the fresh sign-in to it" "fresh sign-in was saved to acct-01" "$out"
[ "$rc" = "0" ] && t_ok "codex: add redirect exits 0 (nothing new to register)" || t_fail "codex add redirect rc" "rc=$rc"
[ -s "$CX/acct-01/auth.json" ] && t_ok "codex: add redirect landed the credential" \
  || t_fail "codex add redirect" "acct-01/auth.json missing"
[ "$before_dirs" = "$(ls "$CX" | sort)" ] && t_ok "codex: add redirect leaves no reserved dir behind" \
  || t_fail "codex add redirect cleanup" "pool dirs changed"
n="$(grep -c '"email": "a@cx"' "$CX/accounts.json")"
[ "$n" = "1" ] && t_ok "codex: add redirect creates no duplicate entry" || t_fail "codex add redirect dup" "count=$n"
# relogin end-to-end: a redirect mid-run fixes the OTHER account, whose own turn is
# then skipped instead of demanding a second sign-in. Both accounts' home must be
# THIS machine's kind, or a credless account reads as 'remote' (grant lives
# elsewhere) on the other platform and never enters the worklist.
cx_mk=mac; [ "$(uname -s)" = "Darwin" ] || cx_mk=linux
python3 - "$CX/accounts.json" "$cx_mk" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
for a in d['accounts']:
    if a['id'] in ('acct-01', 'acct-04'):
        a['home'] = sys.argv[2]
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
rm -f "$CX/acct-01/auth.json" "$CX/acct-04/auth.json"
out="$(FAKE_EMAIL=d@cx codex-accounts relogin --yes 2>&1)"
rc=$?
check "codex: relogin redirect saves the mis-ordered sign-in" "credential was saved to acct-04" "$out"
check "codex: relogin skips an account fixed mid-run" "already has a working login" "$out"
check "codex: relogin counts the redirect-fixed account" "re-authenticated 1 of 2" "$out"
check "codex: relogin still reports the unfixed account" "still failing: acct-01" "$out"
[ "$rc" != "0" ] && t_ok "codex: relogin with an unfixed account exits nonzero" || t_fail "codex relogin redirect rc" "rc=0"
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
mk_cx_auth "$CX/acct-04/auth.json" d@cx "$FUTURE_EXP"
# the sign-in ceremony is DEVICE-CODE by default (the localhost browser callback
# cannot reach a remote/SSH machine); --browser opts into the callback flow
export FAKE_LOGIN_ARGS="$WORK/cx-login-args"
: > "$FAKE_LOGIN_ARGS"
FAKE_EMAIL=d@cx codex-accounts login acct-04 >/dev/null 2>&1
rc=$?
{ [ "$rc" = "0" ] && [ "$(cat "$FAKE_LOGIN_ARGS")" = "--device-auth" ]; } \
  && t_ok "codex: sign-in uses the device-code flow by default" \
  || t_fail "codex device default" "rc=$rc login args: '$(cat "$FAKE_LOGIN_ARGS")'"
: > "$FAKE_LOGIN_ARGS"
FAKE_EMAIL=d@cx codex-accounts login acct-04 --browser >/dev/null 2>&1
rc=$?
{ [ "$rc" = "0" ] && [ "$(cat "$FAKE_LOGIN_ARGS")" = "" ]; } \
  && t_ok "codex: --browser opts into the localhost callback flow" \
  || t_fail "codex --browser opt-out" "rc=$rc login args: '$(cat "$FAKE_LOGIN_ARGS")'"
# lock released after a completed login
[ ! -d "$CX/acct-04/.login-lock" ] && t_ok "codex: login lock released after completion" \
  || { t_fail "codex login lock release" ".login-lock survived a completed login"; rmdir "$CX/acct-04/.login-lock" 2>/dev/null; }
# a SECOND concurrent login for the same account is refused before any ceremony —
# a parallel run snapshotting the old credential could otherwise "restore" it over
# the fresh one (field incident: months-dead token inside a minutes-old auth.json)
mkdir "$CX/acct-04/.login-lock"
export FAKE_LOGIN_ARGS="$WORK/cx-login-args"
: > "$FAKE_LOGIN_ARGS"
cp "$CX/acct-04/auth.json" "$WORK/cx-lock-auth.bak"
out="$(FAKE_EMAIL=d@cx codex-accounts login acct-04 2>&1)"
rc=$?
check "codex: concurrent login for the same account is refused" "already in progress" "$out"
[ "$rc" != "0" ] && t_ok "codex: concurrent login exits nonzero" || t_fail "codex login lock rc" "rc=0"
[ ! -s "$FAKE_LOGIN_ARGS" ] && t_ok "codex: refused concurrent login never ran a ceremony" \
  || t_fail "codex login lock ceremony" "codex login was invoked despite the lock"
cmp -s "$CX/acct-04/auth.json" "$WORK/cx-lock-auth.bak" \
  && t_ok "codex: refused concurrent login left the credential untouched" \
  || t_fail "codex login lock credential" "auth.json changed"
# a STALE lock (holder died >30min ago) is reclaimed, not fatal
python3 - "$CX/acct-04/.login-lock" <<'EOF'
import os, sys, time
t = time.time() - 2000
os.utime(sys.argv[1], (t, t))
EOF
out="$(FAKE_EMAIL=d@cx codex-accounts login acct-04 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: stale login lock is reclaimed" || t_fail "codex stale login lock" "rc=$rc: $out"
[ ! -d "$CX/acct-04/.login-lock" ] && t_ok "codex: reclaimed lock released again" \
  || { t_fail "codex stale lock release" "lock left behind"; rmdir "$CX/acct-04/.login-lock" 2>/dev/null; }
# lock released after a FAILED ceremony too
FAKE_LOGIN_FAIL=1 FAKE_EMAIL=d@cx codex-accounts login acct-04 >/dev/null 2>&1
[ ! -d "$CX/acct-04/.login-lock" ] && t_ok "codex: login lock released after a failed ceremony" \
  || { t_fail "codex login lock on failure" "lock left behind"; rmdir "$CX/acct-04/.login-lock" 2>/dev/null; }
# remove refuses to delete an account under a live ceremony
mkdir "$CX/acct-04/.login-lock"
out="$(codex-accounts remove acct-04 --yes 2>&1)"
rc=$?
check "codex: remove refuses during a live login" "login for acct-04 is in progress" "$out"
[ "$rc" != "0" ] && [ -d "$CX/acct-04" ] && t_ok "codex: account survives a remove during login" \
  || t_fail "codex remove guard" "rc=$rc dir_exists=$([ -d "$CX/acct-04" ] && echo yes || echo no)"
rmdir "$CX/acct-04/.login-lock"
# a redirect never writes under a mid-ceremony login on the OWNER account either:
# it skips the save and falls back to the plain refusal
mkdir "$CX/acct-01/.login-lock"
mv "$CX/acct-01/auth.json" "$WORK/cx-a01.hold"
out="$(FAKE_EMAIL=a@cx codex-accounts login acct-04 2>&1)"
rc=$?
check "codex: redirect skipped while the owner has a login in progress" "login for acct-01 is in progress" "$out"
[ "$rc" != "0" ] && t_ok "codex: skipped redirect still refuses" || t_fail "codex busy-owner redirect rc" "rc=0"
[ ! -f "$CX/acct-01/auth.json" ] && t_ok "codex: no write under the owner's live ceremony" \
  || t_fail "codex busy-owner redirect" "auth.json written under an active login lock"
rmdir "$CX/acct-01/.login-lock"
mv "$WORK/cx-a01.hold" "$CX/acct-01/auth.json"
got_email="$(python3 - "$CX/acct-04/auth.json" <<'EOF'
import base64, json, sys
t = json.load(open(sys.argv[1]))['tokens']['id_token']
p = t.split('.')[1]; p += '=' * (-len(p) % 4)
print(json.loads(base64.urlsafe_b64decode(p)).get('email', ''))
EOF
)"
[ "$got_email" = "d@cx" ] && t_ok "codex: busy-owner refusal restored the target credential" \
  || t_fail "codex busy-owner restore" "acct-04 auth belongs to: $got_email"
unset FAKE_LOGIN_ARGS

# a parked account shows in expired and relogin fixes exactly that
printf '%s\nreason=refresh-denied-http-400 marked_at=t detail=x\n' "$now" > "$CX/acct-04/.expired"
out="$(codex-accounts expired 2>&1)"
check "codex: expired shows the parked account" "acct-04" "$out"
out="$(FAKE_EMAIL=d@cx codex-accounts relogin --yes 2>&1)"
check "codex: relogin re-authenticates the worklist" "re-authenticated 1 of 1" "$out"
[ ! -f "$CX/acct-04/.expired" ] && t_ok "codex: relogin cleared the park" || t_fail "codex relogin" "park survived"
# a relogin whose ceremony fails is NOT reported fixed: the dead credential stays
# on disk, and success is judged by whether the credential can AUTHENTICATE.
mk_cx_auth "$CX/acct-04/auth.json" d@cx 1000 norefresh
out="$(FAKE_LOGIN_FAIL=1 FAKE_EMAIL=d@cx codex-accounts relogin --yes 2>&1)"
rc=$?
check "codex: failed relogin says still failing" "still failing" "$out"
[ "$rc" != "0" ] && t_ok "codex: failed relogin exits nonzero" || t_fail "codex failed relogin rc" "rc=0"
out="$(codex-accounts expired 2>&1)"
check "codex: the un-fixed account is still on the worklist" "acct-04" "$out"
# api-key-only auth is not subscription auth: audited as unusable, never selected
mk_cx_auth "$CX/acct-04/auth.json" d@cx "$FUTURE_EXP" apikey
out="$(codex-accounts expired 2>&1)"
check "codex: api-key auth is called out as unsupported" "API key" "$out"
out="$(CODEX_SHIM_SELECT=random codex 2>&1)"
case "$out" in *CFG=acct-04*) t_fail "codex apikey selection" "api-key account was selected" ;;
  *) t_ok "codex: api-key account is never selected" ;; esac
codex-accounts remove acct-04 --yes >/dev/null 2>&1

# ---- C13. limits: fixture endpoint, marking, classification -------------------------
: > "$CX/.limits-kick"   # re-arm the shim-kick throttle: no background limits racing these
cat > "$WORK/cx-usage-high.json" <<EOF
{"email":"a@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":42,"limit_window_seconds":18000,"reset_at":$((now+3600))},
   "secondary_window":{"used_percent":57,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "code_review_rate_limit":null,
 "additional_rate_limits":[
   {"limit_name":"GPT-5.3-Codex-Spark","rate_limit":{"allowed":true,"limit_reached":false,
     "primary_window":{"used_percent":12,"limit_window_seconds":18000,"reset_at":$((now+3600))},
     "secondary_window":{"used_percent":95,"limit_window_seconds":604800,"reset_at":$((now+90000))}}}]}
EOF
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-high.json" codex-accounts limits 2>&1)"
check "codex: >=90% model bucket marks the account" "LIMITED GPT-5.3-Codex-Spark:7d at 95%" "$out"
[ -f "$CX/acct-01/.limited" ] && t_ok "codex: .limited marker written" || t_fail "codex limits marker" "missing"
IFS= read -r first < "$CX/acct-01/.limited"
[ "$first" = "$((now+90000))" ] && t_ok "codex: marker carries the offender's reset epoch" \
  || t_fail "codex marker reset" "first line: $first"
python3 - "$CX/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d['max_percent'] == 95, d['max_percent']
assert d['weekly_percent'] == 95, d['weekly_percent']
assert d['session_percent'] == 42, d['session_percent']
names = {b['name']: (b['group'], b['percent']) for b in d['buckets']}
assert names['5h'] == ('session', 42), names
assert names['7d'] == ('weekly', 57), names
assert names['GPT-5.3-Codex-Spark:5h'] == ('session', 12), names
assert names['GPT-5.3-Codex-Spark:7d'] == ('weekly', 95), names
EOF
[ $? -eq 0 ] && t_ok "codex: buckets classified session/weekly with per-model names" \
  || t_fail "codex bucket classification" "see assertions"
# below-threshold refresh clears the marker
cat > "$WORK/cx-usage-low.json" <<EOF
{"email":"a@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":5,"limit_window_seconds":18000,"reset_at":$((now+3600))},
   "secondary_window":{"used_percent":9,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "additional_rate_limits":[]}
EOF
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits 2>&1)"
check "codex: below-threshold refresh clears the marker" "marker cleared" "$out"
[ ! -f "$CX/acct-01/.limited" ] && t_ok "codex: marker gone after clean pass" || t_fail "codex marker clear" "still present"
# a hard limit_reached verdict excludes even when no window is >= threshold
cat > "$WORK/cx-usage-blocked.json" <<EOF
{"email":"a@cx","plan_type":"pro",
 "rate_limit":{"allowed":false,"limit_reached":true,
   "primary_window":{"used_percent":50,"limit_window_seconds":18000,"reset_at":$((now+3600))}}}
EOF
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-blocked.json" codex-accounts limits 2>&1)"
check "codex: limit_reached without a >=90% window still marks" "LIMITED limit_reached at 100%" "$out"
rm -f "$CX"/acct-*/.limited
# reshaped payload: windows are still found by the recursive fallback
cat > "$WORK/cx-usage-reshaped.json" <<EOF
{"totally":{"new":{"shape":{"used_percent":97,"limit_window_seconds":604800,"reset_at":$((now+90000))}}}}
EOF
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-reshaped.json" codex-accounts limits 2>&1)"
check "codex: reshaped payload still tracked (fallback walk)" "LIMITED" "$out"
rm -f "$CX"/acct-*/.limited
# garbage payload degrades that account only, never the run
printf 'this is not json' > "$WORK/cx-usage-garbage.json"
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-garbage.json" codex-accounts limits 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: garbage payload fails open (rc=0)" || t_fail "codex garbage rc" "rc=$rc"
check "codex: garbage payload logged as failure" "usage fetch failed" "$out"
# fetch throttle: fresh data is not re-fetched
out="$(CODEX_MULTIACC_MIN_FETCH=9999 CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits 2>&1)"
printf '%s' "$out" | grep -q "acct-01" \
  && t_fail "codex fetch throttle" "fresh account was re-fetched: $out" \
  || t_ok "codex: fresh account skipped by the fetch throttle"
# 429 backoff honored
python3 - "$CX/acct-02/limits.json" "$(date +%s)" <<'EOF'
import json, sys
json.dump({'fetched_at': 0, 'retry_after': int(sys.argv[2]) + 300, 'backoff': 120},
          open(sys.argv[1], 'w'))
EOF
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits 2>&1)"
check "codex: 429 backoff honored" "acct-02: backing off after 429" "$out"
rm -f "$CX"/acct-*/limits.json

# ---- C13b. codex parity: a 0% window with NO reported reset is NO DATA ---------------
# The claude pool's 2026-09-04 incident (acct-13/acct-14 served every bucket
# `percent: 0, resets_at: null`, ranked as the emptiest accounts in the fleet, handed
# 31 of the last ~60 picks while the client was being rejected on them at their weekly
# limit) is a payload failure, not a claude-specific one — this writer must refuse the
# same way. Codex's usage payload carries reset_at INSIDE each window, and this writer
# formats resets_at itself, so "the payload reported a window" is the distinction.
CD="$WORK/cx-nodata-pool"
mkdir -p "$CD/acct-01" "$CD/acct-02" "$CD/tmp"
: > "$CD/.limits-kick"
cat > "$CD/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,"accounts":[
  {"id":"acct-01","email":"nd1@cx","home":"mac","added_at":"2026-08-21T00:00:00Z"},
  {"id":"acct-02","email":"nd2@cx","home":"mac","added_at":"2026-08-21T00:00:00Z"}]}
EOF
mk_cx_auth "$CD/acct-01/auth.json" nd1@cx "$FUTURE_EXP"
mk_cx_auth "$CD/acct-02/auth.json" nd2@cx "$FUTURE_EXP"
cdl() { # cdl <weekly> <session> <max> -> a truthful, in-window reading on stdout
  printf '{"fetched_at":%s,"source":"chatgpt","weekly_percent":%s,"session_percent":%s,"max_percent":%s,"plan":"pro","buckets":[]}' \
    "$(date +%s)" "$1" "$2" "$3"
}
cdlimits() { # cdlimits <fixture> [extra args] -> a real refresh over the whole CD pool
  local f="$1"; shift
  CODEX_ACCOUNTS_ROOT="$CD" CODEX_MULTIACC_USAGE_URL="file://$f" \
    codex-accounts limits --force "$@" 2>&1
}

# every window 0% with no reset_at at all: nothing here says anything
cat > "$WORK/cx-usage-allzero.json" <<'EOF'
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":0,"limit_window_seconds":18000},
   "secondary_window":{"used_percent":0,"limit_window_seconds":604800}},
 "additional_rate_limits":[]}
EOF
out="$(cdlimits "$WORK/cx-usage-allzero.json")"
check "codex: an all-zero/no-window payload is reported as no usable telemetry" \
  "no usable telemetry (account ranks as unknown, not as empty)" "$out"
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d.get('no_data') is True, d
for k in ('max_percent', 'weekly_percent', 'session_percent'):
    assert k not in d, (k, d)
assert len(d['buckets']) == 2 and d['plan'] == 'pro', d      # diagnostics survive
# the writer's internal "did the payload report this window" flag never reaches disk
for b in d['buckets']:
    assert '_reset_known' not in b, b
EOF
[ $? -eq 0 ] && t_ok "codex: a no-data pass records no_data and none of the percent signals" \
  || t_fail "codex no_data document" "see $CD/acct-01/limits.json"

# one silent model window beside real ones changes nothing
cat > "$WORK/cx-usage-mixed-nodata.json" <<EOF
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":5,"limit_window_seconds":18000,"reset_at":$((now+3600))},
   "secondary_window":{"used_percent":9,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "additional_rate_limits":[
   {"limit_name":"GPT-5.3-Codex-Spark","rate_limit":{"allowed":true,"limit_reached":false,
     "primary_window":{"used_percent":0,"limit_window_seconds":18000},
     "secondary_window":{"used_percent":0,"limit_window_seconds":604800}}}]}
EOF
cdlimits "$WORK/cx-usage-mixed-nodata.json" --quiet >/dev/null
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['session_percent'], d['weekly_percent'], d['max_percent']) == (5, 9, 9), d
assert len(d['buckets']) == 4, d          # the two silent model windows are still recorded
EOF
[ $? -eq 0 ] && t_ok "codex: one silent model window beside real ones leaves the ranking untouched (5/9)" \
  || t_fail "codex mixed no-data payload" "see $CD/acct-01/limits.json"

# 0% WITH reported resets is a real, empty reading
cat > "$WORK/cx-usage-zero-real-windows.json" <<EOF
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":0,"limit_window_seconds":18000,"reset_at":$((now+3600))},
   "secondary_window":{"used_percent":0,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "additional_rate_limits":[]}
EOF
cdlimits "$WORK/cx-usage-zero-real-windows.json" --quiet >/dev/null
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['session_percent'], d['weekly_percent'], d['max_percent']) == (0, 0, 0), d
EOF
[ $? -eq 0 ] && t_ok "codex: 0% WITH reported reset windows still records a real, empty reading" \
  || t_fail "codex zero-with-windows payload" "see $CD/acct-01/limits.json"

# ...and an unknown account loses to any account with a real reading
cdlimits "$WORK/cx-usage-allzero.json" --quiet >/dev/null
cdl 45 10 45 > "$CD/acct-02/limits.json"
rm -f "$CD/.pick-seq" "$CD"/acct-0*/.last-pick "$CD"/acct-0*/.limited
: > "$CD/selection.log"
cd_hits=0
for _ in $(seq 1 10); do
  case "$(CODEX_ACCOUNTS_ROOT="$CD" codex 2>&1)" in *CFG=acct-01*) cd_hits=$((cd_hits+1)) ;; esac
done
[ "$cd_hits" = "0" ] \
  && t_ok "codex: a no-data account never outranks one with real telemetry (0 of 10 picks)" \
  || t_fail "codex no_data ranking" "the fake-zero account took $cd_hits of 10 picks"
grep -q "acct-02 weekly=45% session=10% band=30 band-count=1" "$CD/selection.log" \
  && t_ok "codex: the pick logs the known account alone in the band" \
  || t_fail "codex no_data band" "selection.log: $(tail -1 "$CD/selection.log" 2>/dev/null)"

# ---- C13c. codex parity: ONE marker rule, driven through the REAL rollout path -------
# The codex shim has no telemetry-based clearing path at all (a marker leaves it only
# when its own reset epoch passes), so the whole rule lives in `codex-accounts limits`.
# Until 2026-09-04 that writer kept EVERY active client marker unconditionally, which
# looks safe and is half wrong in each direction: a 7d rejection was safe by accident
# rather than by rule, and a 5h rejection — a window that refills within hours — parked
# the account until its own epoch, the exact stranding #22 (2026-09-03) had to fix on the
# claude side.
#
# These cases no longer HAND the writer a marker. bin/codex writes it, from a rollout
# transcript, the way a rejected run does — because the rule the writer applies reads a
# token the SHIM chooses, and testing it on a hand-written marker tests a vocabulary the
# product never produces. That is exactly what went wrong once already: the guard matched
# seven_day/7d/weekly while the scan labelled markers `client:primary`/`client:secondary`
# after the rollout's own rate_limits KEY names, which map to no fixed window at all
# (live payloads report `primary` as the 10080-minute one). Weekly protection was a no-op
# on this provider, and four green assertions said otherwise. The label is now derived
# from the record's own `window_minutes` at write time, and these tests drive that
# derivation end to end: rollout -> shim -> marker -> limits pass -> selection.
# A third, healthy account: with only two, "everything was parked so the pool fell back"
# and "the freed account was chosen" produce the same log line.
mkdir -p "$CD/acct-03"
mk_cx_auth "$CD/acct-03/auth.json" nd3@cx "$FUTURE_EXP"
python3 - "$CD/accounts.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
if not any(a['id'] == 'acct-03' for a in d['accounts']):
    d['accounts'].append({"id": "acct-03", "email": "nd3@cx", "home": "mac",
                          "added_at": "2026-08-21T00:00:00Z"})
json.dump(d, open(sys.argv[1], 'w'))
EOF
cx_mark() { # cx_mark <acct dir> <bucket> <reset-offset-seconds> <marked_at ISO>
  printf '%s\nbucket=%s percent=100 marked_at=%s reason=client-rate-limit\n' \
    "$(( $(date +%s) + $3 ))" "$2" "$4" > "$1/.limited"
}
cx_rollout() { # cx_rollout <acct dir> <used_percent> <resets_at epoch> <window_minutes|-> <record ISO>
  # One rollout, shaped like the real transcript: the codex CLI writes the windows the
  # server reported into every run's JSONL, and client_limit_scan reads the newest tail.
  # window_minutes rides in the SAME fragment as used_percent/resets_at — which is why
  # the shim can label the marker with the window that was actually spent.
  local day="$1/sessions/2026/09/04" f win=""
  rm -rf "$1/sessions"
  mkdir -p "$day"
  f="$day/rollout-2026-09-04T01-43-21-c13c0001-7fc3-7291-a0fc-7b4e2b035f1a.jsonl"
  [ "$4" = "-" ] || win="\"window_minutes\":$4,"
  {
    printf '{"timestamp":"%s","type":"session_meta","payload":{"session_id":"c13c0001","cwd":"/proj"}}\n' "$5"
    printf '{"timestamp":"%s","type":"event_msg","payload":{"type":"token_count","info":{"model_context_window":258400},"rate_limits":{"limit_id":"codex","limit_name":null,"primary":{"used_percent":%s,%s"resets_at":%s},"secondary":null,"credits":{"has_credits":false,"unlimited":false}}}}\n' \
      "$5" "$2" "$win" "$3"
  } > "$f"
  rm -f "$1/.client-scan"
}
cx_bucket() { # the bucket token on line 2 of <acct dir>/.limited, or '<none>'
  local b=""
  [ -f "$1/.limited" ] && b="$(sed -n '2s/.*bucket=\([^ ]*\).*/\1/p' "$1/.limited" 2>/dev/null)"
  printf '%s\n' "${b:-<none>}"
}
cdlimits0() { # cdlimits with the confirm delay OFF — a marker kept by this pass is kept
              # by RULE, never merely because the rejection is seconds old. (Real markers
              # are written by the shim moments before, so there is no "aged" marker to
              # fabricate; the delay is pinned separately below.)
  local f="$1"; shift
  CODEX_ACCOUNTS_ROOT="$CD" CODEX_MULTIACC_USAGE_URL="file://$f" \
    CODEX_MULTIACC_CLIENT_LIMIT_CONFIRM_DELAY=0 codex-accounts limits --force "$@" 2>&1
}
cx_shim() { CODEX_ACCOUNTS_ROOT="$CD" codex >/dev/null 2>&1; }
rm -f "$CD"/acct-0*/.limited "$CD"/acct-0*/.client-limit-cleared "$CD"/acct-0*/.client-scan
rm -rf "$CD"/acct-0*/sessions
cx_now="$(date +%s)"
cx_wreset=$((cx_now + 345600))          # four days out: a weekly window, still open
cx_sreset=$((cx_now + 1800))            # half an hour out: a five-hour window
# A record STAMPED BEFORE any clear: the watermark tests below turn on this timestamp,
# and a rollout the writer's clear did not supersede would prove nothing about it.
cx_ts_old="$(python3 -c 'import time; print(time.strftime("%Y-%m-%dT%H:%M:%S.120Z", time.gmtime(time.time() - 600)))')"

# (1) The marker names the WINDOW the server spent, not the key the payload happened to
# use. 10080 minutes is the weekly bucket however the rollout labels it.
cx_rollout "$CD/acct-01" "97.4" "$cx_wreset" 10080 "$cx_ts_old"
: > "$CD/selection.log"
cx_shim
{ [ "$(cx_bucket "$CD/acct-01")" = "client:7d" ] \
  && grep -q "acct-01 LIMITED by its own run (7d:97, resets $cx_wreset) — client-reported" \
       "$CD/selection.log"; } \
  && t_ok "codex: a 10080-minute rejection is marked client:7d, not after the rollout's key name" \
  || t_fail "codex weekly marker label" \
     "bucket=$(cx_bucket "$CD/acct-01") log: $(tail -1 "$CD/selection.log" 2>/dev/null)"

# (2) ...and THAT is the token the writer's weekly guard reads. An informative pass with
# real numbers far under the threshold, and the confirm delay switched off so nothing but
# the bucket rule can be keeping it: the marker has to survive the pass AND the next
# launch, because a weekly window cannot fall from the server-proven 97% that wrote it to
# 9% while it is still open.
out="$(cdlimits0 "$WORK/cx-usage-low.json")"
cx_shim
{ [ "$(cx_bucket "$CD/acct-01")" = "client:7d" ] \
  && [ ! -f "$CD/acct-01/.client-limit-cleared" ] \
  && ! printf '%s' "$out" | grep -q "acct-01: marker cleared"; } \
  && t_ok "codex: the client:7d marker outlives an informative 9% pass and the launch after it" \
  || t_fail "codex weekly marker vs informative pass" \
     "bucket=$(cx_bucket "$CD/acct-01") log: $(printf '%s' "$out" | grep acct-01 | tr '\n' ' ')"

# (3) A pass that reported nothing proves nothing, and has to SAY so — or a 32-hour
# telemetry stall reads exactly like a healthy pool.
out="$(cdlimits0 "$WORK/cx-usage-allzero.json")"
{ [ "$(cx_bucket "$CD/acct-01")" = "client:7d" ] \
  && printf '%s' "$out" | grep -q "acct-01: marker kept (no usable telemetry)"; } \
  && t_ok "codex: a no-data pass keeps the client:7d marker, and logs that it kept it" \
  || t_fail "codex weekly marker vs no-data pass" \
     "bucket=$(cx_bucket "$CD/acct-01") log: $(printf '%s' "$out" | grep acct-01 | tr '\n' ' ')"

# (4) The differential, from the same code path with one number changed: 300 minutes is
# the self-healing session window, so the identical rejection on acct-02 is labelled
# client:5h and DOES clear on an informative pass — the #22 (2026-09-03) behavior, which
# over-correcting (2) into "no client marker ever clears" would have destroyed.
cx_rollout "$CD/acct-02" "99.0" "$cx_sreset" 300 "$cx_ts_old"
cx_shim
cx_5h_bucket="$(cx_bucket "$CD/acct-02")"
out="$(cdlimits0 "$WORK/cx-usage-low.json")"
{ [ "$cx_5h_bucket" = "client:5h" ] && [ ! -f "$CD/acct-02/.limited" ] \
  && printf '%s' "$out" | grep -q "acct-02: marker cleared (max 9%)" \
  && [ "$(cx_bucket "$CD/acct-01")" = "client:7d" ]; } \
  && t_ok "codex: a 300-minute rejection is marked client:5h and clears, beside a 7d one that does not" \
  || t_fail "codex 5h vs 7d marker rule" \
     "5h-marked=$cx_5h_bucket 5h-now=$(cx_bucket "$CD/acct-02") 7d=$(cx_bucket "$CD/acct-01") log: $(printf '%s' "$out" | grep 'marker' | tr '\n' ' ')"

# (5) ...and it STAYS cleared. The rollout that reported the spent window is still on
# disk and the scan re-reads its tail on every launch, so without the `.client-limit-
# cleared` watermark the clear achieves nothing: the very next `codex` rewrites the same
# park, once per 15-minute pass, forever. Two launches, because the first would already
# have re-marked.
{ [ -f "$CD/acct-02/.client-limit-cleared" ] && { cx_shim; cx_shim; true; } \
  && [ ! -f "$CD/acct-02/.limited" ]; } \
  && t_ok "codex: the cleared 5h marker is not re-written from the same rollout (watermark)" \
  || t_fail "codex client-limit watermark" \
     "watermark=$([ -f "$CD/acct-02/.client-limit-cleared" ] && echo yes || echo MISSING) bucket=$(cx_bucket "$CD/acct-02")"

# (6) That decision reaches selection: the weekly-parked account stays out while the
# freed one comes back and takes every pick (acct-03 sits 36 points outside the band, so
# "acct-02 is eligible again" is the only thing that can produce this).
cdl 9 5 9 > "$CD/acct-02/limits.json"
cdl 45 10 45 > "$CD/acct-03/limits.json"
rm -f "$CD/.pick-seq" "$CD"/acct-0*/.last-pick
: > "$CD/selection.log"
cw_hits=0; cw2_hits=0
for _ in $(seq 1 6); do
  case "$(CODEX_ACCOUNTS_ROOT="$CD" codex 2>&1)" in
    *CFG=acct-01*) cw_hits=$((cw_hits+1)) ;;
    *CFG=acct-02*) cw2_hits=$((cw2_hits+1)) ;;
  esac
done
{ [ "$cw_hits" = "0" ] && [ "$cw2_hits" = "6" ] \
  && [ "$(cx_bucket "$CD/acct-01")" = "client:7d" ]; } \
  && t_ok "codex: the weekly rejection keeps its account out while the cleared 5h one returns (0 vs 6 of 6)" \
  || t_fail "codex marker selection" \
     "acct-01=$cw_hits acct-02=$cw2_hits of 6; 7d marker=$(cx_bucket "$CD/acct-01")"

# (7) The watermark is a brake, not a mute: a rejection recorded AFTER the clear is news,
# and parks the account again. (Stamped five seconds past the watermark the writer
# actually wrote, so this cannot pass by clock luck.)
cx_wm="$(head -1 "$CD/acct-02/.client-limit-cleared" 2>/dev/null)"
cx_ts_new="$(python3 -c 'import sys, time; print(time.strftime("%Y-%m-%dT%H:%M:%S.120Z", time.gmtime(int(sys.argv[1]) + 5)))' "${cx_wm:-$cx_now}")"
cx_rollout "$CD/acct-02" "96.0" "$cx_sreset" 300 "$cx_ts_new"
cx_shim
{ [ "$(cx_bucket "$CD/acct-02")" = "client:5h" ] \
  && grep -q 'percent=96' "$CD/acct-02/.limited"; } \
  && t_ok "codex: a rejection recorded after the clear parks the account again (a brake, not a mute)" \
  || t_fail "codex watermark is not a mute" \
     "bucket=$(cx_bucket "$CD/acct-02") line: $(sed -n 2p "$CD/acct-02/.limited" 2>/dev/null)"

# (8) A report that names no window at all keeps the raw key name — unknown window stays
# CLEARABLE, the #22 fail-open direction, and its own reset epoch still bounds it. It
# must clear on an informative pass and stay cleared like any other 5h-class marker.
rm -f "$CD/acct-03/.limited" "$CD/acct-03/.client-limit-cleared"
cx_rollout "$CD/acct-03" "97.0" "$cx_sreset" - "$cx_ts_old"
cx_shim
cx_nw_bucket="$(cx_bucket "$CD/acct-03")"
cdlimits0 "$WORK/cx-usage-low.json" --quiet >/dev/null
cx_shim
{ [ "$cx_nw_bucket" = "client:primary" ] && [ ! -f "$CD/acct-03/.limited" ] \
  && [ -f "$CD/acct-03/.client-limit-cleared" ]; } \
  && t_ok "codex: a report with no window_minutes keeps the raw key name and stays clearable" \
  || t_fail "codex windowless marker" \
     "marked=$cx_nw_bucket now=$(cx_bucket "$CD/acct-03") watermark=$([ -f "$CD/acct-03/.client-limit-cleared" ] && echo yes || echo no)"

# (9) The same holds for a marker written by an OLDER version and still on disk: it names
# `primary`/`secondary`, which is no window, so it keeps its pre-2026-09-04 clearable
# behavior rather than being promoted to a weekly park by accident. (Passes on the
# pre-fix tree too — deliberately: it is the guard against reading the new guard as
# "anything ambiguous sticks".)
rm -rf "$CD/acct-03/sessions"
rm -f "$CD/acct-03/.client-limit-cleared"
cx_mark "$CD/acct-03" client:secondary 345600 2020-01-01T00:00:00Z
cdlimits0 "$WORK/cx-usage-low.json" --quiet >/dev/null
[ ! -f "$CD/acct-03/.limited" ] \
  && t_ok "codex: a legacy client:secondary marker (no window in its name) is still clearable" \
  || t_fail "codex legacy marker" "bucket=$(cx_bucket "$CD/acct-03") survived an informative pass"

# (10) The confirm delay, which is what stops a cached usage response from erasing a
# rejection the client was handed seconds ago. The shim writes marked_at=NOW, so the
# marker below is genuinely fresh: the default 300s must keep it, and the same pass with
# the window closed clears it — same env var, clamp and semantics as the claude writer.
rm -f "$CD/acct-02/.limited" "$CD/acct-02/.client-limit-cleared"
cx_rollout "$CD/acct-02" "99.0" "$cx_sreset" 300 "$cx_ts_old"
cx_shim
out="$(cdlimits "$WORK/cx-usage-low.json")"
{ [ "$(cx_bucket "$CD/acct-02")" = "client:5h" ] \
  && ! printf '%s' "$out" | grep -q "acct-02: marker cleared"; } \
  && t_ok "codex: the default 300s confirm delay keeps a rejection handed over seconds ago" \
  || t_fail "codex confirm delay" \
     "bucket=$(cx_bucket "$CD/acct-02") log: $(printf '%s' "$out" | grep acct-02 | tr '\n' ' ')"
out="$(cdlimits0 "$WORK/cx-usage-low.json")"
{ [ ! -f "$CD/acct-02/.limited" ] \
  && printf '%s' "$out" | grep -q "acct-02: marker cleared (max 9%)"; } \
  && t_ok "codex: past the confirm delay the same 5h rejection clears on a real reading" \
  || t_fail "codex confirm delay expiry" \
     "bucket=$(cx_bucket "$CD/acct-02") log: $(printf '%s' "$out" | grep acct-02 | tr '\n' ' ')"

# (11) error-cooldown is untouched by all of the above: the account failed a real call
# moments ago, and no usage reading disproves that. (This one holds on origin/main too —
# it is the guard against the rewritten branch quietly dropping a case.)
rm -rf "$CD"/acct-0*/sessions
printf '%s\nbucket=error-cooldown percent=? reason=error-cooldown\n' "$(( $(date +%s) + 600 ))" \
  > "$CD/acct-01/.limited"
cdlimits "$WORK/cx-usage-low.json" --quiet >/dev/null
[ -f "$CD/acct-01/.limited" ] \
  && t_ok "codex: an error-cooldown marker still survives an informative clean pass" \
  || t_fail "codex cooldown vs limits" "the cooldown marker was cleared"
rm -f "$CD"/acct-0*/.limited "$CD"/acct-0*/.client-limit-cleared "$CD"/acct-0*/.client-scan
rm -rf "$CD"/acct-0*/sessions

# ---- C13d. codex parity: each ranking signal comes from a window of its OWN kind -----
# The claude writer's second 2026-09-04 defect, mirrored here: weekly_percent fell back
# to the overall peak and session_percent to a flat 0, so a payload where only the 5h
# window said anything was recorded as a WEEKLY reading, and one where only the 7d window
# spoke walked through the session gate on a zero nobody reported. A signal no window
# reported must be ABSENT — the shim needs both readings to call an account known.
cat > "$WORK/cx-usage-session-only.json" <<EOF
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":40,"limit_window_seconds":18000,"reset_at":$((now+3600))},
   "secondary_window":{"used_percent":0,"limit_window_seconds":604800}},
 "additional_rate_limits":[]}
EOF
cdlimits "$WORK/cx-usage-session-only.json" --quiet >/dev/null
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d                     # one window DID report: this is a reading
assert (d['session_percent'], d['max_percent']) == (40, 40), d
# The 7d window reported no reset_at and 0%. Recording 40 here (the overall peak) or 0
# (max over a silent window) both invent the number the weekly band ranks on.
assert 'weekly_percent' not in d, d
EOF
[ $? -eq 0 ] && t_ok "codex: a session-only reading records session+max and NO weekly_percent" \
  || t_fail "codex session-only signals" "see $CD/acct-01/limits.json"
cdl 30 10 30 > "$CD/acct-02/limits.json"
cdl 30 10 30 > "$CD/acct-03/limits.json"
rm -f "$CD/.pick-seq" "$CD"/acct-0*/.last-pick "$CD"/acct-0*/.limited
: > "$CD/selection.log"
cs_hits=0
for _ in $(seq 1 10); do
  case "$(CODEX_ACCOUNTS_ROOT="$CD" codex 2>&1)" in *CFG=acct-01*) cs_hits=$((cs_hits+1)) ;; esac
done
[ "$cs_hits" = "0" ] \
  && t_ok "codex: an account with no weekly reading never enters the band (0 of 10 picks)" \
  || t_fail "codex session-only ranking" "the weekly-less account took $cs_hits of 10 picks"

# The mirror image — a weekly reading whose ~5h window has nothing to say — is NOT the
# same defect, and codex feels it hardest: an idle account's payload carries the 7d
# window and no usable session window at all, so session_percent went permanently
# absent across the whole pool. quota_known needs BOTH readings, so EVERY codex account
# scored unknown, bestw never left 101, and the band collapsed into the all-gated tie —
# codex picked uniformly at RANDOM instead of by headroom (selection.log 2026-09-22:
# `session=?%` on every ranked line). A closed window holds no usage: it reads 0.
cat > "$WORK/cx-usage-weekly-only.json" <<EOF
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":0,"limit_window_seconds":18000},
   "secondary_window":{"used_percent":37,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "additional_rate_limits":[]}
EOF
cdlimits "$WORK/cx-usage-weekly-only.json" --quiet >/dev/null
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['weekly_percent'], d['max_percent']) == (37, 37), d
# The ~5h window is CLOSED, not undocumented, so it holds no usage. max_percent is still
# taken over the INFORMATIVE windows only, so this idle 0 never becomes a reading.
assert d['session_percent'] == 0, d
EOF
[ $? -eq 0 ] && t_ok "codex: an idle 5h window beside a real weekly one records session_percent 0" \
  || t_fail "codex idle-session signals" "see $CD/acct-01/limits.json"

# The same story told by omission: no session window in the payload at all.
cat > "$WORK/cx-usage-no-session.json" <<EOF
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "secondary_window":{"used_percent":37,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "additional_rate_limits":[]}
EOF
cdlimits "$WORK/cx-usage-no-session.json" --quiet >/dev/null
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert 'no_data' not in d, d
assert (d['weekly_percent'], d['session_percent'], d['max_percent']) == (37, 0, 37), d
EOF
[ $? -eq 0 ] && t_ok "codex: a payload with no session window at all records session_percent 0" \
  || t_fail "codex absent-session signals" "see $CD/acct-01/limits.json"

# ...and it RANKS: idle plus the better weekly (37) must beat busier rivals (80), which
# is the pick this pool was losing on every single invocation.
cdl 80 10 80 > "$CD/acct-02/limits.json"
cdl 80 10 80 > "$CD/acct-03/limits.json"
rm -f "$CD/.pick-seq" "$CD"/acct-0*/.last-pick
: > "$CD/selection.log"
cwk_hits=0
for _ in $(seq 1 6); do
  case "$(CODEX_ACCOUNTS_ROOT="$CD" codex 2>&1)" in *CFG=acct-01*) cwk_hits=$((cwk_hits+1)) ;; esac
done
[ "$cwk_hits" = "6" ] \
  && t_ok "codex: an idle account with the better weekly takes every pick (6 of 6)" \
  || t_fail "codex idle-session ranking" "the idle account took $cwk_hits of 6"
grep -q "acct-01 weekly=37% session=0% band=30 band-count=1 session-gate=50 session-ok=3" "$CD/selection.log" \
  && t_ok "codex: all three clear the gate and the idle account is alone in the band" \
  || t_fail "codex idle-session log" "$(tail -1 "$CD/selection.log" 2>/dev/null)"

# The guard that must NOT move: a payload where NOTHING answered stays unknown, and
# never picks up a fabricated session 0 on the way out.
cdlimits "$WORK/cx-usage-allzero.json" --quiet >/dev/null
python3 - "$CD/acct-01/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d.get('no_data') is True, d
for k in ('max_percent', 'weekly_percent', 'session_percent'):
    assert k not in d, (k, d)
EOF
[ $? -eq 0 ] && t_ok "codex: an all-zero payload still writes no session_percent (2026-09-04 holds)" \
  || t_fail "codex allzero still unknown" "see $CD/acct-01/limits.json"

# ...and the same guard one window down: an INFERRED session 0 may rank, never unpark.
# codex reports no window at all for a closed one, so silence is its NORMAL shape and
# says nothing about a 429 the client actually received. codex's only telemetry-driven
# clear lives here in `limits` (the shim has none — marker_active waits for the reset),
# so this is the single place the rule has to hold.
mk_client_marker "$CD/acct-01" 5h 1200 7200
cdlimits "$WORK/cx-usage-weekly-only.json" --quiet >/dev/null
{ [ -f "$CD/acct-01/.limited" ] \
  && python3 -c "import json,sys; d=json.load(open('$CD/acct-01/limits.json')); sys.exit(0 if d.get('session_inferred') is True and d['session_percent'] == 0 else 1)"; } \
  && t_ok "codex: an inferred session 0 cannot clear a client:5h marker" \
  || t_fail "codex inferred unpark" "marker gone, or session_inferred not recorded"

# ...while a MEASURED short-window reading still clears it (#22 holds on codex too).
mk_client_marker "$CD/acct-01" 5h 1200 7200
cat > "$WORK/cx-usage-measured-session.json" <<EOF
{"email":"nd@cx","plan_type":"pro",
 "rate_limit":{"allowed":true,"limit_reached":false,
   "primary_window":{"used_percent":5,"limit_window_seconds":18000,"reset_at":$((now+9000))},
   "secondary_window":{"used_percent":37,"limit_window_seconds":604800,"reset_at":$((now+90000))}},
 "additional_rate_limits":[]}
EOF
cdlimits "$WORK/cx-usage-measured-session.json" --quiet >/dev/null
{ [ ! -f "$CD/acct-01/.limited" ] \
  && python3 -c "import json,sys; d=json.load(open('$CD/acct-01/limits.json')); sys.exit(0 if 'session_inferred' not in d and d['session_percent'] == 5 else 1)"; } \
  && t_ok "codex: a MEASURED low session reading still clears a 5h marker (#22 holds)" \
  || t_fail "codex measured recovery" "see $CD/acct-01/.limited"
rm -f "$CD"/acct-0*/.limited "$CD"/acct-0*/.client-limit-cleared
rm -f "$CD"/acct-0*/.limited

# ---- C14. oauth refresh via the token endpoint --------------------------------------
# expired bearer, missing endpoint: fail open with backoff
mk_cx_auth "$CX/acct-01/auth.json" a@cx 1000
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits 2>&1)"
rc=$?
check "codex: failed oauth refresh logged with backoff" "acct-01: oauth refresh failed" "$out"
check "codex: expired bearer logged, not fatal" "acct-01: no fresh bearer" "$out"
[ "$rc" = "0" ] && t_ok "codex: limits exits 0 with an expired-bearer account" || t_fail "codex refresh rc" "rc=$rc"
[ -f "$CX/acct-01/.oauth-refresh.json" ] && t_ok "codex: refresh failure recorded for backoff" \
  || t_fail "codex refresh backoff file" "missing"
# a now-working endpoint is not retried inside the backoff window
python3 - "$WORK/cx-token-ok.json" "$((now + 864000))" <<'EOF'
import base64, json, sys
def jwt(claims):
    enc = lambda o: base64.urlsafe_b64encode(json.dumps(o).encode()).rstrip(b'=').decode()
    return f"{enc({'alg':'RS256'})}.{enc(claims)}.sig"
exp = float(sys.argv[2])
auth_claim = {"chatgpt_plan_type": "pro", "chatgpt_account_id": "acct-uuid"}
json.dump({"access_token": jwt({"exp": exp, "https://api.openai.com/auth": auth_claim, "marker": "REFRESHED"}),
           "refresh_token": "rt-rotated-new",
           "id_token": jwt({"email": "a@cx", "exp": exp, "https://api.openai.com/auth": auth_claim})},
          open(sys.argv[1], 'w'))
EOF
out="$(CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-ok.json" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits 2>&1)"
check "codex: refresh backoff honored (no early retry)" "acct-01: no fresh bearer" "$out"
grep -q "rt-rotated-new" "$CX/acct-01/auth.json" \
  && t_fail "codex backoff" "auth.json rewritten inside the backoff window" \
  || t_ok "codex: no refresh inside the backoff window"
# --force refreshes: rotated tokens persisted 0600, telemetry follows
out="$(CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-ok.json" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force 2>&1)"
check "codex: --force refreshes the expired token" "acct-01: access token refreshed" "$out"
check "codex: refreshed account fetches telemetry" "acct-01: ok" "$out"
python3 - "$CX/acct-01/auth.json" <<'EOF'
import base64, json, os, stat, sys
doc = json.load(open(sys.argv[1]))
t = doc['tokens']
payload = t['access_token'].split('.')[1]
payload += '=' * (-len(payload) % 4)
claims = json.loads(base64.urlsafe_b64decode(payload))
assert claims.get('marker') == 'REFRESHED', 'access token not replaced'
assert t['refresh_token'] == 'rt-rotated-new', 'refresh token not rotated'
assert doc.get('last_refresh', '').startswith('20'), 'last_refresh not stamped'
mode = stat.S_IMODE(os.stat(sys.argv[1]).st_mode)
assert mode == 0o600, oct(mode)
EOF
[ $? -eq 0 ] && t_ok "codex: rotated credential persisted with 0600" || t_fail "codex rotation" "see assertions"
[ ! -f "$CX/acct-01/.oauth-refresh.json" ] && t_ok "codex: successful refresh clears the backoff file" \
  || t_fail "codex refresh clear" "backoff file still present"
grep -q "rt-rotated-new" "$CX/limits.log" \
  && t_fail "codex token leak" "a refresh token leaked into limits.log" \
  || t_ok "codex: limits.log leaks no tokens"
# recently-expired token is left alone (a live codex session may own it) — even --force.
# The expiry is measured from NOW, not from the suite's start: the gate is a five-minute
# window, and pinning it to $now silently makes this assertion depend on how long every
# preceding test took.
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$(( $(date +%s) - 100 ))"
cp "$CX/acct-01/auth.json" "$WORK/cx-recent.bak"
rm -f "$CX/acct-01/limits.json" "$CX/acct-01/.oauth-refresh.json"
out="$(CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-ok.json" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force 2>&1)"
check "codex: recently-expired token not refreshed (even --force)" "acct-01: no fresh bearer" "$out"
cmp -s "$CX/acct-01/auth.json" "$WORK/cx-recent.bak" \
  && t_ok "codex: recently-expired credential left untouched" \
  || t_fail "codex refresh gate" "credential rewritten inside the 5-min grace window"
# no refresh token at all: parked with a clear reason
mk_cx_auth "$CX/acct-01/auth.json" a@cx 1000 norefresh
rm -f "$CX/acct-01/limits.json" "$CX/acct-01/.oauth-refresh.json"
out="$(CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-ok.json" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force 2>&1)"
grep -q "reason=no-refresh-token" "$CX/acct-01/.expired" 2>/dev/null \
  && t_ok "codex: refreshless expired credential is parked" \
  || t_fail "codex no-refresh park" "no marker written"
# a later successful authenticated fetch unparks it
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
rm -f "$CX/acct-01/limits.json"
out="$(CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force 2>&1)"
[ ! -f "$CX/acct-01/.expired" ] && t_ok "codex: a successful usage fetch clears the dead-auth marker" \
  || t_fail "codex unpark" ".expired survived an authenticated fetch"
# ...but never an org-blocked park (telemetry proves nothing about workspace policy)
printf '%s\nreason=org-blocked marked_at=t detail=x\n' "$now" > "$CX/acct-01/.expired"
rm -f "$CX/acct-01/limits.json"
CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force >/dev/null 2>&1
[ -f "$CX/acct-01/.expired" ] && t_ok "codex: a usage fetch does not unpark an org-blocked account" \
  || t_fail "codex org unpark" "telemetry cleared an org block it cannot observe"
rm -f "$CX/acct-01/.expired"
# a 4xx from the token endpoint must not park the pool; invalid_grant is proof
port=""
python3 "$srv_script" > "$WORK/cx-token-port" 2>/dev/null &
cx_srv_pid=$!
for _ in $(seq 1 20); do
  port="$(head -1 "$WORK/cx-token-port" 2>/dev/null)"
  case "$port" in ''|*[!0-9]*) port=""; sleep 0.2 ;; *) break ;; esac
done
if [ -z "$port" ]; then
  kill "$cx_srv_pid" 2>/dev/null; wait "$cx_srv_pid" 2>/dev/null || true
  t_ok "codex: token-endpoint 4xx tests skipped (cannot bind a loopback port here)"
else
  mk_cx_stale() {
    mk_cx_auth "$CX/acct-01/auth.json" a@cx 1000
    rm -f "$CX/acct-01/limits.json" "$CX/acct-01/.oauth-refresh.json" "$CX/acct-01/.expired"
  }
  mk_cx_stale
  CODEX_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/boom" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force >/dev/null 2>&1
  [ ! -f "$CX/acct-01/.expired" ] && t_ok "codex: one opaque 4xx does not park an account" \
    || t_fail "codex 4xx park" "a single non-invalid_grant 400 parked the account"
  CODEX_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/boom" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force >/dev/null 2>&1
  CODEX_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/boom" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force >/dev/null 2>&1
  [ -f "$CX/acct-01/.expired" ] && t_ok "codex: a repeatedly-refused grant is parked on the third strike" \
    || t_fail "codex 4xx strikes" "still not parked after three refusals"
  mk_cx_stale
  CODEX_MULTIACC_TOKEN_URL="http://127.0.0.1:$port/invalid-grant" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force >/dev/null 2>&1
  grep -q "invalid_grant" "$CX/acct-01/.expired" 2>/dev/null \
    && t_ok "codex: invalid_grant parks the account immediately" \
    || t_fail "codex invalid_grant" "no marker for an explicit invalid_grant"
  kill "$cx_srv_pid" 2>/dev/null; wait "$cx_srv_pid" 2>/dev/null || true
fi
mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
rm -f "$CX/acct-01/.expired" "$CX/acct-01/.oauth-refresh.json" "$CX"/acct-*/limits.json
# malformed tokens object (null) degrades that account only
cp "$CX/acct-01/auth.json" "$WORK/cx-auth01.bak"
printf '{"auth_mode":"chatgpt","tokens": null}' > "$CX/acct-01/auth.json"
out="$(CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-ok.json" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: null tokens object fails open (rc=0)" || t_fail "codex null tokens rc" "rc=$rc"
check "codex: null tokens degrades only that account" "acct-01: no fresh bearer" "$out"
[ -f "$CX/acct-02/limits.json" ] && t_ok "codex: accounts after a malformed one still refresh" \
  || t_fail "codex fail-open loop" "acct-02 starved by acct-01's malformed auth"
cp "$WORK/cx-auth01.bak" "$CX/acct-01/auth.json"
rm -f "$CX"/acct-*/limits.json

# refresh is not attempted at all when the rotated credential could not be persisted
# (the grant rotates the refresh token — consuming it and then failing to write
# auth.json would strand the account; codex-review finding).
# Root ignores directory permission bits, so the unwritable-dir setup only works
# as a non-root user (the server suite runs as root — skip there).
if [ "$(id -u)" = "0" ]; then
  t_ok "codex: refresh persistence preflight test skipped (root ignores directory permissions)"
  t_ok "codex: refresh persistence preflight test skipped (root ignores directory permissions) [2]"
else
  mk_cx_auth "$CX/acct-01/auth.json" a@cx 1000
  rm -f "$CX/acct-01/limits.json" "$CX/acct-01/.oauth-refresh.json"
  chmod 500 "$CX/acct-01"
  out="$(CODEX_MULTIACC_TOKEN_URL="file://$WORK/cx-token-ok.json" CODEX_MULTIACC_USAGE_URL="file://$WORK/cx-usage-low.json" codex-accounts limits --force 2>&1)"
  chmod 700 "$CX/acct-01"
  check "codex: unpersistable credential skips the refresh grant" "refresh not attempted" "$out"
  grep -q "rt-rotated-new" "$CX/acct-01/auth.json" \
    && t_fail "codex refresh preflight" "the grant was consumed despite an unwritable dir" \
    || t_ok "codex: refresh grant not consumed when persistence would fail"
  mk_cx_auth "$CX/acct-01/auth.json" a@cx "$FUTURE_EXP"
  rm -f "$CX/acct-01/.oauth-refresh.json"
fi

# two parallel imports get distinct ids and both land in the manifest (lock coverage;
# codex-review finding)
codex-accounts import p1@cx --no-sync >/dev/null 2>&1 &
imp1=$!
codex-accounts import p2@cx --no-sync >/dev/null 2>&1 &
imp2=$!
wait "$imp1"; wait "$imp2"
n1="$(grep -c '"email": "p1@cx"' "$CX/accounts.json")"
n2="$(grep -c '"email": "p2@cx"' "$CX/accounts.json")"
id1="$(python3 -c "import json,sys; print(next((a['id'] for a in json.load(open('$CX/accounts.json'))['accounts'] if a['email']=='p1@cx'), ''))")"
id2="$(python3 -c "import json,sys; print(next((a['id'] for a in json.load(open('$CX/accounts.json'))['accounts'] if a['email']=='p2@cx'), ''))")"
{ [ "$n1" = "1" ] && [ "$n2" = "1" ] && [ -n "$id1" ] && [ -n "$id2" ] && [ "$id1" != "$id2" ]; } \
  && t_ok "codex: parallel imports get distinct ids ($id1, $id2)" \
  || t_fail "codex parallel import" "p1=$n1($id1) p2=$n2($id2)"
codex-accounts remove "$id1" --yes >/dev/null 2>&1
codex-accounts remove "$id2" --yes >/dev/null 2>&1

# ---- C15. verify --------------------------------------------------------------------
out="$(codex-accounts verify --quick 2>&1)"
check "codex: verify --quick passes chatgpt accounts" "acct-01 a@cx: OK" "$out"
check "codex: verify --quick counts" "0 failure(s)" "$out"
out="$(codex-accounts verify 2>&1)"
check "codex: full verify PASS via the real-call matrix" "acct-01 a@cx: PASS" "$out"
check "codex: full verify zero failures" "0 failure(s)" "$out"
# verify parks a dead login it discovers, and a PASS clears an existing park
echo "authfail:acct-02" > "$FAKE_CTL2"
printf '%s\nreason=auth-error marked_at=t detail=x\n' "$now" > "$CX/acct-01/.expired"
out="$(codex-accounts verify 2>&1)"
check "codex: verify flags the dead login" "acct-02 b@cx: FAIL" "$out"
check "codex: verify says what fixes it" "codex-accounts relogin acct-02" "$out"
grep -q "reason=auth-error" "$CX/acct-02/.expired" 2>/dev/null \
  && t_ok "codex: verify parks the dead login" || t_fail "codex verify park" "no marker"
[ ! -f "$CX/acct-01/.expired" ] && t_ok "codex: a verify PASS clears an existing park" \
  || t_fail "codex verify unpark" "PASS left the marker in place"
rm -f "$FAKE_CTL2" "$CX/acct-02/.expired"
# an org-disabled account is parked as org-blocked
echo "orgfail:acct-02" > "$FAKE_CTL2"
out="$(codex-accounts verify 2>&1)"
check "codex: verify calls out the workspace block" "ORG BLOCKED" "$out"
grep -q "reason=org-blocked" "$CX/acct-02/.expired" 2>/dev/null \
  && t_ok "codex: verify parks the org-blocked account" || t_fail "codex verify org park" "no marker"
rm -f "$FAKE_CTL2" "$CX/acct-02/.expired"

# ---- C16. audit vocabulary + empty pool ---------------------------------------------
mkdir -p "$CX/acct-06"
python3 - "$CX/accounts.json" <<'EOF'
import json, sys
doc = json.load(open(sys.argv[1]))
doc['accounts'] = [a for a in doc['accounts'] if a['id'] != 'acct-06']
doc['accounts'].append({'id': 'acct-06', 'email': 'srv@cx', 'home': 'server'})
doc['accounts'].sort(key=lambda a: a['id'])
json.dump(doc, open(sys.argv[1], 'w'), indent=2)
EOF
out="$(python3 "$REPO_DIR/lib/codex_audit.py" "$CX" linux | awk -F'\t' '$1=="acct-06"{print $4}')"
[ "$out" = "missing" ] && t_ok "codex: home=server on the server means NO LOGIN, not 'elsewhere'" \
  || t_fail "codex home vocabulary" "expected missing on linux, got: $out"
out="$(python3 "$REPO_DIR/lib/codex_audit.py" "$CX" mac | awk -F'\t' '$1=="acct-06"{print $4}')"
[ "$out" = "remote" ] && t_ok "codex: home=server on the Mac is correctly 'elsewhere'" \
  || t_fail "codex home vocabulary" "expected remote on mac, got: $out"
python3 - "$CX/accounts.json" <<'EOF'
import json, sys
doc = json.load(open(sys.argv[1]))
doc['accounts'] = [a for a in doc['accounts'] if a['id'] != 'acct-06']
json.dump(doc, open(sys.argv[1], 'w'), indent=2)
EOF
rm -rf "$CX/acct-06"
cxemptypool="$WORK/cx-emptypool"
mkdir -p "$cxemptypool/tmp"
printf '{"version":1,"threshold":90,"accounts":[]}' > "$cxemptypool/accounts.json"
out="$(CODEX_ACCOUNTS_DIR="$cxemptypool" codex-accounts expired 2>&1)"
rc=$?
check "codex: expired on an empty pool says so" "No accounts registered yet" "$out"
[ "$rc" = "0" ] && t_ok "codex: empty pool exits 0" || t_fail "codex empty pool rc" "rc=$rc"

# ---- C17. security hardening --------------------------------------------------------
mkdir -p "$WORK/cx-canary" && : > "$WORK/cx-canary/DO_NOT_DELETE"
cp "$CX/accounts.json" "$WORK/cx-manifest.bak"
python3 - "$CX/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['accounts'].append({'id': '../cx-canary', 'email': 'evil@cx', 'home': 'mac'})
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
out="$(codex-accounts remove ../cx-canary --yes 2>&1)"
rc=$?
[ -f "$WORK/cx-canary/DO_NOT_DELETE" ] && t_ok "codex: remove refuses path-traversal id" \
  || t_fail "codex path traversal" "remove ../cx-canary DELETED files outside the pool"
[ "$rc" != "0" ] && t_ok "codex: traversal id rejected nonzero" || t_fail "codex traversal rc" "rc=0"
codex-accounts list 2>&1 | grep -q "\.\./cx-canary" \
  && t_fail "codex id filter" "traversal id surfaced" \
  || t_ok "codex: invalid manifest ids are filtered out"
cp "$WORK/cx-manifest.bak" "$CX/accounts.json"
if [ "$(uname -s)" = "Darwin" ]; then
  python3 - "$CX/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['server_root'] = "/tmp/x'; touch /tmp/cx_multiacc_PWNED; #"
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  rm -f /tmp/cx_multiacc_PWNED
  out="$(CODEX_MULTIACC_NO_SYNC=0 codex-accounts sync 2>&1)"
  [ ! -f /tmp/cx_multiacc_PWNED ] && t_ok "codex: sync rejects injected server_root" \
    || { t_fail "codex command injection" "server_root injection EXECUTED"; rm -f /tmp/cx_multiacc_PWNED; }
  check "codex: injected server_root refused" "not a plain absolute path" "$out"
  cp "$WORK/cx-manifest.bak" "$CX/accounts.json"
  python3 - "$CX/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1])); d['accounts'] = []
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  out="$(CODEX_MULTIACC_NO_SYNC=0 codex-accounts sync 2>&1)"
  rc=$?
  check "codex: empty manifest refuses to sync" "refusing to blank the target pools" "$out"
  [ "$rc" != "0" ] && t_ok "codex: empty-manifest sync exits nonzero" || t_fail "codex empty sync rc" "rc=0"
  cp "$WORK/cx-manifest.bak" "$CX/accounts.json"

  # replica + peer guards, codex flavor
  printf 'replica\n' > "$CX/sync-role"
  out="$(CODEX_MULTIACC_NO_SYNC=0 codex-accounts sync 2>&1)"
  rc=$?
  check "codex: replica pool refuses to push" "sync replica" "$out"
  [ "$rc" = "0" ] && t_ok "codex: replica sync exits 0" || t_fail "codex replica sync rc" "rc=$rc"
  # ...and a codex replica's auto_sync (fired by remove) is silent — no push, no nag
  out="$(CODEX_MULTIACC_NO_SYNC=0 codex-accounts import rep@cx --id acct-31 --no-sync 2>&1
         CODEX_MULTIACC_NO_SYNC=0 codex-accounts remove acct-31 --yes 2>&1)"
  case "$out" in *"sync failed"*) t_fail "codex replica auto_sync" "a replica mutation warned about sync: $out" ;;
    *) t_ok "codex: replica auto_sync is silent (no push, no warning)" ;; esac
  rm -f "$CX/sync-role"
  python3 - "$CX/accounts.json" <<'EOF'
import json, os, sys
d = json.load(open(sys.argv[1]))
d['peers'] = [{'target': 'gas@peer', 'root': "/tmp/x'; touch /tmp/cx_multiacc_PEER_PWNED; #", 'repo': '/tmp/y'}]
json.dump(d, open(sys.argv[1] + '.tmp', 'w'), indent=2); os.replace(sys.argv[1] + '.tmp', sys.argv[1])
EOF
  rm -f /tmp/cx_multiacc_PEER_PWNED
  out="$(CODEX_MULTIACC_NO_SYNC=0 codex-accounts sync 2>&1)"
  rc=$?
  check "codex: injected peer root refused" "peer root is not a plain absolute path" "$out"
  [ "$rc" != "0" ] && t_ok "codex: bad peer exits nonzero" || t_fail "codex peer validation rc" "rc=0"
  [ ! -f /tmp/cx_multiacc_PEER_PWNED ] && t_ok "codex: peer injection never executed" \
    || { t_fail "codex peer injection" "peer root injection EXECUTED"; rm -f /tmp/cx_multiacc_PEER_PWNED; }
  cp "$WORK/cx-manifest.bak" "$CX/accounts.json"
else
  t_ok "codex: sync validation tests skipped (Mac-only feature)"
fi

# ---- C18. status + npm layer --------------------------------------------------------
out="$(codex-accounts status 2>&1)"
check "codex: status shows threshold" "90%" "$out"
check "codex: status shows account" "a@cx" "$out"
check "codex: status shows plan" "plan pro" "$out"
if command -v node >/dev/null 2>&1; then
  out="$(node "$REPO_DIR/bin/cli.mjs" codex list 2>&1)"
  check "cli.mjs codex passthrough (list)" "a@cx" "$out"
  out="$(node "$REPO_DIR/bin/cli.mjs" --help 2>&1)"
  check "cli --help documents the codex pool" "codex-accounts" "$out"
else
  t_ok "codex npm-layer tests skipped (node not installed)"
fi

# ---- C19. MCP servers for every account (codex parity) ------------------------------
# Same contract as 16e over config.toml: the registry is reconciled into the picked
# account before exec (stamped, no python when nothing changed), a stock `codex mcp
# add|remove` under the shim is mirrored into every account, and `codex-accounts mcp`
# manages the registry — for this pool alone with --provider codex.
CXP="$WORK/cx-mcp-pool"
mkdir -p "$CXP/acct-01" "$CXP/acct-02" "$CXP/tmp"
: > "$CXP/.limits-kick"
cat > "$CXP/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,
 "accounts":[
   {"id":"acct-01","email":"p1@cx","home":"mac","added_at":"2026-08-21T00:00:00Z"},
   {"id":"acct-02","email":"p2@cx","home":"mac","added_at":"2026-08-21T00:00:00Z"}]}
EOF
mk_cx_auth "$CXP/acct-01/auth.json" p1@cx "$FUTURE_EXP"
mk_cx_auth "$CXP/acct-02/auth.json" p2@cx "$FUTURE_EXP"
for i in 01 02; do
  printf 'model = "gpt-5"\n\n[mcp_servers.own-%s]\ncommand = "true"\nargs = []\n' "$i" > "$CXP/acct-$i/config.toml"
done
cx_has() { grep -q "^\[mcp_servers\.$2\]" "$CXP/$1/config.toml" 2>/dev/null; }
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp add --provider codex reg1 -- echo hi 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: mcp add (codex only) exits 0" || t_fail "codex mcp add rc" "rc=$rc: $out"
cx_has acct-01 reg1 && cx_has acct-02 reg1 && t_ok "codex: mcp add reconciles EVERY account" \
  || t_fail "codex mcp add reconcile" "$(cat "$CXP/acct-01/config.toml" "$CXP/acct-02/config.toml")"
cx_has acct-01 own-01 && grep -q '^model = "gpt-5"' "$CXP/acct-01/config.toml" \
  && t_ok "codex: an account's own servers and settings survive the reconcile" \
  || t_fail "codex extras preserved" "$(cat "$CXP/acct-01/config.toml")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp list 2>&1)"
check "codex: mcp list names the server" "reg1" "$out"
# drift + launch: the picked account is reconciled before exec, and stamped
python3 - "$CXP/acct-02/config.toml" <<'PY'
import re, sys
p = sys.argv[1]; src = open(p).read()
out, skip = [], False
for line in src.splitlines(keepends=True):
    if line.lstrip().startswith("["):
        skip = line.strip().startswith("[mcp_servers.reg1")
    if not skip: out.append(line)
open(p, "w").write("".join(out))
PY
cx_has acct-02 reg1 && t_fail "codex drift fixture" "reg1 still present" || t_ok "codex drift fixture: acct-02 lost reg1"
: > "$PYLOG"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" codex 2>&1)"
check "codex: launch runs on the pinned account" "CFG=acct-02" "$out"
cx_has acct-02 reg1 && t_ok "codex: the shim reconciles the picked account before exec" \
  || t_fail "codex shim reconcile" "$(cat "$CXP/acct-02/config.toml")"
[ -s "$CXP/acct-02/.mcp-applied" ] && t_ok "codex: the reconcile leaves a stamp" || t_fail "codex stamp" "no .mcp-applied"
: > "$PYLOG"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" codex 2>&1)"
check "codex: second launch still runs" "CFG=acct-02" "$out"
[ ! -s "$PYLOG" ] && t_ok "codex: an unchanged registry + config spends no python start-up" \
  || t_fail "codex stamp short-circuit" "python ran: $(cat "$PYLOG")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-02 CLAUDE_MULTIACC_PYTHON=/nonexistent/python3 codex 2>&1)"
rc=$?
[ "$rc" = "0" ] && check "codex: a missing python never breaks a launch" "CFG=acct-02" "$out" \
  || t_fail "codex fail-open python" "rc=$rc: $out"
# kill switch
python3 - "$CXP/acct-01/config.toml" <<'PY'
import sys
p = sys.argv[1]; src = open(p).read()
out, skip = [], False
for line in src.splitlines(keepends=True):
    if line.lstrip().startswith("["):
        skip = line.strip().startswith("[mcp_servers.reg1")
    if not skip: out.append(line)
open(p, "w").write("".join(out))
PY
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-01 CODEX_MULTIACC_MCP=0 codex 2>&1)"
check "codex: kill switch: launch still runs" "CFG=acct-01" "$out"
cx_has acct-01 reg1 && t_fail "codex kill switch" "CODEX_MULTIACC_MCP=0 still reconciled" \
  || t_ok "codex: CODEX_MULTIACC_MCP=0 leaves the account alone"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp apply 2>&1)"
cx_has acct-01 reg1 && t_ok "codex: mcp apply repairs the drifted account" || t_fail "codex mcp apply" "$out"
# learn-from-write: a stock 'codex mcp add' under the shim reaches EVERY account
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex mcp add x -- echo hi 2>&1)"
rc=$?
[ "$rc" = "0" ] && check "codex: stock 'codex mcp add' still answers like the real client" "Added global MCP server 'x'" "$out" \
  || t_fail "codex stock mcp add rc" "rc=$rc: $out"
cx_has acct-01 x && cx_has acct-02 x && t_ok "codex: a stock 'codex mcp add' lands in EVERY account" \
  || t_fail "codex mirror add" "$(cat "$CXP/acct-01/config.toml" "$CXP/acct-02/config.toml")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); s=d["mcpServers"]["x"]; sys.exit(0 if s.get("command")=="echo" and s.get("args")==["hi"] else 1)' "$out" \
  && t_ok "codex: the mirrored server is in the registry as a Claude-style block" || t_fail "codex mirror registry" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex mcp remove x 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: stock 'codex mcp remove' exits 0" || t_fail "codex stock mcp remove rc" "rc=$rc: $out"
cx_has acct-01 x || cx_has acct-02 x \
  && t_fail "codex mirror remove" "x survives in an account" || t_ok "codex: a stock 'codex mcp remove' drops the server from EVERY account"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if ("x" in d.get("retiredUser",[]) or "x" in d.get("retired",[])) and "x" not in d.get("mcpServers",{}) else 1)' "$out" \
  && t_ok "codex: a removed server is retired in the registry" || t_fail "codex tombstone" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-01 CODEX_MULTIACC_MCP=0 codex mcp add solo -- echo solo 2>&1)"
cx_has acct-01 solo && ! cx_has acct-02 solo && t_ok "codex: CODEX_MULTIACC_MCP=0: a stock add stays in one account" \
  || t_fail "codex kill switch mirror" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-02 codex mcp remove never-there 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "codex: a failed 'codex mcp remove' keeps its exit status" || t_fail "codex mcp remove rc" "rc=0: $out"
# a client that wrote its table and then died: nothing is mirrored, the failure passes
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-02 FAKE_MCP_WRITE_THEN_FAIL=1 codex mcp add wtf -- echo w 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "codex: a client that writes and then fails still fails the shim run" || t_fail "codex write-then-fail rc" "rc=0: $out"
cx_has acct-02 wtf && ! cx_has acct-01 wtf && t_ok "codex: the failed add stays in the one account that wrote it" \
  || t_fail "codex write-then-fail leak" "$(cat "$CXP/acct-01/config.toml")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "wtf" not in d.get("mcpServers",{}) and "wtf" not in d.get("retired",[]) and "wtf" not in d.get("retiredUser",[]) else 1)' "$out" \
  && t_ok "codex: a failed stock add is never mirrored into the registry" || t_fail "codex failed mirror add" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-02 FAKE_MCP_WRITE_THEN_FAIL=1 codex mcp remove wtf 2>&1)"
rc=$?
[ "$rc" != "0" ] && t_ok "codex: a client that removes and then fails still fails the shim run" || t_fail "codex write-then-fail remove rc" "rc=0: $out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if "wtf" not in d.get("retired",[]) and "wtf" not in d.get("retiredUser",[]) else 1)' "$out" \
  && t_ok "codex: a failed stock remove leaves no tombstone" || t_fail "codex failed mirror remove" "$out"
# NESTED session: CODEX_HOME=<acct> + CODEX_SHIM_ACTIVE=1 is what every pooled codex
# session's children inherit — the passthrough must mirror the write all the same
: > "$PYLOG"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_HOME="$CXP/acct-01" CODEX_SHIM_ACTIVE=1 CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" codex mcp add nested -- echo n 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: a nested (in-session) 'codex mcp add' exits 0" || t_fail "codex nested add rc" "rc=$rc: $out"
cx_has acct-01 nested && cx_has acct-02 nested && t_ok "codex: a nested add is mirrored into EVERY account" \
  || t_fail "codex nested mirror" "$out $(cat "$CXP/acct-02/config.toml")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_HOME="$CXP/acct-01" CODEX_SHIM_ACTIVE=1 codex mcp remove nested 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: a nested 'codex mcp remove' exits 0" || t_fail "codex nested remove rc" "rc=$rc: $out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp list --json 2>&1)"
python3 -c 'import json,sys; d=json.loads(sys.argv[1]); sys.exit(0 if ("nested" in d.get("retiredUser",[]) or "nested" in d.get("retired",[])) and "nested" not in d.get("mcpServers",{}) else 1)' "$out" \
  && t_ok "codex: a nested remove leaves a tombstone" || t_fail "codex nested tombstone" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_ACCOUNT=acct-01 codex 2>&1)"
check "codex: the next launch on that account still runs" "CFG=acct-01" "$out"
cx_has acct-01 nested && t_fail "codex nested remove undone" "the next launch re-added nested" \
  || t_ok "codex: a nested remove is not undone by the next launch"
mkdir -p "$WORK/cx-outside"
: > "$PYLOG"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CODEX_HOME="$WORK/cx-outside" CLAUDE_MULTIACC_PYTHON="$WORK/pylog.sh" codex mcp add outside -- echo o 2>&1)"
[ "$?" = "0" ] && [ ! -s "$PYLOG" ] && ! cx_has acct-01 outside \
  && t_ok "codex: a CODEX_HOME outside the pool is untouched passthrough (no python, no mirror)" \
  || t_fail "codex outside passthrough" "$out; pylog: $(cat "$PYLOG")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp add --provider codex hsvc -- node s.js -h 127.0.0.1 2>&1)"
rc=$?
case "$out" in *USAGE*) t_fail "codex help scan" "-h after -- printed usage" ;; *) [ "$rc" = "0" ] && t_ok "codex: -h after -- is the server's own flag, not --help" || t_fail "codex help scan rc" "rc=$rc: $out" ;; esac
grep -q '^args = \["s.js", "-h", "127.0.0.1"\]' "$CXP/acct-01/config.toml" \
  && t_ok "codex: the server keeps its -h argument" || t_fail "codex help scan args" "$(cat "$CXP/acct-01/config.toml")"
# --provider both from the codex side reaches the claude pool beside it
CLM="$WORK/mcp-claude-pool"
mkdir -p "$CLM/acct-01" "$CLM/tmp"
cat > "$CLM/accounts.json" <<'EOF'
{"version":1,"server":"none","threshold":90,
 "accounts":[{"id":"acct-01","email":"cl1@test","home":"mac","added_at":"2026-07-13T00:00:00Z"}]}
EOF
printf '{"mcpServers":{}}\n' > "$CLM/acct-01/.claude.json"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CLAUDE_ACCOUNTS_ROOT="$CLM" codex-accounts mcp add shared -- echo both 2>&1)"
rc=$?
[ "$rc" = "0" ] && t_ok "codex: mcp add --provider both (default) exits 0" || t_fail "codex mcp add both rc" "rc=$rc: $out"
cx_has acct-01 shared && t_ok "codex: --provider both: the codex pool has the server" || t_fail "codex both codex" "$out"
python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); sys.exit(0 if "shared" in d.get("mcpServers",{}) else 1)' "$CLM/acct-01/.claude.json" \
  && t_ok "codex: --provider both: the claude pool beside it has the server" \
  || t_fail "codex both claude" "$(cat "$CLM/acct-01/.claude.json")"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp --help 2>&1)"
check "codex: mcp --help prints usage" "codex-accounts mcp add" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CLAUDE_ACCOUNTS_ROOT="$WORK/no-such-claude-pool" codex-accounts mcp add --provider claude q -- echo q 2>&1)"
rc=$?
[ "$rc" != "0" ] && check "codex: an explicit --provider claude without a claude pool fails loudly" "no claude pool" "$out" \
  || t_fail "codex explicit provider" "rc=0: $out"
cp "$CXP/acct-02/config.toml" "$WORK/cx-acct-02.bak"
printf '[mcp_servers.broken\ncommand = "x"\n' > "$CXP/acct-02/config.toml"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" CLAUDE_ACCOUNTS_ROOT="$CLM" codex-accounts mcp add partial -- echo p 2>&1)"
rc=$?
[ "$rc" = "3" ] && t_ok "codex: a corrupt config.toml makes mcp add exit 3 (saved, partially applied)" || t_fail "codex partial rc" "rc=$rc: $out"
cx_has acct-01 partial && t_ok "codex: the healthy account was reconciled despite the corrupt one" || t_fail "codex partial healthy" "$out"
python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); sys.exit(0 if "partial" in d.get("mcpServers",{}) else 1)' "$CLM/acct-01/.claude.json" \
  && t_ok "codex: the partial add still reached the claude pool beside it" || t_fail "codex partial sibling" "$(cat "$CLM/acct-01/.claude.json")"
cp "$WORK/cx-acct-02.bak" "$CXP/acct-02/config.toml"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts mcp apply 2>&1)"
cx_has acct-02 partial && t_ok "codex: mcp apply repairs the account once its config is fixed" || t_fail "codex partial repair" "$out"
out="$(CODEX_ACCOUNTS_ROOT="$CXP" codex-accounts import p3@cx --id acct-03 --no-sync 2>&1)"
cx_has acct-03 reg1 && cx_has acct-03 shared && t_ok "codex: a newly seeded account gets every registered server" \
  || t_fail "codex seed applies registry" "$out $(cat "$CXP/acct-03/config.toml" 2>/dev/null)"

# ---- 20. panel pools: --json, credential transfer, instance roots, local sync -------
# Everything here runs against pools under $WORK/panel, addressed with the NEW
# CLAUDE_ACCOUNTS_ROOT/CODEX_ACCOUNTS_ROOT env — while CLAUDE_ACCOUNTS_DIR (the legacy
# spelling) still points at the suite's own pool, which is exactly the precedence a
# second app-robot instance on a shared machine depends on.
PP="$WORK/panel"
JP="$PP/claude-a"
JP2="$PP/claude-b"
PTOKEN="sk-ant-oat01-PANELPOOLTOKENPANELPOOLTOKENPANELPOOLTOKENPANELPOOL"
mkdir -p "$JP/acct-01" "$JP/acct-02" "$JP/acct-03" "$JP2"
# home must be THIS machine's kind: a credential-less home=mac account audits as
# 'remote' (its grant lives elsewhere) rather than 'missing' when the suite runs on
# Linux — which is what the publish CI runs on. Same rule as the relogin-redirect
# fixture (ddb3015).
PMK=mac; [ "$(uname -s)" = "Darwin" ] || PMK=linux
cat > "$JP/accounts.json" <<EOF
{
  "version": 1,
  "server": "root@203.0.113.7",
  "server_root": "/root/.claude-accounts",
  "server_repo": "/root/claude-multiacc",
  "threshold": 90,
  "accounts": [
    {"id": "acct-01", "email": "portable@test", "home": "$PMK", "added_at": "2026-01-02T03:04:05Z"},
    {"id": "acct-02", "email": "local@test", "home": "$PMK", "added_at": "2026-02-02T03:04:05Z"},
    {"id": "acct-03", "email": "nocred@test", "home": "$PMK", "added_at": "2026-03-02T03:04:05Z"}
  ]
}
EOF
printf '%s' "$PTOKEN" > "$JP/acct-01/server.token"
chmod 600 "$JP/acct-01/server.token"
printf '{"claudeAiOauth":{"accessToken":"a","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' \
  > "$JP/acct-02/.credentials.json"
printf '{"version":1,"server":"none","server_root":"/root/.claude-accounts","server_repo":"/root/claude-multiacc","threshold":90,"accounts":[]}\n' \
  > "$JP2/accounts.json"
: > "$JP/.limits-kick"
: > "$JP2/.limits-kick"

CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts list --json > "$PP/list.json" 2>"$PP/list.err"
python3 - "$PP/list.json" "$JP" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d["schema"] == "claude-multiacc/pool.v1", d["schema"]
assert d["provider"] == "claude" and d["kind"] == "list", d
assert d["pool"]["root"] == sys.argv[2], d["pool"]["root"]   # _ROOT beats legacy _DIR
by = {a["id"]: a for a in d["accounts"]}
assert by["acct-01"]["status"] == "active", by["acct-01"]
assert by["acct-01"]["credential_class"] == "portable" and by["acct-01"]["portable"], by["acct-01"]
assert by["acct-02"]["credential_class"] == "machine-local", by["acct-02"]
assert by["acct-02"]["portable"] is False, by["acct-02"]
assert by["acct-03"]["status"] == "missing" and by["acct-03"]["credential_class"] == "none", by["acct-03"]
assert by["acct-01"]["home_dir"].endswith("/acct-01"), by["acct-01"]
assert by["acct-01"]["email"] == "portable@test", by["acct-01"]
assert d["summary"] == {"total": 3, "active": 2, "limited": 0, "needs_login": 1,
                        "portable": 1, "selectable": 2,
                        # how the shim is CURRENTLY ranking: fresh | degraded | blind.
                        # This fixture has no telemetry at all, so: blind.
                        "telemetry": "blind",
                        "ranking_blind": True}, d["summary"]
assert d["pool"]["sync"]["mode"] == "server", d["pool"]["sync"]
EOF
[ $? -eq 0 ] && t_ok "list --json: stable schema, status/class per account, instance root" \
  || t_fail "list --json" "see $PP/list.json"
[ ! -s "$PP/list.err" ] && t_ok "list --json writes nothing to stderr" \
  || t_fail "list --json stderr" "$(head -c 120 "$PP/list.err")"

CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts status --json > "$PP/status.json"
python3 - "$PP/status.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d["kind"] == "status", d["kind"]
a = {x["id"]: x for x in d["accounts"]}["acct-01"]
assert "last_picked" in a and "expired_marker" in a, a
assert a["credentials"]["token"] is True and a["credentials"]["oauth"] is False, a["credentials"]
assert a["credentials"]["token_age_days"] == 0, a["credentials"]
b = {x["id"]: x for x in d["accounts"]}["acct-02"]
assert b["credentials"]["oauth_refresh_expires_at"], b["credentials"]
EOF
[ $? -eq 0 ] && t_ok "status --json: adds last_picked + credential detail" \
  || t_fail "status --json" "see $PP/status.json"

cat > "$WORK/usage-panel.json" <<'EOF'
{"limits":[
  {"kind":"session","percent":12,"resets_at":"2099-01-01T00:00:00+00:00","scope":null},
  {"kind":"weekly_all","percent":93,"resets_at":"2099-01-03T00:00:00+00:00","scope":null}
]}
EOF
CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-panel.json" \
  claude-accounts limits --json > "$PP/limits.json" 2>/dev/null
python3 - "$PP/limits.json" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d["kind"] == "limits", d["kind"]
a = {x["id"]: x for x in d["accounts"]}["acct-01"]
assert a["usage"]["max_percent"] == 93, a["usage"]
assert a["usage"]["source"] == "token", a["usage"]
assert a["status"] == "limited" and a["limited"] is True, a
assert a["limit_reset_at"], a
assert a["selectable"] is False, a
# acct-02 has a live oauth credential, so it fetched the same fixture and parked too
assert d["summary"]["limited"] == 2, d["summary"]
EOF
[ $? -eq 0 ] && t_ok "limits --json: refreshes, then reports usage + limited state" \
  || t_fail "limits --json" "see $PP/limits.json"
rm -f "$JP/acct-01/.limited" "$JP/acct-02/.limited"

# ---- 20a. export-credential: portable only, exit codes a daemon can branch on -------
CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-01 > "$PP/blob.json" 2>"$PP/blob.err"
rc=$?
[ "$rc" = "0" ] && t_ok "export-credential exits 0 for a portable account" \
  || t_fail "export rc" "rc=$rc $(head -c 120 "$PP/blob.err")"
python3 - "$PP/blob.json" "$PTOKEN" "$PMK" <<'EOF'
import json, sys
b = json.load(open(sys.argv[1]))
assert b["format"] == "claude-multiacc/credential" and b["version"] == 1, b
assert b["provider"] == "claude" and b["class"] == "portable", b
assert b["account"] == {"id": "acct-01", "email": "portable@test", "home": sys.argv[3],
                        "added_at": "2026-01-02T03:04:05Z"}, b["account"]
assert b["credential"] == {"type": "setup-token", "value": sys.argv[2]}, "credential mismatch"
assert b["exported_from"]["pool_root"].endswith("claude-a"), b["exported_from"]
EOF
[ $? -eq 0 ] && t_ok "export blob: self-contained credential + identity metadata" \
  || t_fail "export blob shape" "see $PP/blob.json"

out="$(CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-02 2>&1)"
rc=$?
check "export refuses a machine-local credential" "MACHINE-LOCAL" "$out"
check "export says how to make it portable" "claude-accounts mint acct-02" "$out"
[ "$rc" = "3" ] && t_ok "machine-local export exits 3" || t_fail "machine-local exit code" "rc=$rc"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-03 2>&1)"
rc=$?
check "export reports an account with no credential" "no credential material" "$out"
[ "$rc" = "4" ] && t_ok "credential-less export exits 4" || t_fail "no-credential exit code" "rc=$rc"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-77 2>&1)"
[ $? != 0 ] && t_ok "export of an unregistered id fails" || t_fail "unknown id export" "exited 0"

CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-02 --identity-only --out "$PP/ident.json" >/dev/null
rc=$?
python3 - "$PP/ident.json" <<'EOF'
import json, sys
b = json.load(open(sys.argv[1]))
assert b["class"] == "identity", b
assert "credential" not in b, "identity blob must carry no credential material"
assert b["account"]["email"] == "local@test", b
EOF
[ $? -eq 0 ] && [ "$rc" = "0" ] \
  && t_ok "export --identity-only works for a machine-local account (registry only)" \
  || t_fail "identity-only export" "rc=$rc, see $PP/ident.json"
CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-01 --out "$PP/blob-out.json" >/dev/null
case "$(ls -l "$PP/blob-out.json" | cut -c1-10)" in
  -rw-------) t_ok "export --out writes the blob 0600" ;;
  *) t_fail "export --out perms" "$(ls -l "$PP/blob-out.json" | cut -c1-10)" ;;
esac

# ---- 20b. import-credential: faithful, idempotent, and picky ------------------------
out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" claude-accounts import-credential < "$PP/blob.json" 2>&1)"
rc=$?
check "import-credential installs a portable credential" "Imported acct-01 (portable@test" "$out"
[ "$rc" = "0" ] && t_ok "import-credential exits 0" || t_fail "import rc" "rc=$rc"
python3 - "$JP2/accounts.json" "$JP2/acct-01/server.token" "$PTOKEN" "$PMK" <<'EOF'
import json, sys
accs = json.load(open(sys.argv[1]))["accounts"]
assert len(accs) == 1, accs
a = accs[0]
# byte-faithful metadata: the account reads identically on the second machine
assert a == {"id": "acct-01", "email": "portable@test", "home": sys.argv[4],
             "added_at": "2026-01-02T03:04:05Z"}, a
assert open(sys.argv[2]).read() == sys.argv[3], "token content changed in transfer"
EOF
[ $? -eq 0 ] && t_ok "imported account + credential round-trip unchanged" \
  || t_fail "import fidelity" "see $JP2"
case "$(ls -l "$JP2/acct-01/server.token" | cut -c1-10)" in
  -rw-------) t_ok "imported credential is 0600" ;;
  *) t_fail "imported credential perms" "$(ls -l "$JP2/acct-01/server.token" | cut -c1-10)" ;;
esac
# The write goes through a temp file in the account dir; none of it may survive.
[ -z "$(ls -a "$JP2/acct-01" | grep '^\.cred\.')" ] \
  && t_ok "no temp credential file is left behind by an import" \
  || t_fail "import leftovers" "$(ls -a "$JP2/acct-01" | grep '^\.cred\.')"
[ -z "$(ls -a "$JP2/tmp" 2>/dev/null | grep 'import-cred')" ] \
  && t_ok "no staged blob is left behind by an import" \
  || t_fail "staged blob leftovers" "$(ls -a "$JP2/tmp" | grep 'import-cred')"
CLAUDE_ACCOUNTS_ROOT="$JP2" claude-accounts import-credential --in "$PP/blob.json" >/dev/null 2>&1
n="$(python3 -c "import json;print(len(json.load(open('$JP2/accounts.json'))['accounts']))")"
[ "$n" = "1" ] && t_ok "re-importing the same account refreshes it, never duplicates" \
  || t_fail "import idempotence" "$n accounts after a second import"

python3 - "$PP/blob.json" "$PP/blob-apikey.json" <<'EOF'
import json, sys
b = json.load(open(sys.argv[1]))
b["credential"]["value"] = "sk-ant-api03-" + "A" * 60      # an API key, not a setup-token
json.dump(b, open(sys.argv[2], "w"))
EOF
out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" claude-accounts import-credential --in "$PP/blob-apikey.json" 2>&1)"
rc=$?
check "import refuses an API key" "not a subscription setup-token" "$out"
[ "$rc" != "0" ] && t_ok "API-key import exits nonzero" || t_fail "api key import" "exited 0"

out="$(CODEX_ACCOUNTS_ROOT="$PP/codex-b" codex-accounts import-credential --in "$PP/blob.json" 2>&1)"
[ $? != 0 ] && t_ok "a claude blob cannot be imported into the codex pool" \
  || t_fail "cross-provider import" "exited 0"

out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" claude-accounts import-credential --in "$PP/ident.json" 2>&1)"
check "identity-only import registers the account" "identity only, no credential" "$out"
check "identity-only import says what it still needs" "claude-accounts login" "$out"
[ ! -f "$JP2/acct-02/server.token" ] && t_ok "identity-only import installs no credential" \
  || t_fail "identity-only import" "wrote a credential file"

out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" claude-accounts import-credential acct-02 --in "$PP/blob.json" 2>&1)"
rc=$?
check "import refuses to land the same email in a second slot" "already registered as acct-01" "$out"
[ "$rc" != "0" ] && t_ok "conflicting-id import exits nonzero" || t_fail "conflicting id" "exited 0"

# ---- 20c. instance isolation: the shim resolves the same root as the CLI ------------
# The leak assertion is a BEFORE/AFTER of the default pool, taken around the instance
# run. It used to grep $ACC/selection.log for "acct-01" — a line some earlier, unrelated
# test had to have left there, and since picks are random that line is not guaranteed:
# the check flaked once in five runs while proving nothing about isolation either way.
# Nothing but bin/claude writes selection.log, and this section runs no default-pool
# shim, so an unchanged line count is exactly "the instance run stayed in its own pool".
iso_before="$(wc -l < "$ACC/selection.log" 2>/dev/null || echo 0)"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" claude 2>&1)"
check "shim honors CLAUDE_ACCOUNTS_ROOT (instance pool)" "CFG=acct-01" "$out"
[ -f "$JP2/selection.log" ] && t_ok "instance pool records its own selection log" \
  || t_fail "instance selection log" "missing at $JP2/selection.log"
iso_after="$(wc -l < "$ACC/selection.log" 2>/dev/null || echo 0)"
{ [ "$iso_before" = "$iso_after" ] && ! grep -q "portable@test" "$ACC/accounts.json"; } \
  && t_ok "the default pool was untouched by the instance run" \
  || t_fail "pool isolation" \
     "the instance run leaked into $ACC (selection.log $iso_before -> $iso_after lines)"

# ---- 20d. sync target: overridable, and a local-only mode that pushes nowhere -------
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync --no-server 2>&1)"
rc=$?
check "sync --no-server stays local" "local-only" "$out"
[ "$rc" = "0" ] && t_ok "sync --no-server exits 0" || t_fail "sync --no-server rc" "rc=$rc"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_SYNC_TARGET=none CLAUDE_MULTIACC_NO_SYNC=0 \
       claude-accounts sync 2>&1)"
check "SYNC_TARGET=none makes sync local-only" "nothing pushed" "$out"
CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_SYNC_TARGET="ops@panel.example" \
  claude-accounts list --json > "$PP/list-target.json"
python3 - "$PP/list-target.json" <<'EOF'
import json, sys
s = json.load(open(sys.argv[1]))["pool"]["sync"]
assert s["mode"] == "server" and s["target"] == "ops@panel.example", s
EOF
[ $? -eq 0 ] && t_ok "SYNC_TARGET env overrides the manifest server" \
  || t_fail "sync target override" "see $PP/list-target.json"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" CLAUDE_MULTIACC_NO_SYNC=0 \
       claude-accounts import-credential --in "$PP/blob.json" 2>&1)"
case "$out" in
  *"sync failed"*) t_fail "local-only auto_sync" "a local-only pool warned about a server push: $out" ;;
  *) t_ok "local-only pool: mutations never warn about a missing server" ;;
esac
# A replica pool must NEVER push — and pointing it at a local-only target must not
# become a way around that. Local mode narrows the rule (nothing pushes at all); the
# marker is still honored and still reported.
printf 'replica\n' > "$JP/sync-role"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_SYNC_TARGET=none CLAUDE_MULTIACC_NO_SYNC=0 \
       claude-accounts sync 2>&1)"
rc=$?
check "a replica in local-only mode still says it is a replica" "sync replica" "$out"
check "a replica in local-only mode pushes nothing" "nothing pushed either way" "$out"
[ "$rc" = "0" ] && t_ok "replica + local-only exits 0" || t_fail "replica local-only rc" "rc=$rc"
# `sync` refuses outright off the Mac ("sync runs on the Mac, not the server"), so the
# replica and target-injection rules can only be observed there. Stated as a skip rather
# than quietly asserting the wrong message on Linux — which is what broke the publish CI.
if [ "$(uname -s)" = "Darwin" ]; then
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
check "a replica with a server target still refuses to push" "sync replica" "$out"
else
t_ok "server-target sync refusal skipped (sync is Mac-only; this host is $(uname -s))"
fi
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_NO_SYNC=0 \
       claude-accounts import-credential --in "$PP/blob.json" 2>&1)"
case "$out" in
  *"sync failed"*|*"push"*) t_fail "replica auto_sync" "a replica mutation tried to push: $out" ;;
  *) t_ok "a mutation on a replica never pushes (auto_sync stays silent)" ;;
esac
rm -f "$JP/sync-role"

out="$(CLAUDE_ACCOUNTS_ROOT="$JP" CLAUDE_MULTIACC_SYNC_TARGET="ops@x; touch $WORK/PWNED" \
       CLAUDE_MULTIACC_NO_SYNC=0 claude-accounts sync 2>&1)"
rc=$?
if [ "$(uname -s)" = "Darwin" ]; then
  check "an injected SYNC_TARGET is refused" "not a plain user@host" "$out"
else
  t_ok "injected SYNC_TARGET refusal message skipped (sync is Mac-only here)"
fi
# The part that matters everywhere: refused, and never executed.
[ "$rc" != "0" ] && [ ! -f "$WORK/PWNED" ] && t_ok "injected sync target never executed" \
  || t_fail "sync target injection" "rc=$rc"

# ---- 20e. codex parity: no portable class, identity transfer only -------------------
CX2="$PP/codex-a"
mkdir -p "$CX2/acct-01"
cat > "$CX2/accounts.json" <<'EOF'
{"version":1,"server":"none","server_root":"/root/.codex-accounts","server_repo":"/root/claude-multiacc",
 "threshold":90,"accounts":[{"id":"acct-01","email":"cx@panel","home":"mac","added_at":"2026-04-05T06:07:08Z"}]}
EOF
python3 - "$CX2/acct-01/auth.json" <<'EOF'
import base64, json, sys, time
b = lambda o: base64.urlsafe_b64encode(json.dumps(o).encode()).decode().rstrip('=')
jwt = lambda c: b({"alg": "none"}) + '.' + b(c) + '.sig'
json.dump({"auth_mode": "chatgpt", "OPENAI_API_KEY": None,
           "tokens": {"id_token": jwt({"email": "cx@panel"}),
                      "access_token": jwt({"exp": time.time() + 9999}),
                      "refresh_token": "r", "account_id": "acc"},
           "last_refresh": "2026-08-01T00:00:00Z"}, open(sys.argv[1], "w"))
EOF
CODEX_ACCOUNTS_ROOT="$CX2" codex-accounts list --json > "$PP/cx-list.json"
python3 - "$PP/cx-list.json" "$CX2" <<'EOF'
import json, sys
d = json.load(open(sys.argv[1]))
assert d["provider"] == "codex" and d["pool"]["root"] == sys.argv[2], d["pool"]
a = d["accounts"][0]
assert a["status"] == "active", a
assert a["credential_class"] == "machine-local" and a["portable"] is False, a
assert d["summary"]["portable"] == 0, d["summary"]
assert d["pool"]["sync"]["mode"] == "local", d["pool"]["sync"]
EOF
[ $? -eq 0 ] && t_ok "codex list --json: same schema, no portable credentials" \
  || t_fail "codex list --json" "see $PP/cx-list.json"
out="$(CODEX_ACCOUNTS_ROOT="$CX2" codex-accounts export-credential acct-01 2>&1)"
rc=$?
check "codex export always refuses" "no portable credential type" "$out"
check "codex export points at the device-code login" "codex-accounts login acct-01" "$out"
[ "$rc" = "3" ] && t_ok "codex export exits 3 (machine-local)" || t_fail "codex export rc" "rc=$rc"
CODEX_ACCOUNTS_ROOT="$CX2" codex-accounts export-credential acct-01 --identity-only --out "$PP/cx-ident.json" >/dev/null
mkdir -p "$PP/codex-b"
printf '{"version":1,"server":"none","threshold":90,"accounts":[]}\n' > "$PP/codex-b/accounts.json"
out="$(CODEX_ACCOUNTS_ROOT="$PP/codex-b" codex-accounts import-credential --in "$PP/cx-ident.json" 2>&1)"
rc=$?
check "codex identity import registers the account" "Registered acct-01 (cx@panel" "$out"
check "codex identity import asks for a local sign-in" "codex-accounts login acct-01" "$out"
[ "$rc" = "0" ] && t_ok "codex identity import exits 0" || t_fail "codex identity import rc" "rc=$rc"
python3 - "$PP/codex-b/accounts.json" <<'EOF'
import json, sys
a = json.load(open(sys.argv[1]))["accounts"][0]
assert a["added_at"] == "2026-04-05T06:07:08Z", a    # source metadata preserved
EOF
[ $? -eq 0 ] && t_ok "codex identity transfer keeps the source added_at" \
  || t_fail "codex identity metadata" "see $PP/codex-b/accounts.json"

# ---- 20f. codex-review follow-ups: hostile pool roots, empty fields, marker rule ----
# A pool root carrying shell metacharacters must never reach a trap body or a remote
# command as code. (install.sh refuses to SCHEDULE such a root; the CLI must still be
# safe when one is used directly.)
QROOT="$PP/q'; touch $WORK/TRAP_PWNED; '"
mkdir -p "$QROOT"
printf '{"version":1,"server":"none","threshold":90,"accounts":[]}\n' > "$QROOT/accounts.json"
rm -f "$WORK/TRAP_PWNED"
out="$(CLAUDE_ACCOUNTS_ROOT="$QROOT" claude-accounts import-credential --in "$PP/blob.json" 2>&1)"
rc=$?
check "import works from a pool root with shell metacharacters" "Imported acct-01" "$out"
[ "$rc" = "0" ] && [ ! -f "$WORK/TRAP_PWNED" ] \
  && t_ok "a quoted pool root never executes as code (trap body)" \
  || { t_fail "pool root injection" "rc=$rc, sentinel=$([ -f "$WORK/TRAP_PWNED" ] && echo CREATED)"; rm -f "$WORK/TRAP_PWNED"; }
out="$(CLAUDE_ACCOUNTS_ROOT="$QROOT" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-panel.json" \
       claude-accounts limits --json 2>/dev/null | python3 -c "import json,sys;print(json.load(sys.stdin)['accounts'][0]['id'])" 2>&1)"
check "limits --json survives a quoted pool root" "acct-01" "$out"
[ ! -f "$WORK/TRAP_PWNED" ] && t_ok "the limits lock trap never executes a quoted root" \
  || { t_fail "limits trap injection" "sentinel created"; rm -f "$WORK/TRAP_PWNED"; }

# An empty metadata field must stay empty: the record separator is 0x1F precisely
# because bash collapses runs of IFS *whitespace*, which would shift added_at into home.
python3 - "$PP/blob.json" "$PP/blob-nohome.json" <<'EOF'
import json, sys
b = json.load(open(sys.argv[1]))
b["account"]["home"] = ""
b["account"]["email"] = "nohome@test"
json.dump(b, open(sys.argv[2], "w"))
EOF
NH="$PP/claude-nohome"
mkdir -p "$NH"
printf '{"version":1,"server":"none","threshold":90,"accounts":[]}\n' > "$NH/accounts.json"
CLAUDE_ACCOUNTS_ROOT="$NH" claude-accounts import-credential --in "$PP/blob-nohome.json" >/dev/null 2>&1
python3 - "$NH/accounts.json" <<'EOF'
import json, sys
a = json.load(open(sys.argv[1]))["accounts"][0]
assert a["email"] == "nohome@test", a
# home falls back to this machine, and added_at is NOT the value that would land there
# if the empty field had collapsed
assert a["home"] in ("mac", "linux"), a
assert a["added_at"] == "2026-01-02T03:04:05Z", a
EOF
[ $? -eq 0 ] && t_ok "a blob with an empty field imports without shifting the next one" \
  || t_fail "empty-field record" "see $NH/accounts.json"

# Metadata carrying a control character is refused rather than truncating the record.
python3 - "$PP/blob.json" "$PP/blob-ctrl.json" <<'EOF'
import json, sys
b = json.load(open(sys.argv[1]))
b["account"]["email"] = "evil@test\nacct-99"
json.dump(b, open(sys.argv[2], "w"))
EOF
out="$(CLAUDE_ACCOUNTS_ROOT="$NH" claude-accounts import-credential --in "$PP/blob-ctrl.json" 2>&1)"
rc=$?
check "metadata with a control character is refused" "control character" "$out"
[ "$rc" != "0" ] && t_ok "control-character blob exits nonzero" || t_fail "control char blob" "exited 0"

# An adopted account is a symlink: a credential must never be written THROUGH it,
# not even with --force (--force settles identity, it does not authorize escaping the pool).
mkdir -p "$PP/outside"
ln -s "$PP/outside" "$JP2/acct-09"
python3 - "$PP/blob.json" "$PP/blob-09.json" <<'EOF'
import json, sys
b = json.load(open(sys.argv[1]))
b["account"]["id"] = "acct-09"
json.dump(b, open(sys.argv[2], "w"))
EOF
out="$(CLAUDE_ACCOUNTS_ROOT="$JP2" claude-accounts import-credential acct-09 --in "$PP/blob-09.json" --force 2>&1)"
rc=$?
check "import refuses to write through an adopted symlink" "must never be written through it" "$out"
[ "$rc" != "0" ] && [ ! -f "$PP/outside/server.token" ] \
  && t_ok "--force does not authorize writing outside the pool" \
  || t_fail "symlink import" "rc=$rc, wrote=$([ -f "$PP/outside/server.token" ] && echo yes)"
rm -f "$JP2/acct-09"

# The exported blob must land 0600 even when a world-readable file is already there.
: > "$PP/pre-existing.json"
chmod 644 "$PP/pre-existing.json"
CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts export-credential acct-01 --out "$PP/pre-existing.json" >/dev/null
case "$(ls -l "$PP/pre-existing.json" | cut -c1-10)" in
  -rw-------) t_ok "export --out replaces a world-readable file with a 0600 one" ;;
  *) t_fail "export --out perms over existing file" "$(ls -l "$PP/pre-existing.json" | cut -c1-10)" ;;
esac

# The JSON report must apply the shim's marker rule exactly: a marker whose reset has
# passed is NOT limited (the shim deletes it and selects the account), while a garbled
# marker IS (the shim treats it as active rather than racing a concurrent write).
printf '%s\nbucket=weekly percent=95 reason=limits\n' "$((now-600))" > "$JP/acct-01/.limited"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts list --json | python3 -c "
import json,sys; a={x['id']:x for x in json.load(sys.stdin)['accounts']}['acct-01']
print(a['status'], a['limited'], a['selectable'])")"
check "an elapsed .limited marker does not read as limited" "active False True" "$out"
printf 'garbled\n' > "$JP/acct-01/.limited"
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts list --json | python3 -c "
import json,sys; a={x['id']:x for x in json.load(sys.stdin)['accounts']}['acct-01']
print(a['status'], a['limited'])")"
check "a garbled .limited marker reads as limited (same as the shim)" "limited True" "$out"
rm -f "$JP/acct-01/.limited"

# --json must not swallow a following typo, and a broken refresh must not be reported
# as success just because the document rendered.
out="$(CLAUDE_ACCOUNTS_ROOT="$JP" claude-accounts list --json --bogus 2>&1)"
rc=$?
check "list --json rejects an unknown extra option" "unknown option: --bogus" "$out"
[ "$rc" != "0" ] && t_ok "list --json --bogus exits nonzero" || t_fail "strict --json parsing" "exited 0"
BROKEN="$PP/claude-broken"
mkdir -p "$BROKEN"
printf 'not json at all\n' > "$BROKEN/accounts.json"
out="$(CLAUDE_ACCOUNTS_ROOT="$BROKEN" claude-accounts limits --json 2>/dev/null)"
rc=$?
[ "$rc" != "0" ] && t_ok "limits --json propagates a failed refresh (nonzero)" \
  || t_fail "limits --json exit code" "exited 0 on an unreadable manifest"
printf '%s' "$out" | python3 -c "
import json,sys
d=json.load(sys.stdin)
assert d['accounts'] == [], d
assert any('manifest' in w for w in d['warnings']), d['warnings']
" 2>/dev/null \
  && t_ok "limits --json still emits a document (with a warning) when the pool is broken" \
  || t_fail "limits --json on a broken pool" "no usable document"

# ---- 46. a setup token has no identity: the --token paths must not pretend --------
# Regression for two field failures on 2026-08-24: `add <email> --token` died every time
# with "identity could not be read back" (it demanded --force for a ceremony that cannot
# exist), and `mint` named no account at all — so approving in the wrong browser session
# silently pinned another account's subscription to the slot, undetectably.
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 claude-accounts add --token 2>&1)"
rc=$?
check "add --token with no email refuses precisely" "name it: claude-accounts add <email> --token" "$out"
[ "$rc" != "0" ] && t_ok "add --token with no email exits nonzero" || t_fail "add --token no email" "exited 0"
[ ! -d "$ACC/acct-04" ] && t_ok "refused --token add leaves no dir behind" || t_fail "add --token cleanup" "dir left"
# ...and it must refuse BEFORE the ceremony: minting a real 1-year grant only to discard
# it would leave a live credential issued for nothing.
case "$out" in
  *"sign-in link"*) t_fail "add --token refuses before the ceremony" "setup-token already ran for an account it cannot name" ;;
  *) t_ok "add --token with no email never opens the ceremony" ;;
esac

# mint must refuse a bare acct-NN directory the manifest does not know: removed accounts
# and killed `add` runs leave those behind, and a token bound to one is unattributable.
mkdir -p "$ACC/acct-77"
out="$(printf 'sk-ant-oat01-ORPHANORPHANORPHANORPHANORPHANORPHAN\n' \
  | claude-accounts mint acct-77 --paste 2>&1)"
check "mint refuses an unregistered account dir" "unknown account: acct-77" "$out"
[ ! -s "$ACC/acct-77/server.token" ] && t_ok "no token is written into an orphan dir" \
  || t_fail "mint orphan dir" "server.token was written to an unregistered slot"
rm -rf "$ACC/acct-77"

# mint must NAME the account it is about to bind a token to (the only guard there is).
printf 'sk-ant-oat01-MINTNAMEDMINTNAMEDMINTNAMEDMINTNAMEDMINTNAMED\n' \
  | claude-accounts mint acct-01 --paste > "$WORK/mint-named.out" 2>&1
out="$(cat "$WORK/mint-named.out")"
check "mint --paste names the account in its prompt" "for acct-01" "$out"
check "mint warns that a setup token carries no identity" "carries no identity" "$out"

# ---- 47. every known verb answers --help with exit 0 (app-robot probes with it) ----
# app-robot's runner asks `<verb> --help` to decide whether a Mac's build has the verb;
# a non-zero exit reads as "too old" and parked panel-to-Mac credential distribution.
# _KNOWN_VERBS must hold EXACTLY what the dispatcher implements. A verb missing from it
# hides a real verb from the probe; a verb listed but unimplemented makes --help answer 0
# for something that does not exist, which is how the probe stops meaning anything. The
# first cut of this gate got both wrong (mint listed in codex, init-pool in claude), so
# the parity is checked from the source, both directions, for both binaries.
for _bin in claude-accounts codex-accounts; do
  _src="$REPO_DIR/bin/$_bin"
  _dispatch="$(grep -oE '^  [a-z0-9|_-]+\) shift; cmd_' "$_src" | sed -e 's/) shift; cmd_//' -e 's/^  //' | tr '|\n' '  ')"
  _gate="$(grep -m1 '^_KNOWN_VERBS=' "$_src" | sed -e 's/^_KNOWN_VERBS="//' -e 's/"$//')"
  _parity=1
  for _v in $_dispatch; do
    case " $_gate " in
      *" $_v "*) ;;
      *) _parity=0; t_fail "$_bin: dispatcher has '$_v', _KNOWN_VERBS does not" "app-robot's probe would read the verb as absent" ;;
    esac
    "$_bin" "$_v" --help >/dev/null 2>&1
    [ "$?" = "0" ] && t_ok "$_bin $_v --help exits 0" \
      || t_fail "$_bin $_v --help" "non-zero exit — app-robot would read the verb as missing"
  done
  for _v in $_gate; do
    case " $_dispatch " in
      *" $_v "*) ;;
      *) _parity=0; t_fail "$_bin: _KNOWN_VERBS lists '$_v', the dispatcher does not implement it" "--help would answer 0 for a verb that does not exist" ;;
    esac
  done
  [ "$_parity" = "1" ] && t_ok "$_bin: the help gate and the dispatcher list the same verbs"
  "$_bin" frobnicate --help >/dev/null 2>&1
  [ "$?" != "0" ] && t_ok "$_bin: an UNKNOWN verb still fails --help (the probe keeps its meaning)" \
    || t_fail "$_bin unknown verb --help" "exited 0 — the probe would accept a verb that does not exist"
done

# ---- 17. macOS Keychain-held logins --------------------------------------------------
# Claude Code on macOS moves a per-dir OAuth login into the login Keychain (service
# "Claude Code-credentials-<sha256(dir)[:8]>") from any keychain-capable session and
# deletes .credentials.json — the 2026-08-28 incident read five working accounts as
# "missing". The fake `security` above serves items from $FAKE_KEYCHAIN_DIR so the real
# lookup code runs on Linux too. Own pool root: the main pool's manifest has been
# through a dozen mutations by this point in the suite.
KCP="$WORK/kcpool"
export FAKE_KEYCHAIN_DIR="$WORK/keychain"
mkdir -p "$KCP/tmp" "$KCP/acct-01" "$KCP/acct-02" "$FAKE_KEYCHAIN_DIR"
: > "$KCP/.limits-kick"
cat > "$KCP/accounts.json" <<EOF
{ "version": 1, "server": "root@203.0.113.1", "server_root": "/root/.claude-accounts",
  "server_repo": "/root/claude-multiacc", "threshold": 90,
  "accounts": [
    {"id": "acct-01", "email": "kfile@test", "home": "mac", "added_at": "2026-08-28T00:00:00Z"},
    {"id": "acct-02", "email": "kchain@test", "home": "mac", "added_at": "2026-08-28T00:00:00Z"}
  ] }
EOF
printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-kfile","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}' > "$KCP/acct-01/.credentials.json"
kc_hash() { printf '%s' "$1" | { shasum -a 256 2>/dev/null || sha256sum; } | cut -c1-8; }
kc_svc_file() { printf '%s/Claude Code-credentials-%s' "$FAKE_KEYCHAIN_DIR" "$(kc_hash "$1")"; }
kc_put() { # kc_put <acct dir> <credential json> — store it the way the client would
  security add-generic-password -U -a tester -s "Claude Code-credentials-$(kc_hash "$1")" \
    -X "$(printf '%s' "$2" | python3 -c 'import sys;print(sys.stdin.buffer.read().hex())')"
}
kc_put "$KCP/acct-02" '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-kchain","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}'
export CLAUDE_MULTIACC_KEYCHAIN=1

# 17a. the keychain login reads as a working machine-local OAuth login
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts list --json 2>&1)"
python3 - "$out" <<'EOF'
import json, sys
doc = json.loads(sys.argv[1])
rows = {a['id']: a for a in doc['accounts']}
a2 = rows['acct-02']
assert a2['status'] == 'active', a2['status']
assert a2['credential_class'] == 'machine-local', a2['credential_class']
assert a2['credentials']['oauth_store'] == 'keychain', a2['credentials']
assert a2['credentials']['keychain'] == 'readable', a2['credentials']
assert a2['selectable'] is True, a2
assert rows['acct-01']['credentials']['oauth_store'] == 'file', rows['acct-01']['credentials']
assert doc['summary']['selectable'] == 2, doc['summary']
EOF
[ $? -eq 0 ] && t_ok "keychain login is active machine-local in list --json" \
  || t_fail "keychain list --json" "see assertions above"
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts list 2>&1)"
check "keychain login shown in the plain list" "auth=keychain" "$out"

# 17b. the shim runs under a keychain-only account (file account parked by a limit)
printf '%s\nbucket=session percent=95 reason=limits\n' "$((now+3600))" > "$KCP/acct-01/.limited"
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" claude 2>&1)"
check "shim selects the keychain-only account" "CFG=acct-02" "$out"

# 17c. locked keychain (ssh session): 'locked', never 'missing'; excluded HERE only
out="$(FAKE_KEYCHAIN_LOCKED=1 CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts list --json 2>&1)"
python3 - "$out" <<'EOF'
import json, sys
doc = json.loads(sys.argv[1])
a2 = {a['id']: a for a in doc['accounts']}['acct-02']
assert a2['status'] == 'locked', a2['status']
assert a2['credential_class'] == 'machine-local', a2['credential_class']
assert a2['credentials']['keychain'] == 'locked', a2['credentials']
assert a2['selectable'] is False, a2
assert a2['needs_login'] is False, 'locked must not join the re-login worklist'
EOF
[ $? -eq 0 ] && t_ok "locked keychain reads as 'locked' machine-local, not missing" \
  || t_fail "keychain locked state" "see assertions above"
out="$(FAKE_KEYCHAIN_LOCKED=1 CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts expired --quiet 2>&1)"; rc=$?
[ "$rc" = "0" ] && t_ok "a locked keychain login is not a relogin worklist item" \
  || t_fail "locked vs expired" "rc=$rc out=$out"
out="$(FAKE_KEYCHAIN_LOCKED=1 CLAUDE_ACCOUNTS_DIR="$KCP" claude 2>&1)"
check "shim never selects a keychain login it cannot read" "CFG=acct-01" "$out"
rm -f "$KCP/acct-01/.limited"

# 17d. limits: the probe takes its bearer from the keychain
rm -f "$KCP/acct-02/limits.json"
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits 2>&1)"
check "limits fetches with a keychain bearer" "acct-02: ok" "$out"
python3 -c 'import json,sys; d=json.load(open(sys.argv[1])); assert d.get("source")=="oauth", d' \
  "$KCP/acct-02/limits.json" 2>/dev/null \
  && t_ok "keychain-backed telemetry records source=oauth" \
  || t_fail "keychain limits source" "limits.json missing or wrong source"

# 17e. refresh: an expired keychain credential refreshes via the grant and is written
# BACK to the keychain — never copied out into a .credentials.json
kc_put "$KCP/acct-02" '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-kold","refreshToken":"sk-ant-ort01-kc","expiresAt":1000000,"refreshTokenExpiresAt":9999999999999}}'
rm -f "$KCP/acct-02/limits.json" "$KCP/acct-02/.oauth-refresh.json"
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" CLAUDE_MULTIACC_TOKEN_URL="file://$WORK/token-ok.json" CLAUDE_MULTIACC_USAGE_URL="file://$WORK/usage-low.json" claude-accounts limits --force 2>&1)"
check "keychain credential refreshes via the grant" "acct-02: oauth access token refreshed" "$out"
grep -q 'sk-ant-oat01-refreshednew' "$(kc_svc_file "$KCP/acct-02")" \
  && t_ok "rotated credential written back to the keychain" \
  || t_fail "keychain write-back" "item not updated"
[ ! -f "$KCP/acct-02/.credentials.json" ] \
  && t_ok "refresh never copies the keychain credential to a file" \
  || t_fail "keychain leak to file" ".credentials.json appeared beside a keychain login"

# 17f. .expired self-heals on a keychain login written after the marker
printf '%s\nreason=auth-error marked_at=t detail=test\n' "$now" > "$KCP/acct-02/.expired"
touch -t 202001010000 "$KCP/acct-02/.expired"
kc_put "$KCP/acct-02" '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-knew","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}'
CLAUDE_ACCOUNTS_DIR="$KCP" claude >/dev/null 2>&1
[ ! -f "$KCP/acct-02/.expired" ] \
  && t_ok ".expired self-heals on a newer keychain credential" \
  || t_fail "keychain .expired self-heal" "marker survived a newer keychain login"

# 17g. a login ceremony that lands in the keychain registers instead of dying
out="$(CLAUDE_MULTIACC_FORCE_TTY=1 FAKE_LOGIN_KEYCHAIN=1 FAKE_EMAIL=kc3@test CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts add kc3@test 2>&1)"
check "add registers a keychain-backed sign-in" "Registered acct-03 for kc3@test" "$out"
[ ! -f "$KCP/acct-03/.credentials.json" ] \
  && t_ok "keychain add leaves no plaintext credential" \
  || t_fail "keychain add" "unexpected .credentials.json"
[ -f "$(kc_svc_file "$KCP/acct-03")" ] && t_ok "the sign-in landed in the keychain" \
  || t_fail "keychain add item" "no keychain item for acct-03"

# 17h. export refuses a keychain-held machine-local credential, naming the store
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts export-credential acct-03 --out "$WORK/kc-export.json" 2>&1)"; rc=$?
[ "$rc" = "3" ] && t_ok "export-credential refuses a keychain login (exit 3)" \
  || t_fail "keychain export rc" "rc=$rc: $(printf '%s' "$out" | head -c 160)"
check "export names the keychain as the machine-local store" "macOS Keychain" "$out"

# 17i. remove deletes the keychain item with the account
CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts remove acct-03 --yes >/dev/null 2>&1
[ ! -f "$(kc_svc_file "$KCP/acct-03")" ] && t_ok "remove drops the keychain item" \
  || t_fail "keychain remove" "the item survived removal"

# 17j. dedupe keeps the duplicate that actually holds the (keychain) login. The
# keychain holder gets the HIGHER id on purpose: with keychain auth invisible, the
# lowest-id tiebreak would keep credential-less acct-04 and throw the grant away.
python3 - "$KCP/accounts.json" <<'EOF'
import json, sys
doc = json.load(open(sys.argv[1]))
doc['accounts'] += [
    {'id': 'acct-04', 'email': 'kdup@test', 'home': 'mac', 'added_at': '2026-08-28T00:00:00Z'},
    {'id': 'acct-05', 'email': 'kdup@test', 'home': 'mac', 'added_at': '2026-08-28T00:00:00Z'}]
json.dump(doc, open(sys.argv[1], 'w'))
EOF
mkdir -p "$KCP/acct-04" "$KCP/acct-05"
kc_put "$KCP/acct-05" '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-kdup","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999}}'
out="$(CLAUDE_ACCOUNTS_DIR="$KCP" claude-accounts dedupe --yes 2>&1)"
check "dedupe removes the credential-less duplicate, not the keychain one" "will remove acct-04 (kdup@test)" "$out"
[ -f "$(kc_svc_file "$KCP/acct-05")" ] && t_ok "the keychain-authed duplicate survives dedupe" \
  || t_fail "dedupe keychain keep" "acct-05's keychain item is gone"
grep -q '"acct-04"' "$KCP/accounts.json" \
  && t_fail "dedupe manifest" "acct-04 still registered" \
  || t_ok "the credential-less duplicate left the manifest"

export CLAUDE_MULTIACC_KEYCHAIN=0
unset FAKE_KEYCHAIN_DIR

# ---- 18. the rc block shadows `claude` even when the rc file that carries it is cut short ----
# 2026-09-17: a Ctrl-C at the slow conda hook in ~/.zshrc stopped the file before the
# multiacc block, ~/.local/bin stayed in front, and the next `claude` at that prompt ran
# the real binary on ~/.claude — "Not logged in · Please run /login". Every `bash -l` and
# `sh -l` on that Mac bypassed the shim too: ~/.profile (read when there is no
# ~/.bash_profile) carried no block at all. The block now ends with a prompt hook that
# re-asserts the shim dir before every prompt, the installer appends to ~/.profile, and
# `status` probes fresh login shells so a bypass is reported instead of guessed at.
RCH="$WORK/rc-home"
mkdir -p "$RCH/.local/bin"
printf '#!/bin/sh\necho REAL\n' > "$RCH/.local/bin/claude"
cp "$RCH/.local/bin/claude" "$RCH/.local/bin/codex"
chmod +x "$RCH/.local/bin/claude" "$RCH/.local/bin/codex"
rc_block_text() { # the block the installer writes, for THIS repo
  REPO_DIR="$REPO_DIR" MARK_BEGIN='# >>> claude-multiacc >>>' MARK_END='# <<< claude-multiacc <<<' \
    bash -c '. "$REPO_DIR/lib/install_actions.sh"; rc_block'
}
rc_block_text > "$WORK/rc-block.sh"
for rsh in sh bash zsh; do
  command -v "$rsh" >/dev/null 2>&1 || continue
  if "$rsh" -n "$WORK/rc-block.sh" 2>/dev/null; then t_ok "rc block parses under $rsh"
  else t_fail "rc block parses under $rsh" "$("$rsh" -n "$WORK/rc-block.sh" 2>&1 | head -2)"; fi
done
grep -q '_claude_multiacc_path_guard' "$WORK/rc-block.sh" \
  && t_ok "rc block carries the prompt hook" || t_fail "rc block carries the prompt hook"
# bash: the PROMPT_COMMAND hook undoes a later re-prepend, and registers itself once
out="$(HOME="$RCH" bash -c '. "$1"; . "$1"; PATH="$HOME/.local/bin:$PATH"; eval "$PROMPT_COMMAND"; printf "%s|%s" "${PATH%%:*}" "$PROMPT_COMMAND"' _ "$WORK/rc-block.sh" 2>&1)"
[ "$out" = "$REPO_DIR/bin|_claude_multiacc_path_guard" ] \
  && t_ok "bash prompt hook re-asserts the shim dir (registered once)" \
  || t_fail "bash prompt hook re-asserts the shim dir" "got: $out"
if command -v zsh >/dev/null 2>&1; then
  out="$(HOME="$RCH" zsh -c '. "$1"; . "$1"; PATH="$HOME/.local/bin:$PATH"; _claude_multiacc_path_guard; print -r -- "${PATH%%:*}|${(j:,:)precmd_functions}"' _ "$WORK/rc-block.sh" 2>&1)"
  [ "$out" = "$REPO_DIR/bin|_claude_multiacc_path_guard" ] \
    && t_ok "zsh precmd hook re-asserts the shim dir (registered once)" \
    || t_fail "zsh precmd hook re-asserts the shim dir" "got: $out"
fi
# ORDER: a hook registered before ours that rewrites PATH (direnv, a venv) must not have
# the final word — bash appends after it, zsh moves itself behind hooks ~/.zshrc added.
out="$(HOME="$RCH" bash -c 'PROMPT_COMMAND="other_hook"; . "$1"; printf %s "$PROMPT_COMMAND"' _ "$WORK/rc-block.sh" 2>&1)"
[ "$out" = "other_hook;_claude_multiacc_path_guard" ] \
  && t_ok "bash hook is appended after an existing PROMPT_COMMAND" \
  || t_fail "bash hook is appended after an existing PROMPT_COMMAND" "got: $out"
if command -v zsh >/dev/null 2>&1; then
  out="$(HOME="$RCH" zsh -c '. "$1"; precmd_functions+=(later_hook); . "$1"; print -r -- "${(j:,:)precmd_functions}"' _ "$WORK/rc-block.sh" 2>&1)"
  [ "$out" = "later_hook,_claude_multiacc_path_guard" ] \
    && t_ok "zsh hook re-registers itself LAST when the block is sourced again" \
    || t_fail "zsh hook re-registers itself LAST" "got: $out"
  out="$(HOME="$RCH" zsh -c 'IFS=":"; . "$1"; . "$1"; print -r -- "${(j:,:)precmd_functions}"' _ "$WORK/rc-block.sh" 2>&1)"
  [ "$out" = "_claude_multiacc_path_guard" ] \
    && t_ok "zsh hook registers once whatever IFS is" \
    || t_fail "zsh hook registers once whatever IFS is" "got: $out"
fi
# the hook is inert once the shim dir is gone: no error, PATH left alone
out="$(HOME="$RCH" bash -c 'sed "s|'"$REPO_DIR"'|/nonexistent/multiacc|g" "$1" > "$1.gone"; . "$1.gone"; PATH="$HOME/.local/bin:$PATH"; _claude_multiacc_path_guard; printf "rc=%s %s" "$?" "${PATH%%:*}"' _ "$WORK/rc-block.sh" 2>&1)"
[ "$out" = "rc=0 $RCH/.local/bin" ] \
  && t_ok "prompt hook is inert when the shim dir is gone" \
  || t_fail "prompt hook is inert when the shim dir is gone" "got: $out"
# ~/.profile: CREATED when absent (a stock Mac has none — without it every bash/sh login
# shell stays bypassed and the probe would fail health with a remedy that does nothing),
# appended to exactly once when present, and ~/.bash_profile is never created.
rm -f "$RCH/.profile"
HOME="$RCH" REPO_DIR="$REPO_DIR" MARK_BEGIN='# >>> claude-multiacc >>>' MARK_END='# <<< claude-multiacc <<<' \
  bash -c '. "$REPO_DIR/lib/install_actions.sh"; install_profile_block' >/dev/null
[ -f "$RCH/.profile" ] && [ "$(grep -c '# >>> claude-multiacc >>>' "$RCH/.profile")" = "1" ] \
  && t_ok "~/.profile is created with the block when absent" \
  || t_fail "~/.profile is created with the block when absent"
printf 'export PATH="$HOME/.local/bin:$PATH"\n' > "$RCH/.profile"
for _ in 1 2; do
  HOME="$RCH" REPO_DIR="$REPO_DIR" MARK_BEGIN='# >>> claude-multiacc >>>' MARK_END='# <<< claude-multiacc <<<' \
    bash -c '. "$REPO_DIR/lib/install_actions.sh"; install_profile_block' >/dev/null
done
[ "$(grep -c '# >>> claude-multiacc >>>' "$RCH/.profile")" = "1" ] \
  && t_ok "~/.profile gets the block exactly once" || t_fail "~/.profile gets the block exactly once"
[ ! -e "$RCH/.bash_profile" ] && t_ok "installer never creates ~/.bash_profile" \
  || t_fail "installer never creates ~/.bash_profile" "it exists"
for lsh in sh bash; do
  out="$(env -i HOME="$RCH" USER="${USER:-tester}" TERM=dumb PATH=/usr/bin:/bin "$lsh" -lc 'command -v claude' 2>/dev/null)"
  [ "$out" = "$REPO_DIR/bin/claude" ] && t_ok "$lsh -l resolves the shim through ~/.profile" \
    || t_fail "$lsh -l resolves the shim through ~/.profile" "got: $out"
done
# the interrupted-rc incident, end to end, through the probe `status` prints
if command -v zsh >/dev/null 2>&1; then
  cp "$WORK/rc-block.sh" "$RCH/.zshenv"
  { printf 'export PATH="$HOME/.local/bin:$PATH"\n'; cat "$WORK/rc-block.sh"; } > "$RCH/.zprofile"
  printf 'export PATH="$HOME/.local/bin:$PATH"\nreturn 0  # the rest of this rc file was never reached\n' > "$RCH/.zshrc"
  cat "$WORK/rc-block.sh" >> "$RCH/.zshrc"
  out="$(HOME="$RCH" CLAUDE_MULTIACC_PATH_PROBE=1 python3 "$REPO_DIR/lib/shim_path.py" "$REPO_DIR" 2>&1)"; rc=$?
  [ "$rc" = 0 ] && case "$out" in *"zsh -li"*"claude: OK"*) t_ok "interrupted ~/.zshrc: the prompt hook still hands claude to the shim" ;; *) t_fail "interrupted ~/.zshrc probe" "$out" ;; esac
  [ "$rc" = 0 ] || t_fail "interrupted ~/.zshrc probe exit" "rc=$rc: $out"
  # the same rc files with the OLD two-line block (no hook) are the incident itself
  for f in .zshenv .zprofile .zshrc; do
    awk '/^_claude_multiacc_path_guard\(\)/{skip=1} /^# <<< claude-multiacc <<</{skip=0} !skip' "$RCH/$f" > "$RCH/$f.old" && mv "$RCH/$f.old" "$RCH/$f"
  done
  out="$(HOME="$RCH" CLAUDE_MULTIACC_PATH_PROBE=1 python3 "$REPO_DIR/lib/shim_path.py" "$REPO_DIR" 2>&1)"; rc=$?
  case "$rc:$out" in 1:*"zsh -li"*"BYPASSED -> $RCH/.local/bin/claude"*) t_ok "the probe catches the pre-fix block (zsh -li bypassed)" ;;
    *) t_fail "the probe catches the pre-fix block" "rc=$rc: $out" ;; esac
  out="$(HOME="$RCH" CLAUDE_MULTIACC_PATH_PROBE=1 claude-accounts status 2>&1)"
  check "status reports the bypass" "BYPASSED -> $RCH/.local/bin/claude" "$out"
  check "status names the fix" "claude-multiacc install" "$out"
  # restore the hook: status is clean again
  cp "$WORK/rc-block.sh" "$RCH/.zshenv"
  { printf 'export PATH="$HOME/.local/bin:$PATH"\n'; cat "$WORK/rc-block.sh"; } > "$RCH/.zprofile"
  out="$(HOME="$RCH" CLAUDE_MULTIACC_PATH_PROBE=1 claude-accounts status 2>&1)"
  case "$out" in *BYPASSED*|*"NOT ON PATH"*) t_fail "status is clean with the hooked block" "$out" ;;
    *"shim on PATH"*) t_ok "status is clean with the hooked block" ;;
    *) t_fail "status prints the shim probe" "$out" ;; esac
fi
out="$(HOME="$RCH" claude-accounts status 2>&1)"
check "status honours CLAUDE_MULTIACC_PATH_PROBE=0" "probe disabled" "$out"

# ============================ AUTO-RESUME (end to end) ============================
# An interactive session that stops on a usage limit, a dead login or a crash is resumed
# on another account: the shim spawns lib/autoresume.py beside its UNCHANGED exec, the
# watcher tails the session's transcript (codex: rollout), stops the TUI and types the
# relaunch into the pane's SHELL, and the relaunched shim marks the old account before it
# selects. Here the TUI is the fakes' FAKE_TUI mode and tmux is a fake that never talks to
# a server: display-message answers from the environment, and Enter runs the typed line
# with `bash -c` in the background — the pane's shell, with the pane's environment (none
# of the client's CLAUDE_CONFIG_DIR/CODEX_HOME exports). Every case gets its own pool, cut-
# down timing knobs and hard timeouts, and ends in ar_reap, which kills what it started.
ARB="$WORK/ar"
ARH="$WORK/ar-home"          # a sandbox HOME: nothing here may touch the operator's
ARW="$WORK/ar-work dir"      # the session's directory (with a space, on purpose)
ARPY="$(command -v python3)"
mkdir -p "$ARB" "$ARH" "$ARW"
cat > "$FAKEBIN/tmux" <<'EOF'
#!/usr/bin/env bash
# fake tmux for the auto-resume sections (never a server; shadows any real tmux on PATH)
st="${FAKE_TMUX_DIR:-}"
[ -n "$st" ] && [ -d "$st" ] || exit 1
printf '%s\n' "$*" >> "$st/calls"
while [ $# -gt 0 ]; do
  case "$1" in -S|-L) shift; [ $# -gt 0 ] && shift ;; *) break ;; esac
done
verb="${1:-}"; [ $# -gt 0 ] && shift
case "$verb" in
  display-message)
    # -p answers the format the watcher asked for; without -p it is a status-line notice.
    p=0; fmt=""
    while [ $# -gt 0 ]; do
      case "$1" in
        -p) p=1; shift ;;
        -t) shift; [ $# -gt 0 ] && shift ;;
        *) fmt="$1"; shift ;;
      esac
    done
    [ "$p" = 1 ] || exit 0
    printf '%s\n' "$fmt" | sed -e "s/#{pane_pid}/${FAKE_TMUX_PANE_PID:-1}/g" \
      -e "s/#{pane_current_command}/${FAKE_TMUX_PANE_CMD:-zsh}/g" \
      -e "s/#{pane_in_mode}/${FAKE_TMUX_PANE_MODE:-0}/g" \
      -e "s/#{synchronize-panes}/${FAKE_TMUX_PANE_SYNC:-0}/g" ;;
  send-keys)
    lit=0
    while [ $# -gt 0 ]; do
      case "$1" in
        -t) shift; [ $# -gt 0 ] && shift; continue ;;
        -R) shift; continue ;;
        -l) lit=1; shift; continue ;;
      esac
      if [ "$lit" = 1 ]; then
        printf '%s' "$1" >> "$st/line"
      else
        case "$1" in
          C-u) : > "$st/line" ;;
          Enter)
            line="$(cat "$st/line" 2>/dev/null)"; : > "$st/line"
            printf '%s\n' "$line" >> "$st/typed"
            # The trailing `:` keeps bash from exec'ing the command in its own place: like
            # the pane's real shell, it stays the relaunched shim's parent (its PPID).
            ( unset CLAUDE_CONFIG_DIR CLAUDE_CODE_OAUTH_TOKEN CLAUDE_SHIM_ACTIVE CODEX_HOME CODEX_SHIM_ACTIVE
              exec bash -c "$line; :" ) </dev/null >> "$st/shell.out" 2>&1 & ;;
        esac
      fi
      shift
    done ;;
esac
exit 0
EOF
chmod +x "$FAKEBIN/tmux"
# Records a spawn instead of watching: the gate cases need a watcher that leaves its state
# file in place, so "no state file" can only mean "no spawn".
cat > "$ARB/stub-python" <<'EOF'
#!/bin/sh
echo "$*" >> "${FAKE_STUB_PY_LOG:-/dev/null}"
EOF
chmod +x "$ARB/stub-python"

ar_wait() { # ar_wait <seconds> <cmd...>: poll every 0.1 s until cmd succeeds; 1 on timeout
  local n=0 lim=$(($1 * 10))
  shift
  while ! "$@"; do
    n=$((n + 1)); [ "$n" -lt "$lim" ] || return 1
    sleep 0.1
  done
  return 0
}
ar_lines() { [ -f "$2" ] && [ "$(($(wc -l < "$2")))" -ge "$1" ]; }       # <n> <file>
ar_logged() { grep -Eq "$2" "$1/selection.log" 2>/dev/null; }            # <pool> <ERE>
ar_no_watcher() { ! pgrep -f "$1/tmp/autoresume/" >/dev/null 2>&1; }      # <pool>
ar_acct_of() { printf '%s' "$1" | sed -n 's/^CFG=\(acct-[0-9]*\) .*/\1/p'; }
# A stopped client may linger as a zombie until its parent reaps it: that is gone, not alive.
ar_running() { kill -0 "$1" 2>/dev/null && ! ps -o stat= -p "$1" 2>/dev/null | grep -q '^Z'; }
ar_stopped() { ! ar_running "$1"; }
ar_start() { # ar_start [VAR=val ...] -- <cmd> [args...]: the launch typed in the pane, backgrounded
  local pre=()
  while [ $# -gt 0 ] && [ "$1" != "--" ]; do pre+=("$1"); shift; done
  [ $# -gt 0 ] && shift
  ( cd "$ARW" && exec env "${AREC[@]}" ${pre[@]+"${pre[@]}"} "$@" ) </dev/null >> "$ARB/tui.out" 2>&1 &
  AR_PID=$!
  # Not a job of this shell: the crash case SIGKILLs it, and bash would print a job notice.
  # bash still reaps it (waitpid(-1) on SIGCHLD); ar_reap kills it by pid.
  disown "$AR_PID" 2>/dev/null || true
}
ar_reap() { # ar_reap <pool>: stop every client and watcher the case started, then prove it
  local p n=0
  : > "$1/autoresume.off" 2>/dev/null || true   # running watchers leave on their next tick
  if [ -f "$ARB/pids" ]; then
    while read -r p; do kill -TERM "$p" 2>/dev/null; done < "$ARB/pids"
  fi
  while ! ar_no_watcher "$1" && [ "$n" -lt 50 ]; do sleep 0.1; n=$((n + 1)); done
  pkill -KILL -f "$1/tmp/autoresume/" 2>/dev/null || true
  if [ -f "$ARB/pids" ]; then
    while read -r p; do kill -KILL "$p" 2>/dev/null; done < "$ARB/pids"
  fi
  [ -n "${AR_PID:-}" ] && kill -KILL "$AR_PID" 2>/dev/null
  AR_PID=""
}
AR_SID=5f0c1d2e-3a4b-4c5d-8e9f-a0b1c2d3e4f5      # the fake claude's default session id
AR_CXSID=6a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d    # the fake codex's
ar_typed_ok() { # ar_typed_ok <CLAUDE|CODEX> <sid> <ROOTVAR=root or ""> <shim>: exactly one line, exactly this
  local line tok
  [ -f "$ARB/tmux/typed" ] && [ "$(($(wc -l < "$ARB/tmux/typed")))" = 1 ] || return 1
  line="$(cat "$ARB/tmux/typed")"
  tok="${line#" $1_MULTIACC_AR="}"; tok="${tok%%:*}"
  printf '%s\n' "$tok" | grep -Eqx '[A-Za-z0-9]{16,64}' || return 1
  [ "$line" = " $1_MULTIACC_AR=$tok:$2 ${3:+$3 }$4" ]
}
ar_pty() { # ar_pty <both|stdin> <cmd...>: stdin on a pty; stdout on that pty too, or on a pipe
  python3 -c '
import pty, subprocess, sys
m, s = pty.openpty()
r = subprocess.run(sys.argv[2:], stdin=s, stdout=s if sys.argv[1] == "both" else subprocess.PIPE)
if r.stdout:
    sys.stdout.buffer.write(r.stdout)
sys.exit(r.returncode)' "$@"
}
ar_plant() { # ar_plant <pool> <token> <provider> <class> <left acct> -- <argv...>: a watcher's relaunch files
  local pool="$1" tok="$2" prov="$3" cls="$4" acct="$5" sid="$AR_SID"
  shift 5; [ "${1:-}" = "--" ] && shift
  [ "$prov" = codex ] && sid="$AR_CXSID"
  mkdir -p "$pool/tmp/autoresume"
  printf '%s\n' v=1 "provider=$prov" "class=$cls" "acct=$acct" "sid=$sid" "cwd=$ARW" depth=1 chain=PlantTst \
    > "$pool/tmp/autoresume/r-$tok.relaunch"
  printf '%s\0' "$@" > "$pool/tmp/autoresume/r-$tok.argv"
}
# A typed relaunch whose token cannot be honoured names the session and exits 2: the line
# has no argv of its own, so running on would open a FRESH session in the stopped one's place.
ar_dead() { # ar_dead <claude|codex> <name> <expected output> [VAR=val ...]
  local prov="$1" name="$2" want="$3" out rc
  shift 3
  if [ "$prov" = claude ]; then
    out="$(cd "$ARH" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" "$@" claude </dev/null 2>&1)"; rc=$?
  else
    out="$(cd "$ARH" && env "${AREX[@]}" CODEX_MULTIACC_PYTHON="$ARB/stub-python" "$@" codex </dev/null 2>&1)"; rc=$?
  fi
  [ "$rc" = 2 ] && [ "$out" = "$want" ] \
    && t_ok "AR dead token ($prov): $name -> the resume hint, exit 2, nothing started" \
    || t_fail "AR dead token ($prov): $name" "rc=$rc out=$out"
}
AR_DEAD_MSG="auto-resume could not continue automatically (the resume token expired)."

# ---- AR1. claude: fixture pool, environment, and the gate --------------------------------
ARC="$WORK/ar-claude"
ar_claude_pool() { # a fresh two-account pool whose accounts share one projects tree
  local i
  rm -rf "$ARC" "$ARB/tmux" "$ARB/pids" "$ARB/tui.log" "$ARB/stub.log"
  mkdir -p "$ARC/tmp" "$ARC/shared-projects" "$ARB/tmux"
  printf '{"version": 1, "threshold": 90, "accounts": [%s, %s]}\n' \
    '{"id": "acct-01", "email": "a@ar", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
    '{"id": "acct-02", "email": "b@ar", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
    > "$ARC/accounts.json"
  for i in 01 02; do
    mkdir -p "$ARC/acct-$i"
    printf '{"claudeAiOauth":{"accessToken":"sk-ant-oat01-ar%s","refreshToken":"r","expiresAt":9999999999999,"refreshTokenExpiresAt":9999999999999,"scopes":["user:inference"],"subscriptionType":"max"}}' "$i" \
      > "$ARC/acct-$i/.credentials.json"
    printf '{"fetched_at":%s,"weekly_percent":20,"session_percent":10,"max_percent":20,"buckets":[]}' "$(date +%s)" \
      > "$ARC/acct-$i/limits.json"
    ln -s "$ARC/shared-projects" "$ARC/acct-$i/projects"
  done
  : > "$ARC/.limits-kick"
}
AREC=(CLAUDE_ACCOUNTS_DIR="$ARC" HOME="$ARH" TMUX="$ARB/tmux-sock,4242,0" TMUX_PANE=%1
  CLAUDE_MULTIACC_AUTORESUME=1 CLAUDE_MULTIACC_PYTHON="$ARPY" CLAUDE_MULTIACC_AR_TEST_TTY=1
  CLAUDE_MULTIACC_AR_TEST_TMUX_ANYPANE=1 CLAUDE_MULTIACC_AR_POLL=0.1 CLAUDE_MULTIACC_AR_GRACE=0.5
  CLAUDE_MULTIACC_AR_TERM_GRACE=3 CLAUDE_MULTIACC_AR_PANE_WAIT=5 CLAUDE_MULTIACC_AR_PROBE_TIMEOUT=15
  CLAUDE_MULTIACC_AR_CRASH_MIN_RUNTIME=0 CLAUDE_MULTIACC_AUTORESUME_DEBUG=1
  FAKE_TMUX_DIR="$ARB/tmux" FAKE_TUI_LOG="$ARB/tui.log" FAKE_TUI_PIDS="$ARB/pids")

# The gate: only the plain interactive exec in tmux, with an argv the relaunch can rebuild,
# gets a watcher; everything else is exactly today's exec (same argv, no state file).
ar_claude_pool
ar_gate() { # ar_gate <name> <watcher|none> [VAR=val ...] -- <claude args...>
  local name="$1" want="$2" pre=() out states
  shift 2
  while [ $# -gt 0 ] && [ "$1" != "--" ]; do pre+=("$1"); shift; done
  [ $# -gt 0 ] && shift
  rm -rf "$ARC/tmp/autoresume" "$ARB/stub.log"
  out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" \
    FAKE_STUB_PY_LOG="$ARB/stub.log" ${pre[@]+"${pre[@]}"} claude "$@" </dev/null 2>&1)"
  states="$(ls "$ARC/tmp/autoresume/" 2>/dev/null | grep -c '\.state$')"
  case "$out" in
    *"ARGS=$*") ;;
    *) t_fail "auto-resume gate: $name execs the argv unchanged" "$out"; return ;;
  esac
  if [ "$want" = watcher ]; then
    if [ "$states" = 1 ] && ar_wait 5 grep -qs -- "-I .*lib/autoresume.py watch --state $ARC/tmp/autoresume/[0-9]*\.state" "$ARB/stub.log"; then
      t_ok "auto-resume gate: $name gets a watcher, exec unchanged"
    else
      t_fail "auto-resume gate: $name gets a watcher" "states=$states stub=$(cat "$ARB/stub.log" 2>/dev/null)"
    fi
  else
    [ "$states" = 0 ] && [ ! -s "$ARB/stub.log" ] \
      && t_ok "auto-resume gate: $name gets no watcher, exec unchanged" \
      || t_fail "auto-resume gate: $name gets no watcher" "states=$states"
  fi
}
ar_gate "a prompt with the permission flag" watcher -- --dangerously-skip-permissions "fix the bug please"
ar_gate "--resume <uuid> with a model" watcher -- --model opus --resume "$AR_SID"
ar_gate "-p" none -- -p "hi there"
ar_gate "a pinned run" none CLAUDE_ACCOUNT=acct-01 -- --dangerously-skip-permissions
ar_gate "outside tmux" none TMUX= -- --dangerously-skip-permissions
ar_gate "piped stdio" none CLAUDE_MULTIACC_AR_TEST_TTY= -- --dangerously-skip-permissions
ar_gate "an unknown flag" none -- --fork-session --dangerously-skip-permissions
ar_gate "a single-word positional (maybe a subcommand)" none -- doctor
ar_gate "CLAUDE_MULTIACC_AUTORESUME=0" none CLAUDE_MULTIACC_AUTORESUME=0 -- --dangerously-skip-permissions
: > "$ARC/autoresume.off"
ar_gate "the pool's autoresume.off" none -- --dangerously-skip-permissions
rm -f "$ARC/autoresume.off"
# the watcher's argv is the ORIGINAL one, before the fallback-model pin adds --model
ar_gate "no argv at all" watcher --
af="$(ls "$ARC/tmp/autoresume/"*.argv 2>/dev/null | head -1)"
[ -n "$af" ] && [ ! -s "$af" ] \
  && t_ok "auto-resume: a bare launch records an empty original argv" \
  || t_fail "auto-resume: a bare launch records an empty original argv" "$af"
# ...and it stays empty when the pin DOES fire: every account's Fable bucket is spent, so
# the exec carries --model, but the watcher must rebuild from what the user typed (the
# relaunch re-runs selection and pins again for the NEW pick).
for i in 01 02; do
  printf '%s\nbucket=weekly_scoped:Fable percent=100 marked_at=x reason=limits\n' "$(( $(date +%s) + 3600 ))" \
    > "$ARC/acct-$i/.limited"
  printf '{"fetched_at":%s,"max_percent":100,"weekly_percent":20,"session_percent":10,"buckets":[{"name":"session","percent":10},{"name":"weekly_all","percent":20},{"name":"weekly_scoped:Fable","percent":100}]}' \
    "$(date +%s)" > "$ARC/acct-$i/limits.json"
done
rm -rf "$ARC/tmp/autoresume" "$ARB/stub.log"
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" FAKE_STUB_PY_LOG="$ARB/stub.log" \
  claude </dev/null 2>&1)"
af="$(ls "$ARC/tmp/autoresume/"*.argv 2>/dev/null | head -1)"
case "$out" in
  *"ARGS=--model claude-opus-5")
    [ -n "$af" ] && [ -f "$af" ] && [ ! -s "$af" ] \
      && t_ok "auto-resume: the watcher gets the argv from BEFORE the fallback-model pin" \
      || t_fail "auto-resume: the .argv file carries the pin" "$(tr '\0' ' ' < "$af" 2>/dev/null)" ;;
  *) t_fail "auto-resume: the fallback-model pin fired" "$out" ;;
esac
ar_claude_pool
ar_gate "an invalid pin (random fallback)" none CLAUDE_ACCOUNT=acct-99 -- --dangerously-skip-permissions
# The relaunch line is typed into the shell unquoted: a pool root or a shim path that would
# need quoting gets no watcher, and the launch itself is unchanged.
ln -s "$ARC" "$WORK/ar claude root"
ar_gate "a pool root that would need quoting" none CLAUDE_ACCOUNTS_DIR="$WORK/ar claude root" -- --dangerously-skip-permissions
mkdir -p "$WORK/ar shim copy"
cp -R "$REPO_DIR/bin" "$REPO_DIR/lib" "$WORK/ar shim copy/"
rm -rf "$ARC/tmp/autoresume" "$ARB/stub.log"
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" FAKE_STUB_PY_LOG="$ARB/stub.log" \
  "$WORK/ar shim copy/bin/claude" --dangerously-skip-permissions </dev/null 2>&1)"
case "$out" in
  *"ARGS=--dangerously-skip-permissions")
    [ -z "$(ls "$ARC/tmp/autoresume/" 2>/dev/null | grep '\.state$')" ] && [ ! -s "$ARB/stub.log" ] \
      && t_ok "auto-resume gate: a shim path that would need quoting gets no watcher, exec unchanged" \
      || t_fail "auto-resume gate: a shim path that would need quoting gets no watcher" "$(ls "$ARC/tmp/autoresume/" 2>/dev/null)" ;;
  *) t_fail "auto-resume gate: a shim path that would need quoting execs the argv unchanged" "$out" ;;
esac
# stdin on a terminal but stdout piped (`claude "x y" | tee log`): no watcher. The same
# launch with stdout on the terminal too does get one, so the pipe is what decided it.
for mode in stdin both; do
  rm -rf "$ARC/tmp/autoresume" "$ARB/stub.log"
  out="$(cd "$ARW" && ar_pty "$mode" env "${AREC[@]}" CLAUDE_MULTIACC_AR_TEST_TTY= \
    CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" FAKE_STUB_PY_LOG="$ARB/stub.log" \
    claude --dangerously-skip-permissions 2>&1)"
  states="$(ls "$ARC/tmp/autoresume/" 2>/dev/null | grep -c '\.state$')"
  if [ "$mode" = stdin ]; then
    case "$out" in *"ARGS=--dangerously-skip-permissions") ;; *) states="exec:$out" ;; esac
    [ "$states" = 0 ] && [ ! -s "$ARB/stub.log" ] \
      && t_ok "auto-resume gate: a terminal on stdin with stdout piped gets no watcher, exec unchanged" \
      || t_fail "auto-resume gate: stdout piped gets no watcher" "states=$states"
  else
    [ "$states" = 1 ] && t_ok "auto-resume gate: stdin and stdout on a terminal get a watcher (control)" \
      || t_fail "auto-resume gate: both on a terminal get a watcher" "states=$states"
  fi
done
# The client never sees an auto-resume variable (a nested claude must not inherit a probe).
rm -rf "$ARC/tmp/autoresume"
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" \
  CLAUDE_MULTIACC_AR_AVOID=acct-01:9999999999 FAKE_PRINT_ENV=1 \
  claude --dangerously-skip-permissions </dev/null 2>&1)"
check "auto-resume: the client never sees an auto-resume variable" "AR_ENV=0" "$out"
st="$(ls "$ARC/tmp/autoresume/"*.state 2>/dev/null | head -1)"
grep -q "^pid=[0-9]" "$st" 2>/dev/null && grep -q "^tmux=$ARB/tmux-sock,4242,0\$" "$st" \
  && grep -q '^pane=%1$' "$st" && grep -q "^acc_root=$ARC\$" "$st" && grep -q '^depth=0$' "$st" \
  && t_ok "auto-resume: the state file names the pid, pane, pool and chain depth" \
  || t_fail "auto-resume state file" "$(cat "$st" 2>/dev/null)"

# ---- AR2. claude probe mode: the real candidate loop, never an exec ----------------------
ar_claude_pool
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_AR_PROBE=1 claude --dangerously-skip-permissions </dev/null 2>&1)"; rc=$?
case "$rc:$out" in
  0:pick=acct-0[12]" tier=eligible") t_ok "probe prints pick/tier and exits 0" ;;
  *) t_fail "probe prints pick/tier" "rc=$rc out=$out" ;;
esac
case "$out" in *CFG=*) t_fail "probe never execs the client" "$out" ;; *) t_ok "probe never execs the client" ;; esac
all2=1
for _ in 1 2 3 4 5; do
  out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_AR_PROBE=1 \
    CLAUDE_MULTIACC_AR_AVOID="acct-01:$(( $(date +%s) + 3600 )),acct-02:$(( $(date +%s) - 5 ))" \
    claude --dangerously-skip-permissions </dev/null 2>&1)"
  [ "$out" = "pick=acct-02 tier=eligible" ] || all2=0
done
[ "$all2" = 1 ] && t_ok "probe honours AVOID (an expired entry is ignored)" \
  || t_fail "probe AVOID" "$out"
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_AR_PROBE=1 \
  CLAUDE_MULTIACC_AR_AVOID="acct-01:$(( $(date +%s) + 3600 )),acct-02:$(( $(date +%s) + 3600 ))" \
  claude --dangerously-skip-permissions </dev/null 2>&1)"
case "$out" in "pick=acct-0"[12]" tier=soft") t_ok "probe with every account avoided answers tier=soft" ;;
  *) t_fail "probe tier=soft" "$out" ;; esac
ar_logged "$ARC" 'all-limited fallback' \
  && t_fail "a probe logs no fallback pick" "$(grep 'all-limited' "$ARC/selection.log")" \
  || t_ok "a probe logs no fallback pick"
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_AR_PROBE=1 CLAUDE_MULTIACC_DISABLE=1 claude </dev/null 2>&1)"; rc=$?
[ "$rc:$out" = "3:pick= tier=none" ] && t_ok "probe on a passthrough answers tier=none (exit 3)" \
  || t_fail "probe passthrough" "rc=$rc out=$out"
[ ! -f "$ARC/.last-pick" ] && t_ok "a probe does not count as a pick (no rotation memory)" \
  || t_fail "a probe does not count as a pick" "$(cat "$ARC/.last-pick")"
# No valid login anywhere: a launch would fall back to the stock client — a probe must not.
rm -f "$ARC"/acct-0*/.credentials.json
out="$(cd "$ARW" && env "${AREC[@]}" CLAUDE_MULTIACC_AR_PROBE=1 claude --dangerously-skip-permissions </dev/null 2>&1)"; rc=$?
[ "$rc:$out" = "3:pick= tier=none" ] && t_ok "probe on a pool with no valid login answers tier=none (exit 3), never execs" \
  || t_fail "probe with no valid login" "rc=$rc out=$out"

# ---- AR3. claude quota: stop, relaunch on the other account, same session ----------------
# No ANYPANE here: the pane's pid is this shell, which IS the launching shim's parent. The
# transcript scan (12f) is off, so the old account's marker can only come from the relaunch.
ar_claude_pool
ar_start FAKE_TUI=quota CLAUDE_MULTIACC_AR_TEST_TMUX_ANYPANE= FAKE_TMUX_PANE_PID=$$ \
  CLAUDE_MULTIACC_CLIENT_LIMITS=0 -- claude --dangerously-skip-permissions "fix the bug please"
first=$AR_PID
if ar_wait 30 ar_lines 2 "$ARB/tui.log"; then
  l1="$(sed -n 1p "$ARB/tui.log")"; l2="$(sed -n 2p "$ARB/tui.log")"
  from="$(ar_acct_of "$l1")"; to="$(ar_acct_of "$l2")"
  check "AR quota: the first launch ran the user's argv" \
    "ARGS=--dangerously-skip-permissions fix the bug please" "$l1"
  [ -n "$from" ] && [ -n "$to" ] && [ "$from" != "$to" ] \
    && t_ok "AR quota: relaunched on the OTHER account ($from -> $to)" \
    || t_fail "AR quota: relaunched on the other account" "$l1 | $l2"
  check "AR quota: the relaunch resumes the same session with the auto-resume prompt" \
    "ARGS=--dangerously-skip-permissions --resume $AR_SID (claude-multiacc auto-resume) This session was restarted automatically on another account because the previous account hit its usage limit." "$l2"
  case "$l2" in *"fix the bug please"*) t_fail "AR quota: the original prompt is not replayed" "$l2" ;;
    *) t_ok "AR quota: the original prompt is not replayed" ;; esac
  ar_wait 5 ar_stopped "$first" && t_ok "AR quota: the stuck client was stopped" \
    || t_fail "AR quota: the stuck client was stopped" "pid $first alive"
  grep -q 'bucket=client:five_hour percent=100' "$ARC/$from/.limited" 2>/dev/null \
    && t_ok "AR quota: the old account carries a client:five_hour marker" \
    || t_fail "AR quota: marker on the old account" "$(cat "$ARC/$from/.limited" 2>/dev/null)"
  ar_logged "$ARC" "autoresume switch provider=claude chain=[A-Za-z0-9]+ from=$from class=quota sid=$AR_SID depth=1 probe=$to" \
    && t_ok "AR quota: the watcher logged the switch (field 2 = autoresume)" \
    || t_fail "AR quota: switch log line" "$(grep autoresume "$ARC/selection.log")"
  chain="$(sed -n 's/.*autoresume watch provider=claude chain=\([A-Za-z0-9]*\) .*/\1/p' "$ARC/selection.log" | head -1)"
  ar_logged "$ARC" "autoresume relaunch chain=$chain from=$from class=quota depth=1\$" \
    && t_ok "AR quota: the relaunched shim consumed the token and kept the chain" \
    || t_fail "AR quota: relaunch log line" "$(grep autoresume "$ARC/selection.log")"
  ar_typed_ok CLAUDE "$AR_SID" "CLAUDE_ACCOUNTS_ROOT=$(cd "$ARC" && pwd)" "$REPO_DIR/bin/claude" \
    && t_ok "AR quota: exactly one token line was typed: token:sid, the pool root, the shim's path" \
    || t_fail "AR quota: typed line" "$(cat "$ARB/tmux/typed" 2>/dev/null)"
  seq_ok="$(grep -E 'display-message|send-keys' "$ARB/tmux/calls" | sed 's/ -l .*/ -l <line>/' | tr '\n' '|')"
  case "$seq_ok" in
    *"-S $ARB/tmux-sock display-message -p -t %1 #{pane_pid}"*"-S $ARB/tmux-sock send-keys -R -t %1|-S $ARB/tmux-sock send-keys -t %1 C-u|-S $ARB/tmux-sock send-keys -t %1 -l <line>|-S $ARB/tmux-sock send-keys -t %1 Enter|")
      t_ok "AR quota: pane check, then -R, C-u, the line, Enter — on the launching pane" ;;
    *) t_fail "AR quota: tmux sequence" "$seq_ok" ;;
  esac
  ls "$ARC/tmp/autoresume/" 2>/dev/null | grep -q '^r-' \
    && t_fail "AR quota: the relaunch token is single use" "$(ls "$ARC/tmp/autoresume/")" \
    || t_ok "AR quota: the relaunch token is single use (files consumed)"
  ar_wait 10 ar_logged "$ARC" "autoresume watch provider=claude chain=$chain pid=[0-9]+ acct=$to depth=1\$" \
    && t_ok "AR quota: the relaunched session is supervised again (same chain, depth 1)" \
    || t_fail "AR quota: second watcher" "$(grep autoresume "$ARC/selection.log")"
else
  t_fail "AR quota: relaunched within 30 s" "tui=$(cat "$ARB/tui.log" 2>/dev/null) log=$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"
ar_no_watcher "$ARC" && t_ok "AR quota: no watcher left running" || t_fail "AR quota: watcher left running"

# ---- AR4. claude: a pane that is not the launching shell is never typed into -----------
ar_claude_pool
ar_start FAKE_TUI=quota CLAUDE_MULTIACC_AR_TEST_TMUX_ANYPANE= FAKE_TMUX_PANE_PID=1 \
  -- claude --dangerously-skip-permissions "fix the bug please"
if ar_wait 20 ar_logged "$ARC" 'autoresume giveup provider=claude .*reason=pane'; then
  sleep 0.3
  ar_running "$AR_PID" && [ ! -s "$ARB/tmux/typed" ] \
    && ! ls "$ARC/tmp/autoresume/" 2>/dev/null | grep -q '^r-' \
    && t_ok "AR pane: another pane's process -> give up before stopping anything" \
    || t_fail "AR pane: nothing stopped, nothing typed" "$(cat "$ARB/tmux/typed" 2>/dev/null)"
else
  t_fail "AR pane: giveup logged" "$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"

# ---- AR5. claude auth: the old login is parked, the session moves ------------------------
ar_claude_pool
ar_start FAKE_TUI=auth -- claude --dangerously-skip-permissions "fix the bug please"
if ar_wait 30 ar_lines 2 "$ARB/tui.log"; then
  l1="$(sed -n 1p "$ARB/tui.log")"; l2="$(sed -n 2p "$ARB/tui.log")"
  from="$(ar_acct_of "$l1")"; to="$(ar_acct_of "$l2")"
  [ -n "$from" ] && [ "$from" != "$to" ] && [ -f "$ARC/$from/.expired" ] \
    && t_ok "AR auth: the old account is parked (.expired) and the session moved ($from -> $to)" \
    || t_fail "AR auth: park + rotate" "$l1 | $l2 | $(ls -a "$ARC/$from" 2>/dev/null | tr '\n' ' ')"
  check "AR auth: resumed with the login reason" \
    "--resume $AR_SID (claude-multiacc auto-resume) This session was restarted automatically on another account because the previous account's login failed." "$l2"
else
  t_fail "AR auth: relaunched within 30 s" "$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"

# ---- AR6. claude crash: the registry left behind means a crash; relaunch in place -------
ar_claude_pool
ar_start FAKE_TUI=crash -- claude --dangerously-skip-permissions "fix the bug please"
if ar_wait 30 ar_lines 2 "$ARB/tui.log"; then
  l2="$(sed -n 2p "$ARB/tui.log")"
  check "AR crash: resumed with the crash reason, no 'another account'" \
    "--resume $AR_SID (claude-multiacc auto-resume) This session was restarted automatically because the previous process exited unexpectedly." "$l2"
  ar_logged "$ARC" 'autoresume crash provider=claude .* runtime=[0-9]+' \
    && ar_logged "$ARC" 'autoresume relaunch chain=[A-Za-z0-9]+ from=acct-0[12] class=crash depth=1$' \
    && t_ok "AR crash: logged as a crash and relaunched (no marker class)" \
    || t_fail "AR crash: log lines" "$(grep autoresume "$ARC/selection.log")"
  ls "$ARC"/acct-0*/.limited >/dev/null 2>&1 \
    && t_fail "AR crash: no account is marked" "$(ls "$ARC"/acct-0*/.limited)" \
    || t_ok "AR crash: no account is marked"
else
  t_fail "AR crash: relaunched within 30 s" "$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"

# ---- AR7. claude: errors auto-resume must NOT act on ---------------------------------------
# invalid_request: another account would fail the same way — logged once, left alone.
ar_claude_pool
ar_start FAKE_TUI=invalid -- claude --dangerously-skip-permissions "fix the bug please"
if ar_wait 15 ar_logged "$ARC" 'autoresume never provider=claude .*code=invalid_request'; then
  sleep 1.5
  ar_running "$AR_PID" && [ ! -s "$ARB/tmux/typed" ] \
    && t_ok "AR never: invalid_request is logged and the session left alone" \
    || t_fail "AR never: the session was stopped"
else
  t_fail "AR never: logged" "$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"
# An OLD rejection in a resumed transcript never fires: only records from this launch count.
ar_claude_pool
mkdir -p "$ARC/shared-projects/-fake-tui"
printf '{"type":"assistant","isApiErrorMessage":true,"error":"rate_limit","quotaLimits":{"status":"rejected","resetsAt":%s,"rateLimitType":"five_hour"},"timestamp":"2026-01-01T00:00:00.000Z","sessionId":"%s","message":{"content":[{"type":"text","text":"limit"}]}}\n' \
  "$(( $(date +%s) + 3600 ))" "$AR_SID" > "$ARC/shared-projects/-fake-tui/$AR_SID.jsonl"
ar_start FAKE_TUI=idle FAKE_TUI_QUIET=1 -- claude --dangerously-skip-permissions --resume "$AR_SID" "carry on please"
if ar_wait 15 grep -qs "transcript .*$AR_SID.jsonl" "$ARC/tmp/autoresume/$AR_PID.log"; then
  sleep 1.5
  ar_logged "$ARC" 'autoresume (detect|switch)' || ! ar_running "$AR_PID" \
    && t_fail "AR resumed transcript: an old rejection fired" "$(grep autoresume "$ARC/selection.log")" \
    || t_ok "AR resumed transcript: an old rejection does not fire"
else
  t_fail "AR resumed transcript: watcher followed the transcript" "$(cat "$ARC/tmp/autoresume/$AR_PID.log" 2>/dev/null)"
fi
ar_reap "$ARC"

# ---- AR8. claude: no account to move to -> HOLD, nothing is stopped ----------------------
ar_claude_pool
# acct-02 is out for the week (a weekly client marker outlives every telemetry pass).
printf '%s\nbucket=client:seven_day percent=100 marked_at=%s reason=client-rate-limit\n' \
  "$(( $(date +%s) + 86400 ))" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$ARC/acct-02/.limited"
ar_start FAKE_TUI=quota -- claude --dangerously-skip-permissions "fix the bug please"
if ar_wait 20 ar_logged "$ARC" 'autoresume hold provider=claude .*class=quota .*reason=no-room'; then
  sleep 1
  ar_running "$AR_PID" && [ ! -s "$ARB/tmux/typed" ] \
    && ! ls "$ARC/tmp/autoresume/" 2>/dev/null | grep -q '^r-' \
    && t_ok "AR hold: no eligible account -> hold, no kill, nothing typed" \
    || t_fail "AR hold: the session was stopped"
  grep -q 'CFG=acct-01' "$ARB/tui.log" && t_ok "AR hold: the first launch took the only eligible account" \
    || t_fail "AR hold: first pick" "$(cat "$ARB/tui.log")"
else
  t_fail "AR hold: logged" "$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"

# ---- AR9. claude: autoresume.off stops a RUNNING watcher ---------------------------------
ar_claude_pool
ar_start FAKE_TUI=quota FAKE_TUI_DELAY=2.5 -- claude --dangerously-skip-permissions "fix the bug please"
if ar_wait 15 ar_logged "$ARC" 'autoresume watch provider=claude'; then
  : > "$ARC/autoresume.off"
  ar_wait 5 ar_no_watcher "$ARC" && t_ok "AR off: the running watcher exits on autoresume.off" \
    || t_fail "AR off: the running watcher exits on autoresume.off"
  ar_wait 10 grep -qs '"rate_limit"' "$ARC/shared-projects/-fake-tui/$AR_SID.jsonl"
  sleep 1.2
  ar_running "$AR_PID" && [ ! -s "$ARB/tmux/typed" ] && ! ar_logged "$ARC" 'autoresume (detect|switch)' \
    && t_ok "AR off: the limit after the kill switch stops nothing" \
    || t_fail "AR off: the session was stopped"
else
  t_fail "AR off: watcher started" "$(grep autoresume "$ARC/selection.log" 2>/dev/null)"
fi
ar_reap "$ARC"

# ---- AR11. a relaunch re-entering through the token preflight keeps its chain -----------
# The relaunch left acct-01 on a MODEL limit (no marker: the chain's AVOID list is all that
# keeps the session off it). acct-02 leads on headroom but its portable token is revoked,
# so the preflight parks it and re-enters the shim with `exec "$SELF"` — the token is spent
# by then, so the chain rides along in the environment. Without it the re-entered selection
# takes acct-01 (the best weekly left) and the next watcher restarts at depth 0.
ar_claude_pool
printf '{"version": 1, "threshold": 90, "accounts": [%s, %s, %s]}\n' \
  '{"id": "acct-01", "email": "a@ar", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
  '{"id": "acct-02", "email": "b@ar", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
  '{"id": "acct-03", "email": "c@ar", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
  > "$ARC/accounts.json"
mkdir -p "$ARC/acct-03"
cp "$ARC/acct-01/.credentials.json" "$ARC/acct-03/.credentials.json"
ln -s "$ARC/shared-projects" "$ARC/acct-03/projects"
rm -f "$ARC/acct-02/.credentials.json"
printf 'sk-ant-oat01-REVOKED-carry\n' > "$ARC/acct-02/server.token"
nowc="$(date +%s)"
for i in 01:5 02:10 03:20; do
  printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":10,"max_percent":%s,"buckets":[]}' \
    "$nowc" "${i#*:}" "${i#*:}" > "$ARC/acct-${i%%:*}/limits.json"
done
mkdir -p "$ARC/tmp/autoresume"
tok=CarryTok0123456789
printf '%s\n' v=1 provider=claude class=model acct=acct-01 reset= rtype= marked= "sid=$AR_SID" \
  "cwd=$ARW" depth=2 "avoid=acct-01:$((nowc + 18000))" "hist=model:$((nowc - 100))" chain=CarryTst \
  > "$ARC/tmp/autoresume/r-$tok.relaunch"
printf '%s\0' --dangerously-skip-permissions --resume "$AR_SID" "(claude-multiacc auto-resume) carry on please" \
  > "$ARC/tmp/autoresume/r-$tok.argv"
out="$(cd "$ARH" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" FAKE_STUB_PY_LOG="$ARB/stub.log" \
  CLAUDE_MULTIACC_HEADROOM_BAND=0 CLAUDE_MULTIACC_AR="$tok" claude </dev/null 2>&1)"
check "AR carry: the re-entered selection still skips the account the chain left" \
  "CFG=acct-03 TOK=none ARGS=--dangerously-skip-permissions --resume $AR_SID (claude-multiacc auto-resume) carry on please" "$out"
ar_logged "$ARC" 'acct-02 parked \(setup-token-invalid\)' \
  && t_ok "AR carry: the revoked token was parked by the preflight (the re-entry happened)" \
  || t_fail "AR carry: preflight park" "$(cat "$ARC/selection.log")"
st="$(ls "$ARC/tmp/autoresume/"*.state 2>/dev/null | head -1)"
grep -q '^depth=2$' "$st" 2>/dev/null && grep -q '^chain=CarryTst$' "$st" \
  && grep -q "^avoid=acct-01:$((nowc + 18000))\$" "$st" && grep -q '^cwd=/.*/ar-work dir$' "$st" \
  && t_ok "AR carry: the next watcher inherits depth, chain, AVOID and the session's cwd" \
  || t_fail "AR carry: state file" "$(cat "$st" 2>/dev/null)"
[ "$(grep -c 'autoresume relaunch chain=CarryTst from=acct-01 class=model depth=2$' "$ARC/selection.log")" = 1 ] \
  && t_ok "AR carry: the relaunch is logged once, not again by the re-entry" \
  || t_fail "AR carry: relaunch log" "$(grep autoresume "$ARC/selection.log")"
ar_reap "$ARC"

# ---- AR12. claude relaunch tokens: the auth park, dead tokens, the trust mirror ------------
# Planted directly (no watcher, no TUI), so each assertion can only come from the relaunch
# entry itself. acct-01 leads on headroom and HEADROOM_BAND=0 makes the lead decisive.
ar_claude_pool
nowc="$(date +%s)"
for i in 01:5 02:20; do
  printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":10,"max_percent":%s,"buckets":[]}' \
    "$nowc" "${i#*:}" "${i#*:}" > "$ARC/acct-${i%%:*}/limits.json"
done
# class=auth: no auth record in any transcript, so only the relaunch can park acct-01.
ar_plant "$ARC" AuthTok0123456789 claude auth acct-01 -- \
  --dangerously-skip-permissions --resume "$AR_SID" "(claude-multiacc auto-resume) carry on please"
out="$(cd "$ARH" && env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" CLAUDE_MULTIACC_HEADROOM_BAND=0 \
  CLAUDE_MULTIACC_AR="AuthTok0123456789:$AR_SID" claude </dev/null 2>&1)"
[ -f "$ARC/acct-01/.expired" ] && ar_logged "$ARC" 'acct-01 parked \(' \
  && t_ok "AR auth token: the relaunch parks the account it left (.expired)" \
  || t_fail "AR auth token: park" "$(ls -a "$ARC/acct-01" | tr '\n' ' ')"
check "AR auth token: ...and the run lands on the other account, resuming the session" \
  "CFG=acct-02 TOK=none ARGS=--dangerously-skip-permissions --resume $AR_SID (claude-multiacc auto-resume) carry on please" "$out"
# Dead tokens: missing, expired (older than 10 min), malformed, a FIFO in its place.
ar_dead claude "a missing relaunch file" "claude-multiacc: $AR_DEAD_MSG Resume with: claude --resume $AR_SID" \
  CLAUDE_MULTIACC_AR="MissingTok0123456:$AR_SID"
ar_plant "$ARC" ExpiredTok0123456 claude quota acct-01 -- --resume "$AR_SID" "(claude-multiacc auto-resume) x y"
touch -t 202601010000 "$ARC/tmp/autoresume/r-ExpiredTok0123456.relaunch"
ar_dead claude "an expired relaunch file" "claude-multiacc: $AR_DEAD_MSG Resume with: claude --resume $AR_SID" \
  CLAUDE_MULTIACC_AR="ExpiredTok0123456:$AR_SID"
ls "$ARC/tmp/autoresume/" 2>/dev/null | grep -q '^r-ExpiredTok' \
  && t_fail "AR dead token (claude): an expired token is consumed" "$(ls "$ARC/tmp/autoresume/")" \
  || t_ok "AR dead token (claude): an expired token is consumed"
ar_dead claude "a malformed token" "claude-multiacc: $AR_DEAD_MSG Resume with: claude --resume $AR_SID" \
  CLAUDE_MULTIACC_AR="../bad/tok:$AR_SID"
ar_dead claude "an unusable session id (no hint)" "claude-multiacc: $AR_DEAD_MSG" \
  CLAUDE_MULTIACC_AR='MissingTok0123456:$(id)'
mkfifo "$ARC/tmp/autoresume/r-FifoTok0123456789.relaunch"
( cd "$ARH" && exec env "${AREC[@]}" CLAUDE_MULTIACC_PYTHON="$ARB/stub-python" \
  CLAUDE_MULTIACC_AR="FifoTok0123456789:$AR_SID" claude ) </dev/null > "$ARB/fifo.out" 2>&1 &
fp=$!
if ar_wait 10 ar_stopped "$fp"; then
  wait "$fp"; rc=$?
  [ "$rc" = 2 ] && ! grep -q 'CFG=' "$ARB/fifo.out" \
    && t_ok "AR dead token (claude): a FIFO named like a relaunch file never blocks the launch" \
    || t_fail "AR dead token (claude): FIFO" "rc=$rc $(cat "$ARB/fifo.out")"
else
  kill -KILL "$fp" 2>/dev/null; wait "$fp" 2>/dev/null
  t_fail "AR dead token (claude): a FIFO named like a relaunch file blocked the launch"
fi
rm -f "$ARC/tmp/autoresume/r-FifoTok0123456789.relaunch"
# Trust: the relaunch marks its cwd trusted in the PICKED account's .claude.json (Claude
# shows a blocking trust dialog in a new directory even with --dangerously-skip-permissions),
# keeping every other key. The real python runs it; TMUX= keeps the watcher out of the way.
# The key is the directory as the relaunch's own `cd` spells it, plus its physical path
# when that differs (Claude may key projects by either; macOS TMPDIR is a symlink).
ar_claude_pool
nowc="$(date +%s)"
arw_key="$(cd "$ARW" && pwd)"
for i in 01:20 02:5; do
  printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":10,"max_percent":%s,"buckets":[]}' \
    "$nowc" "${i#*:}" "${i#*:}" > "$ARC/acct-${i%%:*}/limits.json"
done
printf '{"numStartups": 7, "projects": {"%s": {"allowedTools": ["Bash"]}, "/elsewhere": {"hasTrustDialogAccepted": false}}}\n' \
  "$arw_key" > "$ARC/acct-02/.claude.json"
chmod 600 "$ARC/acct-02/.claude.json"
printf '{"numStartups": 1}\n' > "$ARC/acct-01/.claude.json"
cp "$ARC/acct-01/.claude.json" "$ARB/acct-01.claude.json"
ar_plant "$ARC" TrustTok0123456789 claude crash acct-01 -- \
  --dangerously-skip-permissions --resume "$AR_SID" "(claude-multiacc auto-resume) carry on please"
out="$(cd "$ARH" && env "${AREC[@]}" TMUX= CLAUDE_MULTIACC_HEADROOM_BAND=0 \
  CLAUDE_MULTIACC_AR="TrustTok0123456789:$AR_SID" claude </dev/null 2>&1)"
check "AR trust: the relaunch ran on the picked account" "CFG=acct-02 " "$out"
if python3 - "$ARC/acct-02/.claude.json" "$arw_key" <<'PYEOF'
import json, os, stat, sys
path, cwd = sys.argv[1], sys.argv[2]
d = json.load(open(path))
p = d["projects"]
real = os.path.realpath(cwd)
ok = (p[cwd] == {"allowedTools": ["Bash"], "hasTrustDialogAccepted": True}
      and (real == cwd or p.get(real) == {"hasTrustDialogAccepted": True})
      and len(p) == (2 if real == cwd else 3) and d.get("numStartups") == 7
      and p["/elsewhere"] == {"hasTrustDialogAccepted": False}
      and stat.S_IMODE(os.stat(path).st_mode) == 0o600)
sys.exit(0 if ok else 1)
PYEOF
then
  t_ok "AR trust: projects[cwd].hasTrustDialogAccepted=true, every other key and the file mode kept"
else
  t_fail "AR trust: .claude.json after the relaunch" "$(cat "$ARC/acct-02/.claude.json")"
fi
cmp -s "$ARC/acct-01/.claude.json" "$ARB/acct-01.claude.json" \
  && t_ok "AR trust: the account the session left is not touched" \
  || t_fail "AR trust: the left account's .claude.json changed" "$(cat "$ARC/acct-01/.claude.json")"
# A plain launch (no token) never edits trust.
printf '{"numStartups": 7}\n' > "$ARC/acct-02/.claude.json"
cp "$ARC/acct-02/.claude.json" "$ARB/acct-02.claude.json"
(cd "$ARW" && env "${AREC[@]}" TMUX= claude --dangerously-skip-permissions </dev/null >/dev/null 2>&1)
cmp -s "$ARC/acct-01/.claude.json" "$ARB/acct-01.claude.json" \
  && cmp -s "$ARC/acct-02/.claude.json" "$ARB/acct-02.claude.json" \
  && t_ok "AR trust: a launch that is not a relaunch never edits .claude.json" \
  || t_fail "AR trust: a plain launch edited .claude.json" "$(cat "$ARC"/acct-0*/.claude.json)"
ar_reap "$ARC"

# ---- AR10. codex: the same machinery through bin/codex ------------------------------------
ARX="$WORK/ar-codex"
ar_codex_pool() { # a fresh two-account codex pool sharing one sessions tree (the installed layout)
  local i
  rm -rf "$ARX" "$ARB/tmux" "$ARB/pids" "$ARB/tui.log" "$ARB/stub.log"
  mkdir -p "$ARX/tmp" "$ARX/shared-sessions" "$ARB/tmux"
  printf '{"version": 1, "threshold": 90, "accounts": [%s, %s]}\n' \
    '{"id": "acct-01", "email": "a@arx", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
    '{"id": "acct-02", "email": "b@arx", "home": "mac", "added_at": "2026-09-23T00:00:00Z"}' \
    > "$ARX/accounts.json"
  for i in 01 02; do
    mkdir -p "$ARX/acct-$i"
    mk_cx_auth "$ARX/acct-$i/auth.json" "$i@arx" "$FUTURE_EXP"
    printf '{"fetched_at":%s,"weekly_percent":20,"session_percent":10,"max_percent":20,"buckets":[]}' "$(date +%s)" \
      > "$ARX/acct-$i/limits.json"
    ln -s "$ARX/shared-sessions" "$ARX/acct-$i/sessions"
  done
  : > "$ARX/.limits-kick"
}
AREX=(CODEX_ACCOUNTS_DIR="$ARX" HOME="$ARH" TMUX="$ARB/tmux-sock,4243,0" TMUX_PANE=%2
  CODEX_MULTIACC_AUTORESUME=1 CODEX_MULTIACC_PYTHON="$ARPY" CODEX_MULTIACC_AR_TEST_TTY=1
  CODEX_MULTIACC_AR_TEST_TMUX_ANYPANE=1 CODEX_MULTIACC_AR_POLL=0.1 CODEX_MULTIACC_AR_GRACE=0.5
  CODEX_MULTIACC_AR_TERM_GRACE=3 CODEX_MULTIACC_AR_PANE_WAIT=5 CODEX_MULTIACC_AR_PROBE_TIMEOUT=15
  CODEX_MULTIACC_AR_DISCOVER_TIMEOUT=20 CODEX_MULTIACC_AUTORESUME_DEBUG=1
  FAKE_TMUX_DIR="$ARB/tmux" FAKE_TUI_LOG="$ARB/tui.log" FAKE_TUI_PIDS="$ARB/pids")
ar_codex_pool
cx_gate() { # cx_gate <name> <watcher|none> [VAR=val ...] -- <codex args...>
  local name="$1" want="$2" pre=() out states
  shift 2
  while [ $# -gt 0 ] && [ "$1" != "--" ]; do pre+=("$1"); shift; done
  [ $# -gt 0 ] && shift
  rm -rf "$ARX/tmp/autoresume" "$ARB/stub.log"
  out="$(cd "$ARW" && env "${AREX[@]}" CODEX_MULTIACC_PYTHON="$ARB/stub-python" \
    FAKE_STUB_PY_LOG="$ARB/stub.log" ${pre[@]+"${pre[@]}"} codex "$@" </dev/null 2>&1)"
  states="$(ls "$ARX/tmp/autoresume/" 2>/dev/null | grep -c '\.state$')"
  case "$out" in *CFG=acct-0*) ;; *) t_fail "codex auto-resume gate: $name execs" "$out"; return ;; esac
  if [ "$want" = watcher ]; then
    [ "$states" = 1 ] && ar_wait 5 grep -qs -- "-I .*lib/autoresume.py watch --state $ARX/tmp/autoresume/[0-9]*\.state" "$ARB/stub.log" \
      && t_ok "codex auto-resume gate: $name gets a watcher" \
      || t_fail "codex auto-resume gate: $name gets a watcher" "states=$states"
  else
    [ "$states" = 0 ] && [ ! -s "$ARB/stub.log" ] \
      && t_ok "codex auto-resume gate: $name gets no watcher" \
      || t_fail "codex auto-resume gate: $name gets no watcher" "states=$states"
  fi
}
cx_gate "a prompt with the bypass flag" watcher -- --dangerously-bypass-approvals-and-sandbox "fix the bug please"
cx_gate "resume <uuid>" watcher -- resume "$AR_CXSID"
cx_gate "exec" none -- exec "do it now"
cx_gate "-p (profile)" none -- -p work
cx_gate "-c overrides" none -- -c model=o3
cx_gate "a pinned run" none CODEX_ACCOUNT=acct-01 --
cx_gate "an invalid pin (random fallback)" none CODEX_ACCOUNT=acct-99 --
cx_gate "outside tmux" none TMUX_PANE= --
cx_gate "CODEX_MULTIACC_AUTORESUME=off" none CODEX_MULTIACC_AUTORESUME=off --
ln -s "$ARX" "$WORK/ar codex root"
cx_gate "a pool root that would need quoting" none CODEX_ACCOUNTS_DIR="$WORK/ar codex root" -- --yolo
# The client never sees an auto-resume variable (AREX itself exports several).
rm -rf "$ARX/tmp/autoresume"
out="$(cd "$ARW" && env "${AREX[@]}" CODEX_MULTIACC_PYTHON="$ARB/stub-python" FAKE_PRINT_ENV=1 \
  codex --yolo </dev/null 2>&1)"
case "$out" in
  *"AR_ENV=0"*) [ -n "$(ls "$ARX/tmp/autoresume/" 2>/dev/null | grep '\.state$')" ] \
      && t_ok "codex auto-resume: the client never sees an auto-resume variable (watcher spawned)" \
      || t_fail "codex auto-resume: env scrub case spawned no watcher" "$out" ;;
  *) t_fail "codex auto-resume: the client never sees an auto-resume variable" "$out" ;;
esac
out="$(cd "$ARW" && env "${AREX[@]}" CODEX_MULTIACC_AR_PROBE=1 codex --yolo </dev/null 2>&1)"; rc=$?
case "$rc:$out" in 0:pick=acct-0[12]" tier=eligible") t_ok "codex probe prints pick/tier, never execs" ;;
  *) t_fail "codex probe" "rc=$rc out=$out" ;; esac
all1=1
for _ in 1 2 3 4 5; do
  out="$(cd "$ARW" && env "${AREX[@]}" CODEX_MULTIACC_AR_PROBE=1 \
    CODEX_MULTIACC_AR_AVOID="acct-02:$(( $(date +%s) + 3600 ))" codex --yolo </dev/null 2>&1)"
  [ "$out" = "pick=acct-01 tier=eligible" ] || all1=0
done
[ "$all1" = 1 ] && t_ok "codex probe honours AVOID (5 of 5)" || t_fail "codex probe AVOID" "$out"
# codex relaunch tokens, planted directly: acct-01 leads, so only the relaunch's own park
# keeps the run off it (the shared sessions tree turns the rollout scan off).
nowx="$(date +%s)"
for i in 01:5 02:20; do
  printf '{"fetched_at":%s,"weekly_percent":%s,"session_percent":10,"max_percent":%s,"buckets":[]}' \
    "$nowx" "${i#*:}" "${i#*:}" > "$ARX/acct-${i%%:*}/limits.json"
done
rm -f "$ARX/.last-pick"
ar_plant "$ARX" CxAuthTok01234567 codex auth acct-01 -- \
  resume --yolo "$AR_CXSID" "(claude-multiacc auto-resume) carry on please"
out="$(cd "$ARH" && env "${AREX[@]}" CODEX_MULTIACC_PYTHON="$ARB/stub-python" CODEX_MULTIACC_HEADROOM_BAND=0 \
  CODEX_MULTIACC_AR="CxAuthTok01234567:$AR_CXSID" codex </dev/null 2>&1)"
grep -q 'reason=auth-error soft_until=' "$ARX/acct-01/.expired" 2>/dev/null \
  && t_ok "AR codex auth token: the relaunch parks the account it left (auth-error, soft)" \
  || t_fail "AR codex auth token: park" "$(cat "$ARX/acct-01/.expired" 2>/dev/null)"
check "AR codex auth token: ...and the run lands on the other account" "CFG=acct-02" "$out"
ar_dead codex "a missing relaunch file" "codex-multiacc: $AR_DEAD_MSG Resume with: codex resume $AR_CXSID" \
  CODEX_MULTIACC_AR="MissingTok0123456:$AR_CXSID"
ar_plant "$ARX" ExpiredTok0123456 codex quota acct-01 -- resume "$AR_CXSID" "(claude-multiacc auto-resume) x y"
touch -t 202601010000 "$ARX/tmp/autoresume/r-ExpiredTok0123456.relaunch"
ar_dead codex "an expired relaunch file" "codex-multiacc: $AR_DEAD_MSG Resume with: codex resume $AR_CXSID" \
  CODEX_MULTIACC_AR="ExpiredTok0123456:$AR_CXSID"
ls "$ARX/tmp/autoresume/" 2>/dev/null | grep -q '^r-ExpiredTok' \
  && t_fail "AR dead token (codex): an expired token is consumed" "$(ls "$ARX/tmp/autoresume/")" \
  || t_ok "AR dead token (codex): an expired token is consumed"
ar_dead codex "a malformed token" "codex-multiacc: $AR_DEAD_MSG Resume with: codex resume $AR_CXSID" \
  CODEX_MULTIACC_AR="../bad/tok:$AR_CXSID"
ar_dead codex "an unusable session id (no hint)" "codex-multiacc: $AR_DEAD_MSG" \
  CODEX_MULTIACC_AR='MissingTok0123456:$(id)'
# No valid login anywhere: a launch would fall back to the stock client — a probe must not.
ar_codex_pool
rm -f "$ARX"/acct-0*/auth.json
out="$(cd "$ARW" && env "${AREX[@]}" CODEX_MULTIACC_AR_PROBE=1 codex --yolo </dev/null 2>&1)"; rc=$?
[ "$rc:$out" = "3:pick= tier=none" ] && t_ok "codex probe on a pool with no valid login answers tier=none (exit 3), never execs" \
  || t_fail "codex probe with no valid login" "rc=$rc out=$out"

ar_codex_pool
AREC=("${AREX[@]}")   # ar_start launches with AREC
ar_start FAKE_TUI=quota -- codex --dangerously-bypass-approvals-and-sandbox "fix the bug please"
first=$AR_PID
if ar_wait 30 ar_lines 2 "$ARB/tui.log"; then
  l1="$(sed -n 1p "$ARB/tui.log")"; l2="$(sed -n 2p "$ARB/tui.log")"
  from="$(ar_acct_of "$l1")"; to="$(ar_acct_of "$l2")"
  [ -n "$from" ] && [ -n "$to" ] && [ "$from" != "$to" ] \
    && t_ok "AR codex quota: relaunched on the OTHER account ($from -> $to)" \
    || t_fail "AR codex quota: relaunched on the other account" "$l1 | $l2"
  check "AR codex quota: \`resume <opts> <sid> <prompt>\`" \
    "ARGS=resume --dangerously-bypass-approvals-and-sandbox $AR_CXSID (claude-multiacc auto-resume) This session was restarted automatically on another account because the previous account hit its usage limit." "$l2"
  ar_wait 5 ar_stopped "$first" && t_ok "AR codex quota: the stuck client was stopped" \
    || t_fail "AR codex quota: the stuck client was stopped" "pid $first alive"
  m1="$(sed -n 1p "$ARX/$from/.limited" 2>/dev/null)"; m2="$(sed -n 2p "$ARX/$from/.limited" 2>/dev/null)"
  nowx="$(date +%s)"
  case "$m1" in ''|*[!0-9]*) m1=0 ;; esac
  [ "$m1" -gt "$((nowx + 500))" ] && [ "$m1" -le "$((nowx + 600))" ] \
    && case "$m2" in "bucket=error-cooldown percent=? marked_at="*" reason=error-cooldown") true ;; *) false ;; esac \
    && t_ok "AR codex quota: the old account gets the 10-minute error-cooldown, never client:7d" \
    || t_fail "AR codex quota: cooldown marker" "$m1 / $m2"
  ar_logged "$ARX" "autoresume relaunch chain=[A-Za-z0-9]+ from=$from class=quota depth=1\$" \
    && ar_logged "$ARX" "autoresume switch provider=codex chain=[A-Za-z0-9]+ from=$from class=quota sid=$AR_CXSID depth=1 probe=$to" \
    && t_ok "AR codex quota: switch + relaunch logged" \
    || t_fail "AR codex quota: log lines" "$(grep autoresume "$ARX/selection.log")"
  ar_typed_ok CODEX "$AR_CXSID" "CODEX_ACCOUNTS_ROOT=$(cd "$ARX" && pwd)" "$REPO_DIR/bin/codex" \
    && grep -q -- "send-keys -R -t %2" "$ARB/tmux/calls" \
    && t_ok "AR codex quota: terminal reset, then the token line typed" \
    || t_fail "AR codex quota: typed line" "$(cat "$ARB/tmux/typed" 2>/dev/null)"
  ar_wait 10 ar_logged "$ARX" "autoresume watch provider=codex chain=[A-Za-z0-9]+ pid=[0-9]+ acct=$to depth=1\$" \
    && t_ok "AR codex quota: the resumed session is supervised again" \
    || t_fail "AR codex quota: second watcher" "$(grep autoresume "$ARX/selection.log")"
else
  t_fail "AR codex quota: relaunched within 30 s" "tui=$(cat "$ARB/tui.log" 2>/dev/null) log=$(grep autoresume "$ARX/selection.log" 2>/dev/null)"
fi
ar_reap "$ARX"
ar_no_watcher "$ARX" && t_ok "AR codex: no watcher left running" || t_fail "AR codex: watcher left running"

# The reset-credit contract is easier to prove against a stateful local HTTP server
# than file:// fixtures: it pins thresholding, credit ordering and idempotent POST retry.
if CODEX_MULTIACC_AUTO_RESET=1 python3 -m unittest discover -s "$REPO_DIR/tests" -p 'test_codex_reset*.py'; then
  t_ok "codex: automatic earned-reset integration suite"
else
  t_fail "codex automatic reset suite" "see unittest output above"
fi
# ...and its claude twin: the cedar_ember status rides on the usage response, the claim
# is idempotent across the fleet, and a confirmed reset lifts even a weekly client park.
# The claude half of the MCP registry must run on STOCK macOS python (3.9): the shim
# reconciles with whatever `python3` is on PATH, and a runner Mac's is /usr/bin/python3.
# Skipped silently where that interpreter is absent or already 3.11+ (CI is ubuntu).
if [ -x /usr/bin/python3 ] && /usr/bin/python3 -c 'import sys; sys.exit(0 if sys.version_info < (3, 11) else 1)' 2>/dev/null; then
  if /usr/bin/python3 "$REPO_DIR/tests/test_mcp_registry.py" >/dev/null 2>&1; then
    t_ok "MCP registry unit suite on stock python $(/usr/bin/python3 -c 'import sys;print("%d.%d"%sys.version_info[:2])')"
  else
    t_fail "MCP registry unit suite on stock python" "/usr/bin/python3 tests/test_mcp_registry.py failed"
  fi
fi
if CLAUDE_MULTIACC_AUTO_RESET=1 python3 -m unittest discover -s "$REPO_DIR/tests" -p 'test_claude_reset*.py'; then
  t_ok "claude: automatic limit-reset integration suite"
else
  t_fail "claude automatic reset suite" "see unittest output above"
fi
# ...and the auto-resume watcher, unit by unit: classifiers, argv sanitizer, relaunch
# files, budgets, tmux commands and a fake-runner walk through every stop/relaunch branch.
if python3 -m unittest discover -s "$REPO_DIR/tests" -p 'test_autoresume.py'; then
  t_ok "auto-resume watcher unit suite"
else
  t_fail "auto-resume watcher unit suite" "see unittest output above"
fi

# ---- summary ---------------------------------------------------------------------
echo
echo "passed: $PASS  failed: $FAIL"
[ "$FAIL" = "0" ] || exit 1
