Give the stress fixture back its sibling attempts
`place_action` used to read `depth` from `index`, so the fixture's retry attempts all landed on the turn's own depth and formed one sibling group. Now that depth comes from the head, each attempt moved the head one step and every retry became a turn of its own. The fixture's own check caught it: a coordinate holding a single superseded attempt has no live row, and that turn disappears from the story. The attempts at one turn share that turn's coordinate, so only the first one goes through `place_action` and the rest copy its placement. This is what `attempts.add_attempt` does. The fixture cannot call it directly, because it makes the newest attempt live and the fixture needs a live attempt that is often not the newest. Also drop the `variant_index` and `variant_count` arguments, which raise `TypeError` now, and read the two mark positions from a helper instead of from the adventure columns migrations 72 and 73 removed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YFQY6WgaE3JaX3dXkxLynV
This commit is contained in:
co-authored by
Claude Opus 5
parent
949f58a054
commit
6a5d8e98f9
@@ -340,6 +340,16 @@ def rich_attempts(rng: random.Random, index: int) -> tuple[list[str], int]:
|
|||||||
return texts, (0 if index % 18 == 1 else count - 1)
|
return texts, (0 if index % 18 == 1 else count - 1)
|
||||||
|
|
||||||
|
|
||||||
|
def rich_cursor_positions(action_count: int) -> tuple[int, int]:
|
||||||
|
"""Return the memory and summary mark positions for the rich fixture.
|
||||||
|
|
||||||
|
The marks start out as positions because that is the form a pre-SP3
|
||||||
|
database holds. `build_fixture` turns them into anchors once the actions
|
||||||
|
they point at exist.
|
||||||
|
"""
|
||||||
|
return max(0, action_count - 8), max(0, action_count - 20)
|
||||||
|
|
||||||
|
|
||||||
def add_rich_extras(db, args, rng: random.Random, user, adventure) -> None:
|
def add_rich_extras(db, args, rng: random.Random, user, adventure) -> None:
|
||||||
"""Adds everything `--rich` contributes apart from the actions themselves.
|
"""Adds everything `--rich` contributes apart from the actions themselves.
|
||||||
|
|
||||||
@@ -360,14 +370,10 @@ def add_rich_extras(db, args, rng: random.Random, user, adventure) -> None:
|
|||||||
adventure.world_state = rich_world_state(schema, args.actions)
|
adventure.world_state = rich_world_state(schema, args.actions)
|
||||||
adventure.script_state = rich_script_state(args.actions)
|
adventure.script_state = rich_script_state(args.actions)
|
||||||
# The post-turn passes do nothing unless summarization is on and the marks
|
# The post-turn passes do nothing unless summarization is on and the marks
|
||||||
# are past the start. They are written here as positions and translated into
|
# are past the start. `build_fixture` translates the marks into anchors
|
||||||
# anchors once the actions exist. See `build_fixture`. A database being
|
# once the actions exist. See `rich_cursor_positions`.
|
||||||
# migrated to SP3 still holds positions, so the fixture carries both forms
|
|
||||||
# and the two have to agree.
|
|
||||||
adventure.auto_summarize = True
|
adventure.auto_summarize = True
|
||||||
adventure.story_summary = RICH_SUMMARY
|
adventure.story_summary = RICH_SUMMARY
|
||||||
adventure.memory_cursor = max(0, args.actions - 8)
|
|
||||||
adventure.summary_cursor = max(0, args.actions - 20)
|
|
||||||
|
|
||||||
for kind, name, keys, entry in RICH_CARDS:
|
for kind, name, keys, entry in RICH_CARDS:
|
||||||
db.add(models.StoryCard(
|
db.add(models.StoryCard(
|
||||||
@@ -504,6 +510,14 @@ def build_fixture(args, rng: random.Random) -> tuple[int, int]:
|
|||||||
NARRATION if is_ai else PLAYER_INPUT
|
NARRATION if is_ai else PLAYER_INPUT
|
||||||
]
|
]
|
||||||
live = 0
|
live = 0
|
||||||
|
# The attempts at one turn share that turn's coordinate. Only the
|
||||||
|
# first one moves the head, so the rest copy the placement of the
|
||||||
|
# first instead of going through `tree.place_action`, which would
|
||||||
|
# read each of them as a new turn. This mirrors
|
||||||
|
# `attempts.add_attempt`, which the fixture cannot call directly
|
||||||
|
# because it makes the newest attempt live and the fixture needs a
|
||||||
|
# live attempt that is often not the newest.
|
||||||
|
first_attempt = None
|
||||||
for n, body in enumerate(texts):
|
for n, body in enumerate(texts):
|
||||||
action = models.Action(
|
action = models.Action(
|
||||||
adventure_id=adventure.id,
|
adventure_id=adventure.id,
|
||||||
@@ -524,8 +538,6 @@ def build_fixture(args, rng: random.Random) -> tuple[int, int]:
|
|||||||
# Every third AI turn was retried once, so a turn is
|
# Every third AI turn was retried once, so a turn is
|
||||||
# sometimes several rows sharing one coordinate.
|
# sometimes several rows sharing one coordinate.
|
||||||
live=(n == live),
|
live=(n == live),
|
||||||
variant_index=n,
|
|
||||||
variant_count=len(texts) if len(texts) > 1 else 0,
|
|
||||||
# Under `--rich` the value increases with the turn, so an
|
# Under `--rich` the value increases with the turn, so an
|
||||||
# incorrect rollback shows a wrong number rather than no
|
# incorrect rollback shows a wrong number rather than no
|
||||||
# value. Otherwise `tree.stamp_outcome` writes the
|
# value. Otherwise `tree.stamp_outcome` writes the
|
||||||
@@ -541,7 +553,13 @@ def build_fixture(args, rng: random.Random) -> tuple[int, int]:
|
|||||||
# sees it. The fixture has to stamp its own nodes, or it would
|
# sees it. The fixture has to stamp its own nodes, or it would
|
||||||
# be the one database in the project whose actions have no
|
# be the one database in the project whose actions have no
|
||||||
# branch.
|
# branch.
|
||||||
tree.place_action(db, adventure, action)
|
if first_attempt is None:
|
||||||
|
tree.place_action(db, adventure, action)
|
||||||
|
first_attempt = action
|
||||||
|
else:
|
||||||
|
action.branch_id = first_attempt.branch_id
|
||||||
|
action.depth = first_attempt.depth
|
||||||
|
action.parent_id = first_attempt.parent_id
|
||||||
db.add(action)
|
db.add(action)
|
||||||
|
|
||||||
for i in range(args.memories):
|
for i in range(args.memories):
|
||||||
@@ -572,8 +590,9 @@ def build_fixture(args, rng: random.Random) -> tuple[int, int]:
|
|||||||
# fixture stamped LATEST never runs a migration, so skipping this
|
# fixture stamped LATEST never runs a migration, so skipping this
|
||||||
# would leave the one database whose marks are only positions.
|
# would leave the one database whose marks are only positions.
|
||||||
db.flush()
|
db.flush()
|
||||||
cursors.anchor_at_position(adventure, cursors.MEMORY, adventure.memory_cursor)
|
memory_position, summary_position = rich_cursor_positions(args.actions)
|
||||||
cursors.anchor_at_position(adventure, cursors.SUMMARY, adventure.summary_cursor)
|
cursors.anchor_at_position(adventure, cursors.MEMORY, memory_position)
|
||||||
|
cursors.anchor_at_position(adventure, cursors.SUMMARY, summary_position)
|
||||||
add_second_adventure(db, rng, user)
|
add_second_adventure(db, rng, user)
|
||||||
_assert_live_variant_invariant(db, adventure.id)
|
_assert_live_variant_invariant(db, adventure.id)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user