Playwright E2E + acceptance video (motir-core) — configured and unconfigured legal links, and the cloud re-consent hold over the manifest
Opened by Zhu Yue ·
Type: test · Executor: coding_agent · Repo: motir-core · ONE PR. The story's end-to-end walk on the application host, and — because the deliverable is a surface a person watches — its acceptance receipt.
⚠️ RE-SCOPED 2026-09-01 — step 3's 404 left with the deletion
The deletion moved out of this story (plan-rules/kind-container.md's merge-count check — see MOTIR-3909's own amendment). /legal still answers on the application host when this story merges, so step 3 is now the post-deletion E2E's, in the deletion story, and this card's blocked_by edge to the deletion is gone with it.
Everything else is unchanged, and the remaining walk is complete on its own terms: the unconfigured sign-up sentence and rail, the configured links, and the cloud re-consent hold over the manifest. Those are what this story ships.
⚠️ Do not weaken step 3 into an assertion this story CAN make. "/legal renders but nothing links to it" is a different claim from "/legal is gone", and a spec that quietly substitutes the first would leave the second unasserted by anybody.
The flow, which is the story's verification recipe automated
Unconfigured (the state a self-hoster gets, and the state most of this walk is about):
- Open sign-up — there is NO legal paragraph at all: assert the paragraph's ABSENCE, not merely that it carries no anchor, and assert the card's foot renders correctly without it (the notice sat under a
border-twithpt-4). ⚠️ AMENDED 2026-09-01 (MOTIR-4004,docs/decisions/public-surface-hosts.mdAMENDMENT 2 §D): the notice is ABSENT, not re-flowed — a sentence entirely about two documents becomes FALSE rather than merely weaker when they do not exist. - Sign in — the rail's bottom section renders without a Legal row.
RequestMOVED to the post-deletion E2E (2026-09-01). The route is still in the tree when this story merges./legaland/legal/terms— 404…
Configured (the hosted arrangement):
- Sign-up shows both links, each
hrefequal to the configured absolute URL and each a plain anchor rather than a client-navigating link — assert the element and the attribute, because a cross-originnext/linklooks identical until it is used. - The rail's Legal row is present and points at the configured index.
- A signed-in reader whose accepted version is materially behind is held at
/re-consent; each outstanding row links to that document's configured URL; Agree and continue returns them to where they were going, and a second page load is not held.
⚠️ THE LANE — read its configuration before writing a line in it
The manifest and MOTIR_CLOUD are process-wide, server-side reads. A branch resolved that way has no per-test override and no client seam a request stub can reach, so a spec written in a lane that does not set them passes on unfixed code and stays green for ever — the failure mode is a permanent pass, not a red test.
Rung-2 evidence that a cloud lane already exists: tests/e2e/cloud-legal-reconsent.spec.ts is shipped and drives the re-consent hold. Start there. Read that lane's own config for what it sets, and:
- name the exact mechanism each arm relies on, in the spec's own comment;
- assert the arm is MOUNTED before asserting anything about it — that sign-up really is in the unconfigured state, that the build really is cloud — so nothing can pass vacuously;
- if one lane cannot host both arms, say so and put each arm in the lane that can, rather than weakening an assertion to fit.
States, not just the happy path
- Empty — the unconfigured arm above IS this story's empty state, and it is the common one.
- Loading — waited on by authoritative signals, never a timeout.
- Error — a configured entry whose URL is unreachable: the page must still render, because the link's target is another host's problem and not a reason for sign-up to fail.
- Terminal — Agree and continue is the terminal act; assert the acceptance is recorded and the next load is not held.
The acceptance video
The deliverable has a user-observable surface, so this card records and publishes the walk to MOTIR-3909 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.
⚠️ What this card does NOT walk
motir.co/legalin a browser. That is MOTIR-3886's — the public site's whole-journey spec, whose step 4 already reads "Open Docs, then a legal document from the footer — each stays on the public host" under an acceptance criterion covering steps 1–8. It runs after MOTIR-3884, which runs after the render card, so those pages exist by the time it opens them. Standing up a second cross-origin harness here would duplicate it.- The 301 itself — MOTIR-3884's, and MOTIR-3886 asserts it.
- The deployed manifest — the provisioning card reads that back from the platform; an E2E against a local build cannot.
Acceptance criteria
- One spec covering steps 1, 2 and 4–6 (step 3 moved out), green in CI, waiting on authoritative signals throughout — no arbitrary timeouts.
Step 3 asserts the 404 STATUS CODE forMOVED to the post-deletion E2E (2026-09-01)./legaland/legal/terms…- Step 4 asserts the element type AND the
href— a plain anchor, and a URL equal to the configured value rather than a path. - Step 6 drives the hold, the row's configured link, the agree act, the recorded acceptance and the un-held second load.
- Each of the four state cases above is asserted.
- The spec asserts each arm is MOUNTED before asserting anything about it, and names in a comment the exact mechanism that puts the lane in that arm.
- The acceptance video is recorded, paced for a human, and published to MOTIR-3909; 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, never re-run blind.
- The PR body records that the
motir.cohalf of the journey is MOTIR-3886's, quoting its step 4, so the deferral is attributable.
Context refs
motir-core/tests/e2e/cloud-legal-reconsent.spec.ts— the shipped re-consent walk and the cloud lane it runs in; the starting pointmotir-core/tests/e2e/_helpers/— the fixtures and the acceptance-video patternmotir-core/docs/decisions/acceptance-video.md— the receipt's contract and its floormotir-core/CLAUDE.md— the E2E discipline (authoritative waits)motir-core/app/(auth)/sign-up/_components/SignUpCard.tsx·app/(authed)/_components/SidebarNav.tsx·app/(auth)/re-consent/— the surfaces walked- the link-surfaces card — the feature-finisher this verifies;
blocked_by - the post-deletion E2E — took step 3 on 2026-09-01, in the deletion story; the deletion
blocked_byedge went with it - MOTIR-3886 — the public-site walk that covers
motir.co/legal
Advisory dispositions
likely-missing-edge→ MOTIR-3886: NOT REAL, and the edge would be backwards. That card is named as the owner of themotir.cohalf of the journey this card deliberately does not walk — a hand-off OUT. It isblocked_byMOTIR-3884, which this plan makesblocked_bythe render card, so an edge inward would close a cycle.- The remaining
referenceadvisories name cards this one's Boundary excludes. A boundary exists to say a deliverable is somebody else's, and naming the owner is what makes the exclusion checkable — so the reference is deliberate and no edge is owed.
Discussion
No comments yet.
Adding to this discussion signs you in on app.motir.co and brings you back to this request.