"""The self-authored skill finalization gate of ``ouroboros.loop``. Split out of ``tests/test_loop_misc.py`` when that module was divided by theme; every moved block is verbatim. """ from __future__ import annotations import json from ouroboros.loop_nudges import _skill_finalization_message, _skill_names_touched_by_trace from ouroboros.skill_loader import ( SkillReviewState, compute_content_hash, save_enabled, save_review_state, ) # --------------------------------------------------------------------------- # Skill finalization gate (self-authored skills must reach ready+enabled # before the loop accepts a final text response) # --------------------------------------------------------------------------- def _write_self_authored_skill(drive_root, name: str = "alpha"): skill_dir = drive_root / "skills" / "external" / name state_dir = drive_root / "state" / "skills" / name skill_dir.mkdir(parents=True) state_dir.mkdir(parents=True) (skill_dir / "SKILL.md").write_text( "---\nname: alpha\ntype: instruction\nversion: 0.1.0\n---\nbody\n", encoding="utf-8", ) marker = { "schema_version": 1, "origin": "self_authored", "task_id": "task-1", "created_at": "2026-05-07T00:00:00+00:00", } (skill_dir / ".self_authored.json").write_text(json.dumps(marker), encoding="utf-8") (state_dir / "self_authored.json").write_text(json.dumps(marker), encoding="utf-8") return skill_dir def test_skill_names_touched_by_trace_detects_data_skill_edits(): trace = { "tool_calls": [ {"tool": "write_file", "args": {"path": "skills/external/alpha/plugin.py"}}, {"tool": "edit_text", "args": {"path": "data/skills/external/beta/SKILL.md"}}, {"tool": "write_file", "args": {"path": "SKILL.md", "bucket": "external", "skill_name": "delta"}}, ] } assert _skill_names_touched_by_trace(trace) == ["alpha", "beta", "delta"] def test_skill_finalization_message_blocks_unreviewed_self_authored_skill(tmp_path): drive_root = tmp_path / "drive" drive_root.mkdir() _write_self_authored_skill(drive_root) trace = {"tool_calls": [{"tool": "write_file", "args": {"path": "skills/external/alpha/SKILL.md"}}]} message = _skill_finalization_message(drive_root, trace) assert "SKILL_NOT_FINALIZED" in message assert "alpha" in message def test_skill_finalization_message_sees_real_skill_payload_selectors(tmp_path): drive_root = tmp_path / "drive" drive_root.mkdir() _write_self_authored_skill(drive_root) for tool, selector in ( ("run_command", {"cmd": ["true"], "cwd": "skill_payload"}), ("run_script", {"script": "pass", "cwd": "skill_payload/scripts"}), ("delegate_start", {"prompt": "repair", "root": "skill_payload"}), ): trace = {"tool_calls": [{"tool": tool, "args": { **selector, "bucket": "external", "skill_name": "alpha", }}]} assert "alpha" in _skill_finalization_message(drive_root, trace) def test_skill_finalization_message_allows_ready_self_authored_skill(tmp_path): drive_root = tmp_path / "drive" drive_root.mkdir() skill_dir = _write_self_authored_skill(drive_root) content_hash = compute_content_hash(skill_dir) save_review_state(drive_root, "alpha", SkillReviewState(status="pass", content_hash=content_hash)) save_enabled(drive_root, "alpha", True) trace = {"tool_calls": [{"tool": "write_file", "args": {"path": "skills/external/alpha/SKILL.md"}}]} assert _skill_finalization_message(drive_root, trace) == ""