Let any turn be played again, not just the newest

`retry` only ever saw the last action: mid-story there was no way to ask for
another take at all. Now the take endpoint takes either kind of node, and the
kind decides what happens -- an AI turn regenerates, a player turn takes the
text supplied. The client asks the same way for both.

The tip is the only case that needs no branch, and only for an AI turn, where
the takes are still leaves nobody has built on. That is the existing retry,
reached by another road. Everywhere else `branch_at` leaves the path just
before the turn so the story after it keeps the take it was written for.

Both paths roll the shared state back to before the turn ran, which the fork
endpoint was already doing and the player-take path was not -- a script would
otherwise have stacked this take's output mutations on the one being replaced.

426 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 c3c9b310eb
commit ea7336e5d3
3 changed files with 88 additions and 33 deletions
+8 -2
View File
@@ -266,9 +266,15 @@ class ActionCreate(BaseModel):
class TakeCreate(BaseModel):
"""Another take of a turn the player wrote themselves (SP9)."""
"""Another take of a turn (SP9).
text: ActionText
`text` is what the player is saying instead, and is theirs to write only
when the turn was theirs. An AI turn's other take is generated, so the field
is ignored there rather than refused — the client asks the same way for both
and the node type decides what happens.
"""
text: ActionText = ""
class AdventureOut(ORMModel):