ouroboros/tests/test_v6600_answer_protocol.py
Ouroboros c0d424b888 fix(v6.61.2): 3-OS test portability for the v6.61.1 hardening suites
Four Windows-runner failures in the v6.61.1 release matrix, all TEST-side
(runtime code unchanged; macOS/Linux/local green throughout):

- test_verify_and_record_handler_artifact_and_declared: the traversal probe
  used six `..` segments, which on Windows runners (pytest tmp nested ~7 levels
  under the user home) landed INSIDE the home tree — where the deliberate
  user_files read lane makes an artifact probe an honest miss rather than a
  refusal. The probe now escapes to the filesystem root on every OS.
- test_bytes_equal_confines_operands: same root cause for the relative-traversal
  operand; the test now jails OUROBOROS_USER_FILES_ROOT into the workspace so
  every confinement refusal is deterministic cross-OS.
- test_checkpoint_commit_coop_roots_commits_dirty_tree_and_skips_secrets: the
  git-log read decoded with the Windows ANSI code page, mangling the em-dash in
  the checkpoint subject; encoding="utf-8" pinned.
- test_resolve_room_workspace_loud_fails_on_broken_working_dir: rmtree of a git
  tree hits WinError 5 on read-only object files; chmod-and-retry onerror
  handler added.

README patch-row cap kept at 5 (6.54.1 rolled off); all version carriers bumped
to 6.61.2.
2026-07-09 13:30:13 +03:00

367 lines
16 KiB
Python

