"""How family canon reaches a session (milestone 463 step 6), without a database: the line enter_project carries, the skill and its triggers, and the pointers every other surface gives to it. Retrieval reach, the readout's counts and the owed answers against Postgres are in tests/test_integration_family_reach.py. """ from __future__ import annotations import pathlib import re from scribe.services import moment_actions from scribe.services.family_adoption import family_line from tests.helpers import skill_text, tool_doc ROOT = pathlib.Path(__file__).resolve().parents[1] def _cell(status="unassessed", *, in_scope=True, needs_recheck=False): return {"status": status, "in_scope": in_scope, "needs_recheck": needs_recheck} # --- the enter_project line ---------------------------------------------------------- def test_nothing_to_answer_is_no_line(): assert family_line(5, []) is None assert family_line(5, [_cell("adopted"), _cell("exempt")]) is None def test_the_line_counts_each_ask_and_names_the_call_that_lists_it(): line = family_line(5, [ _cell(), _cell(), _cell("owed"), _cell("adopted", needs_recheck=True), ]) assert (line["unassessed"], line["owed"], line["needs_recheck"]) == (2, 1, 1) assert line["line"].endswith("2 unassessed · 1 owed · 1 to recheck") assert line["calls"] == { "unassessed": 'list_family_adoptions(project_id=5, status="unassessed")', "owed": 'list_family_adoptions(project_id=5, status="owed")', "needs_recheck": "list_family_adoptions(project_id=5, needs_recheck=true)", } assert "family-canon" in line["answer_with"] def test_a_count_of_zero_names_no_call(): line = family_line(5, [_cell("owed")]) assert set(line["calls"]) == {"owed"} and "unassessed" not in line["line"] def test_an_answer_kept_as_history_off_the_platform_is_not_asked_again(): """A row whose project left the idea's platforms stays as history; an unassessed one there is not something this project is asked for.""" assert family_line(5, [_cell(in_scope=False)]) is None # --- the skill ---------------------------------------------------------------------- def _frontmatter(name: str) -> str: text = (ROOT / "plugin" / "skills" / name / "SKILL.md").read_text() return re.match(r"\A---\n(.*?)\n---\n", text, re.S).group(1) def test_the_family_canon_skill_ships_and_triggers_on_what_the_server_sends(): """Its description is what makes a session load it, so it names every key the server hands back about family canon.""" front = _frontmatter("family-canon") assert "name: family-canon" in front for trigger in ("family_hint", "`family`", "family_owed", "enter_project"): assert trigger in front, trigger assert moment_actions.BUNDLED_SKILL_MOMENTS["family-canon"] == ("work.record",) def test_the_skill_carries_the_reflexes_and_defers_the_lists_to_the_tools(): text = " ".join(skill_text("family-canon").split()) for phrase in ("one criterion with no support vetoes it", "in the order `assess_family_adoption` lists them", "every ground above it must be said not to apply", "What counts as a reason", "The precedent reflex"): assert phrase in text, phrase def test_the_plugin_names_the_skill_it_ships(): manifest = (ROOT / "plugin" / ".claude-plugin" / "plugin.json").read_text() static = (ROOT / "plugin" / "hooks" / "scribe_static_context.md").read_text() assert "family-canon" in manifest and "family-canon" in " ".join(static.split()) # --- the pointers --------------------------------------------------------------------- def test_every_surface_that_meets_family_canon_points_at_the_skill(): server = (ROOT / "src" / "scribe" / "mcp" / "server.py").read_text() index = re.search(r'_INSTRUCTIONS = """(.*?)"""', server, re.S).group(1) assert "family-canon" in index and "`family`" in index for module, tool in (("notes", "create_note"), ("snippets", "create_snippet"), ("shapes", "classify_shapes")): assert "family-canon" in tool_doc(f"scribe.mcp.tools.{module}", tool), tool assert "family_hint" in tool_doc("scribe.mcp.tools.notes", "create_note") assert "`family`" in tool_doc("scribe.mcp.tools.projects", "enter_project") assert "family_owed" in tool_doc("scribe.mcp.tools.tasks", "update_task") assert "family_owed" in skill_text("reporting-back")