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

104 lines
8.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# P2 — Verification Record: Home Cockpit + Workspace Desktop vs Brief v2.1 (2026-06-11)
**Phase:** P2 per the ratified sequence (decision register, `deltas/open-questions.md`) — "verify + J08 alert".
**Scope verified:** PRD §12.1 (Home Cockpit) + §12.2 (Workspace Desktop) functional requirements, states,
and acceptance criteria, against main @ `4e3d65d` (post-P1a conversion, post-P1b auth gate).
**Method:** 4-lane verification workflow (Home FRs / Home states+AC / Desktop FRs / Desktop states+AC),
every claimed gap adversarially refuted by an independent agent; 2 scout lanes (J08 implementation map,
wizard onFinish live-run map). 20 agents. Then a 4-lens adversarial diff review (16 agents) over the fixes.
## Verdict
**25 of 37 verified items met or ratified-divergence; 12 confirmed gaps (1 HIGH, 5 MEDIUM, 6 LOW);
2 gap claims refuted (first-run empty state and AC-k reachability are MET).** The HIGH and all
tiny/small verified defects were fixed in this phase; feature-shaped gaps are ledgered below.
## Fixed in P2 (this phase)
| # | Sev | Item | Fix |
|---|-----|------|-----|
| G8 | HIGH | "Artifact ready" state dead — `getWorkspaceFiles` returned the `{files:[...]}` envelope; `normalizeArtifacts` silently rendered Artifacts empty forever | Envelope unwrap at the fetch layer (`adapter.ts`) + fetch-layer regression lock (`adapter.files.test.ts`) — component tests mock the adapter and were structurally blind here |
| G0 | MED | Greeting never showed the user's name (B8 backend half landed, FE never consumed `userName`); raw ISO date rendered verbatim | `personalizeGreeting()` server-side (name spliced into the first clause); `formatBriefingDate()` in `HomeCockpit` |
| G4 | MED | J08 alert absent (D6 verification item — Journey 6 step 1) | `needsReviewCount` on `GET /api/home/briefing` (personal-mind, 200-frame bound matching the Memory Center's own window) + attention banner with Review CTA + deep-link chain (below) |
| G1 | LOW | Ranking recency-only; PRD says "recency AND priority" | `applyPriorityRanking()` — bounded boost: each pending/blocked item buys up to 5×1h of effective recency |
| G10 | LOW | Header `type`/`status` hollow — context route never projected them | `/api/workspaces/:id/context` now projects `description`/`type`/`status` (FE already rendered all three) |
| G11 | LOW | Stale workspace URL claimed "server offline"; errored screen sticky | Duck-typed `AdapterHttpError` branching: 404 → "Workspace not found" + go-Home CTA, 403 → permission; Retry button + `useRevalidateOnError` (armed for the transient offline state only) |
**J08 deep-link chain (new):** Home banner → `waggle:open-app {appId:'memory', filter:'unreviewed'}`
AppShell shim (stash + `/memory?filter=unreviewed`) → `MemoryRoute` re-stash on cold load
(AutomationsRoute pattern, so typed/refreshed URLs work) → `MemoryCenterTab` consumes (stash + live
event), validates against `STATUS_FILTERS`, seeds the status filter. Count and view share the same
bound (200) and the same mind (personal), so the number always matches what the user lands on.
**Diff review (4 lenses, adversarial):** 9 confirmed findings (0 critical/high; 2 medium — both test
gaps), 3 refuted. All 9 fixed pre-commit: MemoryRoute URL re-stash, revalidation gated to offline-only,
monotonic request guard in `MemoryCenterTab.load()` (also cures the pre-existing rapid-filter race),
`_phase1-contract.md` §2 amendment, queryString filter pin, route-level ranking inject pin,
focus-revalidation pin, needs-review comparison query corrected to `limit=200`.
## Met (verified with file:line evidence — highlights)
- Home: workspaces ranked w/ one-click Continue (real data, personal-only per A2), overnight summary
(memories/artifacts/automations/failures), suggested next actions, quick capture (all 4 kinds wired
to `/api/quick-capture`), Ctrl+K hint (D9 "Win+K" pill is gone), loading/first-run/normal/offline/
overnight-failure states, P1b error+retry path (cold-load crash guard survived conversion).
- Desktop: all 8 PRD tabs present + URL-driven (founder two-seam edit), chat-as-one-widget (D1-4)
with ChatHost keep-alive, 5/6 canvas widgets on real feeds, right panel, fixed layout, agents-running
indicator, no-memory/active/agent-running/permission/offline states.
- Refuted as gaps (i.e. actually met): Home first-run empty (Journey 2), Desktop AC-k reachability
(memory/artifacts/agents/skills/tasks/automations/settings all reachable from the workspace).
- Ratified divergences (PRD ≠ code is correct): D5 team/share tier-hidden; configurable widgets
later-phase.
## Residuals — ledgered, NOT fixed in P2
| Item | Sev | Size | Owner |
|------|-----|------|-------|
| S02-FR2: Memory/Timeline/Settings/Research tabs are placeholders (capability is 1 click away via left-nav routes) | MED | M | **P3 (D2)** for the Memory tab embed; rest P7 |
| S02-FR5: status bar — automations-active + MCPs-connected chips unbuilt (feeds exist) | MED | S | P7 |
| S01-R4: `upNext` only carries cron schedules; awareness 'task' rows never aggregated; 'event' has no calendar substrate (defensible deferral) | MED | S | P7 (tasks); register note (events) |
| S01-R7: `activeModels` never populated server-side; FE tile inert | LOW | S | P7 |
| S01-R2 aggravator: priority data only computed for the recency top-8 (`MAX_RANKED_WORKSPACES` fan-out cap) — a high-pending workspace outside the top-8 can't surface | LOW | S | P7 |
| S02-FR3: research-overview widget unbuilt (Research feature wholesale later-phase) | LOW | S | P7 / register note |
| S02-state-f: sync conflict N/A until team sync (Phase 5 founder-deferred) — record in the D15 state grid | LOW | doc | P7 (D15) |
| S02-AC-j residue: `status` can never be non-active (update route doesn't accept status/type) | LOW | S | P7 |
| J08 count bound: getRecent(200) scan undercounts past 200 unreviewed frames (consistent with the Memory Center view itself; large E-11 imports could exceed it — SQL count if exactness ever matters) | LOW | S | P7 |
| AppShell shim filter passthrough has no mounted-router test (queryString + route-level stash are pinned) | LOW | S | P7 |
## Acceptance check 8 — wizard onFinish seeding (LIVE-RUN, first ever)
**Result: PASS — after fixing two real defects the run itself surfaced.** Driven via Playwright
against a fresh sidecar (3333) + Vite dev (8080) with `?forceWizard=true`, three full wizard runs.
**Defect 1 (state):** `loadState()` re-evaluated the `?forceWizard` reset on every call — including
the `waggle:onboarding-sync` reload fired by every wizard save. The moment workspace-create persisted
`{workspaceId}`, the sync reload reset onboarding to `{completed:false, step:0}` and wiped it; `onFinish`
then ran with a fallback `local-*` id and the seeding chain silently broke (run 1 ended force-completed
by the returning-user auto-complete, user stranded on `/home`). Fix: once-per-page-load latch
(`forceWizardConsumed`), pinned by `p2-onboarding-forcewizard.test.ts`.
**Defect 2 (navigation):** the wizard finishes at pathname `/`; completing onboarding (normal-priority
state) commits before `handleOnboardingFinish`'s navigate (a `v7_startTransition` update), so the shell
mounts at `/`, `IndexRedirect` fires, and its `/home` navigation queues after the wizard's and wins.
Fix: one-shot `pendingWizardLanding` handoff — `IndexRedirect` honors the wizard's landing target.
Live-verified; not unit-pinned (module-internal handoff — the live smoke is the evidence; ledgered).
**Run 3 (post-fix) assertions, all green:** lands on `/workspaces/p2-smoke-three/chat` (real server id,
not `local-*`); widget header `P2 Smoke Three · general-purpose` (wizard persona active); composer
prefilled `Hello! What can you help me with?` (QW-1 starter, NOT sent); `waggle-chat-state-v1` persisted
the persona; zero chat-completion/LLM requests in the network log. Smoke workspaces deleted after.
**Flagged for founder (production-class, NOT fixed here):** the returning-user auto-complete
(`useOnboarding.ts` "Bug #2" effect) completes the wizard whenever a `useOnboarding` instance mounts
with `completed:false`, no `forceWizard` in the URL, and ≥1 workspace on the server. Its own comment
says the boot-time `wsManager.ensureDefault` stub counts. If `ensureDefault` seeds `default-workspace`
before first FE mount on a clean install, **a truly-new production user may never see onboarding at
all** (and the Tauri filesystem first-launch flag does not gate this effect). Needs a clean-install
verification (P4/D12 binary work is the natural place); until then this is a suspected
launch-integrity defect, not a confirmed one.
## Gates at close
FE tsc 0 · server tsc 0 (after `npm run build:packages`) · FE vitest 75 files green ·
server-local green · `npm run lint` exit 0. Suite counts in the session handoff.