mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-03 04:07:04 +00:00
tests: the paid E-lane's first executions — a real delegated leaf in the roster, E1 asserts open faults; receipts in the ledger (owner batch №13 item 2 = A)
E13 is green on a priced route (openrouter::anthropic/claude-haiku-4.5); E1 is green once its assertion reads open containment faults rather than the faults LOG (which carries resolution rows). E2/E3 reach the real Claudexor lane and are refused there — «Claude subscription route is not ready»: delegate_start asks for the subscription substrate on purpose and an isolated install's owned daemon has no login, which only the owner may create. Row DEFER-E2E-PAID-LANE keeps its deferral under OWNER authority with that residual. Product finding recorded: a data root deep enough to push the owned daemon's unix socket past AF_UNIX's limit refuses every delegated start (`listen EINVAL`).
This commit is contained in:
parent
79597f9db0
commit
cb736346d0
5 changed files with 49 additions and 9 deletions
|
|
@ -107,7 +107,7 @@ Schema (fixed; one row per artifact-level delta family, never per commit):
|
|||
| W4-F3 | plan-item | Evolution restart marker vs manual restarts: `request_evolution_restart` returns BEFORE writing `pending_restart_verify.json` when `OUROBOROS_EVOLUTION_AUTO_RESTART` is off, so the exact-claim verify path (`require_claim=True`) is structurally unreachable for installs that restart by hand; absorb attribution then rests on the weaker markerless path. Found by the F4 wave-4 system-E2E lane (docs/v7next/LEDGER_CORRECTIONS.md «E2E-находки w4»), judged «looks intentional», not fixed by that lane's rule; no owner decision recorded. residual: manual-restart installs never exercise the strict verify path in 7.0 | post-release | deferred | POST | docs/v7next/LEDGER_CORRECTIONS.md (w4 findings table, row W4-F3) |
|
||||
| W4-F4 | plan-item | Rescue-local ref accumulation: `create_rescue_local_ref` pins every update stash to a durable `rescue-local-<stash12>` branch and nothing ever deletes them — a refused/unwound attempt leaves its ref exactly like a successful one. Deliberate durability («git-gc can never lose the owner's work»); the unbounded per-distinct-stash growth is the disclosed cost. Same wave-4 lane; no owner decision recorded. residual: the branch list grows with every distinct update stash in 7.0 | post-release | deferred | POST | docs/v7next/LEDGER_CORRECTIONS.md (w4 findings table, row W4-F4) |
|
||||
| DEFER-E2E-DELEG-MUT | plan-item | System-E2E scenarios for MUTATING delegated runs (snapshot + patch pull-in + isolation proof) were carried across the F4 waves and never landed: S1-S23 contain only non-mutating delegation runs. Declared «deferred (disclosed)» by the operator in the wave-3b and wave-4 ledger sections; no owner decision recorded (owner question in the STOP batch). residual: the one delegation branch that changes the working tree on behalf of an external harness has no system-E2E cover in 7.0 | post-release | deferred | POST | docs/v7next/LEDGER_CORRECTIONS.md («Deferred (disclosed)» in the F4 wave-3b and wave-4 sections) |
|
||||
| DEFER-E2E-PAID-LANE | plan-item | The paid («live») system-E2E lane — E1 (delegated launch → wait → answer → cancel), E2/E3 (clean and conflicting delegated patch pull-in) and E13 (a task with an exhausted budget PAUSES before dispatch, replacing the withdrawn E8) — is written (tests/test_e2e_cancellation_scenarios.py, fixtures_e2e_cancellation.py LANE_PAID) and has never been executed: it needs a model with a known price, which the mock lane has not. Plan §8/§10 made an owner-live quittance on the exact SHA an acceptance criterion; no owner decision to waive it is recorded (owner question in the STOP batch). residual: the four scenarios are unverified on any SHA until the owner either runs them (units of $) or waives the criterion | post-release | deferred | POST | tests/test_e2e_cancellation_scenarios.py (module docstring) + tests/fixtures_e2e_cancellation.py (LANE_PAID) |
|
||||
| DEFER-E2E-PAID-LANE | plan-item | The paid («live») system-E2E lane — E1 (delegated launch → wait → answer → cancel), E2/E3 (clean and conflicting delegated patch pull-in) and E13 (a task with an exhausted budget PAUSES before dispatch, replacing the withdrawn E8) — is written (tests/test_e2e_cancellation_scenarios.py, fixtures_e2e_cancellation.py LANE_PAID) and has never been executed: it needs a model with a known price, which the mock lane has not. Plan §8/§10 made an owner-live quittance on the exact SHA an acceptance criterion; no owner decision to waive it is recorded (owner question in the STOP batch). residual: the four scenarios are unverified on any SHA until the owner either runs them (units of $) or waives the criterion EXECUTED BY OWNER DECISION: batch №13 item 2 (2026-09-02, [A-BATCH-13-ANSWERS]), owner verbatim «2. A». Runs 2026-09-02/03 on ad39ec54, 6bd799fb, ca1b38df, 9c04ff47 (operator receipts in LEDGER «From the paid E-lane»): E13 GREEN on `openrouter::anthropic/claude-haiku-4.5` (a priced route; `anthropic::` has no tariff, so the drain never fires there — by design, cost unknown is never enforced); E1 GREEN once its fault assertion read OPEN faults (the faults log carries resolution rows); E2/E3 reach the real Claudexor lane and are refused by it: `claude is unavailable: Claude subscription route is not ready` — `delegate_start` asks for the subscription substrate by design and the owned daemon of an isolated install has no login; an interactive login is the owner's act. residual: E2/E3 (clean and conflicting delegated patch pull-in) unexecuted until an install with a logged-in Claude account runs the lane | post-release | deferred | POST | tests/test_e2e_cancellation_scenarios.py (module docstring) + tests/fixtures_e2e_cancellation.py (LANE_PAID) |
|
||||
| DEFER-TYPED-PROC-5 | plan-item | Owner batch №7 item 1=A retired the regex fallback that guessed process exit codes from prose; five surfaces were then left WITHOUT typed exit/signal facts: extension child-process death, `skill_exec`/`skill_preflight`, `verify_and_record` (printed `exit=`, stamped nothing), `run_command` timeouts and pre-exec failures, Windows kills. LANDED by owner batch №13 item 10 = B (typed process-facts lane): the thread-local channel is now PUBLISHER-scoped instead of tool-name-scoped (the `_PROCESS_META_TOOLS` table is retired; the loop clears the slot before EVERY dispatch, which is a stronger no-contamination contract than the name gate it replaces), and the family grows three members that exist exactly where an exit code does not — `timed_out`, `killed_by_host`, `pre_exec_failure` (the platform's exception class). Producers stamp at the point the truth is known: the extension child in `_run_child` (clean exit, abnormal exit with its POSIX signal, deadline kill, output-cap kill), `_run_skill_subprocess` (including the negative code its `returncode or 0` return flattens, and the spawn OSError), the `skill_preflight` validators — whose synthesized `-9`/`-1` are RETIRED for `returncode=None` plus the typed reason, since the fakes read downstream as real POSIX signal deaths (on Windows too, where a host kill produces none) — and the `verify_and_record` check, whose receipt now copies the SAME publication instead of deriving duration/signal a second time. Consumers: one projection feeds the UI live-log card, the tools.jsonl row and the durable trace. Windows kills are carried honestly rather than faked: `killed_by_host` beside whatever `TerminateProcess` left in `exit_code`, and never a fabricated signal name — Windows-executed proof pending the matrix | retain | done | F6 | tests/test_process_signal_observability.py::test_extension_child_death_publishes_typed_exit_and_signal + tests/test_process_signal_observability.py::test_skill_exec_signal_death_survives_the_or_zero_flattening + tests/test_process_signal_observability.py::test_skill_preflight_timeout_reports_no_returncode_instead_of_fake_minus_nine + tests/test_process_signal_observability.py::test_verify_check_publishes_typed_exit_and_signal + tests/test_process_signal_observability.py::test_run_shell_timeout_publishes_typed_timeout_facts + tests/test_process_signal_observability.py::test_windows_host_kill_carries_no_forged_signal + tests/test_process_signal_observability.py::test_tools_jsonl_row_carries_the_typed_process_facts |
|
||||
| DEFER-SPEC64-PATHS | plan-item | Spec §6.4 «Paths/roots» (OUROBOROS_V7_SPEC_v72.md ~:815-820) — one `HostPaths`/`TaskPaths` authority, removal of the two `SimpleNamespace` Env clones in agent_task_pipeline.py (:241, :681) and of the silent `Path.home()/Ouroboros/data` fallbacks in seven domain modules — was never delivered on the oracle or here and never entered any inventory or decision; the bytes are inherited from upstream (no regression). DEFERRED OUT OF 7.0 BY THE OWNER: batch №13 item 8 (2026-09-02, [A-BATCH-13-ANSWERS]), owner verbatim «8. A» on «post-release строка — подтвердить». residual: with an incomplete OUROBOROS_* env set a process can still resolve two different data roots without an error | post-release | deferred | POST | OUROBOROS_V7_SPEC_v72.md §6.4 (the requirement); this row (the only tracking) |
|
||||
| DEFER-F23-ACCEPTANCE | plan-item | Roast recommendation F23 — a machine-readable `acceptance.json` with schema and checker (exact SHA, run/artifact ids, scenario consumption, D02-D38 dispositions with decision ids, review quorum, cost cap) — was accepted into the plan (V7NEXT_PLAN.md :261) and never built; the release bar (`scripts/v7next_adoption.py --release`), `scripts/rc_audit.py` and the exact-SHA evidence manifests cover part of it (rows/hooks/gates), not quorum, cost or scenario consumption. Recorded so the gap is visible (owner question in the STOP batch: build before the tag / post-release / close as covered-by-gates). residual: campaign acceptance is proven by the evidence manifests and the validator, not by one generated capsule CLOSED AS COVERED-BY-GATES BY THE OWNER: batch №13 item 7 (2026-09-02, requirements archive [A-BATCH-13-ANSWERS]), owner verbatim «7. A» on «закрыть F23 как «покрыт гейтами» с записью пробелов». What covers it: the exact-SHA evidence manifests (every gate its own rc, HEAD after each gate, live-data inventory), `scripts/v7next_adoption.py --release` (rows/hooks/authority) with its pytest wrapper, `scripts/rc_audit.py`. residual: no single generated capsule; review quorum, spend and scenario consumption are proven by the ledger sections and the operator's manifests, not by one machine-readable file | retain | done | F6 | scripts/v7next_adoption.py + tests/test_v7next_adoption.py (the release bar) |
|
||||
|
|
|
|||
|
|
@ -9203,3 +9203,30 @@ publication (and moved the key-by-key rationale to `_RECEIPT_PROCESS_KEYS`,
|
|||
where the contract now lives), and `_handle_skill_exec` gave its two pre-exec
|
||||
publications back to `_run_skill_subprocess`, which is where the spawn — and
|
||||
therefore the truth about it — actually is.
|
||||
|
||||
## From the paid E-lane (owner batch №13 item 2 = A; first executions 2026-09-02/03)
|
||||
|
||||
Receipts (operator host, isolated roots under /tmp/claude-1006, keys passed BY NAME, values never printed):
|
||||
|
||||
| run | tree | model / key name | result |
|
||||
|---|---|---|---|
|
||||
| 20:28–20:50Z 02.09 | ad39ec54 | `anthropic::claude-haiku-4-5` / `anthropic` | 4/4 red — E1–E3: `delegate_start` refused («api_actor_requires_schedule_subagent», then «subagent_selection_required»): the lane's roster had only an `api_model` row; E13: `spent_usd 0.0` after four completed tasks — the direct `anthropic::` route has no tariff, the drain never fires |
|
||||
| 07:40–07:47Z 03.09 | 6bd799fb | `openrouter::anthropic/claude-haiku-4.5` / `anton_new_nsfw_key_openrouter` | E13 GREEN (budget_scope_paused recorded, no intents left); E1–E3: owned claudexord failed to start — `listen EINVAL` on its unix socket: the isolated root under the operator's private TMPDIR made `data/claudexor/daemon/claudexord.sock` 115 bytes, beyond AF_UNIX's 108 |
|
||||
| 07:48–07:55Z 03.09 | ca1b38df | same, `--basetemp=/tmp/claude-1006/pb` | E1: the four verb families landed, the assertion read the faults LOG as a fault (it held only `delegate_run_containment_resolved` rows); E2/E3: the run reaches the real lane and fails at routing — `claude is unavailable: Claude subscription route is not ready` |
|
||||
| 07:56–07:58Z 03.09 | 9c04ff47 | same | E1 GREEN with the assertion on `open_containment_faults(data_root) == []` |
|
||||
|
||||
Adjustments to the lane (test-shape, committed with this section): the paid roster gets a real
|
||||
delegated leaf (`agent_session`, `claude=claude-haiku-4-5`) and E1–E3 name it in `subagent_id`;
|
||||
E1 asserts OPEN faults. Not adjusted: E2/E3 — `ouroboros/tools/delegate.py` asks the engine for
|
||||
`authPreference: subscription` on purpose (an invisible API-key fallback would settle a run at a
|
||||
confident $0.00), and the owned daemon of an isolated install has no subscription login; logging an
|
||||
account into it is an interactive owner act the operator may not perform. E2/E3 therefore remain
|
||||
unexecuted (row DEFER-E2E-PAID-LANE, OWNER authority) until the owner's own logged-in install runs
|
||||
`OUROBOROS_E2E_CANCEL=paid`.
|
||||
|
||||
Product finding from the lane (disclosed, post-release issue draft): the owned claudexord listens on
|
||||
`<data>/claudexor/daemon/claudexord.sock`; a data root deeper than ~70 characters puts that path over
|
||||
the AF_UNIX limit (108 on Linux, 104 on macOS) and every delegated start is refused with
|
||||
`daemon_spawn_failed` whose log tail reads `listen EINVAL` — the refusal is typed but the cause is not
|
||||
named. Ordinary installs (`~/Ouroboros/data`) are far below the limit; deep roots (nested temp dirs,
|
||||
long usernames under /Users) are not.
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ DEFERRED_OUT_OF_V70 = {
|
|||
"W4-F3": OPERATOR,
|
||||
"W4-F4": OPERATOR,
|
||||
"DEFER-E2E-DELEG-MUT": OPERATOR,
|
||||
"DEFER-E2E-PAID-LANE": OPERATOR,
|
||||
"DEFER-E2E-PAID-LANE": OWNER, # batch №13 item 2 = A; E1/E13 executed, E2/E3 await a logged-in install
|
||||
"DEFER-SPEC64-PATHS": OWNER, # batch №13 item 8 = A
|
||||
}
|
||||
# Post-cutoff upstream adoption trains: id -> (upstream tip, campaign merge).
|
||||
|
|
|
|||
|
|
@ -333,7 +333,17 @@ def isolated_settings(*, stub: StubModelServer | None, paid: bool = False, **ove
|
|||
"recommended_use": "Read-only survey for the E2E cancellation lane.",
|
||||
"route": {"kind": "api_model", "target_id": slug},
|
||||
"effort": "low",
|
||||
}],
|
||||
}] + ([{
|
||||
# The paid lane's REAL delegated leaf (E1-E3): `delegate_start` refuses an
|
||||
# api_model row («api_actor_requires_schedule_subagent») and requires an
|
||||
# explicit subagent_id — first paid execution, 2026-09-02, found both.
|
||||
# The harness is Claudexor's `claude` route on the host's own login.
|
||||
"subagent_id": "delegated-leaf",
|
||||
"name": "Delegated leaf",
|
||||
"recommended_use": "Real delegated run through the Claudexor lane (paid E1-E3).",
|
||||
"route": {"kind": "agent_session", "target_id": "claude=claude-haiku-4-5"},
|
||||
"effort": "low",
|
||||
}] if paid else []),
|
||||
})
|
||||
cfg.update(overrides)
|
||||
return cfg
|
||||
|
|
|
|||
|
|
@ -668,7 +668,7 @@ def test_e1_delegated_run_lifecycle_emits_the_four_verb_families(e2e_clone, tmp_
|
|||
try:
|
||||
data_root = server.data_root
|
||||
task_id = server.submit(
|
||||
"Use delegate_start to open one delegated run that asks a trivial question, "
|
||||
"Use delegate_start(subagent_id=\"delegated-leaf\") to open one delegated run that asks a trivial question, "
|
||||
"delegate_wait for it, delegate_answer any interaction it raises, then "
|
||||
"delegate_cancel the run and finish."
|
||||
)
|
||||
|
|
@ -676,9 +676,12 @@ def test_e1_delegated_run_lifecycle_emits_the_four_verb_families(e2e_clone, tmp_
|
|||
assert events(data_root, "delegate_run_start_requested"), "no delegated run was requested"
|
||||
assert events(data_root, "delegate_run_started"), "the delegated run never started"
|
||||
assert events(data_root, "delegate_run_cancel_outcome"), "no cancel outcome was recorded"
|
||||
faults = pathlib.Path(data_root) / "logs" / "containment_faults.jsonl"
|
||||
assert not (faults.exists() and faults.read_text(encoding="utf-8").strip()), \
|
||||
"the delegated lane recorded a containment fault"
|
||||
from ouroboros.delegate_custody import open_containment_faults
|
||||
# The faults log is a LEDGER: a resolution row follows its fault, and a clean run
|
||||
# writes only resolutions (first paid execution, 2026-09-03: `settled_terminal`,
|
||||
# `verified_terminal`). Open faults are the fault, not the file's existence.
|
||||
assert open_containment_faults(data_root) == [], \
|
||||
"the delegated lane left an OPEN containment fault"
|
||||
finally:
|
||||
server.stop()
|
||||
|
||||
|
|
@ -692,7 +695,7 @@ def test_e2_delegated_patch_integration_disposes_the_snapshot(e2e_clone, tmp_pat
|
|||
try:
|
||||
data_root = server.data_root
|
||||
task_id = server.submit(
|
||||
"Open a MUTATING delegated run that adds one new file with a single line of "
|
||||
"Open a MUTATING delegated run with delegate_start(subagent_id=\"delegated-leaf\") that adds one new file with a single line of "
|
||||
"text, then integrate its patch with integrate_delegated_patch and finish."
|
||||
)
|
||||
server.wait_task(task_id, timeout=1800)
|
||||
|
|
@ -715,7 +718,7 @@ def test_e3_conflicting_delegated_patch_preserves_the_snapshot(e2e_clone, tmp_pa
|
|||
try:
|
||||
data_root = server.data_root
|
||||
task_id = server.submit(
|
||||
"Open a MUTATING delegated run that edits README.md, then — before "
|
||||
"Open a MUTATING delegated run with delegate_start(subagent_id=\"delegated-leaf\") that edits README.md, then — before "
|
||||
"integrating — change the same lines of README.md yourself, then attempt "
|
||||
"integrate_delegated_patch and report what happened."
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue