Skip to content

feat(safety): Tier 1 real-money safety rails#16

Merged
Multipixelone merged 1 commit into
mainfrom
claude/refine-local-plan-qx648a
Jun 21, 2026
Merged

feat(safety): Tier 1 real-money safety rails#16
Multipixelone merged 1 commit into
mainfrom
claude/refine-local-plan-qx648a

Conversation

@Multipixelone

Copy link
Copy Markdown
Owner

Summary

PR 1 of a two-PR plan, hardening the real-money buy flow. This is Tier 1 (safety & correctness); Tiers 2 & 3 (debugging aids + operational features) follow once this merges.

All four changes are conservative and preserve the existing never-double-order invariants.

1.1 Hard cart-contents guard before Place Order ⚠️ real money

Costco's cart is server-side and shared across every profile launch, and a live Place Order checks out the whole cart. _reset_cart is best-effort and silent on failure, so a stale line it can't drain could ride along into a real order. A new base hook _verify_cart_singleton (no-op default; only Costco enforces it) verifies the review page holds only the intended item before placing, using two signals:

  • cart-line count on the review page (CART_LINE_SELECTORS, unverified — backstopped below), and
  • order-total band: review_total <= price × qty × 1.30 + $15 (reuses the live-verified review total).

It runs before submitted=True (and on dry-run, so dry-run exercises it). A mismatch — or an unverifiable cart (both signals unreadable) — aborts to needs_review with a cart_mismatch screenshot. Fail-closed by design (operator-confirmed): a selector drift causes a safe pause, never a wrong order. Only aborts on totals over band, so a checkout discount never trips it.

1.2 Tighten false-positive block/challenge detection

_is_blocked now keys on the 403/429 HTTP status as the primary, drift-proof signal, and requires the Akamai deny-page body markers ("access denied" and "reference #") to co-occur — so a benign page mentioning just one (an order's "Reference #", a help article naming Akamai) no longer false-blocks and needlessly pauses the worker.

1.3 Configurable Costco storeId / catalogId

ROOMIEORDER_COSTCO_STORE_ID / ROOMIEORDER_COSTCO_CATALOG_ID (defaults 10301/10701) thread into the silent SSO re-auth URL, replacing the hardcoded ids that broke a different warehouse/region.

1.4 Bounded auto-retry for pre-cart transient failures (opt-in)

A retryable flag on PurchaseResult, set only for failures strictly before any cart interaction (PDP-load timeout, a one-off no_price) and never once the cart is touched or an order submitted. Gated behind ROOMIEORDER_AUTO_RETRY (off by default): the worker re-enqueues such failures up to ROOMIEORDER_AUTO_RETRY_MAX instead of pausing. store.py's MAX_ATTEMPTS=1 never-re-claim invariant is left untouched — the retry lives entirely in the worker.

Tests

nix develop -c pytest -q-equivalent, ruff, and mypy src all green. New offline coverage:

  • cart guard: in-band single line passes; extra line / over-band aborts; fail-closed when unverifiable; band scales with qty; Amazon base hook is a no-op
  • block detection: 403/429 → blocked; lone marker → not blocked; co-occurrence → blocked
  • worker auto-retry: re-enqueues bounded; off by default; skips non-retryable
  • new config vars parse with defaults

Not in this PR (Tier 2 & 3, follow-up)

Correlation logging, full-page failure screenshots, doctor --check-login, shots pruning, verify-order, proactive session-freshness notify, healthcheck heartbeat, and doc fixes (incl. documenting the new cart_mismatch tag and CART_LINE_SELECTORS as a to-verify selector).

⚠️ Per AGENTS.md §1, green CI does not prove the Playwright path works. The cart-guard CART_LINE_SELECTORS are unverified guesses; the order-total band is the reliable backstop. Live bring-up (dump-dom to confirm the line selectors, dry-run clean vs. stale-line cart) is required before relying on the line-count signal.

🤖 Generated with Claude Code


Generated by Claude Code

Harden the money-moving buy flow with four safety/correctness changes:

- Hard cart-contents guard before Place Order: verify the review page holds
  only the intended item+qty (cart-line count + order-total band) before
  placing. Fails closed — an unverifiable cart aborts to needs_review rather
  than risk checking out a stale line left by a best-effort _reset_cart. Runs
  on dry-run too, so `dry-run` exercises it. Base hook is a no-op; only Costco
  (shared server-side cart) enforces it.
- Tighten Akamai block detection: key on the 403/429 HTTP status as the primary
  signal and require the deny-page body markers ("access denied" + "reference #")
  to co-occur, so a benign page mentioning one no longer false-blocks and pauses
  the worker.
- Configurable Costco storeId/catalogId (ROOMIEORDER_COSTCO_STORE_ID /
  _CATALOG_ID) threaded into the silent SSO re-auth URL, replacing hardcoded ids.
- Opt-in bounded auto-retry (ROOMIEORDER_AUTO_RETRY) for money-safe pre-cart
  transient failures (PDP-load timeout, one-off no_price). A `retryable` flag is
  set only before any cart interaction; the worker re-enqueues up to a bound
  instead of pausing. store.py MAX_ATTEMPTS=1 invariant is untouched.

Tests cover the cart guard (band, extra line, fail-closed, qty scaling, Amazon
no-op), block co-occurrence + status, the worker auto-retry bound, and the new
config vars.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J322vufhqKDvdJmukTZdkq
@Multipixelone Multipixelone enabled auto-merge June 21, 2026 21:35
@Multipixelone Multipixelone merged commit 5044f5b into main Jun 21, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants