docs(work): decompose platform-retrofit and walking-skeleton epics

platform-retrofit: 8 stories / 18 tasks (spec bundle into docs/product,
single-version release-please before deletions, demo feature removal,
web-next auth shell, optional cores, work-tree archive, library traces,
agent-doc rewrite). walking-skeleton: 11 stories / 28 tasks across
workspaces, discovery, core-runner-protocol, runner app, editor, and
the flagship connect-to-selection e2e; builds on platform-retrofit
(prose dependency note — cross-epic frontmatter unsupported).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
2026-07-12 12:28:51 +02:00
parent 442b70476c
commit 99180887f3
22 changed files with 1286 additions and 3 deletions

View File

@@ -0,0 +1,44 @@
---
id: 01-vite-kitchen-fixture
epic: walking-skeleton
title: vite-kitchen fixture + git-serving test helpers
type: technical-story
status: in-progress
feature: core-testing
depends-on: []
blocks: [04-runner-app-protocol-clone-install]
created: 2026-07-12T10:24:14Z
---
## Goal
Land `fixtures/vite-kitchen` — a minimal Vite + React + TS + Tailwind repo with a `Button` component — at the repo root, outside the pnpm workspace and turbo graph, plus `core-testing` helpers that serve any fixture as a local bare repo over the git protocol so integration tests can drive a real `git clone` without cloud resources.
## Why
The protocol integration suite (the load-bearing test tier of this epic) spawns a real runner against a `git daemon`-served `vite-kitchen` (tech spec §15). The fixture and its serving helpers are the substrate every runner story's tests stand on, so they land first.
**Sequencing note (cross-epic):** the sibling `platform-retrofit` epic (clean floor, ADR-022 traces, scaffolded optional cores incl. `core-events` + `core-realtime`, pre-approved editor deps) must complete before this epic starts — the PRD's "Builds on" names it. Cross-epic `depends-on` frontmatter is not supported; this note is the dependency record.
## Done when
- `fixtures/vite-kitchen` exists at the repo root: minimal Vite + React + TS + Tailwind app with a `Button` component (typed props for the docgen scan), invisible to pnpm workspace resolution and the turbo graph.
- `core-testing` exports helpers that serve a fixture directory as a local bare repo / `git daemon` remote (setup/teardown, clone URL), with tests exercising a real `git clone` of `vite-kitchen`.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- `fixtures/` directory at repo root, outside pnpm workspace and turbo graph (PRD Implementation decisions).
- The `Button` component with props the react-docgen-typescript scan can discover (name + props).
- `core-testing` bare-repo/`git daemon` serving helpers for tests.
## Out of scope
- The runner's clone/install/scan of the fixture (stories 0405).
- PAT-authenticated fixture hosting beyond what the leak-assertion tests need (real GitHub/GitLab connections are out of PRD scope).
- Additional fixtures (Next.js fixture arrives with `preview-and-nextjs-depth`).
## Tasks
- [ ] Create `fixtures/vite-kitchen` at the repo root — minimal Vite + React + TS + Tailwind app with a `Button` component (typed props) — outside the pnpm workspace and turbo graph; confirm `pnpm install` and turbo ignore it and all gates stay green.
- [ ] Add `core-testing` helpers that serve a fixture directory as a local bare repo / `git daemon` remote (setup/teardown, clone URL) with tests exercising a real `git clone` of `vite-kitchen`.

View File

@@ -0,0 +1,44 @@
---
id: 02-core-runner-protocol
epic: walking-skeleton
title: core-runner-protocol package — versioned, zod-validated message schemas
type: technical-story
status: todo
feature: core-runner-protocol
depends-on: []
blocks: [04-runner-app-protocol-clone-install, 09-editor-package]
created: 2026-07-12T10:24:14Z
---
## Goal
Ship `@repo/core-runner-protocol`: versioned, zod-validated message schemas for the runner protocol (hello/ready, clone, install, scan, adapter-start, render-frame, status/error events) shared by features, editor, and runner, so the three sides cannot drift apart silently (PRD user story 7).
## Why
The runner protocol is plain WS/JSON, not tRPC (ADR-027) — which means nothing type-checks the wire unless every message is zod-parsed against one shared schema package. Every other story in this epic (runner app, provisioner, lifecycle events, editor frame) consumes these schemas; they must exist first.
## Done when
- `@repo/core-runner-protocol` exists as a green optional core package.
- Message envelope carries `protocolVersion: "0"` and a workspace-scoped auth token (PRD Implementation decisions).
- Zod-validated schemas exist for: hello/ready, clone, install, scan, adapter-start, render-frame, and status/error events — status events carry stage + elapsed (ui-gap §5 staged-progress), error events carry named causes.
- Unit tests cover accept/reject round-trips for every message type (`.strict()` schemas reject unknown fields).
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- `pnpm turbo gen core-package runner-protocol` scaffold.
- Versioned envelope + the message schema set listed above.
- Schema unit tests.
## Out of scope
- The WS server/client implementations (stories 04 and 07) — this package is schemas only.
- Protocol version negotiation beyond the pinned `"0"` (later PRDs).
- Watch/HMR messages (`discovery-and-library`).
## Tasks
- [ ] Run `pnpm turbo gen core-package runner-protocol` → green `@repo/core-runner-protocol` package shell.
- [ ] Add the versioned protocol surface: message envelope (`protocolVersion: "0"`, workspace-scoped auth token) + zod-validated `.strict()` schemas for hello/ready, clone, install, scan, adapter-start, render-frame, and status/error events (staged progress carries stage + elapsed; errors carry named causes), with unit tests covering accept/reject round-trips for every message type.

