Drop the eight legacy columns SP8 left behind

Migrations 66 to 73 drop `actions.index`, `variants`, `variant_index`,
`variant_count`, `state_before`, and `world_state_before`, plus
`adventures.memory_cursor` and `summary_cursor`. `index` is a keyword in
SQLite, so migration 71 quotes it.

Nothing outside the migrations read these. `models.py`, `schemas.py`, and
`ACTION_LIST_COLUMNS` lose the same eight fields, `Adventure.actions` orders
by `id`, and `attempts.renumber`, `context.history.max_action_index`, and
`nodes.next_index` are deleted.

Two changes keep the migration replayable on a `create_all` database:

- `_split_variants_into_siblings` wrote through the live ORM table, so it
  stopped compiling once migration 66 removed five of its columns. It now
  writes through `_ACTIONS_AT_60`, a frozen `Table` with its own `MetaData`.
- Five data passes read columns these migrations drop. Each now calls
  `_has_columns` and returns early when the columns are absent.

`bootstrap` takes a `through` version so a migration test can stop at the
schema it asserts on.

555 tests pass, up from 549. Eight of the new cases assert each column is
gone after a real schema-45 database migrates all the way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0198qDK3gmgSo7EtQ4GTPqqK
This commit is contained in:
parththakkar106
2026-08-29 17:15:49 +05:30
committed by Parth
co-authored by Claude Opus 5
parent e0bf2b61d9
commit f1bebe18d0
41 changed files with 477 additions and 378 deletions
+8 -11
View File
@@ -68,7 +68,7 @@ def make_adventure(db, action_count: int) -> models.Adventure:
db.flush()
for i in range(action_count):
db.add(models.Action(
adventure_id=adventure.id, index=i,
adventure_id=adventure.id,
type="ai" if i % 2 else "do", text=f"Action {i}.",
))
db.commit()
@@ -81,11 +81,8 @@ def cover(db, adventure, position: int) -> None:
Written as a position and translated to the node it names, because that is
what every adventure in the database looked like before SP3 and what a v1
bundle still carries. `memory_cursor` keeps the old number so the two
coordinate systems can be compared where a test cares.
bundle still carries.
"""
adventure.memory_cursor = position
adventure.summary_cursor = position
cursors.anchor_at_position(adventure, cursors.MEMORY, position)
cursors.anchor_at_position(adventure, cursors.SUMMARY, position)
db.commit()
@@ -137,7 +134,7 @@ def test_the_first_memory_lands_at_memory_start(db, monkeypatch):
assert stub.excerpts == [] # too short to have started at all
db.add(models.Action(
adventure_id=adventure.id, index=memorybank.MEMORY_START - 1,
adventure_id=adventure.id,
type="do", text="Later.",
))
db.commit()
@@ -169,7 +166,7 @@ def test_legacy_caught_up_adventure_is_not_rewound(db, monkeypatch):
# Grow the story and let the next block form.
for i in range(12, 25):
db.add(models.Action(adventure_id=adventure.id, index=i, type="do", text=f"Action {i}."))
db.add(models.Action(adventure_id=adventure.id, type="do", text=f"Action {i}."))
db.commit()
db.refresh(adventure)
run_memories(db, adventure, StubSummarizer(), monkeypatch)
@@ -213,7 +210,7 @@ def summarized_adventure(db):
adventure = make_adventure(db, 13)
for text, start, end in (("A", 0, 5), ("B", 6, 11)):
node = db.query(models.Action).filter_by(
adventure_id=adventure.id, index=end
adventure_id=adventure.id, depth=end
).one()
memory = models.Memory(
adventure_id=adventure.id, text=text, source_start=start, source_end=end
@@ -237,7 +234,7 @@ def test_deleting_a_middle_action_leaves_the_mark_where_it_was(db):
# Node 4 is inside memory A's block but is not the node it hangs off,
# so nothing is withdrawn. The old code read it the same way: only a
# memory whose end had fallen off the story was pruned.
victim = db.query(models.Action).filter_by(adventure_id=adventure.id, index=4).one()
victim = db.query(models.Action).filter_by(adventure_id=adventure.id, depth=4).one()
assert memorybank.forget_node(db, adventure, victim) == 0
db.delete(victim)
@@ -251,7 +248,7 @@ def test_deleting_a_middle_action_leaves_the_mark_where_it_was(db):
def test_deleting_a_later_action_leaves_the_mark_alone(db):
adventure = summarized_adventure(db)
victim = db.query(models.Action).filter_by(adventure_id=adventure.id, index=12).one()
victim = db.query(models.Action).filter_by(adventure_id=adventure.id, depth=12).one()
memorybank.forget_node(db, adventure, victim)
db.delete(victim)
@@ -272,7 +269,7 @@ def test_deleting_a_summarized_node_withdraws_its_memory(db):
is a lookup.
"""
adventure = summarized_adventure(db)
victim = db.query(models.Action).filter_by(adventure_id=adventure.id, index=11).one()
victim = db.query(models.Action).filter_by(adventure_id=adventure.id, depth=11).one()
assert memorybank.forget_node(db, adventure, victim) == 1
db.delete(victim)