Make the branch happen when you write, not when you look

Stepping between takes used to be two controls and two meanings. At the tip a
chip switched; above the tip it only *previewed*, and taking that line needed a
second button next to it. Which one you got depended on where you were standing,
which is the thing that made the tree unusable when it was driven by hand.

So the server stops caring that anyone is looking. Reading a take the story
moved past changes nothing and creates nothing. `ActionCreate.after_id` names
the node a turn is played after, and naming a take the story left is the first
moment the player has said which line they mean -- so that is where the fork
happens, and only there.

`stand_on` is the old fork endpoint's body, lifted out whole. It already knew
the two cases and got them right: at the tip the takes are leaves nobody built
on, so it is a switch and no branch is made; past the tip the line being left
keeps every turn it has, so the take needs a branch. Both callers now share it,
which is the point -- a fork asked for and a fork arrived at are the same move.

Six tests. Five fail with the grouping reverted to the coordinate, and the one
that does not is deliberate: naming the tip in `after_id` must stay an ordinary
turn that forks nothing, which guards against over-correcting rather than
against the original bug. The nesting test passes both ways too and is kept for
what it says, not for what it catches -- a coordinate separates C1's takes from
C2's by accident, because the fork has already put them on different branches.

415 tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Dvvqn9ZDR4ixeFPHNbww7
This commit is contained in:
parththakkar106
2026-08-18 21:34:12 +05:30
committed by Parth
co-authored by Claude Opus 5
parent 6fa213f6db
commit e126bda387
3 changed files with 331 additions and 17 deletions
+8
View File
@@ -244,6 +244,14 @@ class ActionUpdate(BaseModel):
class ActionCreate(BaseModel):
type: Literal["do", "say", "story", "continue"]
text: ActionText = ""
# The node this action is played after (SP9). Omitted means "the tip",
# which is every ordinary turn.
#
# Naming a take the story moved past is how a branch gets made: stepping
# between takes costs nothing and creates nothing, and the fork happens on
# the first thing written below one. That is the only moment the player has
# said which line they mean — before it, they were reading.
after_id: int | None = None
class AdventureOut(ORMModel):