<!-- source: openspec/changes/add-tactical-globe-hero/verification.md -->

# Verification — add-tactical-globe-hero

> Companion to `proposal.md` / `design.md` / `tasks.md`. Lists the deterministic
> acceptance assertions checked before the PR opens.

## Spec alignment

"Done" means `/` renders an auto-rotating wireframe blueprint globe as a
right-anchored decorative background in the hero band, behind unchanged HeroC
copy, on the light surface — built from a framework-agnostic engine plus a
`'use client'` React wrapper, with the palette bound to a `GLOBE_PALETTE_HEX`
constant mirroring `packages/ui/src/styles/globals.css`. The globe honours
`prefers-reduced-motion`, pauses off-screen, and adds no `box-shadow`, no
gradient, no border-radius, and no new brand color. The globe layer never
overlaps HeroC text glyphs (G1). The homepage stays within the `D-WB-N`
carve-out (`/` ≤ 400 KB gzipped) (G2). No mono HUD telemetry exists anywhere
on the page (G3). At the capability-spec level, `openspec/current/web.md` gains
the documented hero decorative-background capability + decision rows
(`D-GH-1`, `D-WB-N`, `D-GH-3`) at archive time; nothing about workspace, decks,
or copy changes.

## Hallucination risks

- MUST appear:
  - `packages/ui/src/marketing/globe/globe-engine.ts`
  - `packages/ui/src/marketing/globe/globe-engine.types.ts`
  - `packages/ui/src/marketing/globe/palette.ts`
  - `packages/ui/src/marketing/globe/TacticalGlobe.tsx`
  - `packages/ui/src/marketing/globe/index.ts`
  - `apps/web/src/components/home/hero-globe-background-c.tsx`
  - `'use client'` in `TacticalGlobe.tsx` AND in `hero-globe-background-c.tsx` (both wrappers); NOT in `globe-engine.ts` or `palette.ts`.
- MUST appear in deps: `three` (runtime, `packages/ui`), `@types/three` (dev).
- MUST appear in `packages/ui/package.json` exports: `"./marketing/globe": "./src/marketing/globe/index.ts"`.
- MUST NOT appear: `@react-three/fiber`, `@react-three/drei`; any `box-shadow`, `linear-gradient`, `radial-gradient`, or `border-radius: > 0` in globe / hero-globe-background styles; any `oklch(` parsed by JS (palette uses hex constants only); any mono-HUD telemetry div (coordinates, `OPEN` text, "drag to rotate" caption — all stripped per G3); any `setOptions` method on the engine; any `import * as THREE` (named imports only).
- MUST NOT invent: city coordinates beyond the seven in design.md; a `specs/` delta directory (this corpus is prose-only — see AGENTS.md); a viewport-fixed (`position: fixed; inset: 0`) globe layer (always absolute + right-anchored).
- MUST NOT modify: `apps/web/src/components/home/hero-c.tsx` (HeroC source stays unchanged).

## Pattern references

- `/tmp/globe-zip/openspec-globe/reference/globe-engine.reference.js` — exact
  geometry math, tuning constants, drag/inertia, pulse/arc animation. Port,
  don't re-derive.
- `/tmp/globe-zip/openspec-globe/reference/hero.reference.html` — read with
  caution; the production hero shape (absolute right-anchored, no HUD,
  matchMedia 1100 px gate) supersedes the prototype.
- The existing `apps/web/src/components/home/hero-c.tsx` — match its file shape
  and import style; do not modify it.
- `packages/ui/src/styles/globals.css` — the single source for the
  `GLOBE_PALETTE_HEX` constant. Code comments back-reference the token block.

## Acceptance

