feat(ledger): divergence readout — button B where button A is canon, shape history, and judged-shape recheck (#2793, milestone 294 step 7)
CI & Build / TypeScript typecheck (push) Failing after 2s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 28s
CI & Build / Python tests (push) Failing after 37s
CI & Build / Build & push image (push) Skipped
CI & Build / TypeScript typecheck (push) Failing after 2s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 28s
CI & Build / Python tests (push) Failing after 37s
CI & Build / Build & push image (push) Skipped
Every judgment now goes through one helper that remembers the fingerprint judged (classified_sha) and writes a code_shape_events row; the sync writes vanished / reappeared / drifted events and flags recheck_at when a body moves under an instance/variant. The refresh flags diverges_from on shapes new since the previous computation that sit where one canon dominates the judged siblings of their directory+kind and were not proposed as that canon (a first seed flags nothing); the write-path hint asks the same question in-band for the shapes the hook names. list_shapes(flag=divergence|recheck), shape_history(project_id, path, symbol) (read-only), coverage line/payload/ card carry divergent + recheck. Backup v8 carries the history. Plugin 0.1.36. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1248,3 +1248,42 @@ def test_hook_sends_the_enclosing_definition_for_a_body_edit(tmp_path):
|
||||
},
|
||||
})
|
||||
assert seen["shapes"] == ["sym:onTrash"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_the_write_time_divergence_check_is_named_in_band():
|
||||
"""#2793: the hook named a shape at a path whose directory a canon
|
||||
dominates, and the stamp didn't make it that canon's instance — the hint
|
||||
must say so at the write, even when nothing else renders."""
|
||||
from scribe.services import plugin_context as pc
|
||||
div = [{"symbol": "confirmDanger", "kind": "sym", "canon_snippet_id": 2761,
|
||||
"instances": 20, "judged": 21}]
|
||||
check = AsyncMock(return_value=div)
|
||||
with patch.object(pc, "get_writepath_config", AsyncMock(return_value=_cfg())), \
|
||||
patch.object(pc.snippets_svc, "list_snippets", AsyncMock(return_value=([], 0))), \
|
||||
patch.object(pc, "semantic_search_notes", AsyncMock(return_value=[])), \
|
||||
patch.object(pc, "record_retrieval", MagicMock()), \
|
||||
patch.object(pc, "owner_names_for", AsyncMock(return_value={})), \
|
||||
patch.object(pc.shape_ledger_svc, "recent_pulls", AsyncMock(return_value={})), \
|
||||
patch.object(pc.shape_ledger_svc, "write_time_divergence", check):
|
||||
out = await pc.build_write_path_hint(
|
||||
1, "frontend/src/components/Danger.vue", code=REAL_CODE, project_id=24,
|
||||
stamp_shapes=[("sym", "confirmDanger")],
|
||||
)
|
||||
check.assert_awaited_once_with(24, "frontend/src/components/Danger.vue",
|
||||
[("sym", "confirmDanger")], [])
|
||||
assert out["divergence"] == div
|
||||
assert "Divergence check at `frontend/src/components/Danger.vue`" in out["context"]
|
||||
assert "`confirmDanger` → #2761 (20 of 21 judged siblings are its instances)" in out["context"]
|
||||
assert "variant" in out["context"]
|
||||
# No project → no check at all.
|
||||
check.reset_mock()
|
||||
with patch.object(pc, "get_writepath_config", AsyncMock(return_value=_cfg())), \
|
||||
patch.object(pc.snippets_svc, "list_snippets", AsyncMock(return_value=([], 0))), \
|
||||
patch.object(pc, "semantic_search_notes", AsyncMock(return_value=[])), \
|
||||
patch.object(pc, "record_retrieval", MagicMock()), \
|
||||
patch.object(pc.shape_ledger_svc, "recent_pulls", AsyncMock(return_value={})), \
|
||||
patch.object(pc.shape_ledger_svc, "write_time_divergence", check):
|
||||
out = await pc.build_write_path_hint(1, "x.py", code=REAL_CODE, stamp_shapes=[("sym", "f")])
|
||||
check.assert_not_awaited()
|
||||
assert out["divergence"] == []
|
||||
|
||||
Reference in New Issue
Block a user