feat(systems): the area vocabulary becomes a global table so a rule can point at one (#3027, milestone 307 step 1)
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / TypeScript typecheck (push) Successful in 39s
CI & Build / Python lint (push) Successful in 4s
CI & Build / integration (push) Successful in 30s
CI & Build / Python tests (push) Failing after 56s
CI & Build / Build & push image (push) Skipped
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / TypeScript typecheck (push) Successful in 39s
CI & Build / Python lint (push) Successful in 4s
CI & Build / integration (push) Successful in 30s
CI & Build / Python tests (push) Failing after 56s
CI & Build / Build & push image (push) Skipped
The eight standard area names already existed — as STANDARD_SYSTEMS, a tuple in
services/systems.py that milestone 297 seeds at inception. A constant cannot be
a foreign key, so nothing outside a project could reference an area: systems.
project_id is NOT NULL, and a rule that spans projects would have to chain
itself to one project's row. And because the list only ever applied on the
inception-seed path, three spellings of one area reached this instance anyway
(CI & runners / CI and Release / CI & release).
- canonical_systems: global, no user_id — a shared project inherits the
vocabulary instead of re-earning it. Migration 0087 seeds the same eight.
- systems.canonical_id: nullable, SET NULL. Association only — no System is
renamed and record_systems is untouched, so no record's tags move.
- canonical_slug folds &/and, case and punctuation, so spelling variants map
mechanically and a real difference ("CI & runners") becomes a proposal a
human confirms. propose_mappings reports; set_system_canonical is the only
writer.
- seed_standard_systems now reads the catalog and maps as it mints, so a
project born standard never needs a reconciliation pass.
- Catalog writes are admin-only; reads are open — a global list anyone can
extend stops being shared.
- backup: carried by SLUG, not id (ids are per-install). Restore reuses the
target's own rows and only creates entries an admin added on the source; an
unknown slug restores unmapped rather than failing.
Rule 22: STANDARD_SYSTEMS is removed, not deprecated. Rule 115: nothing seeded
names an app, repo or house convention. Design in note 3026.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-5
@@ -57,9 +57,22 @@ def test_normalize_choices_is_canonical_and_complete():
|
||||
"design_system_id": None, "seed_systems": False}
|
||||
|
||||
|
||||
def test_standard_systems_vocabulary_is_one_list_for_ask_and_seed():
|
||||
from scribe.mcp.tools.systems import _STANDARD_SYSTEMS
|
||||
from scribe.services.systems import STANDARD_SYSTEMS
|
||||
assert _STANDARD_SYSTEMS == tuple(n for n, _ in STANDARD_SYSTEMS)
|
||||
assert len(STANDARD_SYSTEMS) == 8 and all(charter for _, charter in STANDARD_SYSTEMS)
|
||||
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"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user