Files
FabledScribe/tests/test_design_cascade.py
T
bvandeusenandClaude Opus 5.5 79de8938b9 docs(6209): forty test files — design cascade and stylesheet, embeddings, family canon, forge, backup round trips, inception, placement, platforms, moments, rule move and verification, search scope, facets
Module and test docstrings state what is pinned without the record number
or step that introduced it. Incident accounts become the failure shape in
the present tense: the pipefail head, the code_shapes import, the export
order, the facet dialects, the cross-kind repeat, the write-once kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 21:40:25 -04:00

411 lines
17 KiB
Python

"""The parent chain: walking it, and refusing to close it.
Pure functions over a `{id: parent_id}` literal, so a whole hierarchy is one line
of setup and no database is involved. That is the reason the cascade lives in its
own import-free module — see services/design_cascade.py.
"""
from types import SimpleNamespace
from scribe.services.design_cascade import ancestry, resolve_tokens, would_cycle
from tests.helpers import design_token_stub
# --- ancestry ---------------------------------------------------------------
def test_ancestry_returns_the_chain_deepest_first():
"""Deepest first because that is the order resolution consumes it in: the
system being resolved wins over its parent, which wins over the root."""
parents = {1: None, 2: 1, 3: 2}
assert ancestry(3, parents) == [3, 2, 1]
def test_a_root_is_its_own_whole_chain():
"""A family system has no parent, and that is an ordinary state — not an
incomplete one. It must resolve to exactly itself."""
assert ancestry(1, {1: None}) == [1]
def test_a_missing_parent_truncates_rather_than_raising():
"""A parent that was soft-deleted (or filtered out of the caller's scope) is
a shorter chain, not a failed request. The alternative — raising — would make
one deleted system break every descendant's rendering."""
assert ancestry(3, {3: 2}) == [3, 2]
def test_a_system_absent_from_the_map_still_yields_itself():
assert ancestry(9, {}) == [9]
def test_ancestry_terminates_on_a_cycle_instead_of_hanging():
"""LOAD-BEARING, and the reason a visited-set exists even though writes are
guarded. A loop introduced by a direct DB edit or a future bug must degrade
to a truncated chain: truncation shows up in the result, a hang shows up as
an outage. Every id appears exactly once."""
parents = {1: 3, 2: 1, 3: 2}
chain = ancestry(1, parents)
assert chain == [1, 3, 2]
assert len(chain) == len(set(chain))
def test_ancestry_terminates_on_a_self_parent():
assert ancestry(1, {1: 1}) == [1]
# --- would_cycle ------------------------------------------------------------
def test_clearing_the_parent_never_cycles():
"""None means "make this a root", which is always safe."""
assert would_cycle(2, None, {1: None, 2: 1}) is False
def test_a_system_cannot_be_its_own_parent():
assert would_cycle(1, 1, {1: None}) is True
def test_an_ordinary_reparent_is_allowed():
"""family <- app is the shape the whole model exists for; it must not trip
the guard."""
assert would_cycle(2, 1, {1: None, 2: None}) is False
def test_a_direct_swap_is_refused():
"""A -> B, then B -> A. The two-system case, and the one a UI produces first
because both systems are on screen together."""
parents = {1: None, 2: 1}
assert would_cycle(1, 2, parents) is True
def test_an_indirect_loop_is_refused():
"""Three deep: root <- mid <- leaf, then root's parent set to leaf. Catching
this is what makes the check a chain walk rather than a parent comparison."""
parents = {1: None, 2: 1, 3: 2}
assert would_cycle(1, 3, parents) is True
def test_reparenting_onto_a_sibling_subtree_is_allowed():
"""Two branches off one root. Moving one under the other is legitimate — the
guard must refuse loops, not reorganisation."""
parents = {1: None, 2: 1, 3: 1}
assert would_cycle(3, 2, parents) is False
def test_the_guard_survives_a_hierarchy_that_is_already_corrupt():
"""If a cycle somehow already exists, the guard still has to answer rather
than spin — the write path is exactly where such a hierarchy gets repaired."""
parents = {1: 2, 2: 1, 3: None}
assert would_cycle(3, 1, parents) is False
assert would_cycle(1, 2, parents) is True
# --- resolution -------------------------------------------------------------
#
# The cascade proper. Hierarchies are stated as literals
# because resolve_tokens is pure and duck-typed — which is the whole reason it
# lives here rather than inside the service.
# A family (1) and an app inheriting from it (2) — the shape the model exists for.
FAMILY, APP = 1, 2
PARENTS = {FAMILY: None, APP: FAMILY}
def _by_name(tokens):
return {t.name: t for t in tokens}
def test_a_system_with_no_tokens_of_its_own_inherits_the_whole_family_set():
"""The correct answer for an app that has not departed from the family yet —
and the state every app system starts in."""
resolved = resolve_tokens(
APP, PARENTS,
{FAMILY: [design_token_stub(name="--fs-obsidian", value_by_mode={"base": "#14171a"})], APP: []},
)
assert [t.name for t in resolved] == ["--fs-obsidian"]
assert resolved[0].value_by_mode == {"base": "#14171a"}
assert resolved[0].origin_by_mode == {"base": FAMILY}
def test_the_deepest_system_wins_and_says_what_it_overrode():
"""Provenance is the point of the whole model: the effective set is just a
list without it, and "where does this app depart from the family?" becomes a
diff someone has to compute."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#6b2118"})],
APP: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#5b4a8a"})],
},
))
accent = resolved["--fs-accent"]
assert accent.value_by_mode == {"base": "#5b4a8a"}
assert accent.origin_by_mode == {"base": APP}
# The shadowed ancestor is still there, behind the winner.
assert [c.system_id for c in accent.contributions["base"]] == [APP, FAMILY]
assert accent.contributions["base"][1].value == "#6b2118"
def test_overriding_one_mode_leaves_the_others_inherited():
"""LOAD-BEARING, and the argument that decided the storage shape. An accent
deepened for light backgrounds while dark is left alone must own `base` and
still inherit `dark` — which is why merging is per (name, MODE) and why the
value column is a map rather than a pair of columns."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#34a877", "dark": "#34a877"})],
APP: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#15803d"})],
},
))
accent = resolved["--fs-accent"]
assert accent.value_by_mode == {"base": "#15803d", "dark": "#34a877"}
assert accent.origin_by_mode == {"base": APP, "dark": FAMILY}
def test_a_token_only_the_app_defines_is_not_an_override():
"""Introducing a token and overriding one are different acts, and a UI that
labelled both "overridden here" would misdescribe the first."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{FAMILY: [], APP: [design_token_stub(name="--fs-editor-caret", value_by_mode={"base": "#5b4a8a"})]},
))
caret = resolved["--fs-editor-caret"]
assert caret.origin_by_mode == {"base": APP}
assert caret.is_overridden_in(APP) is False
def test_is_overridden_in_is_true_only_for_the_system_that_shadowed():
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#6b2118"})],
APP: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#5b4a8a"})],
},
))
accent = resolved["--fs-accent"]
assert accent.is_overridden_in(APP) is True
assert accent.is_overridden_in(FAMILY) is False
def test_three_levels_stack_nearest_first():
"""A chain deeper than family->app, to prove the walk isn't a single hop."""
parents = {1: None, 2: 1, 3: 2}
resolved = _by_name(resolve_tokens(
3, parents,
{
1: [design_token_stub(name="--fs-bg", value_by_mode={"base": "a"})],
2: [design_token_stub(name="--fs-bg", value_by_mode={"base": "b"})],
3: [design_token_stub(name="--fs-bg", value_by_mode={"base": "c"})],
},
))
bg = resolved["--fs-bg"]
assert bg.value_by_mode == {"base": "c"}
assert [c.value for c in bg.contributions["base"]] == ["c", "b", "a"]
def test_resolving_the_family_itself_ignores_its_children():
"""Inheritance runs one way. A family system resolved on its own must not
pick up an app's overrides — otherwise every app would restyle the house."""
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#6b2118"})],
APP: [design_token_stub(name="--fs-accent", value_by_mode={"base": "#5b4a8a"})],
},
))
assert resolved["--fs-accent"].value_by_mode == {"base": "#6b2118"}
def test_value_for_falls_back_to_the_base_mode():
"""A token that isn't mode-dependent carries only `base`, and asking it for
"dark" must yield that rather than nothing — the read rule the storage shape
implies."""
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS, {FAMILY: [design_token_stub(name="--fs-radius-md", value_by_mode={"base": "8px"})]},
))
radius = resolved["--fs-radius-md"]
assert radius.value_for("dark") == "8px"
assert radius.value_for("base") == "8px"
def test_value_for_prefers_an_explicit_mode_over_the_fallback():
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS,
{FAMILY: [design_token_stub(name="--fs-bg", value_by_mode={"base": "#f7f5ef", "dark": "#14171a"})]},
))
assert resolved["--fs-bg"].value_for("dark") == "#14171a"
def test_metadata_is_inherited_when_the_override_leaves_it_blank():
"""A child overriding a colour routinely says nothing about what the token is
FOR. Inheriting the family's description beats blanking it — the override was
about the value, not the meaning."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-obsidian", value_by_mode={"base": "#14171a"}, group_name="surface", purpose="page bg, deepest surface")],
APP: [design_token_stub(name="--fs-obsidian", value_by_mode={"base": "#101317"})],
},
))
obsidian = resolved["--fs-obsidian"]
assert obsidian.group_name == "surface"
assert obsidian.purpose == "page bg, deepest surface"
assert obsidian.value_by_mode == {"base": "#101317"} # the value still won
def test_an_override_that_states_metadata_wins_it_too():
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-x", value_by_mode={"base": "a"}, purpose="family says")],
APP: [design_token_stub(name="--fs-x", value_by_mode={"base": "b"}, purpose="app says")],
},
))
assert resolved["--fs-x"].purpose == "app says"
def test_an_override_at_default_order_keeps_the_familys_position():
"""order_index 0 is the column DEFAULT, so it reads as unstated. Treating it
as "first" would let a colour-only override drag its token to the top of the
group — a visible reshuffle nobody asked for."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-x", value_by_mode={"base": "a"}, order_index=7)],
APP: [design_token_stub(name="--fs-x", value_by_mode={"base": "b"})],
},
))
assert resolved["--fs-x"].order_index == 7
def test_the_effective_set_is_ordered_by_group_then_position_with_ungrouped_last():
resolved = resolve_tokens(
FAMILY, PARENTS,
{FAMILY: [
design_token_stub(name="--fs-z", value_by_mode={"base": "1"}), # ungrouped
design_token_stub(name="--fs-b", value_by_mode={"base": "2"}, group_name="text", order_index=1),
design_token_stub(name="--fs-a", value_by_mode={"base": "3"}, group_name="surface", order_index=2),
design_token_stub(name="--fs-c", value_by_mode={"base": "4"}, group_name="surface", order_index=1),
]},
)
assert [t.name for t in resolved] == ["--fs-c", "--fs-a", "--fs-b", "--fs-z"]
def test_resolution_terminates_on_a_corrupt_hierarchy():
"""Resolution inherits ancestry's visited-set. A loop reaching this function
must produce a truncated set, not a hung request — the defensive half of the
cycle guard, exercised end to end."""
parents = {1: 2, 2: 1}
resolved = _by_name(resolve_tokens(
1, parents,
{1: [design_token_stub(name="--fs-a", value_by_mode={"base": "one"})], 2: [design_token_stub(name="--fs-b", value_by_mode={"base": "two"})]},
))
assert set(resolved) == {"--fs-a", "--fs-b"}
# Each system contributes exactly once, not endlessly.
assert len(resolved["--fs-a"].contributions["base"]) == 1
# --- supersedes -------------------------------------------------------------
#
# The declaration that replaces a prohibition. A design system stores what things
# ARE, so "pure white is never text" has no row — but "write this token instead
# of #fff" does, and it is the same fact stated forwards.
def test_supersedes_is_inherited_when_the_override_is_silent_about_it():
"""LOAD-BEARING. A child overriding a colour says nothing about which
literals it replaces, and blanking the family's declaration there would
silently disarm the check for every app that customises the token."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-text", value_by_mode={"base": "#e8e4d8"}, supersedes=["#fff", "#ffffff"])],
APP: [design_token_stub(name="--fs-text", value_by_mode={"base": "#f0ece0"})],
},
))
text = resolved["--fs-text"]
assert text.supersedes == ("#fff", "#ffffff")
assert text.value_by_mode == {"base": "#f0ece0"} # the value still overrode
def test_an_override_that_states_its_own_supersedes_replaces_the_list():
"""Whole-list replacement, not a merge — an app that means "only #fff" must
be able to say so without inheriting entries it deliberately dropped."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [design_token_stub(name="--fs-text", value_by_mode={"base": "a"}, supersedes=["#fff", "#ffffff"])],
APP: [design_token_stub(name="--fs-text", value_by_mode={"base": "b"}, supersedes=["#fff"])],
},
))
assert resolved["--fs-text"].supersedes == ("#fff",)
def test_a_token_that_supersedes_nothing_resolves_to_an_empty_tuple():
"""Most tokens replace nothing. That has to be an empty sequence rather than
None, so no caller has to test for two kinds of nothing."""
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS, {FAMILY: [design_token_stub(name="--fs-radius-md", value_by_mode={"base": "8px"})]},
))
assert resolved["--fs-radius-md"].supersedes == ()
def test_supersedes_survives_serialisation_as_a_list():
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS,
{FAMILY: [design_token_stub(name="--fs-text", value_by_mode={"base": "#e8e4d8"}, supersedes=["#fff"])]},
))
assert resolved["--fs-text"].to_dict()["supersedes"] == ["#fff"]
def test_the_superseded_literal_need_not_match_the_tokens_own_value():
"""The whole reason this is DECLARED rather than derived. `#fff` and
Parchment are different colours, so a value-matching rule could never have
connected them — which is why the prohibition looked unrepresentable until
it was turned around."""
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS,
{FAMILY: [design_token_stub(name="--fs-text", value_by_mode={"base": "#e8e4d8"}, supersedes=["#fff"])]},
))
text = resolved["--fs-text"]
assert text.value_by_mode["base"] not in text.supersedes
def test_rows_without_a_supersedes_attribute_at_all_still_resolve():
"""Duck-typed input: a caller passing rows from before the column existed
must not crash the cascade."""
legacy = SimpleNamespace(
name="--fs-x", value_by_mode={"base": "a"},
group_name=None, purpose=None, order_index=0,
)
resolved = _by_name(resolve_tokens(FAMILY, PARENTS, {FAMILY: [legacy]}))
assert resolved["--fs-x"].supersedes == ()
# --- rationale --------------------------------------------------------------
def test_rationale_cascades_like_purpose_and_is_a_different_question():
"""`purpose` is what the token is FOR; `rationale` is why it is this value.
Rules carry the second routinely ("Success = Moss, aligned by design") and a
token row needs a place to put it."""
resolved = _by_name(resolve_tokens(
APP, PARENTS,
{
FAMILY: [SimpleNamespace(
name="--fs-success", value_by_mode={"base": "#4a5d3f"},
group_name="semantic", purpose="success states",
rationale="equals Moss, aligned by design",
order_index=0, supersedes=[],
)],
APP: [design_token_stub(name="--fs-success", value_by_mode={"base": "#3f5236"})],
},
))
token = resolved["--fs-success"]
assert token.rationale == "equals Moss, aligned by design"
assert token.purpose == "success states"
assert token.value_by_mode == {"base": "#3f5236"} # the value still overrode
def test_a_token_without_a_rationale_resolves_to_none():
resolved = _by_name(resolve_tokens(
FAMILY, PARENTS, {FAMILY: [design_token_stub(name="--fs-x", value_by_mode={"base": "1px"})]},
))
assert resolved["--fs-x"].rationale is None