V1 Web PWA · Surface walkthrough

Veritas · today's lead

A per-surface walkthrough of the V1 Web PWA customer surface: layout, states, interactions, data, and cross-references.

walked
8sections8 minread

On this page

Context. surface customer · domain veritas · route /veritas · auth signed-in · source apps/oshun/web/src/app/veritas/page.tsx

Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; live screen-reader, touch, offline, and telemetry-delivery checks pending a manual AT pass. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; content re-verified 2026-06-03 against current source. 2026-06-27 Codex Veritas hub addendum — signed-in /veritas grounded-lead render against the real BFF briefing, private cache headers, canonical metadata, Lilith nav/subnav links, article/evidence rail mapping, no fabricated source rows, save/read/share/flag action contracts, standalone PWA relaunch, and mobile overflow safety are covered by the E2E references below. 2026-06-30 Codex addendum — the broadsheet "Bias analysis" subnav entry to /domains/veritas/bias and detector Close/browser-history return to /veritas are covered by veritas-bias-detector.spec.ts. 2026-06-30 Codex addendum — the broadsheet "Article analyzer" subnav entry to /domains/veritas/articles is covered by veritas-article-analyzer.spec.ts. 2026-06-30 Codex addendum — the broadsheet "Claim tracker" and "Fact checker" subnav entries to /domains/veritas/claims and /domains/veritas/fact-check are covered by veritas-claim-tracker.spec.ts and veritas-fact-checker.spec.ts.

Purpose#

The Veritas domain hub: a broadsheet-style "today's lead" — a single grounded story rendered alongside its claims, sources, and counter-evidence rail. The thin server component awaits getVeritasLead() (a real BFF fetch of /v1/veritas/briefing/home) and hands lead.data to VeritasRoom (Lilith design-system room). When no grounded lead exists the BFF returns 503 and getVeritasLead() yields an honest "unavailable" VeritasData (veritasLeadUnavailable()) — never a fabricated article.

Entry points#

  • Domain card on / (DomainCardGrid) — primary cold-entry from home
  • Domain switcher in shell header / /switcher
  • Shell sub-nav "Today's lead" tab — the LSubNav mounted by VeritasRoom marks this view active
  • Shell sub-nav "Article analyzer" tab — navigates to the signed-in Veritas Article Analyzer at /domains/veritas/articles
  • Shell sub-nav "Claim tracker" tab — navigates to the signed-in Veritas Claim Tracker at /domains/veritas/claims
  • Shell sub-nav "Fact checker" tab — navigates to the signed-in Veritas Fact Checker at /domains/veritas/fact-check
  • Shell sub-nav "Bias analysis" tab — navigates to the signed-in Veritas Bias Detector at /domains/veritas/bias and returns by browser history
  • Direct URL / bookmark — yes (auth required)
  • PWA shortcut — if declared in manifest.json (verify)
  • Deep link from notification — e.g., correction notice on a previously read piece

Layout regions#

page.tsx is a thin server component: const lead = await getVeritasLead()<VeritasRoom data={lead.data} />. VeritasRoom wraps content in LWebShell with an LCustomerNav active="library" and a domain LSubNav (lead | topics | sources | updates | articles | claims | fact-check | bias, lead active). Each LSubNav item carries a real href (/veritas, /veritas/topic, /veritas/source, /veritas/story, /domains/veritas/articles, /domains/veritas/claims, /domains/veritas/fact-check, /domains/veritas/bias).

  • Header: Lilith customer nav (Library tab active)
  • Sub-nav: domain tablist — Today's lead | Topic hubs | Sources | Story updates | Article analyzer | Claim tracker | Fact checker | Bias analysis
  • Masthead band: top rule with "Veritas · today's lead", a date label ("Tuesday, the sixth of May"), and reading meta ("8 min · N claims")
  • Article (left, 2fr desktop; one-column mobile stack): kicker eyebrow, large headline, byline + confidence pip, body paragraphs (first paragraph carries a drop-cap; paragraph 3 carries a pull-quote), then the <VeritasArticleActions> bar (a 'use client' component): Save to notebook · Read sources · Share excerpt plus a TrustSafetyFlagButton
  • Column rule: vertical divider between article and rail
  • Evidence rail (right, 1fr, sticky on desktop; stacked below article on tablet/mobile): Evidence · N claims header followed by claim cards (number, italic statement, confidence pip, optional source rows when the room data includes citation titles, optional counter-evidence pane), a closing Method note card, and — when data.nisabaDeepReadCue is set — a "Go deeper in Nisaba" card whose Link (aria-label "Open the Nisaba case-study notebook for this article") points at data.nisabaDeepReadCue.href

