Rewrite Python comments in Google developer documentation style (#12)

* Rewrite comments in Google developer documentation style

Rewrite the comments and docstrings across the backend core modules so they
read plainly. The previous prose was accurate but dense and figurative, which
made it slow to skim.

Applies the Google developer documentation style guide: short sentences, active
voice, present tense, American spelling, and no metaphors, idioms, or
rhetorical asides. Replaces em-dash chains with separate sentences.
This commit is contained in:
Parth
2026-08-26 15:37:25 +05:30
committed by GitHub
parent cf6161a5ee
commit e7d75c3b05
83 changed files with 4605 additions and 3988 deletions
+73 -69
View File
@@ -1,31 +1,32 @@
"""Phase 14 — how far along a story the derived work has got.
"""Phase 14: tracks how far along a story the derived work has reached.
Two things are built from the story and stored beside it: the memories, and the
Story Summary. Both need to know where they left off, and that mark used to be
a *count* — "the first 12 story actions are covered". A count is a position in
a list, and this list moves: delete an action from in front of the mark and
every later action slides down a slot, so the mark now covers one it has never
seen. Every rule in `memorybank` about sliding cursors, rewinding them and
translating between positions and `Action.index` existed to patch that up, and
each was a separate chance to get it wrong in a way nothing reports.
Two things are built from the story and stored beside it: the memories and the
story summary. Both need to record where they stopped.
A cursor here is an **anchor**: `(branch_id, depth)`, the node up to and
including which the work is done. Deleting an action does not move it, because
a depth is not a position — it is a coordinate along a path. "What is not
covered yet" becomes `history.count_after(anchor)`, which is a question about
the story rather than about a list index, and it answers correctly whatever has
been deleted from in front of it.
That mark used to be a count, such as "the first 12 story actions are covered".
A count is a position in a list, and this list changes. If you delete an action
in front of the mark, every later action moves down one slot, so the mark now
covers an action it never read. The rules in `memorybank` for sliding cursors,
rewinding them, and converting between positions and `Action.index` all existed
to correct for that, and each rule was a chance to introduce a silent error.
The branch half is what makes it survive forking. A depth alone is ambiguous
once two branches have a node 41; the anchor says which one, and
`Path.depth_on` reads it back as a depth on whatever story is being played —
capped at the fork, or "nothing covered" if the anchor sits on ground this path
never travelled. Until forking ships there is one branch and that is always a
no-op, which is the point: the coordinate system is right before anything needs
it to be.
A cursor here is an anchor instead. It stores `(branch_id, depth)`, naming the
node up to and including which the work is done. Deleting an action does not
move it, because a depth is a coordinate along a path rather than a position in
a list. The question "what is not covered yet" becomes
`history.count_after(anchor)`, which asks about the story rather than about a
list index, and it stays correct no matter what is deleted in front of it.
`NO_DEPTH` (-1) is "nothing covered", so a fresh adventure needs no special
case: every node is deeper than -1.
The branch half of the anchor is what makes it survive forking. A depth alone is
ambiguous once two branches both hold a node at depth 41. The anchor names the
branch, and `Path.depth_on` reads it back as a depth on whichever story is being
played. That read caps the depth at the fork, or reports nothing covered if the
anchor sits on a branch this path does not contain. Until forking ships there is
one branch, so this always returns the stored depth. That is the point: the
coordinate system is correct before anything depends on it.
`NO_DEPTH`, which is -1, means nothing is covered. A new adventure therefore
needs no special case, because every node is deeper than -1.
"""
from sqlalchemy.orm import Session
@@ -37,12 +38,11 @@ NO_DEPTH = lineage.NO_DEPTH
class Cursor:
"""One anchor on the adventure row: the memory bank's, or the summary's.
"""One anchor on the adventure row, for either the memory bank or the summary.
A pair of columns rather than a foreign key to the node. The node can be
deleted — that is most of what undo does — and the boundary is still
meaningful afterwards, so a pointer that has to resolve would be a pointer
that keeps not resolving.
The anchor is a pair of columns rather than a foreign key to the node. The
node can be deleted, which is what undo does, and the boundary still means
something afterwards. A foreign key would repeatedly fail to resolve.
"""
def __init__(self, name: str):
@@ -53,14 +53,14 @@ class Cursor:
# ------------------------------------------------------------- reading
def stored(self, adventure: models.Adventure) -> tuple[int | None, int]:
"""The anchor exactly as written, unread by any path."""
"""Returns the anchor as written, without resolving it against a path."""
depth = getattr(adventure, self.depth_field)
return getattr(adventure, self.branch_field), (
NO_DEPTH if depth is None else depth
)
def depth(self, db: Session, adventure: models.Adventure) -> int:
"""The anchor as a depth on the story currently being played."""
"""Returns the anchor as a depth on the story being played now."""
branch_id, depth = self.stored(adventure)
return lineage.path_of(db, adventure).depth_on(branch_id, depth)
@@ -69,44 +69,47 @@ class Cursor:
def anchor(
self, adventure: models.Adventure, branch_id: int | None, depth: int
) -> None:
"""Put the anchor at a coordinate given outright.
"""Sets the anchor to a coordinate supplied directly.
The plain setter under `anchor_at`. Only an import has a coordinate
without a node to read it off — a v2 bundle carries the anchor itself
(`app/bundle.py`), and the node it named lives in another database.
This is the plain setter beneath `anchor_at`. Only an import supplies a
coordinate with no node to read it from. A v2 bundle carries the anchor
itself, as described in `app/bundle.py`, and the node it named lives in
a different database.
"""
setattr(adventure, self.branch_field, branch_id)
setattr(adventure, self.depth_field, max(depth, NO_DEPTH))
def anchor_at(self, adventure: models.Adventure, node: models.Action) -> None:
"""Mark the work done up to and including `node`.
"""Marks the work done up to and including `node`.
Takes the node's own branch, not the adventure's head: a block of six
actions can end before the fork this branch was made at, and the
coverage belongs where the ground is.
This uses the node's own branch rather than the adventure's head. A block
of six actions can end before the fork that created the current branch,
and the coverage belongs where those actions are.
"""
self.anchor(adventure, node.branch_id, lineage.NO_DEPTH
if node.depth is None else node.depth)
def clear(self, adventure: models.Adventure) -> None:
"""Forget the anchor entirely: nothing is covered.
"""Clears the anchor, so that nothing counts as covered.
For when the ground the anchor stood on is gone — a deleted branch. On
Postgres a stale branch id would simply never resolve, but SQLite hands
a freed id to the next fork, and an anchor that resolves onto a branch
it has never seen would report a stretch of story as already
summarized. Clearing costs a re-summarize, which is the safe direction.
Call this when the branch the anchor referred to is deleted. On Postgres
a stale branch id would never resolve. On SQLite the next fork can reuse
an id that was just freed, and a stale anchor would then resolve onto a
branch it never saw and report that stretch of story as summarized.
Clearing the anchor costs one re-summarize, which is the safe direction
to be wrong in.
"""
self.anchor(adventure, None, NO_DEPTH)
def rewind_to(
self, adventure: models.Adventure, branch_id: int | None, depth: int
) -> None:
"""Move the anchor back to `depth` if it is past it; never forward.
"""Moves the anchor back to `depth` if it is past that depth.
The one direction that is safe without knowing what else has happened:
re-covering ground costs a summarizer call, skipping it loses a stretch
of story out of the memories for good.
The anchor never moves forward here. Moving backward is the only
direction that is safe without knowing what else changed. Covering
ground twice costs one summarizer call. Skipping ground removes a
stretch of story from the memories permanently.
"""
_, current = self.stored(adventure)
if current <= depth:
@@ -123,12 +126,12 @@ ALL = (MEMORY, SUMMARY)
def rewind_all(
adventure: models.Adventure, branch_id: int | None, depth: int
) -> None:
"""Hand a stretch of story back to *both* passes.
"""Returns a stretch of story to both the memory pass and the summary pass.
They move together because they cover the same ground from different sides:
the summary folds in the memories, so a memory withdrawn without rewinding
the summary leaves the summary claiming to have read something no longer
there.
The two move together because they cover the same actions from different
directions. The summary folds in the memories, so withdrawing a memory
without rewinding the summary would leave the summary claiming to have read
something that no longer exists.
"""
for cursor in ALL:
cursor.rewind_to(adventure, branch_id, depth)
@@ -137,18 +140,19 @@ def rewind_all(
def anchor_at_position(
adventure: models.Adventure, cursor: Cursor, position: int
) -> None:
"""Set `cursor` from a count of covered story actions — a v1 bundle's mark,
or a database written before the anchors existed.
"""Sets `cursor` from a count of covered story actions.
The position-th story action in depth order is the node that says the same
thing, and goes on saying it once something in front of it is deleted. A
position past the end of the story is not a bad value: an adventure caught
up under the older rule can carry one, and it means the same thing the tip
does, so that is where it lands.
A v1 bundle stores its mark as a count, and so does a database written
before the anchors existed.
The SQL half of this rule is `migrations._backfill_cursor_anchors`, which
has to do it for every adventure at once without loading any of them; the
two must agree.
The action at `position` in depth order is the node that carries the same
meaning, and it keeps that meaning after something in front of it is
deleted. A position past the end of the story is not an invalid value. An
adventure that was fully caught up under the old rule can hold one, and it
means the same thing as the tip, so this function anchors at the tip.
`migrations._backfill_cursor_anchors` implements this rule in SQL for every
adventure at once, without loading any of them. The two must agree.
"""
if position <= 0:
return
@@ -158,11 +162,11 @@ def anchor_at_position(
def position_of(adventure: models.Adventure, depth: int) -> int:
"""How many story actions lie at or before `depth` — an anchor read back as
a count.
"""Returns how many story actions lie at or before `depth`.
The v1 export bundle stores the cursors as positions, and a v1 bundle is
read by builds that have never heard of a depth. This is the one place that
still speaks that coordinate system, and SP6's v2 format retires it.
This reads an anchor back as a count. The v1 export bundle stores cursors as
counts, and builds that have never used depths read v1 bundles. This
function is the only remaining code that speaks that coordinate system. The
v2 format introduced in SP6 replaces it.
"""
return max(history.count(adventure) - history.count_after(adventure, depth), 0)