ouroboros/tests/test_loop_skill_finalization.py
Ouroboros 9698e2e077 Merge upstream ouroboros 23ab428f into the v7 line: absorb 407 commits into the module split
Second parent is the frozen upstream `ouroboros` head (23ab428f, 407 commits
since the merge base a76961de); first parent is v7.0.0-rc.8 (18b9832e).

Every upstream change lands in v7's owning leaf: S1 transplants keep upstream's
bodies (comments verbatim) under the call-time handle idiom, S2 hand-merges keep
both intents, S3 keeps v7 only with proof (retired 7.0 ABI surfaces, superseded
mechanisms). Per-symbol relocation ledger: docs/archive/v7next/LEDGER_CORRECTIONS.md
(F2 absorption section). Provisional decisions awaiting owner ratification:
D-18 (two-destination symbols), D-19 (acceptance rows follow upstream R2),
D-20 (acceptance_dialogue stays deleted), D-21 (tools/registry.py: facade
import block only).

Docs: upstream ARCHITECTURE/DEVELOPMENT as the base with compact v7 deltas;
bookkeeping moved to docs/archive/v7next. Size-ratchet manifest, domain
manifest and generated inventories regenerated; new leaves: tools/write_shape
walker, gateway/cost_breakdown, tools/core_secret_paths; provider_catalogs.py
and acceptance_dialogue.py removed (v7 owners).
2026-09-04 19:32:55 +00:00

90 lines
3.5 KiB
Python

"""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) == ""