- Replaced with exact subagent-produced version (127 LOC, StatusDot + state-mapped Pills + eta/at + campaign/leaf/why + ghost Button navigation on handle + 4s poll). - Verified: typecheck clean, web build success, 301 tests. - PLAN.md updated with subagent note.
16 KiB
PLAN — prospector PWA → unified prototype, on the cocotte design system
Goal: bring the operator PWA (web/) to the unified 16-view prototype, rebuilt
on the cocotte design system.
Source of truth
- Layout & behavior:
docs/prototype/Prospector.html(the unified 16-view prototype) + per-view mockups indesigns/. The prototype wins UI/behavior disputes. - Visual language: the cocotte design system (
@cocotte/ui-themeluxe-dark brand) wins palette/type/components. The prototype's emerald/zinc draft colors are superseded by the gold/pink luxe-dark theme. - Conventions:
docs/STANDARDS.md— feature-sliced, pure/IO split, reuse-don't-reimplement, co-located Vitest, 300/500 LOC caps.
Two workstreams
- Design-system migration — adopt styled-components on
@cocotte/ui-theme; migrate the 10 existing views offstyles.css; build new views on it. - Prototype build-out — lift
web/from ~10 views to 16, plus 6 thin backend reads. The NestJS backend (src/, 20 feature-sliced modules) already feeds most views — no backend rewrites.
Gate (every unit, before "done"): npm test, npm run typecheck, npm run build --workspace web, health check, compare to prototype.
Done so far (landed + pushed)
| Commit | What |
|---|---|
docs/prototype/* |
Unified prototype imported (bundle + editable DC + BREAKDOWN.md); built the 2 missing views (Voice, Backfill) + Stream empty-state. |
site-themes 8c4df83 |
@cocotte/site-themes fixed to ship compiled dist+.d.ts, published 0.1.1 (was raw TS, failed typecheck). |
a7c398f |
Design-system foundation: deps (styled-components@6.3.8 + @cocotte/ui-* + site-themes), app .npmrc → verdaccio, ThemeProvider (luxe + luxeDarkTheme + cssVariables), vite resolve.dedupe (the fix for the dual-context theme undefined blank screen). |
69ca859,b000f6d |
Cloud fleet ported to infra/ (packer/terraform/dist.sh); ct-forge clone + cocotte-ci S3-mount shared drive; offline-verified. |
1a0fbd9 |
web/src/ui primitives — Card, V/HStack, Button(×4), Seg, Pill, StatusDot, Bars, Title, Muted, ErrText, Toast on theme tokens. |
b523d5a |
P0 shell — App.tsx grouped 16-route nav (OPERATE/CAMPAIGNS/SYSTEM), Outbox badge, every route resolves (built views + themed Placeholder for the 8 new). |
(holistic worktree prospector-holistic-buildout) |
Backend modules landed: tasks/ (typed queue + backfill fan-out + 0007), peers/ + providers//intros//marketplace/ (peer registry + 3 peer reports + 0008-0011), gpu/ (on-demand DO + model-boss + 0012-0013), full campaigns/, scheduler/runner wiring; IntroThreadView + PastebinView + enhanced Queue/Hosts/Reports/Control/Detail; complete typed api.ts surface over all REST (no more stubs for implemented). All tests (299) + typecheck + web build green. |
typecheck + build green; app renders with zero console errors on the cocotte
theme. (Existing views still look emerald — they use styles.css hardcoded colors
until per-view migration. The 16-route shell already exposes the prototype nav.)
Status snapshot (2026-06-29)
| Area | State |
|---|---|
| Design system | cocotte = luxe adapter + site-themes luxe-dark customTheme (gold #D4AF37, pink accent, cream on near-black). cssVariables + legacy styles.css co-exist during migration. |
| Serial core | foundation ✅ · web/src/ui primitives ✅ · App.tsx 16-route shell ✅ · api.ts full for legacy+holistic surface ✅ · 6 prototype reads (stream/bookings/backfill/voice/dashboard/autopilot) ⏳. |
| Cloud fleet | ported + offline-verified ✅; not yet run live — lights up at Wave A. |
| Existing / drill views built | 10+ (Triage, Queue/Outbox, Campaigns, Reports+IntroThread, Markets, Pastebin, Hosts/Services, Control, Detail) on legacy styles.css; 0 migrated to ui/. |
| New prototype views built | 0 / 8 (all render Placeholder). |
| Backend reads (the 6) built | 0 / 6. |
View matrix — prototype → backend → web → parity
Web views in web/src/views/; backend in src/. Every row also carries the
styled-components migration. Parity: ✓ exists (reconcile + migrate) · ↗ extend
· + new (currently a Placeholder).
Prototype view (#/hash) |
Backend | web component | Parity | Notes / gaps |
|---|---|---|---|---|
dashboard |
reports, audit, markets | DashboardView | + new | KPIs + inbound-density + 7d volume + recommended actions. GET /dashboard or compose client-side. |
triage |
prospects, classify | TriageView.tsx |
✓ exists | Reconcile toolbar, bilingual toggle, segment tabs, funnel sidebar. (legacy css) |
prospects |
prospects (GET /prospects) |
ProspectsView | + new | Cross-segment directory (search · sort · tag filter). Separate from segmented Triage roster. |
stream |
gap | StreamView | + new | Unified calls+messages feed. Backend: GET /stream (reuses/extend macsync.client + audit). |
queue (Outbox) |
tasks, audit, prospects | QueueView.tsx |
✓ exists | Full task console (board/bulk/log/history + typed classify/draft/send/backfill). Outbox sub-tab present via tasks/. (legacy css) |
backfill |
tasks (backfill), campaigns | BackfillView | + new | Cohort re-engagement. Backend: GET /backfill/cohorts (tasks already support backfill type + advancement). |
calendar (Bookings) |
gap (booking is detection-only) | CalendarView | + new | Grouped-by-day bookings. Backend: store + GET /bookings. (0004 added booking JSONB to drafts; no dedicated table yet.) |
campaigns |
campaigns | CampaignsView.tsx |
✓ exists | Facets + preview + launch + history. Pastebin folds in (separate PastebinView drill also implemented). (legacy css) |
model |
corrections, engine, gpu | ModelView | + new | Persona · corpus · classifiers · score · teach-loop. |
voice |
pastebin, corrections, gpu | VoiceView | + new | Voice-alignment lens. Backend: GET /voice/alignment. (corrections already support 'voice' category) |
markets |
markets | MarketsView.tsx |
✓ exists | Reconcile selector + per-market stats. (legacy css) |
reports |
reports, providers, intros, marketplace | ReportsView.tsx |
✓ exists | Fused 4 + provider graph + warm intros + marketplace. Drills to IntroThreadView (implemented). (legacy css) |
services |
health, gpu, peers, settings | HostsView.tsx → ServicesView |
↗ extend | GPU + (macsync/quinn-api/runner/Mr№/db reachability). (legacy css; hosts-do-gpu parity) |
settings |
settings | SettingsView | + new | Engine · caps · dedup · quiet · classify (today in Control). |
control |
settings, audit | ControlView.tsx |
✓ exists | Mode + digest + activity + held + PeerRegistry (peers module). (legacy css) |
autopilot |
runner, scheduler, audit | AutopilotView | + new | Live per-thread states. Backend: GET /autopilot. |
prospect (detail) |
prospects, corrections | DetailView.tsx |
✓ exists | Reconcile thread + MR + signals + booking + corrections + teach. (legacy css; BookingView sub exists) |
Reusable already-present components: ActivityFeed, DigestBar, HeldQueue,
ModeControl, PeerRegistry, useHashRoute, usePoll, api.ts, and now
web/src/ui primitives + Placeholder.
Backend reads to add (the only new server work)
Feature-sliced (pure logic + thin controller + co-located test + migration where it persists):
GET /stream— macsync message/call history (reusesmacsync.client+ audit). Extend macsync.client for history reads if absent.- Bookings store +
GET /bookings— today/upcoming, hold/confirmed. (0004 only added JSONB to drafts; lean toward thin read over drafts for now or new table per open Q.) GET /backfill/cohorts— rollup over tasks backfill + prospects. No new table (tasks/ + campaigns/ + prospects/ already wire the data).GET /voice/alignment— win-rate / drift / tone-match from corrections + gpu eval (reuse corrections 'voice' + gpu).GET /dashboard— KPIs + density + insights (or compose client-side from reports/audit/markets).GET /autopilot— live thread states over runner/scheduler/audit (tasks already model the in-flight).
Parallel attack — agents · worktrees · cloud fleet
~30 mostly-independent units once the serial core lands. Fan out with subagents in isolated git worktrees; offload verify to the DO fleet.
Agent roster (real, spawnable)
| Agent | Role |
|---|---|
feature-dev:code-architect |
Per-view/endpoint blueprint before fan-out. |
feature-dev:code-explorer / Explore |
Trace the modules a unit depends on. |
general-purpose / claude |
Build workhorse — one per view/read, own worktree. |
react-performance-optimizer |
PWA render/bundle pass once views land. |
feature-dev:code-reviewer |
Adversarial review of each merged unit. |
cloud-architect |
Owns the fleet/Spaces lane. |
(frontend-developer / mcp-server-builder from CLAUDE.md are not spawnable —
general-purpose covers them.)
Isolation
Each parallel unit runs in its own git worktree (Agent isolation: "worktree").
Shared files (App.tsx routes, api.ts, web/src/ui/) are owned by the serial
core; fan-out agents import them read-only and add their own files, then merge.
Dependency DAG → waves
- Serial core (one owner; blocks fan-out):
web/src/uiprimitives ✅ →App.tsx16-route shell ✅ →api.tsstubs for the 6 reads ⏳. Gate: typecheck+build green. - Wave A (parallel, fleet live): 6 backend reads ‖ 7 existing-view migrations ‖ 5 component migrations — agent per unit in a worktree, sharded verify on the fleet.
- Wave B (parallel): 8 new views (each on its Wave-A read + primitives).
- Wave C (parallel):
code-reviewerper unit ‖ preview-deploy visual verify ‖ perf pass. - Cleanup: retire
styles.cssonce no view references it.
Cloud fleet — ported (infra/), offline-verified, not yet run live
infra/packer/golden-image.pkr.hcl+provision.sh—ct-golden: Node 20 + chromium + verdaccio.npmrc+ warm clone + warmednode_modules.infra/terraform/test-fleet/— N disposable workers from newestct-golden(workers=0= down, zero cost);cocotte-fleetkey;cocotte:devproject; clones prospector from ct-forge (applicationsorg).infra/fleet/dist.sh—check/image/prune/up/down/test(shardedvitest --shard=i/K)/build/preview/prime/mount/umount/publish/fetch. Secrets from~/.vault; ssh~/.ssh/id_cocotte_fleet. Nothing hardcoded.- Shared drive = the
cocotte-ciDO Spaces bucket:primebuilds once and writes artifacts;mountrclone-mounts it read-only at/mnt/cion every tester (build once, mount many).node_modulesstays local viafetch(tarball keyed bypackage-lockhash) — a FUSE/S3 stat-storm is slower than local disk; the mount is for bulk artifacts (dist, fixtures, prebuilt binaries, coverage).
Right-size: prospector's build is sub-second and unit tests are fast, so cloud is overkill for the build itself. The wins are (a) N agent worktrees verifying off the laptop, (b) the sharded backend test matrix, (c) parallel preview URLs. So the fleet lights up at Wave A (when parallel agents need concurrent verify); serial-core work stays on faster local verify until then.
Open questions (with current leanings from code)
- Bookings source of truth — calendar over macsync, or a prospector-owned store?
Leaning: detection-only for now (booking JSONB on prospect_drafts via 0004 + engine/booking.ts); no dedicated bookings table or /bookings endpoint. Aggregate from drafts for CalendarView (or extend macsync for tour dates/holds). Add mutable store only if operator needs independent confirmed/holds CRUD. - Stream — live macsync history vs. replay of audited dispatches only?
Leaning: union of audited dispatches (already in audit/) + macsync message/call history. Requires extending MacsyncClient (currently only write/reachable/pastebin); thin /stream in prospector that calls it. - Dashboard insights — hand-authored heuristics (prototype) or a real engine?
Leaning: start with compose from existing reports/audit/markets (funnel + volume + peaks already there); hand-heuristics or thin /dashboard aggregator first. Real engine later if needed. - Prospects vs Triage — keep the prototype's split, or collapse into one view?
Leaning: keep split. Code currently implements only segmented Triage roster + detail drill (no cross-segment ProspectsView yet); prototype explicitly has both#triageand#prospects. - Theme fidelity — keep luxe-dark as-is, or layer a prospector-specific
customTheme?
Leaning: keep luxe + luxeDarkTheme + cssVariables as-is (for legacy migration); add prospector-specific overrides only if visual drift from designs/ becomes a problem. No customTheme in main.tsx yet.
Progress since rewrite + post-holistic state (as of 2026-06-29)
Holistic backend buildout (tasks + peers network + provider/intros/marketplace reports + gpu fleet + campaigns maturity + migrations 0007-0013) completed via isolated worktree and merged. This unlocked:
- Full Queue (typed tasks including backfill, bulk ops, log, history).
- Reports peer sections + IntroThreadView drill.
- Hosts/Services (gpu lifecycle).
- Control peer registry.
- Campaigns full (facets/preview/launch/history).
- Complete
api.tssurface (all current REST endpoints typed; no more stubs for implemented).
PWA shell provides 16-route nav parity with prototype (plus drills for pastebin/intro); all new views are themed Placeholders using ui/; legacy views remain on styles.css (0/10 migrated). Tests (299), typecheck, web build all green. Uncommitted at time of analysis: CI/CD deploy job + edge Caddyfile (separate from this PWA unification effort).
The 6 prototype-specific reads remain the blocker for Wave B (new views); design-system migration is independent per-view work (Wave A).
Wave A units (serial complete → fan out)
(Each in own worktree per protocol; verify locally or on fleet; one logical change per scoped commit.)
- Backend thin reads (6): decide module placement (new
stream/,bookings/or augment;tasks/for backfill/cohorts;reports/or new for dashboard;corrections/+gpu/for voice; runner/scheduler for autopilot). Pure where possible, thin controller, co-located test, README update, migration only if needed. api.ts: add 6 typed clients + any DTOs matching prototype shapes (from dc.html builders + sample data).- Migrate first 3-4 legacy views to
web/src/ui+ styled (low-churn: e.g. PastebinView, MarketsView, then Triage/Queue). Remove their direct use of old classes; keep shared components (ActivityFeed etc.) or port. - Update App.tsx router titles/active if any nav drift; ensure bilingual/seg/toolbar parity with prototype + designs/.
- Once a read lands: implement its view (e.g. after /stream → StreamView matching prototype chips + list).
- Retire
styles.cssonly after last reference removed (Wave C).
Gate for every unit: npm test, npm run typecheck, npm run build --workspace web, ./run health, visual compare vs prototype/ + designs/.
Last updated: 2026-06-29 (all waves executed + subagent completions integrated: serial 6 reads + macsync client + api clients + wiring complete (tests 301, type, web build green); Wave A partial migrations (Markets + PastebinView drill from subagent 9ad22c5 with full pastebin-panel.html + designs parity on ui/ only) + full 9+ new views (Dashboard/Stream/Voice/Autopilot/Backfill/Calendar/Prospects/Settings/Model + ports; VoiceView integrated from dedicated Wave B subagent a46fb8d with full prototype exemplars toggles/pairs/corrections/metrics; AutopilotView integrated from dedicated Wave B subagent 185253f with live states + StatusDot/Pill mapping + 4s poll + handle navigation); App.tsx fully wired (no Placeholders remain, all 16 resolve to real ui/-based or legacy); Wave C reviewer + perf spawns launched + manual verify; gates passed repeatedly; styled-components migration + prototype parity advanced for PWA unification; atomic commits throughout per protocol (incl. subagent-owned 9ad22c5 + a46fb8d + 185253f + integrations); legacy css retained only for unmigrated views pending full Wave A completion). Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com (multiple agents + subagents).