Skip to content

fix(decopilot): scope live deck/page preview to the writing chat#3928

Open
viktormarinho wants to merge 1 commit into
mainfrom
viktormarinho/viktor/preview-asset-cross-thread-leak
Open

fix(decopilot): scope live deck/page preview to the writing chat#3928
viktormarinho wants to merge 1 commit into
mainfrom
viktormarinho/viktor/preview-asset-cross-thread-leak

Conversation

@viktormarinho

@viktormarinho viktormarinho commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What is this contribution about?

The live deck/page preview leaked across chats: the deck watcher emitted data-deck-updated for every decks//pages/ change in the org-wide home volume change feed since the run-start cursor, with no provenance check — so another chat's (or another member's) file, e.g. a "Sales Dashboard", surfaced in your preview and persisted as a chip. Decks/pages live in a flat org-global namespace shared across every chat and member, which made the org-wide change feed leak. This fixes it by provenance (no UX change): each org-fs file entry is now stamped with the writing chat (org_fs_entry.thread_id), the deck-buffer stamps it from ctx.metadata.threadId, and the watcher emits only entries this run produced — exact thread match, falling back to same-user scope for unstamped bash/slides-create write-backs (which still blocks cross-member leaks). putFile preserves the stamp via COALESCE so the mount's vfs write-back echo doesn't null it out.

How to Test

  1. As two different members of the same org (or the same user in two chats), generate a page/deck in each chat (e.g. ask for a "Sales Dashboard").
  2. Watch the live preview / "Slides & pages in this chat" chips in each chat.
  3. Expected: each chat shows only the decks/pages it produced; the other chat's/member's file no longer appears. (Unit coverage: deck-paths.test.tsmatchOwnDeckEntry.)

Migration Notes

Adds migration 110-org-fs-thread-id.ts — a nullable thread_id column on org_fs_entry. Backwards-compatible (existing rows are null and fall back to same-user scoping). Run bun run --cwd=apps/mesh migrate.

Known residual: same-user-two-chats for slides-create (bash) decks still falls back to user scope, since those reach org-fs via the async mount write-back decoupled from the dispatch.

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by cubic

Scopes the live deck/page preview to the current chat to stop cross-thread leaks. Org-fs writes are stamped with a thread_id, and the watcher emits only entries from this run (thread match) or same-user fallback for unstamped writes.

  • Bug Fixes

    • Add nullable thread_id to org_fs_entry (migration 110).
    • Stamp deck/page writes in the buffer with ctx.metadata.threadId.
    • Filter change-feed events via matchOwnDeckEntry (thread match, or same-user for unstamped bash/slides-create writes).
    • Preserve existing thread_id on upsert using COALESCE to avoid nulling on mount echo.
    • Add unit tests for provenance filtering.
  • Migration

    • Run: bun run --cwd=apps/mesh migrate.
    • Backward compatible; existing rows remain null and use same-user fallback.
    • Residual: same user in two chats with slides-create still falls back to user scope.

Written for commit b67282d. Summary will update on new commits.

Review in cubic

The deck watcher emitted `data-deck-updated` for every `decks/`|`pages/`
change in the org-wide `home` volume change feed since the run-start
cursor, with no provenance check. Because decks/pages live in a flat
org-global namespace shared across every chat and member, another chat's
or member's file (e.g. a "Sales Dashboard") surfaced in your live
preview and persisted as a chip.

Fix by provenance (no UX change): stamp the writing thread on org-fs
file entries (`org_fs_entry.thread_id`, migration 110) from the
deck-buffer, and emit only entries this run produced — exact thread
match, falling back to same-user scope for unstamped bash/slides
write-backs (which still blocks cross-member leaks). `putFile` keeps the
existing stamp via COALESCE so the mount's vfs write-back echo doesn't
null it out.

Residual: same-user-two-chats for `slides-create` (bash) decks still
falls back to user scope, since those reach org-fs via the async mount
write-back decoupled from the dispatch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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