AE Architecture Map — L65 refresh, May 12 2026 REFERENCE
The Anything Engine
Surviving Surface Area
After the dead-code sweep + L20-L73 extraction wave, the codebase is small enough to fit in your head. This is the complete file map: 9 BFF wrappers, 8 hooks, 33 components, 23 AE lib modules, 4 openui modules — plus a freshly populated src/lib/ with 10 cross-feature shared modules and 19 per-feature utils directories. 1241 unit tests across 72 files (was 0 pre-sweep). 14 cross-feature dedupes documented below. Crash-safety: 4 ErrorBoundaries in production now (was 1 at session start) — AuthedContent shell, network route slot, CrayonChat dialog, AE Renderer.
1241
Unit tests (72 files)
Section 1 — the tree
src/features/anything-engine/ — full layout
src/features/anything-engine/
├── api/ # 1 file — TanStack Query hooks for conversations
│ └── use-anything-engine-conversations.ts
├── components/ # 33 files — the live AE UI surface
│ ├── chat-shell.tsx # /chat standalone route — 3,198 lines
│ ├── anything-engine-canvas-openui.tsx # NOTE: actually in openui/ subdir
│ ├── …26 anything-engine-* prefixed…
│ └── …6 unprefixed (avatar, voice, etc.)…
├── hooks/ # 8 files — React hooks for AE state
│ ├── use-conversation-starters.tsx
│ ├── use-dispatch-gate.ts (+ .test.ts)
│ ├── use-pitch-profile-poll.ts (+ .test.ts)
│ ├── use-preload-context.ts
│ ├── use-selected-anything-engine-conversation.ts
│ ├── use-anything-engine-conversation-search.ts
│ ├── use-voice.ts (TTS)
│ └── use-voice-input.ts (STT)
├── lib/ # 23 files — pure functions + helpers (was 4 pre-L20)
│ ├── anything-engine-hotkeys.tsx # React provider/context
│ ├── mock-outcomes.ts # mock fallback (TODO: real outcomes API)
│ ├── ack-for.ts (+ test) # MCQ acknowledgement strings
│ ├── adapt-contact-card.ts (+ test)
│ ├── array-buffer-to-base64.ts (+ test)
│ ├── build-thread-lang.ts (+ test)
│ ├── class-labels.ts (+ test)
│ ├── coerce-conversation-title.ts (+ test)
│ ├── contact-card-utils.ts (+ test)
│ ├── dispatch-card-helpers.ts (+ test)
│ ├── firm-name-utils.ts (+ test)
│ ├── format-helpers.ts (+ test) # formatUsd / parseUsd / formatBytes
│ ├── hotkey-parser.ts (+ test)
│ ├── leak-filter.ts (+ test) # banned-phrase + PII guard
│ ├── network-error-message.ts (+ test)
│ ├── parse-conversation-id.ts (+ test)
│ ├── relative-time.ts (+ test)
│ ├── sanitize-ask-back-reasoning.ts (+ test)
│ ├── scanning-phrases.ts (+ test)
│ ├── source-label.ts (+ test)
│ ├── starter-helpers.ts (+ test)
│ ├── strength-meter-utils.ts (+ test)
│ └── tooltip-position.ts (+ test)
├── openui/ # 4 files — OpenUI 0.5 canvas + primitives
│ ├── anything-engine-canvas-openui.tsx # THE network top-nav AE canvas (~2,080 lines)
│ ├── components.tsx # OpenUI primitive registry (~2,080 lines)
│ └── crayon-to-openlang.ts (+ .test.ts)
├── server/ # 9 files — TanStack Start server functions (BFFs)
│ ├── classify-fn.ts # ep 8400 — front-door classifier
│ ├── dispatch-fn.ts # ep 8399 — legacy dispatch
│ ├── openui05-dispatch-fn.ts # ep 8506 — OpenUI 0.5 dispatch
│ ├── interview-fn.ts # ep 8411 — per-class interview
│ ├── find-talent-interview-fn.ts # ep 8484 — find_talent dedicated
│ ├── start-outcome-fn.ts # ep 8417 — suggestion_request creation
│ ├── upload-files-fn.ts # ep 8420 — multipart deck upload
│ ├── pitch-profile-fn.ts # ep 8420 GET — ready-gate poll
│ └── build-summary-fn.ts # ep 8505 — re-summarize on edit
└── styles/ # 1 file — CSS for chat-shell + canvas
└── anything-engine.css # 3,063 lines (was 3,859 pre-sweep)
Section 2 — entry points
Two ways the user reaches AE
/network?active-view=anything-engine
The canonical product surface. Top-nav sparkle icon → URL switches → network-canvas.tsx renders <AnythingEngineCanvasOpenUI/> from openui/anything-engine-canvas-openui.tsx. This is what Mark dogfoods.
CANONICAL
/chat (standalone route)
Auth-gated full-page route. src/routes/_authed/chat.tsx renders <ChatShell/> from components/chat-shell.tsx. The full sandbox-port shape with side-bar, history list, persistent layout. Mark gated from this until history-replay backports stabilize.
DEEP-LINK
Section 2b — new this push (L73)
Crash-safety: 4 ErrorBoundaries in production
Pre-L73, the only React ErrorBoundary in the app was around the AE <Renderer/> (shipped May 9). A render throw anywhere else would blank-canvas the whole app. The L73 push (commit 1babb15c) added 3 new boundaries — the count is now 4.
AuthedContent boundary (whole-app shell)
Wraps the entire authed surface. A render throw in any feature canvas (network / copilot / settings / anything) shows a recoverable error UI instead of a blank page. Biggest single crash-blast-radius reduction.
SHIPPED L73
Network route boundary (per-canvas)
Wraps the network top-nav active-view canvas slot. A throw in OutcomesCanvas / DiscoverCanvas / TeamsCanvas / etc. no longer takes down the surrounding chrome. User can still tab to a working canvas.
SHIPPED L73
CrayonChat boundary (copilot dialog)
Wraps the CrayonChat composer + thread inside the copilot dialog. A render throw in a custom template (one of 18) no longer kills the dialog — user can dismiss and reopen.
SHIPPED L73
AE Renderer boundary (May 9 origin)
First boundary in the app. Wraps the OpenUI 0.5 <Renderer/> in anything-engine-canvas-openui.tsx. Catches render throws from primitive registry mounts so a malformed openui_lang from the server doesn’t blank the canvas. Commit 3d290fc.
PRE-EXISTING
Net effect. 1 boundary → 4 boundaries in a single PR. Plus
noImplicitOverride strict flag now enforced in
tsconfig.json — one more class of refactor regression caught at typecheck time. See
perf-wins.html wave 21-23 section for the full L73 commit breakdown.
Section 3 — the 9 BFFs
server/ — TanStack Start server functions
Every Xano endpoint the AE talks to has a thin TypeScript wrapper. The wrappers handle multipart encoding, env var resolution, response typing, and (post-this-session) authenticated user_id passthrough.
classify-fn.ts — ep 8400 (Haiku 4.5)
Front-door classifier. Routes a user query to one of 15 outcome classes (find_investors, find_talent, etc.) or "ask_back" if confidence < 0.7. Stateless, no Zep memory. Source-of-truth prompt: prompts/anything_engine/classify.md.
STATELESS
dispatch-fn.ts — ep 8399 (legacy)
Legacy dispatch from the pre-OpenUI-0.5 era. Used by chat-shell.tsx. Returns DispatchEvent[]. Now passes authenticated user_id (was hardcoded "15"). Wraps Xano group 1270.
USER_ID WIRED
openui05-dispatch-fn.ts — ep 8506 (OpenUI 0.5)
Canonical dispatch for the OpenUI 0.5 canvas. Returns top-level openui_lang string ready to feed into <Renderer/>. Wraps Xano group 1276. Server-side handles same-firm dedup + banned-phrase lint + SIGNAL TAXONOMY tag enforcement. Switches Opus 4.1 for find_investors, Haiku 4.5 for everything else.
USER_ID WIRED
interview-fn.ts — ep 8411 (Haiku 4.5)
Per-class interview gate for find_investors / find_customers / research_person. Returns {ready, summary, next_question, missing_fields, options[]}. find_talent has its own endpoint. Now passes user_id for Zep memory continuity per turn.
USER_ID WIRED
find-talent-interview-fn.ts — ep 8484 (Haiku 4.5)
find_talent dedicated interview endpoint. MCQ-driven 8-dim adaptive interview per Mark's May 6 verbatim prompt. Returns {stage, payload, raw, class}.
USER_ID WIRED
start-outcome-fn.ts — ep 8417
Eager suggestion_request row creation. Mark's Apr 30 directive: file uploads need a suggestion_request_id BEFORE any file is attached. Frontend calls on chat-mount or first tile-click.
USER_ID WIRED
upload-files-fn.ts — ep 8420 (multipart)
Multipart file upload. Reconstructs FormData from base64-encoded blobs. Triggers fn 12917 (extract-pitch-profile) + fn 12918 (build-pitch-profile) + embed step. Was the SECOND hardcoded "15" leak bug. Now wired correctly.
USER_ID WIRED (P0 BUG)
pitch-profile-fn.ts — ep 8420 GET
Read-only ready-gate poll over fundraising_pitch_profiles (table 710). Returns {ready, narrative_count, missing_fields, profile}. Frontend polls every ~5s after deck upload until ready=true. Stateless — no user_id needed (keyed on suggestion_request_id which is already user-scoped).
N/A (READ-ONLY)
build-summary-fn.ts — ep 8505
Re-runs the summary synthesizer when the user edits a confirmation field. Stateless — synthesis only, no DB write. Used by the post-confirmation readback edit-loop.
N/A (SYNTH ONLY)
Section 4 — 10 hooks
hooks/ — React state primitives
use-conversation-starters.tsx
487 LOC. Builds 4 dynamic starter slots (calendar / active-work / network-intel / time-of-day) from live data. Mark tell #4: starters are NEVER static strings. Capped at 3 per session for clean 3-col grid alignment.
DYNAMIC
use-dispatch-gate.ts (+ test)
Predicate hook for whether dispatch button can fire. Combines ready-gate poll state, narrative count, polling state, and error. 4 test cases.
GATE
use-pitch-profile-poll.ts (+ test)
Wraps pitchProfileFn in TanStack Query with ~5s refetch interval. Returns {profile, ready, narrativeCount, missingFields, isPolling, error}. 4 test cases.
POLL
use-preload-context.ts
Pre-loads user + company baseline context on Outcomes tab open. Lifts data into the canvas before the user types anything. Speeds first-turn perceived latency.
PRELOAD
use-selected-anything-engine-conversation.ts
URL-param-backed selection state for the conversation history list. Handles JSON-parse quirk where TanStack Router serializes numbers as quoted strings.
URL STATE
use-anything-engine-conversation-search.ts
URL-param-backed search query state for filtering the left-rail conversation list.
URL STATE
use-voice.ts (TTS)
Two-provider TTS: Gradium (primary) + ElevenLabs (fallback). 8 curated voices (4M/4F). Streaming + blob playback. Env: VITE_GRADIUM_API_KEY, VITE_ELEVENLABS_API_KEY.
VOICE
use-voice-input.ts (STT)
Web Speech API primary, MediaRecorder + Gradium ASR fallback. Press-to-talk UX (not silence detection).
VOICE
Section 5 — AE lib + openui
Pure functions + OpenUI primitives
The AE lib/ directory grew from 4 modules pre-L20 to 23 modules post-L65 as helpers were extracted out of chat-shell.tsx, components.tsx, and anything-engine-right-rail.tsx. Almost all carry colocated .test.ts coverage. Highlights below; the full inventory is in the tree above.
lib/anything-engine-hotkeys.tsx
React provider + context for AE keyboard shortcuts. Wraps the canvas + chat-shell.
CTX
lib/build-thread-lang.ts (+ test)
Builds a top-level OpenUI Lang string from the per-turn event log. Used by the canvas to feed <Renderer/>. 15 unit tests including malformed-lang edge case (closed L65).
EXTRACTED
lib/coerce-conversation-title.ts (+ 13 tests)
Defensive helper that detects MCQ-fragment titles (money ranges, percentages, single-clause text) and prefixes "New outcome · " so the left rail history stays scannable.
EXTRACTED
lib/leak-filter.ts + sanitize-ask-back-reasoning.ts (+ tests)
Guardrails. Banned-phrase + internal-routing-reasoning suppression so server-side reasoning never reaches the canvas surface. Mark spec May 7 fix.
EXTRACTED
lib/contact-card-utils.ts + adapt-contact-card.ts + firm-name-utils.ts (+ tests)
Result-card helpers. Dedupe firm-name labels, build dispatch-card props, adapt legacy Crayon contact_card payload to OpenUI ContactCard shape. 31 + 23 + tests for firm-name-utils.
EXTRACTED
lib/dispatch-card-helpers.ts + class-labels.ts + scanning-phrases.ts (+ tests)
Per-class labels + scanning-state phrases (varied verbs by outcome class) + dispatch-card formatters. 36 + 33 + 12 tests respectively.
EXTRACTED
lib/format-helpers.ts + relative-time.ts + tooltip-position.ts (+ tests)
Pure formatters: USD ($1.2M / $850K), bytes (12 KB / 5 MB), relative time (2h / 3d), tooltip-arrow positioning math. Right-rail + chat-shell + composer all consume.
EXTRACTED
lib/strength-meter-utils.ts + source-label.ts + starter-helpers.ts (+ tests)
Match-strength bond color/label, signal-source taxonomy label, conversation-starter slot builders. 43 + 38 + 26 tests.
EXTRACTED
lib/mock-outcomes.ts
Mock data fallback when the outcomes API is unavailable. Used by chat-shell, right-rail, outcome-sidebar, anything-engine-right-rail. Marked TODO: replace with real outcomes API once backend lands.
MOCK
openui/anything-engine-canvas-openui.tsx
~2,080 lines. The OpenUI 0.5 network-tab canvas. Renders welcome state (hero + 3 starters + 15 tile expansion), interview turns, dispatch confirmation, and result cards. Uses @openuidev/react-lang Renderer with the components.tsx primitive registry.
CANVAS
openui/components.tsx
~2,080 lines. OpenUI primitive registry. Defines every component the Renderer can mount: ContactCard, ScanningCard, InterviewTurn, DispatchConfirmation, ButtonGroup, ErrorState, etc. Schema-validated via Zod.
PRIMITIVES
openui/crayon-to-openlang.ts (+ 9 tests)
Adapter layer for legacy DispatchResult.events[] (Crayon shape) → OpenUI Lang string. Used by chat-shell to feed legacy event streams into the new Renderer.
ADAPTER
Section 5b — new this wave
Shared lib + per-feature utils after L65
L20-L73 extracted ~75 helper modules across the codebase, with byte-identical copies promoted to src/lib/ and feature-internal helpers landing in per-feature utils/ + lib/. Each extraction carries colocated unit tests. Total: 1241 tests across 72 files.
Why it matters. Pre-sweep, identical helpers were copy-pasted across 2-7 sites with subtle drift. Post-L65, every cross-feature primitive lives in exactly one canonical location with full test coverage. The next person to touch chat-shell, copilot, or the right-rail can grep for the helper they need rather than rewriting it.
src/lib/ — cross-feature shared (10 modules, all with colocated tests except utils.ts & audio.ts)
src/lib/utils.ts
Canonical cn() Tailwind class merger (clsx + twMerge). Used everywhere — single source of truth for class composition.
FOUNDATION
src/lib/audio.ts
Premium chime — warm filtered ADSR-enveloped tones for start/stop. Replaces inline AudioContext code in mic-button + voice-bar.
FOUNDATION
src/lib/djb2.ts (+ test)
DJB2 string hash. Was duplicated inline in 2 locations. Promoted to canonical.
DEDUPED
src/lib/name-initials.ts (+ test)
Canonical nameInitials, emailNameInitials, firstTwoInitials. Avatar-fallback logic was copy-pasted across 4+ surfaces; now one helper.
DEDUPED
src/lib/person-subtitle.ts (+ test)
Builds the "Title @ Company" or "Email" subtitle line under a person row. Unified 5 inline copies across copilot, network, search, person-sheet, person-picker.
DEDUPED
src/lib/sse-stream.ts (+ test)
Server-Sent Events parser. Was leverage-loops-owned; promoted to src/lib. Used by leverage-loops, meeting-prep, outcomes for streaming Xano responses. Replaces 47+ inline lines per call site.
PROMOTED
src/lib/sanitize-html.ts (+ test)
DOMPurify wrapper with server-fallback + XSS guard for xlink:href + formaction. 55 unit tests covering edge cases.
FOUNDATION
src/lib/tts-text-prep.ts (+ test)
Strips markdown + de-acronyms + sentence-splits text before sending to TTS. 43 tests. Was duplicated between AE voice + copilot voice; now one canonical implementation.
DEDUPED
src/lib/date-formatters.ts (+ test)
4 named exports (formatDate, formatDateShort, formatDateTime, formatDay) consolidating 6 inline copies across calendar, history, meeting-prep, conversation-list, etc.
DEDUPED
src/lib/date-range-formatters.ts (+ test)
formatDateRangeSimple + formatDateRangeSmart. Unified 2 of 3 sites; 17 tests. (3rd site is feature-specific, intentionally separate.)
DEDUPED
src/lib/timezone.ts (+ test)
toTZDate timezone helper for calendar / meeting-prep. 10 tests covering DST + offset edges.
FOUNDATION
Per-feature utils + lib (19 directories, 14 carry tests)
src/features/
├── activities/utils/ # date.ts (parseDateString) — 7 tests
├── anything-engine/lib/ # 23 modules, 21 tests — see Section 5
├── collections/utils/ # excludeById + filterIconsBySearch + resolveIconName — 21 tests
├── command-palette/utils/ # findSearchResultMatch — 10 tests
├── copilot/lib/ # images.ts + xano-copilot.ts + orbiter-avatar.ts
├── copilot/utils/ # network-summary + relative-time — 15+ tests
├── discover/utils/ # grid-node-adapters (5 byte-identical) + no-results — 11 tests
├── email-composer/utils/ # attachment-helpers (formatFileSize + getAttachmentIcon) — 18 tests
├── email-inbox/utils/ # categorize-attachments + render-workspace-icon — 22 tests
├── email-outreach/utils/ # (1 module, 1 test)
├── emails/utils/ # isMessageSentByUser + getSenderDisplayName — 12 tests
├── import-contacts/utils/ # formatImportRelativeTime — 6 tests
├── master-companies/lib/ # funding-round-helpers — 35 tests
├── master-links/utils/ # dedupeLinksByService — 7 tests
├── master-persons/utils/ # (1 module, 1 test)
├── meeting-prep/utils/ # attendees + group-events + meeting-time — 53 tests
├── merge/utils/ # getUnique{Emails,Addresses,Phones} — 11 tests
├── node-selection/utils/ # partitionSelectedNodes + selectionSummary — 19 tests
├── node-targets/utils/ # isNodeViewQueryKey + NODE_VIEW_QUERY_KEYS — 8 tests
├── notes/utils/ # note-modal-helpers (3 fns) — 23 tests
├── organisations/utils/ # member-display + sort-organisations — 21 tests
├── relativity/lib/ # colors — 19 tests
├── tiptap-editor/lib/ # 4 modules (incl tiptap-utils + advanced + collab + supabase) — 55 tests
└── voice-settings/utils/ # voice-mapper helpers — 11 tests
Cross-feature dedupes — 14 promotions documented
Each row below names a primitive that existed as N inline copies before this wave and is now in exactly one canonical location.
1. djb2 hash → src/lib/djb2.ts
2 inline copies replaced. Used by deterministic-color avatars and stable hash IDs.
2 → 1
2. nameInitials / emailNameInitials → src/lib/name-initials.ts
2 inline copies replaced for firstTwoInitials + new canonical for both name- and email-derived initials.
2 → 1
3. getAuthToken → src/integrations/xano (canonical)
7 inline copies across BFFs and direct fetchers consolidated. Auth-token leaks were a recurring P0 source — now one helper to inspect.
7 → 1
4. personSubtitle → src/lib/person-subtitle.ts
5 inline copies unified. "Title @ Company" or "Email" line under a person row.
5 → 1
5. sse-stream → src/lib/sse-stream.ts (was leverage-loops-owned)
Promoted out of feature-local. Now consumed by leverage-loops, meeting-prep, outcomes. Replaces 47 inline lines per call site (3 sites).
3 → 1
6. formatDate → src/lib/date-formatters.ts
6 inline copies replaced by 4 named exports.
6 → 1
7. formatDateRangeSimple + formatDateRangeSmart → src/lib/date-range-formatters.ts
2 of 3 sites unified. 3rd site is intentionally feature-specific.
3 → 1
8. TTS text-prep → src/lib/tts-text-prep.ts
Duplicated between AE voice + copilot voice; now one canonical implementation. 43 tests.
2 → 1
9. formatUsdShort + formatBytes → AE lib/format-helpers.ts (canonical)
AE right-rail was carrying its own copy; now imports from lib/. Other surfaces (chat-shell, dispatch-card) already use canonical.
2 → 1
10. buildAttendees → meeting-prep/utils/attendees.ts
3 inline copies (2 in meeting-prep canvases + 1 in copilot) unified. Builds the comma-separated attendee list for prep cards.
3 → 1
11. buildNetworkSummary → copilot/utils/network-summary.ts
Was duplicated across 2 canvas surfaces; now one helper.
2 → 1
12. filterIconsBySearch → collections/utils/filter-icons-by-search.ts
Originally a useMemo inside teams; now reused by collections + teams. First cross-feature reuse out of a feature-owned helper.
2 → 1
13. formatCategoryName + stripBrackets → email-inbox/utils
Final byte-identical cross-file duplicate in email-inbox. 2 inline copies unified.
2 → 1
14. 5 byte-identical gridNodes adapters → discover/utils/grid-node-adapters.ts
Largest single dedupe of the wave. 5 byte-identical adapter functions across discover surfaces consolidated into one module. Closed L65.
5 → 1
What this gets you. 1241 unit tests across 72 test files (was 0 pre-L20). Every helper that ships in PR #343 has executable proof of behavior. The architecture-map of pure-function helpers is now searchable: grep src/lib first, then per-feature utils/ or lib/, then the component itself.
Section 6 — the 33 surviving components
components/ — what actually ships
Big surfaces (the entry components)
chat-shell.tsx # /chat — 3,198 lines, full sandbox-port shape
event-renderer.tsx # Crayon event → React mapping for chat-shell
right-rail.tsx # 309 lines, lightweight rail variant
anything-engine-right-rail.tsx # 1,342 lines, full Summary/Context/Modify tabs
icon-top-nav.tsx # Top-nav for /chat (replaces the network top-nav)
outcome-sidebar.tsx # Mock outcomes sidebar in chat-shell
Crayon-style cards (rendered by Renderer)
dispatch-confirmation-card.tsx # Editable summary card before dispatch fires
inline-interview-card.tsx # MCQ card rendered in chat thread
inline-dispatch-card.tsx # In-thread dispatch confirmation
fork-in-the-road.tsx # PATH A (deck) vs PATH B (interview) choice
person-picker.tsx # Network search with avatar + context fetch
UI primitives + AE-specific chrome
avatar.tsx # DiceBear notionists fallback
avatar-travel-clone.tsx # FLIP travel — Mark tell #1 (byte-exact easing)
loading-indicator.tsx # Crayon LoadingIndicator (canonical)
lattice-orb.tsx # Animated 3D globe (canvas)
memory-panel.tsx # Memory management sidebar
mic-button.tsx # Mic toggle, 3-state arc
voice-bar.tsx # Voice UI: mic, interim text, playback, picker
voice-controls.tsx # Portal-based voice controls for composer
anything-engine-composer.tsx # Custom composer with AE chrome
anything-engine-scanning-card.tsx # Scanning state with spinner verbs
anything-engine-dispatch-confirmation.tsx
anything-engine-mode-indicator.tsx
anything-engine-tooltip.tsx
anything-engine-strength-meter.tsx
anything-engine-status-dot.tsx
anything-engine-badge-cluster.tsx
anything-engine-card-badge.tsx
anything-engine-company-chip.tsx
anything-engine-conversation-context-menu.tsx
History list (left rail)
anything-engine-history-list.tsx
anything-engine-history-group.tsx # Today / Yesterday / This week groupings
anything-engine-history-item.tsx
anything-engine-history-search.tsx
Section 7 — how it all fits together
End-to-end find_investors flow
1. User clicks find_investors tile
→ anything-engine-canvas-openui.tsx
→ composer pre-fills with starter prompt
2. User types and hits Send
→ runTurn() in canvas-openui.tsx
→ openui05ClassifyFn (ep 8400) — Haiku confirms class
→ setLatestClass("find_investors")
3. Interview phase begins
→ interviewFn (ep 8411) — Haiku asks first question
→ InterviewTurn primitive renders MCQ chips
→ User clicks chip → MCQ value submits → next interviewFn call
→ Loop until ready=true
4. Result count picker (Mark spec May 8)
→ Result count picker turn renders
→ User picks 20 / 100 / "as many as you can"
5. Format picker (Mark spec May 8)
→ Format picker turn renders
→ User picks suggestion / collection / csv / pdf
→ coerceConversationTitle helper sets sane left-rail title
6. Dispatch fires
→ openui05DispatchFn (ep 8506) with authedUserId
→ Xano: prefilter → headroom → graph_rag → final-trim
→ Returns openui_lang string with N ContactCard mounts
7. Cards render
→ <Renderer response={openui_lang}/>
→ Mounts N ContactCard primitives from components.tsx
→ Each card: name + role + company + thesis + match% + DiceBear avatar
8. Right rail updates
→ "ae-canvas-update" CustomEvent fires
→ anything-engine-right-rail.tsx Summary tab flips to Complete (green)
→ Match count + duration shown