Skip to content

Add signup flow regression test covering nine QA findings - #70

Merged
Avi-ADAM merged 7 commits into
mainfrom
claude/1lev1-user-testing-yramwu
Aug 15, 2026
Merged

Add signup flow regression test covering nine QA findings#70
Avi-ADAM merged 7 commits into
mainfrom
claude/1lev1-user-testing-yramwu

Conversation

@Avi-ADAM

Copy link
Copy Markdown
Owner

Summary

Adds scripts/smoke/flows/signup.mjs, a comprehensive regression test that walks the complete new-member onboarding path from /hascama through email confirmation, login, and profile building to the lev screen. This flow covers all nine defects found in docs/QA_NEW_USER_WALKTHROUGH_2026-08.md, three of them severe.

Key changes

  • New smoke test flow (scripts/smoke/flows/signup.mjs):

    • Two-phase design: phase 1 registers and stops at email confirmation (saves account state); phase 2 opens the confirmation link and completes onboarding
    • 15 assertion steps, each guarding a specific QA finding (F1–F9)
    • Covers consent checkbox keyboard accessibility (F8), JWT cookie state (F4), socket authentication (F4), raw GraphQL rejections (F1), empty review screen handling (F5), suggestion chip labeling (F7), chip styling (F6), matching engine execution (F3), and hub CTA routing (F9)
    • Writes to live database (requires --yes flag); account state persisted to $TMPDIR/1lev1-smoke-signup.json between phases
    • Uses Hebrew test data and validates both keyboard and mouse interaction paths
  • Updated QA documentation (docs/QA_NEW_USER_WALKTHROUGH_2026-08.md):

    • Revised finding Centralize graphql queries with sendtosser #3 from "onboarding doesn't trigger matching" to "lev screen empty after full onboarding" with corrected root-cause analysis
    • Clarified that Centralize graphql queries with sendtosser #3 is a symptom of V4 #2 (fuzzy skill matching), not an independent bug
    • Added validation results from production testing with a second test account
    • Documented which findings were re-examined and corrected during verification
    • Added regression test coverage table mapping each finding to its assertion step
  • Updated smoke test README (scripts/smoke/README.md):

    • Noted that B3 finding is now fixed and deployed
    • Added signup flow documentation under new "Write flows" section
    • Clarified that write flows require --yes and cannot be run accidentally
    • Explained two-phase design and email confirmation handling

Implementation details

  • Keyboard navigation test for consent checkbox uses bounded Tab-walking (30 stops max) to detect display:none regression
  • Suggestion chip validation extracts both label text and computed text-decoration-line style to catch styling regressions
  • Matching engine assertion checks that refresh completes cleanly without asserting result count (empty suggestions are valid when no missions match)
  • Raw GraphQL rejection detection filters /api/send 403 responses to catch F1 regression
  • Account creation uses +tag addressing on test mailbox for mail delivery without external dependencies

https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8

claude added 7 commits August 12, 2026 07:35
Manual production walkthrough of the full signup path with a real
browser and a purpose-made account (user id 256): /hascama → /signup →
email confirmation → /login → /onboard provider flow → /me, plus a
sweep of the 12 main pages.

Documents 9 findings, three of them severe:

- initialForum() in src/lib/stores/pendMisMes.js sends raw GraphQL,
  which /api/send rejects with 403 outside dev — the whole chat/forum
  subsystem never loads for a logged-in user in production.
- The embedding matcher's SUGGESTION threshold of 0.72 maps extracted
  skills onto unrelated existing entries (JavaScript → React,
  בדיקות אוטומטיות → תיקון מחשבים), and the review chip shows the
  user's own word while saving the other label, so the mismatch is
  invisible until /me.
- /api/onboard/save never calls matchUserToOpenEntities the way
  updateUserRelation does, so a freshly onboarded profile produces no
  match suggestions and /lev still tells the user to go add skills.

Also covers the "undefined" jwt cookie, sessionStorage-only review
state, suggestion chips defaulting to a struck-through off state, the
inaccessible consent checkbox on /hascama, and the "לשיחה עם Lev" CTA
landing on a page with no chat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8
Chat/forum fetches never loaded in production. initialForum() built raw
GraphQL strings, and /api/send rejects raw queries outside dev, so every
page of a logged-in user fired a 403 and the username, profile picture,
project list and all forums/messages were never fetched. Adds two
parametric qids (292initialForumAll, 293initialForumByIds) with matching
qidsAccess entries and moves the store to sendToSer. The first qid takes
$idL, which the endpoint overwrites from the id cookie, so a client can
no longer ask for another user's forums the way the client-supplied myId
allowed. The call is silent so a background chat fetch cannot redirect a
working user to /login.

Onboarding never triggered match suggestions. updateUserRelation calls
matchUserToOpenEntities, but onboarding writes through
/api/onboard/save, which did not — so the one path every new user takes
was the only one that left the lev page empty, telling them to go add
the skills they had just added. The save now triggers the refresh,
awaited so suggestions exist before the user can reach /lev, and wrapped
so a matching failure cannot fail a save that already succeeded.

Suggested vocabulary was saved under a different label than the chip
displayed. A suggestion renders the user's own words but persists
existingLabel, so "בסיסי נתונים" was stored as "ממשל נתונים" with no way
to notice before reaching /me. The chip now shows the entry it will be
saved under, kept legible on an off chip, and buildPayload dedupes by
existingId so one entry is not sent three times.