View File

@@ -0,0 +1,56 @@
---
id: 03-workspaces-feature-core
epic: walking-skeleton
title: workspaces feature core — connect, status, list + encrypted credential storage
type: user-story
status: todo
feature: workspaces
depends-on: []
blocks:
[
06-runner-provisioner-port,
07-runner-lifecycle-events-and-realtime,
10-web-next-wiring,
]
created: 2026-07-12T10:24:14Z
---
## Goal
Ship the minimal `workspaces` feature: `connectWorkspace` (name + git URL + PAT, audited), `getWorkspaceStatus`, `listWorkspaces`, and a Workspaces Payload collection whose PAT field is encrypted at rest and write-only — so a signed-in user can connect a repository by git URL + token (PRD user story 1).
## Why
The workspace is the root entity of the entire skeleton: provisioning (story 06), lifecycle events (story 07), and the web-next UX (story 10) all hang off it. Credential handling is the security-critical part and must land with the collection, not be retrofitted: PAT stored encrypted AES-256-GCM with a scrypt-derived key from `VEECT_SECRET`, decrypted only server-side, never returned by the Payload API (PRD Implementation decisions; tech spec §13).
## Done when
- `pnpm turbo gen feature workspaces` scaffold is green.
- `connectWorkspace` (`mutates: true`, `audits: ["workspace-connected"]`), `getWorkspaceStatus`, and `listWorkspaces` are declared in `feature.manifest.ts`, implemented manifest-first with contracts, unit tests (mocks injected directly), DI wiring, and tRPC procedures.
- Workspaces Payload collection stores the PAT encrypted AES-256-GCM (scrypt key derivation from `VEECT_SECRET`); the field is write-only — no API read path returns it.
- Repository contract suite runs against both the mock and the Payload impl, including the write-only credential behavior (PRD Testing decisions).
- No use-case output schema ever includes the credential.
- Coverage bands: template defaults (PRD Implementation decisions — use cases are thin orchestration).
- Boot assertion (`assertFeatureConformance`) green in dev-seed mode.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- Feature scaffold, three use cases, manifest declarations, audit emission for `connectWorkspace`.
- Workspaces Payload collection + real repository + encrypted write-only credential field.
- Repository contract suite (mock + Payload).
- Dev-seed binder (`__seeds__/dev.ts`) so `pnpm dev` boots without Payload.
## Out of scope
- Runner provisioning + lifecycle status events (stories 0607) — `getWorkspaceStatus` returns persisted state only in this story.
- The manifest's `publishes` / realtime declarations (story 07).
- Connect UX (story 10); org walls, trust prompt, env manager (`workspaces-and-connections`).
- Real GitHub/GitLab connections beyond git URL + PAT.
## Tasks
- [ ] Run `pnpm turbo gen feature workspaces` → green feature scaffold (manifest, contracts, binders, controllers, tests, dev-seed).
- [ ] Add `connectWorkspace` use case — manifest entry (`mutates: true`, `audits: ["workspace-connected"]`), input schema (name + git URL + PAT), output schema (credential never included), red test → green impl, DI wiring with audit emission, tRPC procedure.
- [ ] Add the Workspaces Payload collection + real repository: PAT encrypted AES-256-GCM with a scrypt-derived key from `VEECT_SECRET`, write-only field (Payload API never returns it); repository contract suite covering mock + Payload impls incl. the write-only credential behavior.
- [ ] Add `getWorkspaceStatus` and `listWorkspaces` use cases — manifest entries, contracts, red tests → green impls, DI wiring, tRPC procedures — returning persisted workspace/runner status.

