Give every memory a node, and show only the ones on your path
A hand-written memory used to carry a NULL depth, described in the model as "belongs to the adventure rather than to a path". That sounds harmless and is not: a NULL is a coordinate no fork can cap, so a note typed on one line followed the reader onto branches whose story it never described. It takes the head now — the story you were reading when you wrote it — and obeys exactly the rule a summarised memory obeys. The unanchored escape clause in lineage.Path.clause existed for that single case and is deleted rather than left unused. Its docstring argued that a capped depth would drop a typed memory the moment its branch stopped being the newest entry; anchoring answers the same worry better, because the memory is not exempt from the path, it is on one. The drawer now shows the path being read and nothing else, filtered by the clause retrieval itself uses, so the bank you can see is the bank the model can see. Nothing is stranded: a memory lives on a branch, switching to that branch shows it, and deleting the branch deletes it. Pinning decides order, the path decides existence. Migration 62 lands existing NULL-depth memories at depth 0 of their branch rather than at the tip. 0 is at or before every fork point, so every memory stays visible from exactly the paths it is visible from today — nobody's bank loses a row on deploy. The tip is the tidier-sounding choice and would have emptied them out of every branch forked earlier than they were typed. This supersedes the on_path flag and the "another branch" badge from earlier today; anchoring makes them redundant, and they are removed. Four tests changed because they asserted the old contract, not because they broke. The one worth reading is the pair replacing test_a_hand_written_memory_is_not_lost_at_the_first_fork: typed on shared trunk it still survives a fork, and typed on ground the fork never travelled it no longer follows you. 402 tests. Verified on tools/branch_fixture.py: each branch's drawer holds its own memory and not the other's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015H5qiyiR7gtFQaoDphHZ3g
This commit is contained in:
committed by
Parth
co-authored by
Claude Opus 5
parent
1d1367ce3a
commit
2d38a162d4
@@ -212,18 +212,50 @@ def test_the_lineage_is_read_whole_not_windowed(forked):
|
||||
assert "on the shared trunk" in retrieved(adventure, settings)
|
||||
|
||||
|
||||
def test_a_hand_written_memory_is_not_lost_at_the_first_fork(forked):
|
||||
"""A memory nobody derived summarises no node, so it has a branch but no
|
||||
depth. A capped `depth <= fork` would drop it the moment its branch stopped
|
||||
being the newest entry — a memory vanishing some turns after it was typed,
|
||||
which is exactly the kind of thing nothing reports."""
|
||||
def test_a_hand_written_memory_is_anchored_where_it_was_typed(forked):
|
||||
"""SP7: a typed memory takes the head, so it obeys the same rule as a
|
||||
summarised one.
|
||||
|
||||
It used to carry no depth, which sounded like "belongs to the whole
|
||||
adventure" and behaved like "cannot be capped at a fork" — it followed the
|
||||
reader onto branches whose story it never described. Anchoring it makes the
|
||||
bank answer one question rather than two.
|
||||
"""
|
||||
db, adventure, settings, ids = forked
|
||||
switch_to(db, adventure, ids["a"], 5)
|
||||
typed = add_memory(db, adventure, "typed by hand", None)
|
||||
assert (typed.branch_id, typed.depth) == (ids["a"], None)
|
||||
assert (typed.branch_id, typed.depth) == (ids["a"], 5), "the head it was typed at"
|
||||
|
||||
switch_to(db, adventure, ids["c"], 7) # fork away from where it was written
|
||||
assert "typed by hand" in retrieved(adventure, settings)
|
||||
|
||||
def test_a_typed_memory_survives_a_fork_of_the_ground_it_was_typed_on(forked):
|
||||
"""The half of the old behaviour that was right, kept.
|
||||
|
||||
Typed on the shared trunk it is still there after forking away — but
|
||||
because the fork's path goes through that node, not because the memory was
|
||||
exempt from being capped.
|
||||
"""
|
||||
db, adventure, settings, ids = forked
|
||||
switch_to(db, adventure, ids["a"], 3) # the trunk B, and so C, branch from
|
||||
add_memory(db, adventure, "typed on the trunk", None)
|
||||
|
||||
switch_to(db, adventure, ids["c"], 7)
|
||||
assert "typed on the trunk" in retrieved(adventure, settings)
|
||||
|
||||
|
||||
def test_a_typed_memory_does_not_follow_you_onto_a_path_it_is_not_on(forked):
|
||||
"""And the half that was wrong, fixed.
|
||||
|
||||
A5 is A's own continuation past the point B left it, so it is a sibling of
|
||||
the story C tells — precisely where the `sibling` memory sits, and excluded
|
||||
for precisely the same reason. Typing rather than summarising buys no
|
||||
exemption from the path.
|
||||
"""
|
||||
db, adventure, settings, ids = forked
|
||||
switch_to(db, adventure, ids["a"], 5)
|
||||
add_memory(db, adventure, "typed off the path", None)
|
||||
|
||||
switch_to(db, adventure, ids["c"], 7)
|
||||
assert "typed off the path" not in retrieved(adventure, settings)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ the marks
|
||||
|
||||
Reference in New Issue
Block a user