Skip to content

Fix: chat/prompt not persisting scene changes — throw on missing active scene - #561

Open
Srujanreddy1234 wants to merge 1 commit into
pascalorg:mainfrom
Srujanreddy1234:main
Open

Fix: chat/prompt not persisting scene changes — throw on missing active scene#561
Srujanreddy1234 wants to merge 1 commit into
pascalorg:mainfrom
Srujanreddy1234:main

Conversation

@Srujanreddy1234

@Srujanreddy1234 Srujanreddy1234 commented Jul 29, 2026

Copy link
Copy Markdown

Problem

The chat/prompt interface in the Pascal 3D floor-plan editor wasn't building or editing anything based on user prompts. When a user submitted a prompt like "Add a bedroom to the current floor plan...", the AI agent's tool calls (create_room, add_door, add_window, furnish_room) executed and mutated the in-memory Zustand store, but no changes were persisted to SQLite and no SSE events were emitted — so the browser never received the updates. From the user's perspective, the assistant appeared to respond, but nothing was ever built.

Root Cause

publishLiveSceneSnapshot() in live-sync.ts was silently returning when no active scene was bound to the MCP session:

const active = operations.getActiveScene()
if (!(active && operations.canAppendSceneEvents)) return // silent no-op

This meant any mutation made without an actively bound scene was dropped with no error, no log, and no signal to the caller.

Compounding this, the from_brief MCP prompt never instructed the LLM to call load_scene / create_project / create_house_from_brief before invoking mutation tools. As a result, the LLM would frequently jump straight to create_room etc. on a fresh session — which then silently failed to persist due to the issue above.

Fix

  • packages/mcp/src/tools/live-sync.ts — publishLiveSceneSnapshot now throws a no_active_scene error when a SceneStore is attached but no active scene is bound, instead of silently no-oping. Behavior when no store is attached (headless/test mode) is unchanged.
  • packages/mcp/src/prompts/from-brief.ts — Added a "CRITICAL FIRST STEP" preamble explicitly instructing the LLM to bind a scene before performing any mutations. Restructured the task into 3 clear numbered steps. Fixed a misleading tool/prompt description that was contributing to the LLM skipping the binding step.

Tests

  • packages/mcp/src/tools/live-sync.test.ts (new) — 4 tests covering:
    • Throws when a store is attached but no scene is active
    • Silently returns when no store is attached (headless/test mode)
    • Persists and emits correctly when an active scene is bound
    • Version increments correctly on successive publishes
  • packages/mcp/src/prompts/prompts.test.ts — Full bedroom regression test: verifies a bedroom prompt produces zone + slab + ceiling + 4 walls + door + window + bed + 2 nightstands + wardrobe, resulting in 4 events with all node types correctly verified. Also adds an error-path test and a headless-mode test.

How to verify

  1. bun test packages/mcp/src/tools/live-sync.test.ts
  2. bun test packages/mcp/src/prompts/prompts.test.ts
  3. Manually: create an empty project at https://editor.pascal.app/, submit the bedroom prompt from Pascall App is Working? #557, confirm the room + furniture now render and persist across reload.

Note

Medium Risk
Changes core MCP persistence behavior for all mutation paths that call live sync; mis-bound sessions now error instead of silently dropping work, which is intentional but affects agent UX.

Overview
Fixes chat/prompt edits that appeared to succeed but never showed in the editor by making live sync fail loudly when a SceneStore is attached but no scene is bound, instead of silently skipping persistence and SSE events.

publishLiveSceneSnapshot now throws no_active_scene with guidance to call load_scene, create_project, or create_house_from_brief before mutation tools; headless mode (no store) still no-ops unchanged.

The from_brief MCP prompt adds a CRITICAL FIRST STEP to bind a scene first, restructures the task into bind → build → validate steps, and updates the prompt description away from implying apply_patch-only workflows.

Tests cover live-sync throw/success/versioning, prompt text for scene binding, and a bedroom-style regression that mutations persist and emit the expected scene events when an active scene is set. A root test-flow.mjs script exercises room tools over in-memory MCP transport.

Reviewed by Cursor Bugbot for commit 23a2f04. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 23a2f04. Configure here.

expect(m.content.text).toContain('load_scene')
expect(m.content.text).toContain('create_project')
expect(m.content.text).toContain('create_house_from_brief')
expect(m.content.text).toContain('no bound scene')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prompt test substring mismatch

High Severity

The new binding-scene test expects the prompt to contain "no bound scene", but the actual prompt text uses "Without a bound scene". This string mismatch causes the test assertion to fail.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 23a2f04. Configure here.

expect(events.length).toBe(1)
expect(events[0]!.kind).toBe('create_wall')
expect(events[0]!.version).toBe(2)
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests need missing store events

High Severity

New regression tests call store.listSceneEvents and expect publishLiveSceneSnapshot to save and emit events when using InMemorySceneStore, but that test store does not implement appendSceneEvent or listSceneEvents, so canAppendSceneEvents is false and publish returns without persisting.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 23a2f04. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant