Skip to content

feat(runtime): establish DoubleAgent service foundation - #39

Merged
bzimbler merged 4 commits into
feat/doubleagent-v2from
feat/ISL-1744
Oct 21, 2026
Merged

bzimbler merged 4 commits into
feat/doubleagent-v2from
feat/ISL-1744

Conversation

@islo-labs

@islo-labs islo-labs Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Replace the research runtime with the Python 3.11+ runtime, experimental Service SDK v0, explicit service manifests, immutable task/evaluation context, fail-closed dispatch, and a single Rust router crate.
  • Preserve each managed request's source ID in a per-dispatch upstream binding. The transport receives source_request_id as a keyword argument; concurrent dispatches cannot overwrite a shared service context.
  • Preserve the original request scheme and exact raw target alongside parsed query pairs through Python and Rust protocol v1. Reject non-object frames with the documented runtime error response.
  • Report unhealthy while required process capabilities are unavailable; require exact normalized managed-host agreement at router startup and every health probe.
  • Strictly validate trusted launch JSON with Pydantic v2. Limit frames to 10 MiB and concurrent router ingress frame bytes to 40 MiB, with fail-closed overload responses. Update the SDK and protocol docs.

Verification

  • Added focused regressions for all six review findings and confirmed they failed on the previous head before implementation.
  • cargo build -p doubleagent-router, uv run pytest (33 passed), uv run ruff check ., uv run ruff format --check ., and uv run pre-commit run --all-files passed.
  • cargo fmt --all -- --check, cargo clippy -p doubleagent-router --all-targets -- -D warnings, and cargo test -p doubleagent-router (7 passed) passed.

Cross-ticket interface assumptions

  • The trusted control plane supplies one raw registered task and immutable evaluation binding in a strictly validated local launch document. Hosted task retrieval and persistence belong to ISL-1743; orchestration belongs to ISL-1769.
  • The launcher supplies a managed-host table that must match the runtime manifests after DNS hostname normalization. Transparent Sandbox A egress, protected gateway-envelope retention, and gateway forwarding belong to ISL-1755.
  • The modified_read frame carries source_request_id from the original managed request and the exact request scheme/raw target. The Python router-backed transport owned by ISL-1745 must accept the bound source_request_id keyword argument and pass it into modified_read_to_wire; the router uses it for protected-envelope lookup. Until that transport is installed, the runtime reports unhealthy and upstream reads fail closed.
  • Overlay, identity, authorization, cursor/search, and filtering capability implementations belong to sibling tickets. This PR defines their SDK surfaces and fail-closed process placeholders only.

Refs: ISL-1744

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Starting automated code review...

@islo-labs islo-labs Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review findings for ISL-1744 (current head 076b9f4):

  1. Router ingress can be stalled by one connection — crates/router/src/main.rs:42-54. The listener handles connections serially, and read_frame blocks on read_exact without an ingress timeout. A peer that opens the socket and sends no frame (or sends a slow frame) prevents every subsequent request and even health request from being served. Since this router sits on all evaluation egress, one stalled request blocks unrelated traffic. Handle connections independently and bound ingress reads so a stalled peer cannot monopolize the listener.

  2. Valid host authorities are rejected instead of preserved — src/doubleagent/sdk/models.py:35-40 and crates/router/src/lib.rs:76-83. ProviderRequest rejects uppercase hosts and any host containing a port, while the router requires an exact match against the lowercase managed-host table. Both API.example.com and api.example.com:443 are valid HTTPS authorities, but this path returns a failure before classification. ISL-1744 requires the raw host to survive the local round trip, and the parent architecture keeps Sandbox A's outbound request contract unchanged. Keep the original authority in the request and use a normalized host key only for routing/host binding.

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Starting automated code re-review...

@islo-labs islo-labs Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of head 0b79b4f: the two findings from my prior review are addressed. The ingress handler now isolates peers and applies a total read deadline, and raw host authorities are preserved while routing uses a canonical key.

One remaining change is needed:

  • Router health stays ready after the runtime is lost — crates/router/src/main.rs:30-36 and crates/router/src/lib.rs:48-63. The router checks runtime health only once during startup. Its later health response is a hard-coded ready, so terminating the Python runtime leaves the router reporting healthy indefinitely even though every managed request returns 502. The parent architecture requires loss of Sandbox B health to block agent egress. Have router health probe the runtime (or track its liveness) and report unhealthy when the runtime is unavailable; cover the runtime-loss case in the health contract.

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Starting automated code re-review...

@islo-labs islo-labs Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of head 8140be7: the router now probes runtime health on every health request and reports unhealthy when the runtime is unavailable or incompatible. This addresses my remaining finding. The earlier ingress concurrency and raw-authority findings remain addressed. I found no further actionable issues; all current CI checks pass.

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Starting E2E verification...

@islo-labs

islo-labs Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor Author

Verification Report — PASSED

Verified PR head 8140be789be8ec351b837ca00214cb7313c4b2a1 as the DoubleAgent Python runtime and Rust router. This PR has no frontend or Islo platform service override. I built and launched its processes directly, sent framed requests through the router, and ran targeted Python 3.11 checks with the Rust binary present. The production transport, overlay, and Sandbox A egress are owned by later tickets; the current process correctly fails closed where those capabilities are unavailable.

