fix(graphify): canonicalize temp base so the isolated-cwd assertion is satisfiable on macOS - #52
Merged
KimYx0207 merged 1 commit intoAug 8, 2026
Conversation
macOS 的 os.tmpdir() 经系统软链 /var -> /private/var 到达,导致 realpathSync.native(cwd) 与 path.resolve(cwd) 永不相等,隔离目录断言 在每台 Mac 上恒抛错,meta:graphify:check 恒 EXIT=1。 改为在 mkdtemp 之前先规范化 tmp base,断言那三行原样保留、未削弱: 把建好的目录换成指向别处的软链时仍然抛错(已实测反证)。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On macOS,
npm run meta:graphify:checkalways fails:Reproduced on unmodified
origin/main(2ca78b93) with a zero-diff worktree.Root cause
scripts/graphify-unicode-normalize.mjscreated the isolated cwd under a rawos.tmpdir()and then asserted that the path is symlink-free by comparingrealpathSync.native(isolatedCwd)withpath.resolve(isolatedCwd).On macOS
os.tmpdir()is/var/folders/..., and/varis a system-ownedsymlink to
/private/var, so the two sides can never be equal:path.resolve(isolatedCwd)/var/folders/.../meta-kim-graphify-normalizer-XXXXrealpathSync.native(isolatedCwd)/private/var/folders/.../meta-kim-graphify-normalizer-XXXXlstat().isDirectory()/isSymbolicLink()true/false(the directory itself is fine)The assertion is therefore unsatisfiable on every macOS machine, regardless of
repository state. A repo-wide grep shows this is the only site with that
comparison shape.
Fix
Canonicalize the temp base before
mkdtempSync, so the created path isalready canonical. The three assertion lines are left byte-for-byte
unchanged.
Why not "realpath both sides"
The obvious alternative — comparing
realpathSync.native(isolatedCwd)againstrealpathSync.native(path.resolve(isolatedCwd)), or againstpath.join(realpathSync.native(tmpdir()), path.basename(isolatedCwd))— makesboth sides identical by construction. That silently deletes a security
assertion guarding the cwd handed to
spawnSyncfor the Python batch. Thispatch deliberately avoids weakening it.
Negative proof the assertion still bites
With the fix applied, replacing the freshly created directory with a symlink
pointing elsewhere still trips the guard:
Verification
Direct before/after on the same call:
Existing regression coverage already exercises this path — no new test needed:
That suite calls
createGraphifyRuntimeNormalizerwith non-ASCII values, so itfails on macOS before this patch and passes after.
Scope and limits
meta:graphify:checkexit 0. Once the normalizer gatepasses, a second pre-existing failure surfaces at
scripts/graphify-cli.mjs:691:GRAPH_REPORT.md exposes a private local path.hasPrivateLocalPath(scripts/graphify-private-path.mjs:3) treats a bare~/as a leak, whilesanitizeKnownMetaKimHomeAliasesonly sanitizes~/.meta-kim. The report faithfully indexes a tracked upstream comment,canonical/runtime-assets/claude/commands/save-progress/SKILL.md:19(
# Detect the Python hook path — it lives in ~/.claude/hooks/), so any userhits it after a rebuild. That fix involves a design trade-off (widen the
sanitizer, distinguish documentation references from real local leaks, or
reword the source comment) and is intentionally left out of this PR. Happy to
follow up if you have a preferred direction.
realpathSync.nativebehaviour there (8.3 short names, case) is unchanged bythis patch in reasoning only, not by measurement.