"""Real-Postgres tests for WHICH rules reach a session (milestone 307 step 5, narrowed by 394). What mocks can't prove, and what this design must not get wrong: 1. A rule is invisible to a project that doesn't work in its area, and arrives — binding, not suggested — to one that does. Area matching is DETERMINISTIC: a tag comparison, never a similarity score. 2. A `co_surfaces` partner arrives with its other half, which is the failure that made merging rule 144 into rule 46 look like the only fix. 3. An explicit suppression outranks an edge. TWO CLAIMS WERE DROPPED HERE BY MILESTONE 394, and it is worth saying which rather than leaving a shorter list. "A rule with no tier binds exactly as before" and "a conditional rule is reachable, not resident" were both about the always-on tier. There is no tier and no resident payload, so neither states anything that can now be true or false — they were not failing, they had stopped being claims. """ import pytest import pytest_asyncio from scribe.models import async_session from scribe.models.project import Project from scribe.services import canonical_systems as canonical_svc from scribe.services import rulebooks as rulebooks_svc from scribe.services import systems as systems_svc from tests.helpers import ensure_user pytestmark = [pytest.mark.integration, pytest.mark.usefixtures("_dispose_engine")] @pytest_asyncio.fixture async def world(): """A project with two rulebooks — one subscribed, one not. Both are ordinary rulebooks since milestone 394; the fixture used to flag one always-on because that was a second, separate way to reach a project. Keeping two is still worth it: a rulebook nobody subscribed to must contribute nothing, and a fixture with only the subscribed one could not tell "correctly scoped" from "returns everything". """ async with async_session() as s: owner = await ensure_user(s, "surfacing_owner") project = Project(user_id=owner.id, title="Surfacing target") s.add(project) await s.flush() ids = {"owner": owner.id, "pid": project.id} await s.commit() always = await rulebooks_svc.create_rulebook(ids["owner"], "Family standards") always_topic = await rulebooks_svc.create_topic(always.id, ids["owner"], "git") await rulebooks_svc.create_rule( always_topic.id, ids["owner"], "dev is home", "Work on dev.", ) book = await rulebooks_svc.create_rulebook(ids["owner"], "Subscribed practices") topic = await rulebooks_svc.create_topic(book.id, ids["owner"], "release") plain = await rulebooks_svc.create_rule( topic.id, ids["owner"], "Between batches, keep stacking", "Keep going.", ) await rulebooks_svc.subscribe_project( project_id=ids["pid"], rulebook_id=book.id, user_id=ids["owner"], ) ids.update({ "always": always.id, "always_topic": always_topic.id, "book": book.id, "topic": topic.id, "plain": plain.id, }) return ids async def _titles(ids) -> set[str]: applicable = await rulebooks_svc.get_applicable_rules(ids["pid"], ids["owner"]) return {r["title"] for r in applicable["rules"]} @pytest.mark.integration async def test_a_conditional_rule_binds_a_project_that_works_in_its_area(world): """The payoff: the tag match carries it in deterministically. The project reaches the area through its own System's canonical_id — its local NAME is irrelevant, which is the whole reason the catalog exists.""" area = await canonical_svc.find_by_name("CI & Release") assert area is not None, "migration 0087 seeds the standard vocabulary" rule = await rulebooks_svc.create_rule( world["topic"], world["owner"], "Release tagging", "Derive the tag.", when_to_apply="when cutting a release", ) await rulebooks_svc.set_rule_systems(rule.id, world["owner"], [area.id]) # Still absent: the project has no Systems at all yet. assert "Release tagging" not in await _titles(world) # The project names the area with its OWN word, mapped to the same canon. local = await systems_svc.create_system( world["owner"], world["pid"], "CI & runners", description="ours", ) await canonical_svc.set_system_canonical(world["owner"], local.id, area.id) surfaced = await rulebooks_svc.get_applicable_rules(world["pid"], world["owner"]) hit = [r for r in surfaced["rules"] if r["title"] == "Release tagging"] assert hit, "a tagged conditional rule must bind a project working in that area" assert [s["name"] for s in hit[0]["systems"]] == ["CI & Release"] @pytest.mark.integration async def test_co_surfaces_drags_in_the_half_that_would_have_been_missed(world): """Rule 144 was split off rule 46 and folded back the same day because "either rule could surface without the other". This is the edge that makes that unnecessary: the partner arrives even though nothing else selected it, and says why it is here.""" partner = await rulebooks_svc.create_rule( world["topic"], world["owner"], "Version names are labels", "A name decides nothing.", when_to_apply="when naming a build", ) # TAGGED TO AN AREA THIS PROJECT DOES NOT WORK IN, which is what makes the # test able to fail at all. Since milestone 394 an UNTAGGED rule in a # subscribed rulebook applies on its own, so an untagged partner arrives # through the ordinary query and the edge is never exercised — the # assertion below passed while proving nothing, which is how this was # noticed. Tagging it puts it out of reach of everything except the edge. area = await canonical_svc.find_by_name("CI & Release") assert area is not None, "migration 0087 seeds the standard vocabulary" await rulebooks_svc.set_rule_systems(partner.id, world["owner"], [area.id]) assert "Version names are labels" not in await _titles(world), ( "the partner must be unreachable on its own, or this test cannot fail" ) await rulebooks_svc.add_rule_relation( world["owner"], world["plain"], partner.id, "co_surfaces", note="they fail together", ) surfaced = await rulebooks_svc.get_applicable_rules(world["pid"], world["owner"]) hit = [r for r in surfaced["rules"] if r["title"] == "Version names are labels"] assert hit, "a co_surfaces partner must arrive with its other half" assert hit[0]["via"] == "co_surfaces" @pytest.mark.integration async def test_a_suppression_outranks_an_edge(world): """The edge says these belong together; the suppression says this project does not want that one. An explicit decision beats an inferred one.""" # Untagged on purpose, unlike the partner above: this test is about the # SUPPRESSION winning, so the partner should be one that would otherwise # arrive by every available route — the ordinary query AND the edge. partner = await rulebooks_svc.create_rule( world["topic"], world["owner"], "Muted partner", "Should not arrive.", ) await rulebooks_svc.add_rule_relation( world["owner"], world["plain"], partner.id, "co_surfaces", ) await rulebooks_svc.suppress_rule_for_project( world["pid"], partner.id, world["owner"], ) surfaced = await rulebooks_svc.get_applicable_rules(world["pid"], world["owner"]) assert "Muted partner" not in {r["title"] for r in surfaced["rules"]}