Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions FORK_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,48 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
*Files:* `docs/fork-changes/`, `scripts/fork_changes.py`, `scripts/render-docs.py`, `scripts/maintain-fork-changes.py`, `scripts/check-docs.sh`


### Fixed


- **test_init's sys.path assertion resolves entries against cwd, so it stops failing in every linked worktree** ([`HEAD`](https://github.com/techempower-org/mempalace/commit/HEAD))
`test_init_filters_sys_path_from_leaked_pythonpath` failed all five sentinel
params in any linked worktree, so every lane in the 2026-09-10 drain wave ran
the suite with it deselected and paid a false red before working that out.

The behaviour under test was correct throughout; the assertion was not. It
iterated `for p in sys.path if p`, excluding the empty string — and the empty
string is the cwd marker `python -c` puts on the path, which is what actually
resolves the child's import. Measured in both trees with PYTHONPATH set to
the sentinel, as the test sets it: the child imports the tree it was launched
from either way (`EMPTY_IN_PATH: True` in both), but `PARENT_ON_SYS_PATH` was
True in the main tree and False from a worktree. The absolute-entry match
succeeded in the main tree for an incidental reason — the shared venv's
editable install adds exactly that directory to `sys.path` — so the green was
measuring "is this the editable target?", not "did the filter over-strip?".
From a worktree the editable entry points at the main tree instead, the
absolute match fails, and the test reports an over-strip that never happened.

Entries are now normalised with `os.path.abspath(p or os.curdir)` before
comparison, which is faithful to the assertion's stated purpose — the package
must stay importable, so its parent must survive on `sys.path` — because the
cwd entry is how it stayed importable. It keeps its teeth: the assertion can
only fail if the filter removed both the cwd marker and any absolute entry
providing the package, which is exactly an over-strip, and a child that
cannot import at all still trips the `returncode == 0` assertion first.

`MEMPALACE_IMPORTED_FROM` is printed for diagnosis and deliberately not
asserted on: which tree the child resolves depends on its cwd, and pinning
that would re-introduce the coupling being removed.

Verified both directions, since a fix that only passes where it already
passed would be worthless: 8/8 from a linked worktree and 8/8 with cwd set to
the main tree, against 5 failed / 3 passed for the old test from a worktree.
The full suite now runs green from a worktree with no manual deselect.

*Tests:* 0 new (repairs 5 existing params; the suite from a worktree goes 5 failed -> 0)
*Files:* `tests/test_init.py`


