# Portal verification and session clearing — v0.12.2

The bounded local portal journey is verified, and the reproduced stale private-content defect is repaired. This is a local checkpoint, not production approval or full-product completion. All 45 capabilities remain tracked; all 14 findings against the original SHS application remain OPEN.

## Reproduced defect and repair

On verified v0.12.1, the owner revoked the exact customer's access. New server requests were correctly denied, but the already-open home and accepted quote still displayed cached private content. The evidence folder retains the before-fix screenshot.

The client now revalidates its customer session after owner revoke/reissue/contact changes, when returning to the tab and periodically while visible. Successful checks compare session and business identity without replacing page data or response inputs. A private API/image/PDF 401, changed identity, validation failure or a 10-second validation timeout clears customer views and private image leases. Context epochs reject late responses from older sessions. Public login/setup failures and foreign-document 404 responses do not clear a valid session. Staff context remains separate. No backend contract, database schema or dependency changed.

Same-origin tabs receive an access-change notice and revalidate immediately. Other browsers rely on focus/visibility and the 30-second visible-page interval. Background throttling and other devices were not tested; instant cross-device erasure is not claimed. Already downloaded files cannot be recalled.

## Actual browser evidence

Fixture preparation used controlled local API helpers before opening the browser: two distinct customers with identical contact details, one job each, four quotes, one private draft invoice and one private material row. No customer passwords or invitations were seeded. Sandy entered and submitted both setup passwords through the UI; no password was supplied in chat or recorded in evidence.

The v0.12.1 journey verified owner invitation capture for the exact customer, human setup/sign-in, reload/reopen, one permitted job, hidden private drafts/costs/notes, deliberate sharing of QA-0001, exact saved wording and £150 total, customer acknowledgement/acceptance, retained owner/customer response history and an actual customer PDF download. The one-page PDF was independently text-checked and rendered: correct customer/amount/status and no private supplier/cost/note or other-customer sentinel appeared. Customer A's direct route to customer B's shared QA-0004 returned Document not found despite identical contact details.

QA-0002 was shared and declined in the customer UI. The owner created QA-0005 revision 2. An already-open QA-0002 response rejected a stale acceptance; reload showed Superseded and retained the customer's original decline. The owner then revoked access, exposing the cached-content defect.

For the v0.12.2 retest, the owner deliberately reissued setup and Sandy completed a fresh password/sign-in handoff. Owner refresh showed Enabled and the consumed capture was gone. The customer saw the same permitted saved records. The owner shared QA-0005 solely for the response-draft check. A typed name and unfinished fictional response remained intact after the owner changed only customer B's invented phone field, triggering a valid session recheck. No response to QA-0005 was submitted.

The owner revoked customer A again. Without any manual reload, the home returned to sign-in and both the accepted QA-0001 page and open QA-0005 response page removed their private content. A subsequent fresh request returned This portal access has ended. The owner session remained usable. This verifies the specific same-origin browser scenario and preservation of the unfinished draft while access was valid.

## Automated checks

- 79 client cases pass, including 12 new session-boundary tests: 401/public-auth/404 differences, image revocation, late responses, independent staff access, owner notifications, valid rechecks, identity changes, focus/visibility/periodic lifecycle, coalescing, timeout and cleanup.
- 41 focused API cases pass in 10.21 seconds: portal access, private PDFs and customers. Exact-ID and valid-shaped foreign-customer rejection coverage remains.
- 43 structural server-render checks and the production build pass. These are separate from browser evidence.
- The full 473-case backend result belongs to preserved v0.12 and was not repeated for this client-only repair. Existing TestClient/httpx deprecation and the 521.24 kB JavaScript chunk advisory remain.

Evidence files: `portal-session-client-tests.txt`, `portal-session-api-tests.xml`, `portal-session-api-tests.txt`, `portal-session-build.txt`, `portal-session-render-check.txt`, `portal-session-checks.json` and `portal-session-preservation-check.json`. Actual screenshots/PDFs remain in the sibling output folders `SHS-Portal-Verification-v0.12.1` and `SHS-Portal-Verification-v0.12.2`, outside the product archive. No bearer code or password is included.

## Runtime and data boundaries

The stable owner review at http://127.0.0.1:8788/ was moved to the hash-verified frozen v0.12.1 runtime before editing/building the maintained project. Its dataset and sessions were preserved byte for byte; no review tab was reloaded, signed out or discarded. Current runtime details are in the sibling `SHS-Owner-Review-Runtime.json`. Historical PID instructions in earlier reports are not current runtime instructions.

The separate test used http://localhost:8789/ and `work/portal-ui-verification-2026-10-28`. Different hostnames isolate host cookies; ports alone do not. The test server is now stopped and its fictional data is retained outside the package. Customer A is revoked, customer B was never invited, QA-0001 is accepted, QA-0002 is superseded with its decline retained, QA-0003 remains private, QA-0004 is the seeded other-customer shared quote, QA-0005 is shared without a response, and IA-0001 remains a private draft. No invoice was issued and no payment was recorded.

Normal `.local-data`, the source ZIP, both 275-file source references and earlier archives remain unchanged. No live SHS, real customer data, provider, external message, payment, domain or deployment was touched.

## Remaining bounded checks

Password recovery request/capture/completion, active-customer contact-change revocation, expiry, broader staff/customer session switching, private photos and invoice/stage PDF browser paths remain pending. Feedback, wider website/gallery/field/recurrence flows, keyboard/screen-reader/touch behavior, installed PWA/offline, browser print and second-machine recovery remain in the full queue. At the measured 689 × 751 CSS-pixel viewport (DPR 2), later owner navigation items are horizontally clipped; no navigation redesign or device certification was performed. Screenshot pixel dimensions are recorded separately.
