# Lane R8 — PG-34 upgrade proof receipt (2026-08-22)

Status: **PG-34 GREEN end-to-end.** Upgrading from the previously deployed release ZIP `0.9.74` to the release candidate `0.9.84` through the wp-admin upload flow preserves plugin settings, workflow-state rows, and customer-edited content, and leaves the new version active with a working admin SPA — proven by a remote Playwright run on a stack with **no source checkout mounted**.

## 1. Artifacts

- Old (previously deployed) ZIP: `international-press-zone-0.9.74.zip`
  - SHA-256: `5720476d82f96796de9d639d61195745e7f528916ff8ca62f3776499962c5716`
  - Provenance: the dev1 deployment artifact retained in the `ipz-dev1-deploy` worktree.
- Candidate ZIP: `international-press-zone-0.9.84.zip`
  - SHA-256: `507f747aac02e93df9e8da6007d12ff01d6103454bc3c89e543e622755e40c22` — byte-identical to the PG-33 artifact (see `golive-lane-r7-20260822-pg33-proof.md`); retrieved from the lane R7 remote mirror and hash-verified.
- Base commit: origin/master `caf14faf2` (includes the landed PG-33 capability and Release 0.9.84).
- Capability commit: `41b1ff3c7` (`upgrade-zip.spec.js`, `UPGRADE.md`, mu-plugin seed/readback helper in `remote-stack.sh`).

## 2. Test capability

Spec: `tests/e2e/upgrade-zip.spec.js`, stack mode `IPZ_STACK_NO_PLUGIN_MOUNT=1`. Env contract (all four required, no fallbacks): `IPZ_OLD_ZIP_PATH`, `IPZ_ZIP_PATH`, `IPZ_OLD_VERSION`, `IPZ_EXPECTED_VERSION`.

State seeding/readback happens through a **test-only mu-plugin** (`ipz-e2e-state.php`) that `remote-stack.sh` writes into the disposable E2E volume's `mu-plugins/` in no-mount mode — it is never part of the plugin source or any release ZIP. Both REST routes (`ipz-e2e/v1/seed`, `ipz-e2e/v1/readback`) and the nonce endpoint require `current_user_can('manage_options')`.

The spec, in one chromium session:
1. Installs and activates the OLD ZIP, asserts the plugin row shows `0.9.74`.
2. Seeds: a published post with fixed title/content; the marker option `ipz_e2e_upgrade_marker`; a marker merged non-destructively into the real `ipz_feature_flags` option (present on 0.9.74 — `options_written` included it); one row in `wp_ipz_workflow_states` (present on 0.9.74 — `workflow_row: true`). The seed endpoint 500s on a failed insert and reports `table_exists` separately, and the spec asserts `workflow_row === table_exists`, so a genuine insert failure cannot silently skip the workflow oracle (sol blocking finding, fixed and re-approved).
3. Upgrades via Plugins → Add New → Upload Plugin with the candidate ZIP: WordPress shows "This plugin is already installed." and the spec follows the **"Replace current with uploaded" link** (it is a link to `update.php`, not a button — proven by the run-1 failure snapshot).
4. Asserts the row shows `0.9.84` with an active Deactivate link.
5. Reads back and asserts: post title+content exactly preserved; both option markers preserved; workflow row count 1.
6. Asserts the admin SPA boots (`#ipz-admin-root`, `window.internationalPressZone`), no PHP error text on any visited page, zero console errors, zero page errors.

## 3. Proof run (remote, canonical)

Host: registry-selected buildbox via `/home/user/.claude/bin/e2e-remote` (IPZ gates are remote-only). Remote mirror: `/home/user/builds/lane-r8-pg34-upgrade-3dd715a9e6c4/`. ZIP transport: `tests/e2e/ipz-release-<version>.zip` copies inside the snapshot tree, never committed.

Invocation:

```
e2e-remote --server 'bash remote-stack.sh' --wait-port 8080 --wait-sec 600 \
  --env IPZ_STACK_NO_PLUGIN_MOUNT=1 \
  --env IPZ_OLD_ZIP_PATH=<mirror>/plugins/international-press-zone/tests/e2e/ipz-release-0.9.74.zip \
  --env IPZ_ZIP_PATH=<mirror>/plugins/international-press-zone/tests/e2e/ipz-release-0.9.84.zip \
  --env IPZ_OLD_VERSION=0.9.74 --env IPZ_EXPECTED_VERSION=0.9.84 \
  -- bash -c 'npm ci --no-audit --no-fund && npx playwright test upgrade-zip.spec.js --project=chromium'
```

Final run result (verbatim tail):

```
  ✓  1 [chromium] › upgrade-zip.spec.js:193:5 › PG-34 upgrade from deployed release ZIP › replaces the old release ZIP and preserves plugin, workflow, and customer state (30.0s)

  1 passed (1.1m)
e2e-remote: client exit=0
```

Iterations: run 1 failed only because the replace control was targeted as a button (it is a link); run 2 passed; sol review then hardened the workflow oracle (insert-failure vs table-absent ambiguity); run 3 passed with the strengthened oracle. Sol final verdict: approved, zero findings.

## 4. Verdict

- PG-34 upgrade proof: `[x] WORKS` — flip recorded in `GOLIVE.md` in this lane.
- Out of scope, unchanged: PG-35 (signed update delivery), PG-36 (rollback), PG-46 (backend catalog).
