Files
waggle-os/docs/ux-refactor/path-exec-phase-C-spec-2026-07-07.md
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

9.2 KiB

Path-to-9 execution · PHASE C — the aliveness loop (Pillar 3) + R20 cleanup

Contract: docs/ux-refactor/path-to-9-2026-07-07.md v3 §Pillar 3 (5/5 endorsed) + R20

convergent residuals. R20 = min 7.6 avg 7.78; the #1 gap (4/5 HIGH) is streaming cadence.

All new motion uses lib/motion/tokens.ts. Both themes. Reduced-motion per REDUCED map.

Lane S1 — streaming cadence + honey caret (Pillar 3.1; THE headline, 4/5 HIGH)

Files: NEW hooks/useStreamCadence.ts (+ test), components/os/apps/chat-blocks/TextBlock.tsx, hooks/useChat.ts (feed the cadence buffer only — do not change the SSE path), tests. Root cause (verified): the SSE delivers chunks; TextBlock re-renders whole markdown per chunk → judges read "line/chunk reveal" not "per-token fade." Fix = a render-side cadence buffer (the v3-sanctioned option: "smooth chunks into a steady visible rhythm with ZERO added latency to first token").

  1. useStreamCadence(rawText, isStreaming){ shown, caretVisible }: keeps a target string (the accumulated raw stream) and a shown length that advances on rAF toward the target at a cadence that SCALES with backlog (reveal ~ max(minCharsPerFrame, ceil(backlog / catchupFrames))) so it NEVER lags more than a small window and drains fully within ~1 frame of stream end. FIRST characters reveal immediately (no buffering delay before first paint). When !isStreaming, snap shown to full. Guard: rawText only grows during a stream (never reveal past target; handle target shrink on reset).
  2. TextBlock consumes it: render renderChatMarkdown(shown) (the smoothed prefix) with a trailing honey caret (--honey-text, a soft blink via a token'd keyframe — NOT animate-pulse; ~1s) at the reveal head. Reduced-motion: snap to full text, static caret (REDUCED.streamingCaret). The existing capability-segment logic + markdown escaping stay.
  3. Hard-case markdown forms without popping (v3 competitor acceptance): a code block + a list must render progressively as the smoothed text crosses their boundaries — no whole-block pop. renderChatMarkdown already escapes+emits; verify partial markdown (unterminated ``` / partial list) degrades gracefully (renders as forming text, not raw noise). Add a test with a chunked code-block+list input asserting monotonic reveal.
  4. Zero added latency: unit-test that the first chunk's first chars are shown within one rAF, and total reveal completes ≤1 frame after the last chunk.

Lane S2 — streaming interaction contract (Pillar 3.1 cont'd; v3 competitor blocking)

Files: components/os/apps/ChatApp.tsx (scroll container + stop control), the chat scroll hook if one exists (grep), tests.

  1. Auto-follow scroll that breaks INSTANTLY on user scroll (input-primacy applied to the stream): while streaming, keep the viewport pinned to the newest content; the moment the user scrolls up, STOP auto-following and show a "Jump to latest ↓" affordance (honey pill, bottom-right of the thread); clicking it re-pins. Re-pin automatically when the user scrolls back to the bottom.
  2. Visible stop control: a Stop button (replaces/augments send while streaming) that halts output immediately mid-stream (wire to the existing SSE cancel — grep useChat for the abort/cancel path; Lane C added streaming-by-id). The partial answer stays; the composer returns to send.
  3. Tests: auto-follow pins during stream; a simulated user scroll-up sets not-following + shows the jump affordance; stop calls the cancel path and re-enables send.

Lane AL — surprise-recall bloom · investment celebration · first-60s wow · home ambient

Files: components/os/apps/chat-blocks/StepBlock.tsx or the Auto-Recall chip component (grep "Auto Recall"/recall chip), apps/HomeCockpit.tsx (briefing accrual line + ambient), overlays/onboarding/* (first-task wiring — verify), NEW components/os/warm/AmbientHiveGlow.tsx (+ test), tests.

  1. Surprise-recall bloom (Pillar 3.2, rubric dim-6 — the product's unique dopamine): when the Auto-Recall chip appears mid-chat (memory pulled into context), it blooms honey for ~600ms (SPRING.micro scale + a honey glow that fades), drawing the eye to the "it remembered" moment. Reduced-motion: instant, no bloom.
  2. Investment celebration (Pillar 3.3): the home briefing states what ACCRUED since last visit ("12 new memories · 2 decisions since Tuesday") sourced from real data (briefing-source counts — honesty gate: bind to the exact number, no estimate). The Phase-B DeltaNumber pulse already exists — reuse it on the accrual figure. If the accrual delta isn't available from the current briefing payload, render nothing (never fabricate) and note the data gap.
  3. First-60s wow (Pillar 3.4): verify the first chat message after onboarding demonstrably uses the just-entered profile ("As a consultant, you'll want…"). If the wiring exists, ensure it's visible; if not, a minimal profile-aware opener. Verify the onboarding→first-task handoff in code before adding anything.
  4. Home ambient hive life (brand HIGH — AmbientHiveGlow.tsx): a slow honey radial "breath" (very low amplitude opacity/scale, ~6s cycle) + optional faint hex-cell shimmer behind the home hero zone, BELOW attention threshold (must not compete with content — brand's "respectful, no gratuitous movement" WIN must survive). Reduced-motion: static (REDUCED.ambient → off). Gate the whole thing behind a prop so it's home-only.

Lane CL — R20 cleanup (verified residuals; several are a11y-HIGH double-yield)

Files: os/BootScreen.tsx (reduced-motion glow), os/apps/AllWorkspacesApp.tsx + apps/memory/MemoryTrustManage.tsx (card/row overflow keyboard reach), the SectionLabel/ eyebrow usages flagged, the capture kit seed (scratchpad — orchestrator owns), tests.

  1. Reduced-motion boot glow freeze (s11, 2 judges): the boot radial "breath" ramp must be static under prefers-reduced-motion — audit BootScreen for any remaining ungated glow (the logo loop was gated in A2; this is the background radial bg-primary/5 blur if animated, + the progress area). Zero lingering animation under reduce.
  2. Card/row overflow ('…') keyboard reachability (a11y+design HIGH): the workspace-card kebab and memory-row actions must be reachable by Tab with a visible --focus-ring on the ACTION itself (roving tabindex if they're in a menu; focus-visible reveal if hover-gated). The s10 acceptance ("reach card actions without a mouse") must be provable — add a keyboard test that tabs to a card, opens its menu via keyboard, and reaches Delete.
  3. Tertiary-text stragglers (a11y): the eyebrow labels the runtime pass / judges still flag (RESEARCH HUB, START HERE card eyebrows, onboarding subhead + on-device footnote) → --text-tertiary (verify each is a real sub-AA case with computed ratio; the SectionLabel primitive was raised in Phase A — these may be one-off usages not on the primitive).
  4. Light-theme focus-ring visibility (a11y): confirm --focus-ring reads on cream — contrast-tokens already proves ≥4.03:1; add ONE light-theme focus-ring assertion to the keyboard test or a spot check, and note the result (all R20 confirmed rings were dark).
  5. Dense-surface rhythm (medium, if time): marketplace results + models grid + memories list row vertical rhythm one step looser toward hero-surface craft. Scope-guard: only spacing, no structural change; if it risks the busy lanes, defer with a note.

Kit v7 (orchestrator, not a lane)

  • Capture seed: add waggle-booted: 'true' + waggle_onboarding_complete: 'true' + waggle:login-briefing-dismissed: 'true' to the returning-user addInitScript so s01 models the REAL returning user (boot skipped, cache-first ~459ms) — the R20 "2s boot wall" was this seed gap (product truth is boot-skipped; gate-verified). KEEP one first-launch boot showcase (s09 onboarding already covers first-run warmth; optionally a dedicated s12_first_launch to preserve the praised boot choreography as its own journey).
  • s04 stream window stays 12fps (judge the new per-char cadence there).

VERIFY STAGE (adversarial, after lanes)

  • V1-streaming: from the 12fps s04 stream window + code read — does the reveal read per-character/word (not chunk)? Is the honey caret present + reduced-motion static? Does a code-block+list form without popping (inspect useStreamCadence + a hard-case test)? Does autoscroll break on user scroll + jump-to-latest appear + stop halt immediately?
  • V2-aliveness: recall bloom fires on the Auto-Recall chip (reduced-motion instant); briefing accrual binds to a real number (no fabrication); ambient glow is below attention threshold + reduced-motion static; first-60s wiring verified.
  • V3-keyboard: re-run the s10 acceptance — tab to a workspace card, open its overflow menu by keyboard, reach Delete with a visible focus ring; confirm light-theme ring.

Orchestrator after verify

tsc web + full apps/web vitest + all gates (contrast-tokens/text-color-guard/warm-gate) + the runtime pass on /home,/settings both themes → commit → kit-v7 capture → R21 judge (gate: min ≥ 8.5 per v3 §3 after Pillar 3) → Phase D (Pillar 1 motion system).