From ead4a7e2ad3bcc7251a9874eb356cbad6392eb3d Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 21 Oct 2026 21:33:08 -0400 Subject: [PATCH] docs(6209): preference door, systems and notes tools, lesson surfacing, rule versions, backup round trip, JSON reader, charter search, provenance, location filter Ten more test files: issue, milestone, rule, decision and snippet numbers come out of docstrings, comments and messages; the preference door states what a preference is instead of quoting the framing; the JSON reader says why jq is not assumed instead of what every hook used to do; the backup round trip's column warning no longer claims the import side is unguarded. Co-Authored-By: Claude Opus 5.5 --- tests/test_hook_json_reader.py | 24 +++++++++---------- ...integration_backup_rule_usage_roundtrip.py | 17 +++++++------ tests/test_integration_rule_versions.py | 12 +++++----- tests/test_lesson_surfacing.py | 14 +++++------ tests/test_mcp_tool_notes.py | 12 +++++----- tests/test_mcp_tool_systems.py | 14 +++++------ tests/test_preference_write_path.py | 17 +++++++------ tests/test_snippet_location_filter.py | 10 ++++---- tests/test_snippet_provenance.py | 14 +++++------ tests/test_system_charter_search.py | 9 ++++--- 10 files changed, 69 insertions(+), 74 deletions(-) diff --git a/tests/test_hook_json_reader.py b/tests/test_hook_json_reader.py index c5b09387..d2ab2057 100644 --- a/tests/test_hook_json_reader.py +++ b/tests/test_hook_json_reader.py @@ -1,12 +1,10 @@ -"""JSON, read and written by the hooks without jq (#4107). +"""JSON, read and written by the hooks without jq. -WHAT THIS REPLACED, AND WHY IT NEEDS TESTING AT ALL. Every hook used to open -`command -v jq >/dev/null 2>&1 || exit 0`, so on a machine without jq the -operator got no session context, no rules, no prior art and no process sync, -and not one word saying why — `exit 0` is indistinguishable from "ran fine, -nothing to say". jq is absent by default on macOS, on the Debian/Ubuntu slim -images, on Alpine and in most CI containers. The parser that replaced it is -`plugin/hooks/scribe_json.awk`, written in POSIX awk, and a parser is exactly +WHY NOT jq, AND WHY THIS NEEDS TESTING AT ALL. jq is absent by default on +macOS, on the Debian/Ubuntu slim images, on Alpine and in most CI containers, +and a hook that exits quietly without it gives the operator no session context, +no rules, no prior art and no process sync, with not one word saying why. The +parser is `plugin/hooks/scribe_json.awk`, written in POSIX awk, and a parser is exactly the kind of thing that works on the six documents you tried it on. So the centre of this file is a DIFFERENTIAL against Python's `json`: the same @@ -16,7 +14,7 @@ is one the hooks can be handed an arbitrary event with. The rest pins the three jobs around it — writing the hook envelope, percent-encoding a URL, and bounding a turn in a transcript — and that each -guard here can fail (rule 167). +guard here can fail. """ from __future__ import annotations @@ -74,7 +72,7 @@ def reference_flatten(value, path="", out=None): shell reads it back with. Every array also reports its LENGTH at `[#]`, including an empty one, and an empty object reports `{#}` 0 — that is what lets a caller tell "the server answered with zero notes" from "the server - did not answer", which #2932 built an outage marker around. + did not answer", which the outage marker is built around. """ out = [] if out is None else out if isinstance(value, dict): @@ -221,7 +219,7 @@ def test_an_absent_field_and_a_null_field_both_read_as_empty(): def test_an_absent_array_length_is_empty_not_zero(): """NOT the same answer as 0, and the distinction is load-bearing: the record nudge fires when the server said "zero notes" and must not fire - when the server said nothing at all (#2932).""" + when the server said nothing at all.""" out = sh(r"""flat=$(scribe_json_flat) printf '[%s][%s]\n' "$(scribe_json_len "$flat" '.note_ids')" \ "$(scribe_json_len "$flat" '.missing')" """, @@ -272,7 +270,7 @@ def test_urlenc_percent_encodes_exactly_the_unreserved_set(value): def test_urlenc_and_the_envelope_can_fail(): - """Rule 167 — a guard that cannot fail is decoration. If the escaper were a + """A guard that cannot fail is decoration. If the escaper were a no-op, this pair would be the assertion that noticed.""" assert sh("scribe_urlenc", stdin="a b") != "a b" raw = sh('scribe_json_out PreToolUse "$(cat)"', stdin='he said "hi"') @@ -376,7 +374,7 @@ def test_a_tool_result_does_not_read_as_a_prompt(): def test_the_turn_guards_can_fail(): - """Rule 167. If the analyzer counted everything, or nothing, these are the + """If the analyzer counted everything, or nothing, these are the assertions that would notice.""" assert _turn([_prompt(), _close("t1", 41), _text("r")])["closed"] == "1" assert _turn([_prompt(), _text("r")])["closed"] == "0" diff --git a/tests/test_integration_backup_rule_usage_roundtrip.py b/tests/test_integration_backup_rule_usage_roundtrip.py index 5e8f0dc0..1923a29e 100644 --- a/tests/test_integration_backup_rule_usage_roundtrip.py +++ b/tests/test_integration_backup_rule_usage_roundtrip.py @@ -1,9 +1,9 @@ -"""Real-Postgres round trip for rule_usage_events (milestone 333 step 1). +"""Real-Postgres round trip for rule_usage_events. **This file is the reason the table exists.** `rule_usage_events` could have been a `rule_id` column on `note_usage_events` — the row carries no note-specific field and the readout is the same shape, which is the strongest -case for sharing that note #3163 admits. What decided against it is identity at +case for sharing. What decides against it is identity at restore, and that is a claim only a real round trip can support. The failure it guards is the quiet kind. `note_usage_events`'s importer maps @@ -17,7 +17,7 @@ So the assertions below are about WHICH MAP resolved the id, and they are written to fail if the answer ever becomes "the note one" or "neither". Same shape as `test_integration_backup_rule_version_roundtrip.py`, which guards -`rule_versions` against #3182's `arose_from_id` trap on the same seam. +`rule_versions` against the same id-remapping trap on the same seam. """ import pytest import pytest_asyncio @@ -143,7 +143,7 @@ async def source(): user_id=None, rule_id=rule.id, event=SURFACED, source="write_path_rule", ), - # A departure and its reason (#4212). Seeded here because + # A departure and its reason. Seeded here because # `detail` is the ONE field on this table that cannot be # recomputed: a fresh install re-earns its counts by being used, # but a stated reason exists once and is gone if a restore drops @@ -290,7 +290,7 @@ async def test_the_actor_is_remapped_and_a_missing_one_survives(restored): attributed = [e for e in restored["events"] if e.user_id is not None] orphaned = [e for e in restored["events"] if e.user_id is None] # Four attributed: the surfacing, the pull, and the two outcome rows - # added with `detail` (#4212). One orphaned, deliberately. + # that carry `detail`. One orphaned, deliberately. assert len(attributed) == 4 assert len(orphaned) == 1, ( "the event with no actor did not come back. Telemetry outlives the " @@ -325,10 +325,9 @@ async def test_a_departures_reason_survives_the_round_trip(restored): 419 was opened to create, undone silently at the one moment nobody is watching. - #4197 is the standing warning behind this test: the backup column guard - watches the export side only, so a column added to the model and to the - exporter and NOT to the importer round-trips as null with nothing to say - so. + A column added to the model and to the exporter and NOT to the importer + round-trips as null with nothing to say so; this round trip is where that + shows up in the data. """ departures = [e for e in restored["events"] if e.event == DEPARTED] assert len(departures) == 1 diff --git a/tests/test_integration_rule_versions.py b/tests/test_integration_rule_versions.py index 9b405335..6580fea3 100644 --- a/tests/test_integration_rule_versions.py +++ b/tests/test_integration_rule_versions.py @@ -1,12 +1,12 @@ -"""Real-Postgres tests for the rule-history write path (milestone 323 step 2). +"""Real-Postgres tests for the rule-history write path. Every assertion here is about ORDERING or ABSENCE, which is why none of them can be made with mocks. What a version is for: it holds what the rule USED TO SAY. The edit destroys -that, and nothing can recompute it — the rescoping of rule 79 had to be -hand-copied into a task log to survive (#3237), which is not a process, it is -a person remembering. +that, and nothing can recompute it — without a version, a rescoped rule's old +wording survives only if a person copies it somewhere, which is not a +process. Two of these pin a DELIBERATE ABSENCE. `note_versions` carries a 300-second interval gate and a 50-version cap, both defences against note autosave. Rules @@ -199,9 +199,9 @@ async def test_history_reads_newest_first(constraint): ] -# ── The read path is ACL-scoped (milestone 323 step 3) ───────────────── +# ── The read path is ACL-scoped ─────────────────────────────────────── # -# Rule 47: every read of user data is scoped by owner. A version carries a +# Every read of user data is scoped by access. A version carries a # `user_id`, which makes it tempting to scope the history by it — that would # be wrong in both directions, and these pin which way round it goes. diff --git a/tests/test_lesson_surfacing.py b/tests/test_lesson_surfacing.py index 05f27b1b..9406e081 100644 --- a/tests/test_lesson_surfacing.py +++ b/tests/test_lesson_surfacing.py @@ -1,11 +1,11 @@ -"""A lesson reaches the session it applies to — milestone 385, step 5. +"""A lesson reaches the session it applies to. Three decisions are guarded here, and each has a way of going quietly wrong that these tests are shaped to catch rather than to describe: WHICH ARM. The two note arms, and no new one. An arm that FILTERS kinds does not merely outrank a kind it omits — it makes it unreachable, and nothing - reports an arm that never had the candidate (#3702). The write path filters; + reports an arm that never had the candidate. The write path filters; the prompt menu does not, but is project-scoped, which for a kind whose whole claim is that it transfers amounts to the same silence. @@ -115,8 +115,8 @@ async def test_the_write_path_asks_for_lessons_at_all(): async def test_a_lesson_takes_a_reserved_slot_and_the_query_is_logged(): """The slot is a claim that a kind deserves a guaranteed line. A claim like that has to be falsifiable from the first deploy, which means its own query - in `retrieval_logs` — #2463's finding, recorded about the slot that shipped - without one.""" + in `retrieval_logs`; a slot without one cannot be judged against what it + displaced.""" rec = MagicMock() out, calls = await _menu( [(0.70, fake_note(id=1, title="Badge layout task", user_id=1, is_task=True))], @@ -143,7 +143,7 @@ async def test_the_reserved_lesson_extends_and_never_evicts(): """It sides with `preference_slot` over `reuse_slot`, and the reason is the ledger rather than taste: an evicted hit was RETURNED by the general search and sits in that call's log row, so displacing it makes the two tables - disagree about one call for a reason nothing in the data explains (#3668). + disagree about one call for a reason nothing in the data explains. The voice argument points the same way — a record that binds nothing should not be able to throw a better-scoring one off the menu.""" main = [(0.72, fake_note(id=1, title="a", user_id=1)), @@ -190,7 +190,7 @@ async def test_a_weak_lesson_does_not_buy_the_slot(): @pytest.mark.asyncio async def test_the_slot_surfacing_matches_its_own_retrieval_row(): - """#3668's identity, on the new arm: what a source says it retrieved and + """The two-table identity, on this arm: what a source says it retrieved and what it says it showed must be the same records. The reserved lesson is fetched by `lesson_slot`'s query, so it is `lesson_slot`'s surfacing — counting it under `auto_inject` as well would book one delivery twice and @@ -275,7 +275,7 @@ async def test_the_write_path_names_the_register_for_a_lesson_too(): def test_the_surfacing_guards_can_fail(): - """Rule 167: each assertion above has to be able to bite. The three shapes + """Each assertion above has to be able to bite. The three shapes it would take to break this feature silently, each checked here against the condition the tests actually assert on.""" # An arm that stops asking for the kind. diff --git a/tests/test_mcp_tool_notes.py b/tests/test_mcp_tool_notes.py index 6637f25a..c502b0b9 100644 --- a/tests/test_mcp_tool_notes.py +++ b/tests/test_mcp_tool_notes.py @@ -15,10 +15,10 @@ pytestmark = pytest.mark.usefixtures("_bind_user") @pytest.fixture(autouse=True) def _no_supersession(): - """Every note read/write now asks for its supersession relations (#278). + """Every note read/write asks for its supersession relations. These are unit tests of the TOOL layer and this job has no database — the - same hazard the `_fake_note` comment below records for note 2109. Stubbed + same hazard the `_fake_note` comment below records. Stubbed to "no relations", which is the state of essentially every note; the relation's own behaviour is covered in test_services_supersession.py, and the attachment is covered explicitly below. @@ -120,7 +120,7 @@ async def test_get_note_returns_dict(): # Own record: no provenance noise. assert "shared" not in out # No supersession relations: both keys ABSENT, not present-and-empty. A - # field that always says nothing trains readers to skip fields (#2483). + # field that always says nothing trains readers to skip fields. assert "supersedes" not in out assert "superseded_by" not in out @@ -218,7 +218,7 @@ async def test_update_note_only_sends_non_default_fields(): `clear` is always forwarded and is not a field: it is how this door says "unset these", and an empty one says "unset nothing". Same shape the rules - door took in #3096, and the same test that had to learn about it there.""" + door takes, and the same test.""" fake = fake_note() mock = AsyncMock(return_value=fake) with patch("scribe.mcp.tools.notes.notes_svc.update_note", mock): @@ -232,7 +232,7 @@ async def test_update_note_only_sends_non_default_fields(): @pytest.mark.asyncio async def test_update_note_forwards_a_check_but_not_an_empty_one(): """"" means "leave this alone" at this door — an agent updating a body must - not wipe a check it was never asked about (milestone 317).""" + not wipe a check it was never asked about.""" mock = AsyncMock(return_value=fake_note()) with patch("scribe.mcp.tools.notes.notes_svc.update_note", mock): await update_note(note_id=1, verify_with="curl the docs") @@ -305,7 +305,7 @@ async def test_delete_note_soft_deletes_and_returns_batch(): ): result = await delete_note(note_id=7) assert result["deleted_batch_id"] == "batch-1" - # The confirmation NAMES what went (#3273). After the delete the row is + # The confirmation NAMES what went. After the delete the row is # trashed, so this line is the last chance to say which note it was. assert result["title"] == "the note that went" assert "the note that went" in result["message"] diff --git a/tests/test_mcp_tool_systems.py b/tests/test_mcp_tool_systems.py index b60c543a..bc25ba9e 100644 --- a/tests/test_mcp_tool_systems.py +++ b/tests/test_mcp_tool_systems.py @@ -5,7 +5,7 @@ import pytest from tests.helpers import fake_note, fake_system, fake_task -# The name assessment both doors run before minting (milestone 307). A test +# The name assessment both doors run before minting. A test # that patches systems_svc wholesale must stub it, or the awaited MagicMock # raises — this shape is the "nothing matched" answer. _NO_MATCH = {"duplicate": None, "canonical": None} @@ -179,8 +179,8 @@ async def test_untagged_hint_zero_systems_prompts_first_create_and_fails_open(): @pytest.mark.asyncio async def test_untagged_hint_escalates_in_a_mature_zero_systems_project(): - """#2683: at 282 records and zero Systems (Minstrel), the generic question - had demonstrably never converted. The escalated ask must carry the + """In a mature project with zero Systems the generic question does not + convert. The escalated ask must carry the project's OWN evidence — record count and recent titles — and demand a concrete deliverable, because that is the property separating the nudges that convert from the prose that doesn't.""" @@ -190,7 +190,7 @@ async def test_untagged_hint_escalates_in_a_mature_zero_systems_project(): patch("scribe.mcp.tools.systems.notes_svc") as notes: svc.list_systems = AsyncMock(return_value=[]) notes.list_notes = AsyncMock(return_value=(recent, 282)) - # The standard names come from the GLOBAL catalog now (milestone 307), + # The standard names come from the GLOBAL catalog, # not a module constant — so the ask reads them through the service. # That the SEEDED vocabulary is these eight is migration 0087's # business, asserted against a real database in the inception @@ -203,7 +203,7 @@ async def test_untagged_hint_escalates_in_a_mature_zero_systems_project(): assert "282 records" in hint assert "Fix scrape retry backoff" in hint # the project's own evidence assert "3-6" in hint and "create_system" in hint - # NOT an approval flow (#2798): the agent mints directly, and the + # NOT an approval flow: the agent mints directly, and the # standard cross-project names carry the consistency instead. assert "without asking permission" in hint assert "propose" not in hint and "confirmed" not in hint @@ -262,7 +262,7 @@ async def test_populated_vocabulary_never_counts_records(): # The name gate's own cases (case/whitespace normalisation, exact-over-overlap, # fail-open) moved to tests/test_services_systems.py with the logic itself — -# services/systems.assess_system_name, so both doors share one answer (#2482). +# services/systems.assess_system_name, so both doors share one answer. # What stays the TOOL's job — rendering a duplicate, applying an exact area, # offering an overlap — is covered at the top of this file. @@ -345,7 +345,7 @@ async def test_add_task_log_on_untagged_project_task_asks_the_question(): notes_svc.get_note_for_user = AsyncMock(return_value=(task, "owner")) seam_svc.list_record_systems = AsyncMock(return_value=[]) seam_svc.list_systems = AsyncMock(return_value=[]) - # Young project: below the #2683 bootstrap threshold, so the mild + # Young project: below the bootstrap threshold, so the mild # question is the expected form here. seam_notes.list_notes = AsyncMock(return_value=([], 2)) from scribe.mcp.tools.tasks import add_task_log diff --git a/tests/test_preference_write_path.py b/tests/test_preference_write_path.py index f7ac662e..762c48de 100644 --- a/tests/test_preference_write_path.py +++ b/tests/test_preference_write_path.py @@ -1,14 +1,13 @@ -"""The preference write path, and how it differs from a rule's (milestone 399). +"""The preference write path, and how it differs from a rule's. WHY TWO DOORS AT ALL -`create_rule`'s docstring IS the approval gate (#3557): it tells its caller to +`create_rule`'s docstring IS the approval gate: it tells its caller to propose, offer three answers, and wait. That is right for a rule — the person a rule binds should have agreed to be bound. -A preference inverts it. The operator's framing: *"preferences are rules that -scribe can and should update during use."* A preference that asks every time -never drifts, and drifting is the whole feature. Reaching one through +A preference inverts it: it is a rule Scribe can and should update during +use. A preference that asks every time never drifts, and drifting is the whole feature. Reaching one through `create_rule(kind=..., when_to_apply="when the moment this fixture stands in for arises")` would mean reading it through the gate's prose, and the caller would hesitate over exactly the act this kind exists to make routine. @@ -18,7 +17,7 @@ So the asymmetry is the product, and these tests pin it. TWO PRESENCE CHECKS, NEVER AN ABSENCE The tempting guard is "create_preference's docstring does NOT run the approval -loop". That is the shape snippet #3352 warns against: an absence check passes +loop". That is a trap: an absence check passes against a docstring that has been deleted, emptied, or rewritten into something else entirely, and it reads as coverage while proving nothing. @@ -35,7 +34,7 @@ from tests.helpers import fake_rule, plain_rule_detail as _plain_detail from tests.helpers import tool_doc as _doc # The tool layer reads its caller from a ContextVar the HTTP transport sets. -# With no request in flight, the module binds it itself (snippet #2836). +# With no request in flight, the module binds it itself. pytestmark = pytest.mark.usefixtures("_bind_user") MODULE = "scribe.mcp.tools.rulebooks" @@ -176,7 +175,7 @@ def test_the_preference_door_says_to_write_it(): """Half two. The inverting instruction has to be PRESENT, not merely unaccompanied by a gate. - An agent that has internalised #3557 will hesitate to write or rewrite a + An agent that has internalised the rule gate will hesitate to write or rewrite a preference unless told plainly that this door is different. Silence here does not read as permission — it reads as an omission, and the caller falls back on the behaviour it already knows. @@ -194,7 +193,7 @@ def test_the_preference_door_says_to_write_it(): def test_the_preference_door_names_the_force_distinction(): - """The routing test, stated positively (rule 165). + """The routing test, stated positively. The confusion this milestone exists to fix is that a session cannot tell which kind it is holding. If the docstring stops drawing the line, the diff --git a/tests/test_snippet_location_filter.py b/tests/test_snippet_location_filter.py index 29617a67..bf6f2b26 100644 --- a/tests/test_snippet_location_filter.py +++ b/tests/test_snippet_location_filter.py @@ -1,8 +1,8 @@ -"""Tests for the snippet location reverse lookup (#2083). +"""Tests for the snippet location reverse lookup. Covers the pure half of the predicate — `location_parts`, `location_matches`, `location_jsonpath` — plus the parameter plumbing across the three surfaces -(service / REST route / MCP tool), which rule #33 requires to agree on names and +(service / REST route / MCP tool), which have to agree on names and defaults. The SQL half can only be proved against real Postgres — see @@ -56,7 +56,7 @@ def test_no_parts_matches_everything(): def test_matches_exact_repo_path_and_symbol(): data = _data({"repo": "Scribe", "path": "src/scribe/x.py", "symbol": "helper"}) assert location_matches(data, {"repo": "Scribe"}) - assert location_matches(data, {"repo": "scribe"}) # repo names: case never distinguishes (#2874) + assert location_matches(data, {"repo": "scribe"}) # repo names: case never distinguishes assert location_matches(data, {"path": "src/scribe/x.py"}) assert location_matches(data, {"symbol": "helper"}) assert location_matches(data, {"repo": "Scribe", "symbol": "helper"}) @@ -102,7 +102,7 @@ def test_blank_recorded_part_does_not_match_a_requested_one(): def test_jsonpath_filters_within_one_locations_entry(): expr = location_jsonpath({"repo": "Scribe", "symbol": "helper"}) assert expr.startswith("$.locations[*] ? (") - # repo: anchored, case-insensitive (#2874) — mirrors location_matches. + # repo: anchored, case-insensitive — mirrors location_matches. assert '@.repo like_regex "^Scribe$" flag "i"' in expr assert '@.symbol == "helper"' in expr assert " && " in expr @@ -149,7 +149,7 @@ def test_location_clause_renders_a_jsonpath_containment(): assert "data" in sql -# --- surface plumbing (rule #33) --------------------------------------------- +# --- surface plumbing --------------------------------------------------------- def test_agent_and_service_surfaces_take_the_same_location_params(): from scribe.mcp.tools.snippets import list_snippets as mcp_list diff --git a/tests/test_snippet_provenance.py b/tests/test_snippet_provenance.py index 4d8d167b..689144fc 100644 --- a/tests/test_snippet_provenance.py +++ b/tests/test_snippet_provenance.py @@ -1,10 +1,10 @@ -"""Body provenance — the cache-with-provenance half of the pointer model (#2688). +"""Body provenance — the cache-with-provenance half of the pointer model. -Decision #2686: the recorded location is the source of truth for a snippet's +The recorded location is the source of truth for a snippet's code and the stored body is a CACHE of it. `data.provenance` records what that cache is a cache OF — the commit the body was read at, and when — so staleness -becomes judgeable instead of guessed, and so the forge fetch (milestone 288 -step 5) has something to refresh. +becomes judgeable instead of guessed, and so the forge fetch has something to +refresh. The rules under test, because each has a way to rot silently: @@ -18,8 +18,8 @@ The rules under test, because each has a way to rot silently: cached body matches the source there. Unit tests cover the compose/carry logic; the integration section runs the -same rules through the real service paths on real Postgres (the #2663 lesson — -a DB-touching path with only mocked coverage is a path with no coverage). +same rules through the real service paths on real Postgres (a DB-touching path +with only mocked coverage is a path with no coverage). """ import pytest import pytest_asyncio @@ -49,7 +49,7 @@ def test_compose_provenance_stamps_sha_and_time(): def test_compose_provenance_without_a_sha_is_none_not_an_empty_record(): - # Absent provenance must stay ABSENT (the pre-#2688 semantics), never an + # Absent provenance must stay ABSENT, never an # empty dict that readers would have to distinguish from a real one. assert compose_provenance(commit_sha="") is None assert compose_provenance(commit_sha=" ") is None diff --git a/tests/test_system_charter_search.py b/tests/test_system_charter_search.py index bc91f231..d6583a10 100644 --- a/tests/test_system_charter_search.py +++ b/tests/test_system_charter_search.py @@ -1,4 +1,4 @@ -"""Systems become findable by meaning — the charter as an ANSWER (#4251). +"""Systems become findable by meaning — the charter as an ANSWER. A System's `description` is a charter: several hundred words saying what belongs in that area and what does not. It is the answer to "where does this @@ -20,7 +20,7 @@ from tests.helpers import make_mock_session def _system(system_id=3, name="Retrieval & recall", description="the charter"): s = MagicMock(id=system_id, project_id=2, description=description) - s.name = name # never via the constructor — see note #2833 + s.name = name # never via the constructor: `name` names the mock return s @@ -65,8 +65,7 @@ def _rows_ctx(rows): async def test_the_search_collapses_to_best_chunk_and_reports_which_one_won(): """A charter is long, and a result shows its NAME — so the paragraph that actually decides where a record belongs has to come back with it, or the - caller judges from two words that cannot say (#4243). Published from the - start here rather than retrofitted, which is what #4251 asked for.""" + caller judges from two words that cannot say.""" a, b = _system(3), _system(4, name="Data Model") rows = [ (a, 0.10, 2, "retrieval telemetry belongs here"), @@ -94,7 +93,7 @@ async def test_the_search_collapses_to_best_chunk_and_reports_which_one_won(): @pytest.mark.asyncio async def test_a_project_the_caller_cannot_read_returns_nothing(): - """Rule 78 — the charter of a project someone was not given is not an + """The charter of a project someone was not given is not an answer to any question they are entitled to ask.""" _session, ctx = _rows_ctx([]) with (