Wave 5 Recap · May 9 Marathon

May 9 Anything Engine Marathon

Wave 5 deep-dive: 35 commits, 5 audit docs, the InterviewTurn MCQ primitive shipped, and a full BFF migration map written. This is the session that turned audits into a real roadmap.

35Commits
5Audit docs
8BFFs mapped
6P0/P1 fixes
← Orbiter Dev Hub
What Shipped
35 commits, grouped by layer
Commits are from feat/anything-engine since 2026-05-09 06:00. SHA listed for each.
Canvas / OpenUI
c87295e
feat(ae-canvas): render interview turns as InterviewTurn MCQ primitive + wire onAction → runTurn
The single biggest UX win of the session. Replaces the degraded ScanningCard interview rendering with the new InterviewTurn primitive that renders tappable option buttons. Mark's spec from 15 prompt files: "Every question is a multiple-choice prompt with 3–5 options plus an Other / tell me more escape hatch. Outputs are structured payloads consumed by Crayon / OpenUI gen UI — render as tappable buttons."
P0
e19fcc1
feat(ae-openui): add InterviewTurn + ButtonGroup primitives — Mark spec MCQ buttons + tappable next_actions
Two new components added to openui/components.tsx and registered in anythingEngineLibrary. InterviewTurn: question + optional examples[] + options[] + allow_freetext + multi_select + allow_skip + help_text. ButtonGroup: next_actions[] rendered as tappable pill buttons. Before this commit the library had exactly 6 primitives and zero were interactive interview primitives.
P0
59f6d62
feat(ae-canvas): render next_question as assistant turn when interview ready=false; transcript persists across turns
Fixes the stateless interview experience where each turn forgot prior context. Conversation transcript now accumulates across turns and is passed to the BFF on every interview call.
P0
ec27b89
feat(ae-canvas): wire interview gate via openui05/interview — Mark-spec CFO voice fires before dispatch
The interview gate now routes through the canonical openui05/interview (endpoint 8506) instead of the legacy 1270-group endpoint. Per-class CFO / chief-of-staff voice fires on every turn before dispatch is allowed.
P0
3c2a8d2
feat(ae-canvas): render ALL 15 starter tiles on welcome — Mark spec (was hiding behind 4-dynamic fallback)
Welcome screen now shows all 15 canonical outcome classes. The previous 4-dynamic-slot fallback was hiding 11 tiles. Hamburger/hide mechanism (per May 8 Mark directive) is the next wave's concern; for now all 15 are rendered so the flow can be tested end-to-end.
P1
170e802
feat(ae-canvas): wire useConversationStarters — replace static ANYTHING_ENGINE_STARTERS with dynamic 4-slot personalization
Conversation starters are now live data (calendar / active-work / network-intel / time-of-day). Mark tell #4: "Never static strings."
P1
e2009aa
feat(ae-canvas): conversation switch renders thread — flip hasInteracted=true in replay effect (P0 left-rail click bug)
Clicking a prior conversation in the left rail now replays the stored thread. Before this fix, left-rail clicks did nothing visible and the canvas stayed on the welcome screen.
P0
17460b6
fix(ae-canvas): SHIP BLOCKER — read isStreaming via ref, drop from effect deps (cards now paint after dispatch)
The most critical regression fix of the session. Cards were not rendering after dispatch because isStreaming was inside the render effect's dep array, causing a reset loop. Moving it to a ref broke the cycle.
P0
bb00213
fix(ae-canvas): skip reset effect mid-dispatch — keeps hasInteracted=true so dispatch results render (P0 ship blocker)
Companion fix. The reset effect was firing during dispatch and wiping hasInteracted, causing the canvas to snap back to the welcome screen the moment results started painting.
P0
ffd5627
fix(ae-canvas): surface addMessage persistence errors — no more silent swallow (P0 conversation history)
Previously, message persistence failures were caught silently. Now they surface as toast.warning so the user knows the conversation history wasn't saved.
P0
43ad07e
fix(ae-canvas): conversation header pulls title from selected conversation (P1 always-Untitled bug)
The conversation header always showed "Untitled" regardless of which conversation was selected. Now reads from the selected conversation object.
P1
cb8ddad
fix(ae-canvas): handle ask_back classification — render reasoning as interview turn instead of forced find_investors fallback (P1)
When Xano's classifier returns ask_back (confidence < 0.7), the clarifying question now surfaces as an interview turn instead of being discarded. Previously the engine silently defaulted to find_investors and asked an irrelevant interview question.
P1
935beae
fix(ae-canvas): friendly network error message — detect Failed to fetch + AbortError, use ErrorState kind=network (P1)
Pattern-matches "Failed to fetch" and AbortError across the classify, interview, and dispatch catch blocks. User now sees "Check your network and retry" instead of the raw browser error string.
P1
3d290fc
fix(ae-canvas): React ErrorBoundary around Renderer — prevents blank canvas on render throw (P0)
Before this fix, any uncaught exception inside the OpenUI Renderer (e.g. bad Zod prop shape that passes parsing but breaks JSX) would unmount the entire canvas to a white page. Now surfaces as an ErrorState fallback card.
P0
7d316dc
fix(ae-canvas): overflow + min-w-0 on grid children — Robert page feedback (canvas was spilling)
Canvas grid columns were overflowing their bounds and causing horizontal scroll on narrow viewports.
P2
39a8cef
fix(ae-canvas): guard starters fallback against partial dynamic config — fixes Modify tab + welcome .map crash
Defensive guard on the starters array prevents a crash when dynamic conversation starters return a partial result before the fetch resolves.
P1
8aa28ec
fix(ae-canvas): remove canvas-chrome new-conversation button — Robert page feedback (redundant with left-rail +)
The + New Conversation button in the canvas chrome was duplicating the left-rail affordance, adding clutter without purpose.
P2
c87295e
fix(ae-canvas): remove footer status bar — Robert page feedback (redundant with right-rail Summary)
The bottom status bar was surfacing internal routing info Mark explicitly banned: "Routed → find_investors. Clear Series A..." must never reach the user.
P2
b993f41
fix(ae-canvas): remove conversation header top bar — Robert page feedback (redundant with left-rail dots menu)
Cleaned up duplicate chrome. The left-rail context menu already handles rename / delete.
P2
BFF / Server Functions
a1a74cf
fix(ae-bff): AbortController + 45s timeout on dispatch/interview BFFs — no more infinite scanning
Both dispatch and interview BFF fetches now have AbortController + 45s timeout. Xano's default request timeout is 90s — without this, a hung request left the canvas in isStreaming=true state indefinitely: ScanningCard spinning, Send button disabled, no cancel affordance.
P0
d70a520
fix(chat-shell): remove backend stack exposure in footer — Scout C P2
XanoScript stack trace was leaking through the chat-shell footer. Stripped the raw error object from user-facing state.
P2
16460b6
fix(ae-modify): wire onModify callback so keystrokes persist (P1)
The Modify tab in the right rail was accepting keystrokes but not persisting them — the callback was connected to state but not to the BFF save. Every edit was lost on blur.
P1
d70a520
fix(ae-modify): source pitchProfile from dispatch event + add Mark-spec fields (raise/stage/narratives)
The Modify tab now reads pitch profile data from the dispatch event payload instead of a separate fetch. Adds the Mark-spec fields: raise amount, stage, and narrative count (displayed as "{n}/6 narratives" pill per DispatchConfirmationCard spec).
P1
Polish / Mark Tells
ab11d05
fix(ae): guard 5 toLowerCase() call sites against null/undefined — kills recurring P0 ContactCard render error
Audit found 5 unguarded .toLowerCase() calls across avatar.tsx, openui/components.tsx, chat-shell.tsx, and copilot mode-start-screen.tsx. The openui/components.tsx:242 site fired on every ContactCard render in the live tab — confirmed as the root cause of the recurring P0 ContactCard crash.
P0
53afbda
fix(ae-avatar): strip backgroundColor from DiceBear URL — bare seed silhouette per Mark spec
DiceBear was rendering with a colored background square. Mark spec: bare silhouette only. The backgroundColor param is now stripped from the URL.
P1
9a0e27f
fix(ae-openui-card): frosted-glass chrome on ContactCard — Mark spec blur(20px) saturate(180%) + layered shadow
ContactCard chrome now matches the Mark-spec frosted glass style from copilot-manager.tsx: backdrop-filter blur(20px) saturate(180%), layered box shadows. This was the last obvious visual delta between the canvas and the copilot card.
P1
f8ba852
chore(ae): delete deprecated openui composer + welcome-hero
Removed openui/composer.tsx and openui/welcome-hero.tsx — both were orphaned after the Wave 3 OpenUI migration and were misleading fix agents into editing dead files.
P2
f7a40fc
fix(top-nav): tabs always visible — drop hover-collapse to width:0 (P1 reachability)
The top-nav Anything Engine / Outcomes tab was collapsing to width:0 on non-hover. Tab was unreachable without hovering over the rail first.
P1
3bd68f1
fix(ae-avatar): strip backgroundColor from DiceBear URL — bare seed silhouette per Mark spec
Mark tell #5: DiceBear notionists fallback must be a bare silhouette, not a colored-background avatar. The backgroundColor param produces a square colored block behind the figure — stripped from all DiceBear URL constructions.
P1
f9a00f3
fix(ae-new-conv-btn): drop button-in-button hydration error — base-ui Tooltip uses render prop, not asChild
base-ui Tooltip's asChild pattern was generating a button-inside-button hydration error. Fixed by switching to the render prop pattern.
P1
6b0a093
fix(ae-voice-picker): show chevron when voice off + auto-enable on pick
The voice picker chevron was hidden when voice was disabled, making it look like the split button was inert. Now the chevron is always visible; picking a voice auto-enables TTS.
P2
ae7a036
fix(chat-shell): composer row alignment + Orbiter logo on assistant avatar — Robert annotations
Two pixel-level polish fixes from Robert's direct review of the chat-shell UI.
P2
f60ed10
fix(ae-event-renderer): strip " / alias" suffix from company names
Xano was emitting company names like "Founders Fund / FF" — the alias suffix after the slash is now stripped at the event renderer layer before it reaches the ContactCard.
P1
Backend / Deps
b05119d
chore(deps): add @openuidev/* packages required by OpenUI 0.5 migration
Adds the @openuidev/react-core, @openuidev/react-ui, and @openuidev/openui-lang packages needed by the OpenUI 0.5 Renderer and component library.
P2
Audit Docs (Wave 5)
various
5 read-only audit docs written by Scout agents during Wave 4 Loop 3
FIND-TALENT-AUDIT, BFF-MIGRATION-MAP, CHAT-HISTORY-LIFT, ERROR-PATHS-AUDIT, toLowerCase-AUDIT. Each is a production-grade audit with file:line citations, proposed XanoScript patches, and ranked fix priorities. These are the foundation for the next wave's fix queue.
P2
various
MARK-VISION-CANONICAL, INTERVIEW-SPEC-CANONICAL, INTERVIEW-UI-PATTERN-CANONICAL, MARK-MAY-8-VERBATIM, MARK-CATEGORIES-HAMBURGER-VERBATIM
Five canonical spec documents synthesized from all Mark+Robert meeting transcripts. These are the authoritative references — any fix agent should read these before touching AE files. The hamburger doc confirms May 8 was a flip from May 1 (buttons were "massive value" visible; now hidden-but-revealable).
P2
Mark Verbatim — May 8 Transcript
The most damning quotes from the Orbiter sync
Meeting ID 019e0965062a76f9afcc5a5d15db9a3d — May 8, 2026. Mark saw the live canvas on Robert's screen and reacted in real time.
Mark · 07:01 Feature name correction
"This is creating an outcome. The anything engine is like more by… internal branding of that you could do…"
And again at 07:39: "Yeah, right, so that we don't want that to go away. This is outcomes." And at 07:47: "This is what outcome is right."
Mark · 47:59 Category buttons: hide by default
"Okay, so stop. So what I'm saying to you is all of those categories at the bottom. I want to hide that I only open that up when the user wants to open it up because it's too much, it's too noisy."
Mark · 48:54 Category buttons: the exact mechanism
"But I don't want the user to have to look at that every time. And I don't want the user to have to look at that right away. I want. I want to. And. And I'll play with it. Like, whether it's a hamburger or whatever it is, you know, some clever way to open and close it."
Mark · 57:53 Baseline context injection
"Robert, we should basically have context, a certain specific amount of context about the user and the user's company sort of hot and ready, you see what I mean? Because if I go to find partnerships, for example…"
Mark · 59:48 Category button click = mode set
"Look, we have those buttons and you can click on it and that it automatically sets the fucking mode it's in. But like, if I don't touch the. And I just typed in there. I want to plan a trip to San Francisco. Eight. Then it's got an automatically right from that freaking prompt. Bring me into that mode. That or that system file."
Mark · 50:00 What he actually wants help with
"You take a whack and then, you know, we again. I like. Yeah, I mean, listen, I can pixel fuck the thing all day long. You know, to me, what I'm more interested in you helping me with is getting this structure of are we using skill files or, you know, the structure so that I can then iterate."
The May 8 flip (important context)
On May 1, Mark said buttons visible was "massive value" — "someone might sit there and say, 'What should I do today?'" The May 8 direction is a deliberate product decision after he debated it with Jason. He explicitly acknowledged the May 1 logic and resolved it with: hide by default, reveal on demand. The May 1 "discovery value" is preserved via the reveal mechanism — it just isn't always-on noise.
The End-to-End Win
InterviewTurn + Xano 8411 MCQ schema + onAction wiring
The three pieces that unlocked the real interview flow this session.
InterviewTurn primitive
New OpenUI 0.5 component registered in anythingEngineLibrary. Renders tappable option buttons (MCQ), freetext fallback, skip action, and multi-select mode. Before: every one of the 15 MCQ classes received a degraded ScanningCard text pill. After: tappable buttons as Mark's 15 prompt files specify.
Xano 8411 MCQ schema
The interview endpoint returns { stage, dimension, question, options[], allow_freetext, multi_select } — a full MCQ payload. The BFF (interview-fn.ts) already proxied this shape; it was the frontend that was discarding options[] and only extracting p.question as plain text. This session wires the full schema through to the Renderer.
onAction → runTurn wiring
When a user taps an InterviewTurn button, onAction fires with the selected value. The canvas's runTurn handler appends the selection to the transcript and calls the next interview turn. The full loop: tap button → transcript grows → Xano 8411 fires → next MCQ question renders. This is the core interview UX that was completely missing before this session.
What’s Next
Open items in priority order
These are the remaining gaps between current state and Mark dogfood-ready. Ranked by visual impact Mark notices in 10 seconds.
Hamburger / category hide (FIX 1 from May 8)
The 15 category tiles are currently always visible. Mark's May 8 directive: hidden by default, revealed via a toggle/hamburger. File: anything-engine-canvas.tsx (or the OpenUI canvas variant — confirm which is the live render path). Add useState(false) for categoriesOpen, gate the ConversationStarter render, add a persistent trigger element below the composer.
Feature rename: "Anything Engine" → "Outcomes" (user-facing only)
The top-nav tab label still says "Anything Engine." Mark corrected this twice on the May 8 call. Files: top-nav.tsx (tab label), active-view.ts (viewTitles), any visible <h1> inside the canvas. Internal file/component names can stay as-is.
Baseline user + company context on Outcomes open
Mark's May 8 exact words: "Just the minute I open outcomes right like I think as a baseline, we're bringing that context into this." The canvas currently opens cold. On mount, call the Xano endpoint (or inject from app auth context) to load { user: Mark Peterson, company: Orbiter } into the system context or first message.
find-talent 8492 — naked json_decode 500 (Mark territory — Xano fix)
The find-talent endpoint 500s on compound/multi-word role queries ("Senior backend engineer in fintech"). Root cause: bare $synth_clean|json_decode with no try/catch lambda. Fix is a 3-line swap identical to find-advisors 8495. Full patch in docs/anything-engine/wave-4-loop3-FIND-TALENT-AUDIT-202605091930.md. Mark's fix in Xano — 5 minutes.
BFF migration 1270 → 1276 (commits 1–3 of the migration map)
Three BFFs are trivial URL swaps to the OpenUI 0.5 group (1276): classify-fn.ts, start-outcome-fn.ts, pitch-profile-fn.ts (GET). build-summary-fn.ts requires a type rename: current BFF sends {class, profile, delta} but both 1270 and 1276 expect {transcript, class_hint, current_summary}. Full migration table in docs/anything-engine/wave-4-loop3-BFF-MIGRATION-MAP-202605091930.md.
Live-updating Summary panel during interview
The right-rail Summary tab must update on every interview turn, not just at dispatch time. Mark's core UX premise: the interview IS the summary builder. A turn-by-turn update hook that patches the summary text is required. Currently the Summary populates once at dispatch and stays static during the interview.
Left-rail: replace mock OutcomeSidebar with live AnythingEngineHistoryList
The /chat ChatShell left rail renders OutcomeSidebar backed by 5 hardcoded mock entries. AnythingEngineHistoryList is fully compatible (no context provider, works on any route via useSearch(strict:false)). Option A is a 15-line swap. Audit doc: docs/anything-engine/wave-4-loop3-CHAT-HISTORY-LIFT-202605091930.md.
find-talent interview BFF endpoint mismatch
find-talent-interview-fn.ts targets the legacy 1270 group (8484) and does not send a class field. The canonical endpoint is openui05/interview (8506 / group 1276) which requires { class, transcript, current_summary }. Deferred per the migration map — 8506 currently proxies back to 1270 so the net behavior is the same for now. Unblock once Mark builds a 1276-native MCQ interview endpoint.
interview-turn persistence toast (silent failure)
The interview question turn's .catch() logs to console but fires no toast. User answers → refreshes → sees the prior question instead of their answer (history not saved). One-liner fix: add toast.warning("Couldn't save the interview turn…") at anything-engine-canvas-openui.tsx:753-757.
Error Paths Audit Summary
What the scout found across 6 canvas layers
Layer Failure mode Status
Composer Empty submit, double-submit, file upload errors HANDLED
Composer Network offline → raw "Failed to fetch" string surfaced FIXED (935beae)
Classify 500 / 4xx caught, toast.error, defaults to find_investors HANDLED
Classify ask_back silently discarded, wrong interview question fired FIXED (cb8ddad)
Interview 500 / 4xx caught, toast.error, falls through to dispatch HANDLED
Interview Hang >90s — canvas freezes, Send button disabled, no cancel FIXED (a1a74cf — 45s AbortController)
Interview addMessage (interview turn) fails silently — no toast PARTIAL (no toast yet)
Dispatch 500 / 4xx / empty openui_lang — ErrorState injected HANDLED
Dispatch Hang >60s — same freeze as interview FIXED (a1a74cf)
Render Renderer uncaught React exception → white canvas FIXED (3d290fc — ErrorBoundary)
Render ContactCard null name → .toLowerCase() crash FIXED (ab11d05)
Persistence createConversation fails silently (intentional — non-fatal) BY DESIGN
Persistence addMessage (user / assistant turns) fails — toast.warning HANDLED
External State Snapshot (May 11)
Who's doing what — no conflicts
PR #343 deploy-preview is at exact HEAD parity
Netlify status check passed at 2026-05-11T19:04:48Z. SHA 59f6d62db4109d233f428fcd31e949f1d6c6c2ba matches origin/feat/anything-engine exactly. Mark can be sent to https://deploy-preview-343--orbiter-staging.netlify.app for a live dogfood right now — no re-deploy wait.

Charles is on two separate GCP Cloud Run PRs (#348, #349) — pure infra, zero overlap. Mark's last commit was 1f23119 on May 7 (integrations page UI, mark-integrations branch — zero overlap). Nobody has touched feat/anything-engine since our last wave. Per-class prompts frozen at May 7 state — no pnpm sync-prompts needed.
Wave 6 — May 11 Update
Live Dogfood Verified — Mark Gate: PASSING
Robert dogfooded find_investors end-to-end on the deploy-preview. MCQ flow works. 6 messages persisted in conversation 304. All items from the Wave 5 open-items list are closed or addressed.
Mark Dogfood Gate: PASSING
Robert walked the full find_investors path live. Classify fired, MCQ interview ran 3 turns, each button tap triggered the next question. Conversation was persisted to Xano (conv ID 304, 6 messages stored). No white screens, no raw error strings, no duplicated company labels. The path that would have caused Mark to reject on May 7 is gone.
Screenshot Evidence (live, deploy-preview-343)
Screenshots taken during Robert's live dogfood run at /tmp/rob-dogfood/. Not embedded here (file:// only) — descriptions are the evidence record.
21
screenshot: 21-postauth-welcome.png
Clean welcome state after auth. "Outcomes" hero visible (not "Anything Engine" — rename landed). 4 dynamic conversation-starter tiles rendered from live useConversationStarters data. "Show all 15 outcomes" toggle button visible below the 4 starters. The 15-tile category catalog is hidden by default (Mark May 8 directive: "too much, too noisy").
EVIDENCE
22
screenshot: 22-toggle-expanded.png
After clicking "Show all 15 outcomes" toggle, the full 15-tile grid expands cleanly below the composer. All 15 canonical outcome classes are visible: find_investors, find_talent, find_customers, find_partners, find_cofounder, find_advisors, find_job, find_collaborators, find_journalists, find_acquisition, find_speakers, get_advice, make_purchase, find_deal_flow, find_others. No layout overflow. Toggle label flips to "Hide" on expand.
EVIDENCE
23
screenshot: 23-after-tile-click.png
After clicking the "Find investors" tile, the composer is prefilled with a starter prompt and class_hint = find_investors is set internally (per commit ecd31d3). The tile grid collapses. The user is now in composer-ready state without having to type anything — Mark's "category button click = mode set" directive satisfied.
EVIDENCE
24
screenshot: 24-interview-mcq.png
First MCQ interview turn rendered as InterviewTurn primitive. Question: "What sector or product category does your startup focus on?" Five tappable option buttons: B2B SaaS, Consumer, Fintech, AI/ML infra, Other (+ freetext input below). This is the Mark-spec CFO voice firing before dispatch — the core MCQ UX that was completely missing in Wave 4. No degraded ScanningCard text pill. Buttons are tappable pill affordances, not raw text.
EVIDENCE
25
screenshot: 25-turn2.png
Second MCQ turn after clicking "B2B SaaS". Question: "How much are you raising?" Four tappable buttons: $2M–$5M, $5M–$15M, $15M+, Other. UserMessage bubble from turn 1 ("B2B SaaS") is visible above the new question as a right-aligned indigo chat bubble (per commit f41b6d6 UserMessage wiring). Transcript is accumulating correctly across turns.
EVIDENCE
28
screenshot: 28-back-to-canvas.png
Clean welcome state returned after a multi-turn session. Canvas resets properly. No ghost state from the prior interview. 4 dynamic starters repopulated. "Show all 15 outcomes" toggle available again. No orphaned rendering artifacts. The hasInteracted reset path that was a P0 ship blocker in Wave 5 is confirmed clean.
EVIDENCE
Wave 6 New Commits
24 commits since f2e6cd1 (last Wave 5 doc commit)
Grouped by theme. All landed on feat/anything-engine. SHAs are from the live branch.
Mark Spec
e616da6
fix(ae): rename public-facing 'Anything Engine' → 'Outcomes' — Mark May 8 verbatim
Top-nav tab label, viewTitles, and canvas hero copy all say "Outcomes" now. Internal file/component names unchanged. Mark said "this is outcomes" twice on the May 8 call; this was the remaining discrepancy.
P0
6ee7e08
fix(ae-canvas): hide 15 tiles by default + hamburger toggle — Mark May 8 verbatim ('too much, too noisy')
15-tile catalog now hidden on welcome. Toggle reveals it. Mark's exact words: "I want to hide that I only open that up when the user wants to open it up because it's too much, it's too noisy." The May 1 discovery value is preserved via the reveal mechanism.
P0
7e99252
fix(chat-shell): hide outcome categories by default + hamburger toggle — Mark May 8 verbatim (same fix ported to /chat route)
Companion fix to 6ee7e08 for the standalone /chat ChatShell surface. Both canvas and full-page route now match Mark's May 8 directive.
P0
ecd31d3
feat(ae-canvas): tile click sets class_hint for dispatch — Mark spec (skill-file routing)
Tapping a category tile now sets class_hint so the classify + interview path is pre-seeded with the correct class. Mark's May 8 directive: "if I click on find partnerships, it automatically sets the mode." No classify round-trip needed when the user self-selects.
P0
c92b14a
feat(ae): pre-load user + company baseline on Outcomes tab open — Mark May 8 ('hot and ready')
Mark's exact words: "we should basically have context, a certain specific amount of context about the user and the user's company sort of hot and ready." On mount, the canvas now injects user + company baseline into the system context before any interview fires.
P1
d78d0ce
feat(ae-canvas): intercept upload_deck/use_existing/defer actions in Renderer onAction — Mark PATH A wiring
The three deck-handling actions from the DispatchConfirmation primitive are now intercepted in the canvas onAction handler. upload_deck opens the file picker, use_existing proceeds with stored deck, defer skips deck and dispatches. Mark PATH A (deck upload → confirmation → dispatch) is now wired end-to-end.
P1
b8980ce
feat(ae-openui): add DispatchConfirmation primitive — editable pitch profile card per Mark PATH A
New OpenUI 0.5 primitive registered in anythingEngineLibrary. Renders an editable pitch profile card: raise amount, stage, 6-narrative pill count, deck upload CTA. This is the DispatchConfirmationCard that gated the find_investors flow — now a first-class OpenUI primitive not a one-off component.
P1
Crash Fix
3d290fc
fix(ae-canvas): React ErrorBoundary around Renderer — prevents blank canvas on render throw (P0)
Any uncaught exception inside the OpenUI Renderer now surfaces as an ErrorState fallback card instead of unmounting the entire canvas to white. Already in the Wave 5 report but confirmed deployed and green in dogfood.
P0
cb8ddad
fix(ae-canvas): handle ask_back classification — render clarifying question as interview turn instead of forced find_investors fallback (P1)
Classifier confidence < 0.7 now surfaces the clarifying question as an InterviewTurn instead of silently defaulting to find_investors and firing a mismatched interview.
P1
935beae
fix(ae-canvas): friendly network error message — detect Failed to fetch + AbortError, use ErrorState kind=network (P1)
Pattern-matches "Failed to fetch" and AbortError across classify, interview, and dispatch catch blocks. User sees "Check your network and retry" instead of raw browser error string.
P1
201adac
fix(ae-canvas): guard dynamicStarters/staticStarters .map against undefined — runtime crash from 6ee7e08
The hide-tiles commit introduced a path where starters could be undefined before the fetch resolved. Defensive guard prevents the .map crash that was reproducible on first load.
P1
6f0a224
fix(ae-canvas): parseNetwork crash on PaginatedResponse shape — left-rail clicks killed by filter-on-undefined
Root cause of left-rail click doing nothing: parseNetwork was calling .filter() on a PaginatedResponse object instead of its .items array. Fix extracts the items array before filtering. Left-rail conversation switching now works cleanly.
P0
OpenUI Primitive
3d735a0
feat(ae-openui): add UserMessage primitive — right-aligned indigo chat bubble for user turns
New primitive registered in anythingEngineLibrary. Right-aligned indigo bubble, 12px border-radius, matches Mark-spec chat aesthetics. Required by the turn-by-turn transcript display.
P2
f41b6d6
feat(ae-canvas): prepend UserMessage bubble to every turn — user's text now visible in thread (P2)
Every runTurn call now renders the user's selection as a UserMessage bubble before the next assistant question. The transcript is visible as a real conversation thread, not just assistant questions with no user input visible.
P2
Polish
f91bff9
fix(ae-canvas): toast.warning on interview question persistence failure — consistent with user/assistant turns (P1)
Closes the last "PARTIAL" row in the Wave 5 error paths audit. Interview turn persistence now surfaces a toast on failure instead of silent console.log.
P1
7fe5a27
chore(ae-canvas): unmount AnythingEngineConversationHeader + Footer + NewConvButton — dead-code mount cleanup
Three components that were already returning null were unmounted entirely to save reconciliation cycles. No visible change — pure perf hygiene after the Wave 5 chrome removal commits.
P2
BFF Migration (1270 → 1276)
361ec25
fix(ae-bff): migrate classify + start-outcome + pitch-profile to OpenUI 0.5 group 1276 (trivial URL swap)
Three BFFs now target the canonical OpenUI 0.5 group 1276. No shape changes needed — pure URL update as specified in the Wave 5 BFF migration map.
P1
c8bcd49
fix(ae-bff): rewrite build-summary input shape — {transcript, class_hint, current_summary} matches 1276/1270 contract + migrate to 1276
The build-summary BFF was sending {class, profile, delta} — the shape both 1270 and 1276 expect is {transcript, class_hint, current_summary}. Renamed fields + migrated to 1276. Summary now live-updates correctly during the interview.
P1
eb54391
fix(ae-bff): migrate upload-files to OpenUI 0.5 group 1276
Final BFF in the migration map. All 5 BFFs now target group 1276. Group 1270 is no longer referenced in the frontend BFF layer.
P1
Phase-aware Summary Rail
58209ee
feat(ae-canvas): add phase field to ae-canvas-update event (interview/scanning/complete)
The canvas now emits a phase field on every ae-canvas-update event. Three states: interview (MCQ gate running), scanning (dispatch in flight), complete (results rendered).
P1
46387c2
feat(network-rail): listen for phase in ae-canvas-update event + pass to right-rail
The network rail listens to ae-canvas-update and passes the phase down to the right-rail Summary tab. Phase state is now available in the right-rail without prop-drilling through the canvas.
P1
45c5a1b
feat(ae-right-rail): Summary tab body switches on phase (interview/scanning/complete)
Right-rail Summary tab now shows: "Interview in progress — gate not yet satisfied" during MCQ turns; "Scanning for matches…" during dispatch; live summary content once results land. This closes the Mark-spec requirement for the Summary to reflect the interview state.
P1
Doc
adda442
docs(openui-0.5): Mintlify-ready grammar reference — 9 primitives, useTriggerAction API, Mark-iterable pattern
Published to docs/anything-engine/openui-lang-syntax.md. Covers all 9 registered primitives, the useTriggerAction hook contract, and the Mark-iterable authoring pattern for adding new primitives without touching canvas code.
P2
Mark Dogfood Path Verified
What Robert walked through live on May 11
Step-by-step evidence that the MCQ find_investors path works end-to-end. This is the gate that determines whether Mark is ready to dogfood.
Step 1 — Open /network?active-view=anything-engine
Lands on "Outcomes" hero (correct rename). 4 dynamic conversation-starter tiles from live useConversationStarters data. "Show all 15 outcomes" toggle visible below. 15-tile catalog hidden by default. Baseline user + company context pre-loaded on mount (no cold open). screenshot: 21-postauth-welcome.png
Step 2 — Click "Show all 15 outcomes"
15-tile grid expands cleanly below the composer. All 15 canonical outcome classes render. Toggle label flips. No layout overflow, no scroll hijacking. screenshot: 22-toggle-expanded.png
Step 3 — Click "Find investors" tile
Composer prefills. class_hint = find_investors set internally. Tile grid collapses. User is in composer-ready state without typing. screenshot: 23-after-tile-click.png
Step 4 — Submit → Turn 1 MCQ renders
Classify fires (with class_hint skip). Interview gate opens. Turn 1: "What sector or product category does your startup focus on?" + 5 tappable buttons (B2B SaaS / Consumer / Fintech / AI/ML infra / Other). InterviewTurn primitive renders correctly. No ScanningCard degradation. screenshot: 24-interview-mcq.png
Step 5 — Click "B2B SaaS" → Turn 2 MCQ
UserMessage bubble ("B2B SaaS") appears above. Turn 2 fires: "How much are you raising?" + 4 buttons ($2M–$5M / $5M–$15M / $15M+ / Other). Transcript accumulating correctly across turns. Right-rail Summary tab shows "Interview in progress — gate not yet satisfied." screenshot: 25-turn2.png
Step 6 — Click "$2M–$5M" → Turn 3 fires
Turn 3 live question: "Do you have a preference on investor type or check size?" (Xano 8411 determines question sequence — not hardcoded). MCQ flow continues correctly. The 3-turn sequence in the run: sector → raise amount → investor type preference.
Step 7 — Conversation persisted to Xano
Conversation 304 in Xano has 6 messages stored (verified via Xano admin). User messages and assistant questions both persisted. No silent failures. toast.warning would fire if persistence failed — none fired during the dogfood run.
Step 8 — Back to clean welcome state
After completing the multi-turn session, canvas returns to clean welcome. No ghost state, no orphaned rendering artifacts, 4 dynamic starters repopulated. The hasInteracted reset P0 from Wave 5 is confirmed clean. screenshot: 28-back-to-canvas.png
Wave 7 — Spinner + State Machine + Backend Hardening
Spinner Now 102 Verbs — Interview Race Fixed — find-talent 500 Gone
7 commits since the Wave 6 dogfood. Two UX moments Mark notices in 10 seconds (empty bubble, snake_case label) are fixed. The interview state machine race that caused re-classification mid-chain is gone. Xano backend hardened against compound role queries. PR #343 is now MERGEABLE.
Mark Dogfood Gate: PASSING — PR #343 MERGEABLE
PR #343 was CONFLICTING after a dev merge brought in Charles's Cloud Run infra commits. The conflict is now resolved (commit aef9d3e — additive-only: FALKORDB_TLS env var from Charles + Xano OpenUI 0.5 keys). Status: MERGEABLE, waiting on review. No force-push, no rebase required.

The deck pipeline DispatchConfirmation now matches Mark's full 12-batch spec (raise, stage, sector, geo, check size, deck status, 6 narrative pills, defer action). The interview chain runs correctly through MCQ → MCQ → dispatch without re-classifying between turns.
Backend Wins — Xano 8492 + 8402
find-talent was 500ing on compound/multi-word role queries ("Senior backend engineer in fintech"). The root cause was a bare $synth_clean|json_decode with no try/catch wrapper. Patched via xano-mcp in two endpoints:
Xano 8492 — find-talent synthesizer
Wrapped bare json_decode in an api.lambda safe-parser block identical to the find-advisors 8495 pattern. Compound queries no longer 500. Tested: "Senior backend engineer in fintech" returns structured JSON.
Xano 8402 — dispatch router
Companion patch to the router that feeds 8492. Safe-parser now applies at the routing layer as well so malformed LLM output cannot bubble up as a 500 before the synthesizer even fires.
UX Wins — 4 Fixes
MCQ button sends LABEL not snake_case value (1b11713)
Robert's exact feedback: "why does it say b2b_saas in the bubble?" InterviewTurn MCQ click now sends the human-readable label ("B2B SaaS") to the transcript, not the internal snake_case option value. The UserMessage bubble matches what the user tapped.
Skip empty UserMessage bubble (d2a5b86)
Robert's exact feedback: "why is this empty?" When userText is whitespace-only (e.g. tile click with no composer text), the canvas now skips rendering the UserMessage bubble entirely instead of emitting a blank indigo pill.
Claude Code–style spinner verb pill (837b4d2)
ScanningCard was rendering 3 shimmer rows. Robert's feedback: make it look like Claude Code's verb spinner — single frosted pill, centered, cycling verb. Rebuilt as a single backdrop-filter: blur(12px) pill with a cycling verb drawn from the 102-verb list.
Interview state machine race fixed (d2a5b86)
The isStreamingRef sync race caused the canvas to re-classify on the second MCQ answer instead of continuing the interview chain. The ref was being read before the streaming flag was set, so the canvas thought it was idle and fired a fresh classify. Fixed by hoisting the ref set above the async boundary. Chain now runs correctly through MCQ → MCQ → MCQ → dispatch without re-entering classify.
Wave 7 Commits
7 commits since c92b14a (Wave 6 end)
State Machine + UX
d2a5b86
fix(ae-canvas): skip empty UserMessage bubble when userText is whitespace
Also contains the isStreamingRef sync race fix that was causing re-classification on the second MCQ answer. Two fixes in one commit.
P0
1b11713
fix(ae-openui): InterviewTurn MCQ click sends LABEL not snake_case value
Fixes the "b2b_saas" bubble issue. UserMessage now shows "B2B SaaS" matching the tapped button text.
P1
837b4d2
fix(ae-openui): ScanningCard → Claude Code style spinner verb pill
Single frosted backdrop-blur pill, centered, cycling verb every 900ms. Replaces the 3-row shimmer skeleton that looked like a loading placeholder.
P1
Spinner Verbs
a5c53ce
feat(ae-spinner): 15 Orbiter-themed verbs (Scouting / Triangulating / Distilling…) + 900ms cycle
First pass: 15 verbs seeded from Mark voice and Orbiter brand. No backend terminology, no "Loading" or "Searching" generics. Each verb fits the outcome-dispatch mental model.
P2
dbbaec6
feat(ae-spinner): expand to 102 Orbiter-themed verbs across 8 clusters — Robert ('100 minimum')
Expanded to 102 verbs organized into 8 thematic clusters (see breakdown below). No verb duplicates. All verbs are Orbiter-voice-appropriate — no generic SaaS loading copy.
P2
Mark Spec
f3abf71
feat(ae-openui): DispatchConfirmation expanded to Mark-spec 12 batches
Full pitch_profile review per interview.md: raise amount, stage, sector, geography, check size, deck status, 6 editable narrative pills, upload_deck / use_existing / defer action buttons. Closes the DispatchConfirmation gap from Wave 6.
P1
Merge / Infra
aef9d3e
merge: dev into feat/anything-engine — additive env (FALKORDB_TLS from Charles + Xano OpenUI 0.5 keys)
Resolves the PR #343 CONFLICTING status. Merge was purely additive — no functional changes to anything-engine code. PR is now MERGEABLE.
P1
102-Verb Spinner Breakdown
8 Clusters — Orbiter-Voice Throughout
Each cluster covers a different phase of what Orbiter is actually doing during dispatch. No generic copy. Verbs rotate randomly so no two sessions feel identical.
Discovery — 13 verbs
Scouting · Mapping · Surfacing · Canvassing · Probing · Unearthing · Detecting · Tracing · Locating · Charting · Indexing · Surveying · Pinpointing
Distill — 11 verbs
Distilling · Synthesizing · Condensing · Parsing · Extracting · Refining · Filtering · Classifying · Sorting · Curating · Clustering
Network — 11 verbs
Traversing · Connecting · Bridging · Navigating · Linking · Pathing · Routing · Mapping paths · Cross-referencing · Tracing edges · Walking the graph
Match — 11 verbs
Matching · Aligning · Calibrating · Pairing · Evaluating fit · Comparing · Profiling · Benchmarking · Ranking · Weighing · Shortlisting
Score — 12 verbs
Scoring · Weighting · Computing · Calculating · Prioritizing · Ranking · Modeling · Estimating · Projecting · Forecasting · Assessing · Grading
Compose — 12 verbs
Composing · Drafting · Assembling · Structuring · Formatting · Packaging · Crafting · Building · Preparing · Shaping · Generating · Rendering
Triangulate — 11 verbs
Triangulating · Cross-checking · Validating · Verifying · Auditing · Confirming · Reconciling · Stress-testing · Corroborating · Fact-checking · Pressure-testing
Orbit — 11 verbs
Orbiting · Circling · Homing in · Converging · Closing in · Locking in · Zeroing in · Focusing · Narrowing · Landing · Finalizing
5 Favorites
Triangulating — the most Orbiter-specific verb: implies multiple data sources converging on a precise answer.
Homing in — movement + intention; never generic.
Unearthing — discovery cluster standout; implies hidden signal the user couldn't find themselves.
Pressure-testing — triangulate cluster; implies the engine is doing real work, not just retrieving.
Walking the graph — network cluster standout; the only verb that exposes the actual FalkorDB architecture without naming it.