# Gallery workflow verification — v0.20.1

30 October 2026. **The bounded owner-to-gallery journey is verified for continued local trials with invented records. Live SHS use, full parity and production release are not approved.** All 45 capabilities remain tracked and all 14 findings against the supplied SHS code remain OPEN.

## What changed

The browser exposed a privacy defect in the independent prototype: signing out cleared private preview images but left unpublished gallery text visible in the already-open tab. v0.20.1 binds that whole preview to the exact owner session. Sign-out/account changes remove the text, images and open viewer; focus, visibility and periodic session checks also clear the view if identity or access changes or validation fails. Late responses cannot restore the cleared content. The same existing watcher continues to protect website previews.

Only the frontend implementation, its regression tests, version label, build and documentation changed from v0.20. There is no schema, backend, dependency, lockfile or route-policy change. Format-12 backup metadata remains `0.20.0`, compatible with the v0.20 checkpoint and its supported older archives. This repair does not change the original SHS app.

## Evidence boundaries

The separate server used `127.0.0.1:8791`, an extracted copy of the exact v0.20 ZIP, and a new fictional dataset. Before browser work, a local TestClient submitted two invented enquiries: one with three synthetic images (one genuinely encoded HEIC, two PNGs), and a separate customer/job with none. No review, customer share or gallery was seeded. All subsequent owner review/share/gallery state changes listed below were performed through actual Chrome controls. The repaired frontend was then rebuilt and copied into that same isolated runtime for the repair retest.

**Fixture creation is API setup, not browser upload evidence.** No new customer/staff passwords or accounts were created to bypass browser credential rules. Staff assignment, exact-customer access and portal revocation have selected API regression proof; their browser screens were not verified in this stage. Fresh public-demo owner sign-ins covered Oak & Vale and Harbour Homeworks.

## Verified owner workflow

1. Open the exact job’s **Job photos**. Save a private caption, description and category; failed native validation retains the edits. Mark the photo reviewed. Customer sharing requires separately entered customer text and an image description. A rejected missing description retains the caption; successful sharing is recorded for that exact customer.
2. In **Gallery**, select the exact job and create a private draft. Public text starts separately; it does not copy the customer name, address, enquiry message or private photo captions. Choose two photos and write their public captions/descriptions, before/after pair and service association.
3. An empty project, an unreviewed selected photo or a missing public image description blocks publication. Permission acknowledgement must be explicitly selected. The saved preview stays private and is distinct from the public page.
4. Save and publish deliberately. The public index, project detail and selected service show the two synthetic images. Literal `<em>` text remains text. The viewer’s Next/ArrowRight, Escape and focus return passed on desktop. Public HTML/JSON and image responses exclude the private contact/intake/ID sentinels; normalized PNGs contain no source metadata.
5. Saving a changed draft leaves the published caption unchanged. A stale second editor receives a conflict and retains its unsaved text. Navigation opens the leave warning; Keep editing preserves the draft, and explicit discard closes the test draft.
6. Sign out while the repaired private preview’s image viewer is open. All draft content and the viewer disappear immediately without reloading that preview. Harbour’s gallery stays empty, and a fresh attempt to open Oak’s private preview is denied.
7. Stop customer sharing. The independently approved public gallery stays published. Withdraw the gallery: fresh public page, JSON and image requests return 404, its index is empty and its associated service no longer lists it. Previously viewed/downloaded copies cannot be recalled.
8. Archive and restore the project privately. Archive its source photo only after withdrawal; restoration leaves that photo private and unreviewed. Republish is rejected until it is reviewed. Editing an already-reviewed second photo clears its review. Review both again and explicitly re-share the first with its customer.
9. Inspect the original publication in history and restore it to the private draft. Publication still requires fresh permission. Publish once with index listing off: the detail URL remains public while index/service listings omit it. Re-enable listing and publish deliberately.
10. The final test state has a reviewed two-image publication, separate saved draft caption, one customer-shared image and one unused archived photo. That exact saved dataset was used for the recovery check.

The numbered raw observations and selected screenshots are in [gallery evidence](gallery-evidence/). [Fixture setup](gallery-evidence/fixture-setup.json), [request audit](gallery-evidence/request-audit.jsonl), and the three HTTP checks ([first publication](gallery-evidence/first-publication-api.json), [withdrawn](gallery-evidence/withdrawn-api.json), [final publication](gallery-evidence/final-publication-api.json)) distinguish setup, UI observations and API assertions. Each HTTP check recorded 17 authorization/public requests, plus empty-business checks. The withdrawn detail currently presents the server’s plain JSON 404 in Chrome; branded withdrawn-project wording remains a usability improvement.

