Signed-in web survey (step 1) โ
- Status: survey complete. No web UI code was changed by this run.
- Ran: 2026-08-27, headless chromium at 1440x1000, signed in as the main test account.
- Target:
http://localhost:5173(the operator's running web dev server, untouched). Not deployed dev. - Why it exists: the 2026-08-24 dashboards survey reached only the PUBLIC web routes and said so (its W3). Everything a signed-in user sees had never been measured.
- Evidence:
screens/(one full-page capture per route),harness/(the two Playwright drivers and their JSON output). - Method:
getBoundingClientRectandgetComputedStyleon the live page, per route. Nothing here is read off a stylesheet.
What was actually driven? โ
| Route | Rendered | Note |
|---|---|---|
#/ | yes | Dashboard home |
#/light | yes | Same shell as #/, with a "Tap a venue" instruction bar |
#/active | no | Blank page, see W-A |
#/waves | no | Silently redirects to #/, see W-B |
#/frens | yes | Empty state (0 frens) |
#/activity | yes | Empty state |
#/schedule | yes | Venue picker step 1 |
#/profile | yes | Profile tab of the Settings shell |
#/profile/settings | yes | |
#/profile/privacy | yes | |
#/profile/safety | yes | |
#/support | yes | |
#/feedback | yes | Modal, no bottom nav |
#/venue/<id> | yes | The seeded alpha venue, with a sponsored offer |
- 14 routes attempted, 12 rendered. The two that did not are findings in their own right.
- Not driven:
#/login,#/signup,#/migrate/phone,#/devtools,#/dev/location-recovery,#/frens/<id>chat,#/schedule/confirmed, and the three legal pages. The first two are public and already surveyed; the rest need state this run did not have (a lit lantern, an accepted wave, a scheduled light).
What did it find? โ
Nine items, W-A through W-I, numbered to continue the dashboards survey's W1-W3 rather than restart it. Options, not verdicts.
W-A. #/active renders a completely blank page. โ
- Measured: hash stays
#/active,document.body.innerTextis the empty string, zero visible headings, zero icons, zero buttons. Not even the bottom nav paints. Capture:screens/active.png, which is 6.8KB of pure background. - Condition: signed in, geolocated inside the alpha venue geofence, with no lantern currently lit.
- Why it matters here:
#/activeis not an orphan.App.jsxnavigates to it from two places (lines 1169 and 1204) and lists it in the routes that keep the dashboard shell mounted (lines 1048 and 1150). A user who lets a lantern expire while sitting on that route gets a black screen with no way out. - The grammar it breaks: every other empty condition in the app renders prose (see W-H). This one renders nothing.
| Option | What it does | Risk |
|---|---|---|
A. Redirect to #/ when there is no active lantern | Matches what #/waves already does | Silent redirects are their own defect, see W-B |
| B. Render the app's empty-state block ("No lantern lit", plus the light CTA) | Consistent with #/activity and #/frens | One more empty state to write |
| C. Keep the shell and nav mounted, empty content area | Cheapest, and the nav alone fixes the trap | Still an unexplained blank region |
W-B. #/waves silently redirects to #/, and nothing says so. โ
- Measured: navigating to
#/wavesends withlocation.hash === '#/'and the dashboard home rendered. Byte-identical probe output to#/. App.jsx:1208navigates to#/wavesfrom within the app, so this is a live in-app destination that does not exist.- Related to W2 in the dashboards survey (three profile routes render one signed-out screen). Same class: a route that resolves somewhere the user did not ask for, with no message.
W-C. Three signed-in screens have no h1, and the profile family gives four different pages the same one. โ
- No
h1at all:#/schedule(starts ath2:Schedule a Light),#/feedback(h2:Submit Request),#/venue/<id>(h2:Lantern Alpha Venue). - One
h1for four pages:#/profile,#/profile/settings,#/profile/privacyand#/profile/safetyall renderh1:Settings. The tab that is actually open never appears at the top of the outline. - A heading carrying data:
#/venue/<id>rendersh3:Lit Lanterns\n0, so the count is inside the heading text. - A heading carrying an emoji:
#/profile/privacyrendersh3:plus a construction emoji plusDev: Location Spoofing. - Story a11y already gates heading order at error level for
apps/webcomponents (AGENTS.md, Testing). These are screen-level compositions that no story renders, so nothing catches them.
W-D. Emoji and text glyphs in chrome, on four signed-in screens. โ
This extends the dashboards survey's W1 (which found three sites, all on public routes) into the signed-in app.
| Screen | Glyph | Where |
|---|---|---|
#/frens | handshake emoji | The "No mutual frens yet" empty state, rendered at 60px/400 |
#/profile | lock emoji | Inside the "This profile is anonymous" prose line |
#/profile/privacy | construction emoji | Inside an <h3> |
#/profile/privacy | 5 checkmark characters | Used as the list bullets of "Privacy Guarantees" |
#/feedback | sparkles, bug, lightning, question mark | The four request-type category buttons |
- The four on
#/feedbackare the clearest chrome case: they are category affordances in a form, exactly the role Lucide fills everywhere else. - The five checkmarks on
#/profile/privacyare the judgement case step 3 already names: a checkmark leading a list item is arguably punctuation. They are, however, list bullets rather than prose, which puts them nearer chrome than the in-sentence case. - The lock on
#/profileis genuinely in prose and is the one this survey would leave.
W-E. Four interactive targets on every signed-in screen are under 24px. โ
- Bottom nav, every screen:
Infomeasures 22x41 andMemeasures 22x41.Frensis 27x41 andPlacesis 32x41, so the row is not uniform either. The measured element is the label plus icon group; the tap area may be larger, and that is worth confirming before acting. - Tour tooltip:
Skipmeasures 25x16. #/profile/privacy:Delete my accountmeasures 123x20.#/feedback: a checkbox input measures 16x16.- WCAG 2.5.8 asks for 24x24. The
e2e:mobile-pwaharness already audits touch targets under phone emulation; this run measured them at desktop width, where the same numbers hold.
W-F. The type ramp is 10 to 14 distinct combinations per screen. โ
Counted as unique font-size / font-weight / line-height / letter-spacing tuples on visible leaf text nodes.
| Screen | Distinct combinations |
|---|---|
#/profile | 14 |
#/frens | 13 |
#/venue/<id> | 12 |
#/, #/profile/privacy, #/support | 10 to 11 |
#/activity | 5 |
- Outliers worth naming:
18px/400/18pxon#/profile(line-height equal to font-size, so lines touch),60px/400used for exactly one emoji on#/frens, and13px/400/21.125pxplus15px/500/22.5pxon#/supportwhich appear on no other screen. #/activityis the counter-example at 5 combinations, which suggests the sprawl is accumulation rather than necessity.
W-G. Four corner radii plus one that is not a value. โ
- Measured across elements wider than 80px:
16px(45 elements),20px(37),12px(20),4px(5), plus3.35544e+07px(15), which is the computed form of a full-round pill. - The admin portal draws radii from
--radius*tokens. The web app uses raw Tailwindrounded-*classes, so the two surfaces have no shared radius vocabulary at all. This is a "one product" gap the tokens do not currently close.
W-H. The signed-in web app has NO empty-value glyph, and that is a deliberate-looking grammar the portal does not share. โ
- Measured across all 12 rendered routes: zero em dash, zero en dash, zero hyphen placeholders. The empty-value problem step 2 fixes is portal-only.
- What the app does instead is prose: "No activity yet", "No mutual frens yet", "No venues found", "Light a lantern or send a wave to get started".
- This is a direct input to step 2's decision. The web app already answers "what does nothing look like" with words. The portal answers it with punctuation, in three vocabularies. The two surfaces will not read as one product until someone says which is right where.
- The honest reading: prose works in a card or an empty list; it does not fit a table cell or a stat tile, which is where every portal instance lives. So the two answers are compatible, and the rule is about SURFACE rather than about taste. That framing is what step 2 adopted.
W-I. The dev location-spoofing panel is purple, and purple is not in the chrome system. โ
ProfileSettings.jsx:829-994usesbg-purple-900/20,border-purple-900/40,text-purple-400,focus:border-purple-400andbg-purple-600for the panel, its heading, its two inputs and its primary button.- The
designskill is explicit that there is no purple or indigo in the chrome system, and that the purple inpackages/ui/colors.jsis user-selectable DOMAIN data (a lantern match colour). This panel is chrome. - It renders only in dev, which is why it survived. It is still a live signed-in surface on the dev build the operator uses.
What could not be seen? โ
- Anything needing a lit lantern:
#/activewith real content, the venue chat surface,#/frens/<id>. - Anything needing a second account: waves received, an accepted connection, a chat thread.
- Phone form factor: this run measured desktop 1440x1000.
e2e:mobile-loopande2e:mobile-pwaalready cover phone emulation and should be read alongside, not re-derived here. - The onboarding tour overlaps content: on
#/profile/privacythe "STEP 1 OF 3" tooltip sits on top of the account-recovery card and obscures its title. Recorded as an observation rather than an item, because it is a tour-sequencing question, not a design grammar.
What does this change about the pass? โ
Step 2's scope is portal-only, and that is now measured rather than assumed. โ
- W-H is the finding. No web file needed an empty-value change, so step 2 landed entirely in
apps/admin.
Step 3 gains five sites and loses none. โ
- W-D adds
#/feedback(4 glyphs),#/profile/privacy(1 emoji in anh3, 5 checkmark bullets),#/profile(1 in prose) to the three the dashboards survey already had. The checkmark-in-prose judgement step 3 anticipated now has a concrete borderline case: checkmarks as LIST BULLETS.
Three items are new and belong to no step yet. โ
- W-A and W-B are navigation defects, which is step 6's subject. They fit its rule (a route that behaves differently from how it looks) and are the natural companions to W2 and X7.
- W-C (heading outlines) has no step. It is cross-cutting, it is an a11y surface the story gate cannot reach, and it is cheap. Raised, not sequenced.
- W-E, W-F, W-G and W-I are raised in
backlog.mdwith what would promote each.