States#

  • LoadinggetVeritasLead() is awaited server-side; the page suspends until the data resolves (no client skeleton in page.tsx)
  • Populated (ready) — the BFF serves a grounded briefing; mapHomeBriefingToVeritasData renders the real article and the evidence rail (claims with sources, optional counter-evidence)
  • Anonymous user — shell middleware redirects per shell/04-auth-session.md (verify against middleware.ts)
  • Error (recoverable)getVeritasLead() returns { status: 'unavailable' } on a 503/unreachable BFF (it does not reject), so the room renders the honest-empty veritasLeadUnavailable() surface rather than hitting an error.tsx boundary
  • Offline — last-rendered HTML served from the service-worker cache; no client refresh path on this page
  • Standalone PWA — cold-launch lands here cleanly when /veritas was the relaunch target
  • Empty / Unavailable — when no grounded lead exists the BFF returns 503 and getVeritasLead() yields veritasLeadUnavailable() — a valid VeritasData with an honest empty surface, so "no lead today" IS a real code path (not N/A)
  • Gated — feature-flag or role gating not present in this page; verify against shell-level gates

Interactions#

Current E2E evidence:

  • apps/oshun/web/e2e/veritas-hub.spec.ts/veritas signed-in hub render from the real BFF home briefing, private cache headers, canonical metadata, Lilith primary/subnav links, article body, confidence labels, evidence rail, claim cards, current no-fabricated-source-row contract, optional counter-evidence mapping, method note, save/read/share/report actions, standalone PWA relaunch, and mobile overflow safety
  • apps/oshun/web/e2e/veritas-bias-detector.spec.ts/veritas "Bias analysis" subnav entry opens /domains/veritas/bias, verifies the detector default cognitive state, and closes back to the broadsheet lead through browser history
  • apps/oshun/web/e2e/veritas-article-analyzer.spec.ts/veritas "Article analyzer" subnav entry opens /domains/veritas/articles and verifies the analyzer overlay renders
  • apps/oshun/web/e2e/veritas-claim-tracker.spec.ts/veritas "Claim tracker" subnav entry opens /domains/veritas/claims and verifies the tracker overlay renders
  • apps/oshun/web/e2e/veritas-fact-checker.spec.ts/veritas "Fact checker" subnav entry opens /domains/veritas/fact-check and verifies the checker overlay renders
  • apps/oshun/web/e2e/veritas-full-journey.spec.ts — broader Veritas journey coverage for hub action affordances, save toggle, evidence-trail depth routes, report dialog, and restricted-scope honest no-lead state
  • apps/oshun/web/e2e/veritas-home-outage.spec.ts — downstream BFF outage configuration proving the browser-level 503 honest no-lead state against real dev infra
  • apps/oshun/web/e2e/veritas-claim-detail-workspace.spec.ts, apps/oshun/web/e2e/story-source-veritas.spec.ts, and apps/oshun/web/e2e/veritas-counterclaims-workspace.spec.ts — deeper claim, story/source, and counterclaim route coverage
  • Today's lead (tab) — active on this route; href and active marker verified
  • Topic hubs (tab) — target /veritas/topic
  • Sources (tab) — target /veritas/source
  • Story updates (tab) — target /veritas/story
  • Article analyzer (tab) — target /domains/veritas/articles, with E2E proof that the analyzer route opens from /veritas
  • Claim tracker (tab) — target /domains/veritas/claims, with E2E proof that the tracker route opens from /veritas
  • Fact checker (tab) — target /domains/veritas/fact-check, with E2E proof that the checker route opens from /veritas
  • Bias analysis (tab) — target /domains/veritas/bias, with E2E proof that Close returns to /veritas

