mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-02 19:58:46 +00:00
562 lines
21 KiB
Python
562 lines
21 KiB
Python
"""Production-shaped source-handle regressions for continuity Phase 3B."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from types import SimpleNamespace
|
|
|
|
from ouroboros import context_compaction as compaction
|
|
from ouroboros.artifacts import collect_task_artifact_records
|
|
from ouroboros.context_budget import ContextReclaimRequest
|
|
from ouroboros.consolidator import consolidate_scratchpad
|
|
from ouroboros.loop_tool_execution import _truncate_tool_result, process_tool_results
|
|
from ouroboros.memory import Memory
|
|
from ouroboros.review_evidence import build_task_acceptance_evidence
|
|
from ouroboros.review_substrate import ReviewRequest, ReviewSlot, run_review_request
|
|
from ouroboros.tools.core import _read_file
|
|
from ouroboros.tools.registry import ToolContext
|
|
|
|
|
|
def _tool_ctx(tmp_path, *, task_id: str = "source-handles") -> ToolContext:
|
|
repo = tmp_path / "repo"
|
|
repo.mkdir(exist_ok=True)
|
|
return ToolContext(repo_dir=repo, drive_root=tmp_path, task_id=task_id)
|
|
|
|
|
|
def _source_ref_from_visible_result(text: str) -> dict:
|
|
prefix = "FULL_RESULT_SOURCE_JSON="
|
|
line = next(line for line in text.splitlines() if line.startswith(prefix))
|
|
return json.loads(line[len(prefix):])
|
|
|
|
|
|
def _read_source(ctx: ToolContext, ref: dict, *, start_char: int = 0) -> str:
|
|
read = ref["read"]
|
|
assert read["tool"] == "read_file"
|
|
args = dict(read["arguments"])
|
|
args["start_char"] = start_char
|
|
return _read_file(ctx, **args)
|
|
|
|
|
|
def test_fifo_eviction_keeps_exact_block_and_current_scratchpad_names_reader(tmp_path):
|
|
memory = Memory(tmp_path)
|
|
contents = [f"scratch-source-{index}" for index in range(11)]
|
|
for content in contents:
|
|
memory.append_scratchpad_block(content, source="phase3b-test")
|
|
|
|
current = memory.load_scratchpad()
|
|
assert "read_file(root='runtime_data', path='memory/scratchpad_journal.jsonl'" in current
|
|
|
|
journal = _read_file(
|
|
_tool_ctx(tmp_path),
|
|
root="runtime_data",
|
|
path="memory/scratchpad_journal.jsonl",
|
|
)
|
|
rows = [json.loads(line) for line in journal.splitlines()[1:] if line.startswith("{")]
|
|
evicted = [row for row in rows if row.get("type") == "block_evicted"]
|
|
assert [row["evicted_block_content"] for row in evicted] == [contents[0]]
|
|
|
|
|
|
class _ConsolidationLLM:
|
|
def chat(self, **_kwargs):
|
|
return {
|
|
"content": json.dumps({
|
|
"knowledge_entries": [],
|
|
"compressed_block": "compressed working memory",
|
|
})
|
|
}, {"prompt_tokens": 10, "completion_tokens": 5}
|
|
|
|
|
|
def test_scratchpad_consolidation_journals_exact_replaced_blocks_and_ref(tmp_path):
|
|
memory = Memory(tmp_path)
|
|
original = []
|
|
for index in range(4):
|
|
content = f"block-{index}-" + (chr(97 + index) * 8_000)
|
|
original.append(memory.append_scratchpad_block(content, source=f"source-{index}"))
|
|
|
|
usage = consolidate_scratchpad(
|
|
memory,
|
|
tmp_path / "memory" / "knowledge",
|
|
_ConsolidationLLM(),
|
|
)
|
|
assert usage["prompt_tokens"] == 10
|
|
assert usage["completion_tokens"] == 5
|
|
|
|
blocks = memory.load_scratchpad_blocks()
|
|
consolidated = blocks[0]
|
|
assert consolidated["source"] == "consolidation"
|
|
source_ref = consolidated["metadata"]["source_ref"]
|
|
assert source_ref["read"] == {
|
|
"tool": "read_file",
|
|
"arguments": {
|
|
"root": "runtime_data",
|
|
"path": "memory/scratchpad_journal.jsonl",
|
|
"start_line": 1,
|
|
},
|
|
}
|
|
assert source_ref["entry_id"]
|
|
|
|
journal = _read_file(
|
|
_tool_ctx(tmp_path),
|
|
root="runtime_data",
|
|
path="memory/scratchpad_journal.jsonl",
|
|
)
|
|
rows = [json.loads(line) for line in journal.splitlines()[1:] if line.startswith("{")]
|
|
entry = next(row for row in rows if row.get("entry_id") == source_ref["entry_id"])
|
|
assert entry["type"] == "blocks_consolidated"
|
|
assert entry["source_blocks"] == original[:2]
|
|
assert source_ref["entry_id"] in memory.load_scratchpad()
|
|
|
|
|
|
def _project_large_result(tmp_path, *, tool_name: str, call_id: str, result: str):
|
|
ctx = _tool_ctx(tmp_path, task_id="large-result")
|
|
messages: list[dict] = []
|
|
trace = {"tool_calls": []}
|
|
tools = SimpleNamespace(_ctx=ctx)
|
|
process_tool_results(
|
|
[{
|
|
"fn_name": tool_name,
|
|
"tool_call_id": call_id,
|
|
"result": result,
|
|
"is_error": False,
|
|
"tool_args": {"cmd": "non-idempotent-operation"},
|
|
"args_for_log": {"cmd": "non-idempotent-operation"},
|
|
"trace_ref": {"manifest_ref": {"path": "private-only"}},
|
|
"result_meta": {"status": "ok"},
|
|
}],
|
|
messages,
|
|
trace,
|
|
emit_progress=lambda _message, *, incident=None: None,
|
|
tools=tools,
|
|
)
|
|
return ctx, messages[0]["content"], trace["tool_calls"][0]
|
|
|
|
|
|
def test_100k_non_idempotent_command_has_exact_actor_read_handle(tmp_path):
|
|
decisive_suffix = "\nDECISIVE_SUFFIX: transaction committed but verification FAILED"
|
|
full = "command-issued-once\n" + ("x" * 100_000) + decisive_suffix
|
|
ctx, visible, trace_row = _project_large_result(
|
|
tmp_path,
|
|
tool_name="run_command",
|
|
call_id="call-non-idempotent",
|
|
result=full,
|
|
)
|
|
|
|
assert decisive_suffix not in visible
|
|
assert "Do not rerun this tool to recover omitted output." in visible
|
|
ref = _source_ref_from_visible_result(visible)
|
|
assert trace_row["result_partial"] is True
|
|
assert trace_row["result_source_ref"] == ref
|
|
assert ref["root"] == "artifact_store"
|
|
assert ref["size"] == len(full.encode("utf-8"))
|
|
assert decisive_suffix in _read_source(ctx, ref, start_char=95_000)
|
|
|
|
|
|
def test_large_extension_result_uses_same_exact_actor_read_handle(tmp_path):
|
|
decisive_suffix = "\nEXTENSION_DECISION=DENY"
|
|
token = "sk-" + ("secret" * 8)
|
|
full = json.dumps({
|
|
"payload": "y" * 20_000, "api_key": token, "decision": decisive_suffix,
|
|
})
|
|
ctx, visible, trace_row = _project_large_result(
|
|
tmp_path,
|
|
tool_name="ext_demo_large_result",
|
|
call_id="call-extension",
|
|
result=full,
|
|
)
|
|
|
|
assert decisive_suffix not in visible
|
|
ref = _source_ref_from_visible_result(visible)
|
|
assert trace_row["result_partial"] is True
|
|
assert trace_row["result_source_ref"] == ref
|
|
recovered = _read_source(ctx, ref)
|
|
assert full in recovered
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx, llm_trace={"tool_calls": [trace_row]},
|
|
drive_root=tmp_path, task_id="large-result",
|
|
)
|
|
assert token not in json.dumps(evidence, ensure_ascii=False)
|
|
assert "***REDACTED***" in evidence["tool_trajectory"][0]["result"]
|
|
assert collect_task_artifact_records(tmp_path, "large-result") == []
|
|
|
|
|
|
def _unit(call_id: str) -> list[dict]:
|
|
return [
|
|
{
|
|
"role": "assistant",
|
|
"content": f"reasoning-{call_id}",
|
|
"tool_calls": [{
|
|
"id": call_id,
|
|
"function": {
|
|
"name": "run_command",
|
|
"arguments": json.dumps({"cmd": "one-shot"}),
|
|
},
|
|
}],
|
|
},
|
|
{
|
|
"role": "tool",
|
|
"tool_call_id": call_id,
|
|
"content": "z" * 6_000 + f"-exact-result-tail-{call_id}",
|
|
},
|
|
]
|
|
|
|
|
|
def test_context_capsule_checkpoint_is_actor_readable_and_dangling_is_explicit(
|
|
monkeypatch, tmp_path,
|
|
):
|
|
messages = _unit("checkpointed")
|
|
request = ContextReclaimRequest(
|
|
route_fp="main-route",
|
|
round_id="round-1",
|
|
transcript_sha256=compaction.context_reclaim_transcript_sha256(messages),
|
|
measurement_basis="cold_estimate",
|
|
measurement_density=1.0,
|
|
reclaim_goal_tokens=100,
|
|
allow_partial_shrink=True,
|
|
)
|
|
monkeypatch.setattr(compaction, "_summarizer_spec", lambda: {
|
|
"model": "summary-model",
|
|
"resolved_model": "summary-model",
|
|
"provider": "test",
|
|
"route_fp": "summary-route",
|
|
"effort": "low",
|
|
"output_budget": 32_768,
|
|
"use_local": False,
|
|
})
|
|
monkeypatch.setattr(
|
|
compaction,
|
|
"_call_summarizer",
|
|
lambda parts, **_kwargs: {
|
|
part.source_id: f"summary {part.sha256}" for part in parts
|
|
},
|
|
)
|
|
|
|
rebuilt, receipt, _usage = compaction.compact_tool_history_llm(
|
|
messages,
|
|
request=request,
|
|
drive_root=tmp_path,
|
|
task_id="checkpoint-task",
|
|
keep_recent=0,
|
|
negative_memo=set(),
|
|
)
|
|
assert receipt.status == "applied"
|
|
capsule = rebuilt[0]["content"][0]["_context_capsule"]
|
|
ref = capsule["checkpoint_ref"]
|
|
assert ref["root"] == "artifact_store"
|
|
ctx = _tool_ctx(tmp_path, task_id="checkpoint-task")
|
|
recovered = _read_source(ctx, ref)
|
|
checkpoint = json.loads(recovered.split("\n", 1)[1])
|
|
assert checkpoint["messages"] == messages
|
|
|
|
source_path = tmp_path / "task_results" / "artifacts" / "checkpoint-task" / ref["path"]
|
|
source_path.unlink()
|
|
assert "NOT_FOUND" in _read_source(ctx, ref)
|
|
|
|
|
|
class _MustNotReviewPartial:
|
|
def __init__(self):
|
|
self.calls = 0
|
|
|
|
def chat(self, **_kwargs):
|
|
self.calls += 1
|
|
raise AssertionError("an unresolved partial source must not reach a clean reviewer")
|
|
|
|
|
|
def test_metadata_less_actor_truncation_envelope_abstains_before_review(tmp_path):
|
|
actor_view = _truncate_tool_result("legacy" * 100_000, "run_command")
|
|
assert "truncated from 600000" in actor_view
|
|
ctx = _tool_ctx(tmp_path, task_id="legacy-partial")
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx,
|
|
llm_trace={"tool_calls": [{
|
|
"tool": "run_command", "status": "ok", "result": actor_view,
|
|
}]},
|
|
drive_root=tmp_path,
|
|
task_id="legacy-partial",
|
|
)
|
|
row = evidence["tool_trajectory"][0]
|
|
assert "truncated from 600000" in row["result"]
|
|
assert row["result_complete"] is False
|
|
assert evidence["__unresolved_partial_artifacts__"][0]["status"] == "source_unavailable"
|
|
|
|
llm = _MustNotReviewPartial()
|
|
result = run_review_request(
|
|
ReviewRequest(
|
|
surface="task_acceptance", goal="decide from legacy evidence",
|
|
subject="candidate", evidence=evidence,
|
|
policy={"min_successful_slots": 1}, task_id="legacy-partial",
|
|
),
|
|
slots=[ReviewSlot(slot_id="slot", model="review-model")],
|
|
drive_root=tmp_path,
|
|
llm=llm,
|
|
)
|
|
assert llm.calls == 0
|
|
assert result.aggregate_signal == "DEGRADED"
|
|
assert result.degraded is True
|
|
|
|
|
|
def test_explicit_complete_row_is_not_reclassified_from_envelope_text(tmp_path):
|
|
result_text = "0123456789\n... (truncated from 20 chars, limit=10)"
|
|
ctx = _tool_ctx(tmp_path, task_id="explicit-complete")
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx,
|
|
llm_trace={"tool_calls": [{
|
|
"tool": "run_command", "status": "ok", "result": result_text,
|
|
"result_partial": False,
|
|
}]},
|
|
drive_root=tmp_path,
|
|
task_id="explicit-complete",
|
|
)
|
|
assert "__unresolved_partial_artifacts__" not in evidence
|
|
assert evidence["tool_trajectory"][0]["result_complete"] is True
|
|
assert evidence["tool_trajectory"][0]["result"] == result_text
|
|
|
|
|
|
def test_budget_recap_preserves_every_legacy_actor_envelope(tmp_path):
|
|
calls = []
|
|
for index in range(3):
|
|
actor_view = _truncate_tool_result(str(index) * 500_000, "run_command")
|
|
assert "truncated from 500000" in actor_view
|
|
calls.append({"tool": "run_command", "status": "ok", "result": actor_view})
|
|
|
|
evidence = build_task_acceptance_evidence(
|
|
_tool_ctx(tmp_path, task_id="legacy-budget"),
|
|
llm_trace={"tool_calls": calls},
|
|
drive_root=tmp_path,
|
|
task_id="legacy-budget",
|
|
)
|
|
rows = evidence["tool_trajectory"]
|
|
assert len(rows) == 3
|
|
assert all("truncated from 500000" in row["result"] for row in rows)
|
|
assert all(row["result_complete"] is False for row in rows)
|
|
assert all("_legacy_projection_envelope" not in row for row in rows)
|
|
assert len(evidence["__unresolved_partial_artifacts__"]) >= 3
|
|
|
|
|
|
def test_redaction_expansion_preserves_legacy_actor_envelope(tmp_path):
|
|
credential_url = "https://alice:phase3b-secret@example.invalid/private?"
|
|
full = (credential_url * 3_000) + ("Z" * 400_000)
|
|
actor_view = _truncate_tool_result(full, "run_command")
|
|
marker = f"truncated from {len(full)}"
|
|
assert marker in actor_view
|
|
|
|
evidence = build_task_acceptance_evidence(
|
|
_tool_ctx(tmp_path, task_id="legacy-redaction"),
|
|
llm_trace={"tool_calls": [{
|
|
"tool": "run_command", "status": "ok", "result": actor_view,
|
|
}]},
|
|
drive_root=tmp_path,
|
|
task_id="legacy-redaction",
|
|
)
|
|
row = evidence["tool_trajectory"][0]
|
|
assert "phase3b-secret" not in row["result"]
|
|
assert "***REDACTED***" in row["result"]
|
|
assert marker in row["result"]
|
|
assert row["result_complete"] is False
|
|
assert "_legacy_projection_envelope" not in row
|
|
|
|
|
|
def test_task_acceptance_abstains_before_review_on_unresolved_partial_source(tmp_path):
|
|
full = "decision-input\n" + ("p" * 20_000) + "\nDECISIVE_ACCEPTANCE_SUFFIX=FAIL"
|
|
ctx, _visible, trace_row = _project_large_result(
|
|
tmp_path, tool_name="ext_acceptance_probe", call_id="acceptance-source", result=full,
|
|
)
|
|
trace = {"tool_calls": [trace_row]}
|
|
complete_evidence = build_task_acceptance_evidence(
|
|
ctx, llm_trace=trace, drive_root=tmp_path, task_id="large-result",
|
|
)
|
|
assert complete_evidence["tool_trajectory"][0]["result_complete"] is True
|
|
assert "DECISIVE_ACCEPTANCE_SUFFIX=FAIL" in complete_evidence["tool_trajectory"][0]["result"]
|
|
|
|
source_ref = trace_row["result_source_ref"]
|
|
source_path = tmp_path / "task_results" / "artifacts" / "large-result" / source_ref["path"]
|
|
source_path.unlink()
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx, llm_trace=trace, drive_root=tmp_path, task_id="large-result",
|
|
)
|
|
assert evidence["__unresolved_partial_artifacts__"][0]["status"] == "source_unavailable"
|
|
|
|
llm = _MustNotReviewPartial()
|
|
paid = []
|
|
result = run_review_request(
|
|
ReviewRequest(
|
|
surface="task_acceptance",
|
|
goal="decide from evidence",
|
|
subject="candidate",
|
|
evidence=evidence,
|
|
policy={"min_successful_slots": 1},
|
|
task_id="acceptance-partial",
|
|
),
|
|
slots=[ReviewSlot(slot_id="slot", model="review-model")],
|
|
drive_root=tmp_path,
|
|
llm=llm,
|
|
usage_ctx=SimpleNamespace(_review_paid_stamp=lambda: paid.append(True)),
|
|
)
|
|
|
|
assert llm.calls == 0
|
|
assert paid == []
|
|
assert result.aggregate_signal == "DEGRADED"
|
|
assert result.degraded is True
|
|
assert result.actors[0]["status"] == "not_dispatched"
|
|
assert result.actors[0]["signal"] == "DEGRADED"
|
|
|
|
|
|
def test_marker_only_repo_diff_abstains_before_review(monkeypatch, tmp_path):
|
|
"""A legacy diff producer must not turn its visible slice into PASS."""
|
|
import ouroboros.review_evidence as evidence_mod
|
|
|
|
monkeypatch.setattr(
|
|
evidence_mod,
|
|
"collect_turn_diff",
|
|
lambda _ctx, **_kwargs: (
|
|
"diff --git a/visible.py b/visible.py\n"
|
|
"⚠️ OMISSION NOTE: truncated at 20000 chars; original length 80000"
|
|
),
|
|
)
|
|
ctx = _tool_ctx(tmp_path, task_id="marker-only-diff")
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx, llm_trace={"tool_calls": []}, drive_root=tmp_path, task_id="marker-only-diff",
|
|
)
|
|
assert evidence["__unresolved_partial_artifacts__"][0]["tool"] == "repo_diff"
|
|
|
|
llm = _MustNotReviewPartial()
|
|
result = run_review_request(
|
|
ReviewRequest(
|
|
surface="task_acceptance", goal="decide from evidence", subject="candidate",
|
|
evidence=evidence, policy={"min_successful_slots": 1}, task_id="marker-only-diff",
|
|
),
|
|
slots=[ReviewSlot(slot_id="slot", model="review-model")],
|
|
drive_root=tmp_path,
|
|
llm=llm,
|
|
)
|
|
assert llm.calls == 0
|
|
assert result.aggregate_signal == "DEGRADED"
|
|
|
|
|
|
def test_large_repo_diff_materializes_exact_source_and_keeps_pass_path(tmp_path):
|
|
"""The normal over-limit path is exact-source backed, not silently degraded."""
|
|
import subprocess as sp
|
|
|
|
ctx = _tool_ctx(tmp_path, task_id="exact-repo-diff")
|
|
repo = ctx.repo_dir
|
|
sp.run(["git", "init"], cwd=repo, check=True, capture_output=True)
|
|
(repo / "large.py").write_text("x = 0\n", encoding="utf-8")
|
|
sp.run(["git", "add", "large.py"], cwd=repo, check=True, capture_output=True)
|
|
sp.run(
|
|
["git", "-c", "user.email=t@t", "-c", "user.name=t", "commit", "-m", "base"],
|
|
cwd=repo, check=True, capture_output=True,
|
|
)
|
|
(repo / "large.py").write_text(
|
|
"\n".join(f"value_{i} = {i}" for i in range(5000)) + "\nDECISIVE_DIFF_TAIL=present\n",
|
|
encoding="utf-8",
|
|
)
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx, llm_trace={"tool_calls": []}, drive_root=tmp_path, task_id="exact-repo-diff",
|
|
)
|
|
assert "__unresolved_partial_artifacts__" not in evidence
|
|
assert evidence["repo_diff_source_ref"]["kind"] == "task_source"
|
|
assert "DECISIVE_DIFF_TAIL=present" in evidence["repo_diff"]
|
|
assert collect_task_artifact_records(tmp_path, "exact-repo-diff") == []
|
|
|
|
class _PassLLM:
|
|
def chat(self, **_kwargs):
|
|
return {"content": json.dumps({"verdict": "PASS", "findings": [], "summary": "ok"})}, {}
|
|
|
|
result = run_review_request(
|
|
ReviewRequest(
|
|
surface="task_acceptance", goal="decide from evidence", subject="candidate",
|
|
evidence=evidence, policy={"min_successful_slots": 1}, task_id="exact-repo-diff",
|
|
),
|
|
slots=[ReviewSlot(slot_id="slot", model="review-model")],
|
|
drive_root=tmp_path,
|
|
llm=_PassLLM(),
|
|
)
|
|
assert result.aggregate_signal == "PASS"
|
|
|
|
|
|
# ── AP3: a pageable tool result persists its exact source like any other ──────
|
|
|
|
class _CountingLLM:
|
|
def __init__(self):
|
|
self.calls = 0
|
|
|
|
def chat(self, **_kwargs):
|
|
self.calls += 1
|
|
body = {"verdict": "PASS", "findings": [], "summary": "reviewed"}
|
|
return {"content": json.dumps(body)}, {"prompt_tokens": 10, "completion_tokens": 5}
|
|
|
|
|
|
def _dispatch_acceptance(tmp_path, evidence: dict, llm) -> object:
|
|
return run_review_request(
|
|
ReviewRequest(
|
|
surface="task_acceptance", goal="decide", subject="candidate",
|
|
evidence=evidence, policy={"min_successful_slots": 1}, task_id="pageable",
|
|
),
|
|
slots=[ReviewSlot(slot_id="slot", model="review-model")],
|
|
drive_root=tmp_path,
|
|
llm=llm,
|
|
)
|
|
|
|
|
|
def test_over_limit_pageable_results_persist_their_exact_source(tmp_path):
|
|
"""The agent can page `read_file`; the acceptance DECIDER cannot. Skipping
|
|
persistence for pageable tools left the panel with a partial row whose exact
|
|
source did not exist, which refused the whole panel for nothing."""
|
|
for tool_name in ("read_file", "query_code", "chat_history"):
|
|
ctx, visible, trace_row = _project_large_result(
|
|
tmp_path, tool_name=tool_name, call_id=f"page-{tool_name}",
|
|
result="page-head\n" + ("y" * 120_000) + "\nDECISIVE_TAIL=FAIL",
|
|
)
|
|
assert trace_row["result_partial"] is True
|
|
assert trace_row["result_source_status"] == "ready"
|
|
assert "FULL_RESULT_SOURCE_JSON=" in visible
|
|
assert "exact source persistence failed" not in visible
|
|
# The wording keeps the tool's own affordance instead of forbidding it.
|
|
assert "or page this tool (offset/limit) for the omitted range" in visible
|
|
ref = _source_ref_from_visible_result(visible)
|
|
assert "DECISIVE_TAIL=FAIL" in _read_source(ctx, ref, start_char=100_000)
|
|
|
|
evidence = build_task_acceptance_evidence(
|
|
ctx, llm_trace={"tool_calls": [dict(trace_row)]},
|
|
drive_root=tmp_path, task_id=ctx.task_id,
|
|
)
|
|
assert evidence["tool_trajectory"][0]["result_complete"] is True
|
|
assert "__unresolved_partial_artifacts__" not in evidence
|
|
|
|
llm = _CountingLLM()
|
|
result = _dispatch_acceptance(tmp_path, evidence, llm)
|
|
assert llm.calls == 1
|
|
assert result.aggregate_signal == "PASS"
|
|
|
|
|
|
def test_a_non_pageable_tool_keeps_its_do_not_rerun_wording(tmp_path):
|
|
_ctx, visible, _row = _project_large_result(
|
|
tmp_path, tool_name="run_command", call_id="page-run",
|
|
result="cmd\n" + ("z" * 120_000),
|
|
)
|
|
assert "Do not rerun this tool to recover omitted output." in visible
|
|
assert "or page this tool" not in visible
|
|
|
|
|
|
def test_a_budget_shed_row_dispatches_while_a_missing_source_still_refuses(tmp_path):
|
|
shed_only = {
|
|
"task_contract": {"requirements": "do X"},
|
|
"__provenance__": {},
|
|
"__unresolved_partial_artifacts__": [{
|
|
"tool": "read_file", "status": "not_materialized_for_reviewer",
|
|
"source_ref": {"kind": "artifact", "path": "tool_results/page.txt"},
|
|
}],
|
|
}
|
|
llm = _CountingLLM()
|
|
assert _dispatch_acceptance(tmp_path, shed_only, llm).aggregate_signal == "PASS"
|
|
assert llm.calls == 1
|
|
|
|
genuine = {
|
|
**shed_only,
|
|
"__unresolved_partial_artifacts__": [
|
|
{"tool": "read_file", "status": "source_unavailable", "source_ref": {}},
|
|
],
|
|
}
|
|
refusing = _MustNotReviewPartial()
|
|
result = _dispatch_acceptance(tmp_path, genuine, refusing)
|
|
assert refusing.calls == 0
|
|
assert result.aggregate_signal == "DEGRADED"
|