cp10 standalone checkout engine

14 of 17 REQs done — all engineering complete and e2e-proven; the rollout (REQ-573/574/575) was discarded by user decision on 2026-06-10. cp10 is a reference build: no production traffic, fully tested and locally servable. For understanding how the engine works, read the guided walkthrough — this page is the historical delivery record of the UR-196 batch.

14 done 3 discarded — no deployment

What the deliverable looks like today

This is the cp10 engine served standalone from its own directory (php -S + index.php, screenshot taken 2026-06-09). It returns HTTP 200 with the JS bundle baked in — proof of the REQ-572 live-route delivery and the guarded PHP includes.

cp10 checkout engine rendered standalone: email, name, card fields, PayPal option, Subscribe button
  1. Card payment block — Braintree hosted fields mount here once the engine boots on a real page. Behind this form sits the new explicit decline-code map (REQ-565/566) that replaced fragile substring matching, with every customer-facing error banner preserved verbatim.
  2. PayPal option — its popup lifecycle is broadcast via the hardened, origin-scoped postMessage helper (REQ-567). A declined PayPal payment now reliably shows the PayPal banner instead of generic card advice (REQ-582).
  3. Address-suggestion block, visibly un-hidden — normally hidden by script. It shows here because standalone serving has no page-provided jQuery, which is exactly the documented load precondition: the host page must supply window.jQuery ≥ 3.5. Expected in this context, not a bug.
  4. Subscribe button — on success the engine writes window.newSubData / window.existingSubData, the contract the page's post-purchase hooks read.

All 17 cp10 REQs

REQWhat it delivers, in plain wordsStatusCommit
Built & committed (offline batch complete)
REQ-564Forked cp9's engine into its own directory and severed every path that escaped it — own build, own dependencies, vendored gateway constants. Zero shared code with cp8/cp9, by design.Doneec3ff728
REQ-565Investigated real gateway decline responses (real Braintree sandbox) and specified the explicit decline-code map.Done75494047
REQ-566Replaced the brittle "does the error text contain the word Declined?" matching with that explicit map (src/decline-codes.js) — every banner customers see reproduced exactly, proven by golden-master tests.Donea4be4605
REQ-567Hardened the engine's outbound messaging: all postMessage calls now locked to this site's origin instead of "anyone" ('*'), through one shared helper.Done146178ee
REQ-568Made the engine's analytics version label (checkoutEngineVersion) immutable and suffix-free, so reporting can never silently drift mid-session.Done58c7f5e1
REQ-569Unit tests on all extracted modules — 128 tests green as of this batch, including the load-bearing 3D-Secure safety predicate.Done0af08f2c
REQ-571Wrote the engine's contract down: the prime doc (area index) covering how a page loads the engine, what it must provide, and what comes back.Donea1d0a4c8
REQ-572Live-route delivery (?page=checkout-eet-engine-cp10) verified working with defensive "bundle missing" logging — the scaffold already carried it; confirmed live, no code change.Donecabb4f10
REQ-581Renamed leftover cp9-named internals to cp10 (globals, data-attributes, log labels) — behavior-neutral, all tests still green.Donec749d26e
The gate — passed
REQ-570Playwright e2e of the full page↔engine handshake, 4/4 green: the page's real loader injects cp10 (the cp9 engine URL network-swapped — REQ-573's repoint in test form); card happy path with real Braintree-sandbox tokenization; generic + PayPal decline banners verbatim, including the engine's real PayPal popup flow — the PayPal-400 fix proven end to end. Run with npm run test:e2e from the engine dir.Done6b46d2a6
Rollout tail — discarded 2026-06-10 (user decision: no deployment)
REQ-573A/B-gate the cp9 page so a configurable % of traffic loads cp10, with instant rollback to the cp9 engine. This is the proving step — the first real customers.Discarded
REQ-574Add cp10's adopting page to Feroot PCI script monitoring.Discarded
REQ-575General availability: publish cp10 as one self-contained cached file (cached/…cp10.html?v=YYYYMMDD), which permanently removes the "deploy dropped dist/" failure mode. Rollback = previous version or cp9.Discarded
Hardening follow-ups discovered during the build — all shipped after clarify
REQ-582Fixed the long-standing PayPal-400 banner bug: the decline mapper now receives the attempt's payment-method type, so every PayPal-path failure shows the PayPal banner instead of generic card advice. Built from the captured response shapes; live-capture confirmation is a pre-rollout checklist item for the A/B window.Done10e92bdd
REQ-583Null-guarded the analytics message listener — a third-party message with null data is now ignored instead of throwing. One guard hardens both analytics buffers.Done77c600e5
REQ-584Origin allowlist on the page-side loader's message listener — the receive-side mirror of REQ-567's send-side hardening. (Shared loader, serves cp8/cp9 too.)Done175d9fa5
REQ-585PayPal payer fields are now omitted from fraud-screening (Forter) params when absent — no more literal "undefined" strings sent to the backend.Donea682bb39

How cp10 integrates — and where the isolation line is

The engine is not an iframe. The host page fetches the engine's HTML and injects it into its own document, so page and engine share one window. The robustness comes from where the boundary is drawn: nothing inside the engine directory reaches outside it, and nothing in cp8/cp9 can touch it.