View File

@@ -0,0 +1,49 @@
---
id: 04-runner-app-protocol-clone-install
epic: walking-skeleton
title: runner app — protocol server, clone stage, install stage
type: technical-story
status: todo
feature: runner
depends-on: [01-vite-kitchen-fixture, 02-core-runner-protocol]
blocks: [05-runner-scan-and-preview-adapter, 06-runner-provisioner-port]
created: 2026-07-12T10:24:14Z
---
## Goal
Ship the first half of `apps/runner`: a WS server speaking `@repo/core-runner-protocol` (hello/ready handshake gated on the workspace-scoped auth token), then the clone stage (PAT via ephemeral credential helper, spec §6 verbatim) and the install stage (package-manager detection), each emitting staged progress and named error events, each proven by the protocol integration suite against a real spawned runner and a `git daemon`-served `vite-kitchen`.
## Why
The runner ↔ repo-toolchain seam is one of the three risks this epic exists to burn down. Clone and install are where credentials touch disk and subprocesses — the credential-leak assertions (no PAT in URLs, argv, logs, or `.git/config`; spec §15) must grow up with the code, not after it. App-tier imperative code is expected here (PRD Implementation decisions); the protocol is the contract, so tests assert through the protocol and never against runner internals (PRD Testing decisions).
## Done when
- `apps/runner` exists; every inbound/outbound message is zod-parsed against `core-runner-protocol`; handshake rejects a bad/missing workspace-scoped token.
- Clone stage delivers the PAT to git via an ephemeral credential helper (spec §6 mechanics verbatim); credential never appears in any log, process argv, or `.git/config` in the runner workspace — asserted by the integration suite.
- Install stage detects the package manager and installs, streaming staged progress events.
- Named error events for bad URL, bad token, and install failure (PRD user story 5).
- Protocol integration suite (real spawned runner + `git daemon`-served fixture, real WS) passes in CI on ubuntu.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- `apps/runner` app scaffold (app-tier — no feature generator applies; template app conventions).
- WS server + envelope parsing + hello/ready handshake + status/error emission.
- Clone stage with ephemeral credential helper + leak assertions.
- Install stage with package-manager detection + progress events.
- Integration tests using `core-testing`'s git-serving helpers (story 01).
## Out of scope
- Scan + preview adapter + agent script (story 05).
- Provisioning of the runner (story 06) — tests spawn it directly.
- Watch/HMR, perf budgets (`discovery-and-library`); Next.js adapter (`preview-and-nextjs-depth`).
- Local runner / CLI agent (`local-runner-cli`).
## Tasks
- [ ] Scaffold `apps/runner`: WS server speaking `@repo/core-runner-protocol` (every message zod-parsed), hello/ready handshake gated on the workspace-scoped auth token, status/error event emission; integration test spawns the real runner and completes the handshake over real WS.
- [ ] Add the clone stage: git clone of the requested repo with the PAT delivered via an ephemeral credential helper (spec §6 verbatim — never in URLs, argv, logs, or `.git/config`), staged progress events; integration test clones the `git daemon`-served `vite-kitchen`, asserts credential-leak absence (grep argv/logs/`.git/config`), and asserts named failure events for bad URL / bad token.
- [ ] Add the install stage: package-manager detection + install with staged progress events; integration test asserts install completes on the fixture and a named failure event is emitted on install error.

View File

