docs(6209): twelve more test files say which behaviour they pin
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m53s
CI & Build / Build & push image (push) Successful in 12s

shape ledger, MCP projects/search/rulebooks tools, backup, chunking,
plugin context, derived mirror, rule band, shape form gate, plugin
version mint and note usage tests drop issue, milestone and rule numbers,
dates and one-install figures from docstrings, comments and messages.
Three shape-form-gate test names that told the discovery story now name
the property: a registry module's helpers are not service functions, the
divergence gate silences only a family contradiction, and callable helpers
beside a callable canon still prompt. The rulebook tool-count comment that
logged each milestone's additions is replaced by the reason it is a count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 21:24:50 -04:00
co-authored by Claude Opus 5.5
parent 91c96a8b8a
commit d41e72d26c
12 changed files with 223 additions and 265 deletions
+17 -18
View File
@@ -1,9 +1,8 @@
"""The shape ledger's schema contract (#2787, milestone 294, note 2786).
"""The shape ledger's schema contract.
Step 1 pins the model: identity, the classification vocabulary, and the
token-free serialisation. The sync pass (step 2) and the classification
surface (step 3) grow their tests here; DB-backed behavior lands in the
integration lane once there is behavior to exercise.
The model: identity, the classification vocabulary, and the token-free
serialisation; then the pure halves of the sync pass and the classification
surface. DB-backed behaviour is in the integration lane.
"""
import pytest
@@ -47,7 +46,7 @@ def test_snippet_reference_survives_snippet_deletion_as_null():
def test_status_queries_have_an_index():
"""list_shapes(status=unclassified) is THE todo query (step 3) — it must
"""list_shapes(status=unclassified) is THE todo query — it must
not degrade into a project-wide scan as ledgers reach thousands of rows."""
names = {ix.name for ix in CodeShape.__table__.indexes}
assert "ix_code_shapes_project_status" in names
@@ -181,7 +180,7 @@ def test_signature_similarity_blanks_the_names():
def test_a_model_with_a_different_mixin_list_is_proposed_against_the_model_canon():
"""The band 0.8 cut (#4306). Measured over judged instances: a model class
"""The band 0.8 cut. Measured over judged instances: a model class
whose mixins differ from the canon's scores ~0.795 against it — a true
instance, and the proposal is read before it is confirmed, so the floor
must admit it."""
@@ -324,7 +323,7 @@ def test_derive_groups_copy_before_name_with_floors():
("d.css", "css", "btn", "s1"), ("e.css", "css", "btn", "s2"), ("f.css", "css", "btn", "s3"),
("g.py", "sym", "main", "s4"), ("h.py", "sym", "main", "s5"), # only 2 files → no name group
("i.py", "sym", "one", "s6"),
# CSS (note 2917): identical bodies under different names are NOT a
# CSS: identical bodies under different names are NOT a
# copy — two meanings sharing the style system's look; the same
# class in two files IS a family (the name floor is 2 for css).
("j.css", "css", "muted", "same"), ("k.css", "css", "pin-auto", "same"),
@@ -344,7 +343,7 @@ def test_derive_groups_copy_before_name_with_floors():
def test_derive_new_summary_counts_copies_first_seen_since_the_previous_refresh():
"""#2899: the arrival-moment drift signal — derive-grouped rows created
"""The arrival-moment drift signal — derive-grouped rows created
after the previous refresh's stamp, newest first, judged rows and a
first seed (since=None) never count."""
from datetime import datetime, timedelta, timezone
@@ -376,8 +375,8 @@ def test_derive_new_summary_counts_copies_first_seen_since_the_previous_refresh(
def test_proposal_summary_ranks_body_identical_groups_first_and_sees_scoped_rows():
"""#2872: dup groups (the real copies) outrank name groups (usually
convention), wider spread first; #2869: scoped rows are in the readout."""
"""Dup groups (the real copies) outrank name groups (usually
convention), wider spread first; scoped rows are in the readout."""
from scribe.models.code_shape import CodeShape
from scribe.services.shape_ledger import proposal_summary
@@ -396,7 +395,7 @@ def test_proposal_summary_ranks_body_identical_groups_first_and_sees_scoped_rows
row("v/J.vue", "closed-msg", "dup:abc", status="exempt"),
]
out = proposal_summary(rows)
# Milestone 302: with consumer paths in hand, each css group says what
# With consumer paths in hand, each css group says what
# renders it — distinct files across the members; absent otherwise.
assert "consumers" not in out["derive_groups"][0]
for i, r in enumerate(rows): # unsaved rows have no id; give them one
@@ -429,7 +428,7 @@ def test_proposer_tools_are_mounted():
assert mcp._tool_manager.get_tool("confirm_shape_proposals") is not None
tool = mcp._tool_manager.get_tool("list_shapes")
assert "proposal" in tool.parameters.get("properties", {})
# #2868: the audit surfaces — compact pages and the sweep form.
# The audit surfaces — compact pages and the sweep form.
assert "compact" in tool.parameters.get("properties", {})
rule = mcp._tool_manager.get_tool("classify_shapes_by_rule")
assert rule is not None
@@ -437,7 +436,7 @@ def test_proposer_tools_are_mounted():
assert name in rule.parameters.get("properties", {}), name
# --- #2868: the bulk surfaces (pure) -----------------------------------------
# --- the bulk surfaces (pure) -----------------------------------------------
def test_compact_row_carries_identity_standing_and_the_proposers_word_only():
@@ -461,7 +460,7 @@ def test_compact_row_carries_identity_standing_and_the_proposers_word_only():
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
"""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)."""
@@ -490,7 +489,7 @@ def test_resolve_consumers_prefers_the_own_file_and_fans_out_for_shared_names():
def test_resolve_consumers_credits_every_row_a_prefix_could_have_built():
"""#2970: `status-${s}` names a class the map cannot pin down, so the
"""`status-${s}` names a class the map cannot pin down, so the
prefix reference `status-*` credits every row whose symbol starts with
the head — each under the same own-file-else-fan-out rule. Crediting all
of them is the honest reading: the alternative is calling live rules
@@ -533,7 +532,7 @@ def test_consumer_edges_table_cascades_with_the_shape():
def test_uses_edges_table_and_validation():
"""#2870: consumption is its own relation — a table that cascades with
"""Consumption is its own relation — a table that cascades with
both ends, and `uses` on a classification must be a list of ids."""
from scribe.models import Base
from scribe.models.code_shape import USE_BASES, CodeShapeUse
@@ -562,7 +561,7 @@ def test_reference_canons_names_every_used_canon_not_just_the_best():
def test_reason_codes_are_a_fixed_catalogue_and_validated():
"""#2874: an optional index beside the prose reason; unknown codes are a
"""An optional index beside the prose reason; unknown codes are a
structural error (the batch applies nothing)."""
from scribe.models.code_shape import REASON_CODES
from scribe.services.shape_ledger import validate_classifications