Scenario 1: Trusted health reports the protocol version and both explicitly loaded services — PASSED

Launched doubleagent.runtime.main with an evaluation document naming only the alpha.yaml and beta.yaml manifests, then queried its trusted Unix socket. Output: status: ready, protocol_version: 1, sdk_version: v0, evaluation_id: eval-verify, and services alpha and beta with their declared hosts and recovery policy versions. Router health also returned ready.

Scenario 2: Managed requests preserve method, host, path, ordered duplicate query/header pairs, and binary bodies through a Rust-to-Python round trip — PASSED

With target/debug/doubleagent-router present, ran tests/test_protocol.py::test_rust_router_python_runtime_round_trip. Its three cases (alpha.example, ALPHA.example, alpha.example:443) compare the complete request received by the Python recording capability to the request sent through Rust: POST, host, /read, duplicate ordered a query pairs, duplicate ordered X-A headers, and body 00 ff. The response body assertion is hello 00 00 ff. All three cases passed in the targeted run.

Scenario 3: Services receive immutable, evaluation-bound task context; mismatched task IDs are rejected — PASSED

test_task_binding_and_deep_immutability confirmed nested task data cannot be changed and a mismatched evaluation/task ID raises ValueError. test_trusted_launch_loads_registration_and_service_bundle loaded the same data from a trusted launch file and rejected a changed registered task ID. Both passed.

Scenario 4: Supported operations return raw provider responses, and virtual writes cannot use upstream transport — PASSED

test_multiple_services_and_raw_request_handling verified both services returned status 207, original duplicate headers, and binary bodies through the recording capability. test_bound_capabilities_and_virtual_write verified /write returned 201 and wrote the overlay without an upstream request; /bad-write attempted upstream access and returned a managed 502, still with zero upstream requests. The production entrypoint's unavailable upstream/overlay placeholders also returned managed 502 responses in the live process run, as specified for this foundation.

Scenario 5: Unknown services and operations fail closed without upstream forwarding — PASSED

The live router returned a raw 502 for other.example and a raw 501 for alpha.example/unknown. test_unknown_service_and_operation_fail_closed also verified unknown service status 421 at runtime, unknown and undeclared operations status 501, and zero calls to the recording upstream or overlay.

Scenario 6: The SDK exposes no capture or checkpoint interface — PASSED

git grep -n -i -E 'capture|checkpoint' -- src/doubleagent crates/router found no symbols. Python inspection of doubleagent.sdk listed its 19 public exports; none contain capture or checkpoint.

Scenario 7: Python and Rust CI checks pass — PASSED

gh pr checks https://github.com/islo-labs/doubleagent/pull/39 reported python pass and router pass for CI at this head. CodeQL actions, Python, and Rust checks also passed. Local cargo build -p doubleagent-router succeeded; targeted Python runs reported 8 passed, 4 passed, and 3 passed on Python 3.11.

Scenario 8: Runtime loss and stalled peers — PASSED

In the live process run, router health changed from ready to unhealthy after the Python runtime exited. Targeted checks test_stalled_ingress_peer_does_not_block_router_health and test_slow_ingress_frame_has_total_deadline passed; health remained reachable while another peer stalled, and a slow frame ended with 502 within the ingress deadline.

Evidence and scope

The live run command was .venv/bin/python /tmp/verify1744.py; key output was router_health ... ready, unknown_host ... status 502, unknown_operation ... status 501, missing_upstream ... status 502, and router_health_after_runtime_loss ... unhealthy. The runtime log showed normal startup and shutdown, with no service error logs. The repository checkout remained clean. launch-platform supports Islo platform services only, so no DoubleAgent PR branch can be deployed through it; this PR's executable runtime and router were verified directly. A requested launch-platform run found five newer, unrelated Islo main commits and began rebuilding them; I stopped that costly rebuild after the DoubleAgent checks completed. /workspace/.platform-state.json still shows the previous Islo service SHAs. No UI or preview is provided by this PR.

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Starting automated code re-review...

@islo-labs islo-labs Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review of head 698bd54: I checked the new source-request binding, raw scheme/target round trip, strict launch validation, capability-aware health, managed-host negotiation, and router frame budget against ISL-1744 and the earlier fixes. I found no remaining actionable issues. All current CI checks pass; I did not run tests locally.

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Starting E2E re-verification...

@islo-labs

islo-labs Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor Author

Verification Report — PASSED

Re-verified PR #39 at head 698bd5401a9bc34da279ac89738300649e8e2490 on Python 3.11. The change is a backend-only DoubleAgent runtime/router foundation. I built the Rust router, launched the Python entrypoint with both explicit test manifests, sent framed requests to its private Unix socket, and exercised the ready Rust-to-Python path with recording capabilities. All seven required scenarios passed. The entrypoint intentionally reports unhealthy until the sibling transport/state capabilities are installed; the router refused to start against that unhealthy process.

