Skip to content

[Bug]: Windows Local folder misses an existing UNC project when the input uses forward slashes #34755

Closed as not planned

Description

@coygeek

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

packages/contracts or packages/shared

Steps to reproduce

  1. In a fresh clone of pingdotgg/t3code, check out 7462f234e89027943cf0d1a73d3ae1f36571d4e3, use the repository's Node v26.12.1 toolchain, and install with vp i --frozen-lockfile -- --yes < /dev/null. Use an isolated T3CODE_HOME, for example export T3CODE_HOME="$(mktemp -d)", before running the install and test. I ran these install/test steps in a detached worktree of that exact commit.
  2. Save the following as packages/client-runtime/src/operations/verify-unc-r2.test.ts:
import { win32 } from "node:path";
import { EnvironmentId, ProjectId } from "@t3tools/contracts";
import { expect, it } from "vite-plus/test";
import type { EnvironmentProject } from "../state/models.ts";
import { findExistingAddProject, resolveAddProjectPath } from "./projects.ts";

const environmentId = EnvironmentId.make("environment-test");
const timestamp = new Date(0).toISOString();
const project: EnvironmentProject = {
  environmentId,
  id: ProjectId.make("project-existing"),
  title: "Repo",
  workspaceRoot: "\\\\server\\share\\repo",
  createdAt: timestamp,
  updatedAt: timestamp,
  repositoryIdentity: null,
  defaultModelSelection: null,
  scripts: [],
};

it("control: Windows path semantics identify the two UNC spellings", () => {
  expect(win32.resolve("//server/share/repo")).toBe(win32.resolve(project.workspaceRoot));
});

it.each([
  ["backslash control", "\\\\server\\share\\repo"],
  ["case control", "\\\\SERVER\\Share\\Repo"],
  ["forward slash", "//server/share/repo"],
  ["forward slash and case", "//Server/Share/Repo"],
])("Windows Local folder reuses an existing project: %s", (_label, rawPath) => {
  const resolved = resolveAddProjectPath({ rawPath, currentProjectCwd: null, platform: "Win32" });
  expect(resolved.ok).toBe(true);
  if (!resolved.ok) throw new Error(resolved.error);
  const existing = findExistingAddProject({ projects: [project], environmentId, path: resolved.path });
  console.log(JSON.stringify({ rawPath, resolvedPath: resolved.path, matched: existing?.id ?? null }));
  expect(existing?.id).toBe(project.id);
});

it("control: POSIX double-slash paths retain literal backslashes and case", () => {
  const posixProject = { ...project, workspaceRoot: "//server/share/a\\b" };
  const resolved = resolveAddProjectPath({ rawPath: posixProject.workspaceRoot, platform: "Linux" });
  expect(resolved).toEqual({ ok: true, path: posixProject.workspaceRoot });
  if (!resolved.ok) throw new Error(resolved.error);
  expect(findExistingAddProject({ projects: [posixProject], environmentId, path: resolved.path })).toBe(posixProject);
  expect(findExistingAddProject({ projects: [posixProject], environmentId, path: "//server/share/a/b" })).toBeNull();
  expect(findExistingAddProject({ projects: [posixProject], environmentId, path: "//SERVER/share/a\\b" })).toBeNull();
});
  1. Run vp test run packages/client-runtime/src/operations/verify-unc-r2.test.ts --reporter=verbose from the repository root.
  2. Observe two failing forward-slash cases beside four passing controls. Both forward-slash inputs resolve successfully and log matched: null; both backslash inputs log matched: "project-existing". The Windows lexical-equivalence and POSIX-preservation controls also pass. Remove the temporary test afterward.

The single independent run produced both failures deterministically for the shown pure inputs. The test invokes the actual resolver and lookup used by mobile submission; it does not substitute mocked implementations. The existing shared path and web project-lookup tests were also run separately and passed, 63 tests total.

Expected behavior

For a Windows destination, entering the same registered UNC root with forward rather than backslash separators should reuse that existing project. Mobile's existing-project branch opens its draft, and the existing project lookup test requires Windows formatting variants to find the same project. The shared path module documents Windows slash equivalence; the passing Node win32.resolve control confirms the two test strings have the same Windows lexical path.

This expectation applies to Windows input. The shared path tests also require a POSIX double-slash path to preserve literal backslashes. A correction must preserve that independent behavior; treating every double-slash path on every destination as Windows is not the expected result.

Actual behavior

