feat(ledger): the CSS consumer map — code_shape_consumers edges (shape → file whose markup names the class, count), migration 0086, resolve_consumers (own-file row when the template defines the class, else every other definition), sync_repo_consumers rebuilt from the archive on every refresh, consumers_of; derived, so not backed up (milestone 302 step 2, #2935)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Failing after 29s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Failing after 52s
CI & Build / Build & push image (push) Skipped
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Failing after 29s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Failing after 52s
CI & Build / Build & push image (push) Skipped
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -433,6 +433,44 @@ def test_compact_row_carries_identity_standing_and_the_proposers_word_only():
|
||||
assert noisy not in compact
|
||||
|
||||
|
||||
def test_resolve_consumers_prefers_the_own_file_and_fans_out_for_shared_names():
|
||||
"""Milestone 302: a class named in a template resolves to that file's
|
||||
OWN row when it defines the class (a scoped rule, consumed by its own
|
||||
markup); otherwise to every other definition of the name — one shared
|
||||
sheet, or all of several (the map fans out rather than guessing)."""
|
||||
from scribe.services.shape_ledger import resolve_consumers
|
||||
css_rows = [
|
||||
(1, "v/A.vue", "error-msg"), # scoped, defined + used in A
|
||||
(2, "v/B.vue", "error-msg"), # scoped, defined in B, used in B and C
|
||||
(3, "assets/components.css", "btn-primary"), # the shared sheet
|
||||
(4, "assets/a.css", "pill"), (5, "assets/b.css", "pill"), # two shared defs
|
||||
(6, "assets/c.css", "unused"),
|
||||
]
|
||||
refs = {
|
||||
"v/A.vue": {"error-msg": 2, "btn-primary": 1, "nothing-defined": 1},
|
||||
"v/B.vue": {"error-msg": 1},
|
||||
"v/C.vue": {"error-msg": 1, "pill": 3},
|
||||
}
|
||||
assert resolve_consumers(css_rows, refs) == {
|
||||
(1, "v/A.vue"): 2, # own row, not B's
|
||||
(3, "v/A.vue"): 1, # the shared sheet
|
||||
(2, "v/B.vue"): 1, # own row
|
||||
(2, "v/C.vue"): 1, # C defines nothing → the other file's row
|
||||
(4, "v/C.vue"): 3, (5, "v/C.vue"): 3, # ambiguous: both, not a guess
|
||||
}
|
||||
# Unknown tokens and an unreferenced row leave no trace.
|
||||
assert all(sid != 6 for sid, _ in resolve_consumers(css_rows, refs))
|
||||
|
||||
|
||||
def test_consumer_edges_table_cascades_with_the_shape():
|
||||
from scribe.models import Base
|
||||
from scribe.models.code_shape import CONSUMER_BASES, CodeShapeConsumer
|
||||
assert "code_shape_consumers" in Base.metadata.tables
|
||||
cols = CodeShapeConsumer.__table__.c
|
||||
assert next(iter(cols.shape_id.foreign_keys)).ondelete == "CASCADE"
|
||||
assert CONSUMER_BASES == ("template",)
|
||||
|
||||
|
||||
def test_uses_edges_table_and_validation():
|
||||
"""#2870: consumption is its own relation — a table that cascades with
|
||||
both ends, and `uses` on a classification must be a list of ids."""
|
||||
|
||||
Reference in New Issue
Block a user