From d40f334ca579430299bcdbce855b03a061557ac2 Mon Sep 17 00:00:00 2001 From: David Stone Date: Wed, 20 May 2026 10:09:43 -0600 Subject: [PATCH 1/3] chore: upgrade planning templates --- TODO.md | 231 +++++++++++++++++++++----------------------------- todo/PLANS.md | 130 ++++++++++++++++++++++++++-- 2 files changed, 219 insertions(+), 142 deletions(-) diff --git a/TODO.md b/TODO.md index 86cd29fca..e7ee80c38 100644 --- a/TODO.md +++ b/TODO.md @@ -1,138 +1,97 @@ + + + # TODO -## Tasks - -- [x] t374 Add support for creating new domains in Cloudflare @superdav42 #374 ~4h started:2026-03-24T00:00:00Z pr:#377 completed:2026-03-25 -- [x] t450 Positioning and growth plan to attract more customers ref:GH#450 ~8h pr:#452 completed:2026-03-25 -- [x] t451 Fix WP Performance Metrics CI ECONNREFUSED failure (WordPress server not starting on port 9400) ref:GH#475 ~2h #bug #auto-dispatch pr:#476 completed:2026-03-25 -- [x] t452 feat(tax): implement universal tax fallback as "Apply to all countries" dropdown option on Tax Rates page ref:GH#505 ~3h #enhancement #auto-dispatch pr:#506 completed:2026-03-26 -- [x] t509 fix: template_selection validation never fires — field ID maps to wrong rule key ref:GH#799 ~1h #bug #auto-dispatch pr:#800 completed:2026-04-12 - -## Unit Test Coverage Tasks - -Overall coverage: **35%** (20,720 / 59,212 statements). 90 files at 0% coverage. - -### Priority 1 — Business-Critical Code (low coverage, high risk) - -- [x] t453 test(checkout): write unit tests for Checkout class (inc/checkout/class-checkout.php — 7.9% coverage, 960 uncovered stmts) #testing #auto-dispatch ~6h ref:GH#555 pr:#569 completed:2026-03-27 -- [x] t454 test(cart): improve Cart test coverage (inc/checkout/class-cart.php — 61.1% coverage, 382 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#556 pr:#583 completed:2026-03-28 -- [x] t455 test(stripe): write unit tests for Base_Stripe_Gateway (inc/gateways/class-base-stripe-gateway.php — 28.6% coverage, 1093 uncovered stmts) #testing #auto-dispatch ~8h ref:GH#624 pr:#648 completed:2026-03-28 -- [x] t456 test(stripe): improve Stripe_Gateway test coverage (inc/gateways/class-stripe-gateway.php — 55% coverage, 200 uncovered stmts) #testing ~4h pr:#623 completed:2026-03-28 -- [x] t457 test(paypal): write unit tests for PayPal_Gateway (inc/gateways/class-paypal-gateway.php — 1.1% coverage, 783 uncovered stmts) #testing #auto-dispatch ~6h ref:GH#627 pr:#649 completed:2026-03-28 -- [x] t458 test(paypal): improve PayPal_REST_Gateway test coverage (inc/gateways/class-paypal-rest-gateway.php — 29.8% coverage, 683 uncovered stmts) #testing #auto-dispatch ~5h ref:GH#629 pr:#636 completed:2026-03-28 -- [x] t459 test(paypal): write tests for PayPal_OAuth_Handler (inc/gateways/class-paypal-oauth-handler.php — 15% coverage, 238 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#549 pr:#554 completed:2026-03-27 -- [x] t460 test(gateway): improve Gateway_Manager test coverage (inc/managers/class-gateway-manager.php — 34.7% coverage, 177 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#550 pr:#552 completed:2026-03-27 -- [x] t461 test(checkout-pages): improve Checkout_Pages test coverage (inc/checkout/class-checkout-pages.php — 33.7% coverage, 203 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#551 pr:#553 completed:2026-03-27 - -### Priority 2 — Core Domain Logic (moderate coverage gaps) - -- [x] t462 test(site-manager): improve Site_Manager test coverage (inc/managers/class-site-manager.php — 23.5% coverage, 433 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#557 pr:#568 completed:2026-03-27 -- [x] t463 test(domain-manager): improve DNS_Record_Manager test coverage (inc/managers/class-dns-record-manager.php — 14.4% coverage, 393 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#558 pr:#361 completed:2026-03-27 -- [x] t464 test(event-manager): improve Event_Manager test coverage (inc/managers/class-event-manager.php — 33% coverage, 240 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#559 pr:#566 completed:2026-03-27 -- [x] t465 test(form-manager): improve Form_Manager test coverage (inc/managers/class-form-manager.php — 9.7% coverage, 251 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#560 pr:#362 completed:2026-03-27 -- [x] t466 test(notes-manager): improve Notes_Manager test coverage (inc/managers/class-notes-manager.php — 9.9% coverage, 283 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#561 pr:#287 completed:2026-03-27 -- [x] t467 test(sso): improve SSO test coverage (inc/sso/class-sso.php — 36.7% coverage, 210 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#570 pr:#584 completed:2026-03-28 -- [x] t468 test(domain-mapping): write tests for Domain_Mapping (inc/class-domain-mapping.php — 13.8% coverage, 168 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#571 pr:#579 completed:2026-03-28 -- [x] t469 test(membership-functions): improve membership function tests (inc/functions/membership.php — 28.3% coverage, 152 uncovered stmts) #testing #auto-dispatch ~2h ref:GH#572 pr:#577 completed:2026-03-28 -- [x] t470 test(checkout-form-model): improve Checkout_Form model tests (inc/models/class-checkout-form.php — 65.7% coverage, 286 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#573 pr:#582 completed:2026-03-28 -- [x] t471 test(mcp-abilities): improve MCP abilities trait tests (inc/apis/trait-mcp-abilities.php — 69.3% coverage, 162 uncovered stmts) #testing #auto-dispatch ~2h ref:GH#574 pr:#581 completed:2026-03-28 -- [x] t472 test(rest-api): improve REST API trait tests (inc/apis/trait-rest-api.php — 31.6% coverage, 160 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#575 pr:#578 completed:2026-03-28 - -### Priority 3 — Admin Pages (0% coverage, UI-heavy but testable logic) - -- [x] t473 test(admin): write unit tests for Membership_Edit_Admin_Page (inc/admin-pages/class-membership-edit-admin-page.php — 5% coverage, 1042 uncovered stmts) #testing #auto-dispatch ~6h ref:GH#626 pr:#634 completed:2026-03-28 -- [x] t474 test(admin): write unit tests for Payment_Edit_Admin_Page (inc/admin-pages/class-payment-edit-admin-page.php — 0% coverage, 913 uncovered stmts) #testing ~5h pr:#632 completed:2026-03-28 -- [x] t475 test(admin): write unit tests for Checkout_Form_Edit_Admin_Page (inc/admin-pages/class-checkout-form-edit-admin-page.php — 0% coverage, 901 uncovered stmts) #testing ~5h ref:GH#630 pr:#637 completed:2026-03-28 -- [x] t476 test(admin): write unit tests for Product_Edit_Admin_Page (inc/admin-pages/class-product-edit-admin-page.php — 0% coverage, 869 uncovered stmts) #testing ~5h pr:#633 completed:2026-03-28 -- [x] t477 test(admin): write unit tests for Customer_Edit_Admin_Page (inc/admin-pages/class-customer-edit-admin-page.php — 0% coverage, 784 uncovered stmts) #testing ~5h pr:#622 completed:2026-03-28 -- [x] t478 test(admin): write unit tests for Discount_Code_Edit_Admin_Page (inc/admin-pages/class-discount-code-edit-admin-page.php — 1.5% coverage, 526 uncovered stmts) #testing ~4h pr:#618 completed:2026-03-28 -- [x] t479 test(admin): write unit tests for Edit_Admin_Page base class (inc/admin-pages/class-edit-admin-page.php — 2.8% coverage, 375 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#576 pr:#580 completed:2026-03-28 - -### Priority 4 — Infrastructure & Integration Code - -- [x] t480 test(migrator): write unit tests for Migrator (inc/installers/class-migrator.php — 0% coverage, 1057 uncovered stmts) #testing ~6h pr:#620 completed:2026-03-28 -- [x] t481 test(debug): improve Debug test coverage (inc/debug/class-debug.php — 24.3% coverage, 383 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#585 pr:#593 completed:2026-03-28 -- [x] t482 test(wp-ultimo): improve WP_Ultimo main class tests (inc/class-wp-ultimo.php — 5.7% coverage, 394 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#586 pr:#592 completed:2026-03-28 -- [x] t483 test(ajax): write unit tests for Ajax class (inc/class-ajax.php — 1.8% coverage, 213 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#587 pr:#596 completed:2026-03-28 -- [x] t484 test(api): improve API class test coverage (inc/class-api.php — 6.6% coverage, 199 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#588 pr:#591 completed:2026-03-28 -- [x] t485 test(host-providers): write tests for Cloudflare host provider (inc/integrations/host-providers/class-cloudflare-host-provider.php — 19.2% coverage, 307 uncovered stmts) #testing ~4h pr:#619 completed:2026-03-28 -- [x] t486 test(host-providers): write tests for cPanel host provider (inc/integrations/host-providers/class-cpanel-host-provider.php — 0% coverage, 279 uncovered stmts) #testing ~3h pr:#621 completed:2026-03-28 -- [x] t487 test(host-providers): write tests for Hestia host provider (inc/integrations/host-providers/class-hestia-host-provider.php — 5.2% coverage, 254 uncovered stmts) #testing ~3h pr:#617 completed:2026-03-28 -- [x] t488 test(host-providers): write tests for Base_Host_Provider (inc/integrations/host-providers/class-base-host-provider.php — 16.9% coverage, 148 uncovered stmts) #testing #auto-dispatch ~2h ref:GH#589 pr:#594 completed:2026-03-28 -- [x] t489 test(default-content): write tests for Default_Content_Installer (inc/installers/class-default-content-installer.php — 0.5% coverage, 206 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#590 pr:#595 completed:2026-03-28 - -### Priority 5 — List Tables & Signup Fields - -- [x] t490 test(list-tables): write unit tests for Base_List_Table (inc/list-tables/class-base-list-table.php — 4.4% coverage, 461 uncovered stmts) #testing #auto-dispatch ~4h ref:GH#600 pr:#609 completed:2026-03-28 -- [x] t491 test(signup-fields): write tests for Base_Signup_Field (inc/checkout/signup-fields/class-base-signup-field.php — 16% coverage, 199 uncovered stmts) #testing #auto-dispatch ~3h ref:GH#601 pr:#608 completed:2026-03-28 -- [x] t492 test(signup-fields): write tests for Template_Selection field (inc/checkout/signup-fields/class-signup-field-template-selection.php — 1.1% coverage, 174 uncovered stmts) #testing #auto-dispatch ~2h ref:GH#602 pr:#607 completed:2026-03-28 -- [x] t493 test(signup-fields): write tests for Period_Selection field (inc/checkout/signup-fields/class-signup-field-period-selection.php — 1.3% coverage, 156 uncovered stmts) #testing #auto-dispatch ~2h ref:GH#603 pr:#606 completed:2026-03-28 - -### Priority 6 — API Schemas (0% coverage, data-validation code) - -- [x] t494 test(api-schemas): write tests for API schema validation files (inc/apis/schemas/ — 0% coverage across 24 files, 2436 uncovered stmts) #testing #auto-dispatch ~6h ref:GH#604 pr:#605 completed:2026-03-28 - -### Priority 7 — More Admin Pages (0% coverage) - -- [x] t496 test(admin): write unit tests for Domain_Edit_Admin_Page (inc/admin-pages/class-domain-edit-admin-page.php — 0% coverage, ~932 lines) #testing #auto-dispatch ~6h ref:GH#638 pr:#653 completed:2026-03-28 -- [x] t497 test(admin): write unit tests for Email_Edit_Admin_Page (inc/admin-pages/class-email-edit-admin-page.php — 0% coverage, ~576 lines) #testing #auto-dispatch ~4h ref:GH#639 pr:#650 completed:2026-03-28 -- [x] t498 test(admin): write unit tests for Broadcast_Edit_Admin_Page (inc/admin-pages/class-broadcast-edit-admin-page.php — 0% coverage, ~513 lines) #testing #auto-dispatch ~4h ref:GH#640 pr:#655 completed:2026-03-28 -- [x] t499 test(admin): write unit tests for Base_Admin_Page (inc/admin-pages/class-base-admin-page.php — 0% coverage, ~800 lines) #testing #auto-dispatch ~5h ref:GH#641 pr:#651 completed:2026-03-28 -- [x] t500 test(admin): write unit tests for Addons_Admin_Page (inc/admin-pages/class-addons-admin-page.php — 0% coverage, ~513 lines) #testing #auto-dispatch ~4h ref:GH#642 pr:#667 completed:2026-03-28 -- [x] t501 test(admin): write unit tests for Dashboard_Admin_Page (inc/admin-pages/class-dashboard-admin-page.php — 0% coverage) #testing #auto-dispatch ~4h ref:GH#643 pr:#657 completed:2026-03-28 -- [x] t502 test(admin): write unit tests for Customer_List_Admin_Page (inc/admin-pages/class-customer-list-admin-page.php — 0% coverage) #testing #auto-dispatch ~3h ref:GH#644 pr:#663 completed:2026-03-28 -- [x] t503 test(admin): write unit tests for Discount_Code_List_Admin_Page (inc/admin-pages/class-discount-code-list-admin-page.php — 0% coverage) #testing #auto-dispatch ~3h ref:GH#645 pr:#454 verified:2026-03-28 -- [x] t504 test(admin): write unit tests for Domain_List_Admin_Page (inc/admin-pages/class-domain-list-admin-page.php — 0% coverage) #testing #auto-dispatch ~3h ref:GH#646 pr:#654 completed:2026-03-28 -- [x] t505 test(admin): write unit tests for Email_List_Admin_Page (inc/admin-pages/class-email-list-admin-page.php — 0% coverage) #testing #auto-dispatch ~3h ref:GH#647 pr:#656 completed:2026-03-28 - -### Priority 8 — Remaining Admin Pages (0% coverage) - -- [x] t506 test(admin): write unit tests for Settings_Admin_Page (inc/admin-pages/class-settings-admin-page.php — 0% coverage, ~980 lines) #testing #auto-dispatch ~6h ref:GH#658 pr:#664 completed:2026-03-28 -- [x] t507 test(admin): write unit tests for Setup_Wizard_Admin_Page (inc/admin-pages/class-setup-wizard-admin-page.php — 0% coverage, ~947 lines) #testing #auto-dispatch ~6h ref:GH#659 pr:#665 completed:2026-03-28 -- [x] t508 test(admin): write unit tests for System_Info_Admin_Page (inc/admin-pages/class-system-info-admin-page.php — 0% coverage, ~778 lines) #testing #auto-dispatch ~5h ref:GH#660 pr:#669 completed:2026-03-28 -- [x] t509 test(admin): write unit tests for Email_Template_Customize_Admin_Page (inc/admin-pages/class-email-template-customize-admin-page.php — 0% coverage, ~692 lines) #testing #auto-dispatch ~4h ref:GH#661 pr:#668 completed:2026-03-28 -- [x] t510 test(admin): write unit tests for Template_Library_Admin_Page (inc/admin-pages/class-template-library-admin-page.php — 0% coverage, ~673 lines) #testing #auto-dispatch ~4h ref:GH#662 pr:#666 completed:2026-03-28 - -### Priority 9 — Remaining Admin Pages & List Tables (0% coverage) - -- [x] t511 test(admin): write unit tests for Multisite_Setup_Admin_Page (inc/admin-pages/class-multisite-setup-admin-page.php — 0% coverage, ~520 lines) #testing #auto-dispatch ~4h ref:GH#672 pr:#682 completed:2026-03-28 -- [x] t512 test(admin): write unit tests for Wizard_Admin_Page (inc/admin-pages/class-wizard-admin-page.php — 0% coverage, ~445 lines) #testing #auto-dispatch ~3h ref:GH#673 pr:#686 completed:2026-03-28 -- [x] t513 test(admin): write unit tests for Invoice_Template_Customize_Admin_Page (inc/admin-pages/class-invoice-template-customize-admin-page.php — 0% coverage, ~435 lines) #testing #auto-dispatch ~3h ref:GH#674 pr:#680 completed:2026-03-28 -- [x] t514 test(admin): write unit tests for Hosting_Integration_Wizard_Admin_Page (inc/admin-pages/class-hosting-integration-wizard-admin-page.php — 0% coverage, ~420 lines) #testing #auto-dispatch ~3h ref:GH#675 pr:#687 completed:2026-03-28 -- [x] t515 test(admin): write unit tests for External_Cron_Admin_Page (inc/admin-pages/class-external-cron-admin-page.php — 0% coverage, ~417 lines) #testing #auto-dispatch ~3h ref:GH#676 pr:#683 completed:2026-03-28 -- [x] t516 test(list-tables): write unit tests for remaining list table classes (15 files, 0% coverage) #testing #auto-dispatch ~6h ref:GH#677 pr:#684 completed:2026-03-28 -- [x] t517 test(admin): write unit tests for View_Logs and Tax_Rates admin pages (0% coverage) #testing #auto-dispatch ~3h ref:GH#678 pr:#681 completed:2026-03-28 -- [x] t518 test(admin): write unit tests for Template_Previewer, Checkout_Form_List, and Event_View admin pages (0% coverage) #testing #auto-dispatch ~3h ref:GH#679 pr:#685 completed:2026-03-28 - -### Fix: Test suite exits early at 56% - -- [x] t495 fix(tests): Form_Manager_Test::test_handle_model_delete_form_requires_confirmation calls exit() killing test runner at test 2533/4411 #bug #auto-dispatch ~1h ref:GH#562 pr:#563 completed:2026-03-27 - -## New Tasks - -- [x] t519 fix(security): replace wp_redirect with wp_safe_redirect in class-primary-domain.php #bug #auto-dispatch ~1h ref:GH#689 pr:#694 completed:2026-03-29 -- [x] t520 feat(addon): create multisite-ultimate-fluentaffiliate addon for recurring commission tracking #enhancement #auto-dispatch ~12h ref:GH#690 completed:2026-03-29 -- [x] t521 chore: remove stale @todo comments for already-implemented methods #enhancement #auto-dispatch ~1h ref:GH#691 pr:#693 completed:2026-03-29 -- [x] t522 test(integrations): write unit tests for integration provider classes (bunnynet, cloudways, enhance, laravel-forge, plesk, rocket, serverpilot, wpengine, wpmudev) #testing #auto-dispatch ~4h ref:GH#697 pr:#698 completed:2026-03-29 -- [x] t523 feat(paypal): PayPal PPCP integration review compliance — disconnect disclaimer, onboarding failure UI, merchant status validation, payee field, debug ID logging @superdav42 #paypal #compliance ~8h ref:GH#725 pr:#726 completed:2026-04-01 -- [x] t524 feat(checkout): add simple checkout form template with auto-generated credentials (re-implement PR #740 which was closed due to merge conflicts) #enhancement #auto-dispatch ~4h ref:GH#746 pr:#737 completed:2026-04-04 -- [x] t525 fix(dashboard): enqueue wu-styling on network admin dashboard for activity-stream widget #bug #auto-dispatch ~1h ref:GH#767 pr:#768 completed:2026-04-08 -- [x] GH#808 test: add autoload-order regression tests for mpdf PSR HTTP message shim ref:GH#808 pr:#818 completed:2026-04-13 -- [x] GH#813 fix: guard false return from get_available_site_templates() in switch_template() — TypeError on PHP 8.0+ ref:GH#813 pr:#819 completed:2026-04-13 -- [x] GH#814 test(reactivation): add unit tests verifying all PR #751 review findings were addressed ref:GH#814 pr:#817 completed:2026-04-13 - -## Production Bugs (2026-04-28) - -- [ ] t531 fix(checkout): password fields and strength meter stop working after inline login popup + email change — Vue 2 recycles login-prompt DOM node as password-div, detaching jQuery bindings on #field-password #bug #auto-dispatch ~3h ref:GH#973 logged:2026-04-28 - -## Production Bugs (2026-04-22) - -- [ ] t529 fix(membership): orphan pending_site after membership cancellation — watchdog cancels membership but pending_site meta stays, customer retries checkout and gets no site #bug #auto-dispatch ~4h ref:GH#902 -- [ ] t528 fix(checkout): duplicate WP users created on checkout retry — wp_insert_user called without get_user_by email check #bug #auto-dispatch ~2h ref:GH#903 -- [ ] t530 fix(checkout): reclaim orphan pending_site on WC order completion — no code picks up transferable pending_site when payment succeeds #bug #auto-dispatch ~4h ref:GH#904 -- [ ] t526 fix(i18n): JS checkout validator missing i18n strings — field_required etc. hardcoded English in checkout.min.js #bug #auto-dispatch ~2h ref:GH#905 -- [ ] t527 fix(ux): default minimum_password_strength too strict — super_strong rejects reasonable passwords, default to strong #enhancement #auto-dispatch ~1h ref:GH#906 - -## Production Bugs (2026-05-05) - -- [x] t532 fix(admin): white page after site deletion in Edit Site screen — post-delete redirect lands on a blank page instead of the site list #bugfix #auto-dispatch ~1h logged:2026-05-05 pr:#1125 completed:2026-05-05 \ No newline at end of file +Project task tracking with time estimates, dependencies, and TOON-enhanced parsing. + +Compatible with [todo-md](https://github.com/todo-md/todo-md), [todomd](https://github.com/todomd/todo.md), [taskell](https://github.com/smallhadroncollider/taskell), and [Beads](https://github.com/steveyegge/beads). + +## Format + +**Human-readable:** + + + +Format: `- [ ] tNNN Description @owner #tag ~estimate risk:level logged:date` + +**Task IDs:** +- `t001` - Top-level task +- `t001.1` - Subtask of t001 +- `t001.1.1` - Sub-subtask + +**Dependencies:** +- `blocked-by:t001` - This task waits for t001 +- `blocked-by:t001,t002` - Waits for multiple tasks +- `blocks:t003` - This task blocks t003 + +**Time fields:** +- `~estimate` - AI-assisted execution time (~15m trivial, ~30m small, ~1h medium, ~2h large, ~4h major — see `reference/planning-detail.md`) +- `actual:` - Actual active time spent (from session-time-helper.sh) +- `logged:` - When task was added +- `started:` - When branch was created +- `completed:` - When task was marked done + +**Risk (human oversight needed):** +- `risk:low` - Autonomous: fire-and-forget, review PR after +- `risk:med` - Supervised: check in mid-task, review before merge +- `risk:high` - Engaged: stay present, test thoroughly, potential regressions + + + +## Ready + + + + + +## Backlog + + + +## In Progress + + + +## In Review + + + + + +## Done + + + +## Declined + + + + + + + + + + + + + + diff --git a/todo/PLANS.md b/todo/PLANS.md index b8c3f3051..70b2490bb 100644 --- a/todo/PLANS.md +++ b/todo/PLANS.md @@ -1,11 +1,50 @@ -# Plans -## t523: PayPal PPCP Integration Review Compliance + + +# Execution Plans -**Status:** Planning -**Estimate:** ~8h (code) + manual deliverables -**Priority:** High — blocks PayPal partnership approval -**Tags:** #paypal #gateway #compliance +Complex, multi-session work requiring research, design decisions, and detailed tracking. + +Based on [OpenAI's PLANS.md](https://cookbook.openai.com/articles/codex_exec_plans) with TOON-enhanced parsing and [Beads](https://github.com/steveyegge/beads) integration for dependency visualization. + + + +## Format + +Each plan includes: +- **Plan ID**: `p001`, `p002`, etc. (for cross-referencing) +- **Status**: Planning / In Progress (Phase X/Y) / Blocked / Completed +- **Time Estimate**: `~2w (ai:1w test:0.5w read:0.5w)` +- **Timestamps**: `logged:`, `started:`, `completed:` +- **Dependencies**: `blocked-by:p001` or `blocks:p003` +- **Linkage (The Pin)**: File:line references for search hit-rate (see below) +- **Progress**: Timestamped checkboxes with estimates and actuals +- **Decision Log**: Key decisions with rationale +- **Surprises & Discoveries**: Unexpected findings +- **Outcomes & Retrospective**: Results and lessons (when complete) + +### Linkage (The Pin) + +Based on [Loom's spec-as-lookup-table pattern](https://ghuntley.com/ralph/), each plan should include a Linkage section that functions as a lookup table for AI search: + +| Concept | Files | Lines | Synonyms | +|---------|-------|-------|----------| +| {concept} | {file path} | {line range} | {related terms} | + +**Why this matters:** +- Reduces hallucination by providing explicit anchors +- Improves search hit-rate with synonyms +- Points to exact file hunks for context +- Prevents AI from inventing when it should reference + +## Active Plans + + + + ### Context from Discussion @@ -105,3 +144,82 @@ validation, order/capture process, BN code, and debug ID submission. - `inc/gateways/class-paypal-rest-gateway.php` (main changes) - `inc/gateways/class-paypal-oauth-handler.php` (may need status check helper) - Proxy server code (separate repo/server) + +## Completed Plans + + + + + +## Archived Plans + + + + + +--- + +## Plan Template + +```markdown +### p00X: Plan Title + +**Status:** Planning +**Owner:** @username +**Tags:** #tag1 #tag2 +**Estimate:** ~Xd (ai:Xd test:Xd read:Xd) +**Dependencies:** blocked-by:p001 (if any) +**PRD:** [todo/tasks/prd-{slug}.md](tasks/prd-{slug}.md) +**Tasks:** [todo/tasks/tasks-{slug}.md](tasks/tasks-{slug}.md) +**Logged:** YYYY-MM-DD + +#### Purpose + +Brief description of why this work matters. + +#### Development Environment + + + +| Item | Value | +|------|-------| +| Language/runtime | e.g. Python 3.12, Node 20 | +| Venv/install | e.g. `python3 -m venv .venv && pip install -e ".[dev]"` | +| Tests | e.g. `source .venv/bin/activate && pytest` | +| Do NOT | e.g. install globally; run `pip install -e` from worktree using canonical venv | + +#### Linkage (The Pin) + +| Concept | Files | Lines | Synonyms | +|---------|-------|-------|----------| +| {main concept} | src/path/file.ts | 45-120 | {term1}, {term2} | +| {related concept} | src/path/other.ts | 12-89 | {term3}, {term4} | + +#### Progress + +- [ ] (YYYY-MM-DD HH:MMZ) Phase 1: Description ~Xh +- [ ] (YYYY-MM-DD HH:MMZ) Phase 2: Description ~Xh + +#### Decision Log + +(Decisions recorded during implementation) + +#### Surprises & Discoveries + +(Unexpected findings during implementation) +``` + +--- + +## Analytics + + + + + + From 31736aa51d03be96c72b5550e11dd34309575ea5 Mon Sep 17 00:00:00 2001 From: David Stone Date: Tue, 26 May 2026 09:08:37 -0600 Subject: [PATCH 2/3] ci(e2e): run the 9 cypress specs that existed but were never invoked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The e2e workflow listed only 6 of the 16 spec files in tests/e2e/cypress/integration/. The other 10 were committed and syntactically valid but never executed in CI, so any regression they guarded against could slip through unnoticed. Audit findings (16 specs total): Already in CI (6, unchanged): - 000-setup.spec.js - 010-manual-checkout-flow.spec.js - 020-free-trial-flow.spec.js - 030-stripe-checkout-flow.spec.js (gated, STRIPE_TEST_SK_KEY) - 040-stripe-renewal-flow.spec.js (gated, STRIPE_TEST_SK_KEY) - 065-sso-redirect-loop.spec.js Added to CI in this change (9): - login.spec.js (sanity) - mail.spec.js (sanity) - wizard.spec.js (drives Setup Wizard UI) - 011-password-reset-subsite-domain.spec.js (regression: PR #1169) - 030-modal-form-error-handling.spec.js (UI: AJAX error handling) - 050-password-strength-enforcement.spec.js (UI: zxcvbn scoring) - 060-sso-cross-domain.spec.js (SSO: domain mapping) - 066-sso-bootstrap-race.spec.js (regression: PR #1185) - 035-paypal-checkout-flow.spec.js (gated, new PAYPAL_SANDBOX_*) Intentionally excluded (1): - installation.spec.js — single ‘cy.visit(/wp-admin/)’ call with no assertions; doesn’t actually test anything. Recommend deletion in a follow-up; not removed here to keep this change ci-only. Why wizard.spec.js matters specifically: 000-setup.spec.js bypasses the Setup Wizard UI by calling the installer + setup-finished flag directly. The path Setup_Wizard_Admin_Page::handle_save_settings -> Settings::save_settings -> Field::set_value -> validate_textarea_field was therefore never exercised in CI. The recent fix/textarea-array-coercion fix added unit-test coverage for the validator itself; running wizard.spec.js now covers the integration path. Step organisation (after the existing ‘Run Setup Test’): 1. Sanity Tests — login, mail (smoke) 2. Wizard Test — wizard 3. Regression & UI — 011, 030, 050, 066 4. Checkout Tests — 010, 020 (existing) 5. SSO Tests — 060 (new), 065 (was: only 065) 6. Stripe Tests — 030, 040 (existing, gated) 7. PayPal Tests — 035 (new, gated on PAYPAL_SANDBOX_*) All new groups follow the existing pattern: ‘set +e’ + per-spec loop + aggregated failure count + final exit 1 if any failed, so a single flake doesn’t mask other failures. PayPal step mirrors the Stripe gating: if PAYPAL_SANDBOX_CLIENT_SECRET is unavailable (typical for fork PRs) the step prints the same diagnostic message Stripe uses and exits 0. The PAYPAL_SANDBOX_* repo secrets are not currently configured upstream, so PayPal will skip until they are added; Stripe continues to run. Verification performed in this change: - YAML parse: python3 -c 'import yaml; yaml.safe_load(open(path))' OK - Per-spec node --check on all 9 added specs OK - All referenced fixture .php files exist in tests/e2e/cypress/fixtures - Inventory diff: workflow now references 15/16 specs Local Cypress execution is not attempted in this commit because each matrix variant requires a fresh wp-env (Docker download + WP install + plugin activation + multi-spec run) and would take longer than the CI run that gates the merge. CI is the canonical verification surface for this change. --- .github/workflows/e2e.yml | 200 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 1c2331dbb..207505556 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -194,6 +194,107 @@ jobs: echo "=== PHP error log ===" npx wp-env run tests-cli cat /var/www/html/wp-content/debug.log 2>&1 | tail -100 || echo "No debug.log found" + - name: Run Sanity Tests (login, mail) + id: sanity-tests + run: | + set +e + echo "=== Starting Sanity Tests ===" + + # Smoke tests that don't depend on Ultimate Multisite plugin state — + # verify the WordPress test environment, admin login, and Mailpit + # service are all functional before exercising plugin features. + SANITY_TESTS=( + "tests/e2e/cypress/integration/login.spec.js" + "tests/e2e/cypress/integration/mail.spec.js" + ) + + TOTAL_FAILURES=0 + + for TEST_SPEC in "${SANITY_TESTS[@]}"; do + echo "Running: $TEST_SPEC" + + npx cypress run \ + --config-file cypress.config.test.js \ + --spec "$TEST_SPEC" \ + --browser ${{ matrix.browser }} + + CYPRESS_EXIT_CODE=$? + + if [ $CYPRESS_EXIT_CODE -eq 0 ]; then + echo "✅ $TEST_SPEC passed" + else + echo "❌ $TEST_SPEC failed with exit code $CYPRESS_EXIT_CODE" + TOTAL_FAILURES=$((TOTAL_FAILURES + 1)) + fi + done + + if [ $TOTAL_FAILURES -gt 0 ]; then + echo "❌ $TOTAL_FAILURES sanity test(s) failed" + exit 1 + fi + + echo "✅ All sanity tests passed!" + + - name: Run Wizard Test (Setup Wizard UI) + id: wizard-test + run: | + echo "=== Starting Setup Wizard UI Test ===" + + # wizard.spec.js drives the actual Setup Wizard form submission path + # (handle_save_settings -> Settings::save_settings -> Field::set_value), + # which 000-setup.spec.js bypasses by calling the installer directly. + # The wizard spec clears NETWORK_OPTION_SETUP_FINISHED itself before + # running, then re-marks setup complete at the end — safe to run after + # 000-setup. This regression-guards the addslashes/TypeError class of + # bugs that only surface when the wizard form actually POSTs. + npx cypress run \ + --config-file cypress.config.test.js \ + --spec "tests/e2e/cypress/integration/wizard.spec.js" \ + --browser ${{ matrix.browser }} + + - name: Run Regression & UI Tests (After Setup) + id: regression-tests + run: | + set +e + echo "=== Starting Regression & UI Tests ===" + + # High-value regression guards for previously-fixed bugs and UI + # error-handling. All are self-contained (WP-CLI fixtures or pure + # browser interaction) and need no external credentials. + REGRESSION_TESTS=( + "tests/e2e/cypress/integration/011-password-reset-subsite-domain.spec.js" + "tests/e2e/cypress/integration/030-modal-form-error-handling.spec.js" + "tests/e2e/cypress/integration/050-password-strength-enforcement.spec.js" + "tests/e2e/cypress/integration/066-sso-bootstrap-race.spec.js" + ) + + TOTAL_FAILURES=0 + + for TEST_SPEC in "${REGRESSION_TESTS[@]}"; do + echo "Running: $TEST_SPEC" + + npx cypress run \ + --config-file cypress.config.test.js \ + --spec "$TEST_SPEC" \ + --browser ${{ matrix.browser }} + + CYPRESS_EXIT_CODE=$? + + if [ $CYPRESS_EXIT_CODE -eq 0 ]; then + echo "✅ $TEST_SPEC passed" + else + echo "❌ $TEST_SPEC failed with exit code $CYPRESS_EXIT_CODE" + TOTAL_FAILURES=$((TOTAL_FAILURES + 1)) + fi + done + + if [ $TOTAL_FAILURES -gt 0 ]; then + echo "❌ $TOTAL_FAILURES regression test(s) failed" + exit 1 + fi + + echo "✅ All regression tests passed!" + - name: Run Checkout Tests (After Setup) id: checkout-tests run: | @@ -232,14 +333,43 @@ jobs: echo "✅ All checkout tests passed!" - - name: Run SSO Redirect Loop Tests (After Setup) + - name: Run SSO Tests (After Setup) id: sso-tests run: | - echo "=== Starting SSO Redirect Loop Tests ===" - npx cypress run \ - --config-file cypress.config.test.js \ - --spec "tests/e2e/cypress/integration/065-sso-redirect-loop.spec.js" \ - --browser ${{ matrix.browser }} + set +e + echo "=== Starting SSO Tests ===" + + SSO_TESTS=( + "tests/e2e/cypress/integration/060-sso-cross-domain.spec.js" + "tests/e2e/cypress/integration/065-sso-redirect-loop.spec.js" + ) + + TOTAL_FAILURES=0 + + for TEST_SPEC in "${SSO_TESTS[@]}"; do + echo "Running: $TEST_SPEC" + + npx cypress run \ + --config-file cypress.config.test.js \ + --spec "$TEST_SPEC" \ + --browser ${{ matrix.browser }} + + CYPRESS_EXIT_CODE=$? + + if [ $CYPRESS_EXIT_CODE -eq 0 ]; then + echo "✅ $TEST_SPEC passed" + else + echo "❌ $TEST_SPEC failed with exit code $CYPRESS_EXIT_CODE" + TOTAL_FAILURES=$((TOTAL_FAILURES + 1)) + fi + done + + if [ $TOTAL_FAILURES -gt 0 ]; then + echo "❌ $TOTAL_FAILURES SSO test(s) failed" + exit 1 + fi + + echo "✅ All SSO tests passed!" - name: Run Stripe Tests (After Setup) id: stripe-tests @@ -298,6 +428,64 @@ jobs: echo "✅ All Stripe tests passed!" + - name: Run PayPal Tests (After Setup) + id: paypal-tests + env: + PAYPAL_SANDBOX_CLIENT_ID: ${{ secrets.PAYPAL_SANDBOX_CLIENT_ID }} + PAYPAL_SANDBOX_CLIENT_SECRET: ${{ secrets.PAYPAL_SANDBOX_CLIENT_SECRET }} + run: | + if [ -z "$PAYPAL_SANDBOX_CLIENT_SECRET" ]; then + echo "⏭️ Skipping PayPal tests: PAYPAL_SANDBOX_CLIENT_SECRET not available in this run." + echo "" + echo " The repo secrets PAYPAL_SANDBOX_CLIENT_ID and PAYPAL_SANDBOX_CLIENT_SECRET" + echo " must be configured for these tests to run. GitHub Actions does NOT expose" + echo " secrets to workflows triggered by pull_request events from forked" + echo " repositories — this is a security feature, not a misconfiguration." + echo "" + echo " PayPal tests will run automatically when:" + echo " • this branch is merged to main (push event), or" + echo " • the PR is opened from a branch in the upstream Ultimate-Multisite repo" + echo " AND the PAYPAL_SANDBOX_* secrets have been configured at the repo level." + echo "" + echo " To verify locally, run: gh secret list --repo Ultimate-Multisite/ultimate-multisite" + exit 0 + fi + + set +e + echo "=== Starting PayPal Tests ===" + + PAYPAL_TESTS=( + "tests/e2e/cypress/integration/035-paypal-checkout-flow.spec.js" + ) + + TOTAL_FAILURES=0 + + for TEST_SPEC in "${PAYPAL_TESTS[@]}"; do + echo "Running: $TEST_SPEC" + + npx cypress run \ + --config-file cypress.config.test.js \ + --spec "$TEST_SPEC" \ + --browser ${{ matrix.browser }} \ + --env PAYPAL_SANDBOX_CLIENT_ID="$PAYPAL_SANDBOX_CLIENT_ID",PAYPAL_SANDBOX_CLIENT_SECRET="$PAYPAL_SANDBOX_CLIENT_SECRET" + + CYPRESS_EXIT_CODE=$? + + if [ $CYPRESS_EXIT_CODE -eq 0 ]; then + echo "✅ $TEST_SPEC passed" + else + echo "❌ $TEST_SPEC failed with exit code $CYPRESS_EXIT_CODE" + TOTAL_FAILURES=$((TOTAL_FAILURES + 1)) + fi + done + + if [ $TOTAL_FAILURES -gt 0 ]; then + echo "❌ $TOTAL_FAILURES PayPal test(s) failed" + exit 1 + fi + + echo "✅ All PayPal tests passed!" + - name: Fix permissions for Cypress output if: always() run: sudo chown -R $USER:$USER tests/e2e/cypress From caf596dd9b19c8fac8342f1ade5b200e51f7a80f Mon Sep 17 00:00:00 2001 From: David Stone Date: Tue, 26 May 2026 09:54:55 -0600 Subject: [PATCH 3/3] ci(e2e): disable custom login page after wizard spec The wizard's Default Content step creates a Login page and points Ultimate Multisite's custom-login feature at it, which redirects /wp-login.php -> /login/. The custom page has no #rememberme checkbox, so cy.loginByForm() fails in every subsequent spec's session-setup hook. 000-setup.spec.js already calls setup-disable-custom-login.php defensively in its before() hook for the same reason; this CI step runs the same fixture right after wizard.spec.js so the regression, checkout, SSO, and gated gateway groups inherit a clean login state. Observed on PR #1280 cypress matrix run 26456938227 where 030-modal-form-error-handling failed in its session-setup hook with 'Expected to find element: #rememberme, but never found it', cascading into every subsequent step being skipped. --- .github/workflows/e2e.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 207505556..0054790bd 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -252,6 +252,22 @@ jobs: --spec "tests/e2e/cypress/integration/wizard.spec.js" \ --browser ${{ matrix.browser }} + - name: Reset custom login page (post-wizard cleanup) + id: reset-custom-login + run: | + echo "=== Disabling custom login page after wizard ===" + # The wizard's "Default Content" step creates a Login page and points + # Ultimate Multisite's custom-login feature at it, which redirects + # /wp-login.php -> /login/. The custom page has no #rememberme + # checkbox, so subsequent specs that use cy.loginByForm() fail in + # their session-setup hook. 000-setup.spec.js calls this same + # fixture defensively in its before() hook for the same reason. + PLUGIN_SLUG=$(basename "$PWD") + npx wp-env run tests-cli wp eval-file \ + "/var/www/html/wp-content/plugins/$PLUGIN_SLUG/tests/e2e/cypress/fixtures/setup-disable-custom-login.php" || \ + npx wp-env run tests-cli wp eval-file \ + "/var/www/html/wp-content/plugins/ultimate-multisite/tests/e2e/cypress/fixtures/setup-disable-custom-login.php" + - name: Run Regression & UI Tests (After Setup) id: regression-tests run: |