Skip to content

integration: builder hardening P0 + canvas decomposition (train) - #39

Merged
adriannoes merged 12 commits into
mainfrom
integration/builder-asap-runtime
Jul 28, 2026
Merged

adriannoes merged 12 commits into
mainfrom
integration/builder-asap-runtime

Conversation

@adriannoes

Copy link
Copy Markdown
Collaborator

Summary

Integration train PR: Builder Hardening Sprint 0 + 0.5 on integration/builder-asap-runtime. ASAP Sprint 2 (Playground) and Sprint 3 (marketplace → builder + correlation) will land as further commits on this same PR — do not open separate PRs to main per sprint.

Landed so far

  • Client undo/redo as single source of truth (server /undo//redo//history/status → 410 Gone)
  • Atomic undo/redo (rollback stacks if PATCH fails)
  • Version restore + Supabase workflow_versions (fail-loud without Supabase in production)
  • Select-all, run edge highlight, safe ISO duration, GlassContainer toolbar, shell height
  • Canvas decomposition (history / mutations / clipboard / highlight hooks); canvas under size budget
  • Tests for history, versions, duration, select-all, restore, failed-PATCH rollback

Still on this train (not in tip yet)

  • ASAP Sprint 2 — Playground ASAP tools
  • ASAP Sprint 3 — Registry → Builder deep link + correlation_id
  • Full HANDOFF smoke before ready-for-review / merge

Test plan

  • CI green on this PR (pnpm run check / project gates)
  • Manual: /builder — undo/redo across edits; restore version; ⌘A selects all nodes
  • Manual: Run workflow — duration renders; edges highlight on path
  • Manual: toolbar row + viewport under app shell (no nested h-screen clip)
  • After S2/S3: Playground ASAP off-by-default; /marketplace → /builder?asapAgent=

Review notes

  • Draft until train exit criteria (HANDOFF). Review Sprint 0/0.5 now for early feedback; expect more commits for S2/S3.
  • Local reviews already done: T3 Fable + thermo-nuclear (follow-ups F1/F3/F7/F4 prod addressed on branch).
  • Known deferred P1: MiniMap, Zod on all workflow APIs, peek-commit history, etc.

Return 410 Gone so UI relies on client HistoryManager only and empty server Maps cannot lie about canUndo.
Prefer workflow_versions with RLS UPDATE/DELETE; keep in-memory Map only as non-prod fallback when Supabase is unavailable.
Coerce startedAt/completedAt before duration math so JSON-serialized runs no longer throw on .getTime().
Expose connectionIdsTouchingNode so canvas highlight can animate edges on the active run path.
Replace nested h-screen with dvh shell offset so mobile header and sidebar no longer clip the builder.
Use client HistoryManager for undo/redo and canUndo flags, implement version restore via PATCH, select all nodes/edges, highlight running edges, and fix toolbar GlassContainer inner layout.
Add HistoryManager unit tests and canvas coverage for client undo/redo, version restore, and empty-stack toolbar state; shim ResizeObserver in test setup.
Roll back HistoryManager stacks and skip SWR mutate when persist fails, matching restore so Sprint 3 builder demos cannot lie about canUndo.
Split builder-canvas into focused hooks and subscribe HistoryManager via useSyncExternalStore so ASAP sprints can extend the shell without growing the monolith past 800 lines.
Prevent silent in-memory workflow_versions fallback on serverless deploys so marketplace/restore demos cannot lie about persistence.
@vercel

vercel Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-agent-kit Ready Ready Preview, Comment, Open in v0 Jul 28, 2026 1:39am

@adriannoes adriannoes self-assigned this Jul 28, 2026
@adriannoes
adriannoes marked this pull request as ready for review July 28, 2026 01:08
Avoid assigning to read-only process.env.NODE_ENV so tsc --noEmit passes in CI.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

Solid Sprint 0 / 0.5 builder hardening: client HistoryManager as the undo/redo source of truth (server routes → 410), Supabase-backed workflow_versions with a production fail-loud guard, canvas decomposition into focused hooks, and meaningful unit/component coverage. Quality is high for a train PR, but CI is currently red and a few correctness gaps undercut the claimed atomic history / honest persistence contracts.

Must Fix

  1. CI typecheck failure — tests/lib/version-store.test.ts assigns process.env.NODE_ENV, which is readonly under current typings (TS2540). Confirmed in check run 30319394919. Use vi.stubEnv("NODE_ENV", "production") (and restore) instead.
  2. Concurrent undo/redo can corrupt stacks and persist the wrong graph — use-builder-history.ts mutates stacks before PATCH completes, with no in-flight lock. Rapid ⌘Z uses the same stale SWR workflow, duplicates redo entries, and out-of-order responses can win. Serialize transitions (or ignore overlapping calls) and add a race test.
  3. Version tag/delete can report success with zero rows changed — tagVersion / deleteVersion return !error. Under RLS, a viewer (or a concurrently deleted row) often gets no PostgREST error and zero affected rows, so the API can return 200 { success: true } without mutating. Prefer .select(...).maybeSingle() / affected-row checks and map denial to 403/404.

Should Fix

  1. getVersion masks DB failures as 404 — if (error || !data) return undefined turns outages / schema errors into "Version not found". Distinguish no-row from real errors (as getVersionsFromDb already does).
  2. Graph mutations still push history before persist — In use-builder-graph-mutations.ts, most handlers call saveToHistory() then ignore response.ok (and still toast success / revalidate). Failed edits leave ghost undo entries and clear redo. Align with the atomic undo/redo pattern: commit history only after success, or roll back the snapshot.
  3. Select-all is incomplete — ⌘A selects all nodes/edges locally, but copy / duplicate / delete still operate on the first selectedNodeId only. Wire multi-selection through clipboard/delete (the copy API already accepts nodeIds[]).
  4. Loose version path parsing — Number.parseInt(version, 10) accepts "1junk" / "1.5" as 1. Validate with Zod (z.coerce.number().int().positive() or equivalent) on version routes.
  5. Non-atomic version numbering — createVersion does read-max-then-insert; concurrent creates race on UNIQUE(workflow_id, version). Allocate in SQL or retry unique violations.

Nice to Have

  • Run edge highlight currently marks every edge touching a node (adjacency), not the traversed path; also, execute currently clears highlight rather than applying the returned run path.
  • durationMs still accepts JS-Date-normalized invalid calendars and negative spans.
  • execution-monitor.tsx still sets execution from any JSON body without response.ok (pre-existing; crash risk on { error } via execution.logs.length).
  • Toolbar zoom % from getViewport() may stay stale; prefer useViewport().
  • Route-level workspace binding (getWorkflow(id, workspace.id)) + editor role checks would harden the in-memory fallback path where RLS does not apply.

Positive Highlights

  • Honest client history: server undo/redo/status → 410 removes empty-Map lies about canUndo.
  • Production no longer silently falls back to a process-local version Map; RLS UPDATE/DELETE policies for workflow_versions correctly scope to owner/editor via workspace membership.
  • Canvas split into history / mutations / clipboard / highlight hooks keeps builder-canvas.tsx under the ~800-line budget while preserving keyboard flows.
  • Strong new tests for HistoryManager, failed-PATCH undo rollback, version production guard, duration coercion, and select-all updater behavior.

Early feedback on Sprint 0/0.5 as requested — still expecting S2/S3 on this train. Please clear the Must Fix items (especially the CI break and undo race) before treating this slice as merge-ready.

Open in Web View Automation 

Sent by Cursor Automation: Adrianno’s personal code review

Comment thread tests/lib/version-store.test.ts
Comment thread src/components/builder/hooks/use-builder-history.ts Outdated
Comment thread src/lib/version-store.ts Outdated
Comment thread src/lib/version-store.ts Outdated
Comment thread src/components/builder/hooks/use-builder-graph-mutations.ts Outdated
Comment thread src/components/builder/builder-canvas.tsx Outdated
Comment thread src/app/api/workflows/[id]/versions/[version]/route.ts Outdated
Serialize undo/redo, fail-loud version writes, atomic graph history,
multi-select clipboard, strict version params, and workspace-scoped
workflow access so Sprint 0/0.5 review threads can resolve honestly.
@adriannoes

Copy link
Copy Markdown
Collaborator Author

Review follow-up (da21695)

All inline review threads from the Cursor Bot request-changes pass are replied + resolved. Summary of what landed beyond those threads (same commit):

Should Fix (no inline thread)

  • Non-atomic version numbering — createVersion retries on unique violation (23505) up to 3 attempts.

Nice to Have

  • Run edge highlight — path-based connectionIdsAlongNodePath; execute applies the returned log path instead of clearing highlight.
  • durationMs — rejects negative spans and impossible calendars (e.g. 2026-02-30).
  • execution-monitor — checks response.ok before treating JSON as an execution; surfaces run errors.
  • Toolbar zoom — uses useViewport() so % stays reactive.
  • Workspace binding — workflow GET/PATCH/DELETE + nested routes/helpers pass result.workspace.id into getWorkflow / updateWorkflow / node-connection helpers.

pnpm run check was green locally before push.

@adriannoes
adriannoes merged commit 6b20736 into main Jul 28, 2026
3 checks passed
@adriannoes
adriannoes deleted the integration/builder-asap-runtime branch July 28, 2026 01:43

This branch was successfully deployed

1 active deployment
Preview — da216959 Deployed Jul 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant