docs(6206): rulebook model comments state the design, not the history of the rulebook

The relation kinds say what each prevents without the rule-46 split story;
the removed tier, subscriptions and suppressions are stated as what the
model does not have, with the migration that dropped them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 20:38:01 -04:00
co-authored by Claude Opus 5.5
parent a01f5492bc
commit cad74df190
+23 -30
View File
@@ -92,15 +92,13 @@ class Rule(Base, TimestampMixin, SoftDeleteMixin):
# WHEN this rule applies — the trigger, not the instruction. Required of
# new rules at the service layer and nullable here, because rules written
# before migration 0088 have none and a migration cannot invent one.
# It carries three jobs at once (note 3026): it is the readable form of
# the canon tag, the half of the document that makes a rule findable by
# meaning, and — since milestone 394 removed the always-on tier — the ONLY
# thing that decides whether a rule ever reaches a session at all. A rule
# It carries three jobs at once: it is the readable form of the canon tag,
# the half of the document that makes a rule findable by meaning, and —
# with no always-on tier — the ONLY thing that decides whether a rule ever reaches a session at all. A rule
# with no trigger is not a quiet rule, it is an unreachable one.
when_to_apply: Mapped[str | None] = mapped_column(Text, nullable=True)
# WHAT KIND of instruction this is. `tier` used to sit beside this and
# carry delivery; milestone 394 removed it, so kind is now the only axis
# on a rule and delivery belongs entirely to retrieval.
# WHAT KIND of instruction this is — the only axis on a rule; delivery
# belongs entirely to retrieval.
# `rule` must be FOLLOWED: ignoring it breaks something or crosses a
# boundary. `preference` is how this person wants work DONE: ignoring it
# costs consistency, not correctness.
@@ -116,7 +114,7 @@ class Rule(Base, TimestampMixin, SoftDeleteMixin):
# trigger-dominated document, ownership-scoped search, the retrieval arms,
# relations, and `rule_versions`, which is where its drift is recorded.
# Defaults to `rule` so nothing changes force on upgrade.
# CHECK ck_rules_kind (migration 0098, rule 36).
# CHECK ck_rules_kind (migration 0098).
kind: Mapped[str] = mapped_column(Text, default="rule", server_default="rule")
why: Mapped[str | None] = mapped_column(Text, nullable=True)
how_to_apply: Mapped[str | None] = mapped_column(Text, nullable=True)
@@ -141,7 +139,7 @@ class Rule(Base, TimestampMixin, SoftDeleteMixin):
DateTime(timezone=True), nullable=True
)
# The record that caused this rule — the edge notes and tasks already
# have. Rule 46's `why` names note 2813 in prose; this is that link as a
# have. A `why` can name its origin in prose; this is that link as a
# field, so it survives a rewording of the paragraph.
arose_from_id: Mapped[int | None] = mapped_column(
BigInteger, ForeignKey("notes.id", ondelete="SET NULL"), nullable=True
@@ -175,10 +173,9 @@ class Rule(Base, TimestampMixin, SoftDeleteMixin):
}
# Which global AREA a rule is about (milestone 307). Points at the canonical
# catalog, NEVER at a project's `systems` row: a rule that spans projects
# cannot be chained to one project's vocabulary. This is the edge three
# projects were drawing by hand, as rule text copied into a System's charter.
# Which global AREA a rule is about. Points at the canonical catalog, NEVER at
# a project's `systems` row: a rule that spans projects cannot be chained to
# one project's vocabulary.
rule_systems = Table(
"rule_systems",
Base.metadata,
@@ -188,7 +185,7 @@ rule_systems = Table(
)
# Which MOMENTS of work a rule arrives at (milestone 458). A rule mounted on a
# Which MOMENTS of work a rule arrives at. A rule mounted on a
# moment is delivered whenever that moment happens, by lookup and with no
# score — the route for a rule that is about WHEN something is done rather
# than what it is about, which semantic retrieval structurally misses. The
@@ -204,17 +201,15 @@ rule_moments = Table(
)
class RuleRelation(Base, CreatedAtMixin):
"""A typed edge between two rules. Each kind exists because its ABSENCE
forced a workaround somewhere in the operator's rulebook (note 3026).
"""A typed edge between two rules. Each kind exists because without it a
rulebook needs a workaround.
- ``co_surfaces`` — these fail together, so they must arrive together.
Without it, the only way to guarantee that was to merge them into one
row, which is what happened to rule 46: split into 144, folded back the
same day because "either rule could surface without the other."
Without it, the only way to guarantee that is to merge them into one
row, because either rule could surface without the other.
Symmetric in meaning; stored once and read both ways.
- ``overrides`` — this rule supersedes that one for its scope. Only
*suppression* existed, so an override had to be written as a parallel
rule that then drifts from its parent.
- ``overrides`` — this rule supersedes that one for its scope. Without
it, an override is a parallel rule that drifts from its parent.
- ``elaborates`` — this rule adds local specifics to that one; surfacing
the parent brings the addendum with it.
@@ -232,7 +227,7 @@ class RuleRelation(Base, CreatedAtMixin):
to_rule_id: Mapped[int] = mapped_column(
BigInteger, ForeignKey("rules.id", ondelete="CASCADE"), index=True
)
# CHECK ck_rule_relations_kind (migration 0088, rule 36).
# CHECK ck_rule_relations_kind (migration 0088).
kind: Mapped[str] = mapped_column(Text)
note: Mapped[str | None] = mapped_column(Text, nullable=True)
@@ -251,10 +246,8 @@ class RuleRelation(Base, CreatedAtMixin):
}
# `project_rulebook_subscriptions`, `project_rule_suppressions` and
# `project_topic_suppressions` lived here until milestone 414 (migration 0101).
# A rule's home is its scope now: a rule in a rulebook topic is global, a rule
# on a project applies to that project, and retrieval reads that directly. A
# subscription had stopped changing anything a session received, and a
# suppression muted rules from a subscription. A project that departs from a
# global rule writes a project rule with an `overrides` relation instead.
# A rule's home is its scope: a rule in a rulebook topic is global, a rule on
# a project applies to that project, and retrieval reads that directly. There
# are no per-project subscriptions or suppressions (migration 0101 dropped
# those tables); a project that departs from a global rule writes a project
# rule with an `overrides` relation.