Replaces the pill-card swimlane layout shipped in PR #245 — which the
operator rejected as "intentional divergence from the canonical
mockup" (issue #251) — with a circular-node, multi-region, bezier-edge
canvas that matches `marketing/mockups/provision-mockup-v4.png`.
What changed
------------
New geometry library (`src/lib/flowLayoutV4.ts`):
• Multi-region partition — caller supplies FlowRegion[]; every
region renders as a horizontal band stacked top → bottom.
• Per-region longest-path stage assignment (Kahn) keyed on Job
dependsOn + caller-supplied `extraDepIds` (component-graph edges
surfaced from ApplicationDescriptor.dependencies so dense families
like SPINE / GUARDIAN read as columns even when the test catalog
has no per-job dependsOn yet).
• Sub-column splitting at MAX_PER_COLUMN (8) so dense families
stack vertically rather than fanning out into many sub-columns.
• Caller-injected family palette (PRODUCTS taxonomy from
componentGroups.ts) so the flow + the wizard StepComponents
page colour-code identically.
• Bezier router — straight for span=0 within-region, cubic-bezier
for span≥1 and all cross-region edges (warm-amber dashed).
New presentation layer:
• `FlowCanvasV4.tsx` — circular nodes with status-tinted progress
arcs, family-colour rings, single-letter glyphs (✓ / ✕ / family
initial), per-status arrow markers, region band frames, and
stage column dividers + labels.
• `FlowDeploymentTree.tsx` + `flowDeploymentTreeData.ts` — left
"DEPLOYMENT PROGRESS" panel; static tree (NO accordion per the
operator's standing rule), groups by region → family → job.
• `FlowLogFeed.tsx` — right "LIVE LOG" panel; replays the focused
job's recent reducer events, status-coloured, blinking cursor
when live.
`FlowPage.tsx`:
• Replaces the JobBubble pipelineLayout pipeline with the
flowLayoutV4 + FlowCanvasV4 + tree + log triplet.
• Wires region descriptors from `useWizardStore().regions` (with a
fallback single-region for empty stores).
• Derives stage hints — Phase 0 = stage 1, cluster-bootstrap =
stage 2, components = 3 + componentGraphDepth.
• Picks an initial focused job (running > failed > first) so the
log feed always shows something on first paint.
• Inlines the surface CSS so canvas + tree + log stay in lockstep.
Preserved testid contract
-------------------------
data-testid="flow-canvas-svg" — root <svg>
data-testid="flow-job-<jobId>" — every node group
data-testid="flow-batch-<regionId>" — every region band
data-testid="flow-canvas-empty" — empty placeholder
So the existing cosmetic-guards Test #6/#7/#8 continue to pass without
edit (Jobs↔Batches mode toggle + single-click → FloatingLogPane behaviour
is unchanged).
New testids for the upgraded V4 surface:
data-testid="flow-node-circle-<jobId>" — actual <circle>
data-testid="flow-region-<regionId>" — region band frame
data-testid="flow-stage-<n>" — stage column divider
data-testid="flow-edge-<from>-<to>" — directional edges
data-testid="flow-deployment-tree" — left tree
data-testid="flow-log-feed" — right log panel
Tests
-----
21 new unit tests in `src/lib/flowLayoutV4.test.ts` lock the layout
contract (multi-region partitioning, cross-region edge classification,
family palette mapping, bezier routing). All 500 vitest tests + tsc
typecheck green.
Per docs/INVIOLABLE-PRINCIPLES.md
---------------------------------
#1 (waterfall) — full target shape ships in one PR: circular nodes,
multi-region bands, bezier edges, log feed,
deployment tree, family palette, stage hints.
#2 (no compromise) — no graph library, no canvas; pure SVG so testids
work and the operator can right-click → inspect.
#4 (never hardcode) — every dimension is in FlowGeometryV4 knobs;
every colour comes from the FlowFamily palette
(caller-injected, sourced from PRODUCTS).
Closes#251.
Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>