@@ -0,0 +1,46 @@
---
id: 05-runner-scan-and-preview-adapter
epic: walking-skeleton
title: runner scan stage + embedded-Vite preview adapter + canvas agent v0
type: technical-story
status: todo
feature: runner
depends-on: [04-runner-app-protocol-clone-install]
blocks: [07-runner-lifecycle-events-and-realtime]
created: 2026-07-12T10:24:14Z
---
## Goal
Complete `apps/runner`: a minimal react-docgen-typescript scan that returns ≥1 component (name + props) from the fixture, and an embedded-Vite preview adapter rooted at the clone that serves a Veect frame-host page — importing the component requested via `render-frame` and mounting the injected, Veect-authored canvas agent script v0.
## Why
This is invariant #1 made real: the component renders through the repo's own toolchain, not a Veect re-implementation (ADR-028 — no NodeRenderer on the board path). The agent script is the editor's only eyes inside the cross-origin iframe; it must be adapter-injected and never sourced from the repo (ADR-028 consequences — security floor even at fixture scale).
## Done when
- Scan stage runs react-docgen-typescript over the fixture's component glob and emits a scan-result message with ≥1 component carrying name + props (skeleton fidelity; full `ComponentMeta` comes with `discovery-and-library`).
- Preview adapter starts embedded Vite rooted at the clone on a dedicated port = dedicated origin (spec §9), serving a frame-host entry that imports the requested component with default props (`render-frame`) and mounts the agent script.
- Canvas agent v0 reports `runtime.ready`, component bounding boxes (post `fonts.loaded`), and click-target resolution; `targetOrigin` pinned in both directions (ADR-028).
- Agent script is Veect-authored and adapter-injected — never sourced from the repo.
- Protocol integration suite extends to: scan returns ≥1 component → adapter serves the frame host with the agent script → adapter origin liveness (PRD Success criteria).
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- Scan stage (react-docgen-typescript, minimal glob) + scan-result message.
- Embedded-Vite adapter, frame-host entry, `render-frame` handling, adapter-ready/status events.
- Canvas agent script v0 (ready, geometry, click-target resolution; pinned `targetOrigin`).
- Integration tests for scan payload, adapter origin liveness, and agent-script presence.
## Out of scope
- The editor-side canvas-protocol client (story 09).
- Watch/HMR, perf-500 budgets (`discovery-and-library`); Next.js adapter (`preview-and-nextjs-depth`).
- Multi-view frames, isolation, code panel (later PRDs).
## Tasks
- [ ] Add the scan stage: minimal react-docgen-typescript scan over the fixture's component glob → scan-result message with ≥1 component (name + props); integration test asserts the `Button` payload arrives over real WS.
- [ ] Add the preview adapter: embedded Vite rooted at the clone on a dedicated port/origin (spec §9), frame-host entry importing the component requested via `render-frame` (default props) and mounting the injected Veect-authored canvas agent script v0 (`runtime.ready`, bounding boxes post `fonts.loaded`, click-target resolution; pinned `targetOrigin` both directions; never sourced from the repo); adapter-ready/status events; integration test asserts adapter origin liveness and that the frame host serves with the agent script.

View File

@@ -0,0 +1,44 @@
---
id: 06-runner-provisioner-port
epic: walking-skeleton
title: IRunnerProvisioner port + local-process and single-host Docker implementations
type: technical-story
status: todo
feature: workspaces
depends-on: [03-workspaces-feature-core, 04-runner-app-protocol-clone-install]
blocks: [07-runner-lifecycle-events-and-realtime]
created: 2026-07-12T10:24:14Z
---
## Goal
Ship the runner provisioning port — `IRunnerProvisioner` (`provision(workspaceId) → RunnerHandle`, `terminate`, `status`) in `workspaces` infrastructure — with two implementations: a local child-process provisioner (dev/CI) and a single-host Docker provisioner (the container-per-workspace baseline of ADR-027 §2).
## Why
Each workspace's repo code must execute in its own isolated runner so a malicious repo cannot touch other tenants (PRD user story 6, ADR-027). Putting provisioning behind a port keeps fleet orchestration explicitly a later concern behind the same interface, and lets `pnpm dev` + CI run the whole skeleton with a plain child process (PRD user story 8).
## Done when
- `IRunnerProvisioner` service port lives in `workspaces` infrastructure with `provision(workspaceId) → RunnerHandle`, `terminate`, `status` (PRD Implementation decisions).
- Local child-process implementation spawns the real `apps/runner`; tests provision, complete the protocol handshake, and terminate cleanly.
- Docker implementation: docker CLI via execa (PRD Q1 — app/infra-tier placement, so no ADR-022 trace required); image `node:22-bookworm-slim` + git at a pinned digest (PRD Q3); container-per-workspace with no cross-tenant network (PRD security floor).
- The Docker path has a documented manual dev-machine check; CI uses the process provisioner (PRD Success criteria).
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- The port + `RunnerHandle` shape.
- Local child-process implementation + tests against the real runner.
- Single-host Docker implementation (docker CLI via execa) + tests against a stubbed docker CLI + documented manual verification steps.
## Out of scope
- Fleet orchestration, hibernation, egress policy hardening, resource-limit tuning (`workspaces-and-connections`).
- Quotas, metering, billing.
- Doctor-style runner image version checks (`workspaces-and-connections`, PRD Q3).
## Tasks
- [ ] Add the `IRunnerProvisioner` service port in `workspaces` infrastructure (`provision(workspaceId) → RunnerHandle`, `terminate`, `status`) + the local child-process implementation spawning `apps/runner`; tests provision a real runner, complete the protocol handshake, and terminate cleanly.
- [ ] Add the single-host Docker implementation (docker CLI via execa, app/infra-tier per PRD Q1; `node:22-bookworm-slim` + git at a pinned digest; container-per-workspace, no cross-tenant network) with unit tests against a stubbed docker CLI + documented manual dev-machine verification (CI stays on the process provisioner).

