"""Real-Postgres tests for WHICH rules a project's listing names (milestone 307 step 5, narrowed by 394 and 414). A session receives rules by retrieval, scoped by a rule's home (see test_integration_rule_scope). This is the other surface — the listing a planning read carries — and what mocks can't prove about it: 1. A global rule tagged to an area arrives in the listing of a project that works in that area, and not before. Area matching is DETERMINISTIC: a tag comparison, never a similarity score. 2. An UNTAGGED global rule is not listed: it applies everywhere and arrives by retrieval, and listing every one under every project would say nothing. 3. A `co_surfaces` partner arrives with its other half — the failure that made merging rule 144 into rule 46 look like the only fix — unless the partner lives on a different project, because an edge is not a way in. Milestone 414 dropped the suppression claim ("an explicit suppression outranks an edge") with suppressions themselves. """ 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 one rule of its own, and a rulebook of global rules.""" async with async_session() as s: owner = await ensure_user(s, "surfacing_owner") project = Project(user_id=owner.id, title="Surfacing target") elsewhere = Project(user_id=owner.id, title="Another project") s.add_all([project, elsewhere]) await s.flush() ids = {"owner": owner.id, "pid": project.id, "elsewhere": elsewhere.id} await s.commit() book = await rulebooks_svc.create_rulebook(ids["owner"], "Family standards") topic = await rulebooks_svc.create_topic(book.id, ids["owner"], "release") await rulebooks_svc.create_rule( topic.id, ids["owner"], "dev is home", "Work on dev.", when_to_apply="before pushing a branch", ) own = await rulebooks_svc.create_project_rule( ids["pid"], ids["owner"], "Between batches, keep stacking", "Keep going.", when_to_apply="when a batch goes green", ) ids.update({"book": book.id, "topic": topic.id, "own": own.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_an_untagged_global_rule_is_not_listed(world): """It applies here — and everywhere — so naming it under this project says nothing a reader can act on. The project's own rule is always listed.""" applicable = await rulebooks_svc.get_applicable_rules(world["pid"], world["owner"]) assert "dev is home" not in await _titles(world) assert [r["title"] for r in applicable["project_rules"]] == [ "Between batches, keep stacking"] @pytest.mark.integration async def test_a_tagged_global_rule_is_listed_for_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 global rule must be listed for 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, so nothing but the edge # can bring it in — otherwise this test could pass without 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["own"], 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_an_edge_is_not_a_way_into_another_project(world): """A partner that lives on a different project belongs to that project. The edge says the two fail together; it does not make one project's rule apply to another.""" foreign = await rulebooks_svc.create_project_rule( world["elsewhere"], world["owner"], "Another project's rule", "Not here.", when_to_apply="working on the other project", ) await rulebooks_svc.add_rule_relation( world["owner"], world["own"], foreign.id, "co_surfaces", ) surfaced = await rulebooks_svc.get_applicable_rules(world["pid"], world["owner"]) assert "Another project's rule" not in {r["title"] for r in surfaced["rules"]}