Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(files): section folders never fetch their own children

merged#2868CedarCopilot

CedarCopilot wants to merge 2 commits into staging from fix/filebrowser-section-eager-fetch

Live on prod, 0 of 1 surfaces working, 2 days leftTimeline and evidence
  1. Opened
    Sep 21, 2026, 7:49 PM
  2. Sep 21, 2026, 8:47 PM
  3. Merged
    Sep 21, 2026, 8:57 PM
  4. Live on prod
    Sep 21, 2026, 8:57 PM
  5. Observed 0 hours, 1 surface, 0 requests
    Sep 21, 2026, 8:57 PM
  6. Watching

    Live on prod, 0 of 1 surfaces working, 2 days left

    Sep 21, 2026, 8:57 PM
  7. Pipelines steady after this deploy
    Sep 21, 2026, 8:57 PM

Behaviors Libra is checking

An org-namespaced agent now shows the currently viewed person's own user-scoped agent output, including nested descendants, alongside the shared organization-scoped configuration.Not checked
prod
A user-namespaced agent continues to use its existing user-scoped root without adding a redundant My files section.Not checked
prod
The own-output section is labeled My files normally and is labeled with the viewed person's name only when customer view-as is actively naming that person.Not checked
prod
Cross-scope user-file sections resolve their root and descendants under the requested viewed-user scope, preventing another user's document at the same literal path from being displayed.Not checked
prod
Collapsed ordinary folders remain lazy while only configured sections and their descendants are fetched without an explicit expansion.Not checked
prod
The file tree remains loading until eager same-scope and cross-scope section walks have settled, preventing populated sections from briefly rendering as empty.Not checked
prod

Libra found 1 production surface on prod but could not judge any of them yet. 1 surface had no requests at all. Libra checks hourly for 3 days after each deploy.

Summary

FileBrowser's kind: 'folder' sections (Memory, Config on AgentOutputTab) are drawn by filtering useFileTree's rows for a path prefix (sectionRows.get(sec.path) in FileBrowser.tsx). Nothing ever populated rows with a section's children:

  • autoExpandDepth explicitly excludes sections , AgentOutputTab's own comment: "The sections are untouched by this: Memory and Config stay shut."
  • A section's onToggle handler (toggleSection(sec.path)) only flips a local visibility boolean; it never calls expand(), the only mechanism that adds a folder id to useFileTree's expandedIds.

So a real, non-empty, fully accessible Config or Memory folder rendered as permanently empty , with zero network requests fired when a user clicked to expand it, since nothing was ever wired to fetch it in the first place.

How this was found

Verified end-to-end against live production data for a real customer's coaching agent before writing any code:

  • getAgentOutputs (server), called directly with the real org/user/agent ids, returned 5 real documents under byNamespace.config.
  • listChildren (server), called directly with the real Config folder's document id as parentId, returned the same children correctly.
  • The browser network tab confirmed the X-Admin-View-User header was correct on every request, and that expanding the Config folder fired no new network request at all , directly confirming nothing was wired to fetch it, rather than an access or data problem.

Fix

Added sectionPaths to useFileTree's options:

  1. Resolve each section root's document id from the tree's own root listing (already fetched for every tree , no extra query needed for this step).
  2. Recursively include every folder found beneath a section root in an eager fetch+walk set (eagerFolderIds), grown one level per settled query , the same incremental shape rootChain already uses for resolving rootPath's ancestry, but as a set rather than a chain, since a section can branch (e.g. config/templates sits beside config/playbook).
  3. walk() treats an id in eagerFolderIds as expanded unconditionally, so a section's full subtree , however deep , surfaces in rows without anyone clicking it open.
  4. isLoading now also accounts for a section's fetch still being in flight, so a section doesn't flash empty before its query resolves.

Ordinary (non-section) folders are untouched: still lazy, one files.listChildren query per manual expand, exactly as before. FileBrowser.tsx's existing prefix-based grouping into sectionRows is unchanged , it just now has real data to filter.

Test plan

  • New test file (useFileTree.sectionPaths.test.tsx) exercises the real hook (not mocked, unlike every existing test that touches useFileTree) with a mocked tRPC client returning per-parentId fixtures. Confirms: a section's children (including a nested two-levels-deep folder) appear in rows without ever calling expand; an ordinary folder stays lazy; omitting sectionPaths entirely reproduces the original behavior unchanged.
  • All existing tests touching this code still pass unchanged: fileBrowserAdminView.test.tsx, playbookFileTree.test.tsx, AgentOutputTab.test.tsx, AgentFileBrowserSelection.test.tsx, AgentViewLayout.test.tsx (47 tests, all green).
  • pnpm --filter @zero/mail run types , zero errors in either touched file (pre-existing failures in this fresh worktree are all missing generated code , @/paraglide/*, react-router +types , unrelated to this change).
  • eslint on both touched files , clean (one pre-existing, unrelated warning in FileBrowser.tsx predates this change, confirmed via git blame).

šŸ¤– Generated with Claude Code

Show production surfaces and changed-file mapping

Production surfaces

SurfaceRequestsErrorsp95UsersVerdict
files.listChildren0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.

Changed files → surfaces

  • apps/mail/modules/agents/__tests__/AgentOutputTab.test.tsxno production surface mapped
  • apps/mail/modules/agents/components/AgentOutputTab.tsxno production surface mapped
  • apps/mail/modules/conversations/components/files/ConversationFileTree.tsxno production surface mapped
  • apps/mail/modules/conversations/components/files/__tests__/useFileTree.crossScopeSections.test.tsxno production surface mapped
  • apps/mail/modules/conversations/components/files/__tests__/useFileTree.sectionPaths.test.tsxno production surface mapped
  • apps/mail/modules/files/components/FileBrowser.tsxno production surface mapped