View File

@@ -0,0 +1,54 @@
---
id: 07-runner-lifecycle-events-and-realtime
epic: walking-skeleton
title: runner lifecycle — status events, scan event, realtime channel
type: technical-story
status: todo
feature: workspaces
depends-on:
[
03-workspaces-feature-core,
05-runner-scan-and-preview-adapter,
06-runner-provisioner-port,
]
blocks: [08-discovery-feature, 10-web-next-wiring]
created: 2026-07-12T10:24:14Z
---
## Goal
Wire the control-plane side of the runner lifecycle: `connectWorkspace` provisions via `IRunnerProvisioner` and drives the protocol session (clone → install → scan → start preview); `workspaces` publishes `runner-status-changed` and the scan event on `IEventBus`; a realtime channel pushes stage progress + adapter-ready to the browser. This wires `core-events` and `core-realtime` end to end (PRD In scope).
## Why
Staged, honest progress is what keeps a minutes-long operation from looking hung (PRD user story 2, ui-gap §5) — and named error events (bad URL, bad token, install failure) are what make failure states diagnosable instead of a blank board (user story 5). Registry ingestion is a cross-feature reaction, so it must cross the boundary via the event bus, not a direct call (rule E0) — this story publishes; story 08 consumes.
## Done when
- `connectWorkspace` kicks off provisioning + the protocol session; the credential is decrypted only server-side and passed to the runner over the authenticated protocol channel (PRD Implementation decisions).
- `runner-status-changed` event contract lives in `workspaces` `events/`, is exported from the feature root barrel (rule E1), and is declared under `publishes` in `feature.manifest.ts`; staged events carry stage + elapsed; error events carry named causes.
- The scan event contract is likewise public + declared; the lifecycle session publishes it with the scan-result payload when the runner's scan completes.
- Realtime channel descriptor is exported from the root barrel (rule R1) and declared in the manifest; it pushes stage progress + adapter-ready to the browser; no direct `socket.io` import in the feature (rule R2).
- `getWorkspaceStatus` reflects live staged status, including named error states.
- Tests use a recording bus + scripted runner double (protocol as the contract — no assertions on runner internals).
- `pnpm conformance` event closure green; boot assertion green.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- Lifecycle orchestration in `workspaces` (provision → protocol session → staged status), off the request path.
- `runner-status-changed` + scan event contracts, manifest `publishes` declarations, bus publishing.
- Realtime channel descriptor + broadcast wiring, manifest declaration.
- Named error states for bad URL / bad token / install failure.
## Out of scope
- The scan-event consumer (story 08 — discovery).
- Browser subscription UI (story 10).
- Workspace hibernation, runner fleet concerns (`workspaces-and-connections`).
## Tasks
- [ ] Run `pnpm turbo gen event` for the `runner-status-changed` contract (public from the `workspaces` root barrel; manifest `publishes` declaration) + wire the lifecycle orchestration: `connectWorkspace` provisions via `IRunnerProvisioner`, drives the protocol session (clone → install → scan → start preview) with the credential passed only over the authenticated channel, publishes staged status events (stage + elapsed) and named error events (bad URL, bad token, install failure); `getWorkspaceStatus` reflects live staged status; tests with recording bus + scripted runner double.
- [ ] Run `pnpm turbo gen event` for the scan event contract (public + manifest-declared) + publish the scan-result payload from the lifecycle session when the runner's scan completes; test asserts the publish carries the registry payload.
- [ ] Run `pnpm turbo gen realtime` for the workspace-status channel: exported channel descriptor + broadcast wiring pushing stage progress + adapter-ready to the browser; manifest declaration; handlers stay private (rule R1); tests.

View File

