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:
@@ -683,6 +683,49 @@ async def test_derive_new_names_the_copy_that_joined_a_family_since_the_stamp(se
|
||||
assert derive_new_summary(rows, since=None)["count"] == 0
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_consumer_map_syncs_edges_from_template_references(seeded):
|
||||
"""Milestone 302: the consumer edges follow the archive — own-file
|
||||
resolution for a scoped class, fan-out to the shared sheet for a class a
|
||||
template does not define, counts refreshed and stale edges removed on
|
||||
the next sync, and a vanished row's edges gone with it."""
|
||||
from scribe.services.shape_ledger import consumers_of, live_rows, sync_repo_consumers
|
||||
|
||||
pid = seeded["pid"]
|
||||
defs = _defs(
|
||||
("v/A.vue", "css", "error-msg", ".error-msg {", ".error-msg { color: red }"),
|
||||
("v/B.vue", "css", "error-msg", ".error-msg {", ".error-msg { color: blue }"),
|
||||
("assets/components.css", "css", "btn-primary", ".btn-primary {", ".btn-primary { x: 1 }"),
|
||||
)
|
||||
await sync_repo_shapes(pid, REPO, defs, seen_marker="m1")
|
||||
refs = {
|
||||
"v/A.vue": {"error-msg": 2, "btn-primary": 1},
|
||||
"v/B.vue": {"error-msg": 1},
|
||||
"v/C.vue": {"error-msg": 1, "btn-primary": 4},
|
||||
}
|
||||
assert await sync_repo_consumers(pid, REPO, refs) == 5
|
||||
rows = {(r.path, r.symbol): r.id for r in await live_rows(pid) if r.kind == "css"}
|
||||
edges = await consumers_of(rows.values())
|
||||
view = {(p, s): [(e.path, e.count) for e in edges.get(i, [])] for (p, s), i in rows.items()}
|
||||
assert view[("v/A.vue", "error-msg")] == [("v/A.vue", 2)]
|
||||
assert view[("v/B.vue", "error-msg")] == [("v/B.vue", 1), ("v/C.vue", 1)]
|
||||
assert view[("assets/components.css", "btn-primary")] == [("v/A.vue", 1), ("v/C.vue", 4)]
|
||||
assert view[("web/button.css", "btn")] == [] # the seeded row: no template names it
|
||||
|
||||
# The next tree: C stops using error-msg, A uses btn-primary twice now.
|
||||
refs2 = {"v/A.vue": {"error-msg": 2, "btn-primary": 2}, "v/B.vue": {"error-msg": 1}}
|
||||
assert await sync_repo_consumers(pid, REPO, refs2) == 3
|
||||
edges = await consumers_of(rows.values())
|
||||
assert [(e.path, e.count) for e in edges[rows[("v/B.vue", "error-msg")]]] == [("v/B.vue", 1)]
|
||||
assert [(e.path, e.count) for e in edges[rows[("assets/components.css", "btn-primary")]]] == [("v/A.vue", 2)]
|
||||
|
||||
# B's rule vanishes from the tree → its edges go with the pass.
|
||||
await sync_repo_shapes(pid, REPO, [d for d in defs if d[0] != "v/B.vue"], seen_marker="m2")
|
||||
await sync_repo_consumers(pid, REPO, refs2)
|
||||
edges = await consumers_of(rows.values())
|
||||
assert rows[("v/B.vue", "error-msg")] not in edges
|
||||
|
||||
|
||||
# --- #2793: the divergence readout against real rows -------------------------
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user