fix: keep configured presentation target live

This commit is contained in:
lda
2026-07-11 21:36:55 +07:00 Verified
parent 6588c0edfe
commit 4b75948450
2 changed files with 23 additions and 6 deletions
@@ -207,6 +207,17 @@ describe("PresentationRoute", () => {
expect(await screen.findByRole("button", { name: /run prepared workflow/i })).toBeInTheDocument(); expect(await screen.findByRole("button", { name: /run prepared workflow/i })).toBeInTheDocument();
}); });
it("does not prime replay evidence on a live direct hash", async () => {
window.sessionStorage.setItem("lda.workflowConsole.target", "http://127.0.0.1:8765/rpc");
window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />);
expect(await screen.findByText(/Live target is ready/i)).toBeInTheDocument();
expect(screen.queryByText("Workflow input")).not.toBeInTheDocument();
expect(screen.queryByRole("button", { name: "Submit" })).not.toBeInTheDocument();
});
it("updates the chat intro after the live health probe succeeds", async () => { it("updates the chat intro after the live health probe succeeds", async () => {
window.sessionStorage.setItem("lda.workflowConsole.target", "http://127.0.0.1:8765/rpc"); window.sessionStorage.setItem("lda.workflowConsole.target", "http://127.0.0.1:8765/rpc");
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
@@ -228,6 +239,7 @@ describe("PresentationRoute", () => {
}); });
it("renders replay-backed approval evidence on a direct approval hash", async () => { it("renders replay-backed approval evidence on a direct approval hash", async () => {
setReplayMode();
window.location.hash = "#scene/typed-human-boundary/approval"; window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -311,6 +323,7 @@ describe("PresentationRoute", () => {
}); });
it("opens approval with enabled approval controls immediately after priming", async () => { it("opens approval with enabled approval controls immediately after priming", async () => {
setReplayMode();
window.location.hash = "#scene/typed-human-boundary/approval"; window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -320,6 +333,7 @@ describe("PresentationRoute", () => {
}); });
it("opens resume with resume operation proof immediately after priming", async () => { it("opens resume with resume operation proof immediately after priming", async () => {
setReplayMode();
window.location.hash = "#scene/resume-output-evidence/resume"; window.location.hash = "#scene/resume-output-evidence/resume";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -328,6 +342,7 @@ describe("PresentationRoute", () => {
}); });
it("direct approval route primes interrupt payload but not output", async () => { it("direct approval route primes interrupt payload but not output", async () => {
setReplayMode();
window.location.hash = "#scene/typed-human-boundary/approval"; window.location.hash = "#scene/typed-human-boundary/approval";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -337,6 +352,7 @@ describe("PresentationRoute", () => {
}); });
it("direct resume route primes resume and output proof", async () => { it("direct resume route primes resume and output proof", async () => {
setReplayMode();
window.location.hash = "#scene/resume-output-evidence/resume"; window.location.hash = "#scene/resume-output-evidence/resume";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -360,6 +376,7 @@ describe("PresentationRoute", () => {
}); });
it("direct trace route primes trace frames", async () => { it("direct trace route primes trace frames", async () => {
setReplayMode();
window.location.hash = "#scene/resume-output-evidence/trace"; window.location.hash = "#scene/resume-output-evidence/trace";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -372,6 +389,7 @@ describe("PresentationRoute", () => {
}); });
it("keeps trace frames when navigating from output to trace", async () => { it("keeps trace frames when navigating from output to trace", async () => {
setReplayMode();
window.location.hash = "#scene/resume-output-evidence/output"; window.location.hash = "#scene/resume-output-evidence/output";
const { PresentationRoute } = await import("./PresentationRoute.js"); const { PresentationRoute } = await import("./PresentationRoute.js");
render(<PresentationRoute />); render(<PresentationRoute />);
@@ -95,12 +95,11 @@ export const PresentationRoute = () => {
}, []); }, []);
useEffect(() => { useEffect(() => {
// Scene deep-links need the recorded demo state before the operator starts a live run. if (demo.state.phase !== "ready") return;
// The chat action can still switch the shared timeline to live via start("live"). // The resolved target owns the initial mode: a healthy loopback target must
if (demo.state.phase === "ready" && demo.state.mode !== "replay") { // remain live, while an invalid target starts from the offline recording.
demo.setMode("replay"); if (demo.state.mode !== presentationTarget.mode) demo.setMode(presentationTarget.mode);
} }, [demo.setMode, demo.state.mode, demo.state.phase, presentationTarget.mode]);
}, [demo.state.phase, demo.state.mode, demo.setMode]);
useEffect(() => { useEffect(() => {
if (demo.state.phase === "ready" && demo.state.mode === "replay") { if (demo.state.phase === "ready" && demo.state.mode === "replay") {