From 8bc2183d4931c2a04e50455f71770a8faea873e6 Mon Sep 17 00:00:00 2001 From: dovvnloading Date: Sun, 26 Jul 2026 19:35:54 -0400 Subject: [PATCH] Qt-removal R7.5f: remove stale phase promises from user-visible text Several disabled controls and one backend notification told users a capability would arrive in an internal project phase (R3/R4/R5/R6) that had already shipped and closed - promising "coming in R4" when R4 was long done and the feature still wasn't there. Scope was derived by grepping the codebase rather than from the plan's "4 R4 placeholders" shorthand, which turned out to undercount it. Eight strings across six files, including a stale R6 promise on DocumentNodeView's Export item and a backend notification in plugins.py's executePlugin fallthrough - neither of which an "R4" search would have found. Replacements are plain and phase-free: - ChatNodeView (Key Takeaway, Explainer Note): "AI note generation isn't available yet" - DocumentNodeView (Export): "Document export isn't available yet" - AppBar (provider mode select): "Switching provider modes isn't available yet" - Composer (attach): "Attachments aren't available yet" - Composer (model/provider): "Model selection isn't available here yet - configure models in Settings" - plugins.py fallthrough: node creation "isn't available yet" - HtmlNodeView (popout): keeps the real security reason, drops the internal plan-doc citation - SceneCanvas placeholder node body: "Placeholder node" Every new claim was checked against the code before being written, to avoid replacing one false statement with another. Model selection is genuinely reachable in Settings for all three providers (setOllamaModelAssignment, saveApiConfiguration/loadApiModels, setLlamaCppChatModelPath), so the one string that points somewhere is accurate. Provider-mode switching exists nowhere - set_current_mode is only called by bootstrap_provider_state at startup - so that string deliberately offers no workaround. Adversarial review caught one miss: SceneCanvas's PlaceholderNodeView rendered "placeholder - real nodes land in R3" as body text, the most visible instance of all, reachable by double-clicking empty canvas and as the fallback for any unrecognized node kind. The initial sweep covered title attributes and quoted strings but not JSX text content. Five coupled test assertions updated to match. 885 backend / 1208 frontend tests pass, typecheck/lint/build clean, burn-down gate unchanged at 152/84/68. Closes R7.5 (a-g). Co-Authored-By: Claude Opus 5 --- backend/plugins.py | 2 +- backend/tests/test_plugins.py | 2 +- web_ui/src/app/canvas/ChatNodeView.test.tsx | 2 +- web_ui/src/app/canvas/ChatNodeView.tsx | 4 ++-- web_ui/src/app/canvas/DocumentNodeView.test.tsx | 2 +- web_ui/src/app/canvas/DocumentNodeView.tsx | 2 +- web_ui/src/app/canvas/HtmlNodeView.test.tsx | 2 +- web_ui/src/app/canvas/HtmlNodeView.tsx | 2 +- web_ui/src/app/canvas/SceneCanvas.tsx | 2 +- web_ui/src/app/chrome/AppBar.tsx | 2 +- web_ui/src/app/chrome/Composer.test.tsx | 4 +++- web_ui/src/app/chrome/Composer.tsx | 4 ++-- 12 files changed, 16 insertions(+), 14 deletions(-) diff --git a/backend/plugins.py b/backend/plugins.py index 2bd2b650..c753a2be 100644 --- a/backend/plugins.py +++ b/backend/plugins.py @@ -308,7 +308,7 @@ async def execute_plugin(plugin_name: str, parent_node_id: str | None = None): await bus.publish("scene") return node.id - notifications.show(f'"{name}" node creation lands in R3/R5.', "info") + notifications.show(f'"{name}" node creation isn\'t available yet.', "info") await bus.publish("notification") return None diff --git a/backend/tests/test_plugins.py b/backend/tests/test_plugins.py index 75fe5409..9db7cce0 100644 --- a/backend/tests/test_plugins.py +++ b/backend/tests/test_plugins.py @@ -110,7 +110,7 @@ def test_execute_plugin_falls_through_to_the_generic_deferred_notice_for_an_unha assert result is None assert notifications.visible is True assert notifications.msg_type == "info" - assert notifications.message == '"Future Plugin" node creation lands in R3/R5.' + assert notifications.message == '"Future Plugin" node creation isn\'t available yet.' def test_execute_plugin_shows_warning_notification_for_unknown_plugin(): diff --git a/web_ui/src/app/canvas/ChatNodeView.test.tsx b/web_ui/src/app/canvas/ChatNodeView.test.tsx index 4f5342cd..a6d6a27b 100644 --- a/web_ui/src/app/canvas/ChatNodeView.test.tsx +++ b/web_ui/src/app/canvas/ChatNodeView.test.tsx @@ -100,7 +100,7 @@ describe("ChatNodeView", () => { for (const name of ["Generate Key Takeaway", "Generate Explainer Note"]) { const item = screen.getByRole("menuitem", { name }); expect(item).toBeDisabled(); - expect(item).toHaveAttribute("title", "AI generation lands in R4"); + expect(item).toHaveAttribute("title", "AI note generation isn't available yet"); } expect(screen.getByRole("menuitem", { name: "Generate Image" })).not.toBeDisabled(); expect(screen.getByRole("menuitem", { name: "Generate Chart" })).not.toBeDisabled(); diff --git a/web_ui/src/app/canvas/ChatNodeView.tsx b/web_ui/src/app/canvas/ChatNodeView.tsx index 09927486..08459c6b 100644 --- a/web_ui/src/app/canvas/ChatNodeView.tsx +++ b/web_ui/src/app/canvas/ChatNodeView.tsx @@ -207,10 +207,10 @@ function ChatNodeMenu({ - - {/* R6.2: a real click-to-expand submenu (not disabled) - same diff --git a/web_ui/src/app/canvas/DocumentNodeView.test.tsx b/web_ui/src/app/canvas/DocumentNodeView.test.tsx index 247ae6ff..a66f2586 100644 --- a/web_ui/src/app/canvas/DocumentNodeView.test.tsx +++ b/web_ui/src/app/canvas/DocumentNodeView.test.tsx @@ -195,7 +195,7 @@ describe("DocumentNodeView", () => { const exportItem = screen.getByRole("menuitem", { name: "Export" }); expect(exportItem).toBeDisabled(); - expect(exportItem).toHaveAttribute("title", "Export lands in R6"); + expect(exportItem).toHaveAttribute("title", "Document export isn't available yet"); // filePath is empty -> Open File must be entirely absent, matching the // legacy menu's own conditional (only added when file_path is set). diff --git a/web_ui/src/app/canvas/DocumentNodeView.tsx b/web_ui/src/app/canvas/DocumentNodeView.tsx index 01f51b7b..c563065c 100644 --- a/web_ui/src/app/canvas/DocumentNodeView.tsx +++ b/web_ui/src/app/canvas/DocumentNodeView.tsx @@ -263,7 +263,7 @@ function DocumentNodeMenu({ )}
{isDocumentKind && ( - )} diff --git a/web_ui/src/app/canvas/HtmlNodeView.test.tsx b/web_ui/src/app/canvas/HtmlNodeView.test.tsx index 06404b38..dcb94061 100644 --- a/web_ui/src/app/canvas/HtmlNodeView.test.tsx +++ b/web_ui/src/app/canvas/HtmlNodeView.test.tsx @@ -178,7 +178,7 @@ describe("HtmlNodeView", () => { expect(popout).toBeDisabled(); expect(popout).toHaveAttribute( "title", - "Popout view isn't built yet - see the R3 plan doc for why a naive window.open() would be unsafe for untrusted HTML", + "Popout view isn't built yet - opening untrusted HTML in a separate window needs a security review first", ); await user.click(popout); // disabled - fires nothing diff --git a/web_ui/src/app/canvas/HtmlNodeView.tsx b/web_ui/src/app/canvas/HtmlNodeView.tsx index e30db563..152b8be1 100644 --- a/web_ui/src/app/canvas/HtmlNodeView.tsx +++ b/web_ui/src/app/canvas/HtmlNodeView.tsx @@ -202,7 +202,7 @@ export function HtmlNodeView({ data, selected }: NodeProps) { type="button" className="html-node-header-btn" disabled - title="Popout view isn't built yet - see the R3 plan doc for why a naive window.open() would be unsafe for untrusted HTML" + title="Popout view isn't built yet - opening untrusted HTML in a separate window needs a security review first" > Popout diff --git a/web_ui/src/app/canvas/SceneCanvas.tsx b/web_ui/src/app/canvas/SceneCanvas.tsx index 9891e479..b8b0dd6b 100644 --- a/web_ui/src/app/canvas/SceneCanvas.tsx +++ b/web_ui/src/app/canvas/SceneCanvas.tsx @@ -146,7 +146,7 @@ function PlaceholderNodeView({ data, selected }: NodeProps) { on bottom. */}
{data.title}
- {!collapsed &&
placeholder — real nodes land in R3
} + {!collapsed &&
Placeholder node
}
); diff --git a/web_ui/src/app/chrome/AppBar.tsx b/web_ui/src/app/chrome/AppBar.tsx index 0688c76e..3cbbd621 100644 --- a/web_ui/src/app/chrome/AppBar.tsx +++ b/web_ui/src/app/chrome/AppBar.tsx @@ -116,7 +116,7 @@ export function AppBar({ store }: { store: SceneStore }) { value="Ollama (Local)" aria-label="Provider mode" disabled - title="Provider modes land in R4" + title="Switching provider modes isn't available yet" onChange={() => {}} > diff --git a/web_ui/src/app/chrome/Composer.test.tsx b/web_ui/src/app/chrome/Composer.test.tsx index 70d5646d..5f718f28 100644 --- a/web_ui/src/app/chrome/Composer.test.tsx +++ b/web_ui/src/app/chrome/Composer.test.tsx @@ -69,7 +69,9 @@ describe("Composer", () => { ); expect(screen.getByLabelText("Send message")).toBeDisabled(); expect(screen.getByLabelText("Attach context")).toBeDisabled(); - expect(screen.getByTitle("Model/provider selection lands in R4")).toBeDisabled(); + expect( + screen.getByTitle("Model selection isn't available here yet - configure models in Settings"), + ).toBeDisabled(); }); it("Send is enabled once there's text, calls sceneStore.sendMessage, and clears the draft", async () => { diff --git a/web_ui/src/app/chrome/Composer.tsx b/web_ui/src/app/chrome/Composer.tsx index 1d836ae7..5dc52db1 100644 --- a/web_ui/src/app/chrome/Composer.tsx +++ b/web_ui/src/app/chrome/Composer.tsx @@ -95,7 +95,7 @@ export function Composer({ store, sceneStore }: { store: ComposerStore; sceneSto type="button" className="composer-icon-button" disabled - title="Attachments land in R4 (file-staging pipeline)" + title="Attachments aren't available yet" aria-label="Attach context" > @@ -119,7 +119,7 @@ export function Composer({ store, sceneStore }: { store: ComposerStore; sceneSto type="button" className="composer-control" disabled - title="Model/provider selection lands in R4" + title="Model selection isn't available here yet - configure models in Settings" > {composer.route.provider}