mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-03 04:07:04 +00:00
Second parent is the frozen upstream `ouroboros` head (23ab428f, 407 commits since the merge basea76961de); 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).
90 lines
3.5 KiB
Python
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) == ""
|