diff --git a/components/experimental/branch-switcher.jsx b/components/experimental/branch-switcher.jsx
new file mode 100644
index 0000000..02cfe7c
--- /dev/null
+++ b/components/experimental/branch-switcher.jsx
@@ -0,0 +1,123 @@
+/**
+ * Experimental branch switcher — RTO.25A
+ *
+ * Smallest branch representation needed to test passive late-result indication.
+ * Does NOT replace production branch navigation. Temporary fixture only.
+ */
+
+"use client";
+
+import React, { useState, useEffect } from "react";
+
+/* ── Keyframes (injected once via
+);
+
+/* ── Status dot (passive new-result indicator) ─────────── */
+
+function NewIndicator({ visible }) {
+ if (!visible) return null;
+
+ return (
+
+
+
+
+
+ );
+}
+
+/* ── Single branch row ─────────────────────────────────── */
+
+function BranchRow({ id, label, active, isNew, onClick }) {
+ const isActive = Boolean(active);
+
+ return (
+
+ );
+}
+
+/* ── Card wrapper ────────────────────────────────────────── */
+
+export default function ExperimentalBranchSwitcher({
+ branches = [],
+ activeBranchId,
+ branchNewResults = {},
+ onBranchSelect,
+}) {
+ if (!branches.length) return null;
+
+ return (
+
+ {/* Label — clearly experimental */}
+
+ Branches{" "}
+ (exp)
+
+
+ Browse branches. Current focus is preserved.
+
+
+
+ {branches.map((branch) => (
+ onBranchSelect?.(branch.id)}
+ />
+ ))}
+
+
+ );
+}
+
+export { PulseStyle };
diff --git a/components/scenario-form.jsx b/components/scenario-form.jsx
index 14d91c9..9b6ab1c 100644
--- a/components/scenario-form.jsx
+++ b/components/scenario-form.jsx
@@ -4,6 +4,7 @@ import React, { useEffect } from "react";
import { useState, useRef, useMemo } from "react";
import DiagnosticsView from "@/components/diagnostics-view";
import ReasoningWorkspace, { LoadingOverlay, ContinueLaterBanner } from "@/components/reasoning-workspace";
+import ExperimentalBranchSwitcher, { PulseStyle } from "@/components/experimental/branch-switcher";
import { mockFetch, AVAILABLE_SCENARIOS } from "@/lib/mocks/confidence-engine/mock-client";
/* Compile-time env resolution — NEXT_PUBLIC_ vars are injected by Next.js at build */
@@ -221,6 +222,28 @@ export default function ScenarioForm() {
const [hideFacilitatorOnLanding, setHideFacilitatorOnLanding] = useState(false);
const textareaRef = useRef(null);
+ /* ── RTO.25A — passive late-result branch switcher (experimental) ── */
+
+ const BRANCHES = [
+ { id: "branch-a", label: "Competitor development" },
+ { id: "branch-b", label: "Customer demand" },
+ ];
+
+ const [activeBranchId, setActiveBranchId] = useState("branch-b");
+ const [branchNewResults, setBranchNewResults] = useState({});
+
+ // Simulate a late semantic result arriving on Branch A ~2s after a graph loads
+ useEffect(() => {
+ if (status !== "success" && status !== "error") return;
+ // Only simulate once per graph load
+ if (branchNewResults["branch-a"]) return;
+
+ const timer = setTimeout(() => {
+ setBranchNewResults((prev) => ({ ...prev, "branch-a": true }));
+ }, 2000);
+ return () => clearTimeout(timer);
+ }, [status, branchNewResults]);
+
/* Restore persisted session on mount (Phase 3) ─────────── */
useEffect(() => {
if (typeof window === "undefined") return;
@@ -507,35 +530,58 @@ export default function ScenarioForm() {
{/* ── Main result workspace ─────────────────────── */}
{((status === "success" || status === "error") && status !== "loading") && (
- {
- clearSession();
- setStatus("idle");
- setResult(null);
- setAnswer("");
- setUpdateStatus("idle");
- setUpdateResult(null);
- setLastSubmittedAnswer("");
- setCurrentUnderstanding(null);
- setUpdateError(null);
- }}
- />
+ <>
+
+
+ {/* Workspace (3/4) */}
+
+ {
+ clearSession();
+ setStatus("idle");
+ setResult(null);
+ setAnswer("");
+ setUpdateStatus("idle");
+ setUpdateResult(null);
+ setLastSubmittedAnswer("");
+ setCurrentUnderstanding(null);
+ setUpdateError(null);
+ }}
+ />
+
+
+ {/* Branch switcher (1/4 sidebar) */}
+
+ {
+ /* User intentionally navigates — nothing more */
+ if (id !== activeBranchId) {
+ setActiveBranchId(id);
+ }
+ }}
+ />
+
+
+ >
)}
{/* ── Continue later banner when session was restored ── */}