"""v6.60.0 (Phase 4) — answer protocol (contract-gated FINAL ANSWER), blocking
widening, and the bytes_equal verification mode.
"""
from __future__ import annotations
import pathlib
from ouroboros.contracts.task_contract import (
answer_protocol_active,
build_task_contract,
normalize_answer_protocol,
)
# --- 4.1 contract field ---------------------------------------------------------
def test_normalize_answer_protocol_closed_enum():
assert normalize_answer_protocol("final_answer_line") == "final_answer_line"
assert normalize_answer_protocol("FINAL_ANSWER_LINE") == "final_answer_line"
assert normalize_answer_protocol("") == ""
assert normalize_answer_protocol(None) == ""
assert normalize_answer_protocol("bogus") == "" # unknown -> no protocol, never an instruction
def test_contract_carries_answer_protocol_and_inherits_via_metadata():
contract = build_task_contract({"description": "x", "answer_protocol": "final_answer_line"})
assert contract["answer_protocol"] == "final_answer_line"
# metadata path (the subagent/CLI --task-metadata-json route)
contract_meta = build_task_contract({"description": "x", "metadata": {"answer_protocol": "final_answer_line"}})
assert contract_meta["answer_protocol"] == "final_answer_line"
# default: no protocol
assert build_task_contract({"description": "x"})["answer_protocol"] == ""
def test_answer_protocol_active_gate_reads_ctx_and_dicts():
from types import SimpleNamespace
assert answer_protocol_active({"answer_protocol": "final_answer_line"}) is True
assert answer_protocol_active({"answer_protocol": ""}) is False
ctx = SimpleNamespace(task_contract={"answer_protocol": "final_answer_line"}, task_metadata={})
assert answer_protocol_active(ctx) is True
ctx2 = SimpleNamespace(task_contract={}, task_metadata={"task_contract": {"answer_protocol": "final_answer_line"}})
assert answer_protocol_active(ctx2) is True
assert answer_protocol_active(SimpleNamespace(task_contract={}, task_metadata={})) is False
def test_context_injects_protocol_rule_only_when_declared(tmp_path):
from ouroboros.context import build_runtime_section
class _Env:
repo_dir = str(tmp_path)
drive_root = tmp_path
task_with = {"id": "t1", "task_contract": {"answer_protocol": "final_answer_line"}}
task_without = {"id": "t2", "task_contract": {}}
with_rule = build_runtime_section(_Env(), task_with)
without_rule = build_runtime_section(_Env(), task_without)
assert "FINAL ANSWER" in with_rule
assert "answer_protocol" in with_rule
assert "FINAL ANSWER" not in without_rule
def test_system_prompt_carries_no_marker_doctrine():
"""The SYSTEM.md marker rule moved to the per-task contract: the default prompt
must NOT instruct every task to emit FINAL ANSWER lines. Whitespace-NORMALIZED
check (adversarial r1: a line-wrapped 'FINAL\\nANSWER' slipped past the plain
substring assert — the guard must be wrap-insensitive)."""
text = (pathlib.Path(__file__).resolve().parents[1] / "prompts" / "SYSTEM.md").read_text(encoding="utf-8")
normalized = " ".join(text.split())
assert "FINAL ANSWER" not in normalized
assert "CANDIDATES:" not in normalized
def test_pacing_marker_phrases_are_protocol_gated():
from types import SimpleNamespace
from ouroboros.task_pacing import build_intrinsic_pacing_note
from ouroboros.deadline_utils import utc_now
import datetime
created = utc_now() - datetime.timedelta(minutes=90)
def _note(ctx):
return build_intrinsic_pacing_note(
ctx, created=created, now=utc_now(), round_idx=5, accumulated_usage={"cost": 1.0},
)
plain = SimpleNamespace(task_contract={}, task_metadata={})
note_plain = _note(plain)
assert note_plain is not None and "FINAL ANSWER" not in note_plain.text
protocol = SimpleNamespace(task_contract={"answer_protocol": "final_answer_line"}, task_metadata={})
note_protocol = _note(protocol)
assert note_protocol is not None and "FINAL ANSWER" in note_protocol.text
# --- 4.2 blocking widening --------------------------------------------------------
def _result(signal, findings, tiers=("solved",)):
from types import SimpleNamespace
actors = [
{"slot_id": f"s{i}", "signal": signal, "parsed": {"outcome_tier": tier}}
for i, tier in enumerate(tiers)
]
return SimpleNamespace(aggregate_signal=signal, actors=actors, parsed_findings=findings)
def test_obligations_widen_to_high_only_on_failing_aggregate():
from ouroboros.loop import _collect_acceptance_obligations
high_finding = {"severity": "high", "slot_id": "s0", "item": "missed requirement", "recommendation": "implement X"}
critical_finding = {"severity": "critical", "slot_id": "s0", "item": "broken", "recommendation": "fix Y"}
# PASS aggregate: high findings do NOT become obligations (critical-only bar).
trace_pass = {}
_collect_acceptance_obligations(trace_pass, _result("PASS", [high_finding, critical_finding]))
items = {o["item"] for o in trace_pass["acceptance_obligations"]}
assert items == {"broken"}
# FAIL aggregate: high + critical both become obligations.
trace_fail = {}
_collect_acceptance_obligations(trace_fail, _result("FAIL", [high_finding, critical_finding]))
items_fail = {o["item"] for o in trace_fail["acceptance_obligations"]}
assert items_fail == {"missed requirement", "broken"}
# blocked_with_evidence tier (even on non-FAIL signal): widened too.
trace_blocked = {}
_collect_acceptance_obligations(
trace_blocked, _result("PASS", [high_finding], tiers=("blocked_with_evidence",))
)
assert {o["item"] for o in trace_blocked["acceptance_obligations"]} == {"missed requirement"}
def test_verdict_is_advisory_flag_is_gone():
"""The dead policy KEY is removed from every ReviewRequest (comments may still
name it historically); enforcement semantics live in OUROBOROS_REVIEW_ENFORCEMENT."""
hits = []
for path in (pathlib.Path(__file__).resolve().parents[1] / "ouroboros").rglob("*.py"):
if '"verdict_is_advisory":' in path.read_text(encoding="utf-8", errors="replace"):
hits.append(str(path))
assert hits == [], f"dead policy key still set in: {hits}"
# --- 4.3 bytes_equal ---------------------------------------------------------------
def _bytes_equal_ctx(tmp_path):
"""A real ToolContext whose active workspace holds the compared files —
bytes_equal operands are CONFINED (adversarial r1), so the mechanics tests
run against workspace-resident files like real callers do."""
from ouroboros.tools.registry import ToolContext
work = tmp_path / "ws"
work.mkdir(exist_ok=True)
drive = tmp_path / "drive"
drive.mkdir(exist_ok=True)
return ToolContext(repo_dir=work, drive_root=drive, task_id="t"), work
def test_bytes_equal_compare(tmp_path):
from ouroboros.tools.verify import _compare_files_bytes_equal
ctx, work = _bytes_equal_ctx(tmp_path)
a = work / "a.bin"
b = work / "b.bin"
a.write_bytes(b"hello world" * 100)
b.write_bytes(b"hello world" * 100)
equal, detail = _compare_files_bytes_equal(ctx, [str(a), str(b)], work, use_executor=False)
assert equal is True and "==" in detail
# Introduce a one-byte divergence mid-file; the detail names the offset + hexdump.
data = bytearray(b"hello world" * 100)
data[500] = 0x00
b.write_bytes(bytes(data))
equal2, detail2 = _compare_files_bytes_equal(ctx, [str(a), str(b)], work, use_executor=False)
assert equal2 is False
assert "offset 500" in detail2 and "@" in detail2
# Size mismatch (prefix case).
b.write_bytes(b"hello world")
equal3, detail3 = _compare_files_bytes_equal(ctx, [str(a), str(b)], work, use_executor=False)
assert equal3 is False and "sizes" in detail3
# Missing file is a fail, not an exception.
equal4, detail4 = _compare_files_bytes_equal(ctx, [str(a), str(work / "nope")], work, use_executor=False)
assert equal4 is False and "not found" in detail4
# Relative paths resolve against the workspace.
b.write_bytes(a.read_bytes())
equal5, _ = _compare_files_bytes_equal(ctx, ["a.bin", "b.bin"], work, use_executor=False)
assert equal5 is True
def test_bytes_equal_confines_operands(tmp_path, monkeypatch):
"""Adversarial r1 hard blocker: the comparison is a byte-read oracle (sizes +
divergence hexdump), so BOTH operands must clear the same confinement every
other artifact-path surface enforces — no control-plane, no arbitrary host
files, no protected black-box references, no absolute/traversal paths in-executor.
The user_files root is JAILED into the workspace so the refusals are
deterministic on every OS (Windows runners put pytest tmp INSIDE the user
home, where the deliberate user_files lane would otherwise admit tmp siblings)."""
from ouroboros.tools.verify import _compare_files_bytes_equal
ctx, work = _bytes_equal_ctx(tmp_path)
monkeypatch.setenv("OUROBOROS_USER_FILES_ROOT", str(work))
inside = work / "golden.bin"
inside.write_bytes(b"data")
# Arbitrary host file (outside workspace + home): refused, no size/hexdump leak.
equal, detail = _compare_files_bytes_equal(
ctx, ["/etc/passwd", str(inside)], work, use_executor=False
)
assert equal is False and "refused" in detail
assert "sizes" not in detail and "@" not in detail
# Control-plane (the data drive) is refused even though it exists on disk.
secret = pathlib.Path(ctx.drive_root) / "settings.json"
secret.write_text("{}", encoding="utf-8")
equal2, detail2 = _compare_files_bytes_equal(
ctx, [str(secret), str(inside)], work, use_executor=False
)
assert equal2 is False and "refused" in detail2
# Relative traversal out of the workspace: refused.
outside = tmp_path / "outside.bin"
outside.write_bytes(b"data")
equal3, detail3 = _compare_files_bytes_equal(
ctx, ["../outside.bin", str(inside)], work, use_executor=False
)
assert equal3 is False and "refused" in detail3
# Executor surface: absolute and traversing operands are refused BEFORE any cmp
# runs (same rule as _probe_artifact_lifecycle — no hidden-grader oracle).
equal4, detail4 = _compare_files_bytes_equal(
ctx, ["/hidden/tests/expected.bin", "golden.bin"], work, use_executor=True
)
assert equal4 is False and "workspace-relative" in detail4
equal5, detail5 = _compare_files_bytes_equal(
ctx, ["golden.bin", "../peer/graded.bin"], work, use_executor=True
)
assert equal5 is False and "workspace-relative" in detail5
def test_bytes_equal_user_files_lane_is_deliberate(tmp_path, monkeypatch):
"""Claudexor final-review adjudication pinned as a contract: an in-home file
that clears the user_files guard IS a valid bytes_equal operand (the agent's
profiles already grant full user_files READ — a size/hexdump is weaker), while
a bench-style OUROBOROS_USER_FILES_ROOT jail confines the lane: the same
outside-jail path refuses."""
from ouroboros.tools.verify import _compare_files_bytes_equal
ctx, work = _bytes_equal_ctx(tmp_path)
inside = work / "golden.bin"
inside.write_bytes(b"data")
# Simulate "in-home, non-secret" by pointing the user_files root at tmp_path:
# the sibling file clears the guard → comparable (deliberate lane).
monkeypatch.setenv("OUROBOROS_USER_FILES_ROOT", str(tmp_path))
owner_file = tmp_path / "owner_notes.bin"
owner_file.write_bytes(b"data")
equal, detail = _compare_files_bytes_equal(
ctx, [str(owner_file), str(inside)], work, use_executor=False
)
assert equal is True and "refused" not in detail
# Jail the user_files root elsewhere: the SAME operand now refuses (bench shape).
jail = tmp_path / "jail"
jail.mkdir()
monkeypatch.setenv("OUROBOROS_USER_FILES_ROOT", str(jail))
equal2, detail2 = _compare_files_bytes_equal(
ctx, [str(owner_file), str(inside)], work, use_executor=False
)
assert equal2 is False and "refused" in detail2
def test_bytes_equal_refuses_protected_black_box_reference(tmp_path):
"""A black-box reference binary must stay byte-opaque: comparing it IS reading
its bytes, so the protected-artifacts read_bytes denial applies."""
from ouroboros.tools.registry import ToolContext
from ouroboros.tools.verify import _compare_files_bytes_equal
work = tmp_path / "ws"
work.mkdir()
drive = tmp_path / "drive"
drive.mkdir()
ref = work / "reference_bin"
ref.write_bytes(b"opaque")
probe = work / "probe.bin"
probe.write_bytes(b"opaque")
record = {"id": "ref", "role": "black_box_reference", "paths": ["./reference_bin"]}
ctx = ToolContext(
repo_dir=work, drive_root=drive, task_id="t",
task_metadata={"task_contract": {"resource_policy": {"protected_artifacts": [record]}}},
)
equal, detail = _compare_files_bytes_equal(
ctx, [str(ref), str(probe)], work, use_executor=False
)
assert equal is False and "refused" in detail
def test_review_output_budget_knob_lowers_never_raises(monkeypatch):
"""OUROBOROS_REVIEW_MAX_TOKENS lets an operator shrink the reviewer response
reservation so a mega-diff input pack + output fits a reviewer endpoint's
context cap (triad r3: 999K input + 65K default output overflowed ALL triad
endpoints). Floored at 8192; can never exceed the 65536 default."""
from ouroboros.tools.review import _review_output_budget
monkeypatch.delenv("OUROBOROS_REVIEW_MAX_TOKENS", raising=False)
assert _review_output_budget() == 65536
monkeypatch.setenv("OUROBOROS_REVIEW_MAX_TOKENS", "32768")
assert _review_output_budget() == 32768
monkeypatch.setenv("OUROBOROS_REVIEW_MAX_TOKENS", "128")
assert _review_output_budget() == 8192
monkeypatch.setenv("OUROBOROS_REVIEW_MAX_TOKENS", "999999")
assert _review_output_budget() == 65536
monkeypatch.setenv("OUROBOROS_REVIEW_MAX_TOKENS", "bogus")
assert _review_output_budget() == 65536
def test_bytes_equal_executor_infra_exit_is_not_a_byte_verdict(tmp_path, monkeypatch):
"""cmp exit >1 (missing binary =127, missing file =2) is an INFRA failure —
still FAIL, but the receipt must not claim the bytes differ (triad r3)."""
from types import SimpleNamespace
import ouroboros.workspace_executor as wx
from ouroboros.tools.verify import _compare_files_bytes_equal
ctx, work = _bytes_equal_ctx(tmp_path)
(work / "a.bin").write_bytes(b"x")
(work / "b.bin").write_bytes(b"x")
monkeypatch.setattr(
wx, "execute",
lambda *a, **k: SimpleNamespace(returncode=127, stdout="", stderr="cmp: not found"),
)
equal, detail = _compare_files_bytes_equal(ctx, ["a.bin", "b.bin"], work, use_executor=True)
assert equal is False
assert "infra error" in detail and "bytes differ" not in detail
def test_bytes_equal_rejected_for_non_run_kinds(tmp_path):
from ouroboros.tools.registry import ToolContext
from ouroboros.tools.verify import _verify_and_record
work = tmp_path / "ws"
work.mkdir()
drive = tmp_path / "drive"
drive.mkdir()
ctx = ToolContext(repo_dir=work, drive_root=drive, task_id="t")
out = _verify_and_record(
ctx, contract_kind="artifact_observation",
expected_match="bytes_equal", artifact_paths=["a.bin", "b.bin"],
)
assert "TOOL_ARG_ERROR" in out and "run-kind" in out
def test_verify_and_record_bytes_equal_requires_two_paths(tmp_path):
from ouroboros.tools.registry import ToolContext
from ouroboros.tools.verify import _verify_and_record
work = tmp_path / "ws"
work.mkdir()
drive = tmp_path / "drive"
drive.mkdir()
ctx = ToolContext(repo_dir=work, drive_root=drive, task_id="t")
out = _verify_and_record(
ctx, contract_kind="explicit_command", check=["true"],
expected_match="bytes_equal", artifact_paths=["only-one.txt"],
)
assert "TOOL_ARG_ERROR" in out and "exactly two files" in out