merge: reconcile Wave 1.1 with post-PR40 lab

Merge canonical lab 9557b8d5909eb4a885c3bf49e19a65dd904f8c1d exactly once.
Retain invocation journal ownership and lineage, provider terminal ordering,
teacher handoff, framed DONE handling, and canonical authority/Ajax routing.

Combine dynamic dispatch receipts with lab policy forwarding. Adapt native
shell/patch evidence, explicit TUI verifiers, and artifact recovery presentation.
Refresh generated configuration source links and strengthen adapter regressions.

Validation: focused 2118 passed; Wave 1.1 script 2291 passed; broad runtime
5649 passed; full pytest 11581 passed, 53 skipped, 2 xfailed, 6 subtests passed.
Compileall 1689 Python files; syntax 279 JS and 82 MJS files; diff and
conflict-marker checks passed.
This commit is contained in:
Alexandre Teixeira
2026-10-01 09:09:55 +01:00
304 changed files with 41744 additions and 24384 deletions
+48 -9
View File
@@ -9,11 +9,13 @@ return, or moves the done-break, could silently flip this. See PR #1999 / #1997.
import asyncio
import json
from pathlib import Path
import pytest
import src.agent_loop as al
from src.tool_capabilities import ToolGateDecision
from src.tool_capabilities import capabilities_for_action
from src.tool_approvals import tool_approval_store
from tests.runtime_evidence_helpers import authoritative_executor
def _collect(gen):
@@ -39,6 +41,16 @@ def _patch_common(monkeypatch):
monkeypatch.setattr(al, "get_setting", lambda key, default=None: default, raising=False)
monkeypatch.setattr(al, "get_mcp_manager", lambda: None, raising=False)
monkeypatch.setattr(al, "estimate_tokens", lambda *a, **k: 10, raising=False)
# The round providers are synthetic. Keep real compaction logic while
# supplying its context window instead of probing the dummy endpoint.
import src.context_compactor as context_compactor
monkeypatch.setattr(context_compactor, "get_context_length", lambda *a, **k: 128_000)
# These fixtures supply the round provider below. Any direct grace-synthesis
# request has no configured response, rather than contacting the fake URL.
async def _unconfigured_direct_provider(*args, **kwargs):
raise RuntimeError("No direct-provider completion configured in this fixture")
yield # Keep the direct-provider async-generator interface.
monkeypatch.setattr(al, "stream_llm", _unconfigured_direct_provider)
# These tests exercise round convergence. Keep the prompt-integrity gate
# out of the fixture so a synthetic tool result does not turn the next
# round into an approval test instead.
@@ -997,6 +1009,7 @@ def test_empty_workspace_round_gets_one_bounded_action_nudge(monkeypatch):
yield 'data: {"delta":"Workspace checked."}\n\n'
yield "data: [DONE]\n\n"
@authoritative_executor
async def _fake_exec(block, *args, **kwargs):
return (block.tool_type, {"output": "/workspace", "exit_code": 0})
@@ -1011,7 +1024,15 @@ def test_empty_workspace_round_gets_one_bounded_action_nudge(monkeypatch):
)))
assert len(seen) == 3
assert any(e.get("delta") == "Workspace checked." for e in events)
decision = next(e["data"] for e in events if e.get("type") == "completion_decision")
assert not decision["can_complete"]
assert "fixture.py" in decision["missing_artifacts"]
assert any(
e.get("type") == "final_response"
and "Workspace checked." in e.get("content", "")
and "incomplete" in e.get("content", "")
for e in events
)
def test_empty_workspace_nudge_names_only_tools_in_active_schema(monkeypatch):
@@ -1205,7 +1226,8 @@ def test_eval_workspace_prompt_uses_host_tool_then_answers(monkeypatch):
assert any("active workspace is /home/tester/project" in e.get("delta", "") for e in events)
def test_tui_coding_turn_recovers_inspects_patches_and_verifies(monkeypatch):
@pytest.mark.parametrize('explicit_verifier', [False, True])
def test_tui_coding_turn_recovers_inspects_patches_and_verifies(monkeypatch, explicit_verifier):
"""A stale compact router must still complete a real coding workflow."""
_patch_common(monkeypatch)
calls = []
@@ -1227,6 +1249,7 @@ def test_tui_coding_turn_recovers_inspects_patches_and_verifies(monkeypatch):
},
}
@authoritative_executor
async def _fake_exec(block, *args, **kwargs):
executed.append((block.tool_type, block.content))
if block.tool_type == "host_shell":
@@ -1300,7 +1323,8 @@ def test_tui_coding_turn_recovers_inspects_patches_and_verifies(monkeypatch):
"deepseek-v4-flash",
[{
"role": "user",
"content": "Fix the parser in this local TUI project and run the tests.",
"content": "Fix the parser in this local TUI project and run "
+ ("python -m pytest -q." if explicit_verifier else "the tests."),
}],
max_rounds=6,
relevant_tools={"get_workspace", "ls", "host_shell", "apply_patch", "edit_file", "todowrite"},
@@ -1316,14 +1340,20 @@ def test_tui_coding_turn_recovers_inspects_patches_and_verifies(monkeypatch):
assert not any(tool in {"get_workspace", "ls"} for tool, _ in executed)
# Invalid backend/container tool names are replaced with the authoritative
# host-shell recovery in the same round, so no extra clarification round
# should be required before the patch and verification turns.
assert len(calls) == 3
# should be required before the patch and verification turns. An opaque
# conditional fallback still needs synthesis and cannot attest tests.
assert len(calls) == (3 if explicit_verifier else 4)
decision = next(event['data'] for event in events if event.get('type') == 'completion_decision')
assert decision['can_complete'] is explicit_verifier
assert (decision['status'] == 'verified') is explicit_verifier
assert any(
event.get("type") == "final_response"
and "Verification:" in event.get("content", "")
and "passed" in event.get("content", "")
for event in events
)
) is explicit_verifier
terminal = next(event['data'] for event in events if event.get('type') == 'metrics')
assert terminal['completion_gate']['additional_provider_calls'] == 0
assert not any(event.get("type") in {"rounds_exhausted", "loop_breaker_triggered"} for event in events)
@@ -1339,6 +1369,7 @@ def test_qwen_tui_coding_summary_reports_verification_retry(monkeypatch):
"runtime_execution_contract": {"local_workspace_tasks": "use_host_shell_bridge"},
}
@authoritative_executor
async def _fake_exec(block, *args, **kwargs):
nonlocal test_attempts
executed.append(block.tool_type)
@@ -1390,7 +1421,8 @@ def test_qwen_tui_coding_summary_reports_verification_retry(monkeypatch):
assert "`pytest -q` passed" in summary
def test_tui_coding_turn_replaces_duplicate_edit_with_requested_tests(monkeypatch):
@pytest.mark.parametrize('explicit_verifier', [False, True])
def test_tui_coding_turn_replaces_duplicate_edit_with_requested_tests(monkeypatch, explicit_verifier):
"""A successful edit followed by another edit must converge on real tests."""
_patch_common(monkeypatch)
executed = []
@@ -1407,6 +1439,7 @@ def test_tui_coding_turn_replaces_duplicate_edit_with_requested_tests(monkeypatc
},
}
@authoritative_executor
async def _fake_exec(block, *args, **kwargs):
executed.append((block.tool_type, block.content))
if block.tool_type == "read_file":
@@ -1450,7 +1483,8 @@ def test_tui_coding_turn_replaces_duplicate_edit_with_requested_tests(monkeypatc
"role": "user",
"content": (
"A regression was introduced in nested backend error handling. "
"Find the cause, fix it with a scoped change, and run the relevant tests."
"Find the cause, fix it with a scoped change, and run "
+ ("pytest -q." if explicit_verifier else "the relevant tests.")
),
}],
max_rounds=6,
@@ -1465,12 +1499,15 @@ def test_tui_coding_turn_replaces_duplicate_edit_with_requested_tests(monkeypatc
]
verification_command = json.loads(executed[-1][1])["command"]
assert "pytest" in verification_command
decision = next(event['data'] for event in events if event.get('type') == 'completion_decision')
assert decision['can_complete'] is explicit_verifier
assert (decision['status'] == 'verified') is explicit_verifier
assert any(
"Verification:" in event.get("content", "")
and "passed" in event.get("content", "")
for event in events
if event.get("type") == "final_response"
)
) is explicit_verifier
def test_failed_forced_verifier_allows_an_adapted_test_command(monkeypatch):
@@ -1491,6 +1528,7 @@ def test_failed_forced_verifier_allows_an_adapted_test_command(monkeypatch):
},
}
@authoritative_executor
async def _fake_exec(block, *args, **kwargs):
nonlocal host_attempts
executed.append((block.tool_type, block.content))
@@ -3363,6 +3401,7 @@ def test_final_prose_with_missing_artifact_enters_recovery(monkeypatch):
requests = []
executed = []
@authoritative_executor
async def _fake_exec(block, *args, **kwargs):
executed.append(block)
if block.tool_type == "write_file":