Let a branch be named, and thrown away
SP7 needs three branch operations and SP5 built one. Switching exists; naming and deleting had no column and no route between them. A name is stored because a player chose it. An unnamed branch keeps NULL rather than a generated "branch 4" — a generated label is derived, and it would go stale the moment a branch before it is deleted and the ordinals shift underneath. The client draws those from the fork depth, which nothing can shift. The v2 bundle carries the name for the same reason it carries the fork points and leaves `lineage` out: it is a decision, not something computed from one. Delete is what stands between a tree and unbounded growth, since nothing prunes one on its own. It refuses two branches: the root, which holds the turns every other branch borrows, and the one being read — including any branch the head was forked from, which is the same mistake in disguise and the one that would cascade the head away and leave head_branch_id pointing at nothing. The nodes, memories and descendants go through the foreign keys that already cascade. A cursor standing on a deleted branch is cleared. On Postgres a stale branch id would simply never resolve; SQLite hands the freed id to the next fork, and then the anchor resolves onto a branch it has never seen and calls a stretch of story already summarized. 396 tests, 15 new. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015H5qiyiR7gtFQaoDphHZ3g
This commit is contained in:
committed by
Parth
co-authored by
Claude Opus 5
parent
a7bf47a35e
commit
cf3d52171e
@@ -211,6 +211,13 @@ class Branch(Base):
|
||||
# beneath it, inclusive. Computed once at fork from the parent's lineage
|
||||
# plus one entry, so no read ever reconstructs it.
|
||||
lineage: Mapped[list] = mapped_column(JSON, default=list)
|
||||
# What the player called this line of the story, or NULL for one nobody has
|
||||
# named. NULL rather than a generated "branch 4", because a generated name
|
||||
# is derived and this column is for what was chosen — the same rule the v2
|
||||
# bundle is built on. A stored default would also become a lie the moment a
|
||||
# branch before it is deleted and the ordinals shift under it; an unnamed
|
||||
# branch is drawn from its fork depth instead, which nothing can shift.
|
||||
name: Mapped[str | None] = mapped_column(String(80), nullable=True)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, default=utcnow)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user