[PR #1535] [MERGED] fix(reference): join internal symlink targets with the inventory NFC normalizer #2952

Closed
opened 2026-10-17 21:12:11 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1535
Author: @anujsingh-cse
Created: 10/10/2026
Status: ✅ Merged
Merged: 10/10/2026
Merged by: @morluto

Base: main ← Head: fix/symlink-target-nfc-identity


📝 Commits (3)

  • 91239ef fix(reference): join internal symlink targets with the inventory NFC normalizer
  • 36020b6 fix(reference): preserve source spelling during symlink lookup
  • af6d559 Merge remote-tracking branch 'origin/main' into HEAD

📊 Changes

2 files changed (+68 additions, -1 deletions)

View changed files

📝 src/domain/referenceSourceGraph.test.ts (+53 -0)
📝 src/domain/referenceSourceGraph.ts (+15 -1)

📄 Description

Problem

checkSymlinks in src/domain/referenceSourceGraph.ts resolved an internal symlink target with bare posix.normalize and looked the result up in the inventoried path set:

const resolved = posix.normalize(
  posix.join(posix.dirname(entry.path), entry.target),
);
if (resolved.startsWith("../") || resolved === ".." || !paths.has(resolved))

A target a filesystem reports in NFD (macOS readlink commonly does) joins to an NFD spelling while the inventory holds NFC, so validation reported Internal symlink target must resolve to an inventoried entry for a target the inventory actually contains — the same path-identity class #1488 describes.

The three joins #1488 lists are already routed through normalizeJoinedLogicalPath (that landed with #1513); this join was the remaining one of the class, which the issue's Where list missed.

Fix

Route the symlink join through normalizeJoinedLogicalPath, the inventory identity normalizer, exactly like the #1513 fixes. The feature-seed NFKC query fold stays a query, per the issue's expected behavior. Internal targets are already schema-constrained to relative, backslash-free, normalized spellings, so the extra normalization only adds NFC.

Verification

$ npm run test:focused -- src/domain/referenceSourceGraph.test.ts
Test Files  1 passed (1)
     Tests  11 passed (11)

Two new cases in a dedicated describe block (the file's main describe is at the max-lines-per-function limit):

  • an NFD-spelled target (cafe\u0301.ts) resolving to an NFC inventoried file (src/café.ts) now validates instead of failing
  • an NFD target that normalizes to a path no inventory holds is still rejected

The NFC case fails on the pre-fix source (red/green confirmed locally).

$ npm run check:fast
Tasks: 2 successful, 2 total

$ npm run verify:test-discovery
Discovered all 725 test files exactly once.

Unavailable coverage: no real-provider or host lane is relevant to this validator change.

Refs #1488


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1535 **Author:** [@anujsingh-cse](https://github.com/anujsingh-cse) **Created:** 10/10/2026 **Status:** ✅ Merged **Merged:** 10/10/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/symlink-target-nfc-identity` --- ### 📝 Commits (3) - [`91239ef`](https://github.com/morluto/rea/commit/91239ef5b95853831f714d63a6e39513db6ca4c5) fix(reference): join internal symlink targets with the inventory NFC normalizer - [`36020b6`](https://github.com/morluto/rea/commit/36020b6e145bf1be851355da594e0da63a93d2d4) fix(reference): preserve source spelling during symlink lookup - [`af6d559`](https://github.com/morluto/rea/commit/af6d559d6ae5317032f13648967cfa6e2f10b89a) Merge remote-tracking branch 'origin/main' into HEAD ### 📊 Changes **2 files changed** (+68 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `src/domain/referenceSourceGraph.test.ts` (+53 -0) 📝 `src/domain/referenceSourceGraph.ts` (+15 -1) </details> ### 📄 Description ## Problem `checkSymlinks` in `src/domain/referenceSourceGraph.ts` resolved an internal symlink target with bare `posix.normalize` and looked the result up in the inventoried path set: ```ts const resolved = posix.normalize( posix.join(posix.dirname(entry.path), entry.target), ); if (resolved.startsWith("../") || resolved === ".." || !paths.has(resolved)) ``` A target a filesystem reports in NFD (macOS `readlink` commonly does) joins to an NFD spelling while the inventory holds NFC, so validation reported `Internal symlink target must resolve to an inventoried entry` for a target the inventory actually contains — the same path-identity class #1488 describes. The three joins #1488 lists are already routed through `normalizeJoinedLogicalPath` (that landed with #1513); this join was the remaining one of the class, which the issue's Where list missed. ## Fix Route the symlink join through `normalizeJoinedLogicalPath`, the inventory identity normalizer, exactly like the #1513 fixes. The feature-seed NFKC query fold stays a query, per the issue's expected behavior. Internal targets are already schema-constrained to relative, backslash-free, normalized spellings, so the extra normalization only adds NFC. ## Verification ``` $ npm run test:focused -- src/domain/referenceSourceGraph.test.ts Test Files 1 passed (1) Tests 11 passed (11) ``` Two new cases in a dedicated describe block (the file's main describe is at the `max-lines-per-function` limit): - an NFD-spelled target (`cafe\u0301.ts`) resolving to an NFC inventoried file (`src/café.ts`) now validates instead of failing - an NFD target that normalizes to a path no inventory holds is still rejected The NFC case fails on the pre-fix source (red/green confirmed locally). ``` $ npm run check:fast Tasks: 2 successful, 2 total $ npm run verify:test-discovery Discovered all 725 test files exactly once. ``` Unavailable coverage: no real-provider or host lane is relevant to this validator change. Refs #1488 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-17 21:12:11 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#2952
No description provided.