From 777c31d46488c4410a19db4787087a420806c763 Mon Sep 17 00:00:00 2001 From: Zoid Date: Wed, 24 Jun 2026 21:39:39 -0400 Subject: [PATCH 1/3] chore: archive v4.0 Win-the-Drop milestone All 7 phases (18-24) shipped, audited (status tech_debt, no blockers; 17/17 reqs, 755 tests passing). Archive ROADMAP/REQUIREMENTS/AUDIT to milestones/; collapse live ROADMAP to per-milestone summaries (drops stale Phase Details that desynced roadmap.analyze); evolve PROJECT.md (v4.0 reqs validated, next-milestone candidates); add RETROSPECTIVE.md; reconcile STATE.md (phase table, metrics, 17 deferred live-UAT items). --- .planning/MILESTONES.md | 22 + .planning/PROJECT.md | 69 ++- .planning/RETROSPECTIVE.md | 60 +++ .planning/ROADMAP.md | 395 ++-------------- .planning/STATE.md | 61 ++- .../{ => milestones}/v4.0-MILESTONE-AUDIT.md | 0 .planning/milestones/v4.0-REQUIREMENTS.md | 92 ++++ .planning/milestones/v4.0-ROADMAP.md | 427 ++++++++++++++++++ 8 files changed, 719 insertions(+), 407 deletions(-) create mode 100644 .planning/RETROSPECTIVE.md rename .planning/{ => milestones}/v4.0-MILESTONE-AUDIT.md (100%) create mode 100644 .planning/milestones/v4.0-REQUIREMENTS.md create mode 100644 .planning/milestones/v4.0-ROADMAP.md diff --git a/.planning/MILESTONES.md b/.planning/MILESTONES.md index 683cdd0..a5f414d 100644 --- a/.planning/MILESTONES.md +++ b/.planning/MILESTONES.md @@ -1,5 +1,27 @@ # Milestones +## v4.0 Win-the-Drop (Shipped: 2026-06-25) + +**Phases completed:** 7 phases, 29 plans + +**Delivered:** ShopPyBot now completes *verified* orders on limited-release drops and survives multi-hour unattended runs without one fault taking down the rest. + +**Key accomplishments:** + +- **Safety gate (P18):** Central monitor-only mode + concrete `place_order_guarded()` on the `RetailerPlugin` ABC routes all 7 bundled plugins' place-order clicks through one guard, closing the confirmed 6-of-7 `test_mode` hole (CI grep + zero-write integration test). `CheckoutConfig` schema foundation for downstream phases. +- **Verified checkout (P19):** URL-first order-confirmation detector (`core/confirmation.py`) plus idempotent `order_id`/`confirmed_at`/`checkout_attempts` columns — `purchased` is written only on a real order number, never a button click. +- **Checkout profile + form-fill (P20):** 9-key CredentialStore shipping/billing profile, BestBuy + Amazon form-fill, CVV via `getpass` at runtime only, AST CI assertion proving no CVV leaks to logs; no full card data persisted. +- **Bounded retry (P21):** Single `RetryPolicy` in `core/retry.py` shared by supervisor restart and cart-retry; per-step `asyncio.timeout()` per DOM stage; DB idempotency re-read before each attempt (no double-buy). +- **Supervisor + relaunch (P22):** Per-coroutine supervision with failure budget absorbs crashes before the TaskGroup boundary; full browser relaunch (teardown→stealth→proxy→login); `sqlite3.OperationalError` read isolation; per-item timeout; cross-platform SIGTERM/SIGINT teardown bridge. +- **Encrypted sessions (P23):** Fernet-encrypted per-platform cookie persistence (`core/session_store.py`) via raw CDP restore that bypasses the nodriver `set_all()` bug; skips re-login/MFA across restarts, no plaintext on disk. +- **Health surface + server safety (P24):** `HealthRegistry`, expanded `BotService.get_status()` (per-plugin liveness/heartbeat), `health_degraded` fan-out alert, `shoppybot status` CLI, headless pygame import-crash guard. + +**Audit:** `.planning/milestones/v4.0-MILESTONE-AUDIT.md` — 17/17 requirements, 7/7 phases verified, 6/6 integration seams clean, suite 755 passed / 2 skipped. Status `tech_debt` (no blockers). + +**Known deferred items at close: 17** (see STATE.md → Deferred Items) — 7 live-environment UAT scenarios + 7 `human_needed` verifications (deferred per autonomous live-UAT policy), 1 todo (Amazon WAF auto-solve), 2 dormant seeds (SEED-001 repo scrub, SEED-002 release-please) — all explicitly Out of Scope for v4.0. + +--- + ## v3.0 v3.0 (Shipped: 2026-06-10) **Phases completed:** 6 phases, 21 plans, 32 tasks diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md index 2168030..09154d3 100644 --- a/.planning/PROJECT.md +++ b/.planning/PROJECT.md @@ -16,26 +16,38 @@ Target user: technically capable individuals who want automated stock monitoring ## Current State -**Shipped v3.0 Resilience + Ecosystem (2026-06-10).** Built on the v2.0 modular core (`BotService` API behind a CLI-default front-end plus an optional FastAPI web UI; runtime-selected `CredentialStore` with no plaintext on disk). v3.0 added anti-detection (JS stealth + proxy rotation with ban detection; opt-in 2captcha reCAPTCHA-v2 solving with balance check and spend cap), the plugin ecosystem (ABC `difficulty`/`requires_proxy`/`requires_captcha` attrs, `shoppybot plugins list`, a GitHub-wiki registry spec, contributor docs), and price monitoring (per-item target price, price history table, price-drop fan-out alerts, `items price-history` CLI). +**Shipped v4.0 Win-the-Drop — Acquisition Core + Reliability (2026-06-25).** Built on the v3.0 resilience/ecosystem layer and the v2.0 modular core (`BotService` API behind a CLI-default front-end plus an optional FastAPI web UI; runtime-selected `CredentialStore` with no plaintext on disk). v4.0 makes the bot complete *verified* orders on limited-release drops and survive multi-hour unattended runs: a central monitor-only gate + `place_order_guarded()` ABC closing the 6-of-7 `test_mode` hole; order-confirmation detection (`purchased` only on a real order number); checkout profile + BestBuy/Amazon form-fill with CVV-at-runtime; one unified `RetryPolicy` with per-step timeouts and idempotent cart-retry; per-coroutine supervisor with browser relaunch, DB read isolation, per-item timeout, and a SIGTERM/SIGINT teardown bridge; Fernet-encrypted session persistence; and a per-plugin health surface (`get_status`, `health_degraded` alert, `shoppybot status`) plus a headless pygame import-crash guard. -v3.0: 6 phases (12-17) / 21 plans, all complete. Full suite: 548 passed, 2 skipped. +v4.0: 7 phases (18-24) / 29 plans, all complete. Full suite: 755 passed, 2 skipped. Audit status `tech_debt` (no blockers; pre-accepted live-UAT debt). -**Deferred (carried):** v2.0 live cross-OS/UI manual checks (keyring restart persistence, masked-TTY setup, web dashboard live render, 0.0.0.0 warning) tracked in STATE.md → Deferred Items; Amazon WAF CAPTCHA auto-solve deferred (degrades to manual pause). +**Deferred (carried):** all live-environment UAT (monitor-only/confirmation/form-fill/relaunch/SIGTERM/session/headless) tracked in STATE.md → Deferred Items as the operator's pre-production live-buy checklist; Amazon WAF CAPTCHA auto-solve (manual-pause fallback); public-release hardening — git-history scrub/squash (SEED-001) + release-please tagging (SEED-002). -**Key constraints (held):** secrets never in config.yml/logs/SQLite plaintext; GUI optional, CLI default; the credential-managing web UI binds to localhost by default. +**Key constraints (held):** secrets never in config.yml/logs/SQLite plaintext; full card number / CVV never persisted to disk or logs (retailer-saved payment + CVV-at-runtime only); GUI optional, CLI default; the credential-managing web UI binds to localhost by default. -## Current Milestone: v4.0 Win-the-Drop (Acquisition Core + Reliability) +## Next Milestone + +**No active milestone.** v4.0 Win-the-Drop shipped 2026-06-25. Start the next cycle with `/gsd:new-milestone` (questioning → research → requirements → roadmap). Phase numbering continues from 24. + +Candidate directions from the v4.0 deferral list: +- **Public-release hardening** — git-history scrub/squash (SEED-001) + release-please version tagging (SEED-002); a dedicated release milestone. +- **Checkout form-fill for the remaining 5 retailers** (v4.0 covers BestBuy + Amazon). +- **Request/API-mode (hybrid) checkout** — faster than DOM but per-site reverse-engineering and an arms race. +- **Outcome analytics** (success rate, time-to-checkout) built on the BUY-04 order records. +- **Richer health/observability on the web dashboard** (beyond the CLI/status payload). + +
+Shipped: v4.0 Win-the-Drop (Acquisition Core + Reliability) — 2026-06-25 **Goal:** Make ShopPyBot complete *verified* orders on limited-release drops, and survive multi-hour unattended runs without one fault taking everything down. -**Target features:** -- Acquisition Core: checkout profile (shipping/billing) + form-fill on 1-2 reliable retailers (BestBuy, Amazon); order-confirmation capture (mark `purchased` only on a real confirmation, not a button click); bounded retry-on-cart with backoff; per-item/per-step checkout time budget; a central monitor-only run mode that also closes the `test_mode` place-order hole (6 of 7 plugins). -- Always-On Reliability: per-coroutine supervision + backoff restart; browser-crash detection + relaunch; encrypted session/cookie persistence; DB read-path error isolation; per-item orchestrator timeout; structured health/heartbeat surface; one unified transient retry/backoff. +**Delivered features:** +- Acquisition Core: checkout profile (shipping/billing) + form-fill on BestBuy + Amazon; order-confirmation capture (mark `purchased` only on a real confirmation, not a button click); bounded retry-on-cart with backoff; per-item/per-step checkout time budget; a central monitor-only run mode that also closes the `test_mode` place-order hole (6 of 7 plugins). +- Always-On Reliability: per-coroutine supervision + backoff restart; browser-crash detection + relaunch; encrypted session/cookie persistence; DB read-path error isolation; per-item orchestrator timeout; structured health/heartbeat surface; one unified transient retry/backoff (`RetryPolicy`). - Opportunistic server-safety: headless pygame import-crash guard; SIGTERM/SIGINT teardown bridge (stop orphaning Chrome). -**Deferred to follow-on:** request/API-mode checkout, virtual-waiting-room/queue survival (Queue-it/PerimeterX/Akamai/DataDome), multi-account/multi-profile parallel attempts, Amazon WAF auto-solve. All XL arms-race or ToS-hostile. +**Constraints held:** v2.0 security posture (no plaintext secrets, CLI default, web optional/localhost); payment via retailer-saved methods + CVV-at-runtime (never persist full card data, PCI); checkout work targets the `nodriver` plugin stack. -**Key constraints:** preserve the v2.0 security posture (no plaintext secrets, CLI default, web optional/localhost); payment via retailer-saved methods + CVV-at-runtime (never persist full card data, PCI); checkout work targets the `nodriver` plugin stack; continues phase numbering from 17. +
## Requirements @@ -75,19 +87,25 @@ v3.0: 6 phases (12-17) / 21 plans, all complete. Full suite: 548 passed, 2 skipp - ✓ Price monitoring: per-item target price, price history table, price-drop fan-out alerts, price-history CLI — v3.0 (Phase 16) - ✓ Stability: v2.0 audit tech-debt resolved + test hardening (548 tests) — v3.0 (Phases 12, 17) -### Active (v4.0 Win-the-Drop — Acquisition Core + Reliability) +### Validated (shipped v4.0 Win-the-Drop — Acquisition Core + Reliability) + +- ✓ Acquisition: checkout profile (shipping/billing) + form-fill (BestBuy, Amazon) — v4.0 (Phase 20) +- ✓ Acquisition: order-confirmation capture / verified purchase — v4.0 (Phase 19) +- ✓ Acquisition: bounded retry-on-cart with backoff (idempotent, no double-buy) — v4.0 (Phase 21) +- ✓ Acquisition: per-item/per-step checkout time budget — v4.0 (Phases 21, 22) +- ✓ Acquisition: central monitor-only run mode + close test_mode place-order hole — v4.0 (Phase 18) +- ✓ Reliability: per-coroutine supervision + backoff restart — v4.0 (Phase 22) +- ✓ Reliability: browser-crash detection + relaunch — v4.0 (Phase 22) +- ✓ Reliability: encrypted session/cookie persistence — v4.0 (Phase 23) +- ✓ Reliability: DB read-path error isolation — v4.0 (Phase 22) +- ✓ Reliability: per-item orchestrator timeout — v4.0 (Phase 22) +- ✓ Reliability: structured health/heartbeat surface — v4.0 (Phase 24) +- ✓ Reliability: unified RetryPolicy (one backoff source) — v4.0 (Phase 21) +- ✓ Server-safety: headless pygame import-crash guard + SIGTERM/SIGINT teardown bridge — v4.0 (Phases 24, 22) + +### Active (next milestone) -- [ ] Acquisition: checkout profile (shipping/billing) + form-fill (BestBuy, Amazon) -- [ ] Acquisition: order-confirmation capture / verified purchase -- [ ] Acquisition: bounded retry-on-cart with backoff (idempotent, no double-buy) -- [ ] Acquisition: per-item/per-step checkout time budget -- [ ] Acquisition: central monitor-only run mode + close test_mode place-order hole -- [ ] Reliability: per-coroutine supervision + backoff restart -- [ ] Reliability: browser-crash detection + relaunch -- [ ] Reliability: encrypted session/cookie persistence -- [ ] Reliability: DB read-path error isolation -- [ ] Reliability: per-item orchestrator timeout -- [ ] Reliability: structured health/heartbeat surface +_None yet — run `/gsd:new-milestone` to scope the next cycle. See "Next Milestone" above for candidate directions._ ### Deferred @@ -118,6 +136,11 @@ v3.0: 6 phases (12-17) / 21 plans, all complete. Full suite: 548 passed, 2 skipp | (v2.0) Dynamic CredentialStore | OS keyring with encrypted-file fallback for headless Ubuntu, env-var last resort; secrets never plaintext on disk | Chosen | | (v2.0) Local web UI via FastAPI | Most portable across Ubuntu/Windows, clean core/UI separation, optional extra; binds localhost by default | Chosen | | (v2.0 reversal) No secrets in SQLite | Storing creds in the local DB is plaintext-on-disk, weaker than env/keyring; rejected in favor of CredentialStore | Chosen | +| (v4.0) Single `place_order_guarded()` gate on the ABC | One enforcement point honors monitor-only/`test_mode` for all 7 plugins; closed the confirmed 6-of-7 hole instead of patching each plugin | ✓ Good | +| (v4.0) `purchased` only on a confirmed order number | A button click is not a purchase; confirmation-URL + order-id capture is the idempotency anchor that prevents double-buy on retry | ✓ Good | +| (v4.0) One unified `RetryPolicy` | Supervisor-restart and cart-retry share one backoff module so the two retry concepts cannot diverge or compound into a runaway loop | ✓ Good | +| (v4.0) Retailer-saved payment + CVV-at-runtime | Never persist full card/PAN (PCI scope); CVV via `getpass`, never logged; AST CI assertion guards against leaks | ✓ Good | +| (v4.0) Live-environment UAT deferred as tracked debt | Live retail checkout is ToS/legal risk in CI; confirmation/form-fill selectors verified by manual UAT, tracked in STATE.md Deferred Items | — Pending (operator live-buy checklist) | ## Evolution @@ -137,4 +160,4 @@ This document evolves at phase transitions and milestone boundaries. 4. Update Context with current state --- -*Last updated: 2026-06-10 — v4.0 Win-the-Drop milestone started* +*Last updated: 2026-06-25 — after v4.0 Win-the-Drop milestone (shipped)* diff --git a/.planning/RETROSPECTIVE.md b/.planning/RETROSPECTIVE.md new file mode 100644 index 0000000..25792de --- /dev/null +++ b/.planning/RETROSPECTIVE.md @@ -0,0 +1,60 @@ +# Project Retrospective + +*A living document updated after each milestone. Lessons feed forward into future planning.* + +## Milestone: v4.0 — Win-the-Drop + +**Shipped:** 2026-06-25 +**Phases:** 7 (18-24) | **Plans:** 29 | **Suite:** 755 passed, 2 skipped + +### What Was Built +- Safety gate: monitor-only mode + `place_order_guarded()` ABC closing the 6-of-7 `test_mode` place-order hole (P18). +- Verified checkout: order-confirmation detection + `order_id`/`confirmed_at`/`checkout_attempts` columns — `purchased` only on a real order number (P19). +- Checkout profile + BestBuy/Amazon form-fill, CVV-at-runtime, no card data persisted (P20). +- Unified `RetryPolicy` + per-step `asyncio.timeout()` + idempotent cart-retry (P21). +- Per-coroutine supervisor + browser relaunch + DB read isolation + per-item timeout + SIGTERM/SIGINT bridge (P22). +- Fernet-encrypted session persistence via raw CDP restore, bypassing the nodriver `set_all()` bug (P23). +- Health surface (`HealthRegistry`, `get_status`, `health_degraded` alert, `shoppybot status`) + headless pygame crash guard (P24). + +### What Worked +- **Foundation phase first.** P18 (safety gate + `CheckoutConfig`) had "do first, all downstream depend on it" — every later phase could be built and tested with live orders suppressed by monitor-only. No phase risked a real purchase during development. +- **Single enforcement points.** One `place_order_guarded()` on the ABC (not per-plugin patches) and one `RetryPolicy` (not per-call-site loops) — both backed by CI guards (grep/AST) that fail the build on regression. +- **Idempotency designed before its consumer.** P19 added the `order_id` anchor; P21's cart-retry read it. Designing the anchor a phase ahead of the retry that needs it avoided a double-buy redesign. +- **Clean integration close.** Integration checker verified all 6 cross-phase seams with 0 blockers; PLUGIN_API_VERSION stayed 2 (all additions additive). + +### What Was Inefficient +- **Live UAT can't run on the dev box.** 17 live-environment items (confirmation/form-fill/relaunch/SIGTERM/session/headless selectors + scenarios) accumulated as deferred debt. Correct per policy, but the real acceptance bar for an acquisition bot is a live drop, which CI/dev can't exercise. +- **STATE.md drifted stale.** It froze mid-Phase-23 (status "verifying", phase table showing 18-21 "Not started") while ROADMAP.md stayed authoritative. At milestone close this forced a desync diagnosis before any action was safe. +- **ROADMAP Phase Details not pruned at v3.0 close.** Archived v3.0 phases 12-17 left full detail in the live ROADMAP, so `roadmap.analyze` false-positived them as incomplete `no_directory` phases — which would have driven an autonomous run to "re-execute" already-shipped work. + +### Patterns Established +- **Foundation-phase-first** for any milestone that touches a dangerous action (place-order): ship the gate before the feature. +- **Confirmed-outcome idempotency**: never treat a UI action as success; capture a retailer-side identifier and gate retries on it. +- **Security invariants as CI guards**: AST assertion (no CVV in `writeLog` args), grep assertion (no `for attempt in range(` outside `core/retry.py`), zero-write integration test under monitor-only. +- **Explicit UAT-debt ledger** in STATE.md Deferred Items — live checks that can't run in CI are tracked, not silently dropped. + +### Key Lessons +1. **Prune ROADMAP "Phase Details" at every milestone close.** Leaving archived-milestone detail in the live ROADMAP desyncs `roadmap.analyze` and can mislead a future autonomous run. (Fixed this close: live ROADMAP now collapses to per-milestone `
` only.) +2. **Keep STATE.md in sync, or treat ROADMAP as the sole source of truth.** A stale STATE.md cost a diagnosis step at close. Prefer reconciling STATE at phase transitions. +3. **Design idempotency anchors one phase ahead of the retry that reads them** — it removes rework and closes the double-buy window by construction. + +### Cost Observations +- Model mix: not tracked this milestone. +- Notable: milestone closed via `/gsd-autonomous` lifecycle tail after the phase work + audit were already complete; the run's main value was catching the ROADMAP/STATE desync before executing anything. + +--- + +## Cross-Milestone Trends + +### Cumulative Quality + +| Milestone | Tests (suite) | Notable | +|-----------|---------------|---------| +| v2.0 | 341 passed | Modular core + CredentialStore (no plaintext on disk) | +| v3.0 | 548 passed, 2 skipped | Anti-detection + ecosystem + price monitoring | +| v4.0 | 755 passed, 2 skipped | Verified checkout + always-on reliability | + +### Top Lessons (Verified Across Milestones) + +1. Prune archived-milestone detail from the live ROADMAP at close — keeps `roadmap.analyze` accurate and ROADMAP constant-size. +2. Single enforcement points (one ABC gate, one RetryPolicy) backed by CI guards beat per-site patches for safety-critical invariants. diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index bca98da..027ead1 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -11,7 +11,7 @@ - ✅ **v1 Open Source Launch** — Phases 1-6 (shipped 2026-06-03) - ✅ **v2.0 Modular Core + Cross-Platform UX** — Phases 7-11 (shipped 2026-06-06) - ✅ **v3.0 Resilience + Ecosystem** — Phases 12-17 (shipped 2026-06-10) -- **v4.0 Win-the-Drop (Acquisition Core + Reliability)** — Phases 18-24 (in progress) +- ✅ **v4.0 Win-the-Drop (Acquisition Core + Reliability)** — Phases 18-24 (shipped 2026-06-25) --- @@ -27,6 +27,8 @@ - [x] Phase 5: Notification System (5/5 plans) — 2026-06-03 - [x] Phase 6: Platform Expansion (5/5 plans) — 2026-06-03 +Full phase detail archived at `.planning/milestones/v1-phases` (see also `milestones/`). +
@@ -46,382 +48,47 @@ Audit: `.planning/milestones/v2.0-MILESTONE-AUDIT.md` (status: passed).
✅ v3.0 Resilience + Ecosystem (Phases 12-17) — SHIPPED 2026-06-10 -- [x] **Phase 12: Stability Foundation** — Close v2.0 deferred cross-OS checks and resolve 4 audit tech-debt items (completed 2026-06-09) -- [x] **Phase 13: Anti-Detection Layer 1 — Fingerprint + Proxy** — Apply JS fingerprint stealth patch and implement proxy rotation with ban detection (completed 2026-06-09) -- [x] **Phase 14: Anti-Detection Layer 2 — CAPTCHA Solving** — Integrate 2captcha opt-in solver with CredentialStore key, startup balance check, async executor wrapping, and spend cap (completed 2026-06-09) -- [x] **Phase 15: Plugin Ecosystem Registry** — Add difficulty/proxy/captcha class attrs to ABC, create GitHub wiki registry table, ship `shoppybot plugins list` command (completed 2026-06-09) -- [x] **Phase 16: Price Monitoring** — Per-item target price, append-only price history table, percentage-drop trigger, fan-out price-drop alerts, price-history CLI (completed 2026-06-10) -- [x] **Phase 17: Test Hardening** — Unit and integration coverage for all v3.0 features (completed 2026-06-10) +- [x] Phase 12: Stability Foundation (4/4 plans) — 2026-06-09 +- [x] Phase 13: Anti-Detection Layer 1 — Fingerprint + Proxy (3/3 plans) — 2026-06-09 +- [x] Phase 14: Anti-Detection Layer 2 — CAPTCHA Solving (3/3 plans) — 2026-06-09 +- [x] Phase 15: Plugin Ecosystem Registry (3/3 plans) — 2026-06-09 +- [x] Phase 16: Price Monitoring (4/4 plans) — 2026-06-10 +- [x] Phase 17: Test Hardening (4/4 plans) — 2026-06-10 -Full phase detail archived in `.planning/milestones/v3.0-ROADMAP.md`. +Full phase detail archived at `.planning/milestones/v3.0-ROADMAP.md`. +Audit: `.planning/milestones/v3.0-MILESTONE-AUDIT.md`.
-### v4.0 Win-the-Drop (Phases 18-24) - -- [x] **Phase 18: Safety Gate + Config Foundation** — Central monitor-only mode, `place_order_guarded()` ABC method closing the 6-of-7 plugin safety hole, and `CheckoutConfig` schema as the foundation every downstream phase depends on (completed 2026-06-11) -- [x] **Phase 19: DB Schema + Confirmation Detection** — Add `order_id`/`confirmed_at`/`checkout_attempts` columns and build `core/confirmation.py` so `purchased` is only written on a real confirmed order number, never on a button click (completed 2026-06-11) -- [x] **Phase 20: Checkout Profile + Form-Fill** — Shipping/billing profile stored in CredentialStore (9 keys, no card data), BestBuy and Amazon form-fill, CVV getpass-only at runtime (completed 2026-06-11) -- [x] **Phase 21: Per-Step Timeouts + Unified Retry + Cart-Retry** — One `RetryPolicy` in `core/retry.py` shared by both supervisor restart and cart-retry; per-step `asyncio.timeout()` per DOM stage; idempotency guard reads DB before every attempt (completed 2026-06-12) -- [x] **Phase 22: Supervisor + Browser Relaunch + Server Safety** — Per-coroutine supervision with failure budget absorbs crashes before the TaskGroup boundary; full relaunch sequence (teardown, proxy, stealth, login); DB read isolation; per-item orchestrator timeout; SIGTERM/SIGINT teardown bridge (completed 2026-06-12) -- [x] **Phase 23: Encrypted Session Persistence** — Fernet-encrypted cookie save/restore via `core/session_store.py` (reuses `EncryptedFileBackend` pattern); raw CDP restore path that bypasses the confirmed `set_all()` bug; replaces Phase 22's no-op stub (completed 2026-06-12) -- [x] **Phase 24: Health Surface + Server Safety** — `core/health.py` HealthRegistry, expanded `BotService.get_status()` with per-plugin liveness/heartbeat, `health_degraded` notification event, updated FastAPI `/status` endpoint, headless pygame crash guard (completed 2026-06-12) - ---- - -## Phase Details - -### Phase 12: Stability Foundation - -**Goal**: The v2.0 deferred debt and audit tech-debt are paid down before new features land, so the test suite is a reliable baseline -**Depends on**: Nothing — do first -**Requirements**: STAB-01, STAB-02 -**Success Criteria** (what must be TRUE): - - 1. All 4 deferred v2.0 cross-OS/UI manual checks (keyring restart survival, masked-TTY passphrase prompt, web dashboard render on Ubuntu, `0.0.0.0` bind warning) are executed and documented pass or fail, with any failures fixed - 2. Each of the 4 v2.0 audit tech-debt items has a targeted regression test that passes in CI - 3. No broad refactors occur: only the specific items in scope are changed - -**Plans**: 4 plans - -Plans: - -- [x] 12-01-PLAN.md — TD-1: re-anchor logger logging_level read to core.paths.config_path() + regression test -- [x] 12-02-PLAN.md — TD-2/TD-3: harden SC1 secret-read guard (rglob) and separator guard (__file__-anchored) -- [x] 12-03-PLAN.md — TD-4 config write-seam regression test + accepted MOD-02 gap doc; MC-4 0.0.0.0 banner assertion -- [x] 12-04-PLAN.md — Execute and document MC-1..MC-4 deferred manual checks in docs/PLATFORMS.md - -### Phase 13: Anti-Detection Layer 1 — Fingerprint + Proxy - -**Goal**: Users can enable proxy rotation and the bot applies a JS fingerprint stealth patch at browser startup, measurably reducing Layer 2 bot signals -**Depends on**: Phase 12 -**Requirements**: ANTI-08, ANTI-04, ANTI-05 -**Success Criteria** (what must be TRUE): - - 1. Bot applies `window.chrome`, `navigator.plugins`, `navigator.languages`, and screen-dimension patches via `core/stealth.py` at every browser startup with no plugin ABC version bump - 2. User can enable proxy rotation via an opt-in `proxy:` config section (disabled by default) listing `scheme://host:port` URLs; bot logs "Proxy rotation: enabled, pool_size=N" at startup - 3. Bot detects ban signals (HTTP 403/429/503, challenge-redirect, block-phrase body) and rotates to the next proxy, retiring a proxy after N consecutive failures for a configurable cooldown period - 4. WebRTC Chrome preferences are set at browser launch to prevent real-IP leaks through the proxy tunnel - 5. Each proxy is scoped to its plugin instance (`self._proxy`) and rotated only at browser restart, not mid-session - -**Plans**: 3 plans - -Plans: - -- [x] 13-01-PLAN.md — core/stealth.py: STEALTH_JS + apply_stealth, ProxyPool (round-robin/retire/cooldown), proxy launch args + WebRTC flag, CDP Fetch auth, ban-signal detector (+ unit tests) -- [x] 13-02-PLAN.md — ProxyConfig schema (opt-in, disabled by default) + documented sample.config.yml proxy section -- [x] 13-03-PLAN.md — Wire stealth + proxy into BotService/orchestrator/registry and all 8 plugins; per-instance scoping, exact startup log, fail-loud on pool exhaustion, ban-detect recording - -**UI hint**: no - -### Phase 14: Anti-Detection Layer 2 — CAPTCHA Solving - -**Goal**: Users who encounter reCAPTCHA v2 or Amazon WAF CAPTCHAs can opt into automated solving via 2captcha with full cost visibility and no credential plaintext exposure -**Depends on**: Phase 13 (fingerprint + proxy layer in place before adding CAPTCHA layer) -**Requirements**: ANTI-06, ANTI-07 -**Success Criteria** (what must be TRUE): - - 1. User can enable CAPTCHA solving via `captcha.enabled: true` in config; the 2captcha API key is stored exclusively in CredentialStore (`TWOCAPTCHA_API_KEY`), never in config.yml - 2. Bot checks 2captcha account balance at startup, logs a WARNING when balance is low, and skips solver use (falling back to manual pause) when balance is zero - 3. CAPTCHA solve calls use `run_in_executor` + `asyncio.timeout(120)` so other plugin poll tasks are not blocked during a solve - 4. A configurable `captcha.max_solves_per_run` limit prevents unbounded API charges; default config disables CAPTCHA solving - -**Plans**: 3 plans - -Plans: - -- [x] 14-01-PLAN.md — Foundation: TWOCAPTCHA_API_KEY in SECRET_KEYS, CaptchaConfig, CaptchaSolver 2captcha v1 client (submit/poll/balance/cap) -- [x] 14-02-PLAN.md — Wiring: solver constructed fresh in async_main + startup balance check + registry.assign_solver (mirrors ProxyPool) -- [x] 14-03-PLAN.md — Plugin solve path: Amazon + BestBuy reCAPTCHA solve under run_in_executor+timeout(120) with manual-pause fallback; WAF deferred - -### Phase 15: Plugin Ecosystem Registry - -**Goal**: Community contributors have a discoverable registry with clear difficulty ratings, and users can inspect loaded plugins locally without a network call -**Depends on**: Phase 12 -**Requirements**: REG-01, REG-02, REG-03, REG-04 -**Success Criteria** (what must be TRUE): - - 1. Plugin authors can declare `difficulty`, `requires_proxy`, and `requires_captcha` as class attributes on any plugin; existing plugins without these attrs continue to load with sensible defaults (non-breaking) - 2. The GitHub wiki registry table contains required fields for each community plugin: name, platform, domain patterns, maintainer, anti-detection difficulty, methods implemented, last-verified date, proxy-required, captcha-required - 3. Running `shoppybot plugins list` displays all locally loaded plugins with their declared domain patterns, difficulty, and proxy/captcha flags without making a network call - 4. CONTRIBUTING.md and the PR template require contributors to supply `difficulty`, `requires_proxy`, and `requires_captcha` for new plugin submissions - -**Plans**: 3 plans - -Plans: - -- [x] 15-01-PLAN.md — REG-02: add difficulty/requires_proxy/requires_captcha class attrs + __init_subclass__ difficulty validation to RetailerPlugin ABC (non-breaking, PLUGIN_API_VERSION stays 2) + test_plugin_base.py assertions -- [x] 15-02-PLAN.md — REG-03: BotService.list_plugins() over registry._all_plugins + core/cli/plugins.py handler + plugins-list subparser with --json + no-network CLI tests -- [x] 15-03-PLAN.md — REG-01/REG-04: docs/PLUGIN_REGISTRY.md 9-field wiki SPEC + CONTRIBUTING.md/PR-template/PLUGIN_DEV.md attr requirements + tests/test_docs.py - -### Phase 16: Price Monitoring - -**Goal**: Users can track per-item prices, receive fan-out alerts when prices drop to target or by a configured percentage, and inspect price history from the CLI -**Depends on**: Phase 12 -**Requirements**: PRICE-01, PRICE-02, PRICE-03, PRICE-04, PRICE-05, PRICE-06 -**Success Criteria** (what must be TRUE): - - 1. User can set `target_price` (absolute) and `price_drop_pct` (percentage) per item in config; NULL/absent means price monitoring is off for that item - 2. Bot records scraped prices in an append-only `price_history` SQLite table each poll cycle via an optional `get_price()` plugin ABC hook (default returns `None`); the DB migration is idempotent on existing installs - 3. Price-drop alerts are dispatched through the existing fan-out notification dispatcher using a distinct `price_drop` notification_type with dedup columns separate from stock alert columns - 4. Price alert payloads include the current price, target price, and percentage from target - 5. Running `shoppybot items price-history ` displays the last N recorded prices for that item - -**Plans**: 4 plans - -Plans: - -- [x] 16-01-PLAN.md — Data layer: idempotent price_history table + 4 items columns + 8 parameterized price _sync functions + ItemConfig target_price/price_drop_pct (PRICE-01/02/05) -- [x] 16-02-PLAN.md — Plugin + notification contract: NotificationEvent price fields, default-None get_price() ABC hook, real Amazon get_price() + text→cents parser, price_drop notifier branches (PRICE-02/04) -- [x] 16-03-PLAN.md — Orchestrator wiring: _check_and_buy price path, both triggers with separate dedup, single price_drop dispatch, startup config seeding + BotService.get_price_history (PRICE-02/03/04/05) -- [x] 16-04-PLAN.md — CLI: shoppybot items price-history leaf with --limit (default 10), $X.XX table, no network (PRICE-06) - -**UI hint**: yes - -### Phase 17: Test Hardening - -**Goal**: Every new v3.0 feature has unit and integration coverage so regressions are caught by CI before they reach users -**Depends on**: Phases 13, 14, 15, 16 (tests validate the implemented features) -**Requirements**: STAB-03 -**Success Criteria** (what must be TRUE): - - 1. Unit tests cover proxy config parsing, ban-signal detection logic, per-instance proxy scoping, and cooldown/retire logic - 2. Unit tests cover CAPTCHA config parsing, balance-check behavior, executor wrapping, and spend-cap enforcement - 3. Unit tests cover price comparison threshold logic, `price_history` DB schema (including idempotent migration against a v2.0 DB fixture), and price-drop dedup separation from stock-alert dedup - 4. Integration tests cover the plugin ABC additions (`difficulty`, `requires_proxy`, `requires_captcha` defaults and overrides) and the `get_price()` hook being called alongside `check_availability` - -**Plans**: 4 plans - -Plans: - -- [x] 17-01-PLAN.md — Proxy coverage: PX-01..PX-06 (config validator, fetch-handler tasks, ProxyPool edges, registry routing/lifecycle isolation) -- [x] 17-02-PLAN.md — CAPTCHA coverage: CP-01..CP-05 (poll/timeout errors, balance gate, solve_amazon_waf submit/poll/decode) -- [x] 17-03-PLAN.md — Price + get_price integration: PR-01..PR-04 + AB-01, AB-02 (v2.0-schema migration fixture, trigger guards, get_price-alongside-check_availability) -- [x] 17-04-PLAN.md — Plugin ABC: AB-03, AB-04 (metadata overrides + _handle_ban ban→proxy-cooldown bridge) - ---- - -### Phase 18: Safety Gate + Config Foundation - -**Goal**: Every plugin routes its final place-order action through an ABC-enforced gate that honors monitor-only mode, so no plugin — current or future — can place a live order when monitoring is active -**Depends on**: Nothing (do first; all downstream v4.0 phases depend on this config foundation) -**Requirements**: BUY-01, BUY-02 -**Success Criteria** (what must be TRUE): - - 1. User can start the bot with `--monitor-only` CLI flag or `debug.monitor_only: true` in config; bot performs stock checks and fires alerts but `auto_buy` is never called for any plugin - 2. All 7 bundled plugins route their place-order DOM click through `place_order_guarded()` on the RetailerPlugin ABC; a CI test with all 7 plugins and `monitor_only=True` asserts zero calls to the purchase write-queue - 3. BestBuy's confirmed `test_mode` gap is closed: `place_order.click()` is not called when `monitor_only=True` or `test_mode=True` on any plugin - 4. `CheckoutConfig` sub-model exists in `AppConfig` with `item_timeout_secs`, `step_timeout_secs`, `max_cart_retries`, `backoff_base`, `backoff_jitter`, and `alert_on_errors` fields so downstream phases can use them without schema changes - -**Plans**: 4 plans - -Plans: - -**Wave 1** - -- [x] 18-01-PLAN.md — DebugConfig.monitor_only + CheckoutConfig model + AppConfig wiring (BUY-01, BUY-02) -- [x] 18-02-PLAN.md — place_order_guarded() concrete method on RetailerPlugin ABC + unit tests (BUY-02) - -**Wave 2** *(blocked on Wave 1 completion)* - -- [x] 18-03-PLAN.md — orchestrator monitor_only gate + --monitor-only CLI flag + CVV short-circuit + ALLOWLIST (BUY-01) -- [x] 18-04-PLAN.md — reroute all 7 plugins through place_order_guarded + test_safety_gate.py (7-plugin zero-write + grep) (BUY-02) - -### Phase 19: DB Schema + Confirmation Detection - -**Goal**: Purchases are only recorded when the bot has verified a real order number from the retailer's confirmation page, never on a button click alone -**Depends on**: Phase 18 (monitor-only gate must be live before any live checkout UAT of confirmation selectors) -**Requirements**: BUY-03, BUY-04 -**Success Criteria** (what must be TRUE): - - 1. The `items` table has `order_id TEXT`, `confirmed_at TEXT`, and `checkout_attempts INTEGER DEFAULT 0` columns added via idempotent `ALTER TABLE` (same pattern as v3.0 price columns); existing DB installs migrate without data loss - 2. After `auto_buy()` returns, the orchestrator calls `detect_order_confirmation(tab, platform)` and only enqueues `("confirmed", link, order_id, ts)` to the write-queue when a non-None order_id is returned; `purchased=1` is set only at that point - 3. When confirmation is not detected, the bot logs a WARNING and falls back to the legacy `purchased` write tag (no silent failure, no double-buy risk from the confirmation path itself) - 4. Each confirmed checkout writes `order_id` and `confirmed_at` to the DB, providing the idempotency anchor for retry (Phase 21) to read before any re-attempt - -**Plans**: 4 plans - -Plans: - -**Wave 1** *(parallel-safe; no file overlap)* - -- [x] 19-01-PLAN.md — models.py: 3 idempotent confirmation columns (order_id/confirmed_at/checkout_attempts DEFAULT 0, NOT incremented) + update_item_confirmed_sync (BUY-04) -- [x] 19-02-PLAN.md — core/confirmation.py NEW: detect_order_confirmation (URL-first/DOM-backup map, ~3s settle, Amazon orderID URL-param parse, CONFIRMED- sentinel) + FakeTab tests (BUY-03) -- [x] 19-03-PLAN.md — core/plugin_base.py: additive sync get_active_tab() ABC default (returns main_tab; PLUGIN_API_VERSION stays 2) (BUY-03) - -**Wave 2** *(blocked on Wave 1)* - -- [x] 19-04-PLAN.md — orchestrator wiring (_try_auto_buy detect + confirmed/legacy fallback outside any timeout; _dispatch_write confirmed branch) + Amazon/BestBuy _last_tab + get_active_tab override + orchestrator tests (BUY-03, BUY-04) - -**Research flag** (RESOLVED via 19-RESEARCH.md): per-retailer confirmation URL patterns (Amazon `/gp/buy/thankyou`, BestBuy `/checkout/r/thank-you`) are HIGH confidence and hardcoded in `core/confirmation.py`; backup DOM selectors (`#confirmedOrderId`, `.thank-you-order-number`) are MEDIUM confidence — live UAT on a test_mode buy is tracked as UAT debt (STATE.md Deferred Items). - -### Phase 20: Checkout Profile + Form-Fill - -**Goal**: Users can configure a shipping/billing profile that the bot fills during BestBuy and Amazon checkout, with payment using the retailer-saved method plus CVV entered at runtime and no full card data persisted anywhere -**Depends on**: Phase 18 (monitor-only gate required before any form-fill can be tested live); Phase 19 (confirmation detection should precede form-fill so a completed form-fill can be confirmed) -**Requirements**: BUY-07 -**Success Criteria** (what must be TRUE): - - 1. User can run `shoppybot setup checkout-profile` to interactively populate 9 address keys (`CHECKOUT_FIRST_NAME`, `CHECKOUT_LAST_NAME`, `CHECKOUT_ADDRESS_LINE1`, `CHECKOUT_ADDRESS_LINE2`, `CHECKOUT_CITY`, `CHECKOUT_STATE`, `CHECKOUT_ZIP`, `CHECKOUT_COUNTRY`, `CHECKOUT_PHONE`) in the CredentialStore; no card number or CVV is stored - 2. BestBuy and Amazon plugins fill the shipping form fields from the `CheckoutProfile` loaded at plugin setup time; CVV is provided via `getpass` at runtime only - 3. A CI grep assertion confirms no `_cvv` value appears in any `writeLog()` call argument on checkout code paths - 4. If a shipping form field selector returns None (DOM drift), the plugin logs a WARNING with the selector name and returns False without submitting an incomplete form - -**Plans**: 4 plans - -Plans: - -**Wave 1** *(parallel-safe; no file overlap)* - -- [x] 20-01-PLAN.md — core/checkout_profile.py: CHECKOUT_PROFILE_KEYS (9, NOT in SECRET_KEYS) + CheckoutProfile model + load_checkout_profile() incomplete detection + tests (BUY-07) -- [x] 20-02-PLAN.md — `setup checkout-profile` CLI: visible-prompt 9 keys, key-NAME-only output, optional ADDRESS_LINE2, no card/CVV stored (BUY-07) -- [x] 20-03-PLAN.md — CVV threading: Amazon __init__ _cvv=None + orchestrator amz injection (mirrors BestBuy 411-414) + run.py needs_cvv includes amazon.com (BUY-07) - -**Wave 2** *(blocked on 20-01 + 20-03)* - -- [x] 20-04-PLAN.md — Form-fill: _checkout_profile load at setup() + _fill_field + BestBuy shipping fill before place_order_guarded (missing-selector WARN+False) + Amazon CVV skip-if-absent + CVV-not-in-logs AST test (BUY-07) - -### Phase 21: Per-Step Timeouts + Unified Retry + Cart-Retry - -**Goal**: Checkout attempts are bounded in time and retries, and all retry/backoff logic flows through one shared `RetryPolicy` so supervisor restarts and cart retries cannot compound into a runaway loop -**Depends on**: Phase 18 (CheckoutConfig fields), Phase 19 (DB `order_id` idempotency anchor must exist before retry reads it) -**Requirements**: BUY-05, BUY-06, REL-08 -**Success Criteria** (what must be TRUE): - - 1. `core/retry.py` contains a single `RetryPolicy` dataclass and `with_retry()` async helper; both supervisor restart (Phase 22) and cart-retry use this module; a CI grep assertion confirms no standalone `for attempt in range(N)` retry loops exist outside `core/retry.py` - 2. Each checkout DOM step (navigate, add-to-cart, checkout-proceed, CVV entry, place-order click, confirmation wait) runs under its own `asyncio.timeout(step_timeout_secs)` context manager; the entire `auto_buy()` method is NOT wrapped in a single outer timeout - 3. A `checkout_stage` variable tracks progress within `auto_buy()`; on `CancelledError` the stage is logged for post-mortem and the item is not immediately re-submitted - 4. Cart-retry reads the DB `order_id` column before each attempt; if a prior attempt already wrote a confirmed order, the retry loop exits immediately without re-submitting - 5. Cart-retry is bounded by `CheckoutConfig.max_cart_retries` (default 3) with exponential backoff; the retry never re-enters the place-order click stage on an already-attempted order - -**Plans**: 4 plans - -Plans: - -**Wave 1** *(parallel-safe; no file overlap)* - -- [x] 21-01-PLAN.md — core/retry.py NEW: RetryPolicy dataclass + pure compute_delay (seedable jitter) + with_retry async helper; tests/test_no_retry_loops.py AST guard (no `for attempt in range(` outside core/retry.py) (REL-08) -- [x] 21-02-PLAN.md — models.py: increment_checkout_attempts_sync (+1 per call) + get_item_order_state_sync (purchased, order_id idempotency anchor); no schema change (BUY-05) -- [x] 21-03-PLAN.md — per-step asyncio.timeout: self._checkout_stage default on RetailerPlugin ABC + 6 Amazon / 8 BestBuy DOM stages each under their own asyncio.timeout(step_timeout_secs); no outer timeout; per-item ceiling deferred to P22 (BUY-06) - -**Wave 2** *(blocked on 21-01 + 21-02 + 21-03)* - -- [x] 21-04-PLAN.md — orchestrator cart-retry: extract _attempt_buy(plugin, link)->(bool, str|None) + with_retry/RetryPolicy from CheckoutConfig; DB re-read + checkout_attempts increment before each attempt; confirmed order_id short-circuit (no double-buy); single enqueue outside loop (BUY-05, REL-08) - -**Research flag** (RESOLVED via 21-CONTEXT.md + 21-RESEARCH.md): the `checkout_attempts` increment strategy is resolved — increment once per retry ATTEMPT, BEFORE each attempt (not per-cart-add, not confirmed-only). max_cart_retries semantics documented: it is the number of RETRIES after the first attempt, so total attempts = 1 + max_cart_retries (max_cart_retries=0 → single attempt, no retry). - -### Phase 22: Supervisor + Browser Relaunch + Server Safety - -**Goal**: A single plugin crash or browser death cannot take down the rest of the bot; plugins restart automatically with backoff and full stealth/proxy/login restoration; the bot shuts down cleanly on SIGTERM -**Depends on**: Phase 18 (CheckoutConfig for alert_on_errors), Phase 21 (RetryPolicy from core/retry.py; supervisor reuses it) -**Requirements**: REL-01, REL-02, REL-03, REL-05, REL-06, SRV-02 -**Success Criteria** (what must be TRUE): - - 1. An unhandled exception in one plugin's `run_plugin` coroutine is absorbed by the supervisor before the `asyncio.TaskGroup` boundary; all other plugin coroutines keep running (verified by a test that crashes one plugin and asserts others continue) - 2. A plugin that exceeds N failures within a time window is parked (no further restart attempts) and the operator receives a notification through the existing dispatcher - 3. On a dead or disconnected Chrome process, the supervisor calls `plugin.relaunch()` which executes the full sequence: teardown, assign_proxy, setup (new browser + stealth + proxy auth), restore_session (no-op stub until Phase 23), login; `apply_stealth` is verified called on the relaunched browser - 4. Transient `sqlite3.OperationalError` (locked DB) on any `run_in_executor` read path in `run_plugin` is caught and isolated: the poll cycle is skipped, not terminated - 5. Each item's check/buy cycle runs under `asyncio.timeout(item_timeout_secs)`; the `write_queue.put()` calls are placed OUTSIDE the timeout context so a timed-out item cannot orphan a pending DB write - 6. SIGTERM and SIGINT trigger cooperative teardown (write-queue flush + browser teardown) via a platform-appropriate signal bridge (`sys.platform` branch handles Windows `NotImplementedError` on `loop.add_signal_handler`) - -**Plans**: 4 plans - -Plans: - -**Wave 1** *(parallel-safe; disjoint file)* - -- [x] 22-01-PLAN.md — core/plugin_base.py: concrete relaunch() (teardown→setup→restore_session→login; stealth re-injected via setup) + restore_session() no-op stub returns False; PLUGIN_API_VERSION stays 2 (REL-03) - -**Wave 2** *(orchestrator.py edits serialize — same-file, no parallel)* - -- [x] 22-02-PLAN.md — run_plugin hardening: cfg param + sqlite3.OperationalError read isolation on items read + per-item asyncio.timeout(item_timeout_secs); write_queue.put stays outside (REL-05, REL-06) - -**Wave 3** *(blocked on 22-01 + 22-02)* - -- [x] 22-03-PLAN.md — supervise() wrapper + _is_browser_dead_exc + failure budget (alert_on_errors / 600s deque) + park notify + browser-dead assign_proxy→relaunch + async_main create_task wiring (REL-01, REL-02) - -**Wave 4** *(blocked on 22-03)* - -- [x] 22-04-PLAN.md — _register_signals (POSIX add_signal_handler / Windows signal.signal fallback) + _flush_write_queue manual drain + async_main signal registration + pre-teardown flush (SRV-02) - -**Research flag** (RESOLVED via 22-RESEARCH.md): the nodriver stealth-persistence question is answered — `add_script_to_evaluate_on_new_document` is a per-session CDP command that is NOT persisted across `Browser.stop()` + `Browser.create()`; every plugin’s setup() re-injects stealth via apply_stealth, so relaunch() calling setup() is sufficient (HIGH confidence, confirmed against installed nodriver 0.50.3 source). - -### Phase 23: Encrypted Session Persistence - -**Goal**: Users can opt into encrypted cookie persistence so the bot skips re-login and MFA across restarts without storing any auth material in plaintext -**Depends on**: Phase 22 (supervisor calls `restore_session` on relaunch; Phase 22 ships a no-op stub that this phase replaces) -**Requirements**: REL-04 -**Success Criteria** (what must be TRUE): - - 1. When `platforms..session_persistence: true`, cookies are saved after successful login via `core/session_store.py` using Fernet encryption (same scrypt KDF as `EncryptedFileBackend`); no plaintext `.json` or `.pickle` file is written to disk - 2. On bot restart or plugin relaunch, cookies are restored via raw CDP `cdp.storage.set_cookies()` (bypassing the confirmed `CookieJar.set_all()` bug); the restore path returns `True` if a session file existed, `False` otherwise (no crash if file is absent) - 3. The `data/sessions/` directory is in `.gitignore`; a CI check confirms no session file pattern matches are committed - 4. The Phase 22 no-op `restore_session` stub in `plugin.relaunch()` is replaced by the live `SessionStore.restore()` call - -**Plans**: TBD -**Research flag**: NEEDS PLAN-PHASE RESEARCH — `nodriver cdp.storage.set_cookies()` exact import path and `CookieParam` constructor signature should be verified against the installed `nodriver==0.50.3` package before implementing the restore path. The workaround is confirmed from issues #1816/#2020 but the exact API shape needs local verification. - -### Phase 24: Health Surface + Server Safety - -**Goal**: Operators can query per-plugin liveness and error state from the CLI or web UI, receive alerts when a plugin degrades, and run the bot headlessly on a server without a pygame import crash -**Depends on**: Phases 22 and 23 (health surface reads from supervisor + session state; SRV-01 is self-contained but grouped here as a low-dependency finish item) -**Requirements**: REL-07, SRV-01 -**Success Criteria** (what must be TRUE): - - 1. `BotService.get_status()` returns a structured dict including `{"running": bool, "uptime_secs": float, "plugins": {name: {"status": str, "last_heartbeat": float, "consecutive_errors": int, "items_checked": int, "orders_confirmed": int}}}` queryable from CLI (`shoppybot status`) and the FastAPI `/status` endpoint - 2. When a plugin's `consecutive_errors` exceeds the configured `alert_on_errors` threshold, a `health_degraded` event is dispatched through the existing notification fan-out channels - 3. On a headless host with no audio device, the sound notifier degrades to a silent no-op at import time rather than crashing; the bot starts and runs normally without pygame - -**Plans**: 5 plans - -Plans: - -**Wave 1** *(parallel-safe; disjoint files)* - -- [x] 24-01-PLAN.md — core/health.py HealthRegistry (per-plugin status/heartbeat/consecutive_errors/items_checked/orders_confirmed) + JSON-safe snapshot + in-memory armed/disarmed dedup + tests (REL-07) -- [x] 24-02-PLAN.md — utils.py pygame headless guard: _initialize_audio()/_AUDIO_AVAILABLE, play_sound no-op when no device, redundant mixer.init removed + tests (SRV-01) +
+✅ v4.0 Win-the-Drop (Phases 18-24) — SHIPPED 2026-06-25 -**Wave 2** *(blocked on 24-01; disjoint files service/orchestrator/cli)* +- [x] Phase 18: Safety Gate + Config Foundation (4/4 plans) — 2026-06-11 +- [x] Phase 19: DB Schema + Confirmation Detection (4/4 plans) — 2026-06-11 +- [x] Phase 20: Checkout Profile + Form-Fill (4/4 plans) — 2026-06-11 +- [x] Phase 21: Per-Step Timeouts + Unified Retry + Cart-Retry (4/4 plans) — 2026-06-12 +- [x] Phase 22: Supervisor + Browser Relaunch + Server Safety (4/4 plans) — 2026-06-12 +- [x] Phase 23: Encrypted Session Persistence (4/4 plans) — 2026-06-12 +- [x] Phase 24: Health Surface + Server Safety (5/5 plans) — 2026-06-12 -- [x] 24-03-PLAN.md — core/service.py get_status() locked shape {running,uptime_secs,plugins{...}} + _start_time uptime + single HealthRegistry ref wired into async_main; /status endpoint unchanged + JSON-serializable test (REL-07) -- [x] 24-04-PLAN.md — core/orchestrator.py wiring: health=None kwarg through async_main/supervise/run_plugin; heartbeat/items_checked/status transitions/orders_confirmed; health_degraded fire-once+re-arm dedup via existing dispatcher, distinct from plugin_parked + tests (REL-07) -- [x] 24-05-PLAN.md — core/cli/status.py shoppybot status subcommand (per-plugin table + --json, no network, in-process-state note) + subparser registration + tests (REL-07) +Full phase detail archived at `.planning/milestones/v4.0-ROADMAP.md`. +Audit: `.planning/milestones/v4.0-MILESTONE-AUDIT.md` (status: tech_debt — pre-accepted live-UAT debt). -**UI hint**: yes +
--- ## Progress -| Phase | Milestone | Plans | Status | Completed | -|-------|-----------|-------|--------|-----------| -| 1. Foundations + Security | v1 | 5/5 | Complete | 2026-06-02 | -| 2. Plugin Migration | v1 | 6/6 | Complete | 2026-06-03 | -| 3. Community Documentation | v1 | 2/2 | Complete | 2026-06-03 | -| 4. Async Orchestrator | v1 | 5/5 | Complete | 2026-06-03 | -| 5. Notification System | v1 | 5/5 | Complete | 2026-06-03 | -| 6. Platform Expansion | v1 | 5/5 | Complete | 2026-06-03 | -| 7. Modular Core Service | v2.0 | 3/3 | Complete | 2026-06-04 | -| 8. Credential Store | v2.0 | 4/4 | Complete | 2026-06-04 | -| 9. CLI Front-End | v2.0 | 4/4 | Complete | 2026-06-04 | -| 10. Optional Web UI | v2.0 | 4/4 | Complete | 2026-06-04 | -| 11. Cross-Platform Verification | v2.0 | 5/5 | Complete | 2026-06-05 | -| 12. Stability Foundation | v3.0 | 4/4 | Complete | 2026-06-09 | -| 13. Anti-Detection Layer 1 — Fingerprint + Proxy | v3.0 | 3/3 | Complete | 2026-06-09 | -| 14. Anti-Detection Layer 2 — CAPTCHA Solving | v3.0 | 3/3 | Complete | 2026-06-09 | -| 15. Plugin Ecosystem Registry | v3.0 | 3/3 | Complete | 2026-06-09 | -| 16. Price Monitoring | v3.0 | 4/4 | Complete | 2026-06-10 | -| 17. Test Hardening | v3.0 | 4/4 | Complete | 2026-06-10 | -| 18. Safety Gate + Config Foundation | v4.0 | 4/4 | Complete | 2026-06-11 | -| 19. DB Schema + Confirmation Detection | v4.0 | 4/4 | Complete | 2026-06-11 | -| 20. Checkout Profile + Form-Fill | v4.0 | 4/4 | Complete | 2026-06-11 | -| 21. Per-Step Timeouts + Unified Retry + Cart-Retry | v4.0 | 4/4 | Complete | 2026-06-12 | -| 22. Supervisor + Browser Relaunch + Server Safety | v4.0 | 4/4 | Complete | 2026-06-12 | -| 23. Encrypted Session Persistence | v4.0 | 4/4 | Complete | 2026-06-12 | -| 24. Health Surface + Server Safety | v4.0 | 5/5 | Complete | 2026-06-12 | +| Milestone | Phases | Plans | Status | Shipped | +|-----------|--------|-------|--------|---------| +| v1 Open Source Launch | 1-6 | 28/28 | ✅ Shipped | 2026-06-03 | +| v2.0 Modular Core + Cross-Platform UX | 7-11 | 20/20 | ✅ Shipped | 2026-06-06 | +| v3.0 Resilience + Ecosystem | 12-17 | 21/21 | ✅ Shipped | 2026-06-10 | +| v4.0 Win-the-Drop | 18-24 | 29/29 | ✅ Shipped | 2026-06-25 | -All 66 v1+v2.0 requirements satisfied. v3.0: 18 requirements mapped across Phases 12-17. v4.0: 17 requirements mapped across Phases 18-24. +All requirements satisfied across v1 (44) + v2.0 (22) + v3.0 (18) + v4.0 (17). Per-milestone requirement detail in `.planning/milestones/v*-REQUIREMENTS.md`. --- -*Last updated: 2026-06-12 — Phase 24 planned (5 plans, 2 waves)* +*Last updated: 2026-06-25 — v4.0 Win-the-Drop shipped; ready for next milestone (`/gsd:new-milestone`).* diff --git a/.planning/STATE.md b/.planning/STATE.md index 2fb9cb6..05bd245 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,15 +2,15 @@ gsd_state_version: 1.0 milestone: v4.0 milestone_name: Win-the-Drop -status: verifying -last_updated: "2026-06-12T21:27:47.343Z" -last_activity: 2026-06-12 +status: Awaiting next milestone +last_updated: "2026-06-25T01:32:12.122Z" +last_activity: 2026-06-25 — Milestone v4.0 completed and archived progress: - total_phases: 13 + total_phases: 7 completed_phases: 7 total_plans: 29 completed_plans: 29 - percent: 54 + percent: 100 --- # ShopPyBot — State @@ -28,30 +28,30 @@ progress: ## Current Position -Phase: 24 -Plan: Not started -Status: Phase complete — ready for verification -Last activity: 2026-06-12 +Phase: Milestone v4.0 complete +Plan: — +Status: Awaiting next milestone +Last activity: 2026-06-25 — Milestone v4.0 completed and archived ## Phase Status | Phase | Goal Summary | Status | Reqs | |-------|-------------|--------|------| -| 18 — Safety Gate + Config Foundation | monitor-only mode + place_order_guarded() ABC + CheckoutConfig schema | Not started | BUY-01, BUY-02 | -| 19 — DB Schema + Confirmation Detection | order_id/confirmed_at columns + core/confirmation.py; purchased only on real order | Not started | BUY-03, BUY-04 | -| 20 — Checkout Profile + Form-Fill | 9-key CredentialStore profile; BestBuy + Amazon form-fill; CVV getpass-only | Not started | BUY-07 | -| 21 — Per-Step Timeouts + Unified Retry + Cart-Retry | core/retry.py RetryPolicy; per-step asyncio.timeout; idempotent cart-retry | Not started | BUY-05, BUY-06, REL-08 | +| 18 — Safety Gate + Config Foundation | monitor-only mode + place_order_guarded() ABC + CheckoutConfig schema | Complete | BUY-01, BUY-02 | +| 19 — DB Schema + Confirmation Detection | order_id/confirmed_at columns + core/confirmation.py; purchased only on real order | Complete | BUY-03, BUY-04 | +| 20 — Checkout Profile + Form-Fill | 9-key CredentialStore profile; BestBuy + Amazon form-fill; CVV getpass-only | Complete | BUY-07 | +| 21 — Per-Step Timeouts + Unified Retry + Cart-Retry | core/retry.py RetryPolicy; per-step asyncio.timeout; idempotent cart-retry | Complete | BUY-05, BUY-06, REL-08 | | 22 — Supervisor + Browser Relaunch + Server Safety | per-coroutine supervision; failure budget; full relaunch sequence; DB read isolation; SIGTERM bridge | Complete | REL-01, REL-02, REL-03, REL-05, REL-06, SRV-02 | -| 23 — Encrypted Session Persistence | core/session_store.py Fernet cookies; CDP restore path; replaces Phase 22 stub | In Progress (1/4 plans) | REL-04 | -| 24 — Health Surface + Server Safety | core/health.py HealthRegistry; get_status() expansion; health_degraded alert; pygame headless guard | Not started | REL-07, SRV-01 | +| 23 — Encrypted Session Persistence | core/session_store.py Fernet cookies; CDP restore path; replaces Phase 22 stub | Complete | REL-04 | +| 24 — Health Surface + Server Safety | core/health.py HealthRegistry; get_status() expansion; health_degraded alert; pygame headless guard | Complete | REL-07, SRV-01 | --- ## Performance Metrics -**Plans completed**: 20 of 20 -**Requirements completed**: SRV-02 (plus all prior phases) -**Phases completed**: 5 of 7 +**Plans completed**: 29 of 29 +**Requirements completed**: 17 of 17 (BUY-01..07, REL-01..08, SRV-01, SRV-02) +**Phases completed**: 7 of 7 **Blockers resolved**: 0 --- @@ -93,7 +93,8 @@ Last activity: 2026-06-12 ### Active Todos -- Run `/gsd:plan-phase 18` to begin Phase 18 planning +- v4.0 complete + archived. Run `/gsd:new-milestone` to scope the next cycle (phase numbering continues from 24). +- Operator: work the v4.0 live-UAT checklist (Deferred Items below) before the first production live-buy. ### Blockers @@ -115,6 +116,26 @@ Items acknowledged and deferred at v2.0 milestone close on 2026-06-05. All are l | uat | Phase 01 — 01-UAT.md | partial (0 pending) | | uat | Phase 19 — per-retailer confirmation selectors (Amazon + BestBuy) | UAT required before Phase 19 finalizes selectors | +### Acknowledged at v4.0 milestone close (2026-06-25) — 17 items + +All deferred per the autonomous live-UAT policy; none are code gaps. This is the operator's pre-production live-buy checklist. Source: `gsd-sdk query audit-open` at close. + +| Category | Item | Status | +|----------|------|--------| +| uat | Phase 18 — live `--monitor-only` run fires alerts but places no order (18-HUMAN-UAT.md) | partial (1 pending) | +| uat | Phase 19 — live Amazon/BestBuy confirmation URL + DOM order-number selectors (19-HUMAN-UAT.md) | partial (3 pending) | +| uat | Phase 20 — live BestBuy/Amazon shipping form-fill selectors + CVV entry (20-HUMAN-UAT.md) | partial (4 pending) | +| uat | Phase 21 — per-step timeout clean-abort under a real slow drop (21-HUMAN-UAT.md) | partial (2 pending) | +| uat | Phase 22 — live supervisor restart + browser relaunch + SIGTERM teardown (22-HUMAN-UAT.md) | partial (2 pending) | +| uat | Phase 23 — live cross-restart MFA/login-skip; persisted session accepted (23-HUMAN-UAT.md) | partial (2 pending) | +| uat | Phase 24 — live headless-server run, no audio device / pygame absent (24-HUMAN-UAT.md) | partial (1 pending) | +| verification | Phases 18-24 — VERIFICATION.md status `human_needed` (automated must-haves passed; live checks deferred) | human_needed (7) | +| todo | Amazon WAF CAPTCHA auto-solve wiring (waf-auto-solve-followup.md) | pending (medium); manual-pause fallback in place | +| seed | SEED-001 — public repo history scrub/squash before release | dormant (release milestone) | +| seed | SEED-002 — release-please automatic version tagging | dormant (release milestone) | + +**Tracked HIGH item (from audit):** Phase 21 place-order-stage timeout double-buy edge (placed-but-unconfirmed) — verify live and consider P22-style hardening. + --- | Phase 18 P02 | 267 | 2 tasks | 2 files | | Phase 18 P18-03 | 8m | 2 tasks | 6 files | @@ -335,4 +356,4 @@ Items acknowledged and deferred at v2.0 milestone close on 2026-06-05. All are l ## Operator Next Steps -- Run `/gsd:plan-phase 18` to begin Phase 18 (Safety Gate + Config Foundation) +- Start the next milestone with /gsd:new-milestone diff --git a/.planning/v4.0-MILESTONE-AUDIT.md b/.planning/milestones/v4.0-MILESTONE-AUDIT.md similarity index 100% rename from .planning/v4.0-MILESTONE-AUDIT.md rename to .planning/milestones/v4.0-MILESTONE-AUDIT.md diff --git a/.planning/milestones/v4.0-REQUIREMENTS.md b/.planning/milestones/v4.0-REQUIREMENTS.md new file mode 100644 index 0000000..e513e58 --- /dev/null +++ b/.planning/milestones/v4.0-REQUIREMENTS.md @@ -0,0 +1,92 @@ +# Requirements Archive: v4.0 Win-the-Drop + +**Archived:** 2026-06-25 +**Status:** SHIPPED + +For current requirements, see `.planning/REQUIREMENTS.md`. + +--- + +# ShopPyBot — Requirements + +**Current Milestone:** v4.0 Win-the-Drop (Acquisition Core + Reliability) +**Defined:** 2026-06-10 + +Prior milestone requirements (v1 44 + v2.0 22 + v3.0 18) are archived at +`.planning/milestones/v2.0-REQUIREMENTS.md` and `.planning/milestones/v3.0-REQUIREMENTS.md`. +This file scopes v4.0 only. + +--- + +## v4.0 Requirements (Active — Acquisition Core + Reliability) + +### Acquisition — Verified Checkout + +- [x] **BUY-01**: User can run the bot in a monitor-only mode (config flag and/or `--monitor-only`) that performs stock checks and fires alerts but never places an order, enforced once at the orchestrator before `auto_buy` so it applies to every plugin uniformly. +- [x] **BUY-02**: Every plugin routes its final place-order action through a single `place_order_guarded()` concrete method on the RetailerPlugin ABC that honors `test_mode`/monitor-only, so all 7 bundled plugins (and future community plugins) cannot place a live order under test/monitor mode by default. (Closes the confirmed hole where BestBuy and 5 others ignore `test_mode`.) +- [x] **BUY-03**: After `auto_buy` returns, the orchestrator verifies a real placed order using a primary confirmation-URL signal plus an order-number backup signal (with a settle delay), capturing the order id; `purchased` is written only on a confirmed order, never on a button click. +- [x] **BUY-04**: The bot records each checkout outcome (confirmed / failed / timed-out) with the captured order id and a timestamp in the database, providing the idempotency anchor and a basis for future outcome analytics. +- [x] **BUY-05**: On a non-confirmed checkout, the bot retries up to a configurable maximum with backoff, re-reading the persisted `purchased`/outcome state before each attempt so a succeeded-but-misdetected order is never re-submitted (no double-buy). +- [x] **BUY-06**: Each checkout runs under a per-step time budget with checkout-stage tracking and a hard per-item ceiling, so a slow step aborts cleanly (no half-submitted order, no orphaned browser state) rather than starving the drop window. +- [x] **BUY-07**: User can configure a shipping/billing profile that the bot fills during checkout on BestBuy and Amazon; payment uses the retailer-saved method plus CVV entered at runtime, and no full card number is persisted to disk or logs. + +### Always-On Reliability + +- [x] **REL-01**: A supervisor wraps each plugin task so an unhandled exception in one plugin is absorbed before the asyncio TaskGroup boundary and that plugin restarts with exponential backoff, while every other plugin keeps running. +- [x] **REL-02**: A plugin that exceeds a failure budget (N failures within a time window) is parked instead of crash-looping, and the operator is notified through the existing dispatcher. +- [x] **REL-03**: The bot detects a dead or disconnected Chrome process and cold-restarts that plugin's browser, re-applying stealth, proxy assignment, and login before resuming checks. +- [x] **REL-04**: User can opt in to encrypted session/cookie persistence so the bot restores browser cookies across restarts (skipping re-login/MFA); cookies are encrypted via the existing CredentialStore machinery (never plaintext) and restored via the CDP path that avoids the nodriver `set_all()` bug. +- [x] **REL-05**: Transient SQLite errors on the read path (item reads, notification-state reads, price reads) are caught and isolated so a single failed read degrades gracefully instead of crashing the poll loop. +- [x] **REL-06**: Each item's check/buy cycle runs under an overall orchestrator timeout, so a stalled page or a long captcha pause on one item cannot freeze the other items on that retailer. +- [x] **REL-07**: `BotService.get_status()` returns a structured per-plugin health surface (liveness, last-activity, last-error) queryable from the CLI and web UI, and sustained degradation is signaled through the notification dispatcher. +- [x] **REL-08**: Supervisor-restart (REL-01) and cart-retry (BUY-05) share one `RetryPolicy` implementation, so backoff behavior is defined in a single place and the two retry concepts cannot diverge or compound. + +### Server Safety (opportunistic) + +- [x] **SRV-01**: The sound notifier degrades to a silent no-op on a headless host with no audio device instead of crashing at import, so the bot runs unattended on a server. +- [x] **SRV-02**: SIGTERM and SIGINT trigger cooperative teardown (write-queue flush + browser teardown) so a container/systemd stop does not orphan Chrome; the signal bridge uses a platform-appropriate path (Windows has no `loop.add_signal_handler`). + +--- + +## Future Requirements (Deferred to v4.1+) + +- Request/API-mode (hybrid) checkout — faster than DOM, but per-site reverse-engineering and an arms race. +- Multi-account / multi-profile parallel attempts per item — most ToS-hostile; opt-in if ever. +- Checkout profile form-fill for the remaining 5 retailers (v4.0 covers BestBuy + Amazon). +- Richer health/observability on the web dashboard (beyond the CLI/status payload). +- Outcome analytics (success rate, time-to-checkout) built on the BUY-04 outcome records. + +--- + +## Out of Scope (v4.0) + +- Virtual-waiting-room / queue survival (Queue-it, PerimeterX press-and-hold, Akamai `_abck`, DataDome) — behavioral bot managers, not token CAPTCHAs; an arms race with no reliable open-source lever. +- Amazon WAF CAPTCHA auto-solve — re-deferred (`.planning/todos/pending/waf-auto-solve-followup.md`); manual-pause fallback remains. +- Storing full payment card / PAN anywhere — PCI scope; v4.0 relies on retailer-saved payment + CVV-at-runtime only. +- Captcha harvesting / solver farms. +- Public-release hardening (git-history scrub/squash, release-please tagging) — belongs to a dedicated release milestone (SEED-001, SEED-002). +- End-to-end live retail checkout tests in CI — legal/ToS risk; confirmation selectors are verified by manual UAT instead. + +--- + +## Traceability + +| Requirement | Phase | Status | +|-------------|-------|--------| +| BUY-01 | Phase 18 | Complete | +| BUY-02 | Phase 18 | Complete | +| BUY-03 | Phase 19 | Complete | +| BUY-04 | Phase 19 | Complete | +| BUY-05 | Phase 21 | Complete | +| BUY-06 | Phase 21 | Complete | +| BUY-07 | Phase 20 | Complete | +| REL-01 | Phase 22 | Complete | +| REL-02 | Phase 22 | Complete | +| REL-03 | Phase 22 | Complete | +| REL-04 | Phase 23 | Complete | +| REL-05 | Phase 22 | Complete | +| REL-06 | Phase 22 | Complete | +| REL-07 | Phase 24 | Complete | +| REL-08 | Phase 21 | Complete | +| SRV-01 | Phase 24 | Complete | +| SRV-02 | Phase 22 | Complete | diff --git a/.planning/milestones/v4.0-ROADMAP.md b/.planning/milestones/v4.0-ROADMAP.md new file mode 100644 index 0000000..bca98da --- /dev/null +++ b/.planning/milestones/v4.0-ROADMAP.md @@ -0,0 +1,427 @@ +# ShopPyBot — Roadmap + +## Project + +**Core Value:** A drop-in plugin framework that lets the community add new retail platform integrations by placing a single Python file in `plugins/` — no core changes required. + +--- + +## Milestones + +- ✅ **v1 Open Source Launch** — Phases 1-6 (shipped 2026-06-03) +- ✅ **v2.0 Modular Core + Cross-Platform UX** — Phases 7-11 (shipped 2026-06-06) +- ✅ **v3.0 Resilience + Ecosystem** — Phases 12-17 (shipped 2026-06-10) +- **v4.0 Win-the-Drop (Acquisition Core + Reliability)** — Phases 18-24 (in progress) + +--- + +## Phases + +
+✅ v1 Open Source Launch (Phases 1-6) — SHIPPED 2026-06-03 + +- [x] Phase 1: Foundations + Security (5/5 plans) — 2026-06-02 +- [x] Phase 2: Plugin Migration (6/6 plans) — 2026-06-03 +- [x] Phase 3: Community Documentation (2/2 plans) — 2026-06-03 +- [x] Phase 4: Async Orchestrator (5/5 plans) — 2026-06-03 +- [x] Phase 5: Notification System (5/5 plans) — 2026-06-03 +- [x] Phase 6: Platform Expansion (5/5 plans) — 2026-06-03 + +
+ +
+✅ v2.0 Modular Core + Cross-Platform UX (Phases 7-11) — SHIPPED 2026-06-06 + +- [x] Phase 7: Modular Core Service (3/3 plans) — 2026-06-04 +- [x] Phase 8: Credential Store (4/4 plans) — 2026-06-04 +- [x] Phase 9: CLI Front-End (4/4 plans) — 2026-06-04 +- [x] Phase 10: Optional Web UI (4/4 plans) — 2026-06-04 +- [x] Phase 11: Cross-Platform Verification (5/5 plans) — 2026-06-05 + +Full phase detail archived at `.planning/milestones/v2.0-ROADMAP.md`. +Audit: `.planning/milestones/v2.0-MILESTONE-AUDIT.md` (status: passed). + +
+ +
+✅ v3.0 Resilience + Ecosystem (Phases 12-17) — SHIPPED 2026-06-10 + +- [x] **Phase 12: Stability Foundation** — Close v2.0 deferred cross-OS checks and resolve 4 audit tech-debt items (completed 2026-06-09) +- [x] **Phase 13: Anti-Detection Layer 1 — Fingerprint + Proxy** — Apply JS fingerprint stealth patch and implement proxy rotation with ban detection (completed 2026-06-09) +- [x] **Phase 14: Anti-Detection Layer 2 — CAPTCHA Solving** — Integrate 2captcha opt-in solver with CredentialStore key, startup balance check, async executor wrapping, and spend cap (completed 2026-06-09) +- [x] **Phase 15: Plugin Ecosystem Registry** — Add difficulty/proxy/captcha class attrs to ABC, create GitHub wiki registry table, ship `shoppybot plugins list` command (completed 2026-06-09) +- [x] **Phase 16: Price Monitoring** — Per-item target price, append-only price history table, percentage-drop trigger, fan-out price-drop alerts, price-history CLI (completed 2026-06-10) +- [x] **Phase 17: Test Hardening** — Unit and integration coverage for all v3.0 features (completed 2026-06-10) + +Full phase detail archived in `.planning/milestones/v3.0-ROADMAP.md`. + +
+ +### v4.0 Win-the-Drop (Phases 18-24) + +- [x] **Phase 18: Safety Gate + Config Foundation** — Central monitor-only mode, `place_order_guarded()` ABC method closing the 6-of-7 plugin safety hole, and `CheckoutConfig` schema as the foundation every downstream phase depends on (completed 2026-06-11) +- [x] **Phase 19: DB Schema + Confirmation Detection** — Add `order_id`/`confirmed_at`/`checkout_attempts` columns and build `core/confirmation.py` so `purchased` is only written on a real confirmed order number, never on a button click (completed 2026-06-11) +- [x] **Phase 20: Checkout Profile + Form-Fill** — Shipping/billing profile stored in CredentialStore (9 keys, no card data), BestBuy and Amazon form-fill, CVV getpass-only at runtime (completed 2026-06-11) +- [x] **Phase 21: Per-Step Timeouts + Unified Retry + Cart-Retry** — One `RetryPolicy` in `core/retry.py` shared by both supervisor restart and cart-retry; per-step `asyncio.timeout()` per DOM stage; idempotency guard reads DB before every attempt (completed 2026-06-12) +- [x] **Phase 22: Supervisor + Browser Relaunch + Server Safety** — Per-coroutine supervision with failure budget absorbs crashes before the TaskGroup boundary; full relaunch sequence (teardown, proxy, stealth, login); DB read isolation; per-item orchestrator timeout; SIGTERM/SIGINT teardown bridge (completed 2026-06-12) +- [x] **Phase 23: Encrypted Session Persistence** — Fernet-encrypted cookie save/restore via `core/session_store.py` (reuses `EncryptedFileBackend` pattern); raw CDP restore path that bypasses the confirmed `set_all()` bug; replaces Phase 22's no-op stub (completed 2026-06-12) +- [x] **Phase 24: Health Surface + Server Safety** — `core/health.py` HealthRegistry, expanded `BotService.get_status()` with per-plugin liveness/heartbeat, `health_degraded` notification event, updated FastAPI `/status` endpoint, headless pygame crash guard (completed 2026-06-12) + +--- + +## Phase Details + +### Phase 12: Stability Foundation + +**Goal**: The v2.0 deferred debt and audit tech-debt are paid down before new features land, so the test suite is a reliable baseline +**Depends on**: Nothing — do first +**Requirements**: STAB-01, STAB-02 +**Success Criteria** (what must be TRUE): + + 1. All 4 deferred v2.0 cross-OS/UI manual checks (keyring restart survival, masked-TTY passphrase prompt, web dashboard render on Ubuntu, `0.0.0.0` bind warning) are executed and documented pass or fail, with any failures fixed + 2. Each of the 4 v2.0 audit tech-debt items has a targeted regression test that passes in CI + 3. No broad refactors occur: only the specific items in scope are changed + +**Plans**: 4 plans + +Plans: + +- [x] 12-01-PLAN.md — TD-1: re-anchor logger logging_level read to core.paths.config_path() + regression test +- [x] 12-02-PLAN.md — TD-2/TD-3: harden SC1 secret-read guard (rglob) and separator guard (__file__-anchored) +- [x] 12-03-PLAN.md — TD-4 config write-seam regression test + accepted MOD-02 gap doc; MC-4 0.0.0.0 banner assertion +- [x] 12-04-PLAN.md — Execute and document MC-1..MC-4 deferred manual checks in docs/PLATFORMS.md + +### Phase 13: Anti-Detection Layer 1 — Fingerprint + Proxy + +**Goal**: Users can enable proxy rotation and the bot applies a JS fingerprint stealth patch at browser startup, measurably reducing Layer 2 bot signals +**Depends on**: Phase 12 +**Requirements**: ANTI-08, ANTI-04, ANTI-05 +**Success Criteria** (what must be TRUE): + + 1. Bot applies `window.chrome`, `navigator.plugins`, `navigator.languages`, and screen-dimension patches via `core/stealth.py` at every browser startup with no plugin ABC version bump + 2. User can enable proxy rotation via an opt-in `proxy:` config section (disabled by default) listing `scheme://host:port` URLs; bot logs "Proxy rotation: enabled, pool_size=N" at startup + 3. Bot detects ban signals (HTTP 403/429/503, challenge-redirect, block-phrase body) and rotates to the next proxy, retiring a proxy after N consecutive failures for a configurable cooldown period + 4. WebRTC Chrome preferences are set at browser launch to prevent real-IP leaks through the proxy tunnel + 5. Each proxy is scoped to its plugin instance (`self._proxy`) and rotated only at browser restart, not mid-session + +**Plans**: 3 plans + +Plans: + +- [x] 13-01-PLAN.md — core/stealth.py: STEALTH_JS + apply_stealth, ProxyPool (round-robin/retire/cooldown), proxy launch args + WebRTC flag, CDP Fetch auth, ban-signal detector (+ unit tests) +- [x] 13-02-PLAN.md — ProxyConfig schema (opt-in, disabled by default) + documented sample.config.yml proxy section +- [x] 13-03-PLAN.md — Wire stealth + proxy into BotService/orchestrator/registry and all 8 plugins; per-instance scoping, exact startup log, fail-loud on pool exhaustion, ban-detect recording + +**UI hint**: no + +### Phase 14: Anti-Detection Layer 2 — CAPTCHA Solving + +**Goal**: Users who encounter reCAPTCHA v2 or Amazon WAF CAPTCHAs can opt into automated solving via 2captcha with full cost visibility and no credential plaintext exposure +**Depends on**: Phase 13 (fingerprint + proxy layer in place before adding CAPTCHA layer) +**Requirements**: ANTI-06, ANTI-07 +**Success Criteria** (what must be TRUE): + + 1. User can enable CAPTCHA solving via `captcha.enabled: true` in config; the 2captcha API key is stored exclusively in CredentialStore (`TWOCAPTCHA_API_KEY`), never in config.yml + 2. Bot checks 2captcha account balance at startup, logs a WARNING when balance is low, and skips solver use (falling back to manual pause) when balance is zero + 3. CAPTCHA solve calls use `run_in_executor` + `asyncio.timeout(120)` so other plugin poll tasks are not blocked during a solve + 4. A configurable `captcha.max_solves_per_run` limit prevents unbounded API charges; default config disables CAPTCHA solving + +**Plans**: 3 plans + +Plans: + +- [x] 14-01-PLAN.md — Foundation: TWOCAPTCHA_API_KEY in SECRET_KEYS, CaptchaConfig, CaptchaSolver 2captcha v1 client (submit/poll/balance/cap) +- [x] 14-02-PLAN.md — Wiring: solver constructed fresh in async_main + startup balance check + registry.assign_solver (mirrors ProxyPool) +- [x] 14-03-PLAN.md — Plugin solve path: Amazon + BestBuy reCAPTCHA solve under run_in_executor+timeout(120) with manual-pause fallback; WAF deferred + +### Phase 15: Plugin Ecosystem Registry + +**Goal**: Community contributors have a discoverable registry with clear difficulty ratings, and users can inspect loaded plugins locally without a network call +**Depends on**: Phase 12 +**Requirements**: REG-01, REG-02, REG-03, REG-04 +**Success Criteria** (what must be TRUE): + + 1. Plugin authors can declare `difficulty`, `requires_proxy`, and `requires_captcha` as class attributes on any plugin; existing plugins without these attrs continue to load with sensible defaults (non-breaking) + 2. The GitHub wiki registry table contains required fields for each community plugin: name, platform, domain patterns, maintainer, anti-detection difficulty, methods implemented, last-verified date, proxy-required, captcha-required + 3. Running `shoppybot plugins list` displays all locally loaded plugins with their declared domain patterns, difficulty, and proxy/captcha flags without making a network call + 4. CONTRIBUTING.md and the PR template require contributors to supply `difficulty`, `requires_proxy`, and `requires_captcha` for new plugin submissions + +**Plans**: 3 plans + +Plans: + +- [x] 15-01-PLAN.md — REG-02: add difficulty/requires_proxy/requires_captcha class attrs + __init_subclass__ difficulty validation to RetailerPlugin ABC (non-breaking, PLUGIN_API_VERSION stays 2) + test_plugin_base.py assertions +- [x] 15-02-PLAN.md — REG-03: BotService.list_plugins() over registry._all_plugins + core/cli/plugins.py handler + plugins-list subparser with --json + no-network CLI tests +- [x] 15-03-PLAN.md — REG-01/REG-04: docs/PLUGIN_REGISTRY.md 9-field wiki SPEC + CONTRIBUTING.md/PR-template/PLUGIN_DEV.md attr requirements + tests/test_docs.py + +### Phase 16: Price Monitoring + +**Goal**: Users can track per-item prices, receive fan-out alerts when prices drop to target or by a configured percentage, and inspect price history from the CLI +**Depends on**: Phase 12 +**Requirements**: PRICE-01, PRICE-02, PRICE-03, PRICE-04, PRICE-05, PRICE-06 +**Success Criteria** (what must be TRUE): + + 1. User can set `target_price` (absolute) and `price_drop_pct` (percentage) per item in config; NULL/absent means price monitoring is off for that item + 2. Bot records scraped prices in an append-only `price_history` SQLite table each poll cycle via an optional `get_price()` plugin ABC hook (default returns `None`); the DB migration is idempotent on existing installs + 3. Price-drop alerts are dispatched through the existing fan-out notification dispatcher using a distinct `price_drop` notification_type with dedup columns separate from stock alert columns + 4. Price alert payloads include the current price, target price, and percentage from target + 5. Running `shoppybot items price-history ` displays the last N recorded prices for that item + +**Plans**: 4 plans + +Plans: + +- [x] 16-01-PLAN.md — Data layer: idempotent price_history table + 4 items columns + 8 parameterized price _sync functions + ItemConfig target_price/price_drop_pct (PRICE-01/02/05) +- [x] 16-02-PLAN.md — Plugin + notification contract: NotificationEvent price fields, default-None get_price() ABC hook, real Amazon get_price() + text→cents parser, price_drop notifier branches (PRICE-02/04) +- [x] 16-03-PLAN.md — Orchestrator wiring: _check_and_buy price path, both triggers with separate dedup, single price_drop dispatch, startup config seeding + BotService.get_price_history (PRICE-02/03/04/05) +- [x] 16-04-PLAN.md — CLI: shoppybot items price-history leaf with --limit (default 10), $X.XX table, no network (PRICE-06) + +**UI hint**: yes + +### Phase 17: Test Hardening + +**Goal**: Every new v3.0 feature has unit and integration coverage so regressions are caught by CI before they reach users +**Depends on**: Phases 13, 14, 15, 16 (tests validate the implemented features) +**Requirements**: STAB-03 +**Success Criteria** (what must be TRUE): + + 1. Unit tests cover proxy config parsing, ban-signal detection logic, per-instance proxy scoping, and cooldown/retire logic + 2. Unit tests cover CAPTCHA config parsing, balance-check behavior, executor wrapping, and spend-cap enforcement + 3. Unit tests cover price comparison threshold logic, `price_history` DB schema (including idempotent migration against a v2.0 DB fixture), and price-drop dedup separation from stock-alert dedup + 4. Integration tests cover the plugin ABC additions (`difficulty`, `requires_proxy`, `requires_captcha` defaults and overrides) and the `get_price()` hook being called alongside `check_availability` + +**Plans**: 4 plans + +Plans: + +- [x] 17-01-PLAN.md — Proxy coverage: PX-01..PX-06 (config validator, fetch-handler tasks, ProxyPool edges, registry routing/lifecycle isolation) +- [x] 17-02-PLAN.md — CAPTCHA coverage: CP-01..CP-05 (poll/timeout errors, balance gate, solve_amazon_waf submit/poll/decode) +- [x] 17-03-PLAN.md — Price + get_price integration: PR-01..PR-04 + AB-01, AB-02 (v2.0-schema migration fixture, trigger guards, get_price-alongside-check_availability) +- [x] 17-04-PLAN.md — Plugin ABC: AB-03, AB-04 (metadata overrides + _handle_ban ban→proxy-cooldown bridge) + +--- + +### Phase 18: Safety Gate + Config Foundation + +**Goal**: Every plugin routes its final place-order action through an ABC-enforced gate that honors monitor-only mode, so no plugin — current or future — can place a live order when monitoring is active +**Depends on**: Nothing (do first; all downstream v4.0 phases depend on this config foundation) +**Requirements**: BUY-01, BUY-02 +**Success Criteria** (what must be TRUE): + + 1. User can start the bot with `--monitor-only` CLI flag or `debug.monitor_only: true` in config; bot performs stock checks and fires alerts but `auto_buy` is never called for any plugin + 2. All 7 bundled plugins route their place-order DOM click through `place_order_guarded()` on the RetailerPlugin ABC; a CI test with all 7 plugins and `monitor_only=True` asserts zero calls to the purchase write-queue + 3. BestBuy's confirmed `test_mode` gap is closed: `place_order.click()` is not called when `monitor_only=True` or `test_mode=True` on any plugin + 4. `CheckoutConfig` sub-model exists in `AppConfig` with `item_timeout_secs`, `step_timeout_secs`, `max_cart_retries`, `backoff_base`, `backoff_jitter`, and `alert_on_errors` fields so downstream phases can use them without schema changes + +**Plans**: 4 plans + +Plans: + +**Wave 1** + +- [x] 18-01-PLAN.md — DebugConfig.monitor_only + CheckoutConfig model + AppConfig wiring (BUY-01, BUY-02) +- [x] 18-02-PLAN.md — place_order_guarded() concrete method on RetailerPlugin ABC + unit tests (BUY-02) + +**Wave 2** *(blocked on Wave 1 completion)* + +- [x] 18-03-PLAN.md — orchestrator monitor_only gate + --monitor-only CLI flag + CVV short-circuit + ALLOWLIST (BUY-01) +- [x] 18-04-PLAN.md — reroute all 7 plugins through place_order_guarded + test_safety_gate.py (7-plugin zero-write + grep) (BUY-02) + +### Phase 19: DB Schema + Confirmation Detection + +**Goal**: Purchases are only recorded when the bot has verified a real order number from the retailer's confirmation page, never on a button click alone +**Depends on**: Phase 18 (monitor-only gate must be live before any live checkout UAT of confirmation selectors) +**Requirements**: BUY-03, BUY-04 +**Success Criteria** (what must be TRUE): + + 1. The `items` table has `order_id TEXT`, `confirmed_at TEXT`, and `checkout_attempts INTEGER DEFAULT 0` columns added via idempotent `ALTER TABLE` (same pattern as v3.0 price columns); existing DB installs migrate without data loss + 2. After `auto_buy()` returns, the orchestrator calls `detect_order_confirmation(tab, platform)` and only enqueues `("confirmed", link, order_id, ts)` to the write-queue when a non-None order_id is returned; `purchased=1` is set only at that point + 3. When confirmation is not detected, the bot logs a WARNING and falls back to the legacy `purchased` write tag (no silent failure, no double-buy risk from the confirmation path itself) + 4. Each confirmed checkout writes `order_id` and `confirmed_at` to the DB, providing the idempotency anchor for retry (Phase 21) to read before any re-attempt + +**Plans**: 4 plans + +Plans: + +**Wave 1** *(parallel-safe; no file overlap)* + +- [x] 19-01-PLAN.md — models.py: 3 idempotent confirmation columns (order_id/confirmed_at/checkout_attempts DEFAULT 0, NOT incremented) + update_item_confirmed_sync (BUY-04) +- [x] 19-02-PLAN.md — core/confirmation.py NEW: detect_order_confirmation (URL-first/DOM-backup map, ~3s settle, Amazon orderID URL-param parse, CONFIRMED- sentinel) + FakeTab tests (BUY-03) +- [x] 19-03-PLAN.md — core/plugin_base.py: additive sync get_active_tab() ABC default (returns main_tab; PLUGIN_API_VERSION stays 2) (BUY-03) + +**Wave 2** *(blocked on Wave 1)* + +- [x] 19-04-PLAN.md — orchestrator wiring (_try_auto_buy detect + confirmed/legacy fallback outside any timeout; _dispatch_write confirmed branch) + Amazon/BestBuy _last_tab + get_active_tab override + orchestrator tests (BUY-03, BUY-04) + +**Research flag** (RESOLVED via 19-RESEARCH.md): per-retailer confirmation URL patterns (Amazon `/gp/buy/thankyou`, BestBuy `/checkout/r/thank-you`) are HIGH confidence and hardcoded in `core/confirmation.py`; backup DOM selectors (`#confirmedOrderId`, `.thank-you-order-number`) are MEDIUM confidence — live UAT on a test_mode buy is tracked as UAT debt (STATE.md Deferred Items). + +### Phase 20: Checkout Profile + Form-Fill + +**Goal**: Users can configure a shipping/billing profile that the bot fills during BestBuy and Amazon checkout, with payment using the retailer-saved method plus CVV entered at runtime and no full card data persisted anywhere +**Depends on**: Phase 18 (monitor-only gate required before any form-fill can be tested live); Phase 19 (confirmation detection should precede form-fill so a completed form-fill can be confirmed) +**Requirements**: BUY-07 +**Success Criteria** (what must be TRUE): + + 1. User can run `shoppybot setup checkout-profile` to interactively populate 9 address keys (`CHECKOUT_FIRST_NAME`, `CHECKOUT_LAST_NAME`, `CHECKOUT_ADDRESS_LINE1`, `CHECKOUT_ADDRESS_LINE2`, `CHECKOUT_CITY`, `CHECKOUT_STATE`, `CHECKOUT_ZIP`, `CHECKOUT_COUNTRY`, `CHECKOUT_PHONE`) in the CredentialStore; no card number or CVV is stored + 2. BestBuy and Amazon plugins fill the shipping form fields from the `CheckoutProfile` loaded at plugin setup time; CVV is provided via `getpass` at runtime only + 3. A CI grep assertion confirms no `_cvv` value appears in any `writeLog()` call argument on checkout code paths + 4. If a shipping form field selector returns None (DOM drift), the plugin logs a WARNING with the selector name and returns False without submitting an incomplete form + +**Plans**: 4 plans + +Plans: + +**Wave 1** *(parallel-safe; no file overlap)* + +- [x] 20-01-PLAN.md — core/checkout_profile.py: CHECKOUT_PROFILE_KEYS (9, NOT in SECRET_KEYS) + CheckoutProfile model + load_checkout_profile() incomplete detection + tests (BUY-07) +- [x] 20-02-PLAN.md — `setup checkout-profile` CLI: visible-prompt 9 keys, key-NAME-only output, optional ADDRESS_LINE2, no card/CVV stored (BUY-07) +- [x] 20-03-PLAN.md — CVV threading: Amazon __init__ _cvv=None + orchestrator amz injection (mirrors BestBuy 411-414) + run.py needs_cvv includes amazon.com (BUY-07) + +**Wave 2** *(blocked on 20-01 + 20-03)* + +- [x] 20-04-PLAN.md — Form-fill: _checkout_profile load at setup() + _fill_field + BestBuy shipping fill before place_order_guarded (missing-selector WARN+False) + Amazon CVV skip-if-absent + CVV-not-in-logs AST test (BUY-07) + +### Phase 21: Per-Step Timeouts + Unified Retry + Cart-Retry + +**Goal**: Checkout attempts are bounded in time and retries, and all retry/backoff logic flows through one shared `RetryPolicy` so supervisor restarts and cart retries cannot compound into a runaway loop +**Depends on**: Phase 18 (CheckoutConfig fields), Phase 19 (DB `order_id` idempotency anchor must exist before retry reads it) +**Requirements**: BUY-05, BUY-06, REL-08 +**Success Criteria** (what must be TRUE): + + 1. `core/retry.py` contains a single `RetryPolicy` dataclass and `with_retry()` async helper; both supervisor restart (Phase 22) and cart-retry use this module; a CI grep assertion confirms no standalone `for attempt in range(N)` retry loops exist outside `core/retry.py` + 2. Each checkout DOM step (navigate, add-to-cart, checkout-proceed, CVV entry, place-order click, confirmation wait) runs under its own `asyncio.timeout(step_timeout_secs)` context manager; the entire `auto_buy()` method is NOT wrapped in a single outer timeout + 3. A `checkout_stage` variable tracks progress within `auto_buy()`; on `CancelledError` the stage is logged for post-mortem and the item is not immediately re-submitted + 4. Cart-retry reads the DB `order_id` column before each attempt; if a prior attempt already wrote a confirmed order, the retry loop exits immediately without re-submitting + 5. Cart-retry is bounded by `CheckoutConfig.max_cart_retries` (default 3) with exponential backoff; the retry never re-enters the place-order click stage on an already-attempted order + +**Plans**: 4 plans + +Plans: + +**Wave 1** *(parallel-safe; no file overlap)* + +- [x] 21-01-PLAN.md — core/retry.py NEW: RetryPolicy dataclass + pure compute_delay (seedable jitter) + with_retry async helper; tests/test_no_retry_loops.py AST guard (no `for attempt in range(` outside core/retry.py) (REL-08) +- [x] 21-02-PLAN.md — models.py: increment_checkout_attempts_sync (+1 per call) + get_item_order_state_sync (purchased, order_id idempotency anchor); no schema change (BUY-05) +- [x] 21-03-PLAN.md — per-step asyncio.timeout: self._checkout_stage default on RetailerPlugin ABC + 6 Amazon / 8 BestBuy DOM stages each under their own asyncio.timeout(step_timeout_secs); no outer timeout; per-item ceiling deferred to P22 (BUY-06) + +**Wave 2** *(blocked on 21-01 + 21-02 + 21-03)* + +- [x] 21-04-PLAN.md — orchestrator cart-retry: extract _attempt_buy(plugin, link)->(bool, str|None) + with_retry/RetryPolicy from CheckoutConfig; DB re-read + checkout_attempts increment before each attempt; confirmed order_id short-circuit (no double-buy); single enqueue outside loop (BUY-05, REL-08) + +**Research flag** (RESOLVED via 21-CONTEXT.md + 21-RESEARCH.md): the `checkout_attempts` increment strategy is resolved — increment once per retry ATTEMPT, BEFORE each attempt (not per-cart-add, not confirmed-only). max_cart_retries semantics documented: it is the number of RETRIES after the first attempt, so total attempts = 1 + max_cart_retries (max_cart_retries=0 → single attempt, no retry). + +### Phase 22: Supervisor + Browser Relaunch + Server Safety + +**Goal**: A single plugin crash or browser death cannot take down the rest of the bot; plugins restart automatically with backoff and full stealth/proxy/login restoration; the bot shuts down cleanly on SIGTERM +**Depends on**: Phase 18 (CheckoutConfig for alert_on_errors), Phase 21 (RetryPolicy from core/retry.py; supervisor reuses it) +**Requirements**: REL-01, REL-02, REL-03, REL-05, REL-06, SRV-02 +**Success Criteria** (what must be TRUE): + + 1. An unhandled exception in one plugin's `run_plugin` coroutine is absorbed by the supervisor before the `asyncio.TaskGroup` boundary; all other plugin coroutines keep running (verified by a test that crashes one plugin and asserts others continue) + 2. A plugin that exceeds N failures within a time window is parked (no further restart attempts) and the operator receives a notification through the existing dispatcher + 3. On a dead or disconnected Chrome process, the supervisor calls `plugin.relaunch()` which executes the full sequence: teardown, assign_proxy, setup (new browser + stealth + proxy auth), restore_session (no-op stub until Phase 23), login; `apply_stealth` is verified called on the relaunched browser + 4. Transient `sqlite3.OperationalError` (locked DB) on any `run_in_executor` read path in `run_plugin` is caught and isolated: the poll cycle is skipped, not terminated + 5. Each item's check/buy cycle runs under `asyncio.timeout(item_timeout_secs)`; the `write_queue.put()` calls are placed OUTSIDE the timeout context so a timed-out item cannot orphan a pending DB write + 6. SIGTERM and SIGINT trigger cooperative teardown (write-queue flush + browser teardown) via a platform-appropriate signal bridge (`sys.platform` branch handles Windows `NotImplementedError` on `loop.add_signal_handler`) + +**Plans**: 4 plans + +Plans: + +**Wave 1** *(parallel-safe; disjoint file)* + +- [x] 22-01-PLAN.md — core/plugin_base.py: concrete relaunch() (teardown→setup→restore_session→login; stealth re-injected via setup) + restore_session() no-op stub returns False; PLUGIN_API_VERSION stays 2 (REL-03) + +**Wave 2** *(orchestrator.py edits serialize — same-file, no parallel)* + +- [x] 22-02-PLAN.md — run_plugin hardening: cfg param + sqlite3.OperationalError read isolation on items read + per-item asyncio.timeout(item_timeout_secs); write_queue.put stays outside (REL-05, REL-06) + +**Wave 3** *(blocked on 22-01 + 22-02)* + +- [x] 22-03-PLAN.md — supervise() wrapper + _is_browser_dead_exc + failure budget (alert_on_errors / 600s deque) + park notify + browser-dead assign_proxy→relaunch + async_main create_task wiring (REL-01, REL-02) + +**Wave 4** *(blocked on 22-03)* + +- [x] 22-04-PLAN.md — _register_signals (POSIX add_signal_handler / Windows signal.signal fallback) + _flush_write_queue manual drain + async_main signal registration + pre-teardown flush (SRV-02) + +**Research flag** (RESOLVED via 22-RESEARCH.md): the nodriver stealth-persistence question is answered — `add_script_to_evaluate_on_new_document` is a per-session CDP command that is NOT persisted across `Browser.stop()` + `Browser.create()`; every plugin’s setup() re-injects stealth via apply_stealth, so relaunch() calling setup() is sufficient (HIGH confidence, confirmed against installed nodriver 0.50.3 source). + +### Phase 23: Encrypted Session Persistence + +**Goal**: Users can opt into encrypted cookie persistence so the bot skips re-login and MFA across restarts without storing any auth material in plaintext +**Depends on**: Phase 22 (supervisor calls `restore_session` on relaunch; Phase 22 ships a no-op stub that this phase replaces) +**Requirements**: REL-04 +**Success Criteria** (what must be TRUE): + + 1. When `platforms..session_persistence: true`, cookies are saved after successful login via `core/session_store.py` using Fernet encryption (same scrypt KDF as `EncryptedFileBackend`); no plaintext `.json` or `.pickle` file is written to disk + 2. On bot restart or plugin relaunch, cookies are restored via raw CDP `cdp.storage.set_cookies()` (bypassing the confirmed `CookieJar.set_all()` bug); the restore path returns `True` if a session file existed, `False` otherwise (no crash if file is absent) + 3. The `data/sessions/` directory is in `.gitignore`; a CI check confirms no session file pattern matches are committed + 4. The Phase 22 no-op `restore_session` stub in `plugin.relaunch()` is replaced by the live `SessionStore.restore()` call + +**Plans**: TBD +**Research flag**: NEEDS PLAN-PHASE RESEARCH — `nodriver cdp.storage.set_cookies()` exact import path and `CookieParam` constructor signature should be verified against the installed `nodriver==0.50.3` package before implementing the restore path. The workaround is confirmed from issues #1816/#2020 but the exact API shape needs local verification. + +### Phase 24: Health Surface + Server Safety + +**Goal**: Operators can query per-plugin liveness and error state from the CLI or web UI, receive alerts when a plugin degrades, and run the bot headlessly on a server without a pygame import crash +**Depends on**: Phases 22 and 23 (health surface reads from supervisor + session state; SRV-01 is self-contained but grouped here as a low-dependency finish item) +**Requirements**: REL-07, SRV-01 +**Success Criteria** (what must be TRUE): + + 1. `BotService.get_status()` returns a structured dict including `{"running": bool, "uptime_secs": float, "plugins": {name: {"status": str, "last_heartbeat": float, "consecutive_errors": int, "items_checked": int, "orders_confirmed": int}}}` queryable from CLI (`shoppybot status`) and the FastAPI `/status` endpoint + 2. When a plugin's `consecutive_errors` exceeds the configured `alert_on_errors` threshold, a `health_degraded` event is dispatched through the existing notification fan-out channels + 3. On a headless host with no audio device, the sound notifier degrades to a silent no-op at import time rather than crashing; the bot starts and runs normally without pygame + +**Plans**: 5 plans + +Plans: + +**Wave 1** *(parallel-safe; disjoint files)* + +- [x] 24-01-PLAN.md — core/health.py HealthRegistry (per-plugin status/heartbeat/consecutive_errors/items_checked/orders_confirmed) + JSON-safe snapshot + in-memory armed/disarmed dedup + tests (REL-07) +- [x] 24-02-PLAN.md — utils.py pygame headless guard: _initialize_audio()/_AUDIO_AVAILABLE, play_sound no-op when no device, redundant mixer.init removed + tests (SRV-01) + +**Wave 2** *(blocked on 24-01; disjoint files service/orchestrator/cli)* + +- [x] 24-03-PLAN.md — core/service.py get_status() locked shape {running,uptime_secs,plugins{...}} + _start_time uptime + single HealthRegistry ref wired into async_main; /status endpoint unchanged + JSON-serializable test (REL-07) +- [x] 24-04-PLAN.md — core/orchestrator.py wiring: health=None kwarg through async_main/supervise/run_plugin; heartbeat/items_checked/status transitions/orders_confirmed; health_degraded fire-once+re-arm dedup via existing dispatcher, distinct from plugin_parked + tests (REL-07) +- [x] 24-05-PLAN.md — core/cli/status.py shoppybot status subcommand (per-plugin table + --json, no network, in-process-state note) + subparser registration + tests (REL-07) + +**UI hint**: yes + +--- + +## Progress + +| Phase | Milestone | Plans | Status | Completed | +|-------|-----------|-------|--------|-----------| +| 1. Foundations + Security | v1 | 5/5 | Complete | 2026-06-02 | +| 2. Plugin Migration | v1 | 6/6 | Complete | 2026-06-03 | +| 3. Community Documentation | v1 | 2/2 | Complete | 2026-06-03 | +| 4. Async Orchestrator | v1 | 5/5 | Complete | 2026-06-03 | +| 5. Notification System | v1 | 5/5 | Complete | 2026-06-03 | +| 6. Platform Expansion | v1 | 5/5 | Complete | 2026-06-03 | +| 7. Modular Core Service | v2.0 | 3/3 | Complete | 2026-06-04 | +| 8. Credential Store | v2.0 | 4/4 | Complete | 2026-06-04 | +| 9. CLI Front-End | v2.0 | 4/4 | Complete | 2026-06-04 | +| 10. Optional Web UI | v2.0 | 4/4 | Complete | 2026-06-04 | +| 11. Cross-Platform Verification | v2.0 | 5/5 | Complete | 2026-06-05 | +| 12. Stability Foundation | v3.0 | 4/4 | Complete | 2026-06-09 | +| 13. Anti-Detection Layer 1 — Fingerprint + Proxy | v3.0 | 3/3 | Complete | 2026-06-09 | +| 14. Anti-Detection Layer 2 — CAPTCHA Solving | v3.0 | 3/3 | Complete | 2026-06-09 | +| 15. Plugin Ecosystem Registry | v3.0 | 3/3 | Complete | 2026-06-09 | +| 16. Price Monitoring | v3.0 | 4/4 | Complete | 2026-06-10 | +| 17. Test Hardening | v3.0 | 4/4 | Complete | 2026-06-10 | +| 18. Safety Gate + Config Foundation | v4.0 | 4/4 | Complete | 2026-06-11 | +| 19. DB Schema + Confirmation Detection | v4.0 | 4/4 | Complete | 2026-06-11 | +| 20. Checkout Profile + Form-Fill | v4.0 | 4/4 | Complete | 2026-06-11 | +| 21. Per-Step Timeouts + Unified Retry + Cart-Retry | v4.0 | 4/4 | Complete | 2026-06-12 | +| 22. Supervisor + Browser Relaunch + Server Safety | v4.0 | 4/4 | Complete | 2026-06-12 | +| 23. Encrypted Session Persistence | v4.0 | 4/4 | Complete | 2026-06-12 | +| 24. Health Surface + Server Safety | v4.0 | 5/5 | Complete | 2026-06-12 | + +All 66 v1+v2.0 requirements satisfied. v3.0: 18 requirements mapped across Phases 12-17. v4.0: 17 requirements mapped across Phases 18-24. + +--- + +*Last updated: 2026-06-12 — Phase 24 planned (5 plans, 2 waves)* From 7b00e69e03d0103a37538e0bf95728babe978133 Mon Sep 17 00:00:00 2001 From: Zoid Date: Wed, 24 Jun 2026 21:39:55 -0400 Subject: [PATCH 2/3] chore: remove REQUIREMENTS.md for v4.0 milestone close Archived to .planning/milestones/v4.0-REQUIREMENTS.md; next milestone creates a fresh requirements file via /gsd:new-milestone. --- .planning/REQUIREMENTS.md | 83 --------------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 .planning/REQUIREMENTS.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md deleted file mode 100644 index a495073..0000000 --- a/.planning/REQUIREMENTS.md +++ /dev/null @@ -1,83 +0,0 @@ -# ShopPyBot — Requirements - -**Current Milestone:** v4.0 Win-the-Drop (Acquisition Core + Reliability) -**Defined:** 2026-06-10 - -Prior milestone requirements (v1 44 + v2.0 22 + v3.0 18) are archived at -`.planning/milestones/v2.0-REQUIREMENTS.md` and `.planning/milestones/v3.0-REQUIREMENTS.md`. -This file scopes v4.0 only. - ---- - -## v4.0 Requirements (Active — Acquisition Core + Reliability) - -### Acquisition — Verified Checkout - -- [x] **BUY-01**: User can run the bot in a monitor-only mode (config flag and/or `--monitor-only`) that performs stock checks and fires alerts but never places an order, enforced once at the orchestrator before `auto_buy` so it applies to every plugin uniformly. -- [x] **BUY-02**: Every plugin routes its final place-order action through a single `place_order_guarded()` concrete method on the RetailerPlugin ABC that honors `test_mode`/monitor-only, so all 7 bundled plugins (and future community plugins) cannot place a live order under test/monitor mode by default. (Closes the confirmed hole where BestBuy and 5 others ignore `test_mode`.) -- [x] **BUY-03**: After `auto_buy` returns, the orchestrator verifies a real placed order using a primary confirmation-URL signal plus an order-number backup signal (with a settle delay), capturing the order id; `purchased` is written only on a confirmed order, never on a button click. -- [x] **BUY-04**: The bot records each checkout outcome (confirmed / failed / timed-out) with the captured order id and a timestamp in the database, providing the idempotency anchor and a basis for future outcome analytics. -- [x] **BUY-05**: On a non-confirmed checkout, the bot retries up to a configurable maximum with backoff, re-reading the persisted `purchased`/outcome state before each attempt so a succeeded-but-misdetected order is never re-submitted (no double-buy). -- [x] **BUY-06**: Each checkout runs under a per-step time budget with checkout-stage tracking and a hard per-item ceiling, so a slow step aborts cleanly (no half-submitted order, no orphaned browser state) rather than starving the drop window. -- [x] **BUY-07**: User can configure a shipping/billing profile that the bot fills during checkout on BestBuy and Amazon; payment uses the retailer-saved method plus CVV entered at runtime, and no full card number is persisted to disk or logs. - -### Always-On Reliability - -- [x] **REL-01**: A supervisor wraps each plugin task so an unhandled exception in one plugin is absorbed before the asyncio TaskGroup boundary and that plugin restarts with exponential backoff, while every other plugin keeps running. -- [x] **REL-02**: A plugin that exceeds a failure budget (N failures within a time window) is parked instead of crash-looping, and the operator is notified through the existing dispatcher. -- [x] **REL-03**: The bot detects a dead or disconnected Chrome process and cold-restarts that plugin's browser, re-applying stealth, proxy assignment, and login before resuming checks. -- [x] **REL-04**: User can opt in to encrypted session/cookie persistence so the bot restores browser cookies across restarts (skipping re-login/MFA); cookies are encrypted via the existing CredentialStore machinery (never plaintext) and restored via the CDP path that avoids the nodriver `set_all()` bug. -- [x] **REL-05**: Transient SQLite errors on the read path (item reads, notification-state reads, price reads) are caught and isolated so a single failed read degrades gracefully instead of crashing the poll loop. -- [x] **REL-06**: Each item's check/buy cycle runs under an overall orchestrator timeout, so a stalled page or a long captcha pause on one item cannot freeze the other items on that retailer. -- [x] **REL-07**: `BotService.get_status()` returns a structured per-plugin health surface (liveness, last-activity, last-error) queryable from the CLI and web UI, and sustained degradation is signaled through the notification dispatcher. -- [x] **REL-08**: Supervisor-restart (REL-01) and cart-retry (BUY-05) share one `RetryPolicy` implementation, so backoff behavior is defined in a single place and the two retry concepts cannot diverge or compound. - -### Server Safety (opportunistic) - -- [x] **SRV-01**: The sound notifier degrades to a silent no-op on a headless host with no audio device instead of crashing at import, so the bot runs unattended on a server. -- [x] **SRV-02**: SIGTERM and SIGINT trigger cooperative teardown (write-queue flush + browser teardown) so a container/systemd stop does not orphan Chrome; the signal bridge uses a platform-appropriate path (Windows has no `loop.add_signal_handler`). - ---- - -## Future Requirements (Deferred to v4.1+) - -- Request/API-mode (hybrid) checkout — faster than DOM, but per-site reverse-engineering and an arms race. -- Multi-account / multi-profile parallel attempts per item — most ToS-hostile; opt-in if ever. -- Checkout profile form-fill for the remaining 5 retailers (v4.0 covers BestBuy + Amazon). -- Richer health/observability on the web dashboard (beyond the CLI/status payload). -- Outcome analytics (success rate, time-to-checkout) built on the BUY-04 outcome records. - ---- - -## Out of Scope (v4.0) - -- Virtual-waiting-room / queue survival (Queue-it, PerimeterX press-and-hold, Akamai `_abck`, DataDome) — behavioral bot managers, not token CAPTCHAs; an arms race with no reliable open-source lever. -- Amazon WAF CAPTCHA auto-solve — re-deferred (`.planning/todos/pending/waf-auto-solve-followup.md`); manual-pause fallback remains. -- Storing full payment card / PAN anywhere — PCI scope; v4.0 relies on retailer-saved payment + CVV-at-runtime only. -- Captcha harvesting / solver farms. -- Public-release hardening (git-history scrub/squash, release-please tagging) — belongs to a dedicated release milestone (SEED-001, SEED-002). -- End-to-end live retail checkout tests in CI — legal/ToS risk; confirmation selectors are verified by manual UAT instead. - ---- - -## Traceability - -| Requirement | Phase | Status | -|-------------|-------|--------| -| BUY-01 | Phase 18 | Complete | -| BUY-02 | Phase 18 | Complete | -| BUY-03 | Phase 19 | Complete | -| BUY-04 | Phase 19 | Complete | -| BUY-05 | Phase 21 | Complete | -| BUY-06 | Phase 21 | Complete | -| BUY-07 | Phase 20 | Complete | -| REL-01 | Phase 22 | Complete | -| REL-02 | Phase 22 | Complete | -| REL-03 | Phase 22 | Complete | -| REL-04 | Phase 23 | Complete | -| REL-05 | Phase 22 | Complete | -| REL-06 | Phase 22 | Complete | -| REL-07 | Phase 24 | Complete | -| REL-08 | Phase 21 | Complete | -| SRV-01 | Phase 24 | Complete | -| SRV-02 | Phase 22 | Complete | From 7a6ef0988cd58c4c4b52320e6c84f7d61485e351 Mon Sep 17 00:00:00 2001 From: Zoid Date: Wed, 24 Jun 2026 22:29:49 -0400 Subject: [PATCH 3/3] chore: archive v4.0 phase directories Move phases 18-24 from .planning/phases/ to .planning/milestones/v4.0-phases/, matching v1/v2.0/v3.0 archival. Includes phase-24 review-fix doc. .planning/phases/ now empty, ready for next milestone. --- .../18-01-PLAN.md | 0 .../18-01-SUMMARY.md | 0 .../18-02-PLAN.md | 0 .../18-02-SUMMARY.md | 0 .../18-03-PLAN.md | 0 .../18-03-SUMMARY.md | 0 .../18-04-PLAN.md | 0 .../18-04-SUMMARY.md | 0 .../18-CONTEXT.md | 0 .../18-HUMAN-UAT.md | 0 .../18-PATTERNS.md | 0 .../18-RESEARCH.md | 0 .../18-REVIEW.md | 0 .../18-VALIDATION.md | 0 .../18-VERIFICATION.md | 0 .../19-01-PLAN.md | 0 .../19-01-SUMMARY.md | 0 .../19-02-PLAN.md | 0 .../19-02-SUMMARY.md | 0 .../19-03-PLAN.md | 0 .../19-03-SUMMARY.md | 0 .../19-04-PLAN.md | 0 .../19-04-SUMMARY.md | 0 .../19-CONTEXT.md | 0 .../19-HUMAN-UAT.md | 0 .../19-PATTERNS.md | 0 .../19-RESEARCH.md | 0 .../19-REVIEW.md | 0 .../19-VALIDATION.md | 0 .../19-VERIFICATION.md | 0 .../20-01-PLAN.md | 0 .../20-01-SUMMARY.md | 0 .../20-02-PLAN.md | 0 .../20-02-SUMMARY.md | 0 .../20-03-PLAN.md | 0 .../20-03-SUMMARY.md | 0 .../20-04-PLAN.md | 0 .../20-04-SUMMARY.md | 0 .../20-CONTEXT.md | 0 .../20-HUMAN-UAT.md | 0 .../20-PATTERNS.md | 0 .../20-RESEARCH.md | 0 .../20-REVIEW.md | 0 .../20-VALIDATION.md | 0 .../20-VERIFICATION.md | 0 .../21-01-PLAN.md | 0 .../21-01-SUMMARY.md | 0 .../21-02-PLAN.md | 0 .../21-02-SUMMARY.md | 0 .../21-03-PLAN.md | 0 .../21-03-SUMMARY.md | 0 .../21-04-PLAN.md | 0 .../21-04-SUMMARY.md | 0 .../21-CONTEXT.md | 0 .../21-HUMAN-UAT.md | 0 .../21-PATTERNS.md | 0 .../21-RESEARCH.md | 0 .../21-REVIEW.md | 0 .../21-VALIDATION.md | 0 .../21-VERIFICATION.md | 0 .../22-01-PLAN.md | 0 .../22-01-SUMMARY.md | 0 .../22-02-PLAN.md | 0 .../22-02-SUMMARY.md | 0 .../22-03-PLAN.md | 0 .../22-03-SUMMARY.md | 0 .../22-04-PLAN.md | 0 .../22-04-SUMMARY.md | 0 .../22-CONTEXT.md | 0 .../22-HUMAN-UAT.md | 0 .../22-PATTERNS.md | 0 .../22-RESEARCH.md | 0 .../22-REVIEW.md | 0 .../22-VALIDATION.md | 0 .../22-VERIFICATION.md | 0 .../23-01-PLAN.md | 0 .../23-01-SUMMARY.md | 0 .../23-02-PLAN.md | 0 .../23-02-SUMMARY.md | 0 .../23-03-PLAN.md | 0 .../23-03-SUMMARY.md | 0 .../23-04-PLAN.md | 0 .../23-04-SUMMARY.md | 0 .../23-CONTEXT.md | 0 .../23-HUMAN-UAT.md | 0 .../23-PATTERNS.md | 0 .../23-RESEARCH.md | 0 .../23-REVIEW-FIX.md | 0 .../23-REVIEW.md | 0 .../23-VALIDATION.md | 0 .../23-VERIFICATION.md | 0 .../24-01-PLAN.md | 0 .../24-01-SUMMARY.md | 0 .../24-02-PLAN.md | 0 .../24-02-SUMMARY.md | 0 .../24-03-PLAN.md | 0 .../24-03-SUMMARY.md | 0 .../24-04-PLAN.md | 0 .../24-04-SUMMARY.md | 0 .../24-05-PLAN.md | 0 .../24-05-SUMMARY.md | 0 .../24-CONTEXT.md | 0 .../24-HUMAN-UAT.md | 0 .../24-PATTERNS.md | 0 .../24-RESEARCH.md | 0 .../24-REVIEW-FIX.md | 70 +++++++++++++++++++ .../24-REVIEW.md | 0 .../24-VALIDATION.md | 0 .../24-VERIFICATION.md | 0 109 files changed, 70 insertions(+) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-RESEARCH.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/18-safety-gate-config-foundation/18-VERIFICATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-RESEARCH.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/19-db-schema-confirmation-detection/19-VERIFICATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-RESEARCH.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/20-checkout-profile-form-fill/20-VERIFICATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-RESEARCH.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/21-per-step-timeouts-unified-retry-cart-retry/21-VERIFICATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-RESEARCH.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/22-supervisor-browser-relaunch-server-safety/22-VERIFICATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-RESEARCH.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-REVIEW-FIX.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/23-encrypted-session-persistence/23-VERIFICATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-01-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-01-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-02-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-02-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-03-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-03-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-04-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-04-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-05-PLAN.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-05-SUMMARY.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-CONTEXT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-HUMAN-UAT.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-PATTERNS.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-RESEARCH.md (100%) create mode 100644 .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-REVIEW-FIX.md rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-REVIEW.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-VALIDATION.md (100%) rename .planning/{phases => milestones/v4.0-phases}/24-health-surface-server-safety/24-VERIFICATION.md (100%) diff --git a/.planning/phases/18-safety-gate-config-foundation/18-01-PLAN.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-01-PLAN.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-01-PLAN.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-01-PLAN.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-01-SUMMARY.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-01-SUMMARY.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-01-SUMMARY.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-02-PLAN.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-02-PLAN.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-02-PLAN.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-02-PLAN.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-02-SUMMARY.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-02-SUMMARY.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-02-SUMMARY.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-03-PLAN.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-03-PLAN.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-03-PLAN.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-03-PLAN.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-03-SUMMARY.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-03-SUMMARY.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-03-SUMMARY.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-04-PLAN.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-04-PLAN.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-04-PLAN.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-04-PLAN.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-04-SUMMARY.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-04-SUMMARY.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-04-SUMMARY.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-CONTEXT.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-CONTEXT.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-CONTEXT.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-CONTEXT.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-HUMAN-UAT.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-HUMAN-UAT.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-PATTERNS.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-PATTERNS.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-PATTERNS.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-PATTERNS.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-RESEARCH.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-RESEARCH.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-RESEARCH.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-RESEARCH.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-REVIEW.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-REVIEW.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-REVIEW.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-REVIEW.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-VALIDATION.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-VALIDATION.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-VALIDATION.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-VALIDATION.md diff --git a/.planning/phases/18-safety-gate-config-foundation/18-VERIFICATION.md b/.planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-VERIFICATION.md similarity index 100% rename from .planning/phases/18-safety-gate-config-foundation/18-VERIFICATION.md rename to .planning/milestones/v4.0-phases/18-safety-gate-config-foundation/18-VERIFICATION.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-01-PLAN.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-01-PLAN.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-01-PLAN.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-01-PLAN.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-01-SUMMARY.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-01-SUMMARY.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-01-SUMMARY.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-02-PLAN.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-02-PLAN.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-02-PLAN.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-02-PLAN.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-02-SUMMARY.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-02-SUMMARY.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-02-SUMMARY.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-03-PLAN.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-03-PLAN.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-03-PLAN.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-03-PLAN.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-03-SUMMARY.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-03-SUMMARY.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-03-SUMMARY.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-04-PLAN.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-04-PLAN.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-04-PLAN.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-04-PLAN.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-04-SUMMARY.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-04-SUMMARY.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-04-SUMMARY.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-CONTEXT.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-CONTEXT.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-CONTEXT.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-CONTEXT.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-HUMAN-UAT.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-HUMAN-UAT.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-PATTERNS.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-PATTERNS.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-PATTERNS.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-PATTERNS.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-RESEARCH.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-RESEARCH.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-RESEARCH.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-RESEARCH.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-REVIEW.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-REVIEW.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-REVIEW.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-REVIEW.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-VALIDATION.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-VALIDATION.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-VALIDATION.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-VALIDATION.md diff --git a/.planning/phases/19-db-schema-confirmation-detection/19-VERIFICATION.md b/.planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-VERIFICATION.md similarity index 100% rename from .planning/phases/19-db-schema-confirmation-detection/19-VERIFICATION.md rename to .planning/milestones/v4.0-phases/19-db-schema-confirmation-detection/19-VERIFICATION.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-01-PLAN.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-01-PLAN.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-01-PLAN.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-01-PLAN.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-01-SUMMARY.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-01-SUMMARY.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-01-SUMMARY.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-02-PLAN.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-02-PLAN.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-02-PLAN.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-02-PLAN.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-02-SUMMARY.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-02-SUMMARY.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-02-SUMMARY.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-03-PLAN.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-03-PLAN.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-03-PLAN.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-03-PLAN.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-03-SUMMARY.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-03-SUMMARY.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-03-SUMMARY.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-04-PLAN.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-04-PLAN.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-04-PLAN.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-04-PLAN.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-04-SUMMARY.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-04-SUMMARY.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-04-SUMMARY.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-CONTEXT.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-CONTEXT.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-CONTEXT.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-CONTEXT.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-HUMAN-UAT.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-HUMAN-UAT.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-PATTERNS.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-PATTERNS.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-PATTERNS.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-PATTERNS.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-RESEARCH.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-RESEARCH.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-RESEARCH.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-RESEARCH.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-REVIEW.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-REVIEW.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-REVIEW.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-REVIEW.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-VALIDATION.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-VALIDATION.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-VALIDATION.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-VALIDATION.md diff --git a/.planning/phases/20-checkout-profile-form-fill/20-VERIFICATION.md b/.planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-VERIFICATION.md similarity index 100% rename from .planning/phases/20-checkout-profile-form-fill/20-VERIFICATION.md rename to .planning/milestones/v4.0-phases/20-checkout-profile-form-fill/20-VERIFICATION.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-PLAN.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-PLAN.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-PLAN.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-PLAN.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-SUMMARY.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-SUMMARY.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-01-SUMMARY.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-PLAN.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-PLAN.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-PLAN.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-PLAN.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-SUMMARY.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-SUMMARY.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-02-SUMMARY.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-PLAN.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-PLAN.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-PLAN.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-PLAN.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-SUMMARY.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-SUMMARY.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-03-SUMMARY.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-PLAN.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-PLAN.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-PLAN.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-PLAN.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-SUMMARY.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-SUMMARY.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-04-SUMMARY.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-CONTEXT.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-CONTEXT.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-CONTEXT.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-CONTEXT.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-HUMAN-UAT.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-HUMAN-UAT.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-PATTERNS.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-PATTERNS.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-PATTERNS.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-PATTERNS.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-RESEARCH.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-RESEARCH.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-RESEARCH.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-RESEARCH.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-REVIEW.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-REVIEW.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-REVIEW.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-REVIEW.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-VALIDATION.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-VALIDATION.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-VALIDATION.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-VALIDATION.md diff --git a/.planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-VERIFICATION.md b/.planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-VERIFICATION.md similarity index 100% rename from .planning/phases/21-per-step-timeouts-unified-retry-cart-retry/21-VERIFICATION.md rename to .planning/milestones/v4.0-phases/21-per-step-timeouts-unified-retry-cart-retry/21-VERIFICATION.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-01-PLAN.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-01-PLAN.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-01-PLAN.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-01-PLAN.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-01-SUMMARY.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-01-SUMMARY.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-01-SUMMARY.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-02-PLAN.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-02-PLAN.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-02-PLAN.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-02-PLAN.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-02-SUMMARY.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-02-SUMMARY.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-02-SUMMARY.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-03-PLAN.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-03-PLAN.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-03-PLAN.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-03-PLAN.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-03-SUMMARY.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-03-SUMMARY.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-03-SUMMARY.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-04-PLAN.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-04-PLAN.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-04-PLAN.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-04-PLAN.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-04-SUMMARY.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-04-SUMMARY.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-04-SUMMARY.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-CONTEXT.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-CONTEXT.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-CONTEXT.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-CONTEXT.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-HUMAN-UAT.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-HUMAN-UAT.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-PATTERNS.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-PATTERNS.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-PATTERNS.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-PATTERNS.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-RESEARCH.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-RESEARCH.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-RESEARCH.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-RESEARCH.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-REVIEW.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-REVIEW.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-REVIEW.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-REVIEW.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-VALIDATION.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-VALIDATION.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-VALIDATION.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-VALIDATION.md diff --git a/.planning/phases/22-supervisor-browser-relaunch-server-safety/22-VERIFICATION.md b/.planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-VERIFICATION.md similarity index 100% rename from .planning/phases/22-supervisor-browser-relaunch-server-safety/22-VERIFICATION.md rename to .planning/milestones/v4.0-phases/22-supervisor-browser-relaunch-server-safety/22-VERIFICATION.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-01-PLAN.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-01-PLAN.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-01-PLAN.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-01-PLAN.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-01-SUMMARY.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-01-SUMMARY.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-01-SUMMARY.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-02-PLAN.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-02-PLAN.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-02-PLAN.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-02-PLAN.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-02-SUMMARY.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-02-SUMMARY.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-02-SUMMARY.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-03-PLAN.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-03-PLAN.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-03-PLAN.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-03-PLAN.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-03-SUMMARY.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-03-SUMMARY.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-03-SUMMARY.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-04-PLAN.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-04-PLAN.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-04-PLAN.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-04-PLAN.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-04-SUMMARY.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-04-SUMMARY.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-04-SUMMARY.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-CONTEXT.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-CONTEXT.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-CONTEXT.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-CONTEXT.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-HUMAN-UAT.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-HUMAN-UAT.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-PATTERNS.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-PATTERNS.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-PATTERNS.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-PATTERNS.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-RESEARCH.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-RESEARCH.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-RESEARCH.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-RESEARCH.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-REVIEW-FIX.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-REVIEW-FIX.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-REVIEW-FIX.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-REVIEW-FIX.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-REVIEW.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-REVIEW.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-REVIEW.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-REVIEW.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-VALIDATION.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-VALIDATION.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-VALIDATION.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-VALIDATION.md diff --git a/.planning/phases/23-encrypted-session-persistence/23-VERIFICATION.md b/.planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-VERIFICATION.md similarity index 100% rename from .planning/phases/23-encrypted-session-persistence/23-VERIFICATION.md rename to .planning/milestones/v4.0-phases/23-encrypted-session-persistence/23-VERIFICATION.md diff --git a/.planning/phases/24-health-surface-server-safety/24-01-PLAN.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-01-PLAN.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-01-PLAN.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-01-PLAN.md diff --git a/.planning/phases/24-health-surface-server-safety/24-01-SUMMARY.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-01-SUMMARY.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-01-SUMMARY.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-01-SUMMARY.md diff --git a/.planning/phases/24-health-surface-server-safety/24-02-PLAN.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-02-PLAN.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-02-PLAN.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-02-PLAN.md diff --git a/.planning/phases/24-health-surface-server-safety/24-02-SUMMARY.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-02-SUMMARY.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-02-SUMMARY.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-02-SUMMARY.md diff --git a/.planning/phases/24-health-surface-server-safety/24-03-PLAN.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-03-PLAN.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-03-PLAN.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-03-PLAN.md diff --git a/.planning/phases/24-health-surface-server-safety/24-03-SUMMARY.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-03-SUMMARY.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-03-SUMMARY.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-03-SUMMARY.md diff --git a/.planning/phases/24-health-surface-server-safety/24-04-PLAN.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-04-PLAN.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-04-PLAN.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-04-PLAN.md diff --git a/.planning/phases/24-health-surface-server-safety/24-04-SUMMARY.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-04-SUMMARY.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-04-SUMMARY.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-04-SUMMARY.md diff --git a/.planning/phases/24-health-surface-server-safety/24-05-PLAN.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-05-PLAN.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-05-PLAN.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-05-PLAN.md diff --git a/.planning/phases/24-health-surface-server-safety/24-05-SUMMARY.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-05-SUMMARY.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-05-SUMMARY.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-05-SUMMARY.md diff --git a/.planning/phases/24-health-surface-server-safety/24-CONTEXT.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-CONTEXT.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-CONTEXT.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-CONTEXT.md diff --git a/.planning/phases/24-health-surface-server-safety/24-HUMAN-UAT.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-HUMAN-UAT.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-HUMAN-UAT.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-HUMAN-UAT.md diff --git a/.planning/phases/24-health-surface-server-safety/24-PATTERNS.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-PATTERNS.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-PATTERNS.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-PATTERNS.md diff --git a/.planning/phases/24-health-surface-server-safety/24-RESEARCH.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-RESEARCH.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-RESEARCH.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-RESEARCH.md diff --git a/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-REVIEW-FIX.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-REVIEW-FIX.md new file mode 100644 index 0000000..b4933e2 --- /dev/null +++ b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-REVIEW-FIX.md @@ -0,0 +1,70 @@ +--- +phase: 24-health-surface-server-safety +fixed_at: 2026-06-12T00:00:00Z +review_path: .planning/phases/24-health-surface-server-safety/24-REVIEW.md +iteration: 1 +findings_in_scope: 5 +fixed: 5 +skipped: 0 +status: all_fixed +--- + +# Phase 24: Code Review Fix Report + +**Fixed at:** 2026-06-12 +**Source review:** .planning/phases/24-health-surface-server-safety/24-REVIEW.md +**Iteration:** 1 + +**Summary:** +- Findings in scope: 5 (CR-01, WR-01, WR-02, WR-03, IN-02; IN-01 subsumed by CR-01 rewrite) +- Fixed: 5 +- Skipped: 0 + +## Fixed Issues + +### CR-01 + WR-03: Guard pygame import; wrap play_sound audio errors + +**Files modified:** `utils.py`, `tests/test_utils_audio.py` +**Commit:** 8284735 +**Applied fix:** +- Replaced bare `import pygame` with `try/except (ModuleNotFoundError, ImportError)` block; sets `_PYGAME_AVAILABLE` and `_pygame` alias. +- `_initialize_audio()` short-circuits to False when `_PYGAME_AVAILABLE` is False (before calling mixer.init). +- All `pygame.*` references in the module now use `_pygame.*`. +- `play_sound` wraps `mixer.music.load/play` in `try/except _pygame.error` to swallow runtime audio errors (WR-03). +- Dead `_AUDIO_AVAILABLE: bool = False` pre-declaration (IN-01) eliminated as part of the rewrite. +- Updated `tests/test_utils_audio.py`: patches retargeted to `utils._pygame`, added non-vacuous import-failure simulation test (blocks pygame via `sys.modules["pygame"] = None`, reloads utils, asserts `_AUDIO_AVAILABLE=False` and `play_sound` no-ops), added WR-03 load/play error tests. + +**Suite result:** 755 passed, 2 skipped, 0 failures (baseline 752 passed; 3 new tests added) + +### WR-01: Add get_consecutive_errors reader; use in supervise() crash path + +**Files modified:** `core/health.py`, `core/orchestrator.py` +**Commit:** d11bf2c +**Applied fix:** +- Added `HealthRegistry.get_consecutive_errors(name: str) -> int` that reads the live counter directly via `_ensure` + dict lookup. +- Replaced `snap = health.get_snapshot(); consecutive = snap.get(plugin_name, {}).get("consecutive_errors", 0)` in `supervise()` with `consecutive = health.get_consecutive_errors(plugin_name)`. Removes the full deep-copy allocation on the hot crash path. + +### WR-02: Snapshot loop/task before guard in stop() to close TOCTOU + +**Files modified:** `core/service.py` +**Commit:** 79e5419 +**Applied fix:** +- Moved `loop = self._loop` and `task = self._task` captures to the top of `stop()`, before the `if not self._running or loop is None` guard. Guard and `call_soon_threadsafe` now operate on the same consistent local references even if the daemon thread nulls the instance attributes concurrently. + +### IN-02: Display heartbeat age instead of raw monotonic seconds + +**Files modified:** `core/cli/status.py` +**Commit:** 3007ba1 +**Applied fix:** +- Added `import time` and `now = time.monotonic()` in `_format_status_table`. +- Replaced `f"{rec.get('last_heartbeat', 0.0):.1f}"` with `f"{now - rec['last_heartbeat']:.1f}s ago"` (or `"never"` when heartbeat is 0.0). + +### IN-01: Dead _AUDIO_AVAILABLE pre-declaration + +Subsumed by CR-01 fix. The line 8 `_AUDIO_AVAILABLE: bool = False` pre-declaration was not present in the rewritten utils.py; no separate commit required. + +--- + +_Fixed: 2026-06-12_ +_Fixer: Claude (gsd-code-fixer)_ +_Iteration: 1_ diff --git a/.planning/phases/24-health-surface-server-safety/24-REVIEW.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-REVIEW.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-REVIEW.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-REVIEW.md diff --git a/.planning/phases/24-health-surface-server-safety/24-VALIDATION.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-VALIDATION.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-VALIDATION.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-VALIDATION.md diff --git a/.planning/phases/24-health-surface-server-safety/24-VERIFICATION.md b/.planning/milestones/v4.0-phases/24-health-surface-server-safety/24-VERIFICATION.md similarity index 100% rename from .planning/phases/24-health-surface-server-safety/24-VERIFICATION.md rename to .planning/milestones/v4.0-phases/24-health-surface-server-safety/24-VERIFICATION.md