ouroboros/tests/test_delegate_preflight.py
Ouroboros cccc758f6b release 6.94.0: external-project delegation gap closed, nanny/evidence honesty end to end (sprint phase A)
The Slime Lab Escape saga (2026-08-10; 4 attempts, ~$215, the game built
twice) exposed that _WORKSPACE_ALLOWED_TOOLS predates delegation: tasks in
external project workspaces and their read-only children were resolved onto
the harness route and instructed to be nannies while delegate_start/wait/
cancel were filtered from their toolsets — every nanny burned metered API
tokens while the subscription paid $0, and a task contract demanded
send_photo while the same filter hid it.

- _WORKSPACE_ALLOWED_TOOLS += delegate_start/wait/cancel, switch_model,
  send_photo/send_video/send_file; subset invariant test pins both child
  profiles inside the envelope (registry.py additions only — no filter
  predicate changed).
- F3: enable_tools answers 'hidden by policy: <reason>' vs 'not found' via
  read-only registry.policy_hidden_reason(), drift-pinned to
  get_schema_by_name across six context variants; answers for
  contract-disabled names across ALL discovery sources.
- F4: nanny nudge reads durable delegate_custody.task_execution_evidence
  from the canonical (budget) custody root, so split-root subagents see
  their own delegated runs; PENDING != FAILED — started-but-unsettled runs
  emit NANNY_DELEGATED_RUN_PENDING (wait/cancel, do not finalize over an
  in-flight run) and NANNY_DELEGATED_RUN_FAILED is reserved for terminal
  non-successes.
- Q1A: capability preflight before the first paid LLM round
  (agent.preflight_delegate_visibility): a harness-dispatched child whose
  materialized toolset lacks any of the three delegate verbs either ends
  unrun through the typed zero-spend blocked outcome (explicit harness pin;
  delegate_tools_invisible, or delegate_visibility_unverified when toolset
  introspection itself failed) or falls back LOUDLY to native (auto; typed
  capability_delta, dispatch fields re-recorded).
- Substrate honesty: actual_substrate is a purely factual enum from custody
  evidence only (harness_used / harness_attempted / native_only) with raw
  attested counts beside it on every surface (durable result, public
  envelope, wait_tasks projection); unreadable evidence OMITS the claim
  (unknown is never native_only) and evidence_read_failed renders as typed
  unknown ("evidence unavailable"), never a false no-run receipt.
- F6 live toolset: promoted_task_toolset is built from the REAL registry
  availability resolution (workspace and non-workspace probes, live
  credential gates, typed unavailable_builtin_tools reasons), not the
  static allowlist union.
- Q2-B: dispatch note = decide delegation first, typed cost classes,
  delegate even small tasks on a healthy lane; no bare 'free'.
- Function-size gate honored: _prepare_task_context decomposed
  (_run_delegate_preflight / _capture_mutation_baseline).
- Docs + ABI mirrors synced; version carriers 6.94.0; README 6.94.0 row
  extended at landing with the amendment behaviors and the PR #176
  disclosure (community Linux .deb/.rpm packaging rides the same landing).

Squash of sprint/slime-landing 628de71e..7ecaa2bc (b49f8192 phase A initial,
6c03c24e audit amendments, 7ecaa2bc review-wave corrective batch) onto the
PR #176 merge; tree verified identical to 7ecaa2bc modulo the README row
amendment.

Adversarial review: initial wave on b49f8192 (SAFE TO PROCEED, accepted
findings applied) + full wave on 6c03c24e (fable triad + two gpt-5.6-sol
lanes + gemini; CRITICAL/HIGH/LOW accepted findings landed in 7ecaa2bc).
Plan: ~/.claude/plans/ouroboros-slime-saga-sprint.md (owner-approved).

Landing-gate scope fix: unreadable custody evidence emits no fabricated zero counts in the wait_tasks projection.

Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
2026-08-11 01:22:47 +03:00

169 lines
7.1 KiB
Python

