Repository navigation
emrg: the rotation reading tells two spellings of one file apart, so the bookmark counts as memory #2559
Description
What is observed
scripts/check-memory-rotation.py::_same_file decides whether two paths are one file by
comparing resolved strings:
def _same_file(a: Path, b: Path) -> bool:
"""Whether two paths name one file, through symlinks and a relative spelling alike."""
try:
return os.path.realpath(a) == os.path.realpath(b)
except OSError:
return Falseos.path.realpath resolves symlinks and .., and then returns the spelling it was handed
for the components that exist. On a volume that folds case, two spellings of one file
therefore compare unequal — and the volume itself says they are one file.
The helper's one caller is the exclude argument of memory_files: the bookmark is the
clock, not memory content, so it is removed from the scan (#2422). When the exclusion is
spelled differently from the walk, it is not removed.
Where it was observed
macOS 26.6.2 (APFS, case-folding), master 5c6b832d, on this checkout's own bookmark
.emrg/memory/project-memory-rotation-bookmark.md. Measured through the script's own
functions, loaded by path:
bookmark exists : True
variant exists : True
os.path.samefile : True # the volume's answer
script _same_file : False # the script's answer
realpath(variant) : .../memory/PROJECT-MEMORY-ROTATION-BOOKMARK.MD
realpath(bm) : .../memory/project-memory-rotation-bookmark.md
files with true bookmark excluded : 127
files with CASED bookmark excluded: 128
bookmark counted when excluded by its cased spelling: True
The one-file difference is the bookmark itself. That is the exact state #2422 removed: the
bookmark counted as the memory of the agent that holds it, which makes that agent's row read
changed on the strength of the file that asks the question.
What was expected instead
The same answer os.path.samefile gives: two spellings that name one file are one file,
decided by the filesystem's identity (st_dev + st_ino) rather than by a comparison of
strings. emrg/tools/file_policy.py::same_file states this rule for the rest of the tree and
documents why (#2552); emrg/tools/shell_env.py::_same_directory delegates to it (#2558).
What the fix must satisfy
- Two spellings of one file are one file on a volume that folds case, whether or not the
platform is Windows. Decide by identity, not by a transform of the paths. - A path that is not there still gets an answer: it is not the file it is compared with, so
it is not excluded. Excluding a path that does not exist would hide a real memory file. - The
excludebehaviour emrg: the rotation bookmark counts itself as memory, so the project holding it always reads as changed #2422 established does not regress: the bookmark is still removed
when it is spelled the way the walk spells it. - Both directions are measured, and the case-variant arm skips with its reason stated where
the volume keeps two spellings apart, rather than passing without asking.
Note on where the rule should live
This script is deliberately standalone — it imports nothing from the package, so its test
harness puts no tree on sys.path (see the header of tests/test_check_memory_rotation.py).
That constraint is in tension with "one home for the rule": either the script asks
os.path.samefile directly and the tension is recorded in its docstring, or it imports the
home and the standalone property is given up deliberately. Either is defensible; leaving two
different answers to "are these one file" in one repository is not.
Activity
argszero commentedon Oct 23, 2026
Handled by #2562
emrg: the rotation reading asks the volume which two spellings are on…