@@ -0,0 +1,45 @@
---
id: 08-discovery-feature
epic: walking-skeleton
title: discovery feature — registry snapshots, getRegistry, scan ingestion
type: technical-story
status: todo
feature: discovery
depends-on: [07-runner-lifecycle-events-and-realtime]
blocks: [10-web-next-wiring]
created: 2026-07-12T10:24:14Z
---
## Goal
Ship the minimal `discovery` feature: registry snapshot storage, a `getRegistry` use case, and a scan-event handler that ingests the runner's scan results — so the editor has one real component (name + props) to render (skeleton bar; full `ComponentMeta` fidelity comes with `discovery-and-library`).
## Why
Discovery is its own vertical — the registry outlives any single runner session, and later PRDs (`discovery-and-library`) grow it heavily. Ingestion arrives as a cross-feature reaction to the scan event `workspaces` publishes (rule E0); the handler stays private (rule E1) while `getRegistry` is the public read surface the editor route consumes.
## Done when
- `pnpm turbo gen feature discovery` scaffold is green.
- Registry snapshot storage + `getRegistry` use case land manifest-first (contracts, unit tests with direct mock injection, DI wiring, tRPC procedure); the registry exposes one component with name + props from the fixture scan.
- The scan-event handler (`events/handlers/`, never re-exported) ingests scan results into a registry snapshot; `consumes` is declared in `feature.manifest.ts`.
- `pnpm conformance` cross-feature event closure passes — no orphan consumer.
- Coverage bands: template defaults (PRD Implementation decisions).
- Boot assertion green in dev-seed mode.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- Feature scaffold, registry snapshot storage, `getRegistry`, scan-event handler + manifest `consumes` declaration.
- Dev-seed binder with a seeded registry so the editor works in dev-seed mode.
## Out of scope
- Full `ComponentMeta` fidelity, watch/HMR re-scan, perf-500 budgets (`discovery-and-library`).
- Any write surface beyond event ingestion.
## Tasks
- [ ] Run `pnpm turbo gen feature discovery` → green feature scaffold (manifest, contracts, binders, controllers, tests, dev-seed).
- [ ] Add registry snapshot storage + the `getRegistry` use case — manifest entry, contracts, red test → green impl, DI wiring, tRPC procedure; registry exposes one component with name + props; dev-seed provides a seeded registry.
- [ ] Run `pnpm turbo gen event` for the scan-event handler (`events/handlers/on-workspaces-*.handler.ts`, never re-exported per rule E1): ingest scan results into a registry snapshot; manifest `consumes` declaration; `pnpm conformance` event closure green; handler test.

View File

@@ -0,0 +1,49 @@
---
id: 09-editor-package
epic: walking-skeleton
title: editor package — React Flow board, iframe frame node, canvas-protocol client
type: technical-story
status: todo
feature: editor
depends-on: [02-core-runner-protocol]
blocks: [10-web-next-wiring]
created: 2026-07-12T10:24:14Z
---
## Goal
Ship `packages/editor` v0 — the first code of the ADR-029 rebuild: a React Flow board shell, one iframe frame node hosting the adapter origin, a canvas-protocol client proving the selection round-trip, a minimal zustand store (registry + selection only), and an editor-side selection overlay rendered from agent-reported geometry. Stories + tests from day one.
## Why
The editor ↔ iframe canvas seam across the origin boundary is the third risk this epic burns down (ADR-028): chrome renders as editor-side overlays from agent-reported geometry, never inside the repo's frame, and `targetOrigin` is pinned in both directions. ADR-029 mandates template conventions from the first commit — `component-must-have-story`/`-test`, React 19, no prototype vendoring — so the skeleton editor is the permanent foundation, not a throwaway.
## Done when
- `@repo/editor` exists as a green package following template conventions (vitest `@` alias, `rootDir: "."`, conformance ESLint rules active).
- Canvas-protocol client handles `runtime.ready`, geometry reports, and click-target resolution with pinned `targetOrigin` both directions; unit-tested against a scripted agent double (PRD Testing decisions).
- Zustand store holds registry + selection only (no document tree — DesignDoc v1 arrives with `design-doc-and-editor-foundation`).
- React Flow board with one frame node hosting the adapter iframe; the frame renders a single Element (the discovered component with default props) requested via `render-frame`.
- Selection overlay renders editor-side from agent-reported geometry; board pan/zoom stays editor-side (< 16 ms/frame no protocol round-trip on drag; PRD budget).
- Every component has a story + test (`component-must-have-story` / `component-must-have-test`).
- React Flow + zustand runtime deps are covered by the `platform-retrofit` pre-approved traces (ADR-022) no new trace expected; if any additional runtime dep is needed, it gets an `/evaluate-library` trace.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- Package scaffold for `packages/editor`.
- Canvas-protocol client + scripted agent double tests.
- Zustand store (registry + selection).
- Board shell, frame node, selection overlay, stories + component tests.
## Out of scope
- Design-doc persistence the frame is an ephemeral in-memory doc (PRD Out of scope).
- AI compose, Polish, history, multi-view frames, isolation, code panel.
- The web-next route hosting the board (story 10).
## Tasks
- [ ] Scaffold `packages/editor` (`@repo/editor`) as a green package shell using `pnpm turbo gen core-package` output as the baseline shape (adapted for a non-core package): tsconfig `rootDir: "."`, vitest config with `@` alias, conformance ESLint rules active; React 19; React Flow + zustand wired against the pre-approved `platform-retrofit` traces.
- [ ] Add the canvas-protocol client (pinned `targetOrigin` both directions; `runtime.ready`, geometry reports, click-target selection round-trip) unit-tested against a scripted agent double + the minimal zustand store holding registry + selection only.
- [ ] Add the React Flow board shell + one iframe frame node hosting the adapter origin + editor-side selection overlay rendered from agent-reported geometry; the frame renders a single Element (discovered component, default props) requested via `render-frame`; pan/zoom stays editor-side (< 16 ms/frame, no protocol round-trip on drag); stories + component tests for board/frame/overlay.