## [2026-09-10]


Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ The full enumeration of fork-ahead changes. The canonical source is [`docs/fork-

| Description | Upstream PR | Fork commit |
|---|---|---|
| test_init's sys.path assertion resolves entries against cwd, so it stops failing in every linked worktree | — | [`HEAD`](https://github.com/techempower-org/mempalace/commit/HEAD) |
| Fork-change entries split one-per-file; entry shas verified by ancestry and resolved after merge | — | [`HEAD`](https://github.com/techempower-org/mempalace/commit/HEAD) |
| README install path documents putting the mempalace-mcp bridge on PATH | — | [`933602e`](https://github.com/techempower-org/mempalace/commit/933602e) |
| Checkpoint drawers carry the session id, not just the diary entry; session_id is validated | — | [`1a54838`](https://github.com/techempower-org/mempalace/commit/1a54838) |
Expand Down
46 changes: 46 additions & 0 deletions docs/fork-changes/2026-09-11-init-test-cwd-relative-syspath.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
seq: 139
id: init-test-cwd-relative-syspath
date: '2026-09-11'
bucket: Fixed
commit: HEAD
fork_pr: 482
area: Testing
summary: test_init's sys.path assertion resolves entries against cwd, so it stops failing
in every linked worktree
body: |
`test_init_filters_sys_path_from_leaked_pythonpath` failed all five sentinel
params in any linked worktree, so every lane in the 2026-09-10 drain wave ran
the suite with it deselected and paid a false red before working that out.

The behaviour under test was correct throughout; the assertion was not. It
iterated `for p in sys.path if p`, excluding the empty string — and the empty
string is the cwd marker `python -c` puts on the path, which is what actually
resolves the child's import. Measured in both trees with PYTHONPATH set to
the sentinel, as the test sets it: the child imports the tree it was launched
from either way (`EMPTY_IN_PATH: True` in both), but `PARENT_ON_SYS_PATH` was
True in the main tree and False from a worktree. The absolute-entry match
succeeded in the main tree for an incidental reason — the shared venv's
editable install adds exactly that directory to `sys.path` — so the green was
measuring "is this the editable target?", not "did the filter over-strip?".
From a worktree the editable entry points at the main tree instead, the
absolute match fails, and the test reports an over-strip that never happened.

Entries are now normalised with `os.path.abspath(p or os.curdir)` before
comparison, which is faithful to the assertion's stated purpose — the package
must stay importable, so its parent must survive on `sys.path` — because the
cwd entry is how it stayed importable. It keeps its teeth: the assertion can
only fail if the filter removed both the cwd marker and any absolute entry
providing the package, which is exactly an over-strip, and a child that
cannot import at all still trips the `returncode == 0` assertion first.

`MEMPALACE_IMPORTED_FROM` is printed for diagnosis and deliberately not
asserted on: which tree the child resolves depends on its cwd, and pinning
that would re-introduce the coupling being removed.

Verified both directions, since a fix that only passes where it already
passed would be worthless: 8/8 from a linked worktree and 8/8 with cwd set to
the main tree, against 5 failed / 3 passed for the old test from a worktree.
The full suite now runs green from a worktree with no manual deselect.
tests: 0 new (repairs 5 existing params; the suite from a worktree goes 5 failed -> 0)
files:
- tests/test_init.py
24 changes: 21 additions & 3 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,20 @@ def test_init_filters_sys_path_from_leaked_pythonpath(pythonpath):
Asserts on the sentinel substring directly so the test does not
couple to the production normalization logic. The dot/empty/unset
cases additionally exercise the early-return / collision paths
without crashing."""
without crashing.

The parent-retained assertion resolves relative ``sys.path`` entries
against the child's cwd before comparing (#454). ``python -c`` puts the
cwd on ``sys.path`` as the empty string, and that entry is what actually
makes the package importable here — the child imports the tree it was
launched from. Comparing only ABSOLUTE entries made the assertion pass
for an incidental reason: in the main tree the editable install happens
to add that exact directory, so the check succeeded; from a linked
worktree the editable entry points at the main tree instead, the
absolute match failed, and all five sentinel params went red while the
behaviour under test was working perfectly. Measured both ways; every
lane on 2026-09-10 paid that false red.
"""
env = os.environ.copy()
if pythonpath is None:
env.pop("PYTHONPATH", None)
Expand All @@ -44,11 +57,12 @@ def test_init_filters_sys_path_from_leaked_pythonpath(pythonpath):
"import mempalace, os, sys; "
f"prefix = {_LEAK_PREFIX!r}; "
"mempalace_parent = os.path.dirname(os.path.dirname(mempalace.__file__)); "
"norm = lambda p: os.path.normcase(os.path.normpath(os.path.abspath(p or os.curdir))); "
"print('ENV:', repr(os.environ.get('PYTHONPATH'))); "
"print('SENTINEL_IN_PATH:', any(prefix in (p or '') for p in sys.path)); "
"print('MEMPALACE_PARENT_PRESENT:', any("
"os.path.normcase(os.path.normpath(p)) == os.path.normcase(os.path.normpath(mempalace_parent)) "
"for p in sys.path if p))"
"norm(p) == norm(mempalace_parent) for p in sys.path)); "
"print('MEMPALACE_IMPORTED_FROM:', mempalace_parent)"
)
result = subprocess.run(
[sys.executable, "-c", code],
Expand All @@ -74,6 +88,10 @@ def test_init_filters_sys_path_from_leaked_pythonpath(pythonpath):
assert "MEMPALACE_PARENT_PRESENT: True" in out, (
f"filter over-stripped sys.path (mempalace parent gone): {diag}"
)
# MEMPALACE_IMPORTED_FROM is printed for diagnosis and deliberately NOT
# asserted on: which tree the child resolves depends on its cwd, and
# pinning that is the very coupling #454 was about. It belongs in the
# failure output, not in the contract.


def test_init_preserves_cwd_marker_when_pythonpath_collides():
Expand Down
1 change: 1 addition & 0 deletions website/public/llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ The full enumeration of fork-ahead changes. The canonical source is [`docs/fork-

| Description | Upstream PR | Fork commit |
|---|---|---|
| test_init's sys.path assertion resolves entries against cwd, so it stops failing in every linked worktree | — | [`HEAD`](https://github.com/techempower-org/mempalace/commit/HEAD) |
| Fork-change entries split one-per-file; entry shas verified by ancestry and resolved after merge | — | [`HEAD`](https://github.com/techempower-org/mempalace/commit/HEAD) |
| README install path documents putting the mempalace-mcp bridge on PATH | — | [`933602e`](https://github.com/techempower-org/mempalace/commit/933602e) |
| Checkpoint drawers carry the session id, not just the diary entry; session_id is validated | — | [`1a54838`](https://github.com/techempower-org/mempalace/commit/1a54838) |
Expand Down
Loading