docs(6209): coverage, guidance-ownership, shape, warnings tests and shared fixtures
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 13s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 13s
test_pattern_coverage, test_guidance_ownership, test_integration_shape_classify, test_instruction_surfaces_agree, test_retrieval_warnings, helpers.py and conftest.py state the property each test or fixture holds. The issue and milestone numbers, consolidation dates and one-install measurements that recorded how each was found are dropped; fixture dates and ids stay. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""Real-Postgres integration tests for shape classification (#2789).
|
||||
"""Real-Postgres integration tests for shape classification.
|
||||
|
||||
What mocks can't prove: the all-or-nothing batch against real rows, the
|
||||
write-ACL gate, the todo query's filters, and the consumer map riding
|
||||
@@ -96,7 +96,7 @@ async def test_classify_applies_judgments_and_reports_unmatched(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_a_bad_batch_applies_nothing(seeded):
|
||||
"""All-or-nothing (#2709's lesson): a caller must never learn later that
|
||||
"""All-or-nothing: a caller must never learn later that
|
||||
half a batch silently happened."""
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
with pytest.raises(ValueError) as err:
|
||||
@@ -131,7 +131,7 @@ async def test_classification_is_write_gated_and_listing_read_gated(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_rule_form_sweeps_unclassified_rows_only_and_applies_whole(seeded):
|
||||
"""#2868: one judgment over a directory + glob; judged rows are left
|
||||
"""One judgment over a directory + glob; judged rows are left
|
||||
alone unless include_judged; the same gates as the row form."""
|
||||
owner, other, pid, sid = seeded["owner"], seeded["other"], seeded["pid"], seeded["snippet"]
|
||||
await classify_shapes(owner, pid, [
|
||||
@@ -171,7 +171,7 @@ async def test_rule_form_sweeps_unclassified_rows_only_and_applies_whole(seeded)
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_sync_stamps_scoped_rows_and_unstamps_when_they_become_reachable(seeded):
|
||||
"""#2869: by-construction one-offs arrive `scoped` (mechanical), count as
|
||||
"""By-construction one-offs arrive `scoped` (mechanical), count as
|
||||
accounted, are reached by the sweep's default, and go back to the todo
|
||||
if a later tree makes them ordinary. A judgment overrides the stamp."""
|
||||
from scribe.services.coverage import ArchiveShape
|
||||
@@ -203,7 +203,7 @@ async def test_sync_stamps_scoped_rows_and_unstamps_when_they_become_reachable(s
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_uses_edges_are_the_consumer_map(seeded):
|
||||
"""#2870: a shape keeps ONE snippet_id (what it is) and any number of
|
||||
"""A shape keeps ONE snippet_id (what it is) and any number of
|
||||
uses edges (what it calls); the snippet's consumer map lists them,
|
||||
list_shapes(uses=N) finds them, and a sweep can write them."""
|
||||
from scribe.services import snippets as snippets_svc
|
||||
@@ -296,7 +296,7 @@ async def test_get_snippet_carries_the_structured_consumer_map(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_sync_refiles_rows_whose_snippet_was_purged(seeded):
|
||||
"""The SET NULL companion (#2787): a judgment whose target is hard-deleted
|
||||
"""The SET NULL companion: a judgment whose target is hard-deleted
|
||||
rejoins the todo on the next sync instead of dangling target-less."""
|
||||
owner, pid, sid = seeded["owner"], seeded["pid"], seeded["snippet"]
|
||||
await classify_shapes(owner, pid, [
|
||||
@@ -318,12 +318,12 @@ async def test_sync_refiles_rows_whose_snippet_was_purged(seeded):
|
||||
assert row.snippet_id is None
|
||||
|
||||
|
||||
# --- #2791: the write-path feed lands hook evidence as rows -------------------
|
||||
# --- the write-path feed lands hook evidence as rows --------------------------
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_write_path_evidence_is_a_proposal_never_a_verdict(seeded):
|
||||
"""Milestone 439. Pulled + referenced → every named shape of the
|
||||
"""Pulled + referenced → every named shape of the
|
||||
snippet's kind CARRIES the snippet as a proposal (basis "reference"),
|
||||
and its status is untouched: the agent that wrote it says what it is.
|
||||
A judgment is never touched, not even by a proposal. The outsider
|
||||
@@ -465,7 +465,7 @@ async def test_recent_pulls_reads_the_usage_stream(seeded):
|
||||
assert sid + 2000 not in pulls
|
||||
|
||||
|
||||
# --- #2792: the mechanical proposer against real rows -------------------------
|
||||
# --- the mechanical proposer against real rows -------------------------------
|
||||
|
||||
|
||||
def _quiet_semantic():
|
||||
@@ -594,7 +594,7 @@ async def test_derive_groups_land_on_rows_and_in_the_summary(seeded):
|
||||
|
||||
summary = proposal_summary(await live_rows(pid))
|
||||
assert summary["proposed"] == 1
|
||||
# #2872: the body-identical group (a real copy) outranks the bigger name
|
||||
# The body-identical group (a real copy) outranks the bigger name
|
||||
# group (usually convention), even at size 2 vs 3.
|
||||
order = [g["group"] for g in summary["derive_groups"]]
|
||||
assert order[0].startswith("dup:") and order[1] == "name:css:card"
|
||||
@@ -605,7 +605,7 @@ async def test_derive_groups_land_on_rows_and_in_the_summary(seeded):
|
||||
|
||||
# One of the css copies gets judged → the group shrinks on the next pass
|
||||
# but stays a family: a class in two files is already a recipe living in
|
||||
# two places (css name floor 2, note 2917). Judge the second and it's gone.
|
||||
# two places (css name floor 2). Judge the second and it's gone.
|
||||
await classify_shapes(owner, pid, [
|
||||
{"path": "b/z.css", "symbol": "card", "status": "exempt", "reason": "print sheet"},
|
||||
])
|
||||
@@ -623,8 +623,8 @@ async def test_derive_groups_land_on_rows_and_in_the_summary(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_write_time_derive_names_the_family_or_the_canon_for_a_name(seeded):
|
||||
"""#2900: against real rows — a name in a family → the family (other
|
||||
files, count; for CSS a NAME family, never a body one — note 2917); a
|
||||
"""Against real rows — a name in a family → the family (other files,
|
||||
count; for CSS a NAME family, never a body one); a
|
||||
name whose canonical row lives elsewhere → that canon; a judged row at
|
||||
the path, the canon's own file, or an unknown name → silence."""
|
||||
from scribe.services.shape_ledger import apply_derive_groups, write_time_derive
|
||||
@@ -667,7 +667,7 @@ async def test_write_time_derive_names_the_family_or_the_canon_for_a_name(seeded
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_derive_new_names_the_copy_that_joined_a_family_since_the_stamp(seeded):
|
||||
"""#2899: the first sync seeds one `slug`; a later sync adds an identical
|
||||
"""The first sync seeds one `slug`; a later sync adds an identical
|
||||
copy. Against the stamp between them, derive_new counts ONLY the
|
||||
newcomer — the drift since the last refresh, not the whole family."""
|
||||
from datetime import datetime, timezone
|
||||
@@ -700,7 +700,7 @@ async def test_derive_new_names_the_copy_that_joined_a_family_since_the_stamp(se
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_transition_and_prefix_references_clear_the_unused_css_flag(seeded):
|
||||
"""#2970 end to end: the two class forms a template never spells out —
|
||||
"""End to end: the two class forms a template never spells out —
|
||||
a transition `name=` and a concatenated name — travel from the real
|
||||
extractor through resolution into the flag, so rules they reach stop
|
||||
being reported as unused. Only a rule nothing can reach stays listed."""
|
||||
@@ -752,7 +752,7 @@ async def test_transition_and_prefix_references_clear_the_unused_css_flag(seeded
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_consumer_map_syncs_edges_from_template_references(seeded):
|
||||
"""Milestone 302: the consumer edges follow the archive — own-file
|
||||
"""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."""
|
||||
@@ -812,7 +812,7 @@ async def test_consumer_map_syncs_edges_from_template_references(seeded):
|
||||
assert rows[("v/B.vue", "error-msg")] not in edges
|
||||
|
||||
|
||||
# --- #2793: the divergence readout against real rows -------------------------
|
||||
# --- the divergence readout against real rows -------------------------------
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@@ -833,7 +833,7 @@ async def test_a_second_confirm_dialog_is_detected_and_named(seeded):
|
||||
from scribe.services import snippets as snippets_svc
|
||||
|
||||
owner, pid = seeded["owner"], seeded["pid"]
|
||||
# The confirm helper is TS canon: since #2871 a sym basis only proposes
|
||||
# The confirm helper is TS canon: a sym basis only proposes
|
||||
# within the shape's language family, so the fixture's Python snippet
|
||||
# says nothing about these Vue bodies — the canon must be one of theirs.
|
||||
canon = await snippets_svc.create_snippet(
|
||||
@@ -906,10 +906,9 @@ async def test_a_second_confirm_dialog_is_detected_and_named(seeded):
|
||||
|
||||
@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
|
||||
"""The poisoned-ledger case: a directory's "dominant canon" elected
|
||||
entirely by hook stamps written below the 0.80 floor would tell every new
|
||||
shape there it diverged from an unrelated 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
|
||||
@@ -984,14 +983,14 @@ async def test_weak_stamps_elect_no_canon_and_their_flags_are_withdrawn(seeded):
|
||||
|
||||
@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.
|
||||
"""A semantic miss is not evidence.
|
||||
|
||||
THE FIXTURE IS THE ACCEPTANCE CASE ABOVE, DELIBERATELY. A hand-rolled
|
||||
`confirmDanger` beside an async confirm canon is structurally identical to
|
||||
a registry helper beside an async service canon, and the arm's miss was
|
||||
meant to tell them apart. Measured live, true instances of a canon rarely
|
||||
clear the arm's floor either, so a miss fires on both — silencing on
|
||||
it silenced #2793's own case. Here the arm has read the body, found
|
||||
meant to tell them apart. True instances of a canon rarely clear the arm's
|
||||
floor either, so a miss fires on both — silencing on it would silence the
|
||||
case the readout exists for. Here the arm has read the body, found
|
||||
nothing, and the prompt is still RAISED.
|
||||
|
||||
Asserted on the row, not a flag count: `since` sits a second early to
|
||||
@@ -1087,9 +1086,9 @@ async def _two_generations(seeded, tag: str):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_the_capped_semantic_pass_reaches_the_new_shape_first(seeded):
|
||||
"""Measured live: after the #4208 version bump, 1,533 rows competed for 150
|
||||
semantic checks in row order and the six new shapes — the only ones the
|
||||
divergence check acts on — were all left unread and flagged. With room for
|
||||
"""After a version bump, every row competes for a capped number of
|
||||
semantic checks; in row order the new shapes — the only ones the
|
||||
divergence check acts on — are left unread and flagged. With room for
|
||||
ONE check, the new shape must be the one that gets it."""
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
@@ -1155,7 +1154,7 @@ async def test_history_records_what_was_used_when_and_drift_asks_for_a_recheck(s
|
||||
assert await shape_history(other, pid, "src/app.py") == {}
|
||||
|
||||
|
||||
# --- milestone 439: the writer judges what it wrote, before the sync has seen it
|
||||
# --- the writer judges what it wrote, before the sync has seen it
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_a_shape_written_this_turn_is_judged_before_the_sync_sees_it(seeded):
|
||||
@@ -1235,7 +1234,7 @@ async def test_unjudged_is_what_nobody_read(seeded):
|
||||
|
||||
@pytest.mark.integration
|
||||
async def test_a_whole_file_snippet_makes_its_file_row_canonical(seeded):
|
||||
"""Milestone 439: a snippet recorded at a component's path, with no
|
||||
"""A snippet recorded at a component's path, with no
|
||||
symbol, is the canon for that file row — the claim a whole-file record
|
||||
makes and a definition row never could. It still covers no definition
|
||||
inside the file."""
|
||||
|
||||
Reference in New Issue
Block a user