Files
waggle-os/docs/ux-refactor/p1b-plan-review-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

7.4 KiB
Raw Permalink Blame History

P1b Plan — Adversarial Review Record (2026-06-11)

Two workflow rounds over p1b-auth-gate-plan.md v1 (6 lenses; round 1's contract lane completed, 5 lanes re-ran in round 2 after a session-limit failure). 24 confirmed / 0 refuted / 16 LOW. Every confirmed finding was independently verified by a skeptic agent against the live tree before acceptance. All are folded into plan v2; this file records them so they are not re-found, plus the LOW-grade confirmations of plan claims.

Confirmed (folded into plan v2)

# Sev Lens Finding → v2 disposition
1 CRITICAL contract installMcp is a typed JSON getter whose error body carries the ApprovalModal security envelope ({requiresApproval, blocked, severity} on 403/422); throw would kill the flow and the phase4b tests (method-level mocks) are blind → body-envelope migration class + adapter-level pins as hard Stage-A exit criterion
2 CRITICAL sse-ws-auth All five EventSource SSE channels 401-dead in EVERY default run since D1 (bearer-gated /api GETs; EventSource can't send headers; no ?token= on those routes; only /ws has the pattern and connectWebSocket is dead code) → plan §1.4, founder ruling requested, P1b scope unchanged
3 HIGH deadlock Gate-never-released hang: fetchWithTimeout bounds headers only; connect's res.json() reads unbounded → connect watchdog (~15s end-to-end deadline)
4 HIGH deadlock Gate disarms after failed early connect (default Tauri cold-sidecar path) re-opening the ungated burst with no recovery (NetworkError never triggers the 401 leg; focus never fires on an already-focused window) → settled-failure re-arm + ServiceProvider backoff + waggle:connect-settled bus consumed by all Stage-B surfaces
5 HIGH deadlock SSE half of the boot race unfixed and v1's "if and only if they attach the token" conditional matched zero methods (noop-guards = session-long dead subscriptions) → §1.4 honest de-scope; subscribe* untouched; acceptance check 1 scoped to fetch layer
6 HIGH test-blast adapter.eraseData.test.ts/adapter.startTrial.test.ts pin method-level Erase failed (400): <detail> messages with message-first detail; v1's error-first precedence inverted it → message-first pin + legacy-prefix wrappers in both methods
7 HIGH sse-ws-auth Chat sendMessage silent-empty-bubble on stale/missing token; plan's (b)+(c) verified the correct fix; useChat catch defects confirmed → no design change; Stage B useChat rework retained
8 HIGH tier-ui Definitive gate-vs-nag table (nav = pure capability gate, do NOT wire tierResolved; TrialExpiredModal + StatusBar badges already safe; UpgradeModal event-driven safe) → §1.2(d) classification
9 HIGH tier-ui useBilling failure renders FREE-as-fact + upgrade CTAs in Settings→Billing with zero error indication; post-Stage-A every failure funnels there → mandatory reshape
10 HIGH tier-ui SECOND tier-as-fact surface missed by v1: SettingsApp General-tab '{tier} plan' badge fed by getSettings (:54/157/239-241) → single-source from resolved billing state
11 HIGH d3-fidelity LoginBriefing got no revalidation wiring while v1's own UI copy promised "retrying" (plus-clause violation on a ruling-named surface) → wired to useRevalidateOnError, acceptance asserts recovery
12 MEDIUM deadlock setServerUrl mid-flight: stale connect continuations clobber baseUrl/localStorage/token (fallback can persist DEFAULT_SERVER over the user's new URL) → epoch guard
13 MEDIUM deadlock Straggler 401s chain sequential refreshes past single-flight; refresh failure semantics unpinned (silent token-less retry) → token-versioned retry + throwing refreshSessionToken
14 MEDIUM deadlock healthProbe not single-flighted; races useOfflineStatus's exempt /health probes on shared this.baseUrl mutation → single-flight + local-var fallback + epoch commit
15 MEDIUM deadlock uploadFile/ingestFile bypass the chokepoint entirely (raw fetchWithTimeout, hand-attached token, unconditional res.json()) → routed through the shared core
16 MEDIUM test-blast "~30 adapter test files" wrong by ~4× (actual 7; 2 not behavior-identical) → corrected, eraseData/startTrial carved out
17 MEDIUM test-blast Stage C's expected-fallout class is empty (no silent-empty-on-!ok pins exist); real risk was a mechanical rewrite erasing the startTrial message-surfacing guard → Stage C expectation rewritten
18 MEDIUM test-blast Call-count tripwire: kickoff must stay OUT of adapter module scope/constructor (5 files index mock.calls[0]) → zero-network-at-import/construction pin
19 MEDIUM→LOW test-blast 9 component test files render real ServiceProvider over hand-rolled mocks → ServiceProvider existing-members-only constraint
20 MEDIUM sse-ws-auth SSE has zero restart/error recovery even where it could work (es.close() in onerror; once-only subscribes) → part of the §1.4 "SSE auth + reconnect" single follow-up
21 MEDIUM tier-ui refreshTier failure path also clobbers trialInfo (StatusBar trial countdown transiently wiped); tierResolved semantics for unrecognized-tier unpinned → both pinned in (d)
22 MEDIUM→LOW tier-ui Nav getDockForTier confirmed pure capability gate → do-not-touch advisory + comment
23 MEDIUM d3-fidelity P7 deferral defense factually wrong for its own exemplar (MCPHubApp already connect-gated; gate adds nothing) and plus-clause narrowing was self-granted → two cheap wirings in §1.2(h) + decision-log note §3
24 HIGH contract (r1) (v1 round) installMcp misattribution — superseded by #1's fuller statement; plus addCustomMcp/updateMcpPermissions/revokeMcp/startMcp/stopMcp/testMcp body-envelope class, useChat consumer correction, AdapterHttpError.message pin, BackupApp-only among direct sites, uninstall false-success fix

LOW (verified clean / advisory — no plan change beyond what v2 already carries)

  • ensureReady 3-state ambiguity + sync memo assignment + settled-success memo retention → pinned in v2 §1.1(a).
  • "Pass-through stays armed by accident of the import graph" → boot-connect.ts first-import + zero-network pin close it structurally.
  • Setup files clean; no test imports main.tsx/App.tsx; Stage B existing-suite fallout ≈ zero (all coverage net-new).
  • No adapter-level raw/envelope pins exist anywhere (confirms blindness diagnosis) → hard exit criterion.
  • subscribeHarvestProgress degrades silently under 401 (import works, no progress UI) — noted in §1.4.
  • connectWebSocket dead code, builds ?token=null pre-token → P7 ledger.
  • Trial-expired modal verified already-safe; UpgradeModal verified safe; KvarkNudge doesn't exist (resolves to SettingsApp Enterprise CTAs — covered by the Billing-tab fix).
  • useFeatureGate / settings-tier-filter / persona-tier / dock-nudge / onboarding-tier-filter all local-state driven — excluded; stale comment + orphaned file → P7.
  • ComplianceDashboard.tsx:274 verified as THE live-confirmed CockpitApp crash; its refreshTemplates valid-empty cache added to §1.2(h).
  • Ruling coverage sweep: all four D3 sub-items + five live-confirmed targets covered; six named getters stay on throwing path; deviation-class note → §3.
  • Scope-creep audit: nothing cut-worthy; useBilling tagged as D3-4 extension.