The similarity thresholds are left alone: every wrong mapping came from
the suggestion bucket while everything matched at 0.88 was correct, so
MATCH is well calibrated and moving SUGGESTION without measuring against
a corpus would be a guess. The evidence is recorded next to the constant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8
Signup wrote the literal string "undefined" into the jwt cookie whenever
Strapi returned no token, which happens on every registration while email
confirmation is on. The cookie is now written only when a token exists,
and the layout connects the socket on data.loggedIn rather than on the
presence of an id — between signup and confirmation there is an id and no
JWT, which is exactly what made the check-email screen report "Invalid or
expired JWT" before the user had done anything wrong.

The review screen threw its draft away without a word. The analysis lived
in sessionStorage alone, and a missing key redirected back a step, so a
new tab or a browser restart silently cost the user an AI run plus the
writing that fed it. A small cvDraft module now mirrors the draft to
localStorage with a 24h freshness window, both writers go through it, and
when there genuinely is no draft the screen stays put and explains, with
a way back.

Unselected suggestions were rendered struck through at 0.45 opacity,
which reads as deleted rather than as not-yet-chosen — and since
suggestions start off, most of what the AI found looked discarded on
arrival. They now carry a dashed border instead, and the missions hint,
which told the user that clicking removes a mission when clicking in fact
selects it, is corrected in all five locales. The off-by-default
behaviour itself is deliberately kept: turning fuzzy matches on by
default would reinstate the silent-wrong-data problem.

The consent checkbox on /hascama was hidden with display:none, taking it
out of the tab order entirely — a keyboard or screen-reader user could
never tick the terms, and the submit button stays locked until they do.
It is now visually hidden but focusable, with a focus ring on the custom
box that stands in for it.

The hub's assistant card pointed at /lev, the heart-cards screen, which
has no chat input; Lev lives at /chat, and the card now says so.

Verified against a local production build signed in to the real backend:
the checkbox takes focus on the fourth tab stop and toggles with space,
the draft-less review screen explains itself, chips render the entry they
will be saved under without a strike-through, and a logged-out page makes
no socket attempts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8
Adds scripts/smoke/flows/signup.mjs, the regression net for the nine
findings in docs/QA_NEW_USER_WALKTHROUGH_2026-08.md. It walks /hascama →
/signup → email confirmation → /login → onboarding → a profile that
produces match suggestions, and each step names the finding it guards:
the consent checkbox taking keyboard focus, the jwt cookie not being
written as the string "undefined", no authenticated socket before there
is a session, no raw-GraphQL 403 on a logged-in page, suggestion chips
naming the entry they will be saved under without reading as deleted, the
empty review screen explaining itself, and the lev screen actually having
suggestions once onboarding is done.

It runs in two phases, since confirming the address needs a mailbox the
harness cannot read: --yes registers and stops at "check your mail",
saving the account outside the repo, and --confirm '<link>' carries that
same account through to the end. The address is a +tag on the test
account's own mailbox so the mail arrives somewhere readable.

Verified against production along the way: phase one's consent-screen
steps pass on the live site, and a read-only sweep of /lev, /me, /hub and
/onboard now reports 4/4 pages clean — those four pages each fired a
raw-GraphQL 403 before the fix shipped. The README's example output and
the QA report are updated to say so, rather than still describing that
bug as live.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8
Throwaway runs can stay anonymous, but a standing test account wants a
name you can pick out of a members list. SMOKE_SIGNUP_NAME overrides the
default, to pair with SMOKE_SIGNUP_EMAIL: multi-member flows — consensus,
negotiation, a two-person split — need a second account that persists
rather than a fresh one per run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8
…hing

Running the flow end to end against production with a second test account
turned up a wrong diagnosis in the QA report, which this step had faithfully
encoded.

Section 3 blamed the empty lev screen on /api/onboard/save not triggering
the matching engine. It does not hold: levDataLoader.ts:577 already runs a
lazy refreshMySuggestions backfill whenever a member has capabilities and
no stored suggestions, so the engine ran on first load either way. Called
explicitly for the new account it answers success with createdMissions 0 —
it runs fine and genuinely matches nothing, because scoring intersects
skill and role IDs and the profile this member ended up with holds
consulting and team-lead rather than the JavaScript, TypeScript, Svelte and
Node they actually wrote. Section 3 is a symptom of section 2, and the real
repair is calibrating the threshold, not adding another trigger.

So the step now asserts what is actually guaranteed — the engine runs and
returns cleanly — and prints the suggestion count instead of asserting it.
Requiring a non-empty lev screen would fail the flow on a perfectly healthy
site whenever nothing in the catalogue happens to match.

The trigger added to /api/onboard/save stays: computing suggestions at save
time rather than on first paint is still right, just not the fix for the
empty screen, and the report now says so.

The rest of the run: 14 of 15 steps passed, covering findings 1, 2, 4, 5, 6,
7, 8 and 9 against the live site.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ksBqPqj6d8y12Zd2xMTB8
@vercel

vercel Bot commented Aug 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
1-0 Ready Ready Preview Aug 15, 2026 5:54pm

@Avi-ADAM
Avi-ADAM merged commit 59d00bc into main Aug 15, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants