docs(6206): settings, projects, api routes and three models drop citations; four capitalised services stragglers
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m7s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 24s

- api.py's build-version docstring states why a channel name is not a build
  id, without the dated incident.
- rule_version states why rules need a history, without the rule that was
  rescoped and the date.
- Capitalised "Rule N" / "Milestone N" citations the earlier lowercase grep
  missed, in reply_shapes, supersession, services/family and models/family.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:42:41 -04:00
co-authored by Claude Opus 5.5
parent 78e1bdbd93
commit 0c88e1b0b0
9 changed files with 44 additions and 51 deletions
+6 -7
View File
@@ -1,4 +1,4 @@
"""Family canon (milestone 463): ideas that every project on a platform shares,
"""Family canon: ideas that every project on a platform shares,
and each project's recorded answer to them.
A FAMILY IDEA is not a new kind of record. It is an existing `notes` row — a
@@ -45,7 +45,7 @@ from scribe.models import Base
from scribe.models.base import CreatedAtMixin, SoftDeleteMixin, TimestampMixin, iso
# Each tuple is the whitelist its CHECK constraint enforces (migration 0120).
# Rule 36: a new value means DROP + ADD CONSTRAINT in the same migration.
# A new value means DROP + ADD CONSTRAINT in the same migration.
MEMBERSHIP_STATES = ("declared", "detected", "rejected")
IDEA_STATUSES = ("candidate", "canon", "retired")
ADOPTION_STATUSES = ("unassessed", "adopted", "variant", "exempt", "owed")
@@ -73,7 +73,7 @@ class Platform(Base, TimestampMixin, SoftDeleteMixin):
form a backup carries, since ids are per-install.
`markers` are glob patterns over a bound repo's paths that suggest a
project is this platform (step 2's detection). A pattern without a slash
project is this platform (platform detection). A pattern without a slash
matches a file's basename anywhere in the tree; one with a slash matches
the repo-relative path. Empty means declare-only: some platforms leave no
reliable file behind.
@@ -166,7 +166,7 @@ class FamilyIdea(Base, TimestampMixin):
comparing the two numbers, never stored as a flag that could go stale.
`topic_id` is the rule topic holding the idea's binding norms, if it has
any (the note↔topic link #3236 asked for), set by `set_topic`. The topic
any, set by `set_topic`. The topic
never carries platforms of its own; the idea's readouts list its rules,
so an assessment judges a project against them.
"""
@@ -308,8 +308,7 @@ class FamilyDecision(Base, CreatedAtMixin):
`before` and `after` are STATE snapshots — status, version, reason — and
deliberately hold no foreign ids: an id inside JSON cannot be remapped by a
restore, and would come back pointing at whatever took that number (the
#3182 trap). The ids this row needs are columns.
restore, and would come back pointing at whatever took that number. The ids this row needs are columns.
`precedent_ids` are the earlier decisions this one followed. They are what
keeps a call consistent with the last similar one when no person approves
@@ -367,7 +366,7 @@ class FamilyDecision(Base, CreatedAtMixin):
stored again inside `after` (and the prior one inside `before`), and
a promotion's evidence carries the whole criteria reasoning. So a
state here is its status, version and platforms only, and evidence is
the cited list alone (#5131). The full row is `to_dict`, which the
the cited list alone. The full row is `to_dict`, which the
decision log serves.
"""
return {
+5 -5
View File
@@ -10,12 +10,12 @@ from scribe.models.base import CreatedAtMixin, iso
SUGGESTED = "suggested"
CONFIRMED = "confirmed"
REJECTED = "rejected"
# CHECK ck_lesson_rule_links_state (migration 0111, rule 36).
# CHECK ck_lesson_rule_links_state (migration 0111).
LINK_STATES = (SUGGESTED, CONFIRMED, REJECTED)
class LessonRuleLink(Base, CreatedAtMixin):
"""A lesson says it is an instance of a rule (milestone 440, #4196).
"""A lesson says it is an instance of a rule.
A lesson records one concrete situation; a rule records the binding choice
for a class of them. The link lets the rule be reached through the
@@ -53,7 +53,7 @@ class LessonRuleLink(Base, CreatedAtMixin):
# Why it was confirmed or rejected — the reasoning a later reader needs to
# decide whether it still holds, as a rule relation's `note` is.
note: Mapped[str | None] = mapped_column(Text, nullable=True)
# What the suggestion rests on (filled by the co-surfacing recorder, #4637).
# What the suggestion rests on (filled by the co-surfacing recorder).
# Kept after a judgment so a confirmation can be read beside its evidence.
evidence: Mapped[dict | None] = mapped_column(JSONB, nullable=True)
# When a judgment moved it out of `suggested`. Null while suggested.
@@ -78,12 +78,12 @@ class LessonRuleLink(Base, CreatedAtMixin):
class LessonNoRule(Base):
"""A judgment that no rule governs a lesson's situation (#4631).
"""A judgment that no rule governs a lesson's situation.
The third answer to "which rule is this an instance of?", beside naming
one and leaving it open. It is what lets an UNJUDGED lesson be told apart
from one that was looked at and found to stand alone — and a lesson with
no rule is the raw material #4634 reads for convergence, so the
no rule is the raw material convergence reads, so the
difference is the whole signal.
A row of its own rather than a key in the lesson's `data`: that column is
+5 -8
View File
@@ -10,18 +10,15 @@ from scribe.models.base import CreatedAtMixin, iso
class RuleVersion(Base, CreatedAtMixin):
"""One snapshot of a rule's text, taken before an edit overwrote it.
THE SIBLING NOTES ALREADY HAD. `note_versions` has existed for a long
time, and the design-system note calls its history "the changelog". Rules
— which BIND BEHAVIOUR on every session that loads them — had nothing, so
an edit destroyed what the rule used to say. Rescoping rule 79 on
2026-08-29 meant hand-copying the superseded statement into a task log to
keep it (#3237). The more consequential record had the weaker protection.
THE SIBLING OF `note_versions`. Rules BIND BEHAVIOUR on every session that
loads them; without a history, an edit destroys what the rule used to say,
and the more consequential record has the weaker protection.
`CreatedAtMixin`, not `TimestampMixin`: a version is an EVENT. It is
written once and never updated, so an `updated_at` on it would be a column
that can only ever lie.
WHAT IS DELIBERATELY DIFFERENT FROM NoteVersion (milestone 323):
WHAT IS DELIBERATELY DIFFERENT FROM NoteVersion:
- `user_id` is the ACTOR — who made the edit — where NoteVersion's is the
owner, because `update_note` passes an owner-scoped id. For an audit
@@ -34,7 +31,7 @@ class RuleVersion(Base, CreatedAtMixin):
own lifecycle; folding them in would make one word, "version", mean two
different things — the rule's wording, and the rule's place in the
graph. `verified_at` is likewise absent: it is a stamp about a check,
not a property of the text, and step 2's snapshot is taken before
not a property of the text, and the snapshot is taken before
update_rule clears it precisely so the history shows the check that was
in force when this wording was written.
"""