Repository navigation
emrg: the runner's import root tells two spellings of one directory apart #2557
Description
What is observed
emrg/tools/shell_env.py::_same_directory decides whether two spellings name one
directory by comparing os.path.normcase(canonical_path(...)). normcase folds case on
Windows and is the identity function on POSIX, so where a volume folds case while the
platform is POSIX — APFS's default, which is what macOS runs — two spellings of one
directory are reported as two directories.
runner_import_env asks exactly that question, to decide whether the running package's
root is already reachable through PYTHONPATH. When the answer is wrongly "no", it
prepends a second entry naming the same directory.
Where it was observed
macOS 26.6.2 (APFS, case-folding), on master 6a217042. emrg/tools/bash_tool_v2.py and
emrg/tools/pwsh_tool_v2.py both call runner_import_env(), so this is reachable on the
host platform and not only on the Windows rung the function was written for.
Reproduction, both directions, measured on that tree:
$ python3 -c "
import os
from emrg.tools.shell_env import runner_import_env, _running_package_root, _same_directory
root = _running_package_root()
variant = os.path.join(os.path.dirname(root), os.path.basename(root).upper())
print('same spelling ->', runner_import_env({'PYTHONPATH': root}))
print('one directory? ->', _same_directory(variant, root))
print('variant spelling ->', runner_import_env({'PYTHONPATH': variant}))
"
same spelling -> {}
one directory? -> False
variant spelling -> {'PYTHONPATH': '<root>'}
The first answer is correct: the root is already named, so nothing is added. The second
and third name the same directory — the volume says so — and an entry is still added.
What was expected instead
The function's docstring states the purpose it fails at on this volume: "treating them
as two would prepend a duplicate rather than leave a correct declaration alone." Here it
prepends the duplicate that sentence exists to prevent.
What the fix must satisfy
- Two spellings that name one directory are one directory, decided by the filesystem's
own identity (st_dev+st_ino, asos.path.samefilecompares) rather than by a
string transform. This is the same mechanism a protected daemon file is recognised by,
and it answers on every platform without asking which one is running. - A path that is not there still gets an answer — it is not the directory it is compared
with, so the root is prepended. Prepending is the fail-safe direction: a duplicate
entry is harmless, a missing one breaks the runner's import. - Where the platform folds case by default, the two spellings must still read as one
directory; the fix must not regress the Windows case the current spelling gets right. - Both directions are measured, and a volume-dependent one skips with its reason stated
where the volume keeps the spellings apart, rather than passing without asking.
Activity
argszero commentedon Oct 23, 2026
Handled by #2558 — the comparison now asks
emrg.tools.file_policy.same_file(identity,st_dev+st_ino) instead ofnormcase, with the fold measured on APFS and a missing directory still answered by prepending.