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 <noreply@anthropic.com>
This commit is contained in:
2026-10-21 21:33:08 -04:00
co-authored by Claude Opus 5.5
parent fa41e006a7
commit ead4a7e2ad
10 changed files with 69 additions and 74 deletions
+7 -7
View File
@@ -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