fix(systems): the bootstrap ask reads the catalog, so its test must supply one (#3027)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 26s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 1m20s
CI & Build / Build & push image (push) Successful in 38s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / integration (push) Successful in 26s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 1m20s
CI & Build / Build & push image (push) Successful in 38s
CI caught the seam the promotion opened: the standard names now come from an async catalog read, and the unit test patches systems_svc wholesale — so the read raised, the fail-open swallowed it, and the ask shipped without the names it is supposed to carry. Stub standard_systems in that test, and assert the wiring rather than the vocabulary: THAT the seeded set is these eight is migration 0087's business and belongs in the inception integration test, against a real database. Adds the case the promotion actually created — an unreachable or empty catalog must still produce the ask. The names are an aid to the question, not the question; degrading to a weaker nudge is fine, going silent is not. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,15 @@ async def test_untagged_hint_escalates_in_a_mature_zero_systems_project():
|
|||||||
patch("scribe.mcp.tools.systems.notes_svc") as notes:
|
patch("scribe.mcp.tools.systems.notes_svc") as notes:
|
||||||
svc.list_systems = AsyncMock(return_value=[])
|
svc.list_systems = AsyncMock(return_value=[])
|
||||||
notes.list_notes = AsyncMock(return_value=(recent, 282))
|
notes.list_notes = AsyncMock(return_value=(recent, 282))
|
||||||
|
# The standard names come from the GLOBAL catalog now (milestone 307),
|
||||||
|
# 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
|
||||||
|
# integration test; what belongs here is that whatever the catalog
|
||||||
|
# holds reaches the ask verbatim.
|
||||||
|
svc.standard_systems = AsyncMock(return_value=[
|
||||||
|
("CI & Release", "..."), ("Auth & Access", "..."),
|
||||||
|
])
|
||||||
hint = await untagged_systems_hint(1, 5)
|
hint = await untagged_systems_hint(1, 5)
|
||||||
assert "282 records" in hint
|
assert "282 records" in hint
|
||||||
assert "Fix scrape retry backoff" in hint # the project's own evidence
|
assert "Fix scrape retry backoff" in hint # the project's own evidence
|
||||||
@@ -126,6 +135,25 @@ async def test_untagged_hint_escalates_in_a_mature_zero_systems_project():
|
|||||||
assert "no Systems yet" not in hint
|
assert "no Systems yet" not in hint
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_bootstrap_ask_still_asks_when_the_catalog_is_unreachable():
|
||||||
|
"""The standard names are an AID to the question, not the question. If the
|
||||||
|
catalog read fails (or an install has an empty one), the ask must still
|
||||||
|
carry the project's evidence and demand the same deliverable — degrading to
|
||||||
|
a weaker nudge is acceptable, going silent is not."""
|
||||||
|
from scribe.mcp.tools.systems import untagged_systems_hint
|
||||||
|
recent = [fake_note(title="Fix scrape retry backoff")]
|
||||||
|
with patch("scribe.mcp.tools.systems.systems_svc") as svc, \
|
||||||
|
patch("scribe.mcp.tools.systems.notes_svc") as notes:
|
||||||
|
svc.list_systems = AsyncMock(return_value=[])
|
||||||
|
notes.list_notes = AsyncMock(return_value=(recent, 282))
|
||||||
|
svc.standard_systems = AsyncMock(side_effect=RuntimeError("db down"))
|
||||||
|
hint = await untagged_systems_hint(1, 5)
|
||||||
|
assert hint is not None
|
||||||
|
assert "282 records" in hint and "create_system" in hint
|
||||||
|
assert "3-6" in hint and "without asking permission" in hint
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_bootstrap_ask_stays_quiet_below_threshold_and_fails_open():
|
async def test_bootstrap_ask_stays_quiet_below_threshold_and_fails_open():
|
||||||
from scribe.mcp.tools import systems as tools
|
from scribe.mcp.tools import systems as tools
|
||||||
|
|||||||
Reference in New Issue
Block a user