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:
committed by
Parth
co-authored by
Claude Opus 5
parent
e0bf2b61d9
commit
f1bebe18d0
+9
-27
@@ -14,8 +14,8 @@ Version 2 carries the tree. It holds three things version 1 could not, and each
|
||||
one is required:
|
||||
|
||||
* The branches, because a forked adventure is two stories and a flat list holds
|
||||
one. A version 1 export interleaved them by `index`, which read as a garbled
|
||||
story rather than as lost data.
|
||||
one. A version 1 export interleaved them by turn number, which read as a
|
||||
garbled story rather than as lost data.
|
||||
* `live`, because a coordinate can hold several attempts at one turn and exactly
|
||||
one of them is the story.
|
||||
* Both after-snapshots, because they are what a branch switch and an undo
|
||||
@@ -26,22 +26,14 @@ one is required:
|
||||
|
||||
A bundle carries what was chosen, never what is derived. The head branch, the
|
||||
fork points, the live flags, and the anchors are decisions somebody made, so
|
||||
they are in the file. `lineage`, the head depth, `index`, and the variant
|
||||
ordinals are all computed from those, and the import recomputes them:
|
||||
they are in the file. `lineage` and the head depth are computed from those, and
|
||||
the import recomputes them:
|
||||
|
||||
* `lineage` is a cache of `parent` plus `fork_depth`. Shipping it as well would
|
||||
put a second source of truth for one fact into a file anyone can hand-edit,
|
||||
and the two could then disagree without any read reporting it.
|
||||
* The head depth is the tip of the head branch, which is a fact about the nodes
|
||||
that arrived with it.
|
||||
* `index` is the legacy column SP8 drops. Its one remaining job is to give the
|
||||
next row a number nothing else holds, which is a fact about the adventure
|
||||
rather than about a path, so `depth` cannot serve: two branches each have a
|
||||
node at depth 4. The import allocates one index per turn instead, which keeps
|
||||
`max_action_index` correct and keeps siblings sharing an index the way SP4
|
||||
leaves them.
|
||||
* `attempts.renumber` maintains the variant ordinals, and it is the only place
|
||||
allowed to.
|
||||
|
||||
Every hand-editable coordinate is therefore checked before a row is written, in
|
||||
`plan`, rather than repaired afterwards. An import that fails partway leaves an
|
||||
@@ -98,8 +90,7 @@ def export(db: Session, adventure: models.Adventure) -> dict:
|
||||
undefer(models.Action.world_state_after),
|
||||
)
|
||||
.order_by(
|
||||
models.Action.branch_id, models.Action.depth,
|
||||
models.Action.variant_index, models.Action.id,
|
||||
models.Action.branch_id, models.Action.depth, models.Action.id,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
@@ -168,8 +159,7 @@ def _exported_branch(branch: models.Branch, local: dict[int, int]) -> dict:
|
||||
def _exported_node(action: models.Action, local: dict[int, int]) -> dict:
|
||||
node = {
|
||||
"branch": _local(action.branch_id, local),
|
||||
# A pre-tree row's depth is the number `index` already holds.
|
||||
"depth": action.depth if action.depth is not None else action.index,
|
||||
"depth": action.depth,
|
||||
"live": bool(action.live),
|
||||
"type": action.type,
|
||||
"text": action.text,
|
||||
@@ -496,24 +486,17 @@ def _write_nodes(
|
||||
) -> None:
|
||||
"""Writes the nodes, grouped into the turns they are attempts at.
|
||||
|
||||
Two values are allocated here rather than read from the file. `index` is
|
||||
issued once per turn, in the order the bundle lists them, so siblings share
|
||||
one index and no two coordinates do. `max_action_index` needs that to keep
|
||||
issuing numbers nothing holds. Exactly one attempt in each group is also made
|
||||
live, because a file can name none or several, and a turn with no live node
|
||||
disappears from the story.
|
||||
One value is decided here rather than read from the file. Exactly one
|
||||
attempt in each group is made live, because a file can name none or several,
|
||||
and a turn with no live node disappears from the story.
|
||||
"""
|
||||
groups: dict[tuple[int, int], list[models.Action]] = {}
|
||||
indices: dict[tuple[int, int], int] = {}
|
||||
for spec in specs:
|
||||
key = (spec["branch"], spec["depth"])
|
||||
if key not in indices:
|
||||
indices[key] = len(indices)
|
||||
action = models.Action(
|
||||
adventure_id=adventure.id,
|
||||
branch_id=ids[spec["branch"]],
|
||||
depth=spec["depth"],
|
||||
index=indices[key],
|
||||
type=spec["type"],
|
||||
text=spec["text"],
|
||||
reasoning=spec["reasoning"],
|
||||
@@ -531,7 +514,6 @@ def _write_nodes(
|
||||
live = next((row for row in rows if row.live), rows[0])
|
||||
for row in rows:
|
||||
row.live = row is live
|
||||
attempts.renumber(rows)
|
||||
|
||||
|
||||
def _write_memories(
|
||||
|
||||
Reference in New Issue
Block a user