View File

@@ -0,0 +1,53 @@
---
id: 10-web-next-wiring
epic: walking-skeleton
title: web-next wiring — connect UX, staged progress, editor route
type: user-story
status: todo
feature: web-next
depends-on:
[
03-workspaces-feature-core,
07-runner-lifecycle-events-and-realtime,
08-discovery-feature,
09-editor-package,
]
blocks: [11-flagship-e2e]
created: 2026-07-12T10:24:14Z
---
## Goal
Wire the skeleton into `apps/web-next`: workspace list + connect form + staged progress (cloning → installing → scanning → starting preview, with named error states), realtime push of runner status, feature routers composed into the appRouter, `bindAll()` for both features, and the editor route `/w/[workspace]` hosting the board (PRD Q2 — a real route, the editor's permanent home).
## Why
This story is where the user stories become visible: honest staged progress instead of a hung spinner (user story 2, ui-gap §5), a clear named error state instead of a blank board (user story 5), and the real component rendered by the repo's own toolchain on a real route (user story 3). Dev-seed mode + the process provisioner keep `pnpm dev` + fixtures free of cloud resources (user story 8).
## Done when
- `bindAll()` in `apps/web-next` binds `workspaces` + `discovery` in production and dev-seed modes; boot assertion green in both (PRD Success criteria); dev-seed + process provisioner boots with `pnpm dev` and no cloud resources.
- Both feature routers are composed into the appRouter; schemas imported from the use-case files, never redefined inline.
- Workspace list + connect form (name + git URL + PAT) built from feature `ui/` hooks + connected components per `docs/guides/building-feature-ui.md`.
- Staged progress UI driven by the realtime channel: cloning → installing → scanning → starting preview, plus adapter-ready; named error states for bad URL, bad token, install failure — never a blank board.
- Editor route `/w/[workspace]` hosts the board: registry via `getRegistry`, frame node requests `render-frame` of the discovered component with default props; clicking the component in the iframe selects it and the selection state names it.
- Stories + component tests per conformance rules.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass after each task.
## In scope
- `bindAll()` + appRouter composition + provisioner selection (process provisioner as the dev/CI default).
- Workspaces UI: list, connect form, staged progress, error states, realtime subscription.
- Editor route `/w/[workspace]` composing `@repo/editor` with registry + frame data.
## Out of scope
- Full connect UX states — org walls, trust prompt, env manager (`workspaces-and-connections`).
- The Playwright flagship spec (story 11).
- web-tanstack wiring (not in PRD scope).
## Tasks
- [ ] Wire `workspaces` + `discovery` into `apps/web-next`: `bindAll()` in production + dev-seed modes (dev-seed + process provisioner boots via `pnpm dev` with no cloud resources), feature routers composed into the appRouter, realtime channel plumbed to the browser; boot assertion green in both modes; tests.
- [ ] Add the workspace list + connect form + staged progress UI (feature `ui/` hooks + connected components per `building-feature-ui.md`): staged progress cloning → installing → scanning → starting preview driven by realtime push, named error states (bad URL, bad token, install failure — never a blank board); stories + component tests.
- [ ] Add the editor route `/w/[workspace]` hosting the board: registry via `getRegistry`, frame node requesting `render-frame` of the discovered component with default props, click-in-iframe → selection overlay + selection state naming the component; tests.

View File

@@ -0,0 +1,41 @@
---
id: 11-flagship-e2e
epic: walking-skeleton
title: flagship e2e — connect vite-kitchen to selection round-trip
type: user-story
status: todo
feature: web-next
depends-on: [10-web-next-wiring]
blocks: []
created: 2026-07-12T10:24:14Z
---
## Goal
Land the repo's flagship Playwright spec — the M0-recast acceptance: sign in → connect `vite-kitchen` via git URL + PAT → staged progress completes → the editor shows `Button` rendered inside the adapter's iframe → click the button in the iframe → the editor selection overlay appears and the selection state names the component.
## Why
This spec is the epic's definition of done in executable form. It exercises every seam at once — provisioning, clone/install/scan, adapter, realtime progress, and the cross-origin selection round-trip — asserting through the UI and the protocol, never against runner internals, so the runner stays refactorable while the protocol is the contract (PRD Testing decisions).
## Done when
- The Playwright spec (dev-seed + local-process provisioner) covers the full flow from the PRD Success criteria and asserts on iframe content, not a screenshot double.
- The flow completes within the connect-to-rendered-component budget: < 3 min on the warm fixture (PRD budget, spec §16).
- The spec is tagged as the repo's flagship spec and runs green in CI.
- The equivalent flow with the Docker provisioner works on a dev machine per story 06's documented manual check (CI stays on the process provisioner).
- `pnpm typecheck && pnpm lint && pnpm test && pnpm test:e2e && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass.
## In scope
- The flagship Playwright spec under the existing `pnpm test:e2e` surface, running against dev-seed mode with the process provisioner.
- Any test-only plumbing needed to run the spec in CI (fixture serving, runner spawn) reusing the story 01 helpers.
## Out of scope
- Docker-provisioner automation in CI (manual check only, per PRD Success criteria).
- Additional e2e coverage beyond the flagship flow (later PRDs).
## Tasks
- [ ] Add the flagship Playwright spec (dev-seed + process provisioner): sign in connect `vite-kitchen` via git URL + PAT staged progress completes `Button` rendered inside the adapter iframe (assert on iframe content) click in the iframe selection overlay appears and the selection state names the component; completes within the < 3 min warm-fixture budget; tagged as the repo's flagship spec; green in CI.

View File

@@ -0,0 +1,34 @@
---
id: walking-skeleton
prd: docs/work/prds/walking-skeleton.prd.md
title: Walking skeleton — one real component, end to end through the hosted spine
type: epic
status: in-progress
features:
[workspaces, discovery, core-runner-protocol, editor, runner, web-next, core-testing]
created: 2026-07-12T10:24:14Z
---
## Goal
A signed-in user connects a fixture repo; a cloud runner clones and installs it; discovery finds one real component; the editor renders that component on the board through the repo's own Vite in an iframe; clicking it inside the iframe selects it in the editor. One thin, honest, end-to-end vertical through every seam that matters: control plane ↔ runner provisioning, runner ↔ repo toolchain, and editor ↔ iframe canvas across the origin boundary (ADR-027/028/029).
## Why
Every Veect risk that matters lives in the seams, not the parts. The original tech spec front-loaded exactly this with its M0 walking skeleton, but its acceptance criteria died with the Electron distribution (ADR-027). Nothing yet proves the hosted spine works at all, and every subsequent PRD (workspaces, discovery, design-doc, codegen, projects, ai) builds on these seams. If the spine is wrong, we must find out before nine PRDs are stacked on it.
**Sequencing note:** this epic builds on the sibling `platform-retrofit` epic (clean floor, ADR-022 traces, scaffolded optional cores incl. `core-events` + `core-realtime`, pre-approved editor deps). `platform-retrofit` must complete before this epic starts; cross-epic `depends-on` frontmatter is not supported, so this note (and story 01's Why) is the dependency record.
## Stories
- [ ] [01 — vite-kitchen fixture + git-serving test helpers](01-vite-kitchen-fixture/_story.md)
- [ ] [02 — core-runner-protocol package](02-core-runner-protocol/_story.md)
- [ ] [03 — workspaces feature core: connect, status, list + encrypted credentials](03-workspaces-feature-core/_story.md)
- [ ] [04 — runner app: protocol server, clone, install](04-runner-app-protocol-clone-install/_story.md)
- [ ] [05 — runner scan + preview adapter + canvas agent](05-runner-scan-and-preview-adapter/_story.md)
- [ ] [06 — IRunnerProvisioner port + process/Docker implementations](06-runner-provisioner-port/_story.md)
- [ ] [07 — runner lifecycle: events + realtime channel](07-runner-lifecycle-events-and-realtime/_story.md)
- [ ] [08 — discovery feature: registry + scan ingestion](08-discovery-feature/_story.md)
- [ ] [09 — editor package: board, frame, canvas-protocol client](09-editor-package/_story.md)
- [ ] [10 — web-next wiring: connect UX, staged progress, editor route](10-web-next-wiring/_story.md)
- [ ] [11 — flagship e2e: connect-to-selection](11-flagship-e2e/_story.md)