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.
feat/anything-engine since 2026-05-09 06:00. SHA listed for each.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.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.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.019e0965062a76f9afcc5a5d15db9a3d — May 8, 2026. Mark saw the live canvas on Robert's screen and reacted in real time.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.{ 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 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.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.top-nav.tsx (tab label), active-view.ts (viewTitles), any visible <h1> inside the canvas. Internal file/component names can stay as-is.{ user: Mark Peterson, company: Orbiter } into the system context or first message.$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.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./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-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..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.| 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 |
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.
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.
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").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.f41b6d6 UserMessage wiring). Transcript is accumulating correctly across turns.feat/anything-engine. SHAs are from the live branch.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.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.anythingEngineLibrary. Right-aligned indigo bubble, 12px border-radius, matches Mark-spec chat aesthetics. Required by the turn-by-turn transcript display.phase field on every ae-canvas-update event. Three states: interview (MCQ gate running), scanning (dispatch in flight), complete (results rendered).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.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.pngclass_hint = find_investors set internally. Tile grid collapses. User is in composer-ready state without typing. screenshot: 23-after-tile-click.pngdev 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.
$synth_clean|json_decode with no try/catch wrapper. Patched via xano-mcp in two endpoints: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.1b11713)d2a5b86)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.837b4d2)backdrop-filter: blur(12px) pill with a cycling verb drawn from the 102-verb list.d2a5b86)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.