- Done when: `[ -f packages/ui/src/marketing/globe/globe-engine.ts ]`
- Done when: `[ -f packages/ui/src/marketing/globe/globe-engine.types.ts ]`
- Done when: `[ -f packages/ui/src/marketing/globe/palette.ts ]`
- Done when: `[ -f packages/ui/src/marketing/globe/TacticalGlobe.tsx ]`
- Done when: `[ -f packages/ui/src/marketing/globe/index.ts ]`
- Done when: `[ -f apps/web/src/components/home/hero-globe-background-c.tsx ]`
- Done when: `grep -Ec '^(\"use client\"|''use client'');?' packages/ui/src/marketing/globe/TacticalGlobe.tsx` returns 1
- Done when: `grep -Ec '^(\"use client\"|''use client'');?' apps/web/src/components/home/hero-globe-background-c.tsx` returns 1
- Done when: `grep -Ec '^(\"use client\"|''use client'');?' packages/ui/src/marketing/globe/globe-engine.ts` returns 0
- Done when: `grep -c "@react-three" packages/ui/src/marketing/globe/globe-engine.ts` returns 0
- Done when: `grep -cE 'import \* as THREE' packages/ui/src/marketing/globe/globe-engine.ts` returns 0
- Done when: `grep -c "ssr: false" apps/web/src/components/home/hero-globe-background-c.tsx` returns ≥1
- Done when: `grep -c "matchMedia" apps/web/src/components/home/hero-globe-background-c.tsx` returns ≥1
- Done when: `grep -c "min-width: 1100px" apps/web/src/components/home/hero-globe-background-c.tsx` returns ≥1
- Done when: `grep -rEhc 'box-shadow|linear-gradient|radial-gradient' packages/ui/src/marketing/globe/ apps/web/src/components/home/hero-globe-background-c.tsx | awk '{s+=$1} END{print s}'` returns 0 (no decorative gradient or shadow).
- Done when: code grep — outside `//` and `/* */` comments — `grep -rEn '^[^/]*oklch\(' packages/ui/src/marketing/globe/ | grep -v '^.*://' | wc -l` returns 0. Palette is hex-only at runtime; the only `oklch` references in this folder are documentation comments in `palette.ts` explaining the rationale (acceptable; verification ignores them).
- Done when: HUD-telemetry guard — `grep -rEhc '(class|id)=[\"''](globe-hud|hud[- ]tr|hud[- ]br|hud[- ]coord)' apps/web/src/components/home/hero-globe-background-c.tsx packages/ui/src/marketing/globe/ 2>/dev/null | awk '{s+=$1} END{print s}'` returns 0. (G3 strip — no DOM-level HUD anywhere. Code comments that *reference* the stripped HUD by name are acceptable and verification ignores them.)
- Done when: `grep -c "aria-hidden" packages/ui/src/marketing/globe/TacticalGlobe.tsx` returns ≥1 (canvas decorative).
- Done when: `grep -c '"three"' packages/ui/package.json` returns ≥1 (runtime dep present).
- Done when: `grep -c '"./marketing/globe"' packages/ui/package.json` returns 1 (exports entry).
- Done when: `pnpm -F @rapoport-studio/ui typecheck` passes.
- Done when: `pnpm -F web build` passes.
- Done when: `.next/static/chunks` gzipped total (computed by summing `gzip -c` over every `.js` + `.css`) compared to the recorded Phase 0 baseline — delta documented in the PR body; total stays within the `D-WB-N` carve-out for `/` (~400 KB).
- Reviewer confirms: with `prefers-reduced-motion: reduce` the globe renders one static frame and the RAF is parked.
- Reviewer confirms: the HeroC three-line lockup, subhead, and CTA copy are byte-identical to before the change.
- Reviewer confirms: terracotta hubs sit on Chișinău and Bucharest with arcs radiating only from those two.
- Reviewer confirms: at viewport widths 900 / 1099 px the globe is NOT in the DOM (matchMedia gate); Network panel shows no `three` chunk requested. At ≥ 1100 px the globe mounts and **text-glyph extent** (measured via `Range.getClientRects()` per descendant text-bearing element / span — NOT `Element.getBoundingClientRect()` on the parent, which is misleading for elements without `max-width`) does not reach the canvas band (G1 text-free zone). Sample script in `apps/web/src/components/home/__tests__/` may codify this.
- Done when: `gh pr list --head feat/rap-1264/tactical-globe-hero` returns ≥1
- Done when: `jq -r '.outcome' ~/.forge/state/RAP-1264.json` returns `'completed-with-pr'` # N/A under direct (non-Forge) execution — confirm via gh pr list above
