This commit is contained in:
383
docs/ux-refactor/deltas/backend-api-delta.md
Normal file
383
docs/ux-refactor/deltas/backend-api-delta.md
Normal file
@@ -0,0 +1,383 @@
|
||||
# Backend API Delta — Waggle OS UX Refactor (Master List)
|
||||
|
||||
> **Purpose.** The single, consolidated, de-duplicated, **ordered** master list of every backend
|
||||
> endpoint the UX refactor must build or extend, plus every `.mind`/relational schema migration
|
||||
> required. This is the build contract for the LOCKED execution model: **in-place incremental
|
||||
> refactor** of `apps/web` + targeted **local Fastify sidecar** extensions. Every endpoint is built
|
||||
> over the existing substrate — no new database, minimal-to-zero SQLite migration (see §M).
|
||||
>
|
||||
> **Sources (all read & grounded):** PRD §16 (`docs/.../Waggle_OS_UX_Refactor_PRD.md:1060-1158`),
|
||||
> PRD §8/§21 phase+sprint structure (`:212-253`, `:1304-1374`), PRD §15 data model (`:918-1057`);
|
||||
> the 22 gap cards (`docs/ux-refactor/gap-cards/S00–S21`); the route/substrate inventories
|
||||
> (`docs/ux-refactor/_inventory/{backend-routes,substrate-types,frontend}.md`); the audited
|
||||
> backend-map (`docs/backend-map/sections/03a–03g`); and spot-verified live source under
|
||||
> `packages/server/src/local/routes/*.ts`, `packages/server/src/local/workspace-state.ts`,
|
||||
> `packages/hive-mind-core/src/{workspace-manager,mind/schema,mind/db}.ts`,
|
||||
> `packages/core/src/{install-audit,cron-store}.ts`.
|
||||
>
|
||||
> **Scope.** Everything is the **Local Sidecar** (`packages/server/src/local/index.ts` →
|
||||
> `buildLocalServer()`, loopback `:3333`, flat `/api/*`, Bearer session-token). The desktop frontend
|
||||
> talks ONLY to this server. The Clerk-gated **Cloud** server (`packages/server/src/routes/*.ts`) is
|
||||
> out of scope — where its routes collide with PRD paths (notably `/api/agents/*`) the sidecar work is
|
||||
> still **net-new locally** and flagged.
|
||||
|
||||
---
|
||||
|
||||
## How to read this
|
||||
|
||||
Each row carries:
|
||||
|
||||
- **Method + Path** — the PRD/refactor contract path (PRD-literal where §16 names it).
|
||||
- **Disposition** — `NET-NEW` (no route serves this; build it) · `EXTEND` (a real handler exists;
|
||||
add alias/param/field/behavior) · `NET-NEW (thin dispatcher/alias)` (new path, delegates wholly to
|
||||
existing handlers, no new logic).
|
||||
- **Build target** — the exact route file to create or the existing file/handler/builder to extend
|
||||
(with line where load-bearing). **Verified absent:** `agents.ts`, `artifacts.ts`, `home.ts`,
|
||||
`command.ts`, `mcps.ts`, `automations.ts`, `quick-capture.ts` do **not** exist under
|
||||
`packages/server/src/local/routes/` (grep-confirmed) — all are net-new files.
|
||||
- **Substrate** — the store(s) it reads/writes.
|
||||
- **Shape** — a 3–5 line request/response sketch.
|
||||
- **Screens** — gap-card IDs that consume it.
|
||||
|
||||
Counts are in §Counts at the bottom. **De-dup note:** §16 lists 65 endpoints but several are consumed
|
||||
by multiple screens (e.g. `/api/workspaces/:id/state` → S01+S02; `/api/skills/*` → S06+S19;
|
||||
`/api/agents/*` → S09+S18; the cron→automations aliases → S11+S20; connector/MCP → S07+S08+S14+S17;
|
||||
harvest → S15+S16). This master list states each endpoint **once**, attributing all consuming screens.
|
||||
Endpoints that **EXIST as-is** with zero backend work (e.g. `GET /api/workspaces`, `GET /api/connectors`,
|
||||
`GET /api/memory/graph`, the team CRUD core, the harvest engine) are **excluded** — they need only FE
|
||||
wiring. Only NET-NEW + EXTEND backend work is listed.
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 — Architecture alignment (PRD §8 Phase 0 / §21 Sprint 1)
|
||||
|
||||
No new endpoints. Backend-relevant work is **type alignment + shared additive fields** that later
|
||||
phases write through. Land these first because Phase 1–5 write paths depend on them.
|
||||
|
||||
| Item | Disposition | Build target | Substrate | Notes / shape |
|
||||
|---|---|---|---|---|
|
||||
| `WorkspaceConfig` V2 additive fields | EXTEND (no route, no migration) | `packages/hive-mind-core/src/workspace-manager.ts:5-58` (interface) + `CreateWorkspaceOptions :60-95` | `workspace.json` (file, NOT SQLite) | Add optional `description, type(WorkspaceType), status('active'\|'paused'\|'archived'), agentIds[], connectorIds[], mcpIds[], updatedAt, lastActiveAt`. Default `status:'active'`; derive `type` from `templateId`/`group` for existing workspaces. **No DB migration** (JSON file). Consumed by S02/S17. |
|
||||
| Stamp `updatedAt` on write | EXTEND | `workspace-manager.ts:222` (`update()` currently stamps nothing but `riskClassifiedAt`) | `workspace.json` | One-line write-side touch. |
|
||||
| Stamp `lastActiveAt` | EXTEND | agent loop / chat route write-back | `workspace.json` | Currently `lastActive` is DERIVED at read from session mtimes (`workspace-context.ts:375-387`); persist it. |
|
||||
| Shared frontend type unions | EXTEND (FE only) | `apps/web/src/lib/types.ts` | — | Add `WorkspaceType, Scope, Confidence, MemoryKind, ArtifactKind, AgentType, AutonomyLevel, ExtensionType` (PRD §15.2). Reconcile FE `MemoryFrame`/`Workspace` lossy projections against API shapes (substrate-types §e). |
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Core runtime: Home, Workspace Desktop, Command Center (PRD §8 Phase 1 / §21 Sprint 2–3)
|
||||
|
||||
### 1a. Home Cockpit + Quick Capture (S01) — new `home.ts` + extend `memory.ts`
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/home/briefing` | **NET-NEW** | new `routes/home.ts`; fans `buildWorkspaceState()` (`workspace-state.ts:234`) / `buildWorkspaceNowBlock()` (`workspace-context.ts:191`) over `WorkspaceManager.list()` and ranks | `memory_frames`, session JSONL, `awareness`, `cron_schedules`, `identity` (for name) | `→ { greeting, userName, date, workspaces:[{id,name,rank,summary,pending,nextActions}], suggestedActions[] }`. Cross-workspace ranking aggregator (per-workspace builder is the seed; no cross-WS ranker exists today). | S01 |
|
||||
| `GET /api/home/overnight` | **NET-NEW** | new `routes/home.ts`; aggregates over since-last-login window | `events`/`ai_interactions`, `notifications`, `cron_execution_history`, `memory_frames` | `?since=<iso> → { memoriesAdded, artifactsCreated, automationsCompleted, failures:[{source,error}], window:{from,to} }`. No time-windowed delta exists today. | S01 |
|
||||
| `POST /api/quick-capture` | **EXTEND** (thin handler delegating to memory write) | `routes/memory.ts` `POST /api/memory/frames` (`:248`) as the write primitive; new thin handler or alias | `memory_frames` (personal `.mind`) + `awareness` (for `kind:task`) + `POST /api/ingest` (for `kind:file`) | `{ kind:'note'\|'task'\|'link'\|'file', content, workspaceId? } → { frameId }`. Defaults to personal mind, stamps `source:'quick-capture'`; `task` also writes an awareness row so it surfaces in `nextActions`. **No migration.** | S01 |
|
||||
|
||||
### 1b. Workspace Desktop (S02) — extend `workspaces.ts`
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/workspaces/:id/state` | **EXTEND** (thin route) | new thin route in `workspaces.ts` returning the `buildWorkspaceState()` sub-object already computed inside `/context` (`workspaces.ts:311`) | `memory_frames` + session JSONL + `awareness` | `→ WorkspaceState { active, openQuestions, pending, blocked, completed, stale, recentDecisions, nextActions }` (`workspace-state.ts:38-55`). `pending`+`blocked` seed the Tasks tab. No migration. | S01, S02 |
|
||||
| `GET /api/workspaces/:id/activity` | **EXTEND** (thin alias) | new thin route over `GET /api/events?workspaceId=` (`events.ts`) | `ai_interactions` / `execution_traces` / `audit_events` | `?limit= → { events:[{ts,type,actor,summary}] }`. Per-workspace audit feed. No migration. | S02 |
|
||||
|
||||
> **No backend work** for S02 Tasks (`tasks.ts` CRUD EXISTS), Members (`/api/team/members` EXISTS),
|
||||
> or status-bar feeds (`/api/fleet`, `/api/cron`, `/api/capabilities/status` all EXIST — compose
|
||||
> client-side; an aggregate `/status` route is optional and deferred). Artifacts tab is **S05's**
|
||||
> scope; S02 ships an interim file-registry view via existing `GET /api/workspaces/:id/files`.
|
||||
|
||||
### 1c. Command Center (Ctrl+K) (S00, S03) — new `command.ts`
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/command/search?q=` | **NET-NEW** | new `routes/command.ts` federating route | reads `/api/memory/search` (`memory.ts:120`), `WorkspaceManager.list()`, `/api/skills`, `/api/workspaces/:id/sessions/search` (`sessions.ts`) — **no new store** | `?q=&scope= → { results:[CommandResult{id,kind:'search'\|'launch'\|'create'\|'run'\|'navigate'\|'extend', objectType, title, subtitle?, score, requiresApproval?, payload?}] }`. Federates over ~4 substrates. | S00, S03 |
|
||||
| `POST /api/command/execute` | **EXTEND** | existing `POST /api/commands/execute` (note **plural**, `commands.ts`) — extend for navigate/create/run/extend dispatch, OR add a singular `/command/execute` alias | command runtime + dispatch targets | `{ command, objectType?, payload?, workspaceId? } → { ok, result? }`. Current runs slash-commands with a subset CommandContext; PRD's palette execute is broader. | S00, S03 |
|
||||
| `GET /api/command/recent` | **NET-NEW** (or client-derive first) | new `routes/command.ts` reading `ai_interactions` (or derive from session/event history) | `ai_interactions` (read-only) | `→ { recent:[{command,ts,objectType}] }`. No schema change. Cheapest v1 = client-side from session history; promote to server when a consumer needs cross-device. | S03 |
|
||||
| `GET /api/command/suggestions` | **NET-NEW** | new `routes/command.ts` reusing `deriveNextActions` (`workspace-state.ts:182-218`) + folding in `/api/skills/suggestions` | read-only over `memory_frames`/`awareness`/`cron` | `→ { suggestions:[CommandResult] }`. No migration. | S03 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Work layer: Memory Center, Artifact Center, Workspace Creation, Onboarding (PRD §8 Phase 2 / §21 Sprint 4–5)
|
||||
|
||||
### 2a. Memory Center (S04, S16) — extend `memory.ts` + ONE optional migration
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/memory` | **EXTEND** (alias) | accept bare path on existing `GET /api/memory/frames` (`memory.ts:188`) | `memory_frames` | `?scope=&kind=&confidence=&status= → { frames:[...] }`. Alias only. | S04 |
|
||||
| `GET /api/memory/:id` | **NET-NEW** (thin) | new thin read in `memory.ts` over `FrameStore.getById(id)` (no `GET .../frames/:id` exists today) | `memory_frames` | `→ { frame }`. Drawer detail. No migration. | S04 |
|
||||
| `POST /api/memory` | **EXTEND** (alias) | alias on `POST /api/memory/frames` (`memory.ts:248`) | `memory_frames` | `{ kind,title,content,scope,tags? } → { id }`. | S04 |
|
||||
| `PATCH /api/memory/:id` | **EXTEND** | extend `PUT /api/memory/frames/:id` (`memory.ts:448`) to accept `PATCH` + bare `:id` | `memory_frames` (`FrameStore.update`) | `{ content?, importance?, status?, tags? } → { ok }`. | S04 |
|
||||
| `POST /api/memory/:id/archive` | **NET-NEW** (thin) | new thin route; model archive as `FrameStore.update(id, importance:'deprecated')` OR `status` in the new metadata column | `memory_frames` | `→ { ok }`. No hard delete. | S04 |
|
||||
| `DELETE /api/memory/:id` | **EXTEND** (alias) | alias bare `:id` over `DELETE /api/memory/frames/:id` (`memory.ts:551`) | `memory_frames` (`FrameStore.delete`) | `→ { ok }`. | S04 |
|
||||
| `POST /api/memory/merge` | **NET-NEW** | new route in `memory.ts`; real logic (read N frames, synthesize merged content, write one, archive/delete originals) — reuse `FrameStore` + `findDuplicate` dedup | `memory_frames` | `{ frameIds:[...], strategy?:'concat'\|'llm' } → { mergedId, archived:[...] }`. Net-new logic, low schema risk. | S04 |
|
||||
| Harvest preview/commit confidence + selection | **EXTEND** | `POST /api/harvest/preview` (`harvest.ts:221`) → return ALL items (or paged) + per-item `confidence` + normalized `kind`; `POST /api/harvest/commit` (`harvest.ts:243`) → accept `{ selectedIds?:[] }` filter before the `createIFrame` loop (`:382-409`) | in-memory parse (preview) / `memory_frames` (commit) | Honors the trust-gate AC ("nothing imports without approval"). Preview confidence needs a classifier (LLM or heuristic). Preview-only confidence needs **no** migration. | S16 |
|
||||
|
||||
### 2b. Artifact Center (S05) — new `artifacts.ts` (largest net-new domain; aggregation only)
|
||||
|
||||
> **Single largest entity gap:** no `Artifact` type, table, or `/api/artifacts*` route exists anywhere
|
||||
> (substrate-types §e). The backend is a **thin net-new aggregation/normalization layer** over three
|
||||
> existing stores — **NO new data store**. A lightweight `artifacts.json` index holds title/status/
|
||||
> tags/relations; the bytes stay in the existing file/document/storage stores.
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/artifacts` | **NET-NEW** | new `routes/artifacts.ts`; normalize 3 stores | `GET /api/workspaces/:id/files` (`workspaces.ts:594`), document versions (`documents.ts`), storage files (`workspaces.ts /storage/files`) + `artifacts.json` index | `?workspaceId=&kind=&status= → { artifacts:[Artifact{id,title,kind,workspaceId,status,mimeType,storagePath,tags,relatedMemoryIds,...}] }`. | S02, S05 |
|
||||
| `POST /api/artifacts` | **NET-NEW** | `artifacts.ts`; delegates byte-write to `POST /api/ingest` / `files/upload` / `documents` | file/document stores + `artifacts.json` | `{ title,kind,workspaceId,content?/file? } → { id }`. | S05 |
|
||||
| `GET /api/artifacts/:id` | **NET-NEW** | `artifacts.ts`; resolve composite id → normalized Artifact + relations + preview meta | 3 stores + `documents.ts` versions | `→ { artifact, relatedVersions[], relatedMemoryIds[] }`. | S05 |
|
||||
| `PATCH /api/artifacts/:id` | **NET-NEW** | `artifacts.ts`; update title/status/tags/relations in `artifacts.json` (move = re-point storagePath via `files/move`) | `artifacts.json` (+ `files/move`) | `{ title?, status?, tags?, relatedMemoryIds? } → { ok }`. | S05 |
|
||||
| `DELETE /api/artifacts/:id` | **NET-NEW** (route) | `artifacts.ts`; remove index entry + optionally backing file via `files/delete`/`storage/delete` | `artifacts.json` + file stores | `?deleteBacking=bool → { ok }`. | S05 |
|
||||
| `GET /api/artifacts/search-related?q=` | **NET-NEW** | `artifacts.ts`; lean on `memory_frames_fts` + wiki search internally | `memory_frames_fts`, sessions, tasks, fleet | `?q=&artifactId= → { related:[{type,id,title,score}] }`. | S05 |
|
||||
|
||||
### 2c. Workspace Creation (S17) — extend `workspaces.ts` write path
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `POST /api/workspaces` (extend body) | **EXTEND** | `workspaces.ts:116-135` + `WorkspaceManager.create` (`workspace-manager.ts:60-95`) | `workspace.json` | Accept `description, type, status, skills[], agentIds[], connectorIds[], mcpIds[]` (the Phase-0 additive fields). **No DB migration.** | S17 |
|
||||
| `GET /api/workspace-templates` (extend shape) | **EXTEND** (optional) | `workspace-templates.ts:33` | template store | Add `skills[]`/`mcps[]`/`type` to `WorkspaceTemplate` so a chosen template pre-populates all 4 suggestion panels. | S17 |
|
||||
|
||||
### 2d. Onboarding: First Launch, Who-Are-You, Tool Discovery, Memory Import (S12–S15)
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `PUT /api/profile` (extend merge) | **EXTEND** | `profile.ts:167-228` allow-list (`:172-196`) + `UserProfile` (`:41-94`) + `DEFAULT_PROFILE` (`:96-135`) | `profile.json` (NOT SQLite) | Add `workType, teamSize, goals[]` to the merged-fields allow-list + interface. Already mirrors identity → memory P/I frame (`:201-224`). **No migration.** | S13 |
|
||||
| `POST /api/harvest/sources/:id/sync` | **NET-NEW** (thin) | new thin route in `harvest.ts`; resolve registered source + re-run commit | `harvest_sources` + `memory_frames` | `→ { runId }`. Sync today = `POST /api/harvest/commit`. NOTE: current sources keyed by `:source` **name** (not `:id`) — keep name key or alias. No new substrate. | S15, S16 |
|
||||
|
||||
> **S12 First Launch + S14 Tool Discovery need ZERO net-new backend** — all source catalogs already
|
||||
> have routes (`GET /api/connectors`, `GET /api/tools/detect`, `GET /api/offline/status`,
|
||||
> `GET /api/workspaces`); selections persist client-side in `OnboardingState` (localStorage),
|
||||
> optionally threaded via the extended `PUT /api/profile`. The full harvest engine
|
||||
> (`preview/commit/sources/progress/scan-claude-code/runs/extract-identity` + `POST /api/ingest`)
|
||||
> already EXISTS for S15 — only the `/sources/:id/sync` alias (above) and the S16 confidence/selection
|
||||
> extension (Phase 2a) are new.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Intelligence layer: Agents, Skills, Automations (PRD §8 Phase 3 / §21 Sprint 6)
|
||||
|
||||
### 3a. Agent Center + Agent Builder (S09, S18) — new sidecar `agents.ts` + agent store
|
||||
|
||||
> **Naming collision:** `/api/agents/*` CRUD exists ONLY on the Clerk-gated **Cloud** server
|
||||
> (`packages/server/src/routes/agents.ts`) — NOT the sidecar (confirmed absent). All of §16.7 is
|
||||
> **net-new locally**: a new `packages/server/src/local/routes/agents.ts` registered in `local/index.ts`.
|
||||
> **Persistence (recommended v1):** a `{dataDir}/agents.json` file store, mirroring the agent-groups
|
||||
> JSON precedent (`agent-groups.ts:29`) — **no SQLite migration**. (Alternative: an `agents` table in
|
||||
> `mind/schema.ts` with SCHEMA_VERSION bump — only if agents must be FTS/relation-queryable. See §M.)
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/agents` | **NET-NEW** | new `routes/agents.ts`; reads agent store; overlay live status from `/api/agents/active` + `/api/fleet` | `agents.json` (new) | `→ { agents:[Agent{id,name,type,goal,personaId,model,autonomyLevel,status,lastRunAt,successRate,...}] }`. May union saved agents + read-only personas for back-compat. | S09, S18 |
|
||||
| `POST /api/agents` | **NET-NEW** | `agents.ts`; persist Agent (§15.5 fields); PRO-tier gate like `personas.ts:32` | `agents.json` + `install_audit` (if elevated tools/MCPs claimed) | `{ name,type,goal,model,personaId?,autonomyLevel,memoryScopes,skillIds,connectorIds,mcpIds,permissions } → { id }`. | S18 |
|
||||
| `GET /api/agents/:id` | **NET-NEW** | `agents.ts` read over store | `agents.json` | `→ { agent }`. | S09, S18 |
|
||||
| `PATCH /api/agents/:id` | **NET-NEW** | `agents.ts`; mirror `agent-groups.ts:74-90` PATCH shape | `agents.json` | `{ ...partial } → { ok }`. | S18 |
|
||||
| `POST /api/agents/:id/run` | **EXTEND** | resolve agent → call real executor `POST /api/fleet/spawn` (`fleet.ts:66`, the only path that runs `runAgentLoop :185`). **Do NOT** use `agent-groups/:id/run` (stub `:105`). | fleet/orchestrator + `execution_traces` via `TraceRecorder` | `{ input?, workspaceId? } → { sessionId }`. Map agent persona/model/memoryScope/workspace onto spawn body. | S09, S18 |
|
||||
| `POST /api/agents/:id/pause` | **EXTEND** | map agent→active session → `POST /api/fleet/:workspaceId/pause` (`fleet.ts:260`) | fleet | `→ { ok }`. | S09, S18 |
|
||||
| `GET /api/agents/:id/traces` | **NET-NEW** (route over existing store) | new thin read over `execution_traces` (`mind/schema.ts:199`, written by `chat.ts`/`evolution.ts`, **no HTTP read today**), filtered by agent/session; fallback session timeline `sessions.ts` | `execution_traces` + `ai_interactions` | `?limit= → { traces:[{ts,step,tool,outcome,cost}] }`. | S09, S18 |
|
||||
|
||||
### 3b. Skills Hub + Skill Builder (S06, S19) — extend `skills.ts`
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `PATCH /api/skills/:id` | **EXTEND** | add `PATCH` alias + `:id`↔`:name` over `PUT /api/skills/:name` (`skills.ts:506`) | `~/.waggle/skills/*.md` | `{ content? } → { ok }`. No new substrate. | S06, S19 |
|
||||
| `POST /api/skills/:id/test` | **EXTEND** | add `:id` path variant routing to existing `POST /api/skills/test` (body-driven) | skill file + `parseSkillFrontmatter` | `{ testInput? } → { wouldInject, frontmatter }`. Sandbox/dry-run only; no execution. | S06, S19 |
|
||||
| `POST /api/skills/:id/install` | **NET-NEW** (thin dispatcher) | new dispatcher over `POST /api/skills/starter-pack/:id`, `capability-packs/:id`, `marketplace/install` (keep `requireTier('PRO')` for marketplace-sourced) | `marketplace.db` + `MarketplaceInstaller` + `SecurityGate` + `install_audit` | `{ source:'starter'\|'pack'\|'marketplace' } → { installed }`. Resolves source + delegates. | S06 |
|
||||
|
||||
> Skill **create** is the existing structured `POST /api/skills/create` (`skills.ts:431` →
|
||||
> `generateSkillMarkdown` + `redactSkillContent` + audit + hash) — the Builder's real target,
|
||||
> **EXISTS**. Publish reuses `POST /api/marketplace/publish` (PRO). Optional later: extend
|
||||
> `SkillFrontmatter` for structured inputs/outputs/memoryAccess (Builder Steps 3–4) — open question, not
|
||||
> in §16.8. No `.mind` migration (skills are flat files; marketplace is `marketplace.db`).
|
||||
|
||||
### 3c. Automation Center + Automation Builder (S11, S20) — alias cron as automations
|
||||
|
||||
> **The capability is cron** (`cron.ts`, `/api/cron/*` — full CRUD + trigger + history). "Automations"
|
||||
> = a rename/alias surface. **Zero MISSING, all PARTIAL.** Register a real `/api/automations/*` alias
|
||||
> plugin (PRD vocabulary) OR point the new UI at `/api/cron`. Trigger/condition/actions ride in the
|
||||
> existing `job_config TEXT` blob → **no `.mind` migration** for v1.
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/automations` | **EXTEND** (alias) | alias of `GET /api/cron` (`cron.ts:94`); reshape `toResponse` to expose `trigger/condition/actions/status` from `job_type`+`job_config` | `cron_schedules` | `→ { automations:[...] }`. | S11, S20 |
|
||||
| `POST /api/automations` | **EXTEND** (alias) | alias of `POST /api/cron` (`cron.ts:67`); persist `trigger/condition/actions` into `job_config` (+ `cron_expr` for schedule triggers) | `cron_schedules` | `{ name,trigger,condition?,actions[],schedule? } → { id }`. | S11, S20 |
|
||||
| `PATCH /api/automations/:id` | **EXTEND** (alias) | alias of `PATCH /api/cron/:id` (`cron.ts:124`) | `cron_schedules` | `{ ...partial } → { ok }`. **Note real bug:** FE `updateCronJob` calls `PUT /api/cron/:id` but only `PATCH` is registered (adapter.ts:836 vs cron.ts) — fix the adapter. | S11, S20 |
|
||||
| `POST /api/automations/:id/run` | **EXTEND** (alias) | alias of `POST /api/cron/:id/trigger` (`cron.ts:174`; auto-enables + executes + notifies) | `cron_schedules` + executor (`index.ts:1379`) | `→ { runId }`. | S11, S20 |
|
||||
| `POST /api/automations/:id/pause` | **NET-NEW** (thin) / EXTEND | add thin `/pause` route OR adapter calls `PATCH /api/cron/:id { enabled:false }` | `cron_schedules.enabled` + scheduler | `→ { ok }`. Add `/pause` for PRD contract. | S11, S20 |
|
||||
| `GET /api/automations/:id/logs` | **EXTEND** (alias) | alias of `GET /api/cron/:id/history` (in `notifications.ts:202` → `cronStore.getExecutionHistory`) | `cron_execution_history` | `?limit= → { logs:[...] }`. | S11, S20 |
|
||||
| `POST /api/automations/test` | **NET-NEW** | new dry-run route (PRD §12.10 "test before activate"); current `POST /api/cron/:id/trigger` really executes | cron executor (no-persist mode) | `{ trigger,actions[] } → { previewResult }`. No log/notify side-effects. | S20 |
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — Extend layer: Connectors, MCPs, Marketplace, Install Audit (PRD §8 Phase 4 / §21 Sprint 7)
|
||||
|
||||
### 4a. Connector Hub (S07, S14) — extend `connectors.ts`
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `POST /api/connectors/:id/sync` | **NET-NEW** | new route in `connectors.ts` (`WaggleConnector` has `connect`/`healthCheck`/`execute` but **no `sync()`**) | vault sub-key `connector:<id>:lastSync` (or small store) + activity event + `install_audit` | `→ { lastSyncAt, ok }`. **Phased:** MVP = `healthCheck()` + stamp `lastSyncAt` + emit event; full data re-pull is a larger connector-SDK addition. No `.mind` migration. | S07 |
|
||||
| `POST /api/connectors/:id/revoke` | **EXTEND** (alias) | alias to `POST /api/connectors/:id/disconnect` (`connectors.ts:107`) + write `install_audit` `action:'rejected'`/revoke | vault + `install_audit` | `→ { ok }`. Same intent, PRD verb. | S07 |
|
||||
| `POST /api/connectors/:id/connect` (extend) | **EXTEND** | `connectors.ts:55` — add `auditStore.record(...)` on success | vault + `install_audit` | (audit-trail enrichment, no shape change). | S07, S14 |
|
||||
| `GET /api/connectors` (extend payload) | **EXTEND** (optional) | `connectors.ts:6` — carry `category` (already on type, `types.ts:299`) + `lastSyncAt` so UI drops hardcoded CATEGORIES/sync-shim | connector registry | (payload enrichment). | S07, S14 |
|
||||
| `GET /api/connectors/health` (aggregate) | **NET-NEW** (optional, mockup) | `connectors.ts` — fan `healthCheck()` across connectors | connector registry | `→ { connectors:[{id,status,lastSyncAt}], systemHealth }`. Optional v1; compose client-side otherwise. | S07 |
|
||||
| `GET /api/connectors/activity` | **NET-NEW** (or use shared `/api/extend/audit?type=connector`) | reads `install_audit` rows filtered to `type:'connector'` | `install_audit` | `→ { activity:[...] }`. **Prefer the shared `/api/extend/audit`** (4c) which serves S07+S08+S21 with one route. No migration. | S07 |
|
||||
|
||||
### 4b. MCP Hub (S08, S17) — new `mcps.ts` + persisted MCP-config store + runtime population
|
||||
|
||||
> **The deepest backend gap in the Extend layer.** Today `mcpRuntime` is **empty and never populated**
|
||||
> (`local/index.ts:911`); there is no `GET /api/mcps`, no persisted MCP-config store, no boot-time
|
||||
> population. All routes live in a new `packages/server/src/local/routes/mcps.ts`. **Substrate decision:**
|
||||
> persist installed MCP configs as a JSON file / `.mcp.json` (no migration) — confirm dataDir path +
|
||||
> multi-workspace scoping (open question). The MCP catalog is static in `@waggle/shared mcp-catalog.ts`.
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/mcps` | **NET-NEW** | `routes/mcps.ts`; join static catalog (`@waggle/shared mcp-catalog.ts`) + installed-state (`capabilities/status.mcpServers[]`, `.mcp.json`, `marketplace mcp-registry.ts`) | catalog + `.mcp.json` + `install_audit` | `→ { mcps:[{id,name,status,installed,tools[],scope}] }`. Reads existing substrate; no migration. | S08, S17 |
|
||||
| `POST /api/mcps/install` | **EXTEND** | route through existing marketplace installer `POST /api/marketplace/install` (already handles `installType:'mcp'` → writes `.mcp.json`, `installer.ts:580`) | `marketplace.db` + `.mcp.json` + `install_audit` | `{ mcpId } → { installed }`. Resolve MCP id → marketplace package → install. Audit already recorded. | S08 |
|
||||
| `POST /api/mcps/:id/test` | **NET-NEW** | `mcps.ts`; resolve server, `start()` if needed, assert `isHealthy()` (`mcp-runtime.ts:94,399`) and/or `tools/list` round-trip | `McpRuntime` | `→ { ok, tools[], error? }`. Open question: live spawn-and-handshake vs static manifest validation. | S08 |
|
||||
| `POST /api/mcps/:id/revoke` | **NET-NEW** | `mcps.ts`; `mcpRuntime.removeServer(name)` (`mcp-runtime.ts:327`) + delete persisted config + `install_audit` `action:'revoked'` | `McpRuntime` + `.mcp.json` + `install_audit` | `→ { ok }`. | S08 |
|
||||
| `POST /api/mcps` (add custom) | **NET-NEW** | `mcps.ts`; persist config + add to runtime (blueprint API line 530) | `.mcp.json` + `McpRuntime` | `{ name, command, args[], env{}, workspaceId? } → { id }`. | S08 |
|
||||
| `POST /api/mcps/:id/start` · `POST /api/mcps/:id/stop` | **NET-NEW** | `mcps.ts`; map to `McpRuntime` start/stop (PRD §12.8 start/stop) | `McpRuntime` | `→ { status }`. | S08 |
|
||||
| `PATCH /api/mcps/:id/permissions` | **NET-NEW** | `mcps.ts` (blueprint API line 530) | `.mcp.json` config | `{ scope?, permissions? } → { ok }`. | S08 |
|
||||
| `GET /api/mcps/:id/logs` | **NET-NEW** (phased) | `mcps.ts`; needs a ring-buffer of stderr/stateChange in `McpServerInstance` (no log capture today) | new in-memory ring buffer | `→ { logs:[...] }`. Defer to later phase if log-capture infra not built. | S08 |
|
||||
|
||||
> **Boot-time runtime population** (populate `mcpRuntime` from the persisted config at startup,
|
||||
> `local/index.ts:911`) is the foundational non-route work item that unblocks all of the above.
|
||||
|
||||
### 4c. Marketplace / Extend + Install Audit (S21, shared S06/S07/S08)
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `GET /api/marketplace` | **EXTEND** (alias) | bare path = alias of `GET /api/marketplace/search` with default params (`marketplace.ts:56`) | `marketplace.db` | `→ { results:[...] }`. | S21 |
|
||||
| `GET /api/extend/audit` (shared governance read) | **EXTEND** (param) | the install-audit read route `GET /api/audit/installs` **already EXISTS** (`skills.ts:685`); add `?capability=` / `?type=` filter exposing `getByCapability()` (`install-audit.ts:125`) | `install_audit` | `?type=skill\|connector\|mcp\|marketplace&limit= → { entries:[AuditEntry] }`. Serves S06+S07+S08+S21 with one route. No migration. **Note:** substrate-types §d#1 listed this as missing; it is present — the work is the filter param, not a new route. | S06, S07, S08, S21 |
|
||||
|
||||
> **No `POST /api/share`** here — that is Phase 5 (Team). Per-workspace install scoping (§12.13) is
|
||||
> net-new product surface; PRD §22 risk register says "start with catalog + install audit, postpone
|
||||
> billing/public marketplace" — **defer to Phase 4 polish**.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Team intelligence: Team Workspace, RBAC, Sharing, Audit (PRD §8 Phase 5 / §21 Sprint 8)
|
||||
|
||||
> Team CRUD core EXISTS in `team.ts` (`teams.db`): `GET/POST/PUT/DELETE /api/teams`, `/:id`,
|
||||
> `/members`, `/members/:userId`, `/activity`. No `.mind` migration for the team core (`teams.db`
|
||||
> standalone; `team_capability_policies`/`overrides`/`requests` exist in migration `0001`).
|
||||
|
||||
| Method + Path | Disposition | Build target | Substrate | Shape | Screens |
|
||||
|---|---|---|---|---|---|
|
||||
| `POST /api/teams/:id/invite` | **EXTEND** (alias) | thin `/invite` alias forwarding to `POST /api/teams/:id/members` (`team.ts:581`, owner/admin gated) | `team_members` (`teams.db`) | `{ email?, userId?, role? } → { ok }`. No new substrate. | S10 |
|
||||
| `GET /api/teams/:id/audit` | **EXTEND** (alias) | alias `/audit` → existing `GET /api/teams/:id/activity` (`team.ts:690`, reads `audit_events` via `getAuditDb`) | `audit_events` | `→ { events:[...] }`. Or add audit-export shape. No new store. | S10 |
|
||||
| `PATCH /api/teams/:id/members/:memberId` (fix gate) | **EXTEND** (bug fix) | `team.ts:642` (`:userId`==`:memberId`); **fix PUT(owner-only `:615`) vs PATCH(owner/admin `:642`) role-gate inconsistency** | `team_members` | (behavior fix, no shape change). | S10 |
|
||||
| `POST /api/share` | **NET-NEW** | new route (no `/api/share` anywhere — grep-confirmed); shares memory/artifact with role-appropriate perms | `workspace.json teamId` linkage + (if frame-level) `memory_frames` metadata | `{ objectType:'memory'\|'artifact'\|'workspace', objectId, teamId, role } → { ok }`. **Open:** frame-level scope needs the `memory_frames` metadata migration (§M); v1 may scope implicitly via workspace `teamId`. Gate behind TEAMS tier like `/api/team/*`. | S05, S10 |
|
||||
| `POST /api/artifacts/:id/share` | **NET-NEW** (blueprint) | maps to `POST /api/share` + artifact scope; gate TEAMS | `artifacts.json` + team scope | `{ teamId, role } → { ok }`. Blueprint action not in §16.6; defer to Phase 5. | S05 |
|
||||
| `GET /api/teams/:id/governance` (optional) | **NET-NEW** (optional) | surface `team_capability_policies`/`overrides`/`requests` (migration `0001`); Enterprise proxy `GET /api/team/governance/permissions` (`team.ts:418`) is the remote analog | `team_capability_policies` etc. | `→ { policies[], overrides[], requests[] }`. RBAC UI. | S10 |
|
||||
|
||||
---
|
||||
|
||||
## §M — Schema migrations required
|
||||
|
||||
> **Headline: the entire refactor needs AT MOST ONE conditional SQLite migration**, and it is
|
||||
> deferrable. Every other "schema addition" is to a **JSON file** (`workspace.json`, `profile.json`,
|
||||
> `agents.json`, `artifacts.json`, `.mcp.json`) — **not** a database — so it is a pure additive
|
||||
> TypeScript-interface change with **no migration**. The migration runner already does idempotent
|
||||
> additive `ADD COLUMN` on `memory_frames` (precedent: it added `source`, `mind/db.ts:116-124`;
|
||||
> pattern = `pragma_table_info` guard + `ALTER TABLE … ADD COLUMN`).
|
||||
|
||||
### M1 — `memory_frames.metadata` (CONDITIONAL — Phase 2/Phase 5) — the only `.mind` SQLite migration
|
||||
|
||||
- **What:** add one nullable column `metadata TEXT NOT NULL DEFAULT '{}'` to `memory_frames`
|
||||
(`mind/schema.ts:47`). Store `{kind, title, scope, sourceId, sourceUrl, confidence, tags, evidence,
|
||||
relatedMemoryIds, relatedArtifactIds, status}` as JSON (PRD §15.4 fields; PRD endorses metadata-first,
|
||||
`:1013`).
|
||||
- **Why conditional:** `memory_frames` is the **only** mind table without a JSON blob column (unlike
|
||||
`awareness.metadata`, `knowledge_entities.properties`, etc.). Needed ONLY when persisted
|
||||
confidence/provenance/scope/status becomes a real **query/filter axis** (S04 Memory Center filters;
|
||||
S16 persisted-confidence review; S10/S05 frame-level `/api/share` scope). **NOT needed** if S16
|
||||
review is preview-only (pre-commit) and S04 filtering is in-app over the existing columns.
|
||||
- **Risk:** low — single additive nullable column; avoids touching the FTS/vec virtual tables and IPB
|
||||
scoring. **Promotion path:** if `confidence` becomes a primary indexed filter, a later migration adds
|
||||
`confidence REAL` as a real column (same ADD-COLUMN pattern).
|
||||
- **Screens:** S04, S16, S10, S05. **Build target:** `packages/hive-mind-core/src/mind/db.ts` migration
|
||||
block + `mind/schema.ts`.
|
||||
|
||||
### M2 — `install_audit` risk-level CHECK fix (RECOMMENDED — pre-Phase 4, latent bug)
|
||||
|
||||
- **What:** the TS `AuditRiskLevel` includes `'critical'` (`install-audit.ts:16`) but **both** DDL CHECK
|
||||
constraints allow only `('low','medium','high')` (`install-audit.ts:65` AND `schema.ts:130` — duplicated
|
||||
DDL that must stay in sync). A `record({riskLevel:'critical'})` throws a CHECK violation.
|
||||
- **Why:** Phase 4 connector/MCP/skill installs all route through `auditStore.record(...)`. The
|
||||
marketplace route currently side-steps by mapping CRITICAL→`riskLevel:'high'`+`approvalClass:'blocked'`
|
||||
(`marketplace.ts:224-319`) — but any new Extend caller passing `'critical'` crashes.
|
||||
- **Fix (pick one):** (a) widen both CHECK constraints to include `'critical'` (additive CHECK migration
|
||||
— needs table rebuild for SQLite CHECK change, or relax to no-CHECK), OR (b) lock the CRITICAL→`'high'`
|
||||
mapping as the permanent contract and drop `'critical'` from the TS union. (b) is zero-migration.
|
||||
- **Risk:** low. **Screens:** S06, S07, S08, S21 (all Extend installs). **Build target:**
|
||||
`install-audit.ts:65` + `mind/schema.ts:130` (kept in sync) OR the TS union.
|
||||
|
||||
### M3 — `agents` table (OPTIONAL — Phase 3, NOT recommended for v1)
|
||||
|
||||
- **What:** an `agents` table in `mind/schema.ts` with a `SCHEMA_VERSION` bump.
|
||||
- **Recommendation: do NOT do this for v1.** Persist agents to `{dataDir}/agents.json` (file store,
|
||||
mirrors the `agent-groups.json` precedent `agent-groups.ts:29`) — **no migration, reversible.** Only
|
||||
add the table if agents must be FTS/relation-queryable. PRD §14.4 non-goal favors minimal backend.
|
||||
- **Screens:** S09, S18.
|
||||
|
||||
### Non-migrations (additive JSON-file / interface changes only — listed for completeness, NOT migrations)
|
||||
|
||||
- `WorkspaceConfig` V2 fields → `workspace.json` (Phase 0; substrate-types §a).
|
||||
- `UserProfile` `workType/teamSize/goals` → `profile.json` (S13).
|
||||
- `Agent` entity → `agents.json` (Phase 3, M3 alt).
|
||||
- `Artifact` index → `artifacts.json` (Phase 2b).
|
||||
- MCP installed configs → `.mcp.json` (Phase 4b).
|
||||
- Automation `trigger/condition/actions` → existing `job_config TEXT` blob (Phase 3c; no schema change).
|
||||
- `cron_schedules`/`cron_execution_history`/`notifications` tables already exist with lazy creation
|
||||
(`cron-store.ts:135-157`) — no migration for Automations.
|
||||
|
||||
---
|
||||
|
||||
## Counts
|
||||
|
||||
> Counted as **distinct backend endpoints** (each method+path = 1). Endpoints that **EXIST as-is** and
|
||||
> need only frontend wiring are **excluded**. Phase-0 non-route work (V2 fields, FE type unions, write-
|
||||
> side stamps) is counted separately under "interface/field extensions", not as endpoints.
|
||||
|
||||
- **Total endpoints requiring backend work: 53** (NET-NEW + EXTEND, de-duplicated).
|
||||
- **NET-NEW endpoints: 35**
|
||||
- Home ×2 (`/home/briefing`, `/home/overnight`)
|
||||
- Command ×3 (`/command/search`, `/command/recent`, `/command/suggestions`)
|
||||
- Memory ×3 (`/memory/:id`, `/memory/:id/archive`, `/memory/merge`)
|
||||
- Artifacts ×6 (GET, POST, `/:id`, PATCH `/:id`, DELETE `/:id`, `/search-related`)
|
||||
- Agents ×5 (GET, POST, `/:id`, PATCH `/:id`, `/:id/traces`)
|
||||
- Skills ×1 (`/skills/:id/install`)
|
||||
- Automations ×1 (`/automations/test`)
|
||||
- Connectors ×3 (`/:id/sync`, `/connectors/health`, `/connectors/activity`)
|
||||
- MCPs ×8 (`GET /mcps`, `/:id/test`, `/:id/revoke`, `POST /mcps` custom, `/:id/start`, `/:id/stop`, `PATCH /:id/permissions`, `/:id/logs`)
|
||||
- Team ×3 (`POST /api/share`, `POST /artifacts/:id/share`, `GET /teams/:id/governance`)
|
||||
- *(Several MCP/connector/team items are blueprint-implied beyond the §16 literal list; `/api/automations/:id/pause` is counted under EXTEND as a thin alias over the cron `enabled` flag.)*
|
||||
- **EXTEND endpoints: 18** (distinct backend touch-points; an EXTEND may be an alias, an added param, or added behavior)
|
||||
- `/quick-capture` (delegates to memory write)
|
||||
- `/workspaces/:id/state`, `/workspaces/:id/activity` (thin routes over existing builders/events)
|
||||
- `/command/execute` (broaden dispatch)
|
||||
- `/memory` GET, `/memory` POST, `/memory/:id` PATCH, `/memory/:id` DELETE (aliases over `/memory/frames*`)
|
||||
- `/harvest/preview` + `/harvest/commit` (confidence + `selectedIds` selection)
|
||||
- `/harvest/sources/:id/sync` (thin re-commit alias)
|
||||
- `/workspaces` POST (richer body)
|
||||
- `/agents/:id/run`, `/agents/:id/pause` (delegate to fleet)
|
||||
- `/skills/:id` PATCH, `/skills/:id/test` (`:id` variants)
|
||||
- 6× `/automations/*` aliases over `/cron/*` (GET, POST, PATCH, run, pause, logs)
|
||||
- `/connectors/:id/revoke`, `/connectors/:id/connect` (+audit), `/connectors` GET (payload)
|
||||
- `/mcps/install` (via marketplace installer)
|
||||
- `/marketplace` (bare-path alias)
|
||||
- `/extend/audit` filter param (over existing `/audit/installs`)
|
||||
- `/teams/:id/invite`, `/teams/:id/audit`, `/teams/:id/members/:memberId` (alias + role-gate fix)
|
||||
- **Phase-0 interface/field extensions (NOT endpoints): 5** — `WorkspaceConfig` V2 fields + `updatedAt`/
|
||||
`lastActiveAt` write-stamps (`workspace-manager.ts`), FE type unions (`types.ts`), `UserProfile`
|
||||
`workType/teamSize/goals` (`profile.ts`), `WorkspaceTemplate` shape, `Connector` interface fields.
|
||||
- **PRD §16 cross-reference (from `_inventory/backend-routes.md`):** of 65 §16-literal endpoints —
|
||||
**16 EXIST** as-is (FE wiring only), **30 PARTIAL** (→ EXTEND), **19 MISSING** (→ NET-NEW). This
|
||||
master list adds ~16 blueprint-implied endpoints (MCP start/stop/logs/permissions/custom, connector
|
||||
health/activity, automations/test, team governance, artifact-share, extend/audit) beyond the §16
|
||||
literal set.
|
||||
- **Schema migrations:** **1 conditional** SQLite (M1 `memory_frames.metadata`) + **1 recommended**
|
||||
CHECK fix (M2 `install_audit` risk-level) + **1 optional/deferred** (M3 `agents` table — recommend
|
||||
NOT doing in v1). Net likely-to-ship: **1** (`memory_frames.metadata`); **0 strictly required** if
|
||||
S16 confidence stays preview-only and `/api/share` scopes implicitly via workspace `teamId`.
|
||||
- **New sidecar route files: 5** (`home.ts`, `command.ts`, `artifacts.ts`, `agents.ts`, `mcps.ts`)
|
||||
+ 1 alias plugin (`automations.ts` → cron). **New JSON file stores: 2** (`agents.json`,
|
||||
`artifacts.json`); plus reuse of `.mcp.json`, `workspace.json`, `profile.json`.
|
||||
272
docs/ux-refactor/deltas/coverage-check.md
Normal file
272
docs/ux-refactor/deltas/coverage-check.md
Normal file
@@ -0,0 +1,272 @@
|
||||
# Coverage Check — Waggle OS UX Refactor (Adversarial Completeness Audit)
|
||||
|
||||
> **Role:** Coverage Critic. This document is a skeptical, traceability audit of whether the
|
||||
> UX-refactor analysis (22 gap cards `S00–S21` + 3 deltas) is **complete** against the PRD's three
|
||||
> contract axes: **§12 screens (1–21)**, **§16 API endpoints (65)**, and **§26 Definition of Done (11)**.
|
||||
> It also flags PRD surfaces that fall **outside** the §12 numbered-screen list (§9.2/§11 objects,
|
||||
> §13 journeys, §17 RBAC, §10.4 Extend nodes) that no card owns.
|
||||
>
|
||||
> **Method:** every row is grounded in the PRD, the gap cards, `backend-api-delta.md`, and the
|
||||
> source-grounded `_inventory/backend-routes.md` §16 cross-reference (which the delta draws from).
|
||||
> "COVERED" = some card/delta explicitly owns the requirement with a build target. "GAP" = skipped,
|
||||
> implicit-only, or owned by no artifact.
|
||||
>
|
||||
> **Sources read:** PRD `docs/Waggle_OS_UX_Refactor_Master_Handoff_Package/Waggle_OS_UX_Refactor_PRD.md`
|
||||
> (§9, §10, §11, §12 lines 371–662, §13 lines 666–832, §14, §16 lines 1060–1158, §17, §19, §26 lines
|
||||
> 1485–1500); all `docs/ux-refactor/gap-cards/S00–S21.md`; `docs/ux-refactor/deltas/{backend-api-delta,
|
||||
> design-system-delta,shared-types-delta}.md`; `docs/ux-refactor/_inventory/{backend-routes,frontend,
|
||||
> substrate-types}.md`.
|
||||
|
||||
---
|
||||
|
||||
## Table 1 — PRD Screens (the 21 numbered screens + AppShell)
|
||||
|
||||
The 21 numbered screens are the blueprint deck expansion of PRD §12.1–§12.13. AppShell (S00) is the
|
||||
chrome the PRD §1 spine mounts inside (not a §12 screen, but required by §19.1 + §20.3). **Verdict: all
|
||||
21 numbered screens + the shell are COVERED by a gap card.** No numbered screen is missing.
|
||||
|
||||
| # | PRD screen (§ ref) | Status | Gap card |
|
||||
|---|---|---|---|
|
||||
| — | AppShell / IA / Navigation (§1, §19.1, §20.3) | COVERED | **S00** appshell-ia |
|
||||
| 1 | Home Cockpit (§12.1) | COVERED | **S01** home-cockpit |
|
||||
| 2 | Workspace Desktop (§12.2) | COVERED (with sub-gaps, see notes) | **S02** workspace-desktop |
|
||||
| 3 | Command Center (Ctrl+K) (§12.3) | COVERED | **S03** command-center |
|
||||
| 4 | Memory Center (§12.4) | COVERED | **S04** memory-center |
|
||||
| 5 | Artifact Center (§12.5) | COVERED | **S05** artifact-center |
|
||||
| 6 | Skills Hub + Skill Builder (§12.6) | COVERED | **S06** skills-hub (+ **S19** skill-builder) |
|
||||
| 7 | Connector Hub (§12.7) | COVERED | **S07** connector-hub |
|
||||
| 8 | MCP Hub (§12.8) | COVERED | **S08** mcp-hub |
|
||||
| 9 | Agent Center + Agent Builder (§12.9) | COVERED | **S09** agent-center (+ **S18** agent-builder) |
|
||||
| 10 | Automation Center + Builder (§12.10) | COVERED | **S11** automation-center (+ **S20** automation-builder) |
|
||||
| 11 | Team Workspace (§12.11) | COVERED | **S10** team-workspace |
|
||||
| 12 | Onboarding · First Launch (§12.12 step 1) | COVERED | **S12** first-launch |
|
||||
| 13 | Onboarding · Who Are You (§12.12 step 2) | COVERED | **S13** who-are-you |
|
||||
| 14 | Onboarding · Tool Discovery (§12.12 step 3) | COVERED | **S14** tool-discovery |
|
||||
| 15 | Onboarding · Memory Import (§12.12 step 4) | COVERED | **S15** memory-import |
|
||||
| 16 | Onboarding · Memory Review (§12.12 step 5) | COVERED | **S16** memory-review |
|
||||
| 17 | Onboarding · Workspace Creation (§12.12 step 6) | COVERED | **S17** workspace-creation |
|
||||
| 18 | Agent Builder (§12.9 stepper) | COVERED | **S18** agent-builder |
|
||||
| 19 | Skill Builder (§12.6 stepper) | COVERED | **S19** skill-builder |
|
||||
| 20 | Automation Builder (§12.10 stepper) | COVERED | **S20** automation-builder |
|
||||
| 21 | Marketplace / Extend Waggle (§12.13) | COVERED | **S21** marketplace-extend |
|
||||
|
||||
**Note — Home Cockpit (§12.12 step 7 "Home Cockpit").** The 7th onboarding step is "land in Home
|
||||
Cockpit," which is S01 (not a separate screen). Correctly folded. ✔
|
||||
|
||||
**Screen-level sub-gaps (not whole-screen misses, but skipped requirements inside a covered screen):**
|
||||
|
||||
- **G1 — Workspace Desktop tab parity (S02).** PRD §12.2 (line 426 + 436) names **8 tabs**: Overview,
|
||||
Chat, Research/Notes, Artifacts, Memory, Tasks, Timeline, **Settings**. The S02 card's tab bar (line
|
||||
20) lists **7** and omits a **Settings** tab; the card later maps "Settings → existing component" (line
|
||||
86) but never lists Settings in the §12.2 tab enumeration it reproduces. Minor, but the per-workspace
|
||||
Settings tab (needed by Journey 19 "Archive workspace" → "opens workspace settings") should be an
|
||||
explicit S02 tab, not implied.
|
||||
- **G2 — Sessions as a first-class navigable object.** PRD §9.2 + §11 glossary list **Session** as a
|
||||
primary product object ("Should be navigable and related to memory/artifacts"). No gap card surfaces a
|
||||
Sessions list/navigation view; S02 collapses sessions into the **Timeline** tab + Chat. The session
|
||||
substrate is rich and unused at the screen level (`GET /api/workspaces/:id/sessions`,
|
||||
`/sessions/search`, `/sessions/:id/timeline`, `/sessions/:id/export` all EXIST per
|
||||
`_inventory/backend-routes.md:42–46`). Ctrl+K (S03) does federate session search, so sessions are
|
||||
*findable* but not *browsable as an object class*. PRD §13 Journey 3 ("user reviews… sessions") and the
|
||||
object hierarchy §9.2 imply a Sessions surface. **Decide:** explicit Sessions tab/sub-view in S02, or
|
||||
document that Timeline+Ctrl+K is the intended session UX and amend the §11 "navigable" claim.
|
||||
|
||||
---
|
||||
|
||||
## Table 2 — PRD §16 Endpoints (all 65) — addressed in `backend-api-delta.md`?
|
||||
|
||||
`backend-api-delta.md` deliberately lists **only NET-NEW + EXTEND** backend work (49 of 65) and
|
||||
**excludes the 16 EXISTS endpoints** (they need FE wiring only). For audit completeness, "addressed"
|
||||
below = **either** carried in the delta's master table **or** explicitly enumerated as EXISTS-and-excluded
|
||||
in the delta's de-dup note (lines 46–48) / counts cross-reference (line 372). Counts reconcile to the
|
||||
`_inventory/backend-routes.md` §16 table (16 EXISTS / 30 PARTIAL / 19 MISSING = 65).
|
||||
|
||||
| §16 group | PRD endpoint | In delta? | Disposition / where |
|
||||
|---|---|:--:|---|
|
||||
| 16.1 Home | `GET /api/home/briefing` | YES | NET-NEW `home.ts` (delta 1a) |
|
||||
| 16.1 | `POST /api/quick-capture` | YES | EXTEND → memory write (delta 1a) |
|
||||
| 16.1 | `GET /api/home/overnight` | YES | NET-NEW `home.ts` (delta 1a) |
|
||||
| 16.2 Workspaces | `GET /api/workspaces` | YES (EXISTS-excluded) | exists; FE wiring only (delta line 46) |
|
||||
| 16.2 | `POST /api/workspaces` | YES | EXTEND richer body (delta 2c) |
|
||||
| 16.2 | `GET /api/workspaces/:id` | YES (EXISTS-excluded) | exists; FE wiring only |
|
||||
| 16.2 | `PATCH /api/workspaces/:id` | YES (EXISTS-excluded) | exists (also PUT); FE wiring only |
|
||||
| 16.2 | `GET /api/workspaces/:id/state` | YES | EXTEND thin route (delta 1b) |
|
||||
| 16.2 | `GET /api/workspaces/:id/context` | YES (EXISTS-excluded) | exists; the Home/Workspace seed |
|
||||
| 16.2 | `GET /api/workspaces/:id/activity` | YES | EXTEND thin alias (delta 1b) |
|
||||
| 16.3 Command | `GET /api/command/search?q=` | YES | NET-NEW `command.ts` (delta 1c) |
|
||||
| 16.3 | `POST /api/command/execute` | YES | EXTEND over `/commands/execute` (delta 1c) |
|
||||
| 16.3 | `GET /api/command/recent` | YES | NET-NEW / client-derive (delta 1c) |
|
||||
| 16.3 | `GET /api/command/suggestions` | YES | NET-NEW (delta 1c) |
|
||||
| 16.4 Memory | `GET /api/memory` | YES | EXTEND alias (delta 2a) |
|
||||
| 16.4 | `GET /api/memory/:id` | YES | NET-NEW thin read (delta 2a) |
|
||||
| 16.4 | `POST /api/memory` | YES | EXTEND alias (delta 2a) |
|
||||
| 16.4 | `PATCH /api/memory/:id` | YES | EXTEND (PATCH+bare id) (delta 2a) |
|
||||
| 16.4 | `POST /api/memory/:id/archive` | YES | NET-NEW thin (delta 2a) |
|
||||
| 16.4 | `DELETE /api/memory/:id` | YES | EXTEND alias (delta 2a) |
|
||||
| 16.4 | `POST /api/memory/merge` | YES | NET-NEW (delta 2a) |
|
||||
| 16.4 | `GET /api/memory/graph` | YES (EXISTS-excluded) | exists (`knowledge.ts`); FE wiring only (delta line 47) |
|
||||
| 16.5 Harvest | `POST /api/harvest/preview` | YES | EXTEND (confidence+items) (delta 2a) |
|
||||
| 16.5 | `POST /api/harvest/commit` | YES | EXTEND (`selectedIds`) (delta 2a) |
|
||||
| 16.5 | `GET /api/harvest/sources` | YES (EXISTS-excluded) | exists; FE wiring only |
|
||||
| 16.5 | `POST /api/harvest/sources/:id/sync` | YES | NET-NEW thin (delta 2d) |
|
||||
| 16.6 Artifacts | `GET /api/artifacts` | YES | NET-NEW `artifacts.ts` (delta 2b) |
|
||||
| 16.6 | `POST /api/artifacts` | YES | NET-NEW (delta 2b) |
|
||||
| 16.6 | `GET /api/artifacts/:id` | YES | NET-NEW (delta 2b) |
|
||||
| 16.6 | `PATCH /api/artifacts/:id` | YES | NET-NEW (delta 2b) |
|
||||
| 16.6 | `DELETE /api/artifacts/:id` | YES | NET-NEW (delta 2b) |
|
||||
| 16.6 | `GET /api/artifacts/search-related?q=` | YES | NET-NEW (delta 2b) |
|
||||
| 16.7 Agents | `GET /api/agents` | YES | NET-NEW `agents.ts` (delta 3a) |
|
||||
| 16.7 | `POST /api/agents` | YES | NET-NEW (delta 3a) |
|
||||
| 16.7 | `GET /api/agents/:id` | YES | NET-NEW (delta 3a) |
|
||||
| 16.7 | `PATCH /api/agents/:id` | YES | NET-NEW (delta 3a) |
|
||||
| 16.7 | `POST /api/agents/:id/run` | YES | EXTEND → fleet/spawn (delta 3a) |
|
||||
| 16.7 | `POST /api/agents/:id/pause` | YES | EXTEND → fleet pause (delta 3a) |
|
||||
| 16.7 | `GET /api/agents/:id/traces` | YES | NET-NEW over `execution_traces` (delta 3a) |
|
||||
| 16.8 Skills | `GET /api/skills` | YES (EXISTS-excluded) | exists; FE wiring only |
|
||||
| 16.8 | `POST /api/skills` | YES (EXISTS-excluded) | exists (+ `/skills/create`); Builder target |
|
||||
| 16.8 | `PATCH /api/skills/:id` | YES | EXTEND (PATCH+id alias) (delta 3b) |
|
||||
| 16.8 | `POST /api/skills/:id/test` | YES | EXTEND (:id variant) (delta 3b) |
|
||||
| 16.8 | `POST /api/skills/:id/install` | YES | NET-NEW dispatcher (delta 3b) |
|
||||
| 16.9 Conn/MCP/Mkt | `GET /api/connectors` | YES | EXISTS + optional payload EXTEND (delta 4a) |
|
||||
| 16.9 | `POST /api/connectors/:id/connect` | YES | EXISTS + audit EXTEND (delta 4a) |
|
||||
| 16.9 | `POST /api/connectors/:id/sync` | YES | NET-NEW (delta 4a) |
|
||||
| 16.9 | `POST /api/connectors/:id/revoke` | YES | EXTEND alias → disconnect (delta 4a) |
|
||||
| 16.9 | `GET /api/mcps` | YES | NET-NEW `mcps.ts` (delta 4b) |
|
||||
| 16.9 | `POST /api/mcps/install` | YES | EXTEND via marketplace installer (delta 4b) |
|
||||
| 16.9 | `POST /api/mcps/:id/test` | YES | NET-NEW (delta 4b) |
|
||||
| 16.9 | `POST /api/mcps/:id/revoke` | YES | NET-NEW (delta 4b) |
|
||||
| 16.9 | `GET /api/marketplace` | YES | EXTEND bare-path alias (delta 4c) |
|
||||
| 16.9 | `POST /api/marketplace/install` | YES (EXISTS-excluded) | exists (PRO, SecurityGate); FE wiring |
|
||||
| 16.10 Automations | `GET /api/automations` | YES | EXTEND alias → cron (delta 3c) |
|
||||
| 16.10 | `POST /api/automations` | YES | EXTEND alias → cron (delta 3c) |
|
||||
| 16.10 | `PATCH /api/automations/:id` | YES | EXTEND alias (+ FE PUT/PATCH bug fix) (delta 3c) |
|
||||
| 16.10 | `POST /api/automations/:id/run` | YES | EXTEND alias → cron trigger (delta 3c) |
|
||||
| 16.10 | `POST /api/automations/:id/pause` | YES | NET-NEW thin / EXTEND (delta 3c) |
|
||||
| 16.10 | `GET /api/automations/:id/logs` | YES | EXTEND alias → cron history (delta 3c) |
|
||||
| 16.11 Team/RBAC | `GET /api/teams/:id` | YES (EXISTS-excluded) | exists; FE wiring only |
|
||||
| 16.11 | `POST /api/teams/:id/invite` | YES | EXTEND alias → `/members` (delta 5) |
|
||||
| 16.11 | `PATCH /api/teams/:id/members/:memberId` | YES | EXTEND (role-gate bug fix) (delta 5) |
|
||||
| 16.11 | `GET /api/teams/:id/audit` | YES | EXTEND alias → `/activity` (delta 5) |
|
||||
| 16.11 | `POST /api/share` | YES | NET-NEW (delta 5) |
|
||||
|
||||
**Verdict: 65/65 PRD §16 endpoints are addressed** — 49 with explicit build targets, 16 acknowledged as
|
||||
EXISTS-and-excluded (FE-wiring-only). **No §16 endpoint is silently dropped.** The delta additionally
|
||||
adds ~16 blueprint-implied endpoints beyond the §16 literal set (MCP start/stop/logs/permissions/custom,
|
||||
connector health/activity, automations/test, team governance, artifact-share, extend/audit) — over-, not
|
||||
under-, coverage.
|
||||
|
||||
**Audit caveats on Table 2 (skeptical reads — these are scope decisions hidden as "addressed"):**
|
||||
|
||||
- **C1 — `POST /api/connectors/:id/sync` is "phased to a stub" (delta 4a, line 214).** Marked NET-NEW but
|
||||
the MVP is explicitly only `healthCheck()` + a `lastSyncAt` stamp; "full data re-pull is a larger
|
||||
connector-SDK addition." So the headline §12.7 acceptance ("**whether data is flowing**") is met only
|
||||
cosmetically in v1. This is the load-bearing S07 gap and the delta admits it does not truly close it.
|
||||
- **C2 — `GET /api/mcps/:id/logs` deferred (delta 4b, line 238).** No log-capture infra exists; PRD §12.8
|
||||
lists "view logs" as a functional requirement and §16 implies logs visibility. Deferred to "a later
|
||||
phase." So MCP "auditable" (§12.8 acceptance) is partially unmet at the route level for v1.
|
||||
- **C3 — `POST /api/mcps/:id/test` open question unresolved (delta 4b, line 233).** "live spawn-and-
|
||||
handshake vs static manifest validation" is undecided. The endpoint is listed but its semantics are not.
|
||||
- **C4 — Boot-time `mcpRuntime` population (delta 4b, line 240).** This is flagged as "the foundational
|
||||
non-route work item that unblocks all of [MCP]" — but it is **not an endpoint and not phased into a
|
||||
sprint**. It is the single biggest hidden-effort item in the Extend layer and should be an explicit
|
||||
Phase-4 task, not a footnote.
|
||||
|
||||
---
|
||||
|
||||
## Table 3 — PRD §26 Definition of Done (all 11) — addressed by a phase/card?
|
||||
|
||||
**Headline finding (CRITICAL): no gap card or delta references the Definition of Done by name.** A
|
||||
grep for "Definition of Done" / "DoD" across all 22 cards + 3 deltas returns **0 matches**. The DoD is
|
||||
the PRD's release-acceptance contract; the analysis satisfies most items *implicitly* but ships **no
|
||||
DoD→phase/card traceability artifact**. The next planner must not assume DoD is closed just because the
|
||||
screens are covered. Per-item mapping below.
|
||||
|
||||
| # | DoD item (§26) | Status | Where addressed / GAP |
|
||||
|---|---|---|---|
|
||||
| 1 | Home Cockpit replaces blank-chat launch behavior | COVERED (implicit) | S01 builds Home Cockpit; but **no card/delta states the launch-default flip** (today launch = workspace/chat per `frontend.md`). The *behavioral replacement* (boot route → Home) is an **S00 AppShell routing change** that S00 does not explicitly own. **GAP-D1:** name the default-route change. |
|
||||
| 2 | Workspace Desktop is default runtime for workspace work | COVERED | S02 (`create-new` tabbed runtime); S00 routes to it. |
|
||||
| 3 | Ctrl+K can search/launch/create/run/navigate/extend | COVERED | S03 + S00 (global provider); `CommandResult.kind` enum covers all 6 verbs (S03 line 136). |
|
||||
| 4 | Memory Center exposes source/confidence/evidence/scope/edit/delete | COVERED (1 conditional dep) | S04 + S16; ConfidenceBadge/EvidenceChip/EvidencePanel in design-delta; **depends on M1 `memory_frames.metadata` migration** if confidence/scope become real filter axes (delta §M1). If M1 is skipped, "confidence/scope" is in-app-only — verify against §12.4 AC. |
|
||||
| 5 | Artifact Center supports outcome search + related objects | COVERED | S05 + `GET /api/artifacts/search-related` (delta 2b). |
|
||||
| 6 | Onboarding leads profile→tool-discovery→import→review→first workspace | COVERED | S12–S17 chain; S00/onboarding shell. |
|
||||
| 7 | Agents, skills, automations, connectors, MCPs, marketplace have coherent IA | COVERED | S06–S11, S18–S21 all map to the Work/Intelligence/Extend IA (S00 §IA). |
|
||||
| 8 | Team workspace supports shared intelligence + roles | COVERED (RBAC UI partial) | S10; **but RBAC UI is an open question** — `GET /api/teams/:id/governance` is "optional/NET-NEW" (delta 5) and PRD §17 role matrix has **no dedicated card** (see GAP-D2). |
|
||||
| 9 | Sensitive actions are approval-gated and audited | COVERED (cross-cutting, no owner card) | ApprovalModal in design-delta; S03/S08/S18/S19/S20 reference approval; `/extend/audit` (delta 4c). **GAP-D3:** the approval+audit *pattern* is cross-cutting but **owned by no single card** — risk of inconsistent per-screen implementation. |
|
||||
| 10 | All screens have required states (§14) | PARTIAL — **the weakest-traced DoD item** | design-delta builds EmptyState/ErrorState/Skeleton/StatusBadge (the *primitives*), but **no card carries a per-screen §14 state matrix**. State-keyword density is uneven across cards (S02, S18, S20, S21 are thin; S00/S12 are rich). §14.1 mandates 9 global states (Loading/Empty/Populated/Error/Offline/Syncing/Permission-denied/Partial/Approval) on *every* major screen. **GAP-D4:** no screen×state coverage grid exists. |
|
||||
| 11 | Claude Code can continue from PRD without product interpretation | COVERED (this artifact set is the evidence) | The 22 cards + 3 deltas + this check are the interpretation layer; this is met by the existence of the analysis itself, modulo the open questions below. |
|
||||
|
||||
---
|
||||
|
||||
## Concrete gaps to fix (prioritized)
|
||||
|
||||
**CRITICAL (close before the impl plan is "done"):**
|
||||
|
||||
1. **GAP-D4 — No screen × §14-state coverage matrix.** DoD #10 requires *every* major screen to
|
||||
implement the 9 global states (§14.1) plus its screen-specific states (§14.2–§14.7). The design-delta
|
||||
ships the state *primitives* but no artifact proves each of S01–S21 wires Loading/Empty/Error/Offline/
|
||||
Permission-denied/Approval. Cards S02, S18, S20, S21 are visibly thin on state enumeration. **Fix:**
|
||||
add a 21×9 state-coverage grid (per-screen) to the impl plan; it is the single most under-traced DoD
|
||||
item.
|
||||
2. **GAP-D3 — Approval-gating + audit is cross-cutting but owned by no card.** DoD #9 + PRD §17.3 +
|
||||
§18.1. ApprovalModal (design-delta #7) and `/extend/audit` (delta 4c) exist, but no card defines the
|
||||
canonical "which actions are sensitive, what the approval payload is, what gets audited" contract.
|
||||
Risk: each builder (S18/S19/S20) and S03/S08 re-implements approval differently. **Fix:** a dedicated
|
||||
cross-cutting "Approval & Audit" spec section (or an S00 sub-card) naming the gated-action taxonomy.
|
||||
3. **C4 — MCP boot-time runtime population is a hidden foundational task, not a sprint item.** Without it
|
||||
none of the MCP routes function. **Fix:** elevate `mcpRuntime` population (`local/index.ts:911`) to an
|
||||
explicit Phase-4 task with its own estimate.
|
||||
|
||||
**HIGH:**
|
||||
|
||||
4. **GAP-D1 — The blank-chat→Home launch-default flip (DoD #1) is unowned.** S01 builds the screen; no
|
||||
card changes the boot route. **Fix:** assign the default-route change to S00 explicitly.
|
||||
5. **GAP-D2 — PRD §17 RBAC role matrix (Owner/Admin/Contributor/Viewer × 6 capabilities) has no
|
||||
dedicated card.** S10 covers Team Workspace and mentions RBAC, but the role×permission enforcement UI
|
||||
+ the `GET /api/teams/:id/governance` route are "optional." DoD #8 ("supports… roles") and §17.2 are
|
||||
only partially traced. PRD §20.3 lists `RBAC/Audit components` under Create. **Fix:** confirm S10 owns
|
||||
the §17.2 matrix UI, or add an RBAC/Audit card.
|
||||
6. **G2 — Sessions has no first-class screen** despite being a §9.2/§11 primary object. Collapsed into
|
||||
S02 Timeline + Ctrl+K search. **Fix:** either add an explicit Sessions sub-view to S02 or document that
|
||||
Timeline+Ctrl+K is the intended UX and soften the §11 "navigable" claim.
|
||||
7. **C1 — Connector `/sync` MVP is a cosmetic stub** that does not meet §12.7's "whether data is
|
||||
flowing" acceptance. **Fix:** flag in the plan that S07's headline AC is only partially met in v1;
|
||||
schedule the real connector-SDK data-pull.
|
||||
|
||||
**MEDIUM:**
|
||||
|
||||
8. **G1 — S02 omits the §12.2 Settings tab** from its tab enumeration (7 vs PRD's 8). Needed for
|
||||
Journey 19 (Archive workspace). **Fix:** add Settings to the S02 tab list.
|
||||
9. **C2 — MCP `/:id/logs` deferred** vs §12.8 "view logs" functional requirement. **Fix:** confirm
|
||||
v1-acceptable, or schedule the stderr ring-buffer.
|
||||
10. **C3 — MCP `/:id/test` semantics undecided** (live handshake vs static validation). **Fix:** resolve
|
||||
the open question before S08 build.
|
||||
11. **Journeys §13 (20 journeys) are not cross-referenced to cards.** The analysis is screen-oriented;
|
||||
no artifact maps the 20 user journeys (esp. J15 agent-approval, J16 automation-failure→Home-attention,
|
||||
J19 archive, J20 delete-memory) to the screens that must implement each step. Most are implicitly
|
||||
covered, but **J16** (overnight failure surfacing in Home "attention required") spans S01+S11+S20 and
|
||||
is not explicitly owned end-to-end. **Fix:** a journey→screen trace table.
|
||||
|
||||
**LOW / acknowledged-by-design (not true gaps, listed so they are not re-litigated):**
|
||||
|
||||
12. **Models / External-tools Extend nodes (§10.4)** have no standalone Hub card — folded into S21
|
||||
(Models = marketplace category federated from Settings→Models; external_tool = `ExtensionType`).
|
||||
S21 line 132 raises the `ExtensionType` reconciliation open question (agent vs external_tool). This is
|
||||
a deliberate fold, not a miss — but the `ExtensionType` union must be resolved (shared-types-delta).
|
||||
13. **§16 EXISTS endpoints (16) excluded from the delta** — correct by design (FE-wiring-only), and
|
||||
acknowledged in the delta de-dup note. Not a gap.
|
||||
14. **Schema migrations** — at most M1 ships; M2 (install_audit CHECK) is a real latent bug the delta
|
||||
caught (good); M3 (agents table) correctly deferred. No gap.
|
||||
|
||||
---
|
||||
|
||||
## Bottom line
|
||||
|
||||
- **Screens:** 21/21 numbered screens + AppShell COVERED. 2 intra-screen sub-gaps (S02 Settings tab;
|
||||
Sessions-as-object).
|
||||
- **§16 endpoints:** 65/65 addressed (49 build targets + 16 EXISTS-excluded). Coverage is complete; 4
|
||||
scope caveats (connector-sync stub, MCP logs/test/boot) are admitted-but-soft.
|
||||
- **§26 DoD:** 11/11 items map to *some* artifact, but **DoD is never named** and **2 items are only
|
||||
partially traced** (#10 states matrix, #9 approval/audit owner) plus #1 (launch-flip) and #8 (RBAC
|
||||
matrix) have unowned slices. **The biggest completeness risk is not a missing screen — it is the
|
||||
absence of two cross-cutting traceability grids (screen×state, journey×screen) and an explicit
|
||||
approval/audit + RBAC owner.**
|
||||
173
docs/ux-refactor/deltas/design-system-delta.md
Normal file
173
docs/ux-refactor/deltas/design-system-delta.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Design System Delta — Waggle OS UX Refactor
|
||||
|
||||
**Scope:** PRD §19 (Design System Requirements) + Blueprint "Design System Direction"
|
||||
mapped against the live Hive DS in `apps/web/src`.
|
||||
**Execution model (locked):** in-place incremental refactor — reuse existing shadcn/Hive
|
||||
primitives in `apps/web/src/components/ui/*`; build NEW DS components only where PRD §19.1
|
||||
names a concept with no existing reusable primitive.
|
||||
|
||||
**Grounding sources (read):**
|
||||
- Tokens: `apps/web/src/index.css` (canonical palette + light theme), `apps/web/src/waggle-theme.css` (aliases), `apps/web/tailwind.config.ts` (token→utility wiring).
|
||||
- Primitive inventory: `apps/web/src/components/ui/*` (49 files).
|
||||
- PRD §19.1/§19.2/§19.3 — `docs/.../Waggle_OS_UX_Refactor_PRD.md` lines 1222-1261.
|
||||
- Blueprint "Design System Direction" — `_blueprint_extracted.txt` lines 479-492.
|
||||
- Ad-hoc precedents: `MemoryApp.tsx` (provenance chip), `TimelineApp.tsx` (timeline), `OnboardingWizard.tsx` (ad-hoc steps), `ApprovalsApp.tsx` (approvals).
|
||||
|
||||
---
|
||||
|
||||
## (a) PRD §19.1 Component List — EXISTS vs BUILD-NEW
|
||||
|
||||
PRD §19.1 (lines 1226-1242) lists 19 core components. Blueprint adds a few named variants
|
||||
(ContextCard, MemoryCard, ArtifactRow, AgentCard, SkillCard, ConnectorCard, MCPRow,
|
||||
AutomationRunRow, EvidencePanel, ApprovalModal — `_blueprint_extracted.txt` lines 487-488).
|
||||
Mapping below merges both lists.
|
||||
|
||||
| PRD §19.1 component | Status | Existing file / build location | Notes |
|
||||
|---|---|---|---|
|
||||
| **AppShell** | BUILD-NEW (composes EXISTS) | new `components/os/AppShell.tsx`; compose `ui/sidebar.tsx` + `ui/scroll-area.tsx` | No single AppShell today; current shell is `os/Desktop.tsx` (windowing). PRD §20.3 lists AppShell as Create. Reuse `ui/sidebar.tsx` for left nav. |
|
||||
| **Primary navigation** | EXISTS (extend) | `ui/sidebar.tsx`, `ui/navigation-menu.tsx` | Full sidebar primitive present (collapsible, rail, groups). Re-label to Work/Intelligence/Extend/Team IA (PRD §3.2). |
|
||||
| **Workspace switcher** | BUILD-NEW (compose EXISTS) | new; compose `ui/command.tsx` + `ui/dropdown-menu.tsx` | Pattern exists in `sidebar.tsx` docs; assemble against workspace list. |
|
||||
| **Command Center modal** | EXISTS (primitive) → BUILD-NEW (Ctrl+K shell) | primitive `ui/command.tsx` (cmdk: CommandDialog/Input/Group/Item); new `CommandCenter.tsx` | `ui/command.tsx` is full cmdk wrapper. PRD §20.3 + Blueprint require a global Ctrl+K provider/overlay on top — build the provider, reuse the primitive. Existing `overlays/GlobalSearch.tsx` is a prior, narrower attempt to fold in. |
|
||||
| **Card: workspace** (ContextCard/MemoryCard/AgentCard/SkillCard/ConnectorCard) | EXISTS (base) → BUILD-NEW (typed variants) | base `ui/card.tsx`; new per-object cards under `components/os/cards/` | `ui/card.tsx` is the generic shadcn card (Header/Title/Content/Footer). Build typed object cards on top (each renders StatusBadge + actions). `.direction-d-card` / `.waggle-card-lift` utilities (`waggle-theme.css`) give the hover/lift treatment. |
|
||||
| **ArtifactRow / MCPRow / AutomationRunRow** (table rows) | EXISTS (base) | `ui/table.tsx` | Blueprint density rule (line 491): cards for Home/Workspace, **tables** for Memory/Artifacts/Agents/Automations. Use `ui/table.tsx`; build row cell formatters only. |
|
||||
| **Status badges** | EXISTS (base) → BUILD-NEW (StatusBadge variant) | base `ui/badge.tsx`; new `components/os/StatusBadge.tsx` | `ui/badge.tsx` has only default/secondary/destructive/outline — **no semantic status variants** and no icon/dot. Build `StatusBadge` mapping the state enums (PRD §14: running/paused/failed/healthy/...) to the color semantics in (b), with a **non-color dot + text label** (a11y §19.3). |
|
||||
| **Confidence badges** | **BUILD-NEW** | new `components/os/ConfidenceBadge.tsx` | No confidence component exists. `MemoryApp.tsx` has no confidence rendering today (grep: only `provenance`). Renders 0-100 (PRD §15.4) as tiered band (high/med/low) with numeric + label; band color from semantics in (b). |
|
||||
| **Source / evidence chips** (EvidenceChip + EvidencePanel) | **BUILD-NEW** (chip has ad-hoc precedent) | new `components/os/EvidenceChip.tsx` + `components/os/EvidencePanel.tsx` | Closest precedent: the inline provenance pill in `MemoryApp.tsx` (lines ~202-208, `readFrameProvenanceTool`) — promote to a reusable `EvidenceChip`. `EvidencePanel` (Blueprint line 488) is the grouped detail (source + sourceUrl/path + snippet) inside DetailDrawer. |
|
||||
| **Timeline** | **BUILD-NEW** (logic exists) | new `components/os/Timeline.tsx`; reuse `lib/timeline-events.ts` | `TimelineApp.tsx` + `lib/timeline-events.ts` (`iconForEvent`/`colorForEvent`/`describeEvent`) hold the rendering logic, but it is app-specific, not a reusable DS component. Extract the grouped-by-day list into `Timeline`. |
|
||||
| **Activity feed** | **BUILD-NEW** | new `components/os/ActivityFeed.tsx` | No reusable feed today. Distinct from Timeline: feed = reverse-chron event stream for Workspace right-panel "last activity" (PRD §12.2) + Home overnight summary (§12.1). Can share the row renderer with Timeline. |
|
||||
| **Detail drawer** (DetailDrawer) | EXISTS (two bases) → BUILD-NEW (typed wrapper) | bases `ui/sheet.tsx` (right-side, Radix Dialog) and `ui/drawer.tsx` (vaul, bottom); new `components/os/DetailDrawer.tsx` | **Recommend `ui/sheet.tsx` side="right"** as the base — matches Blueprint "optional right context rail" (line 483) and is the standard detail surface for Memory/Artifact/Agent. `ui/drawer.tsx` (vaul) is bottom-sheet, keep for mobile/secondary. Build one `DetailDrawer` wrapper that takes header + EvidencePanel + actions. |
|
||||
| **Builder stepper** (BuilderStepper) | **BUILD-NEW** | new `components/ui/stepper.tsx` (or `components/os/BuilderStepper.tsx`) | **No Stepper primitive exists.** `OnboardingWizard.tsx` hand-rolls step state (`useState(state.step)` + `goToStep`) with no shared progress UI. PRD §19.2: "Create flows use stepper patterns" — needed by Skill/Agent/Automation builders (PRD §12.6/§12.9/§12.10) + Onboarding. Build once, retrofit onboarding. |
|
||||
| **Approval prompt** (ApprovalModal) | EXISTS (base + app) → BUILD-NEW (typed modal) | base `ui/alert-dialog.tsx`; existing app `os/apps/ApprovalsApp.tsx` + `overlays/SpawnAgentDialog.tsx`; new `components/os/ApprovalModal.tsx` | `ui/alert-dialog.tsx` (Radix) is the confirm base; `ApprovalsApp.tsx` already implements an approvals inbox surface. Build a shared `ApprovalModal` (declares: actor, requested action, scope, risk badge, approve/deny/modify) for the permission-gated flows (PRD §12.3 command exec, §12.9 agent elevation, §17.3 elevated actions). |
|
||||
| **Empty state** | **BUILD-NEW** | new `components/os/EmptyState.tsx` | No reusable empty-state component (grep found none). Required on every major screen (PRD §14.1, §22.2). Build icon + headline + body + primary CTA. |
|
||||
| **Error state** | **BUILD-NEW** (base exists) | base `ui/alert.tsx`; new `components/os/ErrorState.tsx` | `ui/alert.tsx` (default/destructive) covers inline alerts; build a full-surface `ErrorState` (illustration + retry) for screen-level errors (PRD §14.1). |
|
||||
| **Skeleton loader** | EXISTS | `ui/skeleton.tsx` | Present. Compose per-surface skeletons (card grid / table rows). |
|
||||
| **Table/list/grid view toggle** | **BUILD-NEW** (base exists) | base `ui/toggle-group.tsx`; new `components/os/ViewToggle.tsx` | `ui/toggle-group.tsx` (Radix, single/multiple) is the base. No `ViewToggle` exists. Build a 3-state (table/list/grid) toggle for Memory/Artifact/Agent surfaces (PRD §19.1 last item, Blueprint density rule). |
|
||||
|
||||
### Supporting primitives confirmed present (reuse, do not rebuild)
|
||||
`ui/tabs.tsx` (workspace tabs PRD §12.2), `ui/dialog.tsx`, `ui/popover.tsx`, `ui/tooltip.tsx` + `ui/hint-tooltip.tsx`, `ui/progress.tsx`, `ui/avatar.tsx` (team avatar stack), `ui/select.tsx`/`ui/checkbox.tsx`/`ui/radio-group.tsx`/`ui/switch.tsx`/`ui/slider.tsx` (builder form fields), `ui/form.tsx` (+ react-hook-form), `ui/chart.tsx` (dashboards/Home metrics), `ui/resizable.tsx` (workspace panels), `ui/scroll-area.tsx`, `ui/separator.tsx`, `ui/breadcrumb.tsx`, `ui/sonner.tsx`/`ui/toast.tsx`/`ui/toaster.tsx` (notifications), `ui/dropdown-menu.tsx`/`ui/context-menu.tsx`, `ui/collapsible.tsx`/`ui/accordion.tsx`.
|
||||
|
||||
### Summary counts
|
||||
- **EXISTS (reuse as-is):** Primary nav (sidebar), Skeleton, Tabs, plus the full supporting-primitive set above.
|
||||
- **EXISTS-as-base → BUILD typed wrapper:** Command Center, object Cards, Status badge, Detail drawer, Approval modal, Error state, View toggle (7).
|
||||
- **BUILD-NEW (no reusable base):** ConfidenceBadge, EvidenceChip, EvidencePanel, BuilderStepper, ActivityFeed, Timeline (DS extraction), EmptyState, AppShell, ViewToggle base-toggle exists but component new (≈8 net-new components).
|
||||
|
||||
---
|
||||
|
||||
## (b) Color Semantics → Hive DS Token Mapping
|
||||
|
||||
PRD/Blueprint semantic palette (Blueprint lines 485-486): **blue = command/work, purple =
|
||||
intelligence, green = healthy/complete, orange = attention/automation, red = risk/failure.**
|
||||
|
||||
The Hive DS already ships these as CSS vars in `index.css` and exposes them as Tailwind
|
||||
utilities via `tailwind.config.ts` (`status.*`, `honey.*`, `hive.*`). **No new base tokens
|
||||
are required** — only a semantic-alias layer so components reference intent, not raw color.
|
||||
|
||||
| UX semantic | Meaning | Existing Hive token (dark, `index.css`) | Tailwind utility | Light-theme value (`index.css` `[data-theme="light"]`) |
|
||||
|---|---|---|---|---|
|
||||
| **Blue = command / work** | running, info, in-progress, command surfaces | `--status-info: #60a5fa` | `text-status-info` / `bg-status-info` | `#1d4ed8` (AA on cream, ratio 6.30) |
|
||||
| **Purple = intelligence** | agents, AI/skills, memory-AI | `--status-ai: #a78bfa` (= DS accent `--accent: 270 60% 68%`) | `text-status-ai` / `bg-status-ai`; `accent` for AI brand | `#6d28d9` (ratio 6.68) |
|
||||
| **Green = healthy / complete** | success, connected, completed, high confidence | `--status-healthy: #34d399` | `text-status-healthy` / `bg-status-healthy` | `#047857` (ratio 5.16) |
|
||||
| **Orange = attention / automation** | warning, attention-required, automation, **medium confidence** | `--status-warning: #fbbf24` (NOT honey-brand) | `text-status-warning` / `bg-status-warning` | `#b45309` (ratio 4.72) |
|
||||
| **Red = risk / failure** | error, failed, high-risk, revoked, **low confidence** | `--status-error: #f87171` (= shadcn `--destructive: 0 72% 63%`) | `text-status-error` / `bg-status-error` / `destructive` | `#b91c1c` (ratio 6.09) |
|
||||
|
||||
**Critical disambiguation — orange ≠ brand honey.** The Hive **brand/primary is honey gold**
|
||||
(`--primary: 40 100% 45%` → `--honey-500: #e5a000`), used for primary CTAs, focus rings,
|
||||
selection, and brand accents (`--ring`, `.glow-primary`, `--shadow-honey`). The UX "orange =
|
||||
attention/automation" semantic must map to **`--status-warning` (#fbbf24)**, a distinct amber,
|
||||
NOT to honey/primary. Keep "attention" and "brand action" visually separable:
|
||||
- Brand / primary action → `bg-primary` / `honey-*`.
|
||||
- Attention / automation status → `bg-status-warning` / `text-status-warning`.
|
||||
|
||||
**Confidence band mapping (ConfidenceBadge, PRD §15.4 `confidence: 0-100`):**
|
||||
- high (≥ ~70) → green `status-healthy`
|
||||
- medium (~40-69) → orange `status-warning`
|
||||
- low (< ~40) → red `status-error`
|
||||
(Thresholds are DS defaults; finalize against the memory scoring scale in `packages/hive-mind-core/src/mind/scoring`.)
|
||||
|
||||
**Implementation note — add a semantic alias layer.** Today components would have to reach
|
||||
for `status-info`/`status-ai` directly. Add intent aliases in `waggle-theme.css` (`:root`
|
||||
already holds `--success/--warning/--error` at lines 44-46) so the new layer reads:
|
||||
```
|
||||
--sem-work: var(--status-info); /* blue */
|
||||
--sem-intelligence:var(--status-ai); /* purple */
|
||||
--sem-healthy: var(--status-healthy); /* green */
|
||||
--sem-attention: var(--status-warning);/* orange */
|
||||
--sem-risk: var(--status-error); /* red */
|
||||
```
|
||||
`StatusBadge`/`ConfidenceBadge`/cards reference `--sem-*` so the mapping lives in one place
|
||||
and inherits both dark and light themes automatically.
|
||||
|
||||
---
|
||||
|
||||
## (c) Dark-default + Light-variant Note
|
||||
|
||||
- **Dark is the default** (Blueprint line 484: "Dark default for desktop agent feel").
|
||||
`index.css :root` IS the dark theme (background `222 20% 4%`); no `data-theme` attr needed.
|
||||
- **Light variant exists and is complete** — `:root[data-theme="light"]` (index.css lines
|
||||
140-221) overrides background, hive scale (inverted), honey (contrast-adjusted), **and all
|
||||
`--status-*` + `--kg-*` tokens darkened for WCAG AA on the cream surface** (ratios documented
|
||||
in source: healthy 5.16, warning 4.72, error 6.09, info 6.30, ai 6.68). Light mode is
|
||||
explicitly intended for "data-heavy Memory/Artifact tables" (Blueprint line 484).
|
||||
- **Consequence for new components:** because the semantic mapping in (b) references
|
||||
`--status-*` (which the light block already overrides), every new component
|
||||
(StatusBadge, ConfidenceBadge, EvidenceChip, etc.) inherits AA-correct light colors **for
|
||||
free** as long as it uses tokens — never hardcode hex. This matches the CLAUDE.md §10
|
||||
closed item "CR-2 hive-950 → semantic tokens" (do not reintroduce raw `hive-950` refs).
|
||||
- **Theme switch mechanism:** toggling `data-theme="light"` on `:root` (the desktop wallpaper
|
||||
overlay + honeycomb-bg already branch on it, index.css lines 269/277). New surfaces must not
|
||||
assume a fixed background.
|
||||
|
||||
---
|
||||
|
||||
## (d) Accessibility Requirements (PRD §19.3 + Blueprint line 489-490)
|
||||
|
||||
PRD §19.3 (lines 1254-1261) + Blueprint "Keyboard-first... no color-only status, text labels
|
||||
for all badges." Per-component obligations for the new/extended DS components:
|
||||
|
||||
1. **Full keyboard support.** Ctrl+K (`CommandCenter`) opens from anywhere via global key
|
||||
handler; builders, drawers, modals are fully tab-navigable. cmdk (`ui/command.tsx`) and
|
||||
Radix bases (`alert-dialog`, `sheet`, `dialog`, `toggle-group`) provide focus trap +
|
||||
arrow-key nav out of the box — preserve, don't override.
|
||||
2. **Visible focus states.** Use the DS focus ring (`--shadow-focus` / `--ring` = honey).
|
||||
shadcn primitives already render `focus:ring-2 focus:ring-ring`; new wrappers must keep it.
|
||||
3. **ARIA labels for command palette + builders.** `CommandCenter` needs `role`/`aria-label`
|
||||
on the dialog + labelled groups; `BuilderStepper` needs `aria-current="step"` on the active
|
||||
step and accessible step names (extend from `OnboardingWizard.tsx` `STEP_NAMES`).
|
||||
4. **Sufficient contrast for dark theme.** Dark `--status-*` are bright on `#08-11` surfaces;
|
||||
light variants are pre-darkened to ≥4.5:1 (documented in index.css). Do not place
|
||||
`status-warning`/`status-info` as small text on light surfaces without the light token.
|
||||
5. **Non-color status indicators (CRITICAL).** `StatusBadge` and `ConfidenceBadge` MUST pair
|
||||
color with a **text label AND/OR a shape/icon** (dot, icon glyph). PRD §19.3 + Blueprint
|
||||
"no color-only status" + "text labels for all badges." This is the single biggest gap vs
|
||||
the current `ui/badge.tsx` (color-only). Confidence must show the number/label, not just a
|
||||
colored band.
|
||||
6. **Screen-reader-friendly tables/lists.** Memory/Artifact/Agent/Automation tables
|
||||
(`ui/table.tsx`) need proper `<th scope>`, caption, and row `aria-label`; `ViewToggle`
|
||||
needs labelled options ("table view"/"grid view"). `Timeline`/`ActivityFeed` use an ordered
|
||||
list semantic with per-item timestamps in accessible text.
|
||||
7. **Approval flows announce intent.** `ApprovalModal` must expose the requested action, scope,
|
||||
and risk level as text (not icon-only) so denial/approval is an informed, SR-readable
|
||||
decision (ties to PRD §17.3 elevated-action approval).
|
||||
|
||||
---
|
||||
|
||||
## Net build list (for the impl plan)
|
||||
|
||||
**New DS components to author** (under `components/ui/` for generic, `components/os/` for product-typed):
|
||||
1. `StatusBadge` (extend `badge.tsx` with semantic variants + non-color indicator)
|
||||
2. `ConfidenceBadge`
|
||||
3. `EvidenceChip` (promote from `MemoryApp.tsx` provenance pill)
|
||||
4. `EvidencePanel`
|
||||
5. `BuilderStepper` / `stepper.tsx`
|
||||
6. `DetailDrawer` (wrap `sheet.tsx` right-side)
|
||||
7. `ApprovalModal` (wrap `alert-dialog.tsx`)
|
||||
8. `ActivityFeed`
|
||||
9. `Timeline` (extract from `TimelineApp.tsx` + `lib/timeline-events.ts`)
|
||||
10. `EmptyState`
|
||||
11. `ErrorState` (wrap `alert.tsx`)
|
||||
12. `ViewToggle` (wrap `toggle-group.tsx`)
|
||||
13. `AppShell` + `WorkspaceSwitcher` + `CommandCenter` (compose existing sidebar/command primitives)
|
||||
14. Object cards: `WorkspaceCard`/`MemoryCard`/`ArtifactRow`/`AgentCard`/`SkillCard`/`ConnectorCard`/`MCPRow`/`AutomationRunRow`
|
||||
|
||||
**Token work:** add `--sem-*` alias layer in `waggle-theme.css` (no new base palette tokens).
|
||||
All bases for the above already exist in `ui/*`; nothing requires a new dependency.
|
||||
701
docs/ux-refactor/deltas/open-questions.md
Normal file
701
docs/ux-refactor/deltas/open-questions.md
Normal file
@@ -0,0 +1,701 @@
|
||||
# Open Questions — UX Refactor (Founder Ratification)
|
||||
|
||||
> Source: PRD §23 (`docs/Waggle_OS_UX_Refactor_Master_Handoff_Package/Waggle_OS_UX_Refactor_PRD.md:1414-1424`)
|
||||
> + the §9 "Open questions" sections of all 22 gap cards (`docs/ux-refactor/gap-cards/S00..S21`).
|
||||
> Every recommendation is kept consistent with the **locked direction**: in-place incremental refactor
|
||||
> of `apps/web` + targeted backend extensions, **full-stack** (net-new/extended APIs where PRD §16 has no
|
||||
> route yet), **local-first** default. Mockups are directional (PRD §24); PRD acceptance criteria win.
|
||||
>
|
||||
> **How to use:** each question has (a) why it matters, (b) options + tradeoffs, (c) a RECOMMENDED answer
|
||||
> for founder ratification, (d) the phase it blocks if unresolved. Questions are grouped: **§A** = the 8
|
||||
> PRD §23 questions; **§B** = cross-cutting decisions surfaced by the gap cards that block ≥2 screens;
|
||||
> **§C** = screen-local questions that block a single screen. Critical (Phase 1–2 blocking) items are
|
||||
> flagged **[BLOCKS P1]** / **[BLOCKS P2]**.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Founder Ratifications — 2026-06-09
|
||||
|
||||
The **spine (Phase 0/1) blockers are RATIFIED as recommended** (founder, 2026-06-09). Phase 0 is
|
||||
unblocked; these are now locked decisions alongside the execution-model + full-stack scope locks:
|
||||
|
||||
- **B1** Shell topology → in-place dock reframe; keep windowed `AppId` nav; group the dock into
|
||||
Work / Intelligence / Extend / Team zones. **No react-router.**
|
||||
- **A1** Workspace Desktop → fixed widget layout v1.
|
||||
- **A2** Home Cockpit → personal-only v1 (team strip later, behind RBAC).
|
||||
- **B4** `/api/*` → alias PRD vocabulary onto existing routes (command / automations / connector-revoke); do not rename.
|
||||
- **B8** Identity → onboarding writes profile **and** seeds the `identity` table.
|
||||
|
||||
## ✅ Founder Ratifications — Phase 2 gate (2026-06-09 S2)
|
||||
|
||||
The **Phase-2 blockers are RATIFIED as recommended** (founder, 2026-06-09), except **C33** which is
|
||||
**held for discussion** (see note below). Locked Phase-2 decisions:
|
||||
|
||||
- **A6** Artifact storage → per-workspace `artifacts.json` index over the existing StorageProvider;
|
||||
artifact = explicit produced output (not every ingested input). No `.mind` migration.
|
||||
- **A8** Memory retention → soft-status in `metadata` (Archive = reversible; Deprecate = existing
|
||||
`importance`); **Delete = hard delete behind a scope-and-consequence confirmation** (PRD J20).
|
||||
≤1 additive migration.
|
||||
- **B2** Confidence → cheap heuristic at preview (source-trust × adapter-type × dedup), persisted in
|
||||
`metadata` only if it becomes a queryable filter; LLM scoring reserved for the standing J08 queue.
|
||||
- **B6** `MemoryKind` → PRD §15.2 canonical in `@waggle/shared`; pure harvest + display-category mapping
|
||||
helpers. Drop FE `event`/`insight` drift.
|
||||
- **A3** Memory graph tab → **ship in v1** (substrate already renders).
|
||||
|
||||
- **C33** Import↔Review commit split → **RESOLVED to the middle path** (founder, 2026-06-09 S2, after
|
||||
discussion). **Commit-as-unreviewed, non-blocking review:** onboarding Import commits immediately (memory
|
||||
feels alive on first run), but frames land with `status:'unreviewed'` + the B2 confidence score; Review is
|
||||
a **non-blocking** curation surface (Memory Center "needs review" filter + the standing J08 queue), NOT a
|
||||
blocking onboarding step. Reads PRD "nothing imports without review/approval" (646/1207) as *nothing is
|
||||
trusted/surfaced until reviewed*, not *nothing is written*. Rationale: importing one's own memories is
|
||||
additive + reversible (A8 archive/delete), so a blocking first-run gate would be friction in the wrong
|
||||
place (founder principle: friction reserved for irreversible/destructive actions). Reuses A8 soft-status
|
||||
+ B2 confidence — no extra migration. Supersedes the original §C C33 "blocking split" recommendation.
|
||||
|
||||
## ✅ Founder Ratifications — Phase 3 gate (2026-06-10)
|
||||
|
||||
The **Phase-3 (Intelligence) items are RATIFIED as recommended** (founder, 2026-06-10). Locked:
|
||||
|
||||
- **B3** Agent entity → real Agent object in `{dataDir}/agents.json` referencing `personaId`; persona =
|
||||
behavioral template field. `successRate`/`lastRun` derived at read from `execution_traces`. No `.mind`
|
||||
migration (M3 not shipped).
|
||||
- **C24** Automation triggers → schedule-only v1 (cron cadence); Event trigger deferred (no event→automation
|
||||
dispatch substrate).
|
||||
- **C26** Builder test-run → NET-NEW no-persist dry-run route (`POST /api/automations/test`); do NOT reuse
|
||||
`cron/:id/trigger` (executes + auto-enables).
|
||||
- **C13** Skill Builder publishes create-to-local (`POST /api/skills/create`); marketplace publish lives in S06/S21.
|
||||
- **C14** Skill inputs/outputs → body markdown v1; no `SkillFrontmatter` extension.
|
||||
- **C22** Agent Center tabs = All/Personal/Workspace/Team/Autonomous/Archive; Templates = side affordance.
|
||||
- **C23** Agent `/run` → one-shot fleet-spawn into a chosen workspace (picker if multiple `workspaceIds`);
|
||||
persistent always-running agents deferred.
|
||||
- **C25** Automation condition step → advisory `jobConfig.condition` string, no evaluation engine v1.
|
||||
- **C27** Analytics tiles → keep success-rate (from `cron_execution_history`); drop "hours saved" or label
|
||||
it an explicit heuristic estimate.
|
||||
- **C36** Skill scope vocabulary → PRD `organization` (align §15.2 `Scope` union).
|
||||
- **C37** Skill test-run fidelity → preview-only (injected-prompt + parsed metadata) v1; live LLM dry-run deferred.
|
||||
|
||||
## ✅ Founder Ratifications — Phase 4 gate (2026-06-10)
|
||||
|
||||
The **Phase-4 (Extend) items are RATIFIED as recommended** (founder, 2026-06-10). Locked:
|
||||
|
||||
- **A4** Real-where-substrate-exists, catalog-for-the-rest: connectors connect + health-probe +
|
||||
`lastSyncAt` stamp (background data re-pull deferred); MCPs install/start/stop/test via the existing
|
||||
marketplace installer + stdio runtime; static catalog renders honest "available / not installed"
|
||||
states — never fake entries (PRD §22.2).
|
||||
- **A5** Marketplace → federate-at-read over the six local domains; no `marketplace.db` migration;
|
||||
remote registry / public marketplace deferred (PRD §4.4 + §22).
|
||||
- **B5** Tier vocabulary → document the mapping; all new gates route through `@waggle/shared tiers.ts`
|
||||
(`TierCapabilities`); MCP Hub + Marketplace install gated **PRO+**.
|
||||
- **B7** `ExtensionType` → `skill | agent | connector | mcp | model | template` (drop `external_tool`;
|
||||
external tools surface via connectors/MCPs). Defined once in `@waggle/shared`.
|
||||
- **C15 / M2** install-audit `critical` CHECK → ship the additive migration (live sighting:
|
||||
`marketplace.ts:228` writes `critical`, silently rejected by the DDL CHECK today).
|
||||
- **C16** Connector "sync now" v1 = re-probe health + stamp `lastSyncAt`.
|
||||
- **C17** `revoke` purges OAuth tokens + writes the stronger audit entry (PRD §17.3); `disconnect`
|
||||
stays the lighter alias.
|
||||
- **C18** One shared `GET /api/extend/audit?type=` serving connectors + MCPs + marketplace.
|
||||
- **C19** MCP scope = single-`workspaceId` config v1 (matches stdio runtime); N:N deferred.
|
||||
- **C20** "Remote Registry" tab deferred (runtime is stdio-only); v1 points at the static catalog.
|
||||
- **C21** MCP `test` = live spawn-and-`isHealthy()`/`tools/list` round-trip where cheap; static
|
||||
manifest validation fallback.
|
||||
- Foundational task (coverage-check C4): populate `mcpRuntime` at boot from persisted config
|
||||
(`local/index.ts` registers none today) — explicit Phase-4 work item gating all MCP routes.
|
||||
|
||||
---
|
||||
|
||||
Remaining pending: **A7** (RBAC — ratify before S10/Phase 5) + Phase-5/6 screen-local items.
|
||||
|
||||
## §A — PRD §23 Open Questions (the canonical 8)
|
||||
|
||||
### A1. Widget customization in Workspace Desktop — fixed layout or true customization in v1?
|
||||
*(PRD §23 Q1, line 1416; gap card S02 §9 Q1.)*
|
||||
|
||||
- **(a) Why it matters:** Determines whether S02 reuses the maximized `AppWindow` + fixed widget layout
|
||||
(cheap, in-place) or builds a draggable/resizable grid (parallel layout system, large blast radius).
|
||||
PRD §12.2 already says "configurable widgets in *later* phase; fixed default layout in initial release".
|
||||
- **(b) Options:**
|
||||
1. *Fixed layout v1* — one default widget arrangement; reuse window manager. Lowest cost, ships Phase 1.
|
||||
2. *Customizable grid v1* — drag/resize/persisted layout. New layout engine, persistence, much larger.
|
||||
3. *Fixed + per-tab presets* — fixed canvas but a couple of named presets. Middle cost.
|
||||
- **(c) RECOMMENDED:** **(a) Fixed layout v1.** PRD §12.2 self-answers this; customization is explicitly
|
||||
a later phase. Rationale: keeps Workspace Desktop a maximized window in the existing OS, zero parallel
|
||||
layout system.
|
||||
- **(d) Blocks:** **Phase 1** (Workspace Desktop, S02). **[BLOCKS P1]** — but the PRD text already
|
||||
resolves it, so this is a confirm-not-debate.
|
||||
|
||||
### A2. Home Cockpit scope — personal-only, or team/global views too?
|
||||
*(PRD §23 Q2, line 1417; gap card S01 §9 Q3, Q5.)*
|
||||
|
||||
- **(a) Why it matters:** Decides whether the briefing reads cross-workspace personal state only, or also
|
||||
team/shared rows. S01 §9 Q3 flags that reading the user's *own* workspaces server-side is now safe
|
||||
(same-user), while team/shared rows must still gate through `approvalGrantStore`/RBAC.
|
||||
- **(b) Options:**
|
||||
1. *Personal-only v1* — briefing aggregates the user's own workspaces; team rows deferred to Phase 5.
|
||||
2. *Personal + team summary v1* — adds a shared-activity strip (needs RBAC + Team substrate live).
|
||||
3. *Toggle (personal/team) v1* — most flexible, most work; team substrate not ready until S10.
|
||||
- **(c) RECOMMENDED:** **(a) Personal-only v1**, with the briefing builder written so a team summary can
|
||||
be appended later behind the existing RBAC gate. Rationale: Team Workspace (S10) is a Phase-5 screen;
|
||||
Home must ship in Phase 1 without it. Local-first + own-data read is the safe boundary.
|
||||
- **(d) Blocks:** **Phase 1** (Home Cockpit, S01). **[BLOCKS P1]**.
|
||||
|
||||
### A3. Memory Center graph view — v1 or later?
|
||||
*(PRD §23 Q3, line 1418; gap card S04 §9 / line 232.)*
|
||||
|
||||
- **(a) Why it matters:** Whether the "Graph" tab ships in the first Memory Center cut.
|
||||
- **(b) Options:**
|
||||
1. *Ship graph in v1* — the `knowledge_entities`/`knowledge_relations` substrate + a graph render
|
||||
already work (S04 line 232: "Graph already works, so keep").
|
||||
2. *Defer graph* — tab hidden until a later polish pass.
|
||||
- **(c) RECOMMENDED:** **(a) Ship in v1.** Rationale: the substrate exists and S04 already confirms it
|
||||
renders; deferring would be removing working capability for no gain.
|
||||
- **(d) Blocks:** **Phase 2** (Memory Center, S04). **[BLOCKS P2]** (scoping-only; default = keep).
|
||||
|
||||
### A4. Which connectors/MCPs are real in v1 vs seeded/mock catalog?
|
||||
*(PRD §23 Q4, line 1419; gap cards S06 §9 Q3, S07 §9 Q1, S08 §9 Q4–Q5, S14 §9 Q1, S15 §9 Q3, S21 §9 Q2.)*
|
||||
|
||||
- **(a) Why it matters:** Touches six screens. Determines the empty/syncing states of the Marketplace,
|
||||
Connector Hub, MCP Hub, Tool Discovery and Memory-Import surfaces, and whether onboarding can pull data
|
||||
in-flow. The connector registry has ~31 real entries; the MCP catalog (`@waggle/shared mcp-catalog.ts`)
|
||||
is static; MCP runtime is **stdio-only** (`mcp-runtime.ts:108-115`) and currently never populated
|
||||
(`local/index.ts:911`).
|
||||
- **(b) Options:**
|
||||
1. *Real-where-the-substrate-exists, catalog-for-the-rest* — OAuth connectors that already have SDK
|
||||
entries connect for real (health-probe + timestamp, no background data-sync — S07 §9 Q1); MCPs
|
||||
install via the existing marketplace installer (`installer.ts:580` writes `.mcp.json`); everything
|
||||
else renders from the static catalog with honest "available / not installed" states.
|
||||
2. *All-mock catalog v1* — nothing actually connects; fastest UI, but violates PRD §22.2 ("no major
|
||||
screen depends only on mocked data when backend support exists").
|
||||
3. *All-real v1* — build connector background-sync + remote MCP transport now; out of scope per PRD §4.4.
|
||||
- **(c) RECOMMENDED:** **(1) Real-where-it-exists, catalog-for-the-rest.** Connectors: connect + health
|
||||
probe + `lastSyncAt` stamp (defer true data re-pull). MCPs: install/start/stop/test against the static
|
||||
catalog via the existing installer + stdio runtime; defer "Remote Registry" transport. Marketplace/Tool
|
||||
Discovery: render the live registry, never invent fake entries. Rationale: honors PRD §22.2 and the
|
||||
local-first default while staying in-place.
|
||||
- **(d) Blocks:** **Phase 4** (S07/S08/S21) and the onboarding **Phase 2** import flow (S14/S15). Not P1.
|
||||
|
||||
### A5. Marketplace — local catalog vs remote registry initially?
|
||||
*(PRD §23 Q5, line 1420; gap card S21 §9 Q2, S08 §9 Q4.)*
|
||||
|
||||
- **(a) Why it matters:** Whether S21 federates the existing local domains (marketplace.db + connectors +
|
||||
templates + personas + models) client-side, or invests in widening `marketplace.db`/`InstallationType`
|
||||
to natively catalog all six extension kinds.
|
||||
- **(b) Options:**
|
||||
1. *Federate-at-read (local-first)* — S21 composes the six categories from existing domains; no DB
|
||||
change; "Remote Registry" is a later tab. (S21 §9 Q2 recommendation.)
|
||||
2. *Native unified catalog table* — widen `marketplace.db` for publish/install/version parity across
|
||||
all six kinds. Enables update-tracking but is a real schema investment; conflicts with PRD §22
|
||||
"postpone public marketplace".
|
||||
- **(c) RECOMMENDED:** **(1) Federate-at-read, local catalog first.** Remote registry / public
|
||||
marketplace billing stays out per PRD §4.4 + §22. Rationale: matches local-first + in-place; no
|
||||
`marketplace.db` migration.
|
||||
- **(d) Blocks:** **Phase 4** (Marketplace, S21). Not P1/P2.
|
||||
|
||||
### A6. Artifact storage — workspace filesystem, virtual store, or external references first?
|
||||
*(PRD §23 Q6, line 1421; gap card S05 §9 Q1, Q2.)*
|
||||
|
||||
- **(a) Why it matters:** Artifacts have **no backing entity today** (the single largest entity gap,
|
||||
S10 line 226). PATCH/relations/status/tags require a stable id + an index. The file registry mixes
|
||||
ingested inputs with produced outputs, so a `kind`/`status` classification rule is also needed.
|
||||
- **(b) Options:**
|
||||
1. *Per-workspace `artifacts.json` index over the existing workspace FS/virtual store* — mirrors
|
||||
`documents.json`; assigns stable ids, holds status/tags/relations; reuses the StorageProvider
|
||||
(virtual | local | team) already in the repo. (S05 §9 Q1.)
|
||||
2. *Composite synthetic id (`workspaceId:store:name`), no index* — cheapest, but can't persist
|
||||
status/tags/relations (PATCH becomes impossible).
|
||||
3. *External references only* — point at files elsewhere; defers the entity but breaks "artifacts are
|
||||
first-class outcomes" (PRD §6.4).
|
||||
- **(c) RECOMMENDED:** **(1) `artifacts.json` index over the existing workspace storage**, with a
|
||||
classification rule: an artifact is an **explicit produced output** (generated doc/deck/sheet/etc. or
|
||||
user-promoted file), not every ingested input. Rationale: gives PATCH/relations a home with no `.mind`
|
||||
migration, reuses the StorageProvider, keeps local-first.
|
||||
- **(d) Blocks:** **Phase 2** (Artifact Center, S05); also gates artifact-sharing in S10. **[BLOCKS P2]**.
|
||||
|
||||
### A7. Minimum viable RBAC for team mode?
|
||||
*(PRD §23 Q7, line 1422; gap card S10 §9 Q1 (blocking), Q2.)*
|
||||
|
||||
- **(a) Why it matters:** Three role models disagree: PRD §17.2 (`Owner/Admin/Contributor/Viewer`),
|
||||
blueprint (`+Member +Guest`), and the **live `teams.db` CHECK** (`owner/admin/member/viewer`,
|
||||
`team.ts:21`). Picking wrong forces a DB CHECK migration + RBAC-logic rewrite. There is also a **real
|
||||
bug**: `PUT …/members/:userId` is owner-only (`team.ts:624`) while `PATCH` on the same path is
|
||||
owner/admin (`team.ts:649`).
|
||||
- **(b) Options:**
|
||||
1. *Keep the live 4-role union (`owner/admin/member/viewer`)* — map PRD "Contributor" → "Member",
|
||||
defer "Guest". No DB migration, no RBAC rewrite. (S10 §9 Q1 recommendation.)
|
||||
2. *Adopt PRD §17.2 four roles literally* — rename `member`→`contributor` in the DB CHECK + all
|
||||
enforcement (migration + grep-everywhere).
|
||||
3. *Adopt blueprint six roles (+Guest)* — new deny-by-default capability rules; largest scope.
|
||||
- **(c) RECOMMENDED:** **(1) Keep the live union; Contributor==Member; defer Guest.** Also **align the
|
||||
PUT/PATCH gate to owner+admin** (PRD uses PATCH; pick the broader gate consistently). Rationale:
|
||||
in-place, zero migration, fixes a real inconsistency.
|
||||
- **(d) Blocks:** **Phase 5** (Team Workspace, S10) — the `TeamRole` type + all member-management UI.
|
||||
Not P1/P2, but **must be ratified before S10 coding starts** (S10 §6: "decision needed before coding").
|
||||
|
||||
### A8. Memory retention / delete / tombstone behavior?
|
||||
*(PRD §23 Q8, line 1423; gap cards S04 §9 Q3, S16 §9 Q2.)*
|
||||
|
||||
- **(a) Why it matters:** PRD §14.4 distinguishes Deprecated / Archived / Deleted-tombstoned, but
|
||||
`memory_frames` has only `importance:'deprecated'` today and no `status`/tombstone column; delete is a
|
||||
hard `FrameStore.delete`. Determines whether an additive `.mind` migration is required and what
|
||||
"archive" vs "delete" mean to the user.
|
||||
- **(b) Options:**
|
||||
1. *Soft-status via `metadata` JSON, hard-delete on Delete* — store `{status: active|archived|
|
||||
deprecated}` in the existing `metadata TEXT` (idempotent `ADD COLUMN` pattern at `db.ts:122` if a
|
||||
queryable column is needed); Delete = hard `FrameStore.delete`. Archive = reversible status.
|
||||
2. *Full tombstone model* — Delete writes a tombstone row (retained, hidden, syncable) for audit/undo.
|
||||
Heavier; needed only if team-sync conflict-resolution requires it.
|
||||
3. *No status, delete-only* — simplest, but loses the Archived/Deprecated states PRD §14.4 requires.
|
||||
- **(c) RECOMMENDED:** **(1) Soft-status in `metadata` (Archive = reversible status, Deprecate = existing
|
||||
`importance`), Delete = hard delete with a scope-and-consequence confirmation** (PRD J20). Promote
|
||||
`status` to a real column only if it becomes a primary filter axis. Defer full tombstones to the
|
||||
team-sync phase. Rationale: local-first, one additive migration at most, satisfies §14.4 states.
|
||||
- **(d) Blocks:** **Phase 2** (Memory Center, S04) — and shares the confidence/metadata migration
|
||||
decision with the onboarding Memory Review (S16, see B2). **[BLOCKS P2]**.
|
||||
|
||||
---
|
||||
|
||||
## §B — Cross-cutting decisions (block ≥2 screens; not in PRD §23 but surfaced by gap cards)
|
||||
|
||||
### B1. Shell topology — keep the bottom-dock OS, or migrate to a left-rail / route-based shell?
|
||||
*(Gap cards S00 §9 Q1–Q2, Q5; S01 §9 Q4; S11 §9 Q5/Q7; S20 §9 Q7.)*
|
||||
|
||||
- **(a) Why it matters:** This is the **Phase-0 IA freeze**. The live shell is a single-route windowed
|
||||
OS with a bottom `Dock.tsx`; blueprint/mocks show a **left navigation** + `/home,/workspaces,…` route
|
||||
groups. Every later screen's navigation/AppId/dock placement depends on this. Deep-linking + browser
|
||||
back-button are the only things real routes buy.
|
||||
- **(b) Options:**
|
||||
1. *In-place dock reframe, keep `AppId`-keyed window navigation* — cheapest, preserves the OS feel and
|
||||
multi-window runtime; no react-router. (S00 §9 Q1–Q2 recommendation.)
|
||||
2. *Left rail + react-router routes* — closer to the mock, gains deep-linking, but a parallel layout +
|
||||
conflicts with multi-window; large blast radius.
|
||||
- **(c) RECOMMENDED:** **(1) In-place dock reframe; keep windowed `AppId` navigation.** Group dock
|
||||
entries into Work / Intelligence / Extend / Team zones to satisfy the IA without a router. Rationale:
|
||||
PRD §24 (mocks directional) + locked in-place direction. Revisit deep-linking only if it becomes a hard
|
||||
requirement.
|
||||
- **(d) Blocks:** **Phase 0 → Phase 1** (AppShell/IA, S00) — and the dock/AppId placement of S11/S20
|
||||
("automations" zone) and S01 (`home` vs `cockpit`). **[BLOCKS P1]** — the IA freeze gates everything.
|
||||
|
||||
### B2. Memory confidence — heuristic-at-preview vs LLM-classify, and persisted vs preview-only?
|
||||
*(Gap cards S04 §9 Q1, S16 §9 Q1–Q2; S15 §9.)*
|
||||
|
||||
- **(a) Why it matters:** `memory_frames` has no confidence today (only `knowledge_relations.confidence`,
|
||||
edges-only, `schema.ts:93`). PRD §12.4 wants "filter by confidence" + "low-confidence surfaced for
|
||||
review", and onboarding Memory Review (S16) + the standing J08 review queue both depend on it. Wiring
|
||||
the existing `HarvestPipeline` classify/synthesize means paid Haiku/Sonnet calls per import (slow,
|
||||
gated on a real embedder); a cheap heuristic avoids that.
|
||||
- **(b) Options:**
|
||||
1. *Cheap heuristic at preview (source-trust × adapter-type × dedup signal), persisted in `metadata`
|
||||
when a queryable filter is needed* — fast, no per-import LLM cost; reserve LLM scoring for an opt-in
|
||||
deep pass / the J08 standing queue. (S16 §9 Q1 recommendation.)
|
||||
2. *LLM classify/synthesize at preview* — real confidence, but onboarding-latency + cost hit.
|
||||
3. *No confidence v1* — drops a core PRD trust requirement (§12.4).
|
||||
- **(c) RECOMMENDED:** **(1) Heuristic for onboarding v1; LLM classify reserved for the standing J08
|
||||
queue.** Persist `{kind, confidence, sourceId, status}` in the existing `memory_frames.metadata TEXT`
|
||||
via the idempotent `ADD COLUMN` pattern (`db.ts:122`) **only if** confidence/status become queryable
|
||||
filters; preview-only needs no migration. Make this one decision once and reuse it across S04 + S16.
|
||||
Rationale: honors PRD trust criteria within the onboarding latency budget, local-first, one additive
|
||||
migration at most.
|
||||
- **(d) Blocks:** **Phase 2** — onboarding Memory Review (S16, a day-0 J01 flow) and Memory Center
|
||||
filters (S04). **[BLOCKS P2]**. Shares the migration with A8.
|
||||
|
||||
### B3. Agent vs Persona boundary, and where the Agent entity is stored.
|
||||
*(Gap cards S09 §9 Q1, Q3; S18 §9 Q1, Q2.)*
|
||||
|
||||
- **(a) Why it matters:** Decides whether Phase 3 introduces a real persisted Agent object (distinct from
|
||||
the 13/17 personas in `persona-data.ts`) or just re-skins the persona catalog. PRD §15.5 lists explicit
|
||||
agent fields (model, autonomy, memoryScopes, skillIds, connectorIds, mcpIds, permissions, …) that a
|
||||
persona does not carry.
|
||||
- **(b) Options:**
|
||||
1. *Real Agent entity in a JSON store (`{dataDir}/agents.json`), referencing `personaId`* — no `.mind`
|
||||
migration, mirrors the `agent-groups.json` precedent; persona = behavioral template field of the
|
||||
agent. (S09 §9 Q1/Q3 + S18 §9 Q1/Q2 recommendation.)
|
||||
2. *`agents` table in `mind/schema.ts` (SCHEMA_VERSION bump)* — heavier; PRD §4.4 non-goal favors
|
||||
minimal backend.
|
||||
3. *No Agent entity; persona re-skin only* — can't satisfy PRD §12.9 explicit-scope requirements.
|
||||
- **(c) RECOMMENDED:** **(1) Real Agent entity, JSON store, references `personaId`.** Derive
|
||||
`successRate`/`lastRun` at read from `execution_traces` (avoid a third tally vocabulary). Rationale:
|
||||
satisfies PRD §12.9/§15.5 with zero migration, in-place over the existing fleet/traces substrate.
|
||||
- **(d) Blocks:** **Phase 3** (Agent Center S09 + Agent Builder S18). Not P1/P2.
|
||||
|
||||
### B4. `/api/*` vocabulary aliasing — singular command, automations, mcps, connectors revoke.
|
||||
*(Gap cards S03 §9 Q1, S11 §9 Q4, S20 §9 Q4, S07 §9 Q3; backend-api-delta.)*
|
||||
|
||||
- **(a) Why it matters:** PRD §16 uses vocabulary (`/api/command/*`, `/api/automations/*`,
|
||||
`/api/connectors/:id/revoke`) that differs from the live routes (`/api/commands/execute`, `/api/cron/*`,
|
||||
`/api/connectors/:id/disconnect`). Renaming breaks existing callers (`adapter.executeCommand`,
|
||||
`commands.ts`, `cron.ts`); aliasing keeps both contracts.
|
||||
- **(b) Options:**
|
||||
1. *Add PRD-vocabulary aliases alongside the live routes* — new `command.ts`/`automations.ts` alias
|
||||
plugins that delegate to the existing registry/cron; existing callers unbroken. (S03/S11/S20
|
||||
recommendations converge on this.)
|
||||
2. *Hard-rename to PRD vocabulary* — clean surface, but breaking; needs exhaustive grep (CLAUDE.md §3.5).
|
||||
- **(c) RECOMMENDED:** **(1) Alias, don't rename.** New singular/plural aliases that delegate to the
|
||||
existing handlers; UI/adapter point at the PRD vocabulary. Rationale: in-place, non-breaking, matches
|
||||
the backend-api-delta dispositions.
|
||||
- **(d) Blocks:** **Phase 1** (Command Center S03) for `/api/command/*`; **Phase 3** (S11/S20) for
|
||||
`/api/automations/*`; **Phase 4** (S07) for connector revoke. The command alias is **[BLOCKS P1]**.
|
||||
|
||||
### B5. Tier-vocabulary unification (`UserTier` / `BillingTier` / `PlanTier` + RBAC roles).
|
||||
*(Gap cards S00 §9 Q3, S08 §9 Q6.)*
|
||||
|
||||
- **(a) Why it matters:** Three independent tier vocabularies gate the dock, billing, and feature access;
|
||||
PRD §17 RBAC roles add a 4th axis. MCP Hub (S08) and the dock (S00) both need a single answer for
|
||||
"is this gated PRO+ or power-user-density".
|
||||
- **(b) Options:**
|
||||
1. *Document the mapping, defer unification* — keep the three vocabularies, ship a single mapping table
|
||||
and a `useFeatureGate` that reads the canonical `tiers.ts`; no cross-cutting rewrite now.
|
||||
2. *Unify into one tier model now* — clean, but cross-cutting (billing + dock + features + RBAC) during
|
||||
a high-velocity refactor.
|
||||
- **(c) RECOMMENDED:** **(1) Document the mapping + route all new gates through `@waggle/shared tiers.ts`
|
||||
(`TierCapabilities`); defer the unification refactor.** Gate MCP Hub + Marketplace install at **PRO+**
|
||||
(matches the existing marketplace install gate). Rationale: avoids a cross-cutting rewrite mid-refactor;
|
||||
reuses the canonical tier system; no parallel gate (S10 §6).
|
||||
- **(d) Blocks:** **Phase 4** (S08 tier gate) primarily; informs the dock gate in Phase 0/1. Not P1
|
||||
blocking if the mapping is documented.
|
||||
|
||||
### B6. `MemoryKind` / `ImportItemType` / FE `MemoryFrame.type` reconciliation.
|
||||
*(Gap cards S04 §9 Q6, S16 §9 Q3.)*
|
||||
|
||||
- **(a) Why it matters:** Three vocabularies disagree: FE `MemoryFrame.type` (`event`/`insight`/…),
|
||||
PRD §15.2 `MemoryKind` (`fact|decision|task|preference|strategy|learning|goal|entity`), and the harvest
|
||||
adapter's 8 `ImportItemType` values. Memory Review categories (Memories/Decisions/Tasks/Artifacts/
|
||||
Projects) need a 1:1 map. Wrong choice re-renders existing frames and changes the type-filter chips.
|
||||
- **(b) Options:**
|
||||
1. *Adopt PRD §15.2 `MemoryKind` as canonical; add a pure `lib/harvest-kind-map.ts` mapping
|
||||
`ImportItemType → MemoryKind` and a display-category map* — drop FE `event`/`insight`, add
|
||||
`preference/strategy/learning/goal`. (S04 §9 Q6 + S16 §9 Q3 direction.)
|
||||
2. *Keep FE types, map PRD onto them* — less churn now, perpetuates drift (precedent: the FrameSource
|
||||
TS-vs-DB drift the shared-types-delta warns against).
|
||||
- **(c) RECOMMENDED:** **(1) PRD §15.2 `MemoryKind` canonical, in `@waggle/shared`; pure mapping helpers
|
||||
for harvest + display categories.** Rationale: one source of truth (shared-types-delta §0 rule), avoids
|
||||
perpetuating drift, keeps the import/review/center contract consistent.
|
||||
- **(d) Blocks:** **Phase 2** (S04 + S16). **[BLOCKS P2]**.
|
||||
|
||||
### B7. `ExtensionType` union — add `agent`, keep `external_tool`, or both?
|
||||
*(Gap card S21 §9 Q1; PRD §12.13 vs §15.2.)*
|
||||
|
||||
- **(a) Why it matters:** PRD §12.13 marketplace categories include **Agents** but `ExtensionType`
|
||||
(§15.2) omits `agent` and adds `external_tool`. The two PRD sections contradict; S21's faceted catalog
|
||||
needs a canonical union.
|
||||
- **(b) Options:**
|
||||
1. *`skill | agent | connector | mcp | model | template`* — matches the §12.13 visible categories;
|
||||
drop `external_tool` (external tools surface via connectors/MCPs anyway).
|
||||
2. *Keep §15.2 literally (`…| external_tool`, no agent)* — but then Agents have no marketplace category.
|
||||
3. *Superset of 7 (`…| external_tool | agent`)* — covers both, at the cost of an unused-for-now member.
|
||||
- **(c) RECOMMENDED:** **(1) `skill | agent | connector | mcp | model | template`.** Rationale: PRD §12.13
|
||||
is the user-visible contract; external tools are already represented by connectors/MCPs, so `agent`
|
||||
earns the slot. Define once in `@waggle/shared`.
|
||||
- **(d) Blocks:** **Phase 4** (Marketplace, S21). Not P1/P2.
|
||||
|
||||
### B8. Identity store of record for onboarding profile.
|
||||
*(Gap card S13 §9 Q1; S01 §9 (greeting name).)*
|
||||
|
||||
- **(a) Why it matters:** Two identity stores exist — `/api/profile` (current onboarding write path) and
|
||||
`/api/identity` (the `identity` table that backs the Home greeting name / `adapter.getIdentity()`).
|
||||
Writing only one leaves the other stale (e.g. Home greets with an empty name).
|
||||
- **(b) Options:**
|
||||
1. *Onboarding writes profile AND seeds identity* — single round-trip extension; Home greeting works
|
||||
immediately. (S13 §9 Q1 direction.)
|
||||
2. *Profile-only, derive identity lazily* — fewer writes, but Home greeting drift until first identity write.
|
||||
- **(c) RECOMMENDED:** **(1) Write profile + seed identity in the same onboarding commit.** Rationale:
|
||||
prevents the two-store drift the gap card flags; cheap; makes the Phase-1 Home greeting correct.
|
||||
- **(d) Blocks:** **Phase 2** (onboarding S13) and the **Phase 1** Home greeting depends on identity
|
||||
being populated. Practically **[BLOCKS P1]** for a correct greeting; functionally a small fix.
|
||||
|
||||
---
|
||||
|
||||
## §C — Screen-local questions (single-screen scope; ratify with the owning card)
|
||||
|
||||
> These do not block other screens. Each carries a default recommendation consistent with the locked
|
||||
> direction; founder can rubber-stamp or override per screen. Cited to the gap card for full context.
|
||||
|
||||
- **C1. S01 Q1 — LoginBriefing fate.** Retire the modal; absorb catch-up into Home Cockpit's first paint
|
||||
(~80% overlap). **Rec: retire + absorb.** *(Phase 1.)*
|
||||
- **C2. S01 Q2 — "Overnight" time-window semantics** (since last close vs midnight vs 12h). **Rec: since
|
||||
last app close, fallback midnight-local.** *(Phase 1.)*
|
||||
- **C3. S01 Q6 — Quick-capture `file` destination** (default/personal store vs prompt for workspace).
|
||||
**Rec: default personal store + optional workspace picker.** *(Phase 1/2.)*
|
||||
- **C4. S02 Q1 — Workspace Desktop window vs full-bleed route.** **Rec: maximized `AppWindow`** (no
|
||||
parallel layout system). *(Phase 1.)*
|
||||
- **C5. S02 Q2 — Overview chat: live mini-composer vs read-only preview.** **Rec: read-only preview that
|
||||
deep-links to the Chat tab** (avoids dual ChatApp render modes in v1). *(Phase 1.)*
|
||||
- **C6. S02 Q3 / S17 Q1 — `WorkspaceType` enum values.** **Rec: `project | client | research | personal`
|
||||
(+`team`/`organization` reserved); `type` coexists with the free-string `group`.** *(Phase 1/2.)*
|
||||
- **C7. S02 Q6 — Tasks store of record** (`/api/workspaces/:id/tasks` vs `WorkspaceState`
|
||||
`pending`/`blocked`). **Rec: seed Tasks from `WorkspaceState` for v1; reconcile to a first-class task
|
||||
store only if editing is needed.** *(Phase 1.)*
|
||||
- **C8. S03 Q4 — Natural-language commands** (heuristic vs LLM). **Rec: deterministic heuristic
|
||||
intent-parse v1; LLM resolver later.** *(Phase 1.)*
|
||||
- **C9. S03 Q5 — Palette permission prompt mechanism.** **Rec: reuse the chat approvals pipeline
|
||||
(`approval.ts` + `pendingApproval`).** *(Phase 1.)*
|
||||
- **C10. S04 Q2 — Conflict state: live recall-time vs persisted.** **Rec: live recall-time signal v1**
|
||||
(`CombinedRetrieval.detectConflict`); persist only if a standing conflict queue is needed. *(Phase 2.)*
|
||||
- **C11. S04 Q4 — Merge semantics.** **Rec: re-cognify/concatenate v1, archive originals (not hard
|
||||
delete); LLM-synthesis later.** *(Phase 2.)*
|
||||
- **C12. S05 Q5 — Artifact previews.** **Rec: icon + on-click `FilePreview` v1; no server thumbnails.** *(Phase 2.)*
|
||||
- **C13. S06 Q2 / S19 Q1 — Skill Builder publish target** (local dir vs marketplace). **Rec: Builder =
|
||||
create-to-local (`POST /api/skills/create`); install-by-id + marketplace publish live in S06/S21.** *(Phase 3.)*
|
||||
- **C14. S06 Q4 / S19 Q2 — Inputs/Outputs persistence** (frontmatter vs body markdown). **Rec: body
|
||||
markdown v1; extend `SkillFrontmatter` only if inputs/outputs must be queryable.** *(Phase 3.)*
|
||||
- **C15. S06 Q6 / install-audit `critical` CHECK bug.** Real bug: `AuditRiskLevel` TS includes `critical`
|
||||
but the DDL CHECK allows only `low/medium/high` (`install-audit.ts:65` vs `:16`) — a `record()` with
|
||||
`critical` throws; skill/MCP/connector installs route through this path. **Rec: ship the one-line CHECK
|
||||
migration to add `critical`** (additive, idempotent-migration pattern at `db.ts:122`), OR make the
|
||||
marketplace `CRITICAL → 'high' + approvalClass:'blocked'` mapping the permanent contract. **Pick the
|
||||
migration** for correctness. *(Phase 4; cross-cuts any install-audit write.)*
|
||||
- **C16. S07 Q1 — Connector "sync now" semantics.** **Rec: v1 = re-probe health + stamp `lastSyncAt`**;
|
||||
background data re-pull deferred. *(Phase 4.)*
|
||||
- **C17. S07 Q3 — revoke vs disconnect.** **Rec: `revoke` purges OAuth tokens + writes a stronger audit
|
||||
entry (PRD §17.3); `disconnect` is the lighter alias.** *(Phase 4.)*
|
||||
- **C18. S07 Q4 / S08 — Audit route shape.** **Rec: one shared `GET /api/extend/audit?type=` serving
|
||||
connectors + MCPs + marketplace**, bound to `personal.mind`. *(Phase 4.)*
|
||||
- **C19. S08 Q2 — MCP scope model** (single `workspaceId` vs `mcpIds[]` N:N). **Rec: single-`workspaceId`
|
||||
config v1 (matches the stdio runtime); N:N membership deferred.** *(Phase 4.)*
|
||||
- **C20. S08 Q4 — "Remote Registry" tab.** **Rec: defer remote-transport MCPs (runtime is stdio-only);
|
||||
v1 tab points at the static catalog / Composio gateway reference, no new transport.** *(Phase 4.)*
|
||||
- **C21. S08 Q5 / S21 Q5 — MCP "test" semantics.** **Rec: live spawn-and-`isHealthy()`/`tools/list`
|
||||
round-trip** where cheap; fall back to static manifest validation. *(Phase 4.)*
|
||||
- **C22. S09 Q6 — Agent categories taxonomy.** **Rec: Templates is a side affordance, not a tab; tabs =
|
||||
All/Personal/Workspace/Team/Autonomous/Archive.** *(Phase 3.)*
|
||||
- **C23. S09 Q7 / S18 Q3 — `/run` target + lifecycle.** **Rec: fleet-spawn a one-shot into a chosen
|
||||
workspace (picker if multiple `workspaceIds`); persistent always-running agents deferred.** *(Phase 3.)*
|
||||
- **C24. S11 Q1 / S20 Q1 — Automation triggers: schedule-only vs event-driven.** **Rec: schedule-only v1
|
||||
(cron cadence); gate/defer the "Event" trigger (no event→automation dispatch substrate today).** *(Phase 3.)*
|
||||
- **C25. S11 Q2 / S20 Q2 — Condition step.** **Rec: store an advisory `jobConfig.condition` string (no
|
||||
evaluation engine) v1.** *(Phase 3.)*
|
||||
- **C26. S11 Q3 / S20 Q3 — Builder "test run".** **Rec: add a no-persist dry-run route (`POST
|
||||
/api/automations/test`); do NOT reuse the real `cron/:id/trigger` which executes + auto-enables.** *(Phase 3.)*
|
||||
- **C27. S11 Q6 — Analytics tiles.** **Rec: keep success-rate (derivable from `cron_execution_history`);
|
||||
drop "hours saved" (no source) or label it an explicit heuristic estimate.** *(Phase 3.)*
|
||||
- **C28. S12 Q1 — Onboarding language selector.** **Rec: static disabled `English (US)` chip (no i18n
|
||||
exists; PRD §4.4 puts i18n out of first-phase scope).** *(Phase 2.)*
|
||||
- **C29. S12 Q2 — First-launch 3s auto-advance on the privacy screen.** **Rec: drop the auto-advance**
|
||||
(it fights the read-the-privacy-note intent). *(Phase 2.)*
|
||||
- **C30. S13 Q3 — Work-type vs Industry vs Template axis.** **Rec: keep Work type as a distinct
|
||||
personalization signal; don't re-ask what the template already implies (PRD §12.12).** *(Phase 2.)*
|
||||
- **C31. S14 Q2 — Tool Discovery id-space.** **Rec: unify under a namespaced scheme
|
||||
(`connector:gmail` / `tool:cursor`) so the recommender + S15 disambiguate.** *(Phase 2.)*
|
||||
- **C32. S14 Q3 — Pre-check detected AI tools.** **Rec: pre-select from `GET /api/tools/detect` with a
|
||||
visible "detected" badge** (J01 implies a trusted populated start). *(Phase 2.)*
|
||||
- **C33. S15 Q2 / S16 Q5 — Import↔Review commit split.** **Rec: S15 stages previews, S16 commits the
|
||||
approved selection** (PRD:646/1207 "nothing imports without review/approval"; current code commits at
|
||||
S15 — fix). Splits onboarding into the Import + Review steps. *(Phase 2; correctness-relevant.)*
|
||||
- **C34. S15 Q1 — Hermes/Codex/Cursor tiles.** **Rec: render as `upload`/"Other" file pickers or
|
||||
"coming soon" v1** (they are AI-OS launcher/hook surfaces, not harvest adapters). *(Phase 2.)*
|
||||
- **C35. S17 Q5 — Workspace Creation: install-on-create vs stage selections.** **Rec: record connector/
|
||||
MCP ids as workspace *intent* on the config; do NOT run install/OAuth at create time.** *(Phase 2.)*
|
||||
- **C36. S19 Q4 — Skill scope vocabulary** (`enterprise` vs PRD `organization`). **Rec: adopt PRD
|
||||
`organization`** for the publish-scope picker (align to the §15.2 `Scope` union). *(Phase 3.)*
|
||||
- **C37. S19 Q5 — Skill test-run fidelity.** **Rec: preview-only (injected-prompt + parsed metadata) v1**;
|
||||
live LLM dry-run deferred. *(Phase 3.)*
|
||||
|
||||
---
|
||||
|
||||
## Phase-blocking summary (founder fast-path)
|
||||
|
||||
**Before Phase 0/1 coding** (the spine): ✅ **RATIFIED 2026-06-09** — **B1** (shell topology / IA freeze),
|
||||
**A1** (fixed layout), **A2** (Home personal-only), **B4** (command alias), **B8** (identity seed for
|
||||
greeting). **Phase 0 is unblocked.**
|
||||
|
||||
**Must ratify before Phase 2** (work + onboarding): **A6** (artifact storage entity), **A8** (memory
|
||||
retention/delete), **B2** (confidence: heuristic + optional migration), **B6** (MemoryKind canonical),
|
||||
**A3** (graph keep — default yes), plus the onboarding correctness item **C33** (Import stages / Review
|
||||
commits).
|
||||
|
||||
**Phase 3+ (intelligence/extend/team), not blocking P1–P2:** **A4, A5, A7, B3, B5, B7** + all remaining
|
||||
§C items. Note **A7** (RBAC) must be ratified before S10 coding specifically, and **C15** (install-audit
|
||||
`critical` CHECK bug) should be fixed before any install-audit write path ships in Phase 4.
|
||||
|
||||
|
||||
---
|
||||
|
||||
# UX Refactor v2.1 — Ratification of Decision Register D1–D15 (2026-06-10)
|
||||
|
||||
**Ratifies:** `docs/UX_REFACTOR_STATE_AUDIT.md` §8.3 · **Ratified by:** Marko Marković (founder)
|
||||
**Authority chain (declared by this register, D10):** this ratification > Brief v2.1 > `docs/UX_REFACTOR_STATE_AUDIT.md` > blueprint handoff package > prior-plan docs (`docs/ux-refactor/`).
|
||||
This document + Brief v2.1 + the audit **supersede all prior conflicting ratifications, explicitly including B1 (2026-06-09)**. This file is the **single decision log** going forward — no parallel ratification tracks.
|
||||
|
||||
## Structural (D1–D5)
|
||||
|
||||
### D1 — Shell topology: RATIFIED option (b) — AppShell via in-place conversion. **B1 is explicitly superseded.**
|
||||
Convert to AppShell + left nav + single canvas + URL routes, reusing every shipped screen component as a route surface. Conditions:
|
||||
1. **Zero screen-component rewrites during conversion**; screens mount under routes as-is. Divergences are phase work, not conversion work.
|
||||
2. Brief route groups become **canonical addresses**; Ctrl+K command index and `handleSearchNavigate` retarget to routes; `waggle:open-app` CustomEvent deep links convert to URL navigation (the event bus may remain as an internal shim during transition, but **URLs are the contract**).
|
||||
3. **No window z-order code ships** (`useWindowManager` z-order/focus/minimize/cascade retired). `waggle-window-state-v1` localStorage migrates or clears cleanly.
|
||||
4. **Chat multi-instance:** chat becomes the widget inside Workspace Desktop (one per workspace, per blueprint "chat is one widget"). If conversion design surfaces a hard requirement for detached chat, propose it as a scoped exception ("D1-c lite") — do not silently keep windowing.
|
||||
5. **B4 ("alias, don't rename" for `/api/*`) survives** — orthogonal to the shell and correct.
|
||||
|
||||
### D2 — Memory Center: RATIFIED — rework AND promote to standalone.
|
||||
Standalone `MemoryCenterApp` (same shape as `ArtifactCenterApp`; audit §7.9 inconsistency resolved in favor of the standalone pattern). Top-level structure = **two-mind split**: "About you" (Personal Mind) / "About this work" (Workspace Mind, per workspace). Reuse `MemoryCenterTab` internals as the per-mind list. Confidence/metadata (B2, M1) carry over. Legacy MemoryApp tabs (Graph/Timeline/etc.) remain accessible from within the new surface or as secondary tabs — **do not delete capability, restructure the entry**.
|
||||
|
||||
### D3 — Auth gate: RATIFIED — full structural scope. All four audit conflicts in scope:
|
||||
1. **Adapter-level pre-token deferral** (structural gate, not per-component convention).
|
||||
2. **Throw-on-`!ok` mandated adapter-wide** — convert all silent-empty getters (`getMarketplace`, `getMcps`, `getPersonas`, `getModels`, `getWorkspaceTemplates`, `getTier`).
|
||||
3. **401 → silent token refresh → single retry** (sidecar-restart recovery) — in scope.
|
||||
4. **Boot-path surfaces in scope:** `Desktop.refreshTier` and `LoginBriefing` must never render silent-FREE / silent-empty on auth failure. **Tier resolution failing open to a rendered FREE state is classified as a monetization defect, severity-critical.**
|
||||
Plus: error states never cache as valid-empty; focus/visibility revalidation on errored surfaces.
|
||||
|
||||
### D4 — Skill-write governance: RATIFIED — autonomy-aware gating, four bindings:
|
||||
- **(i) Policy:** `create_skill` — normal autonomy = ask (in-chat approval card), trusted/yolo = auto-execute. `delete_skill` — **always ask, every autonomy level** (add to `isCriticalNeverAutopass`); destructive actions do not inherit autonomy. `read_skill` ungated. **Always-audit all three** outcomes with `initiator:'agent'`.
|
||||
- **(ii) Surface:** the **in-chat SSE approval card is canonical** for agent skill writes. Brief §2.3's "same modal" is hereby interpreted as **same policy and risk taxonomy, not same component**. Align the card's risk display with the `ui/approval-modal.tsx` taxonomy (D15 work).
|
||||
- **(iii) One write path — AMENDED ruling: do NOT route the agent tool through HTTP.** Extract a **shared skill-write service module** (create/update/delete + redaction + audit write inside the service) consumed by both `routes/skills.ts` and `skill-tools.ts`. One module, one audit trail, two callers.
|
||||
- **(iv) Endpoint consolidation (absorbs D14):** raw `POST /api/skills` delegates to the audited service (or is deprecated in favor of `/api/skills/create`); `PUT` and `DELETE /api/skills/:name` enter the audit trail. **Provenance:** skill frontmatter `initiator`/`source` + `GET /api/skills` returns it + Skills Hub badge ("created by agent — review"), replacing the name-heuristic "Custom" classification for agent-created skills.
|
||||
- **Persona exception RATIFIED:** read-only personas (planner/verifier) keep losing `create_skill`/`delete_skill` while retaining `read_skill`.
|
||||
- **PM residual ruled (PRO-gate on skill creation):** skill creation — human and agent — **stays available at FREE for launch**. The self-evolving loop is the differentiator and must demo at the free tier. Marketplace installs remain PRO-gated. Reversible post-launch with data.
|
||||
|
||||
- **Two-seam WorkspaceDesktopApp edit RATIFIED (founder "go", 2026-06-10):** the derived edit from plan §5.2 — (a) controlled activeTab/onTabChange for URL-driven tabs, (b) chat widget embedded in the chat tab body — is signed off, scoped to exactly those two seams, test-pinned. P1a unblocked.
|
||||
|
||||
### D5 — Team zone: RATIFIED — keep tier-hidden. No stripping, no new work. Approvals-inbox PRO visibility: post-launch consideration, not launch scope.
|
||||
|
||||
## Scope clarifications (D6–D10) — defaults ratified, with notes
|
||||
|
||||
- **D6 — RATIFIED.** S14-in-Launcher and S16-as-needs-review-filter satisfy the launch cut. Consent is given at import initiation; review is quality control, not consent. **Verification item:** Home Cockpit must surface a "N memories need review" alert (journey J08); if absent, add as a small Phase-2 item.
|
||||
- **D7 — RATIFIED.** `UpgradeModal` satisfies §2.2; no rename, no rebuild — tests pin it. Brief language amended to "Upgrade surface."
|
||||
- **D8 — RATIFIED.** Relabel dock `cockpit` entry ("Mission Control"); **"Command Center" is reserved for the Ctrl+K palette.**
|
||||
- **D9 — RATIFIED.** Sweep: code (the `HomeCockpit.tsx:145` user-visible "Win+K" pill is the must-fix; comments included) + `docs/ux-refactor/` prose. Handoff-package PDFs/docx get a one-page annotation (naming erratum), not regeneration.
|
||||
- **D10 — RATIFIED, extended.** Commit the package's text files; gitignore (or LFS) the binaries. Authority chain declared (header above). Prune merged worktrees (`waggle-os-ux-refactor`, `waggle-os-ga`) and the 5 merged branches. Brief path corrections from audit §7 accepted (workspace-manager in hive-mind-core; state/context in server/local).
|
||||
|
||||
## Launch integrity (D11–D15) — all confirmed
|
||||
|
||||
- **D11 — RATIFIED.** Honor `WAGGLE_DATA_DIR` in `service.ts` with the same default; **one startup log line: resolved dataDir + tier**. Fix the stale "default to SOLO" comment while in there. Closes the split-brain with installer/launcher.
|
||||
- **D12 — RATIFIED, launch-blocking for the desktop binary.** Refresh `app/src-tauri/resources/service.js` now; prefer build-time generation + untracking; CI staleness/hash gate is the minimum acceptable. **A binary shipping an April server is a release-stopping defect class.**
|
||||
- **D13 — RATIFIED, both halves.** Document `build:packages` in the boot recipe AND alias `@waggle/shared`→src on the dev path so the class dies.
|
||||
- **D14 — Folded into D4(iv). Closed.**
|
||||
- **D15 — RATIFIED.** Launch-blocking from prior-plan P6: **per-screen state grid** (brief rule 10) + **approval/audit taxonomy consolidation** (brief rule 7, includes D4-ii alignment). Post-launch: connector `/sync` real implementation (stub stands), MCP logs.
|
||||
|
||||
## Additional items (no decision letter — just do)
|
||||
|
||||
- **Backlog flag:** investigate the teams-server boot error from the live probe (`Build failed: Fastify instance is already listening` when `CLERK_SECRET_KEY` is set) — classify noise vs defect. Post-launch unless it affects the solo boot path.
|
||||
- **memory-mcp duplication (audit §7):** out of launch scope. Mark `packages/memory-mcp` dormant; canonical-package decision (vs `hive-mind-mcp-server`) deferred post-launch.
|
||||
- **`WorkspaceBriefing.tsx`:** keep as ChatApp empty state; no merge into Home. Brief's keep-list note corrected.
|
||||
- **Audit process rule going forward:** audits report, they don't mutate (no fast-forwards, no pid overwrites mid-audit; disclose if unavoidable).
|
||||
|
||||
## Phase sequence (unblocked)
|
||||
|
||||
**Phase 0** = D1 conversion plan + route map, naming sweep (D8/D9), doc authority (D10). Then **P1**=D3, **P2**=verify + J08 alert, **P3**=D2, **P4**=D11/D12 + FREE→Upgrade e2e re-run, **P5**=D4 ✅ (2026-06-12, 7 commits 73f2ed5→48292ef), **P7**=D15 scope ✅ (2026-06-12: Track B B1-B5 + Track A A1-A7; D15 closure bar MET). **Nothing from prior Phases 0–4 is rebuilt.**
|
||||
|
||||
---
|
||||
|
||||
## D3 implementation notes (P1b, 2026-06-11)
|
||||
|
||||
Recorded per the single-decision-log rule; full design + verification record in
|
||||
`docs/ux-refactor/p1b-auth-gate-plan.md` + `p1b-plan-review-record.md`.
|
||||
|
||||
1. **fetchRaw exception class — ratified-flow-preserving deviation from the literal
|
||||
"throw mandated adapter-wide" (D3-2).** Two caller classes keep non-throwing
|
||||
semantics because their *error-path payload is load-bearing*: raw-Response
|
||||
consumers (`installMarketplacePackage` — documented 403/SecurityGate status
|
||||
handling) and body-envelope getters (`installMcp` + 6 MCP siblings +
|
||||
`revokeConnector` — their 403/422 bodies carry `TIER_INSUFFICIENT` and the
|
||||
`requiresApproval/blocked/severity` envelope that drives the D4 ApprovalModal
|
||||
security flow). All six ruling-named getters throw as mandated. Adapter-level
|
||||
envelope pins added (component tests mock the adapter and cannot see this layer).
|
||||
2. **Plus-clause revalidation scope.** Wired: tier (ShellContext), useBilling,
|
||||
useWorkspaces, LoginBriefing, MCPHubApp resolvableMcpNames, ComplianceDashboard
|
||||
templates. Deferred to P7 with ledger: ChatWindowInstance FALLBACK_MODELS,
|
||||
TemplatesView/AgentBuilder catalogs (their boot-race instance dies with the gate;
|
||||
the 401-retry leg cures their restart instance; residual is genuine-5xx staleness).
|
||||
3. **D3-4 extensions (same monetization-defect class):** useBilling (Settings→Billing
|
||||
rendered FREE-as-fact + upgrade CTAs on failure) and the Settings→General
|
||||
"{tier} plan" badge (separate getSettings-fed copy, now single-sourced from
|
||||
resolved billing state).
|
||||
4. **DISCOVERED, OUT OF P1b SCOPE — needs a founder ruling:** all five EventSource
|
||||
SSE channels (notifications / events / subagent status / waggle signals / harvest
|
||||
progress) are **401-dead in every default run since D1** — the server bearer-gates
|
||||
all /api/* GETs, EventSource cannot send headers, no SSE route accepts ?token=
|
||||
(only /ws does), and onerror handlers permanently close. Working only under
|
||||
WAGGLE_TRUST_LOCALHOST=1. Fix = server auth model (per-route ?token= like /ws, or
|
||||
exempt-with-validation) + client reconnect design — one coherent follow-up
|
||||
("SSE auth + reconnect"). **Ask: ratify as P1b follow-up stage or P2 line item.**
|
||||
|
||||
---
|
||||
|
||||
## P2 implementation notes (verify + J08, 2026-06-11)
|
||||
|
||||
Recorded per the single-decision-log rule; full record in
|
||||
`docs/ux-refactor/p2-verification-record.md`.
|
||||
|
||||
1. **P2 verification CLOSED.** Home (§12.1) + Desktop (§12.2) verified against Brief
|
||||
v2.1 via a 4-lane adversarial workflow: 25/37 met or ratified-divergence, 12
|
||||
confirmed gaps, 2 claims refuted. The HIGH (dead Artifacts feed — envelope
|
||||
unwrap) + all tiny/small verified defects fixed; feature-shaped residuals
|
||||
ledgered in the record (S02 tab embeds → P3/P7; status-bar chips, upNext
|
||||
tasks, activeModels → P7).
|
||||
2. **D6 J08 alert SHIPPED.** `needsReviewCount` rides `GET /api/home/briefing`
|
||||
(personal-mind only, 200-frame bound matching the Memory Center's own window);
|
||||
Home banner deep-links via `waggle:open-app {appId:'memory', filter:'unreviewed'}`
|
||||
with a `?filter=` URL carrier + MemoryRoute cold-load re-stash (typed URLs and
|
||||
the §2.3 shim share one mechanism, AutomationsRoute pattern).
|
||||
3. **D3-4 extension:** WorkspaceDesktop revalidation arms only for the transient
|
||||
offline state — deterministic 404/403 states do not auto-refetch on focus.
|
||||
4. **Note (P1b-SSE follow-up):** the SSE ask above was ratified and SHIPPED as a
|
||||
P1b follow-up (PR #15, main @ 4e3d65d) — closed before P2 started.
|
||||
|
||||
---
|
||||
|
||||
## P3 implementation notes (D2 two-mind Memory Center, 2026-06-11)
|
||||
|
||||
Recorded per the single-decision-log rule; full design + live-run findings in
|
||||
`docs/ux-refactor/p3-memory-center-plan.md`.
|
||||
|
||||
1. **D2 SHIPPED in full.** Standalone `MemoryCenterApp` (ArtifactCenterApp shape, fully
|
||||
controlled — URL is the only navigation authority): mind pills "About you" / "About this
|
||||
work · {ws}" on the Memories view; all six legacy MemoryApp views survive as secondary
|
||||
tabs (Timeline extracted verbatim to `memory/TimelineTab.tsx`; `MemoryApp.tsx` retired —
|
||||
capability preserved, entry restructured). `/memory/:mindScope` + `?tab=` implemented
|
||||
(conversion plan §5.3 #1-2 closed); `?filter=` J08 stash unchanged. S02-FR2 Memory part
|
||||
closed: WorkspaceDesktop memory tab embeds the per-mind list (`consumeDeepLinks=false` so
|
||||
the J08 stash stays with the /memory route).
|
||||
2. **Server contract (additive):** `GET /api/memory?mind=personal|workspace` selects one
|
||||
store; invalid mind or workspace-less `mind=workspace` is a 400 (a typo must not silently
|
||||
become the merge view); omitted mind keeps the legacy merge (pinned). Workspace-mind
|
||||
mutations now carry `workspace` from the FE — without it, PATCH/archive/delete/merge
|
||||
missed the workspace store entirely (404 class, fixed + pinned).
|
||||
3. **Cross-mind id-collision class:** per-mind SQLite autoincrements collide; the split makes
|
||||
every view single-mind (mutation ambiguity structurally gone from the new UI); selection +
|
||||
list clear on mind switch (cross-mind merge / stale-rows-under-wrong-pill pins). Full id
|
||||
namespacing remains post-launch.
|
||||
4. **Live-run defects fixed (pre-existing, surfaced by the mandatory smoke):**
|
||||
KnowledgeGraphViewer crashed the surface on untyped entities (54/214 real rows; fixed via
|
||||
single-entry node normalization, 'unknown' legend chip); Timeline duplicated React keys on
|
||||
cross-mind id 36 (fixed via mind-qualified keys).
|
||||
|
||||
---
|
||||
|
||||
## P4 implementation notes (D11 + D12 + clean-install onboarding, 2026-06-11)
|
||||
|
||||
Recorded per the single-decision-log rule; full record in
|
||||
`docs/ux-refactor/p4-launch-integrity-record.md`.
|
||||
|
||||
1. **D11 SHIPPED.** `resolveDataDir()` = option > `WAGGLE_DATA_DIR` > `~/.waggle` (split-brain with
|
||||
installer/marketplace/memory-mcp closed); the ratified one-line startup log
|
||||
`Data dir: <resolved> · tier: <effective>` via `readTierFromDataDir` (extracted; same
|
||||
config.json + getEffectiveTier contract as `GET /api/tier`); both stale SOLO comments fixed.
|
||||
Live-verified: env-pointed boot logged the tmp dir + tier FREE.
|
||||
2. **D12 SHIPPED — preferred shape (generation + untracking).** `service.js`/`.map` untracked +
|
||||
gitignored; `tauri.conf.json` `beforeBuildCommand` owns the full prep chain so a raw
|
||||
`npx tauri build` ships a CURRENT server (previously: the April copy). Dev mode unaffected
|
||||
(service.rs debug branch spawns service.ts via tsx). Pinned in tauri-config.test.ts.
|
||||
3. **S4 founder flag RESOLVED — the clean-install skip was REAL.** `ensureDefault()` at boot +
|
||||
the `getWorkspaces().length > 0` auto-complete evidence meant brand-new production users never
|
||||
saw the wizard. Fix: server-authoritative `GET /api/onboarding/status` (completion flag
|
||||
`<dataDir>/first-launch.flag` — same file as the Tauri IPC stamp — OR legacy evidence: any
|
||||
personal-mind frame / >1 workspaces; the seeded stub is NOT evidence) +
|
||||
`POST /api/onboarding/complete` stamped from `useOnboarding.update()` on completion. Fail
|
||||
direction: toward showing the wizard. Live-verified clean dataDir → `completed:false`.
|
||||
Accepted edge: a pre-flag returning user with zero frames + only the default workspace re-sees
|
||||
the wizard once (no durable signal can distinguish them; class dies as flags stamp).
|
||||
4. **FREE→Upgrade e2e re-ran:** Act 4 Tier Wall 6/6 on a fresh FREE install under
|
||||
`WAGGLE_TRUST_LOCALHOST=1`; the unauthenticated first run's 3 failures are the documented
|
||||
dock-era-spec-vs-P1b-bearer-gate class — spec-side token wiring stays ledgered with the P7 e2e
|
||||
band.
|
||||
5. **Two-round adversarial review (19 confirmed total / 34 refuted) — all confirmed findings
|
||||
fixed,** headlined by: a HIGH in P4's own first cut (the D12 hook re-ran arch-parameterized
|
||||
bundle scripts arch-blind — cross-arch macOS release legs would ship a non-launching Intel DMG;
|
||||
hook trimmed to the arch-independent sidecar bundle + a fail-loud resources preflight); a
|
||||
verified MED chain where the wizard's own step-1 profile write counted as returning-user
|
||||
evidence (server-durable PENDING latch added — only explicit completion flips status once a
|
||||
dataDir is identified as un-onboarded); the Tauri fs-flag now honors `WAGGLE_DATA_DIR` (Rust)
|
||||
so the IPC fast-path and the server stamp share one file on every install shape; and the
|
||||
sidecar bundle now compiles `@waggle/shared`/`@waggle/hive-mind-core` from SOURCE (esbuild
|
||||
alias — the regenerated bundle used to embed stale gitignored dist silently). Full dispositions:
|
||||
`docs/ux-refactor/p4-launch-integrity-record.md`.
|
||||
202
docs/ux-refactor/deltas/rbac-security-delta.md
Normal file
202
docs/ux-refactor/deltas/rbac-security-delta.md
Normal file
@@ -0,0 +1,202 @@
|
||||
# RBAC / Security / Audit Delta — Waggle OS UX Refactor
|
||||
|
||||
**Scope:** PRD §17 (RBAC & Permissions) + §18 (Security, Privacy, Compliance) + Blueprint "Architecture Package 8: Security Model".
|
||||
**Execution model:** in-place incremental refactor of `apps/web` + targeted backend extensions (locked). Reuse `install-audit`, `ai_interactions`, `audit_events`, `teams.db`, `confirmation.ts`, `trust-model.ts`, `capability-governance`.
|
||||
**Grounding:** every claim cites a real file/line. Backend-map sections 03c (workspace/team) and 03e (evolution/governance) are the contract reference.
|
||||
|
||||
---
|
||||
|
||||
## 0. TL;DR for the planner
|
||||
|
||||
The security substrate is **substantially built on the agent/runtime side and the local sidecar**, but the RBAC story is **split across two incompatible planes** and the UI surfaces barely exist.
|
||||
|
||||
| Capability | Built? | Where |
|
||||
|---|---|---|
|
||||
| Tool approval gate (write/destructive/connector) | ✅ Strong | `packages/agent/src/confirmation.ts` |
|
||||
| Tiered autonomy (normal/trusted/yolo) | ✅ | `confirmation.ts` `needsConfirmationWithAutonomy` |
|
||||
| Approval inbox + persistent grants | ✅ | `chat.ts` + `/api/approval/*` (03e §8) |
|
||||
| Risk/trust classification for installs | ✅ | `packages/agent/src/trust-model.ts` |
|
||||
| Install audit trail (append-only-ish) | ⚠️ Real table, **NOT** trigger-protected | `packages/core/src/install-audit.ts` |
|
||||
| AI interaction audit (append-only, EU AI Act) | ✅ Trigger-protected | `compliance/interaction-store.ts` + schema triggers |
|
||||
| Generic action audit (`audit_events`) | ⚠️ Real, **NOT** trigger-protected | `local/routes/events.ts` |
|
||||
| RBAC role model (Owner/Admin/Member/Viewer) | ⚠️ **Two** divergent impls | `local/routes/team.ts` vs `routes/capability-governance.ts` |
|
||||
| RBAC role **Guest** | ❌ Not in any schema | — |
|
||||
| RBAC enforced at API layer | ⚠️ Local: ad-hoc per route; Cloud: `fastify.authenticate` | — |
|
||||
| RBAC UI (member mgmt, role matrix, audit views) | ❌ Effectively none | — |
|
||||
| Memory-import consent (preview → commit) | ✅ Backend; UI partial | `local/routes/harvest.ts` |
|
||||
|
||||
**Biggest risk:** the PRD's 5-role table (Owner/Admin/Contributor/Viewer + Blueprint's Guest) must be unified onto **one** role enum and **one** enforcement path. Today the local sidecar (`teams.db`) and the cloud Teams server (`capability-governance`) have separate role enums, separate role hierarchies, and separate enforcement primitives. Picking one is a §17 prerequisite, not a UI detail.
|
||||
|
||||
---
|
||||
|
||||
## 1. RBAC — current vs. required
|
||||
|
||||
### 1.1 PRD/Blueprint target
|
||||
|
||||
PRD §17.2 defines **Owner / Admin / Contributor / Viewer**. The Blueprint security model (line 156) and acceptance criteria (line 603) instead say **Owner / Admin / Member / Viewer / Guest**. These two source documents **disagree on role names** ("Contributor" vs "Member") and on whether "Guest" exists. PRD §24 (mockups directional) plus "PRD acceptance criteria win" means: the implementation must reconcile to a single enum. Recommendation: adopt the Blueprint 5-role set **Owner/Admin/Member/Viewer/Guest** because it is the superset and is already partly encoded in the local schema; map PRD "Contributor" → "Member".
|
||||
|
||||
PRD §17.3 permission principles (must hold):
|
||||
- Agents inherit **minimum** permissions of assigned scope.
|
||||
- MCPs require explicit scope (personal/workspace/team).
|
||||
- Connectors require consent + revocation path.
|
||||
- Automations only run actions allowed by the user/team role.
|
||||
- Shared memories/artifacts display scope + access.
|
||||
- **Elevated actions require human approval.**
|
||||
|
||||
### 1.2 What exists — TWO RBAC planes
|
||||
|
||||
**Plane A — Local sidecar (`teams.db`), the one the desktop frontend actually hits.**
|
||||
`packages/server/src/local/routes/team.ts`:
|
||||
- Schema (lines 61–73): `team_members.role CHECK (role IN ('owner','admin','member','viewer'))`. **No `guest`.**
|
||||
- Enforcement is **ad-hoc, inline, per-route** (not middleware):
|
||||
- Update team → owner/admin (line 532)
|
||||
- Delete team → **owner only** (line 558)
|
||||
- Add member → owner/admin (line 591)
|
||||
- Change role → **owner only** on `PUT` (line 624); owner/admin on `PATCH` (line 650) — *PRD note: PUT/PATCH divergence is a real inconsistency*
|
||||
- Remove member → owner/admin (anyone) or self; **never the owner** (lines 677–684)
|
||||
- Identity is a **single local user** (`getLocalUserId` → `'local-user'`, line 85–92). There is no real multi-user auth on this plane — it is loopback-trust (backend-map 03c §5: "No auth header").
|
||||
|
||||
**Plane B — Cloud Teams server (`fastify.db`, Postgres-style), reached only via team-server proxy.**
|
||||
`packages/server/src/routes/capability-governance.ts`:
|
||||
- `ROLE_HIERARCHY = { member:1, admin:2, owner:3 }` (lines 6–10) — **numeric hierarchy, no viewer, no guest.**
|
||||
- Real auth: every route has `preHandler: [fastify.authenticate]` and uses `request.userId`.
|
||||
- `resolveTeam` checks membership → 403 "Not a member" (line 27–31); `requireAdmin` gates writes (line 36–43).
|
||||
- This is where **capability policies / overrides / requests** live (per-role `allowedSources`, `blockedTools`, `approvalThreshold`) — the actual "Admin can install within policy" mechanism from PRD §17.2. Surfaced to the local app **read-only** via `GET /api/team/governance/permissions` (tier-gated ENTERPRISE, `team.ts` line 418).
|
||||
|
||||
> **Delta:** the two planes have **three** different role vocabularies (`owner/admin/member/viewer`, `member/admin/owner`, and the PRD's `Owner/Admin/Contributor/Viewer`), none of which has `Guest`. None enforce at a shared middleware. The capability-policy engine (the richest RBAC primitive) is cloud-only and the local app can only *read* it.
|
||||
|
||||
### 1.3 What must be built
|
||||
|
||||
1. **Single role enum** in `@waggle/shared` (`type TeamRole = 'owner'|'admin'|'member'|'viewer'|'guest'`). Migrate the `teams.db` CHECK constraint to add `guest`; add an explicit role→capability matrix matching PRD §17.2 (view/create/share/manage-people/install/manage-security columns).
|
||||
2. **Shared enforcement helper** (`requireRole(min)` / `can(action, role, scope)`) used by both `local/routes/team.ts` (replace inline checks) and the cloud routes. Resolve the PUT/PATCH role-change divergence to one rule.
|
||||
3. **Viewer/Guest read-only enforcement** — today `READONLY_TOOLS` + `PermissionManager.sandbox()` (`packages/agent/src/permissions.ts` lines 4–27) exist to lock an *agent* to read-only; reuse this primitive so a Viewer/Guest **session** assembles a sandboxed tool pool. This is the cleanest reuse: `isReadOnly` persona flag + role-driven `PermissionManager` whitelist.
|
||||
4. **RBAC UI** (PRD §11.x Team Workspace, §20.3 "RBAC/Audit components"): member list with role dropdown (POST/PUT/PATCH/DELETE `/api/teams/:id/members*` already exist — 03c §1.3), invite flow (J13), "request access" on permission-denied (Blueprint J21, line 240), and the **role→capability matrix** as a readable table. None of this UI exists today.
|
||||
|
||||
---
|
||||
|
||||
## 2. Approval / consent gating — current vs. required
|
||||
|
||||
This is the **strongest** existing area. PRD §17.3 "elevated actions require human approval" and §18.1 "approval class for elevated/critical capabilities" are largely satisfied at runtime; the gap is UI consistency and a couple of surface flows.
|
||||
|
||||
### 2.1 The runtime approval gate (built)
|
||||
|
||||
`packages/agent/src/confirmation.ts`:
|
||||
- `needsConfirmation(toolName, args)` (line 73) — gates writes (`write_file`, `edit_file`, git push/commit/pr/merge, `install_capability`, cross-workspace reads — `ALWAYS_CONFIRM` line 13), connector **writes** (name-derived, never trusts LLM args — line 76), and destructive bash (`DESTRUCTIVE_BASH_PATTERNS` line 35 + chain-operator bypass defense line 66).
|
||||
- `getApprovalClass()` (line 122) → `standard|elevated|critical`.
|
||||
- `needsConfirmationWithAutonomy(tool, args, level)` (line 224) — tiered autonomy: `normal|trusted|yolo` with a **critical-never-autopass blacklist** (`isCriticalNeverAutopass`, line 192) that holds even at YOLO (`rm -rf /`, `sudo`, force-push to main, etc.).
|
||||
|
||||
### 2.2 How it hooks into the loop (built)
|
||||
|
||||
`packages/server/src/local/routes/chat.ts` registers a **per-request `pre:tool` hook** (line 881):
|
||||
- Reads effective `autonomyLevel` from permission settings (with expired-grant fallback to `normal`, line 363).
|
||||
- `needsConfirmationWithAutonomy` decides; auto-pass at trusted/yolo emits `approval_auto` audit (line 902).
|
||||
- **Persistent grants:** `server.agentState.approvalGrantStore.has(tool, args, workspaceId)` (line 921) silently resolves previously "always allowed" `(tool, args, sourceWorkspaceId)` triples.
|
||||
- Otherwise: computes a `trust` assessment, sends an `approval_required` SSE event (line 959) with `approvalClass`, parks the call in `server.agentState.pendingApprovals` (line 975), and **audits** `approval_requested` / `approval_granted` / `approval_denied` (lines 967, 994, 998).
|
||||
- Inbox + grants API: `/api/approval/:requestId`, `/api/approval/pending`, `/api/approval/grants*` (backend-map 03e §8).
|
||||
|
||||
> The approval/consent flow for **agent elevated actions** (PRD Journey 15, Blueprint J21) is therefore **fully wired backend-side**. The reusable hook point for the new UI is the `approval_required` SSE event + `GET /api/approval/pending` on reconnect.
|
||||
|
||||
### 2.3 The three PRD consent flows — where each hooks
|
||||
|
||||
| PRD consent flow | Backend status | Hook point | UI delta |
|
||||
|---|---|---|---|
|
||||
| **Memory import** (no import without review/approval — §18.2, J01/J08) | ✅ Two-phase exists: `POST /api/harvest/preview` → `POST /api/harvest/commit` (`local/routes/harvest.ts` lines 1–9; preview cap line 49). Identity suggestions stage to profile awaiting review (`IdentitySuggestion`, 03c §2.10). | preview/commit split + `harvest_sources` provenance | **Memory Review screen** (PRD §12.12 step 5) must render preview diff + per-item approve/edit/reject before calling commit. Low-confidence review queue (J08) needs the confidence fields PRD §15.4 recommends adding. |
|
||||
| **Connector / MCP install** (consent + revocation — §17.3, J10/J11) | ✅ Risk classified by `trust-model.ts` `assessTrust` (line 318) → `riskLevel/approvalClass/permissions`. Install writes audit via `server.auditStore.record(...)` (marketplace.ts lines 224–308; skills.ts 212/315/475). Approval routed through the §2.2 gate (`install_capability` is in `ALWAYS_CONFIRM`). | `auditStore.record` + approval gate + `getApprovalClass` | **Connector Hub / MCP Hub install modal** (PRD §12.7/§12.8) must show the `TrustAssessment` (risk badge, permission summary, source label via `formatTrustSummary` line 392) and a **revoke** action. Revoke endpoints exist (`/api/connectors/:id/revoke`, `/api/mcps/:id/revoke` — PRD §16.9) but the audit "revoked" action and UI are gaps. |
|
||||
| **Agent elevated action** (permission prompt — §17.3, J15) | ✅ Fully wired (§2.2). | `approval_required` SSE + `/api/approval/*` | **ApprovalModal** component (Blueprint line 488) — render `approvalClass`, tool + args, [Approve][Deny][Always allow]. Inbox view for `/api/approval/pending`. Today the approval UX is minimal/inline. |
|
||||
|
||||
### 2.4 What must be built (approval)
|
||||
|
||||
- **Unified ApprovalModal + Approvals Inbox** components consuming the existing SSE event + `/api/approval/*` + `/api/approval/grants*`. (Design-system component "ApprovalModal" is named in Blueprint line 488 but not implemented in the new IA.)
|
||||
- **Autonomy selector UI** wired to `GET/PUT /api/settings/permissions` (`defaultAutonomy: normal|trusted|yolo` — 03c §2.8) with per-workspace overrides surfaced.
|
||||
- **Revoke + "revoked" audit action** for connectors/MCPs (close the audit verb gap — `AuditAction` already includes `rejected/blocked` but not an explicit `revoked`; either add it or record as `rejected` with a detail).
|
||||
|
||||
---
|
||||
|
||||
## 3. Audit surfaces — current vs. required
|
||||
|
||||
PRD §18.1: "Append-only audit for AI interactions and sensitive actions." §18.3: "Audit logs should be immutable or append-only where feasible." There are **three distinct audit stores** today, with **inconsistent append-only guarantees**.
|
||||
|
||||
### 3.1 The three stores (all real, all SQLite)
|
||||
|
||||
| Store | Table | File | Append-only? | Purpose |
|
||||
|---|---|---|---|---|
|
||||
| **AI Interaction log** | `ai_interactions` (personal `.mind`) | `packages/core/src/compliance/interaction-store.ts` | ✅ **Yes** — `BEFORE UPDATE`/`BEFORE DELETE` triggers `RAISE(ABORT,...)` (`hive-mind-core/src/mind/schema.ts` lines 187–195) | EU AI Act Art. 12: model/provider/tokens/cost/tools/**inputText/outputText**/humanAction/riskContext/persona. |
|
||||
| **Install audit** | `install_audit` (personal `.mind`) | `packages/core/src/install-audit.ts` | ⚠️ **No triggers** — `record()` is insert-only by convention but DELETE/UPDATE are not blocked; `clear()` exists (line 153) | Capability install trust trail: type/source/risk/trust_source/approval_class/action/initiator. |
|
||||
| **Action audit** | `audit_events` (`audit.db`) | `packages/server/src/local/routes/events.ts` | ⚠️ **No triggers** — `pruneAuditEvents` deletes by age (line ~168) | Generic events: `tool_call`, `memory_write/delete`, `workspace_*`, `session_*`, `approval_*`, `export`, `cron_trigger`, `data_erase_requested` (lines 21–37). |
|
||||
|
||||
### 3.2 Deltas vs PRD §18
|
||||
|
||||
1. **Append-only consistency.** PRD wants AI interactions **and** sensitive actions append-only. Only `ai_interactions` is trigger-protected. To honor §18.1, add `BEFORE UPDATE/BEFORE DELETE → RAISE(ABORT)` triggers (or a tombstone column) to `install_audit` and to the sensitive subset of `audit_events` (`approval_*`, `memory_delete`, `workspace_delete`, `export`, `data_erase_requested`). The `pruneAuditEvents` retention sweep must then be reconciled with "append-only" (retention vs immutability is a real tension — resolve per §18.3 "where feasible", likely a tombstone/archive rather than hard delete for the sensitive subset).
|
||||
2. **`install_audit` risk-level drift (latent bug).** The TS type `AuditRiskLevel` allows `'critical'` (install-audit.ts line 16) but the table `CHECK (risk_level IN ('low','medium','high'))` (line 65) **rejects** `'critical'`. Recording a critical install would throw. The file's own comment (lines 59–61) warns CHECK lists must stay in sync. **Fix before exposing the install-audit UI** (PRD §12.13, Sprint 7 "Install audit UI").
|
||||
3. **Audit-event `userId` is unpopulated** on the local plane (single-user model). For the team audit views (PRD §11.5, J13) the `user_id` column exists (events.ts line 43/72) but nothing fills it. Wiring real `userId` is blocked on the unified-auth decision (§1).
|
||||
|
||||
### 3.3 Audit read/export surfaces (built)
|
||||
|
||||
- `GET /api/admin/audit-export?format=json|csv&from=&to=` — **TEAMS-gated** (settings.ts line 484, 03c §1.5). Reads `auditStore` (install_audit).
|
||||
- `GET /api/teams/:id/activity` — aggregates `audit_events` across a team's workspaces (team.ts line 690, 03c §1.3).
|
||||
- `GET /api/compliance/status` + `POST /api/compliance/export[-pdf]` — EU AI Act per-article report from `ai_interactions` (03e §5; `interaction-store.ts` `getOversightLog` line 144, `getModelInventory` line 116).
|
||||
- TeamSync **pushes** audit events to the cloud team server fire-and-forget (events.ts lines 132–143).
|
||||
|
||||
### 3.4 What must be built (audit UI)
|
||||
|
||||
- **Audit Views** (PRD §11.5/§20.3, Blueprint "export audit" J24 line 249): a unified activity/audit feed that merges the three stores by scope (workspace/team) with filters (event type, actor, date) and CSV/PDF export buttons calling the existing endpoints. The data is there; the read-model needs a thin normalizer because the three tables have different columns.
|
||||
- **Compliance app** surface (PRD §18.3, EU AI Act) — already has full backend (03e §5) incl. PDF; needs the per-article status cards + report-template CRUD UI.
|
||||
- **Right-to-delete UX** (§18.2 archive/delete memory; `data_erase_requested` event already defined) + telemetry clear (`DELETE /api/telemetry/events`, 03e §4).
|
||||
|
||||
---
|
||||
|
||||
## 4. Cross-cutting security deltas (PRD §18.1)
|
||||
|
||||
| §18.1 requirement | Status | Note |
|
||||
|---|---|---|
|
||||
| Local-first storage default | ✅ | All persistence local (SQLite/JSON), backend-map 03c §3. |
|
||||
| User-controlled sync/sharing | ⚠️ | Cloud-sync toggle TEAMS-gated (03c §1.5); per-object share (`POST /api/share`, PRD §16.11) UI absent. |
|
||||
| Workspace-level isolation | ✅ | Per-workspace `*.mind`; `crossWorkspaceHints` permanently disabled for privacy (03c §5). Cross-workspace tools are approval-gated (confirmation.ts line 17). |
|
||||
| Team RBAC | ⚠️ | Split planes — see §1. |
|
||||
| Connector/MCP install audit | ✅ | `install_audit` + `trust-model` (see §2.3, §3). |
|
||||
| Agent permission declarations | ⚠️ | Persona `tools`/`disallowedTools`/`isReadOnly` exist (CLAUDE.md §5); PRD §15.5 agent `permissions`/`memoryScopes` fields not yet a first-class persisted object. Agent Builder (PRD §12.9) must render+persist these. |
|
||||
| Append-only audit | ⚠️ | Only `ai_interactions` (see §3.2). |
|
||||
| Approval class for elevated/critical | ✅ | `getApprovalClass` / `trust-model` (§2). |
|
||||
| Clear revoke/delete/export | ⚠️ | Endpoints mostly exist; UI is the gap. |
|
||||
| Injection defense on external input | ✅ (must preserve) | `scanForInjection()` (CLAUDE.md §7.2) — connector/harvest input must keep calling it. |
|
||||
| Secrets vault-only, masked | ✅ | API keys → encrypted vault, masked on read (03c §2.7). |
|
||||
|
||||
---
|
||||
|
||||
## 5. Recommended build order (security slice of the refactor)
|
||||
|
||||
1. **Decide the auth/identity model** (single-user local vs. real multi-user). Everything in §1 and the `userId` audit gap blocks on this. Minimum-viable per PRD Open Question §23.7: keep loopback single-user locally; treat cloud Teams server as the multi-user authority; the local app **mirrors** roles from the cloud `capability-governance` policies (read path already exists).
|
||||
2. **Unify the role enum** in `@waggle/shared` (add `guest`; map Contributor→Member) + **shared `requireRole`/`can()` helper**; refactor `team.ts` inline checks and cloud routes onto it. Migrate `teams.db` CHECK.
|
||||
3. **Fix `install_audit` risk-level CHECK drift** (§3.2.2) before any install-audit UI.
|
||||
4. **Add append-only triggers** to `install_audit` + sensitive `audit_events` subset (§3.2.1), reconcile with retention.
|
||||
5. **Build shared security components** (Blueprint line 488): `ApprovalModal`, role→capability **matrix** table, `EvidencePanel`, audit-feed normalizer. Wire to existing endpoints.
|
||||
6. **Wire the three consent flows' UIs** (§2.3): Memory Review, Connector/MCP install-with-trust-assessment, Approvals Inbox.
|
||||
7. **Role-driven read-only sandbox** for Viewer/Guest sessions via the existing `PermissionManager.sandbox()` + `READONLY_TOOLS` primitive (§1.3.3).
|
||||
|
||||
---
|
||||
|
||||
## 6. Reuse map (don't rebuild)
|
||||
|
||||
| Need | Reuse | File |
|
||||
|---|---|---|
|
||||
| Tool approval decision | `needsConfirmation` / `needsConfirmationWithAutonomy` / `getApprovalClass` | `packages/agent/src/confirmation.ts` |
|
||||
| Install risk + permission summary | `assessTrust` / `formatTrustSummary` / `resolveTrustSource` | `packages/agent/src/trust-model.ts` |
|
||||
| Read-only lockdown | `PermissionManager.sandbox()` + `READONLY_TOOLS` | `packages/agent/src/permissions.ts` |
|
||||
| Install audit trail | `InstallAuditStore` | `packages/core/src/install-audit.ts` |
|
||||
| AI-interaction audit (append-only) | `InteractionStore` + schema triggers | `packages/core/src/compliance/interaction-store.ts`, `hive-mind-core/src/mind/schema.ts:187` |
|
||||
| Generic action audit | `emitAuditEvent` / `getAuditDb` | `packages/server/src/local/routes/events.ts` |
|
||||
| Local team RBAC CRUD | `teamRoutes` | `packages/server/src/local/routes/team.ts` |
|
||||
| Cloud capability governance (policies/overrides/requests) | `capabilityGovernanceRoutes` + `TeamCapabilityGovernance` | `packages/server/src/routes/capability-governance.ts` |
|
||||
| Approval inbox + grants | `pendingApprovals` map + `approvalGrantStore` + `/api/approval/*` | `packages/server/src/local/routes/chat.ts` + `approval.ts` |
|
||||
| Memory-import consent | `harvest/preview` → `harvest/commit` | `packages/server/src/local/routes/harvest.ts` |
|
||||
| EU AI Act compliance report | `ComplianceStatusChecker` / `ReportGenerator` | `packages/core/src/compliance/*` |
|
||||
|
||||
---
|
||||
|
||||
## 7. Open questions for the founder/PM
|
||||
|
||||
1. **Role name reconciliation:** confirm Owner/Admin/**Member**/Viewer/Guest (Blueprint superset) over PRD §17.2's "Contributor". (Recommended.)
|
||||
2. **Identity model (§23.7):** single-user-local + cloud-authoritative-multi-user, or real local accounts? Gates the audit `userId` and §1 enforcement.
|
||||
3. **Append-only vs retention (§18.3):** for the sensitive `audit_events` subset, hard append-only (no prune) or tombstone-on-prune? EU buyers will ask.
|
||||
4. **Guest scope:** Blueprint says "limited shared artifacts/memory; no agents/MCP" — confirm Guest gets a `PermissionManager.sandbox()` read-only session.
|
||||
5. **Capability-policy reach:** should the rich cloud policy engine (allowedSources/blockedTools/approvalThreshold per role) be brought down to the **local** plane, or stay cloud-only with the local app reading it (current state)?
|
||||
418
docs/ux-refactor/deltas/shared-types-delta.md
Normal file
418
docs/ux-refactor/deltas/shared-types-delta.md
Normal file
@@ -0,0 +1,418 @@
|
||||
# Shared Types Delta — UX Refactor
|
||||
|
||||
> Source of truth: PRD §15.2-15.6 (`docs/Waggle_OS_UX_Refactor_Master_Handoff_Package/Waggle_OS_UX_Refactor_PRD.md:942-1056`).
|
||||
> Grounded against `apps/web/src/lib/types.ts`, `packages/shared/src/types.ts`, `packages/shared/src/mcp-catalog.ts`,
|
||||
> `packages/hive-mind-core/src/mind/frames.ts`, and `docs/ux-refactor/_inventory/substrate-types.md`.
|
||||
> Execution model is **in-place incremental refactor**: extend existing types, do not replace. NEW vs MODIFY is
|
||||
> called out per type, with the current type cited.
|
||||
|
||||
---
|
||||
|
||||
## 0. Placement policy (where each type lives)
|
||||
|
||||
Two TS surfaces matter:
|
||||
|
||||
- **`packages/shared/src/types.ts`** — server/sidecar + cross-package domain types. Already holds `User`, `Team`,
|
||||
`AgentDef`, `Task`, `WaggleMessage`, `ConnectorDefinition`, `ConnectorHealth` (`packages/shared/src/types.ts:4-313`).
|
||||
Anything the **sidecar route layer must produce/persist** (entities, API payload shapes, RBAC) goes here so the
|
||||
server (`packages/server/src/local/routes/*`) and the FE import one definition.
|
||||
- **`apps/web/src/lib/types.ts`** — FE display/view-model types. Already holds `Workspace`, `MemoryFrame`,
|
||||
`Persona`, `SkillPack`, `CronJob`, `Connector` (`apps/web/src/lib/types.ts:22-336`). These are intentionally
|
||||
**lossy projections** of the persisted shapes (substrate-inventory §(e), `_inventory/substrate-types.md:233-237`).
|
||||
|
||||
**Rule for this delta:**
|
||||
1. The PRD §15.2 literal **enums/unions** are domain vocabulary → **`packages/shared`** (single source), then
|
||||
re-exported / imported by the FE. Avoid duplicating the union string lists in two files (drift risk —
|
||||
precedent: the `FrameSource` TS-vs-DB drift, `_inventory/substrate-types.md:120-121`).
|
||||
2. **Persisted entity shapes** (WorkspaceConfigV2, Agent, Artifact, Skill, Automation, MCP) → **`packages/shared`**
|
||||
(server owns persistence; `WorkspaceConfig` itself currently lives in
|
||||
`packages/hive-mind-core/src/workspace-manager.ts:5-58`, not shared — see §1 note).
|
||||
3. **FE view-models** that the screens actually render → **`apps/web/src/lib/types.ts`**, built FROM the shared
|
||||
entity (e.g. FE `Memory` adds derived `relevance`/UI flags). Where a FE thin type already exists
|
||||
(`SkillPack`, `Connector`, `Persona`, `CronJob`), MODIFY it rather than add a parallel type.
|
||||
|
||||
`@waggle/shared` is already imported by the FE (it ships `ConnectorDefinition` etc.), so importing shared enums into
|
||||
`apps/web` is an existing, supported path.
|
||||
|
||||
---
|
||||
|
||||
## 1. §15.2 Enums / literal unions — **ALL NEW** → `packages/shared/src/types.ts`
|
||||
|
||||
None of these exist in either FE or shared today (`_inventory/substrate-types.md:218-229`). Add as a new
|
||||
`// === UX-Refactor vocabulary (PRD §15.2) ===` block in `packages/shared/src/types.ts`. Use string-literal unions
|
||||
(repo rule: prefer unions over `enum`, `rules/typescript/coding-style.md`).
|
||||
|
||||
```ts
|
||||
// === UX-Refactor vocabulary (PRD §15.2) ===
|
||||
export type WorkspaceType =
|
||||
| 'project' | 'client' | 'research' | 'personal' | 'team' | 'organization';
|
||||
export type Scope = 'personal' | 'workspace' | 'team' | 'organization';
|
||||
export type Confidence = number; // 0-100
|
||||
|
||||
export type MemoryKind =
|
||||
| 'fact' | 'decision' | 'task' | 'preference'
|
||||
| 'strategy' | 'learning' | 'goal' | 'entity';
|
||||
export type ArtifactKind =
|
||||
| 'document' | 'presentation' | 'spreadsheet' | 'dashboard'
|
||||
| 'research' | 'code' | 'media' | 'design' | 'other';
|
||||
export type AgentType = 'personal' | 'workspace' | 'team' | 'autonomous';
|
||||
export type AutonomyLevel = 'manual' | 'guided' | 'medium' | 'high';
|
||||
export type ExtensionType =
|
||||
| 'skill' | 'connector' | 'mcp' | 'model' | 'template' | 'external_tool';
|
||||
```
|
||||
|
||||
**Consumed by screens:** `WorkspaceType` → Workspace Desktop header + switcher (§12.2). `Scope` → Memory Center
|
||||
tabs/filters, MCP scope, Team sharing (§12.4, §12.8, §12.11, §17.1). `Confidence` → Memory confidence badge
|
||||
(§12.4, §19.1). `MemoryKind` → Memory Center type filter (§12.4). `ArtifactKind` → Artifact Center categories
|
||||
(§12.5). `AgentType` → Agent Center categories (§12.9). `AutonomyLevel` → Agent Builder (§12.9). `ExtensionType`
|
||||
→ Ctrl+K "Extend" section + Extend/Marketplace (§12.3, §12.7-12.8).
|
||||
|
||||
> **Drift watch:** `MemoryKind` OVERLAPS but does not match the existing FE `MemoryFrame.type`
|
||||
> (`apps/web/src/lib/types.ts:120` = `'fact'|'event'|'insight'|'decision'|'task'|'entity'`) and the DB `frame_type`
|
||||
> (`I|P|B`, an orthogonal axis — `_inventory/substrate-types.md:128`). Do NOT delete FE `type`; map it. The
|
||||
> backend has no `kind` column today — `kind` is heuristically derived
|
||||
> (`packages/server/src/local/routes/workspace-state.ts:82-111`) and lands in `metadata` per §3.
|
||||
|
||||
---
|
||||
|
||||
## 2. §15.3 `WorkspaceConfigV2` — MODIFY (two layers)
|
||||
|
||||
### 2a. Persisted config — MODIFY `WorkspaceConfig`
|
||||
**Current:** `WorkspaceConfig` in `packages/hive-mind-core/src/workspace-manager.ts:5-58` (the `workspace.json`
|
||||
shape). It already carries `id, name, group, icon, model, personaId, templateId, tools, skills, storageType,
|
||||
storagePath, teamId, teamRole, riskLevel, created` (full mapping: `_inventory/substrate-types.md:18-42`).
|
||||
|
||||
**7 additive optional fields needed** (all JSON-file, NO DB migration — `_inventory/substrate-types.md:49-55`):
|
||||
`description?`, `type` (`WorkspaceType`), `status` (`'active'|'paused'|'archived'`), `agentIds?`, `connectorIds?`,
|
||||
`mcpIds?`, `updatedAt`, `lastActiveAt?`. Also extend `CreateWorkspaceOptions`
|
||||
(`workspace-manager.ts:60-95`) for `description/type`, and add two write-side touches: stamp `updatedAt` in
|
||||
`update()` (`workspace-manager.ts:222`), stamp `lastActiveAt` from the chat/agent loop.
|
||||
|
||||
Defaults for existing workspaces: `type` derivable from `templateId`/`group`; `status` defaults `'active'`.
|
||||
Keep all extra current fields (`personality`, `team`, `storageConfig`, `budget`, `tone`,
|
||||
`optimizationEnabled`, `riskClassifiedAt` — `_inventory/substrate-types.md:44-47`).
|
||||
|
||||
> **NEW shared alias:** export an `interface WorkspaceConfigV2` in `packages/shared/src/types.ts` matching PRD
|
||||
> §15.3 exactly, and have `workspace-manager.ts` `WorkspaceConfig extends WorkspaceConfigV2` (plus its legacy
|
||||
> extras). This gives the route layer the PRD contract type without moving the persistence struct.
|
||||
|
||||
### 2b. FE view-model — MODIFY `Workspace`
|
||||
**Current:** `Workspace` in `apps/web/src/lib/types.ts:22-40` — a lossy projection (`persona: string` not
|
||||
`personaId`; derived `hue/memoryCount/sessionCount/lastActive/health/budget/shared`;
|
||||
`_inventory/substrate-types.md:233-237`).
|
||||
|
||||
Add (optional, to stay backward-compatible with derived usage): `description?`, `type?: WorkspaceType`,
|
||||
`status?: 'active'|'paused'|'archived'`, `agentIds?: string[]`, `connectorIds?: string[]`, `mcpIds?: string[]`,
|
||||
`updatedAt?: string`. Keep `persona`; optionally add `personaId?` and migrate consumers. Import `WorkspaceType`
|
||||
from `@waggle/shared`.
|
||||
|
||||
**Consumed by:** Home Cockpit workspace cards (§12.1), Workspace Desktop header + right panel (§12.2),
|
||||
Workspace switcher (§19.1).
|
||||
|
||||
---
|
||||
|
||||
## 3. §15.4 Memory with confidence/provenance — MODIFY FE + NEW shared + backend metadata
|
||||
|
||||
### 3a. Backend storage — metadata-first (one migration)
|
||||
`memory_frames` has **NO `metadata` column** and no `confidence/kind/title/tags/scope/sourceId/sourceUrl/
|
||||
status/updatedAt` (`_inventory/substrate-types.md:125-164`). PRD §15.4 endorses metadata-first
|
||||
(PRD:1013). Lowest-risk: one additive `ALTER TABLE memory_frames ADD COLUMN metadata TEXT NOT NULL DEFAULT '{}'`
|
||||
(idempotent ADD-COLUMN pattern already used for `source` — `packages/hive-mind-core/src/mind/db.ts:116-124`),
|
||||
storing `{kind, title, scope, sourceId, sourceUrl, confidence, tags, evidence, relatedMemoryIds,
|
||||
relatedArtifactIds, status}` as JSON. Promote `confidence REAL` to a real indexed column later IF it becomes a
|
||||
primary filter axis (§12.4 "filter by confidence"). Existing columns map directly: `content`→`content`,
|
||||
`created_at`→`createdAt`, `last_accessed`→`lastAccessedAt`, `importance`→`importance`, `source`→`source`.
|
||||
|
||||
### 3b. NEW shared `Memory` entity → `packages/shared/src/types.ts`
|
||||
The route layer normalizes the DB row + `metadata` into the PRD shape (current normalizer is
|
||||
`normalizeFrame`, `packages/server/src/local/routes/memory.ts:230`). Define the contract type once:
|
||||
|
||||
```ts
|
||||
export interface Memory {
|
||||
id: string;
|
||||
kind: MemoryKind;
|
||||
title: string;
|
||||
content: string;
|
||||
scope: Scope;
|
||||
workspaceId?: string;
|
||||
teamId?: string | null;
|
||||
source: string; // provenance class — maps from frames.source (FrameSource)
|
||||
sourceId?: string | null;
|
||||
sourceUrl?: string | null; // PRD "sourceUrl/path"
|
||||
confidence?: Confidence; // 0-100
|
||||
importance: 'critical' | 'important' | 'normal' | 'temporary' | 'deprecated';
|
||||
evidence?: string[];
|
||||
tags?: string[];
|
||||
relatedMemoryIds?: string[];
|
||||
relatedArtifactIds?: string[];
|
||||
status: 'active' | 'low_confidence' | 'conflict' | 'deprecated' | 'archived' | 'trash';
|
||||
createdAt: string;
|
||||
updatedAt?: string;
|
||||
lastAccessedAt?: string;
|
||||
}
|
||||
```
|
||||
`importance` reuses the existing `Importance` union from `frames.ts:20`. `source` stays a string keyed off
|
||||
`FrameSource` (`frames.ts:21`) rather than re-declaring the enum (avoid the existing TS-vs-DB drift). `status`
|
||||
enumerates the §12.4 Memory states (PRD:504-513) — superset of `importance='deprecated'`.
|
||||
|
||||
### 3c. FE view-model — MODIFY `MemoryFrame` (or add `Memory`)
|
||||
**Current:** `MemoryFrame` in `apps/web/src/lib/types.ts:118-127` (`id/type/title/content/importance:number/
|
||||
timestamp/workspaceId/metadata?`). It does NOT match what `/api/memory/frames` returns — a real FE/BE
|
||||
mismatch to reconcile (`_inventory/substrate-types.md:239-247`).
|
||||
|
||||
Recommended: introduce FE `interface Memory` aligned to the shared `Memory` (import the shared type and add
|
||||
only FE-derived display fields, e.g. `relevance?: number`). Keep `MemoryFrame` temporarily for back-compat,
|
||||
then migrate Memory Center components off it. Do NOT silently widen `MemoryFrame.type`.
|
||||
|
||||
**Consumed by:** Memory Center cards/detail/filters (confidence badge, source/evidence chips, status states,
|
||||
graph) — §12.4, §19.1. Home Cockpit "memory highlights" (§12.1). Workspace Desktop memory widget (§12.2).
|
||||
|
||||
---
|
||||
|
||||
## 4. §15.6 Artifact — **NEW everywhere** (largest gap)
|
||||
|
||||
No `Artifact` type, no artifacts table, no `/api/artifacts*` routes — entirely greenfield
|
||||
(`_inventory/substrate-types.md:259-266`). Closest existing is `FileEntry` (`apps/web/src/lib/types.ts:42-50`),
|
||||
a raw filesystem entry, NOT an outcome object with relations — do NOT overload it.
|
||||
|
||||
### 4a. NEW shared `Artifact` → `packages/shared/src/types.ts`
|
||||
```ts
|
||||
export type ArtifactStatus = 'draft' | 'ready' | 'in_review' | 'final' | 'archived';
|
||||
|
||||
export interface Artifact {
|
||||
id: string;
|
||||
title: string;
|
||||
kind: ArtifactKind;
|
||||
workspaceId: string;
|
||||
teamId?: string | null;
|
||||
createdBy: string;
|
||||
source: string; // agent | user | import | automation
|
||||
status: ArtifactStatus;
|
||||
mimeType?: string;
|
||||
storagePath?: string;
|
||||
previewUrl?: string;
|
||||
tags?: string[];
|
||||
relatedMemoryIds?: string[];
|
||||
relatedSessionIds?: string[];
|
||||
relatedTaskIds?: string[];
|
||||
relatedAgentIds?: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
```
|
||||
Backend: NEW `artifacts` table in `packages/hive-mind-core/src/mind/schema.ts` (keep the two-place DDL-sync
|
||||
discipline noted for `install_audit`, `_inventory/substrate-types.md:171-172`) + NEW `/api/artifacts/*` routes
|
||||
(PRD §16.6).
|
||||
|
||||
### 4b. FE — NEW `Artifact` view-model → `apps/web/src/lib/types.ts`
|
||||
Import or re-shape the shared `Artifact`. **Consumed by:** Artifact Center grid/detail panel + cross-object
|
||||
"Germany GTM" search (§12.5, acceptance criteria PRD:532); Workspace Desktop "key artifacts" widget (§12.2);
|
||||
Ctrl+K Search results (§12.3); `relatedArtifactIds` on Memory (§3) and Agent (§5).
|
||||
|
||||
---
|
||||
|
||||
## 5. §15.5 Agent — MODIFY shared `AgentDef` + NEW FE `Agent`
|
||||
|
||||
### 5a. Shared — MODIFY `AgentDef`
|
||||
**Current:** `AgentDef` in `packages/shared/src/types.ts:36-47` (`id, userId, teamId, name, role, systemPrompt,
|
||||
model, tools, config, createdAt`). MISSING vs §15.5: `type, goal, description, personaId, autonomyLevel,
|
||||
workspaceIds, memoryScopes, skillIds, connectorIds, mcpIds, permissions, status, lastRunAt, successRate`
|
||||
(`_inventory/substrate-types.md:249-257`).
|
||||
|
||||
Add as optional fields (keep `userId/role/systemPrompt/config` — existing callers depend on them):
|
||||
```ts
|
||||
type?: AgentType;
|
||||
goal?: string;
|
||||
description?: string;
|
||||
personaId?: string;
|
||||
autonomyLevel?: AutonomyLevel;
|
||||
workspaceIds?: string[];
|
||||
memoryScopes?: Scope[];
|
||||
skillIds?: string[];
|
||||
connectorIds?: string[];
|
||||
mcpIds?: string[];
|
||||
permissions?: string[];
|
||||
status?: 'idle' | 'running' | 'paused' | 'error' | 'archived';
|
||||
lastRunAt?: string;
|
||||
successRate?: number; // 0-1; derivable from execution_traces.outcome (schema.ts:206) / procedures.success_rate (schema.ts:147)
|
||||
```
|
||||
`type/autonomyLevel/memoryScopes` import from the §1 unions (same file). Backend: agents are not yet a
|
||||
first-class persisted entity with these fields — `/api/agents/*` CRUD+run is net-new (PRD §16.7,
|
||||
`_inventory/substrate-types.md:283`).
|
||||
|
||||
### 5b. FE — NEW `Agent` view-model → `apps/web/src/lib/types.ts`
|
||||
The FE today has only thin `Persona` (`:256-272`) and `AgentStatus` (`:249-254`) — no full Agent entity.
|
||||
Add an `Agent` view-model (import the extended `AgentDef`, or a FE projection of it) carrying the card fields
|
||||
the screens render: goal, status, owner, workspace, capabilities, model, successRate, lastRun.
|
||||
|
||||
**Consumed by:** Agent Center cards/categories + Agent Builder steps (§12.9); Workspace Desktop status bar
|
||||
"agents running" (§12.2); Home Cockpit (§12.1); FleetSession already partially covers runtime
|
||||
(`apps/web/src/lib/types.ts:220-228`).
|
||||
|
||||
---
|
||||
|
||||
## 6. §12.6 Skill — MODIFY FE `SkillPack` (or add `Skill`)
|
||||
|
||||
PRD §15.2 has no standalone Skill interface, but §12.6 enumerates skill object fields explicitly: `name,
|
||||
description, category, instructions, inputs, outputs, tools/data, memory access, owner, status, usage,
|
||||
last used` (PRD:541).
|
||||
|
||||
**Current:** FE `SkillPack` (`apps/web/src/lib/types.ts:210-218`: `id, name, description, category, skills[],
|
||||
installed, trust`) — a marketplace *pack*, not a single authored skill. Backend anchor is `ParsedSkill`/
|
||||
`SkillFrontmatter` (`packages/agent/src/skill-frontmatter.ts:53-56`).
|
||||
|
||||
Recommended: NEW `interface Skill` (don't overload the pack) → place the entity in `packages/shared` (so
|
||||
`/api/skills/*` CRUD, PRD §16.8, can produce it), FE view-model in `apps/web/src/lib/types.ts`:
|
||||
```ts
|
||||
export interface Skill {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
category: string;
|
||||
instructions?: string;
|
||||
inputs?: string[];
|
||||
outputs?: string[];
|
||||
tools?: string[]; // "tools/data"
|
||||
memoryScopes?: Scope[]; // "memory access"
|
||||
owner?: string;
|
||||
status: 'draft' | 'active' | 'archived';
|
||||
usageCount?: number;
|
||||
lastUsedAt?: string;
|
||||
trust?: 'verified' | 'community' | 'experimental'; // reuse SkillPack.trust vocabulary
|
||||
}
|
||||
```
|
||||
Keep `SkillPack` for the marketplace-pack grouping; relate via `SkillPack.skills: string[]` → `Skill.id`.
|
||||
**Consumed by:** Skills Hub tabs + Skill Builder (§12.6); Agent Builder skill assignment (§12.9); Ctrl+K "Run"
|
||||
(§12.3); Workspace `skills[]` (§2).
|
||||
|
||||
---
|
||||
|
||||
## 7. §12.10 Automation — MODIFY FE `CronJob` → NEW `Automation`
|
||||
|
||||
PRD has no §15 Automation interface, but §12.10 lists fields: `name, trigger, condition, actions, agent,
|
||||
notification, schedule, workspace, status` (PRD:605).
|
||||
|
||||
**Current:** FE `CronJob` (`apps/web/src/lib/types.ts:230-238`: `id, name, schedule, workspaceId, enabled,
|
||||
lastRun, nextRun`) — schedule-only, no trigger/condition/actions. Backend anchor is `CronSchedule`
|
||||
(`packages/shared/src/types.ts:162-174`) + `cron-store.ts`.
|
||||
|
||||
Recommended: NEW `interface Automation` superset of CronJob (cron is one trigger type). Entity in
|
||||
`packages/shared` (server owns `/api/automations/*`, PRD §16.10), FE view-model in `apps/web/src/lib/types.ts`:
|
||||
```ts
|
||||
export type AutomationTriggerType = 'schedule' | 'event' | 'manual';
|
||||
|
||||
export interface Automation {
|
||||
id: string;
|
||||
name: string;
|
||||
triggerType: AutomationTriggerType;
|
||||
schedule?: string; // cron expr when triggerType === 'schedule'
|
||||
condition?: string;
|
||||
actions: string[];
|
||||
agentId?: string;
|
||||
notify?: boolean;
|
||||
workspaceId: string;
|
||||
status: 'active' | 'paused' | 'running' | 'failed';
|
||||
lastRun?: string;
|
||||
nextRun?: string;
|
||||
}
|
||||
```
|
||||
Keep `CronJob` for the existing cron UI; `Automation` with `triggerType:'schedule'` projects onto it.
|
||||
**Consumed by:** Automation Center tabs + Automation Builder (§12.10); Home Cockpit overnight/attention
|
||||
(§12.1); Workspace Desktop status bar "automations active" (§12.2).
|
||||
|
||||
---
|
||||
|
||||
## 8. §12.7-12.8 Extension / Connector / MCP — MODIFY existing
|
||||
|
||||
### 8a. Connector — MODIFY FE `Connector`, reuse shared `ConnectorDefinition`
|
||||
**Current shared (rich, keep):** `ConnectorDefinition` + `ConnectorHealth` + `ConnectorCredential` +
|
||||
`ConnectorStatus` (`packages/shared/src/types.ts:249-313`) — already covers status, capabilities, category,
|
||||
substrate, tools, setupGuide, lastSync via health. **Current FE (thin):** `Connector`
|
||||
(`apps/web/src/lib/types.ts:280-285`: `id, name, type, status`).
|
||||
|
||||
Action: MODIFY the FE Connector Hub to consume the shared `ConnectorDefinition`/`ConnectorHealth` directly
|
||||
(the FE already imports `@waggle/shared`), rather than the 4-field `Connector`. Optionally add `lastSyncAt?`,
|
||||
`scope?: Scope` to `ConnectorHealth` for §12.7 "last sync" + §17.3 connector scope. **No new connector type
|
||||
needed** — this is a consumption switch, not a new shape.
|
||||
**Consumed by:** Connector Hub (§12.7), Ctrl+K Extend (§12.3), Workspace `connectorIds[]` (§2).
|
||||
|
||||
### 8b. MCP — NEW FE `McpInstance`, reuse shared `McpServer` catalog
|
||||
**Current:** `McpServer` catalog entry in `packages/shared/src/mcp-catalog.ts:17-28` (`id, name, description,
|
||||
author, category, url, installCmd, capabilities, official, logo`) — a *catalog* entry, not an *installed
|
||||
instance* with runtime state. §12.8 needs installed-instance fields: `version, status, connected to, last
|
||||
used, locality, risk, permissions, logs` (PRD:573).
|
||||
|
||||
Recommended: NEW `interface McpInstance` in `packages/shared` (installed-state, references catalog `id`):
|
||||
```ts
|
||||
export interface McpInstance {
|
||||
id: string; // catalog McpServer.id
|
||||
name: string;
|
||||
version?: string;
|
||||
status: 'installed' | 'running' | 'stopped' | 'error';
|
||||
scope: Scope; // "locality": personal/workspace/team (§17.3)
|
||||
connectedTo?: string[]; // workspace/agent ids
|
||||
riskLevel?: 'low' | 'medium' | 'high' | 'critical';
|
||||
permissions?: string[];
|
||||
lastUsedAt?: string;
|
||||
}
|
||||
```
|
||||
Install governance/audit already exists via `InstallAuditStore` + `AuditCapabilityType`
|
||||
(`packages/core/src/install-audit.ts:22` includes `mcp|connector|skill|marketplace`) — the Extend view needs a
|
||||
NEW `GET /api/extend/audit` read route (no write change; `_inventory/substrate-types.md:196-201`).
|
||||
**Consumed by:** MCP Hub (§12.8), Ctrl+K Extend (§12.3), Workspace `mcpIds[]` (§2).
|
||||
|
||||
> **Flag (latent, pre-existing):** `AuditRiskLevel` TS includes `'critical'` but both DDL CHECKs allow only
|
||||
> `low|medium|high` (`install-audit.ts:65`, `schema.ts:130`) — a `record({riskLevel:'critical'})` throws.
|
||||
> `McpInstance.riskLevel` above includes `'critical'`; if it ever writes to audit, fix the CHECK first
|
||||
> (`_inventory/substrate-types.md:202-207`).
|
||||
|
||||
---
|
||||
|
||||
## 9. §12.3 Command — NEW everywhere → `packages/shared` + FE
|
||||
|
||||
Command Center (Ctrl+K) needs a result/command shape (§12.3, §16.3 `/api/command/*` all net-new,
|
||||
`_inventory/substrate-types.md:282`). No existing type.
|
||||
|
||||
NEW shared `Command` + `CommandResult`:
|
||||
```ts
|
||||
export type CommandCategory = 'search' | 'launch' | 'create' | 'run' | 'navigate' | 'extend';
|
||||
export type CommandResultType =
|
||||
| 'workspace' | 'memory' | 'artifact' | 'session' | 'person'
|
||||
| 'agent' | 'skill' | 'command' | 'connector' | 'mcp' | 'automation';
|
||||
|
||||
export interface CommandResult {
|
||||
id: string;
|
||||
type: CommandResultType;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
category: CommandCategory;
|
||||
icon?: string;
|
||||
requiresApproval?: boolean; // §12.3 permission-gated → approval prompt
|
||||
action?: { route?: string; endpoint?: string; payload?: Record<string, unknown> };
|
||||
}
|
||||
```
|
||||
`CommandResultType` deliberately spans every searchable object class (§12.3 FR "search across workspaces,
|
||||
memory, artifacts, sessions, people, agents, skills, commands, connectors, MCPs"). FE imports these for the
|
||||
command palette and result grouping.
|
||||
**Consumed by:** Command Center (Ctrl+K) (§12.3) — the only consumer, but cross-cutting (it indexes every entity).
|
||||
|
||||
---
|
||||
|
||||
## 10. Summary table
|
||||
|
||||
| Type | NEW / MODIFY | Current (cite) | Lives in | Primary screens |
|
||||
|---|---|---|---|---|
|
||||
| §15.2 unions (8) | **NEW** | none (`_inventory:218-229`) | `packages/shared/src/types.ts` | all (vocabulary) |
|
||||
| `WorkspaceConfigV2` | MODIFY | `workspace-manager.ts:5-58` + FE `Workspace` `types.ts:22-40` | shared (alias) + hive-mind-core (struct) + FE | §12.1, §12.2, switcher |
|
||||
| `Memory` (+confidence/provenance) | MODIFY FE / NEW shared / +metadata col | FE `MemoryFrame` `types.ts:118-127`; `memory_frames` no metadata col (`_inventory:150-153`) | shared entity + FE view-model + DB migration | §12.4, §12.1, §12.2 |
|
||||
| `Artifact` | **NEW** (all layers) | none (`_inventory:259-266`) | shared + DB table + FE | §12.5, §12.2, §12.3 |
|
||||
| `Agent` | MODIFY shared / NEW FE | `AgentDef` `shared/types.ts:36-47` | shared (extend) + FE view-model | §12.9, §12.2 |
|
||||
| `Skill` | MODIFY FE / NEW shared | FE `SkillPack` `types.ts:210-218`; `ParsedSkill` `skill-frontmatter.ts:53` | shared + FE | §12.6, §12.9 |
|
||||
| `Automation` | MODIFY FE / NEW shared | FE `CronJob` `types.ts:230-238`; `CronSchedule` `shared:162-174` | shared + FE | §12.10, §12.1 |
|
||||
| Connector | MODIFY (consume existing) | FE `Connector` `types.ts:280-285`; shared `ConnectorDefinition` `:276-302` | reuse shared | §12.7 |
|
||||
| `McpInstance` | **NEW** (instance) | catalog `McpServer` `mcp-catalog.ts:17-28` | shared + FE | §12.8 |
|
||||
| `Command`/`CommandResult` | **NEW** | none | shared + FE | §12.3 |
|
||||
|
||||
**Migration footprint:** WorkspaceConfigV2 = JSON-file only (no DB). Memory = 1 idempotent `ADD COLUMN metadata`.
|
||||
Artifact = 1 new table + routes. Everything else is TS-type + route work (server CRUD net-new per PRD §16). No
|
||||
literal-union duplication across files — enums live once in `packages/shared` and the FE imports them.
|
||||
Reference in New Issue
Block a user