Playwright E2E + acceptance video — the whole public journey on one host, and the old app-host paths redirecting
Type: test · Executor: coding_agent · Repo: motir-core · ONE PR. The story's end-to-end walk, and — because the deliverable is a surface a person watches — its acceptance receipt.
The flow, which is the story's verification recipe automated
- Load the public site's root — the landing renders, with its three doors.
- Click Explore in the header —
/explorerenders, same host, same chrome, with real project cards. - Open a topic page from the footer's crawl links; go back.
- Open Docs, then a legal document from the footer — each stays on the public host.
- Fetch
/robots.txtand/sitemap.xmlfrom the public host — one of each, allow + the surfaces this host serves. - Request each moved path on the application host — a permanent redirect to the public one, query preserved.
- Request a public project page on the application host — 200, not a redirect (the story boundary).
- Take a door to the application host and arrive at the sign-in surface with its parameter intact.
States, not just the happy path
- Empty —
/explorewith no public projects: the empty state, not a crash. - Loading — the square's ranked tabs and "load more", waited on by their authoritative signals rather than a timeout.
- Error —
explore/error.tsxrenders when the directory read fails. - Terminal / destructive — the redirect is permanent: assert the status code, not merely the final URL, because a 302 and a 308 look identical after the browser follows them.
⚠️ Host simulation, and the scaffold check that governs it
Both hosts must be reachable from one Playwright run. Read the lane's own configuration before writing a line in it: this repository's E2E lanes carry a base URL and a webServer, and a host branch resolved from a request header is drivable per test, while one resolved from a process-wide server-side environment read is NOT — it would have no per-test override, the assertion would pass on unfixed code, and the failure mode is a permanently green guard rather than a red one. Name the exact mechanism in the spec's own comment, and assert the page is on the host it claims before asserting anything about it, so nothing can pass vacuously.
The acceptance video
The story's deliverable is user-observable, so this card records and publishes the walk to the story as its acceptance receipt. It is PACED for a human — a reviewer watches it to accept the story — so the spec waits on real signals and does not race. There is no duration cap; the only machine check is a floor, and a clip too fast to watch fails the publish.
Acceptance criteria
- One spec covering steps 1–8, green in CI, waiting on authoritative signals throughout (no arbitrary timeouts).
- Each of the four state cases above is asserted.
- Step 6 asserts the redirect status code and the destination; step 7 asserts a 200 on
/p/*and that no redirect occurred. - The spec asserts the host of each page it is on before making claims about that page.
- The acceptance video is recorded, paced for a human, and published to the story; the publish is green.
- The spec adds no flake: it is run repeatedly in the lane before the card closes, and any environmental failure is triaged and logged rather than re-run blind.
Context refs
motir-core/tests/e2e/— the lane configuration, the fixtures, and the acceptance-video patternmotir-core/docs/decisions/acceptance-video.md— the receipt's contract and its floormotir-core/app/(public)/explore/error.tsx— the error state this drivesmotir-core/CLAUDE.md— the E2E discipline (authoritative waits)- The root-route, robots/sitemap and redirect cards this is
blocked_by— the behaviour it walks
⚠️ RE-FILED into MOTIR-3932 (2026-08-29) — the journey it walks is no longer in this repository
This card records and publishes the acceptance video for the whole public journey. That journey now happens on motir.co, rendered by motir-marketing — the landing, /explore, a topic page, /docs, a legal document, and the redirects off the application host. motir-core no longer serves any of it, so a Playwright spec in motir-core could only walk the half that is left.
It therefore belongs to MOTIR-3932, which renders the surface, and its cross-parent edges into MOTIR-3881 and the two archived cards are dropped. Its edge into MOTIR-3884 SURVIVES and is now an ordinary sibling edge — both cards are in the same story, and the walk asserts the redirects that card ships.
⚠️ Its host-simulation section needs re-reading before it is built. It was written for one application answering two hostnames with a request-header branch. The arrangement is now two applications on two hostnames, so "both hosts in one Playwright run" is a different problem — read the lane's own configuration and name the mechanism, exactly as the card already insists, rather than inheriting the old sentence.
And motir-core still owes a gate of its own — over the contract, not the journey. That is MOTIR-3885's, which stays behind.