Host page (cp-eet_9) provides: window.jQuery ≥ 3.5, .epcheckout-target container, epCheckoutParams (offer ids, version) et_utils.js loader fetches the engine and injects it same-document checkout-eet-engine-cp10/ (sealed) index.php bundle baked in server-side (no script src); loud console error if dist/bundle.js missing src/ — own copy of everything vendored gateway constants, decline-code map, origin-scoped messaging, immutable version, 3DS predicate, Google Pay, jQuery plugins own package.json + node_modules + dist/ Outbound contract paypalModalStarted / Failed / Closed, analytics events — all same-origin only; window.newSubData / existingSubData on success cp8 / cp9 engines untouched throughout; a break there cannot reach cp10, or vice versa Platform PHP mounts forter / pipa / OneTrust — tolerated serve-time deps, guarded so cp10 runs standalone inject zero shared code

Rollout path (everything reversible at every step)

flowchart LR
    A["Today: built, unit-tested,
e2e-proven — 14 REQs done"] --> B{"Your sign-off
first real customers"} B -->|go| C["REQ-573 A/B gate
small % of cp9-page traffic
+ PayPal live-capture check"] C --> D["REQ-574 Feroot
PCI monitoring"] C -->|proving succeeds| E["REQ-575 GA: cached
self-contained .html?v="] C -.instant rollback.-> R["cp9 engine URL"] E -.rollback.-> R

Limitations — what this does not give you yet

  1. No customer has touched cp10. Until REQ-573 flips the A/B gate, zero production traffic flows to it. Verification so far is unit-level (135 tests) plus a live HTTP serve check — not a real purchase.
  2. The e2e proof ran against mocked declines, not live ones. The card path tokenizes against the real Braintree sandbox, but the decline cases use the captured backend response shapes — the local Go service holds no merchant credentials and implements neither the card nor PayPal legs. Real decline bodies get confirmed during the A/B window (the live-capture checklist item below).
  3. The PayPal-400 fix is built from captured response shapes, not live captures. The four hardening follow-ups (REQ-582–585) are all fixed and test-pinned, but REQ-582's decline-signal design rests on the source-derived backend shapes from the REQ-565 investigation. The pre-rollout checklist item: an operator live-captures real PayPal decline bodies during the A/B window and confirms PayPal-path declines report the PayPal banner in Subscription Error analytics.
  4. The engine cannot run alone by design. It needs a host page providing jQuery ≥ 3.5 and the platform's serve-time PHP mounts. That couples cp10 to the page — never to the cp8/cp9 engines — and is documented as a load precondition, not hidden.
  5. Until the cached GA artifact ships (REQ-575), a deploy filter that drops dist/bundle.js kills the engine. A precise console error surfaces it, but the real cure is the self-contained cached file.
  6. Gateway-ID rotation is now an N-place edit. Vendoring the gateway constants is the accepted price of isolation (the keys are browser-public, so no new secret exposure).

How to get to a well-integrated, robust launch

The architecture work is done; what remains is sequencing. The recommended order:

  1. Give the go for REQ-573 and open the A/B gate at a small percentage — the only remaining decision is yours; every dependency is met. Watch declines, PayPal completion, and analytics labels (cp10 3DS, version field). During this window, run the REQ-582 pre-rollout check: live-capture real PayPal decline bodies and confirm they report the PayPal banner. Rollback is one config change back to the cp9 URL.
  2. REQ-574: add the page to Feroot monitoring during the proving window.
  3. REQ-575: publish the cached versioned artifact and cut over. From then on, rollback is a previous ?v= — and the dist/ deploy trap is gone for good.
Guardrails already in place that keep the architecture robust as it evolves: the isolation grep gate (no path may escape the engine dir), golden-master decline tests (banners can't silently change), 135 unit tests including the 3DS safety predicate, the 4-test load-contract e2e (the page↔engine handshake can't silently break), the immutable version field, and the documented load contract in prime-checkout-eet-engine-cp10.md so the next page integrates from a written spec instead of copying by osmosis.

Verify it yourself

# Isolation gate — must print nothing
grep -rn "\.\./\.\./\.\./shared\|\.\./\.\./shared\|shared/common" \
  web/checkout-eet/p/static/checkout-eet-engine-cp10/src/

# cp8/cp9 engines untouched — must print nothing
git -C web/checkout-eet diff --stat -- \
  p/static/checkout-eet-digital-inline-form p/static/checkout-eet-digital-inline-form-cp9

# Independent build + unit suite (135 tests)
cd web/checkout-eet/p/static/checkout-eet-engine-cp10
npm run build && npm run test:unit

# The load-contract e2e (4 tests; auto-starts PHP on :8100, needs network)
npm run test:e2e

# Serve the engine standalone (what the screenshot shows)
php -S localhost:8123   # then open http://localhost:8123/index.php

# Trace any REQ to its commit
git show ec3ff728   # REQ-564 scaffold; see the table for the other twelve SHAs

AI-generated report (2026-06-09, updated 2026-06-10 after REQ-582–585 and the REQ-570 e2e shipped). REQ statuses, commit SHAs, and the screenshot were verified against the repo and live local runs; test counts (135 unit / 4 e2e) were re-run at the REQ-570 completion and will drift as work continues. Source assets: ai-reports/2026-06-09_2338_UR-196-cp10-engine-status/screenshots/.