ouroboros/tests/test_delegation_phase_b.py

459 lines
21 KiB
Python

"""Phase B of the delegation-substrate sprint (owner decisions 2A/3A/5A/7A).
B1: the dispatch-time executor note (moved whole to `subagent_dispatch_notes`,
re-exported by `agent`) conditionally supersedes native-self-execution framing —
and ONLY on the final post-preflight harness dispatch. B2: the frozen acting
preamble states the write-root boundary without the "do it yourself" imperative.
B3: a really-INJECTED finalization nudge is durably stamped by the worker, and a
COMPLETED harness child with zero delegated runs carries the typed
`nanny_finalized_after_nudge_without_delegation` substrate disclosure. B4:
`capability_delta` gains typed `reduction_reasons`/`substrate_disclosures` lists
and `reason` is DERIVED from them at every writer (byte-identical to the old
hand-splice). B5: `schedule_subagent` descriptions steer objective = outcome,
context = the delegated run's work order, model_lane = leave auto.
"""
from types import SimpleNamespace
import pytest
from ouroboros import subagents
from ouroboros.subagents import (
CapabilityDelta,
DelegationRoute,
SubagentDispatch,
SubagentExecutorResolution,
SubagentLaneResolution,
derive_capability_reason,
envelope_from_task,
resolve_subagent_executor,
_disclose_native_only_substrate,
)
# ---------------------------------------------------------------- B1: dispatch note
def _resolution(executor="harness", reason="harness_ready", route="claude"):
return SubagentExecutorResolution(
requested="auto", executor=executor,
route=DelegationRoute(route_id=route) if executor == "harness" else None,
reason=reason,
)
def test_dispatch_note_override_rides_only_the_harness_branch():
from ouroboros.subagent_dispatch_notes import dispatch_executor_note
note = dispatch_executor_note(_resolution())
# The conditional supersede paragraph (owner decision 2A, verbatim wording).
assert "superseded by this dispatch" in note
assert "WORK ORDER" in note
assert "not a script for you to execute natively" in note
# A native child (the ordinary case) gets no note at all.
assert dispatch_executor_note(_resolution("native", "requested_native")) == ""
# A preflight-DEMOTED child runs native: it gets the metered-unavailable
# marker, never the delegation override (it has no delegated run to route to).
demoted = dispatch_executor_note(_resolution("native", "delegate_tools_invisible"))
assert "METERED API tokens" in demoted
assert "superseded by this dispatch" not in demoted
assert "WORK ORDER" not in demoted
# Blocked pins announce through the typed terminal, not this note.
assert dispatch_executor_note(_resolution("blocked", "delegate_tools_invisible")) == ""
def test_configured_nanny_note_states_the_charter_and_defers_truth_to_receipt():
# Charter (owner 2026-08-28): the host pre-starts the exact leaf before the
# first metered round; the note tells the nanny its rounds are judgment on
# wakes, points at the receipt as run truth, and keeps children explicit.
from ouroboros.subagent_dispatch_notes import dispatch_executor_note
lane = SubagentLaneResolution(
requested_lane="auto", effective_lane="main", model="openai/parent",
resolved_from="main", provenance="configured_subagent",
)
note = dispatch_executor_note(_resolution(), lane)
assert "BEFORE your first metered round" in note
assert "startup/wake receipt in this context is the truth" in note
assert "metered duplicate" in note
assert "cancellation and terminal settlement are verified" in note
assert "explicit separate child" in note
assert "zero_run_decision=incomplete|unknown" in note
assert "delegate everything you can" not in note
assert "WORK ORDER" not in note
def test_agent_reexports_the_moved_note_pair():
# F7: the pair moved whole to the new module; the byte-pinned transport
# suite imports both from ouroboros.agent, so the re-export must be the
# SAME objects under the same names.
import ouroboros.agent as agent
import ouroboros.subagent_dispatch_notes as notes
assert agent.dispatch_executor_note is notes.dispatch_executor_note
assert agent.executor_blocked_outcome is notes.executor_blocked_outcome
# ---------------------------------------------------------------- B2: acting preamble
def test_acting_preamble_states_the_boundary_without_the_native_imperative():
from supervisor.events import _compose_subagent_text
text = _compose_subagent_text(
"obj", role="builder", expected_output="out", constraints="", context="ctx",
task_constraint={"mode": "acting_subagent", "surface": "self_worktree",
"write_root": "/tmp/wt"},
)
assert "[WRITE SURFACE]" in text
assert "All changes land inside the write root only." in text
# The retired imperative framed the child as the native executor of the work.
assert "Make all changes" not in text
# The rest of the frozen block is intact.
assert "Do NOT commit" in text
assert "workspace.patch" in text
# ---------------------------------------------------------- B4: derived reason (byte-equality)
def _harness_ready(monkeypatch):
route = DelegationRoute(route_id="codex")
monkeypatch.setattr(
subagents, "dispatch_executor_resolution",
lambda task: resolve_subagent_executor("auto", route=route),
)
def test_writer1_resolution_reason_is_derived_and_byte_identical(tmp_path, monkeypatch):
# Two dispatch axes at once (the incident shape): a lane slot reduction plus
# an exhausted-window executor fallback. The string must be byte-identical
# to the historical "; ".join AND derived from the typed list.
monkeypatch.setenv("OUROBOROS_MODEL", "provider::main")
monkeypatch.setenv("OUROBOROS_MODEL_HEAVY", "")
route = DelegationRoute(route_id="codex")
monkeypatch.setattr(
subagents, "dispatch_executor_resolution",
lambda task: resolve_subagent_executor(
"auto", route=route, reset_at="2026-09-01T00:00:00Z"),
)
dispatch = subagents.resolve_subagent_dispatch(
{"id": "c1", "type": "task", "requested_model_lane": "heavy"},
task_type="task",
)
delta = dispatch.delta.as_dict()
assert delta["reduction_reasons"] == [
"lane_slot_unavailable=heavy", "subscription_window_exhausted"]
assert delta["substrate_disclosures"] == []
assert delta["reason"] == "lane_slot_unavailable=heavy; subscription_window_exhausted"
assert delta["reason"] == derive_capability_reason(delta["reduction_reasons"])
def test_writer2_preflight_native_fallback_derives_the_reason(tmp_path, monkeypatch):
from ouroboros.agent import preflight_delegate_visibility, resolve_dispatch_axes
monkeypatch.setenv("OUROBOROS_MODEL", "provider::main")
monkeypatch.setenv("OUROBOROS_MODEL_HEAVY", "provider::strong")
monkeypatch.setenv("OUROBOROS_MODEL_LIGHT", "provider::cheap")
_harness_ready(monkeypatch)
task = {"id": "c-fb", "type": "task", "delegation_role": "subagent",
"requested_model_lane": "auto", "parent_model_lane": "heavy",
"requested_executor": "auto"}
dispatch = resolve_dispatch_axes(task)
tools = SimpleNamespace(available_tools=lambda: ["read_file"])
amended, changed = preflight_delegate_visibility(tools, task, dispatch)
assert changed is True
delta = amended.delta.as_dict()
assert delta["reduction_reasons"][-1] == "delegate_tools_invisible"
assert delta["reason"] == derive_capability_reason(delta["reduction_reasons"])
assert delta["substrate_disclosures"] == []
# Byte-identical to the historical construction on this record too.
assert delta["reason"] == "; ".join(delta["reduction_reasons"])
def test_writer3_append_reason_derives_on_the_unverified_path(monkeypatch):
from ouroboros.agent import preflight_delegate_visibility
lane = SubagentLaneResolution(
requested_lane="auto", effective_lane="main", model="m", resolved_from="main")
dispatch = SubagentDispatch(
lane=lane, effort="low", executor="harness", route="claude",
profile="local_readonly_subagent",
delta=CapabilityDelta(requested_executor="auto", effective_executor="harness"),
executor_resolution=_resolution(),
)
task = {"id": "c1", "delegation_role": "subagent", "requested_executor": "auto",
"effective_executor": "harness", "executor_route": "claude"}
def _boom():
raise RuntimeError("registry exploded")
amended, changed = preflight_delegate_visibility(
SimpleNamespace(available_tools=_boom), task, dispatch)
assert changed is True
delta = amended.delta.as_dict()
assert delta["reduction_reasons"] == ["delegate_visibility_unverified"]
assert delta["reason"] == "delegate_visibility_unverified"
assert delta["reason"] == derive_capability_reason(delta["reduction_reasons"])
def test_writer4_substrate_amendment_derives_and_stays_byte_identical():
# NEW-format dict (typed lists present): the fact lands in the substrate
# list, reason re-derives, and the string equals the historical concat.
fresh = CapabilityDelta(
requested_lane="auto", resolved_lane="heavy", effective_lane="main",
reduction_reasons=("lane_slot_unavailable=heavy",),
reason="lane_slot_unavailable=heavy", reduced=True,
).as_dict()
amended = _disclose_native_only_substrate(fresh)
assert amended["substrate_disclosures"] == ["delegated_substrate_unused"]
assert amended["reduction_reasons"] == ["lane_slot_unavailable=heavy"]
assert amended["reason"] == "lane_slot_unavailable=heavy; delegated_substrate_unused"
assert amended["reason"] == derive_capability_reason(
amended["reduction_reasons"], amended["substrate_disclosures"])
# Idempotent, exactly as the old substring check was.
assert _disclose_native_only_substrate(amended)["reason"] == amended["reason"]
# The dispatch-time author's dict stays untouched (amend-a-copy contract).
assert fresh["substrate_disclosures"] == []
# LEGACY durable dict (string only, no lists): the historical concatenated
# shape is preserved byte-for-byte.
legacy = _disclose_native_only_substrate(
{"reason": "lane_slot_unavailable=heavy", "reduced": True})
assert legacy["reason"] == "lane_slot_unavailable=heavy; delegated_substrate_unused"
assert legacy["substrate_disclosures"] == ["delegated_substrate_unused"]
# An empty-reason amendment (the un-reduced harness dispatch) is the bare fact.
empty = _disclose_native_only_substrate(CapabilityDelta().as_dict())
assert empty["reason"] == "delegated_substrate_unused"
assert empty["reduced"] is True
def test_substrate_facts_render_as_separate_disclosure_entries():
from ouroboros.subagents import capability_delta_disclosures
delta = _disclose_native_only_substrate(CapabilityDelta(
requested_lane="auto", resolved_lane="heavy", effective_lane="main",
reduction_reasons=("lane_slot_unavailable=heavy",),
reason="lane_slot_unavailable=heavy", reduced=True,
).as_dict(), nudge_ignored=True)
parts = capability_delta_disclosures(delta)
# Slot fact and substrate facts are SEPARATE entries — never one fused phrase.
assert "model_lane auto(inherited heavy)->main" in parts
assert "delegated_substrate_unused" in parts
assert "nanny_finalized_after_nudge_without_delegation" in parts
assert not any("main" in p and "substrate" in p for p in parts)
def test_prompt_block_directs_harness_children_through_the_delegated_run():
from ouroboros.agent import capability_delta_prompt_block
def _block(effective_executor):
delta = CapabilityDelta(
requested_lane="heavy", resolved_lane="heavy", effective_lane="main",
requested_executor="auto", effective_executor=effective_executor,
reduction_reasons=("lane_slot_unavailable=heavy",),
reason="lane_slot_unavailable=heavy", reduced=True,
)
return capability_delta_prompt_block(
SimpleNamespace(delta=delta, executor_resolution=None))
harness = _block("harness")
assert "model_lane heavy->main" in harness
assert "(lane_slot_unavailable=heavy)" in harness # typed axes, not the raw string
assert "routed through your delegated run" in harness
native = _block("native")
assert "Do the work anyway, but say" in native
assert "delegated run" not in native
# ---------------------------------------------------------- B3: nudge stamp end-to-end
def _drive(tmp_path):
(tmp_path / "logs").mkdir(parents=True, exist_ok=True)
return tmp_path
def _stamp_ctx(drive):
return SimpleNamespace(task_metadata={"budget_drive_root": str(drive)})
def _harness_task(drive, **extra):
return {
"id": "child-1", "delegation_role": "subagent",
"requested_executor": "auto", "effective_executor": "harness",
"executor_route": "claude", "budget_drive_root": str(drive),
"capability_delta": {"reduced": False, "reason": "",
"reduction_reasons": [], "substrate_disclosures": []},
**extra,
}
def test_loop_injection_writes_the_durable_stamp(tmp_path):
import json
from ouroboros import delegate_custody as custody
from ouroboros.delegate_evidence import NANNY_NUDGE_STAMP
from ouroboros.loop import _maybe_inject_finalization_nudges
drive = _drive(tmp_path)
ctx = SimpleNamespace(
_nanny_route_dispatched=True, _nanny_finalization_injected=False,
task_metadata={"budget_drive_root": str(drive)},
)
tools = SimpleNamespace(_ctx=ctx, available_tools=lambda: ["delegate_start"])
msgs: list = []
assert _maybe_inject_finalization_nudges(
tools, drive, "child-1",
{"reasoning_notes": [], "tool_calls": []}, "done", msgs, lambda *_: None,
) is True
rows = [json.loads(line) for line in
(drive / "logs" / "events.jsonl").read_text(encoding="utf-8").splitlines()]
stamps = [r for r in rows if r.get("type") == NANNY_NUDGE_STAMP]
assert stamps and stamps[0]["task_id"] == "child-1"
assert stamps[0]["nanny_code"] == "NANNY_DID_NOT_DELEGATE"
assert custody.task_execution_evidence(drive, "child-1")["nanny_nudge_recorded"] is True
def test_suppressed_nudge_writes_no_stamp(tmp_path):
# Verbs policy-hidden: the ctx flag is still latched, the message is empty,
# and NO stamp lands — the flag can never impersonate a fired nudge.
from ouroboros import delegate_custody as custody
from ouroboros.loop import _maybe_inject_finalization_nudges
drive = _drive(tmp_path)
ctx = SimpleNamespace(
_nanny_route_dispatched=True, _nanny_finalization_injected=False,
task_metadata={"budget_drive_root": str(drive)},
)
tools = SimpleNamespace(_ctx=ctx, available_tools=lambda: ["read_file"])
assert _maybe_inject_finalization_nudges(
tools, drive, "child-1",
{"reasoning_notes": [], "tool_calls": []}, "done", [], lambda *_: None,
) is False
assert ctx._nanny_finalization_injected is True # the flag alone is not the signal
assert custody.task_execution_evidence(drive, "child-1")["nanny_nudge_recorded"] is False
def test_nudge_fact_rides_only_completed_native_only_envelopes(tmp_path):
from ouroboros.delegate_evidence import record_nanny_nudge_stamp
drive = _drive(tmp_path)
record_nanny_nudge_stamp(_stamp_ctx(drive), "child-1", "NANNY_DID_NOT_DELEGATE")
# Nudge fired + zero starts + completed -> the typed fact rides the envelope.
envelope = envelope_from_task(_harness_task(drive), status="completed")
delta = envelope["capability_delta"]
assert "nanny_finalized_after_nudge_without_delegation" in delta["substrate_disclosures"]
assert "delegated_substrate_unused" in delta["substrate_disclosures"]
assert delta["reason"] == (
"delegated_substrate_unused; nanny_finalized_after_nudge_without_delegation")
assert envelope["execution_evidence"]["nanny_nudge_recorded"] is True
# Cancelled: the substrate amendment still discloses, the FINALIZED
# accusation does not (completed-only, B3).
cancelled = envelope_from_task(_harness_task(drive), status="cancelled")
cdelta = cancelled["capability_delta"]
assert "delegated_substrate_unused" in cdelta["substrate_disclosures"]
assert "nanny_finalized_after_nudge_without_delegation" not in cdelta["substrate_disclosures"]
def test_a_refused_attempt_after_the_nudge_is_never_an_accusation(tmp_path):
"""Final-review finding (codex proton0): a nanny that OBEYED the nudge —
called delegate_start and was refused typed before any run existed — must
not be disclosed as having finalized "without delegation". Both durable
attempt shapes count: the pre-mint typed blocker row and a request row
whose POST then died."""
from ouroboros import delegate_custody as custody
from ouroboros.delegate_evidence import record_nanny_nudge_stamp, record_start_blocked
# Shape 1: typed route_health blocker before any invocation was minted.
drive = _drive(tmp_path / "blocked")
record_nanny_nudge_stamp(_stamp_ctx(drive), "child-1", "NANNY_DID_NOT_DELEGATE")
record_start_blocked(_stamp_ctx(drive), "child-1", "route_status_unavailable")
evidence = custody.task_execution_evidence(drive, "child-1")
assert evidence["delegate_start_attempted"] is True
assert evidence["delegated_runs_started"] == 0
envelope = envelope_from_task(_harness_task(drive), status="completed")
delta = envelope["capability_delta"]
assert "delegated_substrate_unused" in delta["substrate_disclosures"]
assert "nanny_finalized_after_nudge_without_delegation" not in delta["substrate_disclosures"]
# Shape 2: the durable request row landed, the POST failed, nothing started.
drive2 = _drive(tmp_path / "requested")
record_nanny_nudge_stamp(_stamp_ctx(drive2), "child-1", "NANNY_DID_NOT_DELEGATE")
assert custody.emit(drive2, custody.START_REQUESTED, {
"task_id": "child-1", "invocation_id": "inv-1", "route": "claude",
"request": {"prompt": "x"}})
envelope2 = envelope_from_task(_harness_task(drive2), status="completed")
assert ("nanny_finalized_after_nudge_without_delegation"
not in envelope2["capability_delta"]["substrate_disclosures"])
# A truly idle nanny (stamp, zero attempts) is still disclosed.
idle = _drive(tmp_path / "idle")
record_nanny_nudge_stamp(_stamp_ctx(idle), "child-1", "NANNY_DID_NOT_DELEGATE")
envelope3 = envelope_from_task(_harness_task(idle), status="completed")
assert ("nanny_finalized_after_nudge_without_delegation"
in envelope3["capability_delta"]["substrate_disclosures"])
def test_nudge_fact_absent_when_delegation_happened_or_nudge_never_fired(tmp_path):
from ouroboros import delegate_custody as custody
from ouroboros.delegate_evidence import record_nanny_nudge_stamp
# Delegation happened (a run started): not native_only, no amendment at all.
drive = _drive(tmp_path / "ran")
record_nanny_nudge_stamp(_stamp_ctx(drive), "child-1", "NANNY_DELEGATED_RUN_PENDING")
assert custody.emit(drive, custody.STARTED, {
"run_id": "run-1", "task_id": "child-1", "route": "claude", "max_seconds": 300})
envelope = envelope_from_task(_harness_task(drive), status="completed")
assert envelope["actual_substrate"] == "harness_attempted"
assert envelope["capability_delta"]["reduced"] is False
# Nudge never fired (no stamp): native_only still discloses the unused
# substrate, without the nudge-ignored accusation.
quiet = _drive(tmp_path / "quiet")
envelope = envelope_from_task(_harness_task(quiet), status="completed")
delta = envelope["capability_delta"]
assert delta["substrate_disclosures"] == ["delegated_substrate_unused"]
assert delta["reason"] == "delegated_substrate_unused"
# ---------------------------------------------------------------- B5: schema descriptions
def test_schedule_subagent_descriptions_carry_the_delegation_guidance():
from ouroboros.tools.control import schedule_subagent_properties
props = schedule_subagent_properties()
objective = props["objective"]["description"]
assert "OUTCOME" in objective and "script" in objective
context = props["context"]["description"]
assert "not instructions" in context and "WORK ORDER" in context
selector = props["subagent_id"]["description"]
assert "Available subagent" in selector and "exact" in selector.lower()
assert "model_lane" not in props
assert "executor" not in props
assert all("type" in spec for spec in props.values())
# ------------------------------------------------- as_dict carries the additive fields
def test_capability_delta_as_dict_carries_the_typed_lists_additively():
delta = CapabilityDelta().as_dict()
assert delta["reduction_reasons"] == []
assert delta["substrate_disclosures"] == []
# The pre-split keys all survive unchanged (additive-only, decision 7A).
for key in ("requested_lane", "resolved_lane", "effective_lane", "lane_provenance",
"derived_effort", "effective_effort", "requested_executor",
"effective_executor", "reason", "reduced", "legacy_note"):
assert key in delta
if __name__ == "__main__":
raise SystemExit(pytest.main([__file__, "-x", "-q"]))