Article body#

  • Body paragraphs (rendered text) — non-interactive; verify drop-cap attaches to the first character of paragraph 0 and the pull-quote falls between paragraphs 2 and 3
  • Confidence pip (LConfidence next to byline) — non-interactive; verify the level matches data.article.confidence

Article action bar (<VeritasArticleActions>, 'use client')#

  • Save to notebook (LBtn, toggles primary/ghost)
    • Function: handleSavetoggleOshunWebLibraryItem(...) with a domain: 'veritas' / kind: 'passage' library entry; the label flips to "✓ Saved to notebook" while saved (state seeded from isOshunWebLibraryItemSaved)
    • Keyboard: Enter/Space activates; included in tab order
    • Touch target: confirm against the ghost-button size token
  • Read sources (LBtn kind="ghost" size="md")
    • Function: a link href={readSourcesHref}; /veritas now passes #veritas-evidence-rail, so the button anchors to the real on-page evidence rail instead of the older fabricated /veritas/claim fallback
  • Share excerpt (LBtn kind="ghost" size="md")
    • Function: handleSharenavigator.share when available, otherwise navigator.clipboard.writeText (shows "Excerpt copied · paste anywhere" / "Shared" / "Could not share · try again"); AbortError resets to idle
  • Flag (TrustSafetyFlagButton, targetKind="content")
    • Function: opens the trust-&-safety report flow for this article (targetId = the derived article id, targetLabel = the headline)

Evidence rail — per claim#

  • Claim card (LCard) — non-interactive container; verify the eyebrow reads Claim · <number> and the italic statement matches claim.statement
  • Confidence pip (LConfidence) — non-interactive; level driven by claim.confidence
  • Source rows / no fabricated rows (LSourceItem) — per-source rows render only when claim.sources is present. The real /v1/veritas/briefing/home payload currently carries verification-trail claims without citation titles, so the hub E2E verifies the page does not fabricate source rows; source inspection is covered by /veritas/source and deeper Veritas specs.
  • Counter-evidence block — appears only when claim.counterEvidence is set; verify the conditional render

Method note & deep-read cue#

  • Method note cardLCard rendering data.methodNote; non-interactive
  • "Go deeper in Nisaba" card — rendered only when data.nisabaDeepReadCue is set; a Link to nisabaDeepReadCue.href (aria-label "Open the Nisaba case-study notebook for this article") carrying nisabaDeepReadCue.label; verify focus styling and the cross-domain hop into Nisaba

Data & contracts#

  • Reads: getVeritasLead() from @/lib/lilith-data/veritasbffGet<VeritasHomeBriefingResponse>('/v1/veritas/briefing/home', { revalidateSeconds: 20 }); returns a VeritasLeadState ({ status: 'ready' | 'unavailable'; data: VeritasData }) where data is always a valid VeritasData ({ article, claims, methodNote, … })
  • Writes: Save to notebook writes a local web-library entry (toggleOshunWebLibraryItem); Share excerpt uses web-share/clipboard; the flag button opens the trust-&-safety report flow
  • Realtime: none
  • Caching: server-component bffGet with revalidateSeconds: 20; service worker caches the rendered HTML for offline reload
  • Auth/role check: shell middleware (verify rule applied to /veritas)
  • Page metadata: title: "Veritas · today’s lead" (curly apostrophe), description: "A grounded story with its sources, claims, and counter-evidence laid out.", alternates.canonical: /veritas

Cross-references#

Open questions / known gaps#

  • Anonymous-user redirect and shell-level gated behaviour remain covered by shared auth/shell specs, but this walkthrough still needs a local cross-reference before it can be checked off here.
  • The optional data.nisabaDeepReadCue path is not populated by mapHomeBriefingToVeritasData() today; add BFF/mapper support or document its removal from the hub contract.
  • Confirm what telemetry, if any, fires on each article action; current hub E2E proves browser behaviour, not analytics emission.
  • Unexpected throw path still relies on the parent/global boundary because no loading.tsx or error.tsx exists in apps/oshun/web/src/app/veritas/.