# P2HS — Audit-Based Implementation & W4P Reconciliation
**Status doc.** Source audit: `P2HS_CROSS_REPO_AUDIT_2026-10-12.md`. This is the implementation prompt as agreed, with the 5 review edits folded in and execution status tracked inline as work lands. Being executed directly in-session (not handed to Codex).

---

## Resolved decisions (do not re-litigate these)

1. **Nuxt on W4P stays static-generated (`nuxt generate`), not full Nitro SSR-in-Worker.** Phase 2's job for Nuxt is to add a Worker-side router that executes the app's own bespoke `/api/*` handlers alongside the existing static output and platform-catalog routes — not to run Nitro SSR inside the Worker. Same pattern applies to React and HTML. Decided 2026-10-12 after confirming `deployment_targets.py`'s `nuxt_app` build config (commit `61ee880`) already targets `nuxt generate`, and that choice predates this session.
2. **CORRECTED — AUTH-1 WAS live in production.** Initial assessment (checked a stale local `main` ref without fetching) wrongly concluded this never reached `main`. After fetching, `origin/main` was found at `aaec533` itself, pushed there directly (not via a branch merge) at **2026-10-12 12:48:46Z**, which auto-deployed via `.github/workflows/deploy.yml`'s `deploy_main` job (confirmed via `gh run list` — run `38251396095`, completed success). The fix (commits `d36e4eb`, `f2b8351`) was pushed and auto-deployed at **2026-10-12 14:25:25Z–14:26:20Z** (run `38262799429`, completed success). **Real exposure window: ~1h37m on 2026-10-12, 12:48:46Z–14:25:25Z UTC.** Phase 1 §4.3 (exposure response) is therefore NOT moot — see status below for what's still needed.
3. **Track A (AUTH-1) is COMPLETE for the code fix and deployed**; the exposure-response sub-task (§4.3) is OPEN — see below.

## The 5 review edits (applied to the plan below)

1. Phase 0 must verify whether each finding's commit has reached `main`/production before treating any remediation as live-incident response. (Done for AUTH-1; apply the same check for any other finding before assuming production impact.)
2. Phase 0.2's live-DB ground-truth query is against the real production database. Read-only, aggregate/state-flag output only — no per-customer PII pulled into context or this doc.
3. Resolved — see decision #1 above.
4. Add a hard checkpoint after the Workers-runtime-compatibility investigation (original §5.3) and before committing to the full build-out (§5.4–5.10), since that's where Phase 2's real unknowns live.
5. `docs/FEATURE_PACKS_APP_BLOCKS_STARTER.md` (DOC-005) added to the Phase 9 documentation list (was missing).

---

## Implementation priorities (unchanged from the compiled plan)

| Priority | Audit findings | Required outcome | Status |
|---|---|---|---|
| Immediate security | AUTH-1 | Eliminate browser-readable access/refresh-token exposure | **Fix deployed** 2026-10-12; exposure-response scoping still OPEN (see §4.3) |
| P0 hosting | W4P-002, DOC-001 | Real generated backend/BFF execution under W4P | **§5.4 locally verified 2026-10-12.** Application `functions/api` routes execute in the project Worker ahead of the catalog. Not live-certified. Pages projects are unchanged. |
| P0 migration | W4P-001 | Deployment records and hosting flags reflect reality | Not started |
| P1 composition | COMP-1, GP-001 | Pinned composition survives every codegen iteration | Not started |
| P1 generation | GEN-04, GEN-02/06 | No route collisions or disconnected authentication interfaces | Not started |
| P2 contracts | COMP-2, COMP-3 | Operational capability bindings and contract parity | Not started |
| Certification | TEST-001/002, GEN-1 | Real Worker execution tests and representative golden applications | Not started |

---

## Track A — AUTH-1 — COMPLETE (record of what was done)

**Root cause:** `sessionHandoffBody()` in both `src/domain/hosting/runtime/project_runtime.mjs` and `src/domain/codegen/runtime/p2hs-auth-magic.mjs` (introduced together in commit `aaec533`, same commit as a legitimate CDN no-store header fix) wrote the magic-link access/refresh tokens into `localStorage`, `sessionStorage`, and a second non-HttpOnly 7-day cookie, in addition to the correct `HttpOnly` cookies. This exposed a live refresh token to any XSS in a generated app.

**Why it was safe to simply remove, with no compatibility bridge needed:** the current canonical API client template, `src/domain/codegen/runtime/p2hs-app-client.js` (the one and only `RUNTIME_CLIENT_SOURCE` per `runtime_client_contract.py` — no legacy-client branching exists for new/regenerated apps), already has `getAccessToken()` return `""` unconditionally and `setAccessToken()` as a no-op, with a comment stating tokens must never be read from or written to browser storage. It resolves "am I signed in" via `GET /api/auth/me` over the `HttpOnly` cookie (same-origin `fetch` auto-forwards cookies). So the planned §4.2 "compatibility bridge" already exists and needed no new work — the actual bug was just that the magic-link handoff template had drifted out of sync with the already-fixed client.

**Files changed:**
- `src/domain/hosting/runtime/project_runtime.mjs` — `sessionHandoffBody()` stripped back to cookie-handoff + redirect only.
- `src/domain/codegen/runtime/p2hs-auth-magic.mjs` — same fix (this is the codegen-emitted template Pages-Functions/Nitro-route wrappers delegate to; both wrapper files, `magic-consume-route.ts` and `magic-consume-pages-fn.js`, call into this shared function and needed no changes themselves).
- `tests/test_project_runtime.py` — rewrote `test_magic_consume_hands_the_session_to_the_generated_app` (which had asserted the *vulnerable* behavior was required) into `test_magic_consume_never_exposes_the_session_to_browser_readable_storage`, and added `test_codegen_magic_link_template_never_exposes_the_session_either`.

