Repository navigation
Workspace index opts into filesystem-root and home-dir scanning, which the library documents as off by default #6
Description
Activity
- addedquestionFurther information is requestedFurther information is requestedneeds-triageMaintainer needs to evaluate this issueMaintainer needs to evaluate this issue
on Aug 29, 2026 This was generated by AI during triage.
Agent Brief
Category: bug
Summary: Stop silently opting every workspace index into filesystem-root and home-directory scanning; give a project root of/or$HOMEa refusal the user can act onScope note: this brief covers only the fork-local, answerable half of the ticket. The question of why upstream enabled these flags is out of scope here — see "Out of scope" below.
Current behavior:
Every workspace search index is created through a singleFileFinder.createcall (@ff-labs/fff-node) that passesenableFsRootScanning: trueandenableHomeDirScanning: true. The library documents both as off by default because they flood the watcher with churn-prone events, and states that a caller setting them true owns the resulting fs-event volume.The flags only take effect when a workspace root actually resolves to
/or the home directory, so most projects are unaffected. But a project root of~expands to the home directory in the workspace path resolvers, so a user can reach this by typing a single character. When they do, they get the unbounded watcher cost with no warning and no way to know they opted in.Both flags came from upstream (
pingdotgg/t3codePR pingdotgg#3099, carried through a refactor in pingdotgg#3352). They are not a fork decision.Desired behavior:
The workspace index no longer enables either flag. A project root that resolves to/or the user's home directory fails to index with a distinct, readable error naming the path and explaining that indexing the filesystem root or the home directory is not supported, rather than a generic create failure. Every other project root behaves exactly as it does today.First task — verify the library's actual behavior.
Install dependencies and confirm empirically whatFileFinder.createdoes with both flags absent andbasePathset to/and to the home directory. There are two possible outcomes and the rest of the work depends on which one holds:- It refuses (returns a non-ok result): the library is already doing the gating. The work is to detect that case and surface a clear message instead of the generic failure.
- It scans a degraded subset without refusing: the library will not gate for us, so add an explicit guard that rejects these roots before the finder is constructed.
Record which one you observed in a comment on this issue before implementing, and note the exact library version you tested against.
Key interfaces:
- The
InitOptionspassed toFileFinder.create:enableFsRootScanningandenableHomeDirScanningshould both be gone. Leave the other options (base path, mmap cache, content indexing per index variant, AI mode) untouched. - The workspace search index's tagged create-failure error already carries the workspace path and a reason string. Either extend it with a distinguishable reason for this case, or add a sibling tagged error alongside it. Follow whichever fits the existing error-modelling convention for these services — do not introduce a thrown exception or a bare string.
- Path resolution: the helper that expands a leading
~in a workspace path is what makes$HOMEreachable. The check must run on the resolved, absolute path, not the user's raw input, so~,$HOME, an explicit absolute home path, and a trailing-slash variant all land in the same branch.
Acceptance criteria:
- Neither
enableFsRootScanningnorenableHomeDirScanningappears anywhere in the workspace index source. - A workspace root that resolves to the home directory fails index creation with an error that names the path and states that home-directory indexing is unsupported.
- A workspace root of
/fails the same way, with wording appropriate to the filesystem root. - The check operates on the resolved absolute path:
~, an explicit absolute home path, and a trailing-slash variant of either all produce the same refusal. - A normal project root (a repo directory) creates its index and searches exactly as before — no behavior change, no new failure path reached.
- A focused test covers the two refusal cases and at least one ordinary root that still succeeds. It must not depend on sleeps or polling; wait on the service's own result.
- A comment on this issue records what
FileFinder.createactually did with the flags off, and the library version tested.
Out of scope:
- Answering why upstream enabled these flags, or changing anything in
pingdotgg/t3code. That is a separate conversation with the maintainer and is not part of this work. - Any change to watcher strategy, debouncing, ignore rules, or refresh coalescing. That is the territory of Scope: watch the workspace so externally-added files appear in the Files tree #2 and its follow-up.
- Adding a general allowlist or policy layer for project roots. This ticket refuses exactly two roots and nothing else.
- Changing the entry cap, the scan timeout, or the idle TTL on the index.
- Making the refusal user-overridable via a setting. If that turns out to be wanted, it is a follow-up ticket.
Conventions:
Readdocs/internals/code-conventions.md, and.macroscope/check-run-agents/effect-service-conventions.mdbefore touching the server service.- addedbugSomething isn't workingSomething isn't workingready-for-agentFully specified, ready for an AFK agentFully specified, ready for an AFK agentand removedquestionFurther information is requestedFurther information is requestedneeds-triageMaintainer needs to evaluate this issueMaintainer needs to evaluate this issue
on Aug 29, 2026 First task: what
FileFinder.createactually does with the flags offTested against
@ff-labs/fff-node0.9.4 (the version pinned inapps/server/package.json), on darwin, via a throwaway script callingFileFinder.createdirectly with the same options the workspace index passes, minus the two flags.Outcome: it refuses — but only partly. Neither of the two outcomes the ticket anticipated holds cleanly.
With both flags absent,
FileFinder.createreturns a non-ok result:{"basePath":"/","flags":"off","ok":false, "error":"Failed to init file picker: Can not run certain FFF features in a file system root or home directories. Consider smaller per-project directories."}The home-directory case behaves the same, and it reads the real
HOMEenv var (probed withHOMEpointed at a temp dir, so nothing scanned the developer's actual home):{"basePath":"<fakeHome>","HOME":"<fakeHome>","flags":"off","ok":false, "error":"Failed to init file picker: Can not run certain FFF features in a file system root or home directories. Consider smaller per-project directories."} {"basePath":"<fakeHome>/proj","HOME":"<fakeHome>","flags":"off","ok":true,"error":null}The gap: the library's check is an exact string match, and a trailing separator defeats it.
{"basePath":"<fakeHome>/","HOME":"<fakeHome>","flags":"off","ok":true,"error":null}So simply deleting the two flags would have satisfied most of the acceptance criteria but silently failed this one:
The check operates on the resolved absolute path:
~, an explicit absolute home path, and a trailing-slash variant of either all produce the same refusal.That is why the change does both: the flags are gone, and
WorkspaceSearchIndexresolves the root and refuses/and$HOMEitself, before a finder is ever constructed. Resolving first collapses~,$HOME, an explicit absolute home path, and any trailing-slash variant into one branch, and lets the failure carry a reason naming the path rather than the generic native diagnostic above.For completeness, with the flags on — today's behavior — every one of these roots is accepted:
{"basePath":"/","flags":"on","ok":true,"error":null} {"basePath":"<fakeHome>","flags":"on","ok":true,"error":null}Incidentally, the cost shows up plainly in the test suite: with the fix reverted, the three refusal tests take 15s, 11s and 1s because the unfixed code genuinely starts scanning
/and$HOME. With the fix they are instant.Error modelling
Kept
WorkspaceSearchIndexCreateFailedand gave it a distinguishablereasonrather than adding a sibling tagged error. A new tag would have rippled throughWorkspaceEntriesError, thews.tsfailure switch, and the client-facing failure enum for no behavioral gain —ws.tsalready forwardserror.reasonasdetail, so the explanation reaches the client with no contract change.
Problem
WorkspaceSearchIndex.createFinder(apps/server/src/workspace/WorkspaceSearchIndex.ts) passes both:The library documents both as off by default, for watcher-cost reasons. From
@ff-labs/fff-nodeInitOptions:enableHomeDirScanningcarries the same trade-off by reference.These only bite when a workspace root actually is
/or$HOME, so most projects are unaffected. But T3 lets a user add any directory as a project, and$HOMEis a plausible thing for someone to point at. When they do, we opt into unbounded watcher churn on their behalf, silently.Questions
$HOME, that argues for keeping them — but knowingly./or$HOME, or a refusal with an explanation, rather than a silent opt-in?/or$HOMEas a project root?Notes
Surfaced while scoping #2. That ticket explicitly put this out of scope and noted it belongs in its own ticket — this is it. Not urgent, and not blocking anything.