"""materialize_artifacts contract tests (v6.90.x P2).
`effective_task_result(..., materialize_artifacts=False)` is a "status/cost
projection only" read for hot display surfaces (history annotation,
api_tasks_list, the SSE follow loop, api_logs_tail discovery): it must skip the
entire artifact block — including the MUTATING child-artifact rebase and the
collect_task_artifact_records file scans — and the task-tree disposition hash
lookup, and must never carry sha-bearing/disposition claims. Every sha-economy
consumer keeps the True default, so a terminal child's `_child_result_sha256`
is identical no matter how many False-path reads happened in between. The
orphan reconciler decides on a False read and materializes only the row it
heals, so a live child's scratch tree is never promoted by the periodic sweep
(issue #1230).
"""
from __future__ import annotations
import asyncio
import json
import pathlib
from types import SimpleNamespace
from ouroboros.task_results import write_task_result
from ouroboros.task_status import find_child_tasks, load_effective_task_result
def _seed_child_drive_scenario(tmp_path):
"""Parent result referencing a terminal child drive that holds an artifact."""
from ouroboros.artifacts import collect_task_artifact_records, copy_file_to_task_artifacts
data = tmp_path / "data"
child = data / "state" / "headless_tasks" / "childart" / "data" # the task's OWN drive
source_dir = tmp_path / "Desktop"
source_dir.mkdir()
source = source_dir / "report.html"
source.write_text("
child
", encoding="utf-8")
copy_file_to_task_artifacts(SimpleNamespace(drive_root=child, task_id="childart"), source, kind="user_file")
child_artifacts = collect_task_artifact_records(child, "childart")
write_task_result(
child,
"childart",
"completed",
result="done",
artifacts=child_artifacts,
artifact_status="ready",
ts="2026-01-01T00:00:02Z",
)
write_task_result(
data,
"childart",
"completed",
result="done",
child_drive_root=str(child),
# Legacy mirrored disposition fields on disk must be stripped either way.
child_result_disposition="integrated",
child_result_disposition_sha256="deadbeef",
delegation_role="subagent",
parent_task_id="parent1",
root_task_id="parent1",
)
(data / "state").mkdir(parents=True, exist_ok=True)
(data / "state" / "queue_snapshot.json").write_text('{"pending": [], "running": []}', encoding="utf-8")
return data, child
def test_false_read_skips_artifact_block_and_disposition(tmp_path, monkeypatch):
data, child = _seed_child_drive_scenario(tmp_path)
import ouroboros.artifacts as artifacts_mod
calls = {"collect": 0, "copy": 0}
real_collect = artifacts_mod.collect_task_artifact_records
real_copy = artifacts_mod.copy_file_to_task_artifacts
monkeypatch.setattr(
artifacts_mod, "collect_task_artifact_records",
lambda *a, **k: calls.__setitem__("collect", calls["collect"] + 1) or real_collect(*a, **k),
)
monkeypatch.setattr(
artifacts_mod, "copy_file_to_task_artifacts",
lambda *a, **k: calls.__setitem__("copy", calls["copy"] + 1) or real_copy(*a, **k),
)
row = load_effective_task_result(data, "childart", materialize_artifacts=False)
assert row["status"] == "completed"
assert row["result"] == "done"
# No artifact machinery ran and no files were copied to the parent.
assert calls == {"collect": 0, "copy": 0}
assert not (data / "task_results" / "artifacts" / "childart" / "report.html").exists()
# A False row never carries sha-bearing/disposition claims — even the legacy
# mirrored on-disk fields are stripped.
for field in (
"child_result_disposition",
"child_result_disposition_sha256",
"child_result_disposition_reason",
"child_result_disposition_source",
"parent_decision_child_result_sha256",
"terminal_child_result_snapshot",
):
assert field not in row
def test_child_result_sha_stable_across_false_path_reads(tmp_path):
from ouroboros.tools.join_ledger import _child_result_sha256
data, child = _seed_child_drive_scenario(tmp_path)
sha_before = _child_result_sha256(load_effective_task_result(data, "childart"))
# Any number of projection-only reads in between must not perturb the sha
# economy (they perform no writes at all).
for _ in range(3):
load_effective_task_result(data, "childart", materialize_artifacts=False)
find_child_tasks(data, parent_task_id="parent1", root_task_id="parent1", materialize_artifacts=False)
sha_after = _child_result_sha256(load_effective_task_result(data, "childart"))
assert sha_before == sha_after
def test_true_default_lists_child_artifacts_without_copying_them(tmp_path):
"""The default read shows the child's recorded rows at their child-drive
paths and copies nothing; copy-back alone rebases them onto the parent."""
from ouroboros.headless import copy_child_task_result
data, child = _seed_child_drive_scenario(tmp_path)
rebased = data / "task_results" / "artifacts" / "childart" / "report.html"
row = load_effective_task_result(data, "childart")
listed = next(item for item in row["artifacts"] if item.get("name") == "report.html")
assert listed["path"] == str(child / "task_results" / "artifacts" / "childart" / "report.html")
assert not rebased.exists() and not rebased.parent.exists()
copied = copy_child_task_result(data, {"id": "childart", "drive_root": str(child)})
assert rebased.read_text(encoding="utf-8") == "child
"
assert [item["path"] for item in copied["artifacts"]] == [str(rebased)]
assert [item["path"] for item in load_effective_task_result(data, "childart")["artifacts"]] == [str(rebased)]
def test_generic_receipt_named_output_never_owns_receipt_authority(tmp_path):
"""A user/process output may keep its name, never the receipt SSOT path."""
from ouroboros.artifacts import (
collect_task_artifact_records,
copy_file_to_task_artifacts,
)
from ouroboros.outcomes import (
append_verification_receipt,
read_verification_receipts,
verification_receipts_path,
)
drive = tmp_path / "data"
source = tmp_path / "outside" / "verification_receipts.jsonl"
source.parent.mkdir()
source.write_text('{"artifact":"v1"}\n', encoding="utf-8")
ctx = SimpleNamespace(drive_root=drive, task_id="receipt-collision")
first = copy_file_to_task_artifacts(ctx, source, kind="process_output")
authority = verification_receipts_path(drive, ctx.task_id)
assert first is not None
assert first["name"].startswith("verification_receipts.")
assert first["name"].endswith(".jsonl")
assert first["path"] != str(authority)
assert append_verification_receipt(
drive,
ctx.task_id,
{"status": "pass", "criterion_id": "host"},
)
source.write_text('{"artifact":"v2"}\n', encoding="utf-8")
second = copy_file_to_task_artifacts(ctx, source, kind="process_output")
assert second is not None
assert second["path"] == first["path"]
assert any(
row.get("criterion_id") == "host"
for row in read_verification_receipts(drive, ctx.task_id)
)
records = collect_task_artifact_records(drive, ctx.task_id)
assert [item["path"] for item in records] == [first["path"]]
from ouroboros.tools.core import _write_file
from ouroboros.tools.registry import ToolContext
repo = tmp_path / "repo"
repo.mkdir()
tool_ctx = ToolContext(repo_dir=repo, drive_root=drive, task_id=ctx.task_id)
blocked = _write_file(
tool_ctx,
path="verification_receipts.jsonl",
content='{"generic":"overwrite"}\n',
root="artifact_store",
)
assert "verification receipt authority path is reserved" in blocked
nested = _write_file(
tool_ctx,
path="nested/verification_receipts.jsonl",
content='{"generic":"allowed"}\n',
root="artifact_store",
)
assert nested.startswith("OK: wrote artifact_store:nested/")
def test_history_and_tasks_list_paths_do_no_artifact_work(tmp_path, monkeypatch):
"""Counter-assert: GET /api/chat/history and GET /api/tasks perform ZERO
collect_task_artifact_records / copy_file_to_task_artifacts calls."""
import ouroboros.artifacts as artifacts_mod
from ouroboros.gateway.history import make_chat_history_endpoint
from ouroboros.gateway.tasks import api_tasks_list
data, child = _seed_child_drive_scenario(tmp_path)
logs = data / "logs"
logs.mkdir(parents=True, exist_ok=True)
(logs / "chat.jsonl").write_text("", encoding="utf-8")
(logs / "progress.jsonl").write_text(
json.dumps({"ts": "2026-01-01T00:00:01Z", "content": "step", "task_id": "childart"}) + "\n",
encoding="utf-8",
)
calls = {"collect": 0, "copy": 0}
monkeypatch.setattr(
artifacts_mod, "collect_task_artifact_records",
lambda *a, **k: calls.__setitem__("collect", calls["collect"] + 1) or [],
)
monkeypatch.setattr(
artifacts_mod, "copy_file_to_task_artifacts",
lambda *a, **k: calls.__setitem__("copy", calls["copy"] + 1) or None,
)
history = make_chat_history_endpoint(data)
response = asyncio.run(history(SimpleNamespace(query_params={"limit": "10"})))
payload = json.loads(response.body.decode("utf-8"))["messages"]
assert any(item.get("task_id") == "childart" for item in payload)
request = SimpleNamespace(
query_params={},
app=SimpleNamespace(state=SimpleNamespace(drive_root=data)),
)
response = asyncio.run(api_tasks_list(request))
tasks = json.loads(response.body.decode("utf-8"))["tasks"]
assert any(task.get("task_id") == "childart" for task in tasks)
assert calls == {"collect": 0, "copy": 0}
def _iso(epoch: float) -> str:
from datetime import datetime, timezone
return datetime.fromtimestamp(epoch, tz=timezone.utc).isoformat()
def _spy_effective_reads(monkeypatch) -> list:
"""Record the ``materialize_artifacts`` flag of every reconciler read (real calls)."""
from ouroboros import task_status
flags: list = []
real = task_status.load_effective_task_result
def _spy(drive_root, tid, materialize_artifacts=True):
flags.append(bool(materialize_artifacts))
return real(drive_root, tid, materialize_artifacts=materialize_artifacts)
monkeypatch.setattr(task_status, "load_effective_task_result", _spy)
return flags
def _count_copies(monkeypatch) -> dict:
import ouroboros.artifacts as artifacts_mod
calls = {"copy": 0}
real_copy = artifacts_mod.copy_file_to_task_artifacts
monkeypatch.setattr(
artifacts_mod, "copy_file_to_task_artifacts",
lambda *a, **k: calls.__setitem__("copy", calls["copy"] + 1) or real_copy(*a, **k),
)
return calls
def test_reconcile_skips_a_live_running_child_without_materializing(tmp_path, monkeypatch):
"""A RUNNING child with a large scratch tree under its artifact dir costs the
300-s sweep one status projection and zero artifact transfers."""
import time
from ouroboros.artifacts import _ARTIFACT_MANIFEST, copy_file_to_task_artifacts, task_artifact_dir_path
from ouroboros.task_status import reconcile_orphaned_running_tasks
now = 1_800_000_000.0
monkeypatch.setattr(time, "time", lambda: now)
data, child, tid = tmp_path / "data", tmp_path / "child", "livechild"
source = tmp_path / "report.html"
source.write_text("live
", encoding="utf-8")
copy_file_to_task_artifacts(SimpleNamespace(drive_root=child, task_id=tid), source, kind="user_file")
sandbox = task_artifact_dir_path(child, tid) / "verification-sandbox"
for index in range(300):
target = sandbox / (".git" if index % 2 else "venv") / f"file{index}.txt"
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(f"scratch {index}\n", encoding="utf-8")
write_task_result(child, tid, "running", result="working", ts=_iso(now - 600))
write_task_result(data, tid, "running", result="working", child_drive_root=str(child), ts=_iso(now - 600))
(data / "state").mkdir(parents=True, exist_ok=True)
(data / "state" / "queue_snapshot.json").write_text(
json.dumps({"ts": _iso(now), "pending": [], "running": [{"id": tid, "task": {"id": tid}}]}),
encoding="utf-8",
)
child_manifest = task_artifact_dir_path(child, tid) / _ARTIFACT_MANIFEST
manifest_before = child_manifest.read_bytes()
flags, copies = _spy_effective_reads(monkeypatch), _count_copies(monkeypatch)
assert reconcile_orphaned_running_tasks(data) == 0
assert flags == [False]
assert copies == {"copy": 0}
assert not (data / "task_results" / "artifacts" / tid).exists()
assert child_manifest.read_bytes() == manifest_before
assert json.loads((data / "task_results" / f"{tid}.json").read_text(encoding="utf-8"))["status"] == "running"
def test_reconcile_heals_a_genuine_orphan_and_settlement_publishes_its_files(tmp_path, monkeypatch):
"""The positive path: a parent row stuck at ``running`` over a finished child drive
is settled from the status-only read — the sweep lists, copies and hashes no file —
with its terminal quiz settlement. The child's file stays served from its OWN drive
until copy-back adopts the child and ``settle_child_drive`` publishes it before the
drive goes (TZ-1 A: publication is explicit, never a read side effect)."""
import time
from ouroboros import owner_quiz
from ouroboros.artifacts import collect_task_artifact_records, copy_file_to_task_artifacts
from ouroboros.headless import prepare_terminal_task_files
from ouroboros.task_custody import settle_child_drive
from ouroboros.task_status import SETTLED_STATUSES, reconcile_orphaned_running_tasks
from ouroboros.utils import append_jsonl
now = 1_800_000_000.0
monkeypatch.setattr(time, "time", lambda: now)
data, tid = tmp_path / "data", "orphanchild"
child = data / "state" / "headless_tasks" / tid / "data" # the task's OWN drive (host layout)
source = tmp_path / "report.html"
source.write_text("child
", encoding="utf-8")
copy_file_to_task_artifacts(SimpleNamespace(drive_root=child, task_id=tid), source, kind="user_file")
write_task_result(child, tid, "completed", result="done", artifacts=collect_task_artifact_records(child, tid),
artifact_status="ready", ts=_iso(now - 3_600))
write_task_result(data, tid, "running", result="Task is running.", child_drive_root=str(child),
ts=_iso(now - 7_200))
owner_quiz.record_asked(data, tid, quiz_id="q1", question="Continue?", options=["yes", "no"])
(data / "state").mkdir(parents=True, exist_ok=True)
(data / "state" / "queue_snapshot.json").write_text(
json.dumps({"ts": _iso(now), "pending": [], "running": []}), encoding="utf-8",
)
events = data / "logs" / "events.jsonl"
append_jsonl(events, {"ts": _iso(now - 7_000), "type": "llm_round", "task_id": tid})
append_jsonl(events, {"ts": _iso(now - 6_000), "type": "worker_boot"})
flags, copies = _spy_effective_reads(monkeypatch), _count_copies(monkeypatch)
expired: list = []
assert reconcile_orphaned_running_tasks(data, expired_quizzes=expired) == 1
assert flags == [False]
assert copies == {"copy": 0}
on_disk = json.loads((data / "task_results" / f"{tid}.json").read_text(encoding="utf-8"))
assert on_disk["status"] in SETTLED_STATUSES
promoted = data / "task_results" / "artifacts" / tid / "report.html"
assert not promoted.exists()
assert expired == [(tid, "q1")]
assert owner_quiz.quiz_states(data, tid)["q1"]["state"] == "expired_terminal"
listed = next(row for row in load_effective_task_result(data, tid)["artifacts"] if row["name"] == "report.html")
assert pathlib.Path(listed["path"]).is_relative_to(child.resolve()) # served from where it lies
assert not prepare_terminal_task_files(data, {"id": tid, "drive_root": str(child)})["error"]
assert settle_child_drive(data, tid, child, live=lambda _task: False)["status"] == "removed"
assert promoted.read_text(encoding="utf-8") == "child
"
assert not child.exists()
published = next(row for row in load_effective_task_result(data, tid)["artifacts"] if row["name"] == "report.html")
assert published["path"] == str(promoted.resolve()) and published["sha256"]