# fix\(server\): canonicalise media paths the same way their callers do · PR \#9575 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/9575)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: merged

Source repository: pingdotgg/t3code

Source branch: windows-tests/media-realpath

Target branch: windows-tests/antigravity-host

Head commit: 2c64068e10a194c8d8732a046147b9f240a4104a

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/9575)

[Commits](https://git.cafe/pingdotgg/t3code/pull/9575/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/9575/diffs?format=markdown)

## Description

---

openMediaFile rejected a file whenever fs/promises.realpath disagreed with
the path it was handed. Callers canonicalise through Effect's
FileSystem.realPath, which is Node's JS realpath; the promises variant is the
native binding, and on Windows it also expands 8.3 short names, so every
media file under a short-named temp or profile directory was refused as a
symlink swap. Use the same realpath as the callers, so the check still
catches a planted link but agrees with a path that is already canonical.

The favicon and asset tests now build their relative-path expectations with
Path.join rather than a literal '/'.

Part of the Windows test-suite stack rooted at [#9564](https://github.com/pingdotgg/t3code/pull/9564); the manual Windows lane comes from [#9538](https://github.com/pingdotgg/t3code/pull/9538).

Model: Claude Fable 5 in Claude Code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches security-sensitive media open acceptance logic; behavior can differ only where the two Node realpath APIs disagree (notably Windows short paths).
> 
> **Overview**
> **`openMediaFile`** no longer uses `fs/promises.realpath` for its “path must already be canonical” guard. It now calls callback **`fs.realpath`** via **`realpathLikeFileSystem`**, matching how upstream code canonicalises with Effect **`FileSystem.realPath`**. That fixes false rejections on Windows when the promises API expands 8.3 short names while the caller’s path is already canonical; symlink-swap protection is unchanged in intent.
> 
> **`AssetAccess`** and **`ProjectFaviconResolver`** tests now assert **`sourcePath`** / resolved favicon paths with **`Path.join`** instead of hard-coded `/` segments, so expectations match platform-native separators.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2c64068e10a194c8d8732a046147b9f240a4104a. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- Macroscope's pull request summary starts here -->
<!-- Macroscope will only edit the content between these invisible markers, and the markers themselves will not be visible in the GitHub rendered markdown. -->
<!-- If you delete either of the start / end markers from your PR's description, Macroscope will append its summary at the bottom of the description. -->
> [!NOTE]
> ### Use callback-based Node `realpath` in `openMediaFile` descriptor checks
> - Adds `realpathLikeFileSystem`, a Promise wrapper around the callback-based Node `fs.realpath`, and replaces the `fs/promises.realpath` call in `openMediaFile`'s acceptance checks with it.
> - This aligns the canonicalization with how callers produce paths, fixing mismatches where the two Node realpath APIs return different representations (e.g. Windows 8.3 short names).
> - Updates `AssetAccess` and `ProjectFaviconResolver` tests to assert exact platform-native joined paths instead of slash-separated substring checks.
> - Behavioral Change: `openMediaFile` may now accept or reject files differently for paths whose `fs/promises.realpath` and callback-based `fs.realpath` disagree; reviewers should check the descriptor acceptance logic in [MediaFile.ts](https://github.com/pingdotgg/t3code/pull/9575/files#diff-424574dcf5b519a9f9ae105181dae2a327bd986f50472319fa6a5c0d64462ed2).
>
> <!-- Macroscope's review summary starts here -->
>
> <sup><a href="https://app.macroscope.com">Macroscope</a> summarized 2c64068.</sup>
> <!-- Macroscope's review summary ends here -->
>
<!-- Macroscope's pull request summary ends here -->