Scenario 1: Trusted health reports the protocol version and both explicitly loaded services — PASSED

.venv/bin/python /tmp/verify1744_round2.py returned trusted health with protocol_version: 1, sdk_version: v0, evaluation_id: eval-verify, and exactly alpha and beta, including their hosts and recovery policy versions. Status was unhealthy because the bundled entrypoint has unavailable capability placeholders. test_trusted_health_exposes_versions_and_services passed with recording capabilities and ready status.

Scenario 2: Managed requests preserve method, host, path, ordered duplicate query/header pairs, and binary bodies through a Rust-to-Python round trip — PASSED

test_rust_router_python_runtime_round_trip ran the Rust process against a ready Python runtime for three authorities (alpha.example, uppercase, and port-bearing). Its assertions compare the whole received request to the sent request: POST, http scheme, raw authority, /read, exact raw target /read?a=1&a=2&flag&flag=&space=a+b&space=a%20b, ordered duplicate parsed query and header pairs, and body 00 ff. The returned body was hello 00 00 ff; all three cases passed.

Scenario 3: Services receive immutable, evaluation-bound task context; mismatched task IDs are rejected — PASSED

test_task_binding_and_deep_immutability rejected nested task mutation and an evaluation/task ID mismatch. test_trusted_launch_loads_registration_and_service_bundle loaded the trusted task and rejected a changed registered task ID. Both passed.

Scenario 4: Supported operations return raw provider responses, and virtual writes cannot use upstream transport — PASSED

With recording capabilities, test_multiple_services_and_raw_request_handling returned 207, original duplicate headers, and binary body data from both services. test_bound_capabilities_and_virtual_write returned 201 for /write, recorded the virtual overlay write with zero upstream calls, and returned 502 for /bad-write when the service attempted upstream transport. Both passed. The live entrypoint's unavailable upstream returned a managed 502 as expected.

Scenario 5: Unknown services and operations fail closed without upstream forwarding — PASSED

The live runtime socket returned 421 for other.example, 501 for alpha.example/unknown, and 502 for a read requiring unavailable upstream transport. test_unknown_service_and_operation_fail_closed passed and asserted zero recording upstream and overlay calls for unknown cases.

Scenario 6: The SDK exposes no capture or checkpoint interface — PASSED

git grep -n -i -E 'capture|checkpoint' -- src/doubleagent crates/router found no symbols. Python inspection of doubleagent.sdk public names found no capture or checkpoint name.

Scenario 7: Python and Rust CI checks pass — PASSED

gh pr checks https://github.com/islo-labs/doubleagent/pull/39 reported python pass and router pass at this head; all CodeQL checks passed too. Local cargo build -p doubleagent-router succeeded. Selected Python checks reported 24 passed and 3 passed; three focused Rust unit checks each passed. I did not run the full suites.

Scenario 8: Source binding and exact target contract — PASSED

The Rust-to-Python round trip asserted source_request_id == request-1. test_source_id_is_bound_per_concurrent_request passed, pairing concurrent bodies 0 and 1 with source-0 and source-1. test_request_preserves_scheme_and_exact_target and the Rust modified_read_requires_complete_raw_target_contract test passed, preserving + versus %20 and flag versus flag=.

Scenario 9: Readiness and managed-host agreement — PASSED

The live entrypoint returned unhealthy and a router launch against it exited 1 with runtime version or health mismatch; no router socket was created. test_router_rejects_mismatched_managed_host_table passed for missing, extra, and wrong hosts. test_router_health_tracks_runtime_loss passed. The runtime log showed normal startup and shutdown.

Scenario 10: Strict launch and bounded protocol frames — PASSED

test_trusted_launch_rejects_invalid_fields passed six invalid launch cases. A JSON array frame returned invalid_request in test_json_array_frame_gets_invalid_request. Rust unit checks passed for the 10 MiB frame ceiling, 40 MiB aggregate reservation, and host negotiation. The stalled and slow ingress regression checks both passed.

Scope

launch-platform has no DoubleAgent override, so this PR cannot be deployed through the Islo platform stack; its own runtime and router were exercised directly. The sibling transport, overlay, and Sandbox A integration are not present in this PR. There is no UI or preview to share. The checkout was clean after verification.

bzimbler
bzimbler previously approved these changes Oct 20, 2026
Refs: ISL-1744

Signed squash of PR #39, preserving the exact final tree at 698bd54. Includes all review fixes.
Refs: ISL-1744

Run genuine Test, Format, Clippy, and Build jobs matching the active repository ruleset.
@bzimbler
bzimbler changed the base branch from main to feat/doubleagent-v2 October 21, 2026 06:37
bzimbler and others added 2 commits October 21, 2026 09:43
ISL-1744

Co-authored-by: Cursor <cursoragent@cursor.com>
ISL-1744

Co-authored-by: Cursor <cursoragent@cursor.com>
@bzimbler
bzimbler merged commit 3734f3c into feat/doubleagent-v2 Oct 21, 2026
8 checks passed
@bzimbler
bzimbler deleted the feat/ISL-1744 branch October 21, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant