Answer the review, and keep the opening node's bank
Nine findings from a review of the phase-14 stack. The one about a retry withdrawing a memory is not a bug — a memory anchored to a node describes that node, and it goes when the node goes. The root is the exception, and it is the only one: migration 62 parked every memory written before memories had coordinates on depth 0, so withdrawing the opening node would retire a whole bank nobody attached there. A memory with no source range covers no story and now stays; a summary that genuinely ends there is still withdrawn. The rest are repairs. * The adventure list quoted whichever attempt was written last rather than the one the story tells, so switching back left the index disagreeing with the page. * A v1 import gave a typed memory no depth, rebuilding the NULL the migration exists to remove — invisible until the imported adventure forked. * The action cap counted a v1 file's turns, and a turn expands into a row per saved attempt, so a file inside the cap could write a multiple of it. * Forking a live node on a borrowed ancestor promoted a sibling on a branch the caller never named. It is a branch switch, and now says so. * Switching attempts left the state, status and memory panels reading the previous take: the story does not change length, so nothing keyed on its length noticed. Same class as the branch-switch bug this phase already fixed. * A retry after switching back numbered the new attempt into the middle of the group instead of the end. * The cursor backfill numbered every action in the table once per adventure; correlated to the adventure being updated, it is an index lookup instead. * Renaming a branch answered own_actions=0. And one behaviour change recorded rather than repaired: script-visible history and actionCount no longer count blank-text rows. That is the right shape and there is no reading compatible with both, so plan/14 says so. 409 tests. 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
2d38a162d4
commit
4af6e17406
@@ -452,3 +452,53 @@ def test_retrieving_from_a_deep_fork_costs_what_a_flat_story_costs(deeply_forked
|
||||
f"retrieval on a 20-fork story cost {forked_bytes:,} B against the "
|
||||
f"{flat_bytes:,} B a flat story of the same length cost"
|
||||
)
|
||||
|
||||
|
||||
# ------------------------------------------------------- the opening node
|
||||
|
||||
def test_a_typed_memory_on_the_opening_node_survives_that_node_going(forked):
|
||||
"""The one place a node and its memories part company.
|
||||
|
||||
A memory anchored to a node is withdrawn with the node, which is the rule
|
||||
and is deliberate: it described that turn, and the turn is leaving. But
|
||||
migration 62 parked *every* memory written before memories had coordinates
|
||||
on depth 0 — the only landing spot visible from every branch — so the
|
||||
opening node carries a whole bank it never produced. Withdrawing it would
|
||||
retire all of that in one click, for every adventure predating the tree.
|
||||
|
||||
A memory with no `source_start` covers no stretch of story, so nothing about
|
||||
it can go stale. It stays.
|
||||
"""
|
||||
db, adventure, settings, ids = forked
|
||||
typed = models.Memory(
|
||||
adventure_id=adventure.id, text="Kira is the innkeeper's daughter",
|
||||
source_start=None, source_end=None,
|
||||
)
|
||||
typed.branch_id, typed.depth = ids["a"], 0
|
||||
db.add(typed)
|
||||
db.commit()
|
||||
typed_id = typed.id
|
||||
|
||||
withdrawn = memorybank.forget_node(db, adventure, ids["nodes"]["A0"])
|
||||
db.commit()
|
||||
|
||||
assert withdrawn == 0
|
||||
assert db.get(models.Memory, typed_id) is not None
|
||||
|
||||
|
||||
def test_a_summary_of_the_opening_node_is_still_withdrawn(forked):
|
||||
"""The exception is about memories that describe nothing, not about depth 0.
|
||||
|
||||
A summary that genuinely ends on the opening node describes text that is
|
||||
going, so it goes too — otherwise the root would collect exactly the
|
||||
dangling rows `forget_node` replaced `prune_dangling_memories` to prevent.
|
||||
"""
|
||||
db, adventure, settings, ids = forked
|
||||
derived = add_memory(db, adventure, "the opening, summarised", ids["nodes"]["A0"])
|
||||
derived_id = derived.id
|
||||
|
||||
withdrawn = memorybank.forget_node(db, adventure, ids["nodes"]["A0"])
|
||||
db.commit()
|
||||
|
||||
assert withdrawn == 1
|
||||
assert db.get(models.Memory, derived_id) is None
|
||||
|
||||
Reference in New Issue
Block a user