Co-authored-by: Kandev Agent <agent@kandev.dev>
7.1 KiB
id, title, status, wave, depends_on, plan, requirements, acceptance_criteria, system_design
| id | title | status | wave | depends_on | plan | requirements | acceptance_criteria | system_design | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 02-enforce-tree-request-scope | Enforce tree request scope | done | 2 |
|
plan.md |
|
|
|
Task 02: Enforce Tree Request Scope
Summary
Admit only workspace-relative identities to reveal, stored expansion, and refresh requests, then enforce the same tree contract before backend execution lookup and filesystem access.
In scope
- Return early from active-file reveal for absolute, absolute-URI, or traversing paths while preserving literal colons in canonical relative names.
- Sanitize restored expansion entries before deriving ancestors and retain valid siblings.
- Filter refresh fan-out and specific change paths before calling
requestFileTree. - Reject invalid tree paths in the WebSocket handler as validation failures without acquiring an execution or writing an ERROR log.
- Reject invalid tree paths in
WorkspaceTracker.GetFileTreebefore join, stat, or filesystem failure telemetry. - Preserve root, valid nested directory, symlink, missing relative path, and subtree merge behavior.
Out of scope
- Editor path normalization delivered by Task 01.
- Changing file-content path rules.
- Suppressing logs for genuine backend dependency or relative filesystem failures.
Acceptance
- The reported
/home/jcfs/...active path never adds absolute ancestors, loads a tree node, or reachesrequestFileTree, including after a generic refresh. - Stored invalid entries are removed while valid relative expansion restores and persists normally.
- Direct absolute or parent-escaping tree requests fail validation before lifecycle or filesystem work and produce no ERROR log.
TDD start
Add these failing regressions before production changes:
file-tree-reveal.test.tssupplies the reported absolute active file and expects no expansion or child load.file-browser-restore-expanded.test.tsxstores valid relative paths beside the absolute chain and expects only the valid paths to be requested and retained.file-browser-apply-changes.test.tssends a generic refresh with absolute expanded paths and expects only""plus valid relative folders.workspace_files_test.gocallsGetFileTreewith an existing absolute directory and expects a validation error rather than a joined lookup.workspace_file_handlers_test.gosupplies an absolute tree path with no lifecycle and expectsErrorCodeValidationand zero ERROR entries.
ASCII UI preview
Relevant state transition from UI-01:
Workspace file active: public/.../case.json -> Files reveals public > ... > case.json
External file active: /opt/reference.md -> Files keeps its current expansion
Stored mixed state: src, src/ui, /home/... -> restore src and src/ui only
No rendered layout or control changes. Desktop and phone consume the same sanitized Files-tree state.
Verification
Run from the repository root:
(cd apps/web && pnpm exec vitest run components/task/file-tree-reveal.test.ts \
components/task/file-browser-restore-expanded.test.tsx \
components/task/file-browser-restore-loader.test.tsx \
components/task/file-browser-apply-changes.test.ts)
(cd apps/web && pnpm run typecheck)
(cd apps/web && pnpm exec eslint components/task/file-tree-reveal.ts \
components/task/file-browser-restore.ts components/task/file-browser-hooks.ts \
--max-warnings 0)
(cd apps/backend && go test ./internal/agentctl/server/process \
-run 'TestGetFileTree' -count=1)
(cd apps/backend && go test ./internal/agent/handlers \
-run 'TestWorkspaceFileHandlers.*Tree' -count=1)
(cd apps/backend && go test ./internal/agentctl/server/process \
./internal/agent/handlers -count=1)
make -C apps/backend lint
After both work orders:
python3 scripts/list-docs.py validate
python3 scripts/lint-spec-files.test.py
python3 scripts/lint-spec-files.py --all
git diff --check
git status --short
Files likely touched
apps/web/components/task/file-tree-reveal.tsapps/web/components/task/file-tree-reveal.test.tsapps/web/components/task/file-browser-restore.tsapps/web/components/task/file-browser-restore-expanded.test.tsxapps/web/components/task/file-browser-restore-loader.test.tsxapps/web/components/task/file-browser-hooks.tsapps/web/components/task/file-browser-apply-changes.test.tsapps/backend/internal/agent/handlers/workspace_file_handlers.goapps/backend/internal/agent/handlers/workspace_file_handlers_test.goapps/backend/internal/agentctl/server/process/workspace_files.goapps/backend/internal/agentctl/server/process/workspace_files_test.go
Dependencies
- Task 01 supplies the shared frontend path classifier and prevents new tool opens from contaminating expansion state.
Risks
- The empty root path is valid and must not be filtered with invalid empty segments.
- Hidden directories beginning with
.are valid; only standalone.and..segments are rejected. - A repository-scoped refresh must keep its current sibling-subtree preservation behavior.
- The handler guard is for invalid client input. Dependency failures after a valid request must keep their operational error signal.
Parallelism
sequential
Inputs
AC-UI-FILE-TREE-PATH-SCOPE-001.2through.5.- Tree-state admission, refresh flow, and backend validation in the system design.
- Existing persisted-expansion and cross-repository refresh regressions.
Results
Implemented canonical tree-path admission for active-file reveal, stored expansion restoration, generic refresh fan-out, and specific file-change refreshes. A shared Go validator now rejects the same invalid identities before WebSocket execution lookup and before agentctl joins or stats a filesystem path. Validation failures produce no operational ERROR log.
PR review narrowed URI detection to absolute URI forms so repository-relative names such as
config:dev remain valid in both frontend and backend validation. The agentctl regression now
asserts the exported validation sentinel with errors.Is.
Validation passed:
- The combined focused frontend suite passed 90 tests across eight files.
go test ./internal/common/workspacepath -count=1passed.- Focused
TestGetFileTreeandTestWorkspaceFileHandlers.*Treeruns passed. - The complete handler package passed, and
make -C apps/backend lintreported zero issues. - Post-review coverage passed a real frontend refresh and POSIX agentctl tree read for
config:dev, plus cross-platform validator cases, the focused Go packages, and backend lint. - The full process package reached two unchanged runner-fixture timing failures on this host:
TestProcessRunnerCapturesOutputandTestProcessRunnerStopLogsSignalAttempts. The branch has no changes to those tests or their production code; both fail identically when run alone.