"""Family canon's schema — the parts that need no database (milestone 463 step 1). The constraints themselves, against real Postgres, are in tests/test_integration_family_canon.py. These pin that the migration and the model agree on every whitelist (rule 36: a value one side accepts and the other refuses only fails at INSERT time, which CI's unit lane never reaches), and that the seed ships nothing an install other than this one would find foreign (rule 115). """ from __future__ import annotations import importlib.util from pathlib import Path from scribe.models import family ROOT = Path(__file__).resolve().parents[1] def _migration(): path = ROOT / "alembic" / "versions" / "0120_family_canon.py" spec = importlib.util.spec_from_file_location("m0120", path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module def test_the_migration_checks_and_the_model_agree(): m = _migration() assert tuple(m._MEMBERSHIP) == family.MEMBERSHIP_STATES assert tuple(m._IDEA_STATUSES) == family.IDEA_STATUSES assert tuple(m._ADOPTION_STATUSES) == family.ADOPTION_STATUSES assert tuple(m._REASONED) == family.REASONED_STATUSES assert tuple(m._ACTIONS) == family.DECISION_ACTIONS assert tuple(m._DECIDERS) == family.DECIDERS def test_the_departures_that_need_a_reason_are_adoption_states(): assert set(family.REASONED_STATUSES) <= set(family.ADOPTION_STATUSES) def test_the_seed_is_generic_and_unique(): seed = _migration()._SEED slugs = [slug for _, slug, _, _ in seed] assert len(slugs) == len(set(slugs)), "a duplicate slug breaks the live-unique index" for name, slug, description, markers in seed: assert name and slug and description assert slug == slug.lower() and " " not in slug # A list, possibly empty — never None. Detection reads it directly. assert isinstance(markers, list) def test_the_column_defaults_match_the_first_state_of_each_lifecycle(): """A row created with no state given starts where its lifecycle starts. An idea is a candidate until promoted; an answer is unassessed until someone assesses it — never silently `adopted`.""" assert family.FamilyIdea.__table__.c.status.server_default.arg == "candidate" assert family.FamilyAdoption.__table__.c.status.server_default.arg == "unassessed" assert family.ProjectPlatform.__table__.c.state.server_default.arg == "declared" def test_a_canon_ideas_scope_lives_on_the_idea_and_nowhere_else(): """One scope source. A rule topic is linked FROM the idea and carries no platforms of its own, so the two cannot disagree about who a standard reaches (#4221's two-sources-of-truth shape).""" from scribe.models.rulebook import RulebookTopic assert "topic_id" in family.FamilyIdea.__table__.c assert not {c.name for c in RulebookTopic.__table__.c} & {"platform_id", "platform_ids"}