Skip to content

Resolve thread storage locations without listing - #2100

Merged
ymichael merged 2 commits into
mainfrom
bb/post-merge-fix-thread-storage-root-lookup-scans-thr_44gh3a95ug
Aug 21, 2026
Merged

Resolve thread storage locations without listing#2100
ymichael merged 2 commits into
mainfrom
bb/post-merge-fix-thread-storage-root-lookup-scans-thr_44gh3a95ug

Conversation

@ymichael

@ymichael ymichael commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

What was wrong

PR #2005 made live thread-storage files resolve through useThreadStoragePaths({ limit: 1 }) even though the caller needs only the authoritative storage root and host. The server therefore sent host.list_paths, whose daemon handler recursively walks the complete storage tree before applying the response limit. Merely opening a file context menu or accepting an external-open request could perform large filesystem work and add remote-host latency. This is the root cause identified in the post-merge review; #2086 lazy-loads the storage browser but does not change this lookup.

The first version of this PR added a direct location route, but review found three incomplete consumers: the Docs file opener still recovered the same metadata through threads.get() plus storageFiles({ limit: "1" }), reconnect catch-up omitted the new location query-key prefix, and the builtin plugin-authoring skill's exact SDK method map omitted storageLocation.

What changed

  • Add GET /api/v1/threads/:id/thread-storage/location and sdk.threads.storageLocation(). The server reuses its existing authoritative requireThreadStorageTarget result and returns { hostId, storageRootPath } without issuing a host filesystem RPC.
  • Resolve app live-file targets and Docs thread-storage open/save operations from that direct location. Both preserve loading/error behavior, absolute-path construction, validated relative paths, rootPath confinement, and local-versus-remote host context without listing storage.
  • Include the location query in thread/environment cache ownership and reconnect invalidation so an active failed lookup recovers when the server socket reconnects.
  • Add storageLocation to the builtin bb-plugin-authoring skill's exact threads SDK method map.
  • Add focused route, SDK/contract, query, cache-owner, reconnect-recovery, Docs confinement, and resolver coverage. This is internal transport for existing file-open behavior, not a new end-user command or configuration surface, so no CLI/guide parity change is needed.
  • No host-daemon message changed, so HOST_DAEMON_PROTOCOL_VERSION is unchanged.

This is the smallest complete fix because the server already knows the host and derives the root from the active host session; exposing and consistently consuming that existing result deletes the broad listing dependency instead of optimizing or special-casing the recursive listing API.

How you verified

  • Before the route existed, its new public-route regression failed with expected 404 to be 200. Afterward, the focused server route passed without reporting any host RPC response, proving the route does not enumerate the filesystem.
  • Before the Docs update, the storage-location-only regression failed with bb.sdk.threads.get is not stubbed; afterward, the focused Docs server file passed 32/32 while asserting the returned remote host and confined root on read, preview, and CAS write.
  • Before reconnect invalidation included the prefix, the active failed-location regression remained undefined instead of recovering to loaded; afterward, the focused cache-effect and cache-owner tests passed 11/11.
  • After rebasing onto origin/main at e171ceba4: pnpm exec turbo run build typecheck --filter=@bb/app --filter=@bb/server --filter=bb-plugin-simple-notes passed 10/10 tasks. A final post-commit Turbo typecheck also passed.
  • Forced full affected test matrix: app 414 files / 3,178 tests passed (3 skipped); server 195 files / 1,817 tests passed; Docs 3 files / 66 tests passed.
  • Earlier focused SDK and server-contract coverage passed 8/8 and 33/33 respectively; their full suites passed 96 and 58 tests.
  • pnpm exec turbo run lint --filter=@bb/app passed with 0 errors and 155 existing warnings outside the changed lines.
  • git diff --check passed.

Fixes: N/A — no matching issue; post-merge follow-up to #2005.

AGENT GENERATED: by GPT-5.6-Sol

@bb-slop-cop

bb-slop-cop Bot commented Aug 20, 2026

Copy link
Copy Markdown

🚨 SLOP COP 🚨 · review

I am reviewing this pull request now. I will check security, code quality, performance, architecture, and the user workflow.

Comment thread packages/sdk/src/areas/threads.ts
Comment thread apps/app/src/hooks/queries/query-keys.ts

@bb-slop-cop bb-slop-cop 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.

🚨 SLOP COP 🚨 · review

Plain-English summary: This change gives the app a direct way to find a thread storage folder. It avoids a slow full scan.

I found two important issues and one documentation issue.

  1. P2 — The Docs plugin still scans the complete storage tree.

    plugins/docs/server.ts:1048 still uses storageFiles({ limit: "1" }) to find the storage root.

    The daemon scans all files before it applies the limit. Docs repeats this work for each open and save operation.

    Replace the paired thread and file-list calls with storageLocation(). Use its hostId and storageRootPath fields.

  2. P2 — Reconnect recovery omits the new location query.

    system-cache-effects.ts:170 refreshes other thread storage queries after a reconnect. It does not refresh storage locations.

    An active query can fail during a disconnect. It can then remain unavailable after the connection returns.

    Add allThreadStorageLocationsQueryKeyPrefix() to that set. Add a reconnect regression test.

  3. P3 — The exact SDK method map omits the new method.

    apps/server/src/services/skills/builtin-skills/bb-plugin-authoring/SKILL.md:585 omits storageLocation from the threads method list.

    Add it between storageFiles and storagePaths.

The security review found no issue. The route keeps the existing thread, environment, host-session, and path-validation boundaries.

The direct performance path works well. It replaces three requests and a waterfall with one request and no host listing command.

The browser test created a real thread. Five location requests returned HTTP 200 in 1.020 to 2.209 milliseconds.

The clean test database had no storage-file link. Therefore, the browser test did not exercise the final external-file menu.

Focused tests passed: app 27, server 78, SDK 96, and server contract 58. Four affected package type checks also passed.

GitHub reports all required checks as successful. I posted an ordinary review comment and did not approve or request changes.

@ymichael
ymichael force-pushed the bb/post-merge-fix-thread-storage-root-lookup-scans-thr_44gh3a95ug branch from a989136 to 045d9e1 Compare August 20, 2026 23:44
@ymichael

Copy link
Copy Markdown
Collaborator Author

Addressed all three SlopCop gaps in 045d9e15b: Docs now uses threads.storageLocation() with host/root confinement preserved; reconnect invalidation covers failed active location queries; and the builtin bb-plugin-authoring SDK map now lists storageLocation between storageFiles and storagePaths. Rebased onto current origin/main (e171ceba4). Full affected tests passed: app 3,178, server 1,817, Docs 66; Turbo build/typecheck passed 10/10 tasks. The two inline threads have focused replies and are resolved.

@ymichael
ymichael merged commit 8be3712 into main Aug 21, 2026
13 checks passed
@ymichael
ymichael deleted the bb/post-merge-fix-thread-storage-root-lookup-scans-thr_44gh3a95ug branch August 21, 2026 00:02
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