fix(shapes): weak stamps elect no canon; the arrival line names the review; Svelte scopes by default (#4608)
CI & Build / Python lint (push) Successful in 8s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m3s
CI & Build / Python tests (push) Successful in 1m44s
CI & Build / Build & push image (push) Successful in 1m5s

Librarian and Stash had 132 and 488 write-path stamps written at 0.68-0.72,
before the 0.80 floor (#4204). Nothing re-judged them, and dominant_canon
counted them, so a YAML CI snippet (#3410) "dominated" Librarian's web
directory and every write there was told it diverged from it — 1408 flags
on one project, 902 on the other, all skimmed past.

- is_weak_stamp: one predicate for "hook-stamped below today's floor".
  dominant_canon and canon_form skip such rows; stamps_to_review lists them
  by the same predicate. No stored row changes — they stay for judgment.
- flag_divergence withdraws a standing flag whose canon no longer dominates
  its directory. A flag is a mechanical prompt, not a judgment.
- The coverage line ends "N weak stamps · M incoherent canons to judge —
  stamps_to_review" when either is nonzero, so a project's own session sees
  the queue on arrival. The shape-accounting skill says what to do with it.
- scoped_definitions handles .svelte: every <style> is component-scoped
  unless <style global> or :global(...); instance-script syms are scoped,
  module-script ones stay ordinary.

Plugin version minted for the skill change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 23:27:07 -04:00
co-authored by Claude Opus 5.5
parent 3270fe90c1
commit eb5cc6d3a7
7 changed files with 291 additions and 12 deletions
+78
View File
@@ -889,6 +889,84 @@ async def test_a_second_confirm_dialog_is_detected_and_named(seeded):
assert total == 0
@pytest.mark.integration
async def test_weak_stamps_elect_no_canon_and_their_flags_are_withdrawn(seeded):
"""#4608, the poisoned-ledger case as it stood on two projects: a
directory's "dominant canon" was elected entirely by hook stamps written
at 0.68-0.72, before the 0.80 floor, so every new shape there was told it
diverged from a YAML CI snippet. The same fixture as the acceptance case
above, with one difference — the four instances are weak hook stamps
rather than an audit — and the prompt must fall silent: at refresh (the
standing flag is withdrawn) and at write time. The stamps themselves are
left exactly as they were, for `stamps_to_review` to put before a judge."""
from datetime import datetime, timedelta, timezone
from sqlalchemy import update
from scribe.services import snippets as snippets_svc
from scribe.services.shape_ledger import (
_RESEMBLE_REASON, flag_divergence, propose_for_repo, write_time_divergence,
)
owner, pid = seeded["owner"], seeded["pid"]
canon = await snippets_svc.create_snippet(
owner, name="cls_confirm_factory",
code="export async function factory(): Promise<boolean> {\n return true;\n}\n",
language="typescript", repo="Widget",
path="frontend/src/composables/useConfirm.ts", symbol="factory",
project_id=pid,
)
sid = int(canon.id)
comp = "frontend/src/components"
names = ("Trash", "Delete", "Remove", "Restore")
base = _defs(
*[(f"{comp}/{n}.vue", "sym", f"on{n}", f"async function on{n}() {{",
f"async function on{n}() {{\n const ok = await factory();\n if (!ok) return;\n}}")
for n in names],
)
await sync_repo_shapes(pid, REPO, base, seen_marker="aaa111")
await classify_shapes(owner, pid, [
{"path": f"{comp}/{n}.vue", "symbol": f"on{n}", "status": "instance", "snippet_id": sid}
for n in names
], via="audit")
previous = datetime.now(timezone.utc)
later = base + _defs(
(f"{comp}/Danger.vue", "sym", "confirmDanger", "function confirmDanger() {",
"function confirmDanger() {\n return window.confirm('Really?');\n}"),
)
await sync_repo_shapes(pid, REPO, later, seen_marker="bbb222")
with _quiet_semantic():
await propose_for_repo(owner, pid, REPO, later)
since = previous - timedelta(seconds=1)
# Judged by an audit, the canon dominates and the new shape is flagged.
assert await flag_divergence(pid, since=since) == 1
# Now make the four what the poisoned ledgers held: unattended stamps
# below today's floor.
weak = _RESEMBLE_REASON.format(sid=sid, score=0.72)
async with async_session() as session:
await session.execute(
update(CodeShape)
.where(CodeShape.project_id == pid, CodeShape.snippet_id == sid)
.values(classified_by="hook", reason=weak)
)
await session.commit()
assert await flag_divergence(pid, since=since) == 0
rows, total = await list_project_shapes(owner, pid, flag="divergence")
assert total == 0, "a flag whose canon no longer dominates is withdrawn"
assert await write_time_divergence(
pid, f"{comp}/Danger.vue", [("sym", "confirmDanger")], stamped=[]
) == []
# Nothing was un-judged: the stamps stand until someone reads them.
async with async_session() as session:
kept = (await session.execute(
select(CodeShape).where(CodeShape.project_id == pid, CodeShape.snippet_id == sid)
)).scalars().all()
assert len(kept) == 4
assert all(r.status == "instance" and r.classified_by == "hook" for r in kept)
@pytest.mark.integration
async def test_a_semantic_miss_does_not_silence_the_prompt(seeded):
"""#4208, reversed on measurement: a semantic miss is not evidence.