"""Q1A capability preflight (2026-08-10 amendments): a harness dispatch whose
materialized toolset does not carry the delegate verbs must never pay for a
single LLM round under a dispatch record that says "harness".
The audited incident (task e9108a09c6574184, "slime games research PDF"): nine
children recorded effective_executor=harness / executor_route=codex, made ZERO
delegated runs and burned ~$29-54 of metered API, while their results said
execution=ok and capability_delta.reduced=false. The Phase A allowlist widening
closed one instance of the class; this preflight closes the class at the last
zero-cost moment — toolset materialization.
"""
from types import SimpleNamespace
from ouroboros.agent import (
_blocked_executor_terminal,
executor_blocked_outcome,
preflight_delegate_visibility,
)
from ouroboros.subagents import (
CapabilityDelta,
SubagentDispatch,
SubagentExecutorResolution,
SubagentLaneResolution,
)
def _dispatch(requested_executor="auto", executor="harness"):
lane = SubagentLaneResolution(
requested_lane="auto", effective_lane="main", model="test-model",
resolved_from="main",
)
delta = CapabilityDelta(
requested_lane="auto", resolved_lane="main", effective_lane="main",
derived_effort="low", effective_effort="low",
requested_executor=requested_executor, effective_executor=executor,
reason="", reduced=False,
)
resolution = SubagentExecutorResolution(
requested=requested_executor, executor=executor, route=None,
reason="harness_ready" if executor == "harness" else "requested_native",
)
return SubagentDispatch(
lane=lane, effort="low", executor=executor,
route="claude" if executor == "harness" else "",
profile="local_readonly_subagent", delta=delta,
executor_resolution=resolution,
)
def _task(requested_executor="auto"):
return {
"id": "child-1",
"delegation_role": "subagent",
"requested_executor": requested_executor,
"effective_executor": "harness",
"executor_route": "claude",
}
def _tools(available):
return SimpleNamespace(available_tools=lambda: list(available))
def test_visible_verbs_leave_the_dispatch_untouched():
dispatch = _dispatch()
task = _task()
result, amended = preflight_delegate_visibility(
_tools(["delegate_start", "delegate_wait", "delegate_cancel", "read_file"]),
task, dispatch)
assert result is dispatch
assert amended is False
assert task["executor_route"] == "claude" # nothing re-stamped
def test_partial_verb_set_is_still_broken():
# A child that can start a run but not wait on it cannot honor the contract.
dispatch = _dispatch(requested_executor="auto")
task = _task(requested_executor="auto")
result, amended = preflight_delegate_visibility(
_tools(["delegate_start", "delegate_cancel", "read_file"]), task, dispatch)
assert amended is True
assert result.executor == "native"
assert "delegate_tools_invisible" in task["capability_delta"]["reason"]
def test_auto_dispatch_with_invisible_verbs_falls_back_loudly_to_native():
dispatch = _dispatch(requested_executor="auto")
task = _task(requested_executor="auto")
result, amended = preflight_delegate_visibility(
_tools(["read_file", "web_search"]), task, dispatch)
assert amended is True
assert result.executor == "native"
assert result.route == ""
# The typed capability_delta entry: the parent and the owner SEE the reduction.
assert task["capability_delta"]["reduced"] is True
assert "delegate_tools_invisible" in task["capability_delta"]["reason"]
assert task["capability_delta"]["effective_executor"] == "native"
# The recorded dispatch fields no longer lie.
assert task["effective_executor"] == "native"
assert task["executor_route"] == ""
assert task["subagent_envelope"]["effective_executor"] == "native"
assert task["subagent_envelope"]["executor_route"] == ""
def test_explicit_harness_pin_with_invisible_verbs_blocks_with_zero_spend():
dispatch = _dispatch(requested_executor="harness")
task = _task(requested_executor="harness")
result, amended = preflight_delegate_visibility(
_tools(["read_file"]), task, dispatch)
assert amended is True
assert result.blocked is True
assert task["effective_executor"] == "blocked"
# The existing blocked terminal carries the distinct typed reason.
text, usage = executor_blocked_outcome(result.executor_resolution)
assert usage["reason_code"] == "delegate_tools_invisible"
assert usage["execution_status"] == "infra_failed"
assert "not visible" in text
assert "NOT run on metered API tokens" in text
# And the cap_info seam _prepare_task_context feeds rebuilds the same outcome.
cap_info = {
"executor_blocked_reason": result.executor_resolution.reason,
"executor_blocked_requested": result.executor_resolution.requested,
"executor_blocked_reset_at": result.executor_resolution.reset_at,
}
terminal_text, terminal_usage, _trace = _blocked_executor_terminal(cap_info)
assert terminal_usage["reason_code"] == "delegate_tools_invisible"
assert "delegate_start" in terminal_text
def _broken_tools():
def _boom():
raise RuntimeError("registry exploded")
return SimpleNamespace(available_tools=_boom)
def test_broken_introspection_with_auto_executor_proceeds_disclosed():
# Fail-open for auto — but never silently: the probe failure rides the delta.
dispatch = _dispatch(requested_executor="auto")
task = _task(requested_executor="auto")
result, amended = preflight_delegate_visibility(_broken_tools(), task, dispatch)
assert amended is True
assert result.executor == "harness" # the dispatch itself is kept
assert task["effective_executor"] == "harness"
assert "delegate_visibility_unverified" in task["capability_delta"]["reason"]
def test_broken_introspection_with_pinned_harness_fails_closed():
# A probe that cannot prove visibility cannot prove the pinned contract is
# executable: the typed blocked outcome, zero spend — under the HONEST
# reason (visibility is unknown, not disproven).
dispatch = _dispatch(requested_executor="harness")
task = _task(requested_executor="harness")
result, amended = preflight_delegate_visibility(_broken_tools(), task, dispatch)
assert amended is True
assert result.blocked is True
assert task["effective_executor"] == "blocked"
text, usage = executor_blocked_outcome(result.executor_resolution)
assert usage["reason_code"] == "delegate_visibility_unverified"
assert "could not be verified" in text
assert "NOT run on metered API tokens" in text
def test_native_and_undispatched_children_are_not_probed():
probe_forbidden = SimpleNamespace(
available_tools=lambda: (_ for _ in ()).throw(AssertionError("must not probe")))
native = _dispatch(executor="native")
assert preflight_delegate_visibility(probe_forbidden, _task(), native) == (native, False)
assert preflight_delegate_visibility(probe_forbidden, _task(), None) == (None, False)