**Verification:**
- `pytest tests/test_project_runtime.py` — 7/7 passed.
- `pytest tests/ -k "magic or auth_magic or project_runtime or codegen_runtime or session_handoff"` — 40 passed, 2 pre-existing failures confirmed unrelated via `git stash` bisection (`test_contract_registry_matches_every_real_exported_function`, `test_the_generated_files_pass_the_guard_that_would_catch_a_regression` — both fail identically with AUTH-1's fix stashed out, so predate this work).
- Confirmed via `git merge-base --is-ancestor aaec533 main` that this never reached production.

**Not done / explicitly out of scope for this track:**
- `scripts/phase5d_migration_inventory.py` — a separate, pre-existing tool for scanning *already-generated customer repos* for this exact `localStorage`/`access_token` pattern. That's retroactive customer-app remediation, a different workstream, requiring live DB + repo-clone access. Flagged, not run.
- The 2 pre-existing failing tests above — unrelated to AUTH-1, not fixed here (scope discipline — don't fold unrelated fixes into a security-fix commit).

**Release gate:** Shipped independently — pushed and auto-deployed to production (`origin/main` `f2b8351`) without the rest of this branch's in-flight W4P/composition work, which remains local-only on `dev/application-foundation` pending its own gates. **Remaining open item: §4.3 exposure-response scoping (query actual magic-link usage during the 1h37m window, decide on session revocation if nonzero).**

---

*(Original full Codex-oriented prompt — Phases 0–10, non-negotiable rules, deliverables, acceptance criteria — retained below verbatim as the reference plan for remaining tracks. Phase/section numbers referenced above match this text.)*

---

# P2HS — Cross-Repository Architecture Reconciliation, W4P-Native BFF Execution, and Generated-App Stabilization

## ROLE

Act as Principal Platform Architect, Staff Runtime Engineer, Cloudflare Workers for Platforms Specialist, Security Engineer, and Cross-Repository Implementation Lead.

**This is an implementation assignment, not another general audit.**

The comprehensive architecture audit has been completed: `P2HS_CROSS_REPO_AUDIT_2026-10-12.md`. Use that document as the authoritative findings register for this implementation, while verifying that referenced code has not changed since the audit.

Do not stop after writing plans. Do not declare implementation complete based only on unit tests or successful Worker uploads.

---

# 1. PRIMARY OBJECTIVE

Align P2HS Core, Cloud, Codegen, Dashboard, starter templates, generated applications, deployment infrastructure, and documentation with one functional W4P-native application architecture.

```
Customer / AI Prompt
         |
         v
Discovery + Recipe Resolution
         |
         v
Pinned GenerationPlan
         |
         v
Capability Admission + Composition
         |
         v
Codegen
         |
         +-- HTML / Nuxt / React
         |
         +-- Static Assets / SSR
         |
         +-- Application-Specific BFF
         |
         +-- Cloud Capability Bindings
         |
         v
Build + W4P Packaging
         |
         v
Per-Project W4P Worker
         |
         +-- Static Asset Serving
         +-- Framework SSR
         +-- Project-Owned API Routes
         +-- Cloud Capability Proxy
         +-- Authentication Handoff
         |
         v
P2HS Cloud
         |
         +-- Auth / AuthZ
         +-- Records / Storage
         +-- Forms
         +-- Files
         +-- Workflows
         +-- Webhooks
         +-- Notifications
         +-- Integrations
         +-- Existing Supported Capabilities
```

> **Note (resolved decision #1):** for Nuxt specifically, "Framework SSR" in this diagram is replaced by "static `nuxt generate` output"; bespoke backend routes are executed by the Worker-side router alongside it, not via Nitro SSR.

The hosting provider should not become the source of application business contracts. P2HS Core remains the control plane. P2HS Cloud remains the authoritative platform capability runtime. W4P executes each project's application-specific Worker runtime.

---

# 2. NON-NEGOTIABLE ARCHITECTURAL RULES

1. Do not introduce new business capabilities.
2. Do not rewrite existing functional Cloud capability handlers.
3. Do not create another competing composition system.
4. Do not retain Cloudflare Pages as the permanent execution dependency for new W4P-native apps.
5. Do not discard existing Pages Functions without preserving their required behavior.
6. Do not route every `/api/*` request blindly to Cloud.
7. Do not duplicate Cloud authentication/authorization logic inside generated BFFs.
8. Do not place Cloud service tokens or raw refresh tokens in browser-readable storage.
9. Do not change customer deployment flags without verifying real deployment state.
10. Do not automatically migrate existing customer applications.
11. Do not mark smoke fixtures as production certification.
12. Do not change production infrastructure or deploy customer apps without explicit authorization.

Preserve existing Core, Cloud, and Dashboard functionality. Preserve Cloud's durable workflow execution model. Preserve the existing working W4P upload, activation, health-probe, versioning, and rollback mechanisms. Prefer correcting shared generators, compilers, contracts, and templates rather than patching individual generated apps.

---

## Phase 0 ground-truth results (2026-10-12, live production Postgres query, read-only aggregate)

Query: latest `project_deploys` row per project, joined against `projects.primary_hosting_provider`. 88 projects, 451 deploy rows total.

| project_flag | latest_deploy_provider | has_provider_namespace | activation_status | deploy_status | count |
|---|---|---|---|---|---|
| cloudflare_w4p_static | cloudflare_pages | false | live | live | **39** |
| cloudflare_w4p_static | cloudflare_w4p_static | false | live | live | **23** |
| cloudflare_w4p_static | cloudflare_w4p_static | false | (null) | failed | 7 |
| cloudflare_w4p_static | (null) | false | (null) | failed | 7 |
| (null) | (null) | false | (null) | (null) | 7 |
| (null) | cloudflare_pages | false | live | live | 2 |
| (null) | (null) | false | (null) | failed | 1 |
| cloudflare_w4p_static | (null) | false | (null) | (null) | 1 |
| (null) | cloudflare_w4p_static | false | (null) | failed | 1 |

**`has_provider_namespace` is false for every single row — 0/88, 100%, no exceptions.** This is worse than W4P-001's original 0/86 finding suggested, now confirmed directly against prod rather than via the self-audit script:
- **39/88 (44%)** are flagged `cloudflare_w4p_static` at the project level but their actual latest deploy was via Cloudflare Pages, `status=live` — these are running on legacy Pages right now, full stop, regardless of what the project record claims.
- **23/88 (26%)** show `activation_status=live, deploy_status=live` for a W4P deploy, yet have no `provider_namespace` recorded at all. Given W4P-002/W4P-001's root cause, this is ambiguous: either the namespace simply isn't being written back on success (an instrumentation gap on an otherwise-real deploy), or `status=live` is itself unreliable. Needs a live namespace existence check (`wrangler dispatch-namespace list`-equivalent) to resolve — not done here, blocked on D1/Cloudflare API access (see below).
- `deployment_target_kind` is `NULL` for every row in the table — entirely unpopulated, a separate data-completeness gap, not pursued further here.
- 7 projects are flagged W4P with zero deploy history at all.

**Action implication for Phase 4 (§7):** the 39-project "flagged W4P, actually on Pages" group is the clearest, lowest-risk reconciliation target — their flag should revert to reflect reality immediately, independent of whether W4P-002 gets fixed, since they are not being served by anything W4P-related today. The 23-project "claims live W4P, no namespace" group needs the live-namespace check before any conclusion.

### Blocked: AUTH-1 exposure-response query (§4.3)
Attempted to query Cloud's `cloud_auth_events` D1 table (`p2hs-cloud`, database id `f01a2da8-12b3-494d-85f0-e5c9bf263acb`) for `magic_link_verified` events in the 12:48:46Z–14:25:25Z window. Both available Cloudflare API tokens in `P2HS-BE/.env` (`CLOUDFLARE_API_TOKEN`, `NEW_CLOUDFLARE_API_TOKEN`) returned `code: 7403` (account not authorized for this service) via `wrangler d1 execute --remote`. This needs either a token scoped for D1 access, or the user running the query directly. Not resolved as of this writing.

### Phase 0.1 local baseline (2026-10-12, no production writes)

| Repo | Branch | HEAD | Dirty tree kept as-is |
|---|---|---|---|
| P2HS-BE | `dev/application-foundation` | `838d11f` | Uncommitted composition-pin work (`public.py`, discovery pin, recipe service, discovery tests, three composition docs) plus untracked `w4p-audit.json`. Not overwritten. |
| P2HSCloud | `dev/application-foundation` | `0eb0c02` | Untracked `b3-evidence/` only. |
| P2HS-Dash | `main` | `5ac2605` | Uncommitted Discovery label fix, plus unrelated connector page/type edits. |

`P2HS_CROSS_REPO_AUDIT_2026-10-12.md` is still not in the workspace. This checkpoint uses the prompt's own W4P-002 statement and the current source, not that missing register. `w4p-audit.json` is a local per-project dump and is not copied here.

---

## §5.3 packaging checkpoint (2026-10-12) — STOP before 5.4

Reviewed `worker_source.py`, `project_runtime.mjs`, `routing_contract.py`, `runtime_projection.py`, `adapters/w4p_static.py`, `w4p_activation.py`, `w4p_workflow.py`, `deployment_targets.py`, and the codegen Pages Function templates under `src/domain/codegen/runtime/*pages-fn.js`.

**What a W4P deploy actually runs.** `build_worker_source()` concatenates `project_runtime.mjs` with one fetch entry. Any path under `/api` is matched only against the platform-port catalog baked at upload time, plus four application-file routes. Every other path is `env.ASSETS.fetch`. A miss is `404 route_not_found`. A catalog row with no Cloud path is `501`. Both the Python uploader and the GitHub Actions uploader put a single module, `worker.js`, on the script. `functions/` is not in that module set, and the static asset directory is the framework build output (for Nuxt, `.output/public` after `nuxt generate`), not the repo's `functions/` tree.

**What Pages actually runs, and the Worker does not.** Codegen still writes `functions/api/**` as `onRequest({ request, env, params })` modules, and a parallel Nitro `server/api/**` wrapper for the same shared libraries. The Pages modules import `_lib` helpers (`p2hs-forms-submit.mjs`, `p2hs-files.mjs`, `p2hs-auth-magic.mjs`, `p2hs-ports.mjs`) and use Workers APIs (`Request`, `Response`, `fetch`, headers). They do not import `node:`. The Nitro wrappers do read `process.env`; those wrappers are the Pages/Nitro adapter, not a Worker entry. File routing is what supplies `params.formKey` and catch-all `path`. The W4P matcher only understands `:name` segments that were compiled from the catalog.

**Nuxt stays static, and that drops `server/api`.** `generate_w4p_deploy_workflow` already replaces the Nuxt build with `NITRO_PRESET=cloudflare_pages npx nuxt generate` and uploads the public output. That matches resolved decision #1. It also means a Nuxt app on W4P currently serves the static site and the catalog proxy only. Neither `server/api` nor `functions/api` is executed.

**Pages Functions can be executed inside the project Worker. They cannot be dropped in unchanged.** They already target the Workers runtime, so this is a routing-convention conversion, not a second runtime. The current upload is one concatenated module, and the Pages modules are many files with relative imports and a `context.params` object the fetch handler never builds. `runtime_projection.py` already keeps the two strategies apart: W4P is `bff_proxy`, legacy Pages is `pages_functions`. Do not collapse that by flipping a global hosting flag.

**Contract to review before 5.4. Not implemented.**

1. One Worker module graph: assets binding, plus a fetch router.
2. Precedence: application routes compiled from `functions/api/**`, then catalog Cloud routes, then the two handlers already special-cased in `project_runtime.mjs` (`/api/__p2hs/health` and magic-link consume), then static assets with the existing SPA fallback.
3. Application handlers are the existing `onRequest` modules, bundled with their `_lib` imports. The router builds `{ request, env, params }` from the file path. Do not execute Nitro `server/api` handlers, and do not read `process` inside the Worker.
4. Build fails when an application route and a catalog route share method and path, or when a handler imports `node:` or `process`. `backend_guard.route_overlaps` already rejects a homemade route that shadows a platform port at codegen time; that check does not run when `worker.js` is assembled.
5. Projects still on Pages stay on `pages_functions` until a per-project route inventory says they are eligible. No production flag rewrite in this step.
6. Customer repos can contain vertical handlers that are not one of the 13 platform templates in Core. Those were not inventoried here. Migration of those apps stays blocked.

**§5.4 implemented locally, not live-certified.** `bundle_application.mjs` compiles `functions/api/**` into the Worker prelude. The fetch handler calls `dispatchApplication` before `handleApiRequest`. GitHub Actions upload does this from the repo checkout. Core's static uploader does it only when `build_metadata.repo_root` is set. A repo with no `functions/api` keeps the catalog-only Worker.

Ownership rule hardened 2026-10-12: application-first routing is preserved only for an explicitly locked platform artifact. The compiler compares every `functions/api/**` route against the catalog, application-file routes, and the reserved health route. An overlap is accepted only when the exact handler path is present in `p2hs/platform-ports.lock.json`, its SHA-256 matches, and the lock declares the overlapping route. An unlocked handler fails with `protected_platform_route_collision`; this prevents arbitrary application code from shadowing auth, staff, tenant-scoped capability, file, or health endpoints. Two application files claiming the same method and canonical path still fail the build (`[formKey]` and `[form_key]` included). `node:` imports, `process`, TypeScript functions, missing handlers, and invalid lock files fail before upload. Nitro `server/` routes are not read. Existing Pages workflows are not switched.

**Phase 2 hardening evidence (2026-10-12, local only):**
- Baseline `HEAD`/`origin/main`: `838d11f`; relevant prior committed W4P/runtime foundations include `bb12c6a`, `629e050`, `61ee880`, and `0e2ebf6`. The Phase 2 compiler, packaging, ownership hardening, and tests listed below remain uncommitted in the dirty `dev/application-foundation` worktree; they were not mixed into the unrelated composition changes.
- Files: `src/domain/hosting/runtime/bundle_application.mjs`, `worker_source.py`, `project_runtime.mjs`, `w4p_workflow.py`, `adapters/w4p_static.py`, `tests/test_w4p_application_routes.py`.
- The Python uploader and GitHub Actions uploader now pass the same protected-route manifest into the bundler. The Worker adapter passes the execution context, including `waitUntil`, to Pages Functions. Application exceptions become a non-leaking 500 response; Cloud upstream failures become a 502 response.
- `python -m pytest -q --basetemp .pytest-phase2 tests/test_w4p_application_routes.py tests/test_w4p_static_adapter.py tests/test_runtime_ownership.py tests/test_routing_contract.py` — **38 passed**.
- Wrangler/workerd probe: `npx --yes wrangler@4.149.0 dev --config .phase2-wrangler-runtime/wrangler.jsonc --local --ip 127.0.0.1 --port 8791 --log-level error`. Real requests verified dynamic `POST` dispatch and params, `waitUntil`, request body, cookie forwarding, response cookies, environment bindings, `/api/__p2hs/health`, static assets, catalog fallback, and a normalized 502 upstream failure. The disposable probe files were removed after execution.
- The existing generated runtime fixtures cover the canonical forms handler and the locked platform-artifact path; the new negative fixture proves an unlocked forms shadow is rejected. This is not yet a full five-application certification matrix or a dispatch-namespace certification.

**5.5–5.10 status:** compiler/bundler integration and local Worker-runtime evidence are **implemented and locally tested**. Static-only, form, booking, staff-authenticated, and Nuxt generated applications have **not** each been functionally certified through their own disposable generated build under the Worker. No production hosting rows were changed. Live W4P certification is **BLOCKED** pending approved disposable namespace credentials and Cloud test data; existing customer deployments were not modified. AUTH-1 exposure scoping remains blocked on D1 access.

---

# 3. PHASE 0 — ESTABLISH DEPLOYMENT AND SOURCE GROUND TRUTH

## 3.1 Repository baseline
Record branch, commit, dirty working tree, uncommitted changes, unmerged feature work, and applicable configuration flags for P2HS-BE, P2HSCloud, P2HS-Dash, Codegen runtime, HTML/Nuxt/React starters, P2HS-Docs, and relevant golden-project fixtures. Preserve in-flight uncommitted composition-recipe work rather than overwriting it. **(Edit 1: also record, per finding, whether its introducing commit has reached `main`/production before scoping remediation as live-incident vs. pre-release.)**

## 3.2 Real deployment state
Inspect `primary_hosting_provider`, deployment provider, `provider_namespace`, `projection_state`, Worker script identity, active version, routing KV entry, Pages deployment state, actual dispatch namespace presence. Investigate W4P-001 (86 projects examined, 77 flagged `cloudflare_w4p_static`, 0 latest-deployment rows with `provider_namespace`, ≥51 still on legacy Pages per independent corroboration). Do not assume these counts are still current. Produce a read-only per-project ground-truth report. Do not correct production rows automatically. **(Edit 2: this is a live production DB query — read-only, aggregate/state-flag output only, no per-customer PII.)**

## 3.3 Audit tooling
Inspect `audit_w4p_migration.py` and its URL handling, including the `cc679f3` fix. Determine whether previous `UnsupportedProtocol` failures remain reproducible. Do not report stale health-probe results as current production outages. Also explicitly name and track **W4P-004** here: which build command actually runs per project (Pages build honoring `functions/` vs. the newer static-only path) — not determinable from static code alone.

## 3.4 Output
Create a baseline artifact containing the verified architecture and deployment state. Proceed with local implementation even if live credentials are unavailable, but keep live migration certification blocked.

---

# 4. PHASE 1 — IMMEDIATE AUTHENTICATION SECURITY REMEDIATION — ✅ COMPLETE

Finding: **AUTH-1**. See "Track A — COMPLETE" section above for what was actually done. Sections 4.1–4.4 below are retained for reference; 4.3 (exposure response) was dropped per resolved decision #2 (never reached production).

## 4.1 Required changes — DONE
Removed raw access/refresh token persistence through `localStorage`, `sessionStorage`, JS-readable cookies. Preserved the existing secure `HttpOnly`/`Secure`/`SameSite=Lax` cookie design. End-user identity continues to forward to Cloud without service-credential substitution (confirmed pre-existing and correct, `project_runtime.mjs:169-172`).

## 4.2 Compatibility — DONE, no new bridge needed
Confirmed the current canonical client (`p2hs-app-client.js`) already never reads tokens from browser storage, and already has `/api/auth/me` working over cookie auth. No new bridge was required — the magic-link handoff template had simply drifted out of sync with it.

## 4.3 Exposure response — OPEN
Real exposure window confirmed: **2026-10-12 12:48:46Z–14:25:25Z UTC (~1h37m)**. The vulnerability only mattered if an attacker had an XSS vector against a generated app AND a user completed a magic-link sign-in during that window — not automatic mass compromise, but not provably zero-impact either. Needed before this sub-task can close:
- Query (read-only) how many magic-link consumptions occurred in that UTC window, and which projects/sessions they belong to, to scope actual (not theoretical) exposure.
- Based on that count: if zero, close with no action; if nonzero, decide with the user whether targeted session revocation / forced reauth for just those sessions is warranted (per the plan's own rule: no mass invalidation without approval).
- Not yet executed — requires the live production DB query from Phase 0.2, which hasn't run yet.

## 4.4 Verification — DONE
Tests added per the acceptance gate's intent: handoff never writes raw tokens to JS storage, no non-HttpOnly token cookie emitted, `HttpOnly` cookies still set correctly, redirect still works. (Logout/replay/protected-route tests are pre-existing elsewhere in the suite and were not touched.)

**Acceptance gate: MET.**

---

# 5. PHASE 2 — IMPLEMENT REAL W4P-NATIVE APPLICATION BFF EXECUTION

Finding: **W4P-002**. This is the primary architectural remediation and the largest remaining track.

## 5.1 Existing problem
The current W4P Worker executes a limited declarative platform-capability route catalog. It does not execute the bespoke per-vertical backend logic present under generated `functions/api/**` (bookings, staff/admin operations, customer-specific operations, form processing, custom workflow initiation, application-specific responses, domain-specific validation).

## 5.2 Required architectural decision
Implement native application-specific BFF execution inside the project's W4P Worker. Do not permanently forward bespoke backend requests to a legacy Pages project. Do not just add more route names to the platform-capability catalog. Do not move arbitrary generated business logic into P2HS Cloud.

## 5.3 Inspect current packaging — ⚠️ CHECKPOINT BEFORE 5.4–5.10 (Edit 4)
Review `worker_source.py`, `project_runtime.mjs`, `routing_contract.py`, `runtime_projection.py`, `w4p_static.py`, `w4p_activation.py`, generated Pages Functions, Nitro build output (static-only per resolved decision #1), React build conventions, HTML starter behavior, codegen runtime adapters, existing bundling/build scripts. Determine whether Pages Functions can be bundled into the W4P Worker's fetch handler safely (this is more a routing-convention conversion than a new-runtime problem, since Pages Functions already run on the Workers runtime — confirm this empirically before assuming either way). **Do not proceed to 5.4–5.10 until this investigation's findings are reviewed** — if full native execution isn't uniformly achievable across frameworks, the canonical-contract design in 5.4 needs to be revised first.

## 5.4 Create one backend execution contract
One canonical application runtime contract: route manifests, route ownership, framework runtime entrypoint (static for Nuxt per decision #1), application-specific handlers, Cloud capability routes, static asset handling, middleware, authentication context, deployment bindings. Avoid overlapping route registries. Build should produce a complete deployable Worker bundle, not assume `functions/` is auto-executed.

## 5.5 Support framework-specific execution
- **Nuxt:** static `nuxt generate` output (confirmed, decision #1) + Worker-executed bespoke API routes. No SSR-in-Worker requirement.
- **React:** determine the actual React starter's runtime model; support generated backend handlers in the Worker regardless of SPA-vs-SSR build.
- **HTML:** preserve lightweight static hosting; if an HTML app admits forms/records/auth, it needs a valid execution path (lightweight Worker/BFF adapter or explicit Cloud capability route) — never a silently nonfunctional feature. HTML is not "fully capability-compatible" until tested (ties to GEN-1 / Phase 10).

## 5.6 Route ownership
Deterministic precedence: application-owned API routes → platform-owned Cloud capability routes → auth/authz routes → framework static/SPA routes → static assets → explicit fallback/404. Based on explicit ownership contracts, not blanket URL prefix. Conflicts rejected at build/generation time; ambiguous routes fail closed.

## 5.7 Execution semantics
Preserve method, path, query, headers, body streaming, cookies, authenticated user context, bindings, response headers, status, redirects, errors. Do not silently substitute unsupported Node APIs. Unsupported backend code should produce a clear build-time compatibility error, not a silent runtime failure.

## 5.8 Cloud capability boundary
Application BFF handlers may invoke admitted Cloud capabilities. Cloud remains responsible for authoritative auth, authorization, durable data, capability/workflow execution, webhooks, provider integrations — do not replicate these in Worker bundles. Project Workers must not acquire elevated authority through forwarded end-user requests.

## 5.9 Build-time safeguards
Fail generation/deployment if: a required backend route is missing; a route has no executable handler; two handlers collide on path/method; an unsupported runtime API is present; an unresolved Cloud binding is required; a service token is embedded in generated source; static assets/entrypoints are missing; the declared hosting mode can't execute the app.

## 5.10 Compatibility strategy
Keep existing Pages-backed apps on their current mechanism until migration eligibility is proven. Where legacy Pages Functions need conversion, do it via a common compilation adapter with explicit compatibility tests — not a manual per-vertical rewrite.

**Acceptance gate:** a newly generated W4P application must execute: public static route, application-owned API route, Cloud capability route, authenticated route, staff-authorized route, data mutation, data readback, validation failure, error response — verified by actual Worker behavior, not generated source inspection.

---

# 6. PHASE 3 — FIX DISPATCHER OWNERSHIP AND LEGACY ROUTING

Findings: **DOC-001, TEST-001**. Note: this targets the separate `legacy`/two-plane routing policy in `routing_plane.py`, not the new W4P-native dispatcher (which RT-001 already confirmed behaves correctly — real route matching, clean 404, no blind forward). **This track does not strictly depend on Phase 2 completing and can run in parallel with Track B if resourcing allows.**

Inspect `src/domain/hosting/routing_plane.py`. Ensure W4P-native projects use the compiled route ownership contract. Do not globally rewrite all `/api/*` calls into Cloud routes. Preserve legacy routing only for projects still running legacy Pages deployments, explicitly and deployment-scoped — never merely because a global hosting flag changed.

Replace `test_routing_contract.py`'s source-substring-only assertions with executable dispatcher tests: application-owned routing, Cloud-owned capability routing, legacy Pages routing, auth routes, staff routes, static routes, unknown paths, host isolation, cookie preservation, missing Worker scripts, incorrect route ownership.

**Acceptance gate:** real dispatcher execution matches the declared ownership contract for each supported hosting generation.

---

# 7. PHASE 4 — MAKE HOSTING STATE TRUTHFUL AND PER-PROJECT

Finding: **W4P-001**.

## 7.1 Required change
Make hosting execution and provider resolution project/environment aware. A global setting may specify the default for *new* deployments but must never override an existing project's authoritative active deployment. Distinguish requested / build / uploaded / validated / active / previous provider, and migration state — don't collapse intent and reality into one flag.

## 7.2 Activation
Only mark a W4P deployment active once: Worker script uploaded, dispatch namespace correct, bindings valid, static assets available, runtime entrypoint exists, required API routes present (depends on Phase 2), health checks pass, routing pointer activated. Store actual provider namespace and active artifact identity. Prevent an incomplete upload from flipping the project to W4P.

## 7.3 Migration reconciliation
Read-only migration preflight and dry run per project: active Pages deployment, generated backend routes, BFF compatibility, W4P Worker existence, domain routing, authentication, required capabilities, migration eligibility. Do not modify project flags solely from the global provider setting. Inconsistencies → a proposed correction script, not an automatic mutation. All production-state mutations require approval.

## 7.4 Rollback
Preserve the last known healthy deployment; rollback must restore both routing behavior and correct active-provider metadata. Never report W4P active when the hostname actually points to Pages.

**Acceptance gate:** project-level hosting state agrees with the actual active deployment and routing target. W4P-native migration stays blocked for any project with unresolved application-specific backend routes.

---

# 8. PHASE 5 — RECONCILE COMPOSITION ACROSS EVERY CODEGEN TURN

Findings: **COMP-1, GP-001, TEST-002**.

## 8.1 One authoritative composition lifecycle
Discovery → Recipe Pin → Initial GenerationPlan → Installed Plan → Subsequent Reconciliation → Explicit Approved Changes. Do not create another composition source of truth.

## 8.2 Fix pinned recipes
Inspect `composition_reconcile.py`, `codegen.py`, `composition_recipes/service.py`, `discovery_apply.py`, `project_discovery.py`, `write_brief_files`. Ensure `composition_recipe_pinned`/`composition_recipe_slug` are honored in every subsequent codegen turn, not just first-build. A pinned null recipe must not be silently re-resolved. The initial plan, GenerationPlan, and customer Discovery view must derive from the same admitted recipe closure.

## 8.3 Distinguish immutable baseline from authorized modifications
Pinning prevents accidental drift, not legitimate user changes. When a customer explicitly asks for new functionality: detect the requested change, validate capability admission, reconcile against the installed plan, preserve existing functionality, record the plan revision, surface material capability changes, require approval for new privileged capabilities / paid integrations / destructive changes. Do not silently add unrelated App Blocks because conversational text changed.

## 8.4 Installed snapshots
Inspect migration 186 / `installed_composition_snapshots`. If intended to preserve installed composition, connect it to the real install/reconcile lifecycle so catalog updates don't silently rewrite installed project functionality. Versioned, deterministic installed-plan snapshots.

## 8.5 Tests
Cover: initial Discovery pin, pinned null recipe, first build, second codegen turn, unrelated prompt changes, explicit feature additions/removals, catalog restamping, legacy unpinned projects, concurrent reconciliation, GenerationPlan consistency, installed-plan persistence.

**Acceptance gate:** every codegen turn reconciles against the authoritative installed composition while allowing explicit, validated modifications.

---

# 9. PHASE 6 — FIX GENERATED-APP FUNCTIONAL DEFECTS

Findings: **GEN-04, GEN-02/06, GEN-1**.

## 9.1 Route collisions
Fix the confirmed `[formKey]` vs `[form_key]` collision. Canonicalize dynamic route identity independent of parameter spelling; reject collisions at build time; keep one canonical route and update generated callers.

## 9.2 Auth interface integration
Inspect older golden seeds where `SignInForm`/`P2hsStaffDashboard` exist but aren't imported into real routes. Determine whether `auth-session-v4` (seen in `.b3-golden-simple`) already fixes this. If so, mark older fixtures legacy and stop presenting them as current evidence; if not, fix the generator and starter route wiring — not just the checked-in fixture.

## 9.3 Functional UI integrity
Every admitted capability needs: a real route, a real handler, correctly bound backend data, enforced authorization, working success/error states, reachable navigation. No placeholder CRUD, no decorative buttons without handlers, no fake hardcoded dashboards unless explicitly sample/demo content.

## 9.4 Starter parity
Common certification matrix across HTML, Nuxt, React with explicitly defined supported behaviors per starter. Don't force HTML into SSR-like behavior, but backend-dependent admitted functionality must execute through a supported mechanism or be rejected at admission.

---

# 10. PHASE 7 — CAPABILITY CONTRACT AND BINDING RECONCILIATION

Findings: **COMP-2, COMP-3**.

## 10.1 Capability bindings
`capability_bindings` is schema-only. Determine whether the host → companion → Cloud → provider resolution design is still approved. If yes, implement the missing producer/consumer lifecycle using existing schemas/abstractions — no duplicate registry. If superseded, document that and provide a safe deprecation plan rather than dropping customer data.

## 10.2 Core ↔ Cloud capability parity
Automated consistency gate between Core's capability catalog, Cloud's capability contracts, App Block/Feature Pack dependencies, provisioning adapters, generated route manifests. Separate user-facing categories from executable Cloud request types (e.g. `records` ≠ necessarily one endpoint) via explicit mappings, not forced name-matching. Fail CI on genuine unsupported/contradictory admitted contracts.

## 10.3 Preserve Cloud capability ownership
No duplicating Forms/Records/Files/Workflows/Notifications/Auth inside application Workers — orchestrate and invoke, don't reimplement.

---

# 11. PHASE 8 — AUTHZ AND EDGE ATTESTATION

Findings: **AUTH-3 and AuthZ rollout status**. Preserve the existing AuthZ v2 implementation — do not redesign it. As of 2026-10-12: fail-closed per-project promotion implemented, Cloud readback proof required, both golden fixtures certified 2026-10-11, cohort checklist (`AUTHZ_V2_COHORT_CHECKLIST.md`) confirmed accurate (a rare positive control, not drifted).

Determine real promotion state for existing projects via authorized read-only DB inspection (ties to Phase 0.2). Do not auto-promote production cohorts. For edge attestation: keep report mode while measuring false positives and validating WP/Shopify machine-caller compatibility; document enforcement prerequisites; preserve rollback. Treat attestation enforcement as a separate approved operational change, never bundled into an unrelated W4P commit.

---

# 12. PHASE 9 — REPAIR DOCUMENTATION DRIFT

Update documentation only after the corresponding implementation is verified. Priority list (Edit 5 adds the fifth item):
- `W4P_ROUTING_CONTRACT.md`
- `ARCHITECTURE_HOSTING_TWO_PLANE.md`
- `COMPOSITION_RECIPES_ARCHITECTURE.md`
- `FAST_LANE_ARCHETYPE_STARTERS_FEATURE_PACKS.md`
- `FEATURE_PACKS_APP_BLOCKS_STARTER.md` *(added — one of the three docs actively being hand-corrected in this session's working tree)*
- Deployment/migration runbooks, starter runtime contracts, generated-app hosting docs, capability binding docs.

Describe Gen1/Gen2/Gen3 accurately; document Gen3 as target; never call Gen2's Pages dependency permanent. Retain legacy docs where still needed for currently deployed projects. Use explicit operational-state labels (Implemented / Locally verified / Integration tested / Live certified / Deployed / Deprecated) — never present future intentions as present-tense fact. Update public Mintlify docs only where customer-facing behavior actually changed.

---

# 13. PHASE 10 — BUILD REAL CERTIFICATION INFRASTRUCTURE

Finding: **GEN-1 and testing gaps**. Confirmed: the ~23 "named vertical fixtures" are actually 5 distinct content payloads cloned under many names, each self-labeled a CI smoke fixture; HTML has zero fixtures. Do not count cloned fixtures as independent certification.

## 13.1 Representative applications
Build/improve fixtures for: static HTML marketing site; HTML app with admitted form/backend functionality; Nuxt authenticated customer portal; React authenticated staff CRUD app; restaurant booking; ecommerce; CRM/lead-management; content-driven app. Each must exercise genuinely distinct workflows. Prefer a small trustworthy suite over a large cloned directory.

## 13.2 Required test levels
Static contract tests; generated build tests (actually install + build); Worker execution tests (instantiate/execute the built Worker, send real HTTP requests — not string-inspect generated JS); Cloud integration tests; authenticated browser tests (real magic-link → session → protected route → logout); W4P live tests (disposable projects to a real dispatch namespace: static delivery, BFF execution, Cloud routing, auth, authz, persistence, rollback — authorized test infra only); visual tests (desktop + mobile, functional certification still required separately).

## 13.3 CI gates
Fail-closed checks for: missing executable handlers; route collisions; incorrect route ownership; missing runtime bindings; service-token leakage; raw browser-readable session-token persistence (this exact AUTH-1 class — add a CI check, not just a unit test); invalid composition reconciliation; starter incompatibility; broken generated builds; mismatched capability contracts; invalid W4P artifact manifests. Keep live-environment certification separate from local CI.

## 13.4 Professional UI baseline
Only after functionality is verified: responsive navigation, consistent typography/spacing, accessible controls, real loading/error/empty states, proper forms/validation, usable tables/CRUD dialogs, clear operational feedback. Use existing design tokens/App Block conventions. No unrelated design-system rewrite.

---

# 14. DEPLOYMENT SAFETY AND MIGRATION POLICY

No automatic migration of existing customer projects. Per-project eligibility requires: known backend route inventory; routes compile into a W4P-executable runtime; valid Cloud capability bindings; working auth; working authz; working static/SSR output; working data mutation/readback; understood production hostname mapping; available rollback; passing relevant golden certification. Projects with unresolved custom Pages Functions stay on the legacy path. No global hosting switch migrates existing projects. Production rollout requires separate approval and a cohort plan.

---

# 15. EXECUTION ORDER AND CHANGE MANAGEMENT

**Track A — Security.** AUTH-1 containment, tests, deploy. **Code fix shipped; exposure-response scoping (§4.3) still open.**
**Track B — Hosting foundation.** Phase 0 ground truth, W4P-002 native BFF execution, DOC-001 dispatcher corrections (can run parallel to W4P-002, see Phase 3 note), W4P-001 deployment-state consistency.
**Track C — Composition.** COMP-1/GP-001 pin/reconcile consistency, installed-plan snapshots.
**Track D — Generated functionality.** GEN-04 route collisions, authentication wiring, starter correctness.
**Track E — Capability contracts.** COMP-2 binding lifecycle, COMP-3 catalog parity.
**Track F — Documentation and certification.** Doc reconciliation, golden builds, CI gates, W4P execution tests, authenticated browser tests.

For each track: identify affected finding IDs → verify present source state → implement the smallest coherent correction → add regression tests → run relevant tests → record exact evidence → commit coherent changes → document remaining blockers. Do not merge unrelated work into one unreviewable commit. Do not claim a track complete if its critical acceptance test failed or could not run.

---

# 16. REQUIRED IMPLEMENTATION DELIVERABLES

**A. Implementation Ledger** — per finding: ID, original severity, current status, root cause, files changed, implementation description, tests added/passed/failed, evidence, remaining blockers. *(Track A's entry is the "Track A — COMPLETE" section above; extend this pattern per track.)*
**B. Architecture Contract** — final Core/Cloud/W4P Worker/Dispatcher/generated-app execution ownership.
**C. W4P Execution Matrix** — static, SSR (N/A for Nuxt per decision #1), app-specific BFF, Cloud capability, auth, staff, webhook behavior.
**D. Migration Ground Truth** — verified deployment state, no PII.
**E. Composition Consistency Report** — Discovery → GenerationPlan → installed plan → reconciliation evidence.
**F. Starter Reliability Matrix** — HTML/Nuxt/React against real tested capabilities.
**G. Certification Evidence** — local/integration/live-Worker/browser results, kept separate.
**H. Documentation Changes** — updated docs + supporting evidence per correction.
**I. Release Readiness** — separate GO/NO-GO for: auth security release (**GO — shipped**), new static W4P deployments, new backend-bearing W4P deployments, existing-customer W4P migration, composition pin guarantee, AuthZ cohort continuation, edge attestation enforcement.

---

# 17. FINAL ACCEPTANCE CRITERIA

Do not mark overall reconciliation complete unless: AUTH-1 fixed and regression-tested (✅); W4P executes application-owned backend routes; legacy Pages-dependent apps remain functional; routing honors explicit ownership; deployment state matches active provider; Worker upload/activation never implies unsupported backend functionality; pinned composition stays consistent across regeneration; generated routes can't collide silently; generated auth interfaces reach real handlers; capability admission matches runtime availability; HTML/Nuxt/React have truthful support matrices; representative applications build and execute; documentation agrees with verified implementation; CI detects the audit's major drift classes; live certifications are clearly distinguished from mocked tests; existing customer deployments are not changed without approval. Unverifiable conditions are marked BLOCKED or UNVERIFIED, not PASSED.

---

# 18. RELEASE GATES (current)

| Gate | Status |
|---|---|
| Auth token security | **Code fix shipped & deployed to prod 2026-10-12 14:26 UTC.** Real exposure window 12:48:46Z–14:25:25Z (~1h37m) — exposure-response scoping (§4.3) still open, pending a DB check for actual magic-link usage in that window. |
| W4P backend applications | NO-GO — blocked on Phase 2 |
| Static-only W4P | Conditional GO — pending Phase 0 ground-truth confirmation |
| Composition pin guarantee | Not certified — blocked on Phase 5 |
| Existing customer migration | NO-GO — blocked on per-project readiness, Phase 4 |
| AuthZ cohort continuation | GO — process is sound, continue per existing checklist |
| Edge attestation enforcement | Hold — stay in report mode pending false-positive measurement |
