Files
kandev/docs/plans/symlink-identification/plan.md
T
2026-09-15 12:20:54 +01:00

6.4 KiB

created, status, requirements, system_design, legacy_specs
created status requirements system_design legacy_specs
2026-09-14 implemented
REQ-WORKSPACES-SYMLINK-001
../../specs/workspaces/system-design/symlink-identification.md

Implementation Plan: Symlink identification

Overview

Deliver one vertical slice: authoritative change-layer metadata, live projection, then consistent Changes and editor indicators. One sequential work order owns integration and verification. Implementation and targeted verification are complete.

Scope

In scope: workspace staged/unstaged/untracked rows, list/tree layouts, opened files in both editor providers and existing preview/mobile surfaces, localization, and stale metadata removal. Out of scope: target navigation, file-tree redesign, remote PR/historical classification without mode metadata, and changed mutations.

Technical approach

Follow the design. Extend FileInfo/FileChangeFacet through the existing transport and store; classify each layer independently without reading targets or depending on patch bodies. Thread existing resolved-path editor state through shared indicators. Reuse mobile Changes/viewer composition. No new dependency or storage schema.

ASCII UI preview

UI-01: Workspace Changes, list or tree, desktop and phone. Entry: task Changes; state: an uncommitted symlink and regular file.

Changes > Unstaged
[+] [link] CLAUDE.md             [edit] [discard]
[+]        AGENTS.md             [edit] [discard]

UI-02: Opened symlink, desktop editor toolbar or phone viewer header. Entry: edit/open CLAUDE.md; state: readable symlink.

CLAUDE.md   [link] Symlink       [existing actions]
------------------------------------------------
                  file contents

The same inline content applies on phones inside the existing mobile surfaces; existing navigation and touch-sized actions remain. Required: marker persists on hover, filename can truncate, marker does not shrink, editor label is visible. Spacing and English copy are illustrative, not pixel or localization contracts. Regular files and unknown metadata omit the marker. Broken links retain the Changes marker and existing file-open error. No new empty/loading surface. Maps to AC-WORKSPACES-SYMLINK-001.1 through .4; rendered checks below prove it.

Tests

  • AC 001.1 and 001.3: add TestSymlinkStatusMetadata in workspace_git_symlink_test.go: staged, unstaged, untracked, deletion, rename, type replacement, mixed layer, broken/external target, skipped diff and unknown metadata. Use real temporary Git repositories. Verify JSON serialization.
  • AC 001.1 and 001.4: extend changes-panel-helpers.test.ts, changes-panel-file-row.test.tsx and set-git-status-return.test.ts for facet mapping, regular/unknown entries, marker persistence and metadata-only refresh.
  • AC 001.2 and 001.4: extend use-file-editors.build-state.test.ts, file-editors-sync.test.ts, and file-editor-content.test.tsx for both providers, symlink-to-regular reload with unchanged contents, same paths in two repositories, and preservation of dirty buffers/request identity.

All AC suffixes refer to AC-WORKSPACES-SYMLINK-001.

E2E tests

Extend e2e/tests/git/symlink-file.spec.ts (chromium) with Changes list/tree markers and editor identification for both providers. Existing target-edit/save coverage must still pass. Add e2e/tests/git/mobile-symlink-identification.spec.ts (mobile-chrome) using real symlink fixtures and existing mobile navigation: identify the row, tap edit, assert visible editor label, open the regular target, and assert the label disappears. Check long paths, document overflow, and retained action hit areas. Together these cover AC 001.1 through .4. Managed runners rebuild product assets; run desktop and mobile sequentially.

Work orders

Verification

(cd apps && pnpm install --frozen-lockfile)
(cd apps/backend && GOCACHE=/tmp/kandev-symlink-go-cache go test ./internal/agentctl/server/process -run 'Symlink|Mixed' -count=1)
(cd apps/backend && GOCACHE=/tmp/kandev-symlink-go-cache go test ./internal/agentctl/types/... -count=1)
(cd apps/web && pnpm test components/task/changes-panel-helpers.test.ts components/task/changes-panel-file-row.test.tsx components/task/file-editor-content.test.tsx hooks/use-file-editors.build-state.test.ts hooks/file-editors-sync.test.ts hooks/domains/session/git-change-facets.test.ts lib/state/slices/session-runtime/set-git-status-return.test.ts)
(cd apps/web && pnpm run typecheck)
(cd apps/web && pnpm run i18n:check)
(cd apps/web && GOCACHE=/tmp/kandev-symlink-go-cache pnpm e2e:run --project chromium tests/git/symlink-file.spec.ts)
(cd apps/web && GOCACHE=/tmp/kandev-symlink-go-cache pnpm e2e:run --no-build --project mobile-chrome tests/git/mobile-symlink-identification.spec.ts)
python3 scripts/list-docs.py validate
python3 scripts/lint-spec-files.py --all
git diff --check

Verification results

Unit, integration, typecheck, localization and lint checks passed. Desktop E2E passed (4 tests); mobile E2E passed (1 test). Exact commands and results are recorded in Task 01.

Post-fixup review regressions are recorded in Task 01: same-path delete/recreate layers are preserved and an existing editor tab refreshes symlink identity without losing dirty content.

Risks

Mode changes and deleted paths cannot be classified from today's filesystem alone. Diff budgets must not erase identity. Store equality and editor refresh can otherwise retain stale labels. Platforms unable to create native symlinks need explicit test skips with a reason; Unix CI must exercise real fixtures.

Public documentation

During implementation add a concise explanation of the marker and editor label to docs/public/sessions-and-review.md (how-to). Do not advertise draft behavior in public docs during this design turn.

User-requested follow-up: Files tree entries use the shared link glyph in the existing file/folder icon slot when FileTreeNode.is_symlink is true. Desktop and phone Files surfaces share this renderer. Directory chevrons, touch actions, and ordinary icons are preserved. Search results without metadata are unchanged.

Files (desktop and phone)
  [link]   new-link.md
  [file]   ordinary-file.md
  > [link] linked-directory