## Recovery and automated checks

The stage-owned server was stopped before backup. The source dataset was moved to a retained folder, making its former path unavailable without deleting it. A verified format-12 archive restored into a fresh folder. All three normalized photo files, original enquiry facts, source filenames/hashes/sizes/order, exact job/customer bindings and existing photo/gallery history rows survived. The separate private draft survived, and the former public snapshot remains in history. Recovery suspended visitor-photo reviews and customer shares, withdrew the project, preserved the archived photo, rejected both old owner sessions and denied foreign-business access. Republish without renewed review returned 409; without permission it returned 422. A second-generation backup verified.

This is terminal/TestClient recovery proof on the same Mac, not a browser recovery, off-device recovery or production disaster-recovery certification. Recovery created its standard replacement owner login file privately; no credentials, runtime database, captures or session cookies are included in the evidence or code ZIP. The first comparison omitted the expected new storage identity and appended recovery audit row; those changes were inspected and the corrected comparison passed against another fresh restore. The first restored folder is retained. See [recovery record](gallery-evidence/gallery-recovery.json).

**167 client tests, 88 structural render checks, 41 selected backend/photo/recovery regressions and the build passed.** Eleven new client regressions cover the preview defect, identity changes, unavailable validation and late responses. The prior v0.20 full 694-case backend pass remains historical; the backend is unchanged and that full suite was not rerun for this frontend-only repair. The existing large-bundle advisory remains. Structural rendering is not browser or accessibility proof.

## Source comparison and remaining scope

The original ZIP’s useful journeys are mapped in [the source record](gallery-evidence/source-map.json). Original `portfolio.py` gathers job/customer media and promotes featured photos; `site_editor.py` implements published gallery index/detail/related items, admin CRUD, job-photo promotion, generated copy and bulk moves. Its one-tap promotion uses the enquiry message for generated copy and publishes immediately when images exist. The independent product retains the job-to-public-project purpose with exact-job sources, separately authored text, owner review and a distinct publication action. Source code was inspected only; no original runtime or tests were executed.

The following remain open, rather than agreed feature exclusions:

- Actual new-format file-picker selection, file retention/Clear/discard, removal/reselection, submit/reopen and real-phone HEIF/HDR variants. The earlier upload tool remained blocked after the setting was enabled; this stage did not repeat file-picker or settings probes.
- Staff and customer portal browser branches; expiry/remote revocation browser variants beyond the repaired sign-out/account test; assisted onboarding and broader device/assistive-technology checks.
- GIF/TIFF/BMP source-format parity, inputs over 12 megapixels, sequences/multiple main images, AVIF/other codecs. Public enquiries accept five PNG/JPEG/WebP/HEIF still images up to 10 MiB each / 50 MiB total; authenticated job-photo uploads remain PNG/JPEG/WebP at 2 MiB. Both use the documented 12 MP bound.
- Multi-project category/related-project browser cases, website-library projects, image reorder variants, complete source action parity, offline/PWA use, source/assets/configuration completeness, rights/native dependency distribution, production storage/load/identity/domains/subscriptions and integrations.

The old v0.8 guide described source-only safety differences; those descriptions do not grant approval to omit useful source functions. Full original parity is still a tracked goal, with explicit decisions needed where safer behavior differs.

## Preserved review and cleanup

Sandy’s v0.19 review at `http://localhost:8789/workspace` was not operated, reloaded, signed out, restarted or upgraded. Its PID 58260 was freshly checked running with the expected review directory and data path. No byte-identical claim is made for editable review data. No normal dataset or source reference copy was changed; original/v0.19/v0.19.1/v0.20 ZIP hashes matched.

The gallery server (PID 68258) stopped and all four tabs created for this stage closed. The older normal Chrome QA tab was absent from the fresh inventory; older Incognito cleanup remains unverified. No viewport override, unlock/dialog/password/settings request or pending handoff remains. The preserved review tabs were not controlled.

Some maintained files were cloud-only and blocked reading/testing. Exact v0.20 baseline files were restored at those maintained paths, with their placeholders retained and hashes recorded. The historical Git pack was not rewritten. [Baseline record](gallery-evidence/repair-source-baseline.json) distinguishes the waits, completed test repeats and recoveries. No test process was killed during the earlier cloud wait; it had already exited when termination was considered.
