Files
FabledScribe/tests/test_inception.py
T
bvandeusenandClaude Opus 5 8820551058
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 7s
CI & Build / integration (push) Failing after 39s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / Python tests (push) Failing after 56s
CI & Build / Build & push image (push) Skipped
fix(394): unbreak collection, the TS typecheck and the plugin version
Five validators failed on 0e10f6b; these are the ones the logs named.

COLLECTION died first and hid everything else: test_inception.py still
imported project_rulebook_exclusions, so pytest aborted before running a
single test in either the unit or the integration lane. The migrations
therefore never ran, which means 0099 and 0100 are still unverified — this
push is what puts them in front of real Postgres.

The obsolete table test went with the import, and its module docstring now
says why rather than just describing one fewer thing.

TypeScript: RulebookDetailPane's currentRulebook computed existed only to
feed the always-on toggle, so removing the toggle left it unread; the vue
'computed' import went with it.

Plugin version minted — plugin content changed and the manifest gates the
executing cache (#2209), so the hook check fails until it moves.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011cPyzNnegXHr5iRMzzy5KJ
2026-09-11 16:26:56 -04:00

78 lines
3.8 KiB
Python

"""Project inception (milestone 297) — step 1: the record's shape.
The WHY a project inherits what it does lives on projects.inception. Pure
validation is pinned here; the effects are step 3's integration tests.
The opt-out of an always-on rulebook had its own association table until
milestone 394. With no always-on tier there is nothing to opt out OF — a
rulebook binds a project only by subscription — so the table and the test
that pinned its shape both went with it.
"""
from scribe.models.project import Project
from scribe.services.inception import (
CHOICE_KEYS, INCEPTION_VIAS, is_decided, normalize_choices, validate_inception,
)
def test_project_carries_an_inception_record_and_to_dict_shows_it():
assert "inception" in Project.__table__.c
assert Project.__table__.c.inception.nullable # NULL = undecided
p = Project(user_id=1, title="x", inception=None)
assert p.to_dict()["inception"] is None and not is_decided(p)
p.inception = {"via": "mcp", "decided_at": "2026-08-22T00:00:00+00:00", "decided_by": 1,
"choices": normalize_choices({"seed_systems": True})}
assert is_decided(p) and p.to_dict()["inception"]["via"] == "mcp"
assert INCEPTION_VIAS == ("mcp", "ui", "legacy")
def test_validate_inception_pins_the_choice_vocabulary():
assert CHOICE_KEYS == ("subscribe_rulebooks", "design_system_id", "seed_systems")
assert validate_inception({}) is None
assert validate_inception({"subscribe_rulebooks": [2],
"design_system_id": 3, "seed_systems": True}) is None
assert validate_inception({"design_system_id": None}) is None
assert "must be an object" in validate_inception([])
assert "unknown inception choice" in validate_inception({"repo": "x"})
# The retired exclusion key is now an UNKNOWN key rather than a typed one,
# which is the right error: a caller still passing it is asking for a
# choice that no longer exists, and silently ignoring it would let them
# believe a rulebook had been declined.
assert "unknown inception choice" in validate_inception(
{"exclude_always_on_rulebooks": [1]})
assert "list of rulebook ids" in validate_inception({"subscribe_rulebooks": [0]})
assert "list of rulebook ids" in validate_inception({"subscribe_rulebooks": [True]})
assert "positive id or null" in validate_inception({"design_system_id": 0})
assert "positive id or null" in validate_inception({"design_system_id": True})
assert "true or false" in validate_inception({"seed_systems": "yes"})
def test_normalize_choices_is_canonical_and_complete():
out = normalize_choices({"subscribe_rulebooks": [3, 1, 3]})
assert out == {"subscribe_rulebooks": [1, 3],
"design_system_id": None, "seed_systems": False}
assert normalize_choices(None) == {"subscribe_rulebooks": [],
"design_system_id": None, "seed_systems": False}
def test_standard_systems_vocabulary_reads_the_catalog_not_a_constant():
"""The vocabulary moved from a module constant to the global catalog table
(milestone 307): a constant cannot be a foreign key, so nothing outside a
project could reference an area. The seed and the bootstrap ask must both
read the table, or the list they show and the list they mint diverge."""
import inspect
from scribe.services import systems as systems_svc
assert not hasattr(systems_svc, "STANDARD_SYSTEMS"), (
"the constant is gone — the catalog table is the single source"
)
source = inspect.getsource(systems_svc.seed_standard_systems)
assert "list_canonical_systems" in source
assert "canonical_id=entry.id" in source, (
"a seeded System must be mapped as it is created, or a project born "
"from the standard set still needs a reconciliation pass"
)