At the baseline below, I ran the shared operations used by mobile Local folder with the actual Windows destination platform string, Win32. With a registered project rooted at \\server\share\repo, resolveAddProjectPath accepts //server/share/repo, but findExistingAddProject returns null. Entering \\server\share\repo or the mixed-case backslash spelling finds the existing project. The forward-slash spelling misses even when every letter has identical case.

Source-traced consequence: mobile skips its existing-project branch, which would open that project's new-task draft, and instead sends a new project-create command. This run did not launch a native client, access a network share, or execute Windows filesystem/persistence operations. It does not establish creation of a duplicate project or a particular UI error.

Impact

Minor bug or occasional failure

Version or commit

Source baseline: 7462f234e89027943cf0d1a73d3ae1f36571d4e3. Fetched origin/main was a41b8820607c2c7bf1efac4912532d0699fa2413, 18 commits later; none changed the relevant path, resolver, lookup, mobile caller, or server normalization/conflict files. The assigned conditional upstream check therefore required no second checkout/test run.

Environment

Observed test host: Darwin 27.2.0 arm64, Node v26.12.1, global vp v1.6.0, repository-pinned vite-plus v1.4.0, Vitest v5.0.5, pnpm v12.14.0. The tested destination is explicitly Win32, which is what mobile produces for a Windows environment. No native Windows execution is claimed.

Logs or stack traces

I ran the reproduction above and observed:

backslash control: resolved successfully; matched "project-existing"
case control: resolved successfully; matched "project-existing"
forward slash: resolved successfully; matched null
forward slash and case: resolved successfully; matched null
Tests  2 failed | 4 passed (6)
AssertionError: expected undefined to be 'project-existing'

The four labelled lines summarize the test's JSON output. The assertion reads existing?.id, so a null lookup produces undefined in the assertion while the diagnostic deliberately prints null. Fixture share/project names are synthetic.

Source evidence for reachability and the failure:

Workaround

No response

Impact and scope

Impact: P2 - a supported Windows folder spelling bypasses existing-project reuse and enters creation instead; the same folder entered with backslashes successfully matches, providing a practical workaround.

Observed scope is client path resolution and existing-project lookup for a Windows destination, exercised on macOS without filesystem access. Case variation is unnecessary to trigger the failure. The backslash control demonstrates the workaround at the same tested boundary. The web palette also calls the shared lookup, but its UI was not run. Native Windows behavior, server response and persisted project effects were not exercised, so no duplicate-creation or data-loss claim is made.

Interface

Library: client-runtime operations used by mobile Local folder; the actual mobile UI path is established from source.

Earliest failure stage

Core processing: existing-project identity comparison after accepted Windows add-folder input.

Additional context

Related issues

  • #13421 includes the exact forward-slash UNC shared-normalizer regression, but is CLOSED with no merge. Its maintainer's final comment closes the implementation because the V2 rewrite removed ProjectionSnapshotQuery.ts, explicitly without assuming the underlying request was resolved. This report re-establishes the surviving shared-path failure through the current mobile resolver/lookup caller.
  • #23237 and #23500 cover home-relative mobile reuse and clone destinations. The current PR diff only resolves home-prefixed paths before calling the existing lookup, returning absolute forward-slash UNC input unchanged; it does not change the shared normalizer. Closed earlier attempts #23238 and #8229 concern that same mobile reuse work, rather than this Windows separator mismatch.
  • Merged #29245 preserves POSIX literal backslashes and includes mixed-UNC file-link compatibility. It establishes the platform constraint above but does not correct project comparison keys.
  • Merged #3829 introduced duplicate-workspace protection; it does not establish successful current client lookup for this input. The current server conflict checks should not be mistaken for opening the existing project's draft.
  • Open #31639 concerns Windows drive-path display and explicitly leaves UNC paths unchanged.

Fresh searches covered normalizeProjectPathForComparison, findExistingAddProject, findProjectByPath, forward-slash UNC, UNC titles and duplicate-project/path terms in open and closed issues/PRs, plus the supplied known-issues index. No open exact report for this UNC separator lookup failure was found.

Activity

  1. maria-rcks commented on Nov 15, 2026

    @maria-rcks
    Collaborator

    Note

    Written by claude-fable-5-2 on behalf of Maria

    Closing: this account is denounced in .github/VOUCHED.td for filing automated issues faster than maintainers can triage them. A fix PR that links this issue is not affected by this close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    vouch:denouncedAuthor is explicitly blocked by the VOUCHED list.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions