---
path: /veritas
surface: customer
domain: veritas
auth: signed-in
source: apps/oshun/web/src/app/veritas/page.tsx
status: walked
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`.
---

# Veritas · today's lead

## 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

- [x] **Loading** — `getVeritasLead()` is awaited server-side; the page suspends
      until the data resolves (no client skeleton in `page.tsx`)
- [x] **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`)
- [x] **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
- [x] **Standalone PWA** — cold-launch lands here cleanly when `/veritas` was
      the relaunch target
- [x] **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

### Sub-nav tablist (`LSubNav`)

- [x] **Today's lead** (tab) — active on this route; href and active marker
      verified
- [x] **Topic hubs** (tab) — target `/veritas/topic`
- [x] **Sources** (tab) — target `/veritas/source`
- [x] **Story updates** (tab) — target `/veritas/story`
- [x] **Article analyzer** (tab) — target `/domains/veritas/articles`, with E2E
      proof that the analyzer route opens from `/veritas`
- [x] **Claim tracker** (tab) — target `/domains/veritas/claims`, with E2E proof
      that the tracker route opens from `/veritas`
- [x] **Fact checker** (tab) — target `/domains/veritas/fact-check`, with E2E
      proof that the checker route opens from `/veritas`
- [x] **Bias analysis** (tab) — target `/domains/veritas/bias`, with E2E proof
      that Close returns to `/veritas`

### Article body

- [x] **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
- [x] **Confidence pip** (`LConfidence` next to byline) — non-interactive;
      verify the level matches `data.article.confidence`

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

- [x] **Save to notebook** (`LBtn`, toggles primary/ghost)
  - Function: `handleSave` → `toggleOshunWebLibraryItem(...)` 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
- [x] **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
- [x] **Share excerpt** (`LBtn kind="ghost" size="md"`)
  - Function: `handleShare` → `navigator.share` when available, otherwise
    `navigator.clipboard.writeText` (shows "Excerpt copied · paste anywhere" /
    "Shared" / "Could not share · try again"); `AbortError` resets to idle
- [x] **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

- [x] **Claim card** (`LCard`) — non-interactive container; verify the eyebrow
      reads `Claim · <number>` and the italic statement matches
      `claim.statement`
- [x] **Confidence pip** (`LConfidence`) — non-interactive; level driven by
      `claim.confidence`
- [x] **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.
- [x] **Counter-evidence block** — appears only when `claim.counterEvidence` is
      set; verify the conditional render

### Method note & deep-read cue

- [x] **Method note card** — `LCard` 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/veritas` —
  `bffGet<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

- Component: `apps/oshun/web/src/components/lilith/rooms.tsx` — `VeritasRoom`
  (lines ~568–801)
- Component: `apps/oshun/web/src/components/lilith/VeritasArticleActions.tsx`
  (`VeritasArticleActions`)
- Data: `apps/oshun/web/src/lib/lilith-data/veritas.ts` (`getVeritasLead()`)
- E2E coverage:
  - `apps/oshun/web/e2e/veritas-hub.spec.ts`
  - `apps/oshun/web/e2e/veritas-full-journey.spec.ts`
  - `apps/oshun/web/e2e/veritas-home-outage.spec.ts`
  - `apps/oshun/web/e2e/veritas-article-analyzer.spec.ts`
  - `apps/oshun/web/e2e/veritas-claim-tracker.spec.ts`
  - `apps/oshun/web/e2e/veritas-fact-checker.spec.ts`
  - `apps/oshun/web/e2e/veritas-bias-detector.spec.ts`
  - `apps/oshun/web/e2e/veritas-claim-detail-workspace.spec.ts`
  - `apps/oshun/web/e2e/story-source-veritas.spec.ts`
  - `apps/oshun/web/e2e/veritas-counterclaims-workspace.spec.ts`
- Shell: [`shell/01-app-shell.md`](../../shell/01-app-shell.md)
- Sibling Veritas routes:
  - [`veritas-claim.md`](./veritas-claim.md) — claim mode
  - [`veritas-counterclaims.md`](./veritas-counterclaims.md)
  - [`veritas-source.md`](./veritas-source.md)
  - [`veritas-story.md`](./veritas-story.md)
  - [`veritas-topic.md`](./veritas-topic.md)
  - [`veritas-provenance.md`](./veritas-provenance.md)
  - [`veritas-retraction.md`](./veritas-retraction.md)
  - [`veritas-mobile.md`](./veritas-mobile.md)
- Domains namespace alternates: `/domains/veritas/*` — see
  [`domains-veritas-bias.md`](./domains-veritas-bias.md),
  [`domains-veritas-articles.md`](./domains-veritas-articles.md), and siblings
- Feature spec: [`V1/features.md`](../../../V1/features.md#veritas)
- Architecture: [`V1/ARCHITECTURE.md`](../../../V1/ARCHITECTURE.md#veritas)

## 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/`.
