diff --git a/docs/specs/2026-09-22-managed-ats-tool-host-v1.md b/docs/specs/2026-09-22-managed-ats-tool-host-v1.md new file mode 100644 index 0000000..247ce1d --- /dev/null +++ b/docs/specs/2026-09-22-managed-ats-tool-host-v1.md @@ -0,0 +1,733 @@ +# Managed ATS read-only tool host contract v1 + +Status: contract freeze +Date: 2026-09-22 +Owners: AETHER-CLOUD, Aether-Agent, ATSv2, Agent Browser +Capability scope: foreground, read-only tools only + +## 1. Purpose and release boundary + +This contract defines the first Cloud-to-local managed-agent tool path. One +admitted model run may invoke one bounded local read-only ATS tool while the +owning user has an attached foreground Agent session. The typed result returns +to the same managed-agent conversation without creating execution authority. + +MUST, MUST NOT, SHOULD and MAY are normative. + +The following are outside v1: + +- paper-order review, approval, submit, cancel or reconciliation; +- live-capital execution; +- broker or provider credentials and account enumeration; +- strategy activation or executable market evidence; +- background or daemon tool hosting; +- browser actions. + +Missing, stale, mismatched or unqualified dependencies make the tool +unavailable. They never trigger a fallback transport or broader capability. + +## 2. Canonical ownership + +### 2.1 AETHER-CLOUD + +Cloud owns authenticated account and managed-agent identity, conversation and +run identity, model and UVT admission, host-session lease issuance, model tool +offering, invocation correlation, durable call deduplication, result custody and +DM delivery. + +Cloud MUST NOT derive trading authority from a DM, agent profile, host lease, +tool manifest or tool result. V1 exposes no order mutation route. + +### 2.2 Aether-Agent + +Agent owns the enrolled local foreground host, terminal/session lifecycle, +account-switch teardown, local resource leases, strict envelope validation, +bounded invocation, a non-authoritative replay cache and safe display. + +Agent MUST NOT mint a Cloud lease, ATS capability, execution plan, approval, +grant, order receipt or broker state. It MUST NOT infer missing tool arguments +from chat text. + +### 2.3 ATSv2 + +ATSv2 owns authenticated runtime capability truth and read-only ATS status. In +later contracts it remains the sole owner of strategy activation, executable +evidence, risk, provider/account bindings, execution grants, plans, approval +consumption, broker adapters, order idempotency, the execution ledger, +reconciliation and kill-switch state. + +Agent and Cloud may transport or project ATSv2 facts, but cannot replace them. + +### 2.4 Agent Browser + +Agent Browser owns browser session custody and observation receipts. Page text +and pixels are untrusted data. Browser observation is not part of the first v1 +canary and cannot be advertised until an owner-bound browser session contract +binds Cloud origin, account, agent, device, local session and run. + +## 3. Non-authority invariants + +None of the following grants execution authority: + +- ATS policy acceptance; +- the Agent plan, skip or danger preference; +- a Cloud DM, admitted model run or UVT allocation; +- a host lease, manifest, capability receipt or successful read tool; +- memory readiness or a writer lease; +- installed, scanned or compiled strategy source; +- configured research data; +- a browser connection, screenshot or page text; +- a prior result or cached receipt. + +Every v1 schema containing a boolean named grants_execution_authority MUST set +it to false. No v1 object may carry an order, approval, broker credential, raw +account number or execute_live flag. + +## 4. Common wire rules + +All v1 objects are closed. Unknown fields fail validation. There is no generic +extensions object on a lease, invocation, cancellation, result or capability. +Every portable top-level object carries a required schema field whose value is +the exact normative schema identifier named in its section. Unknown or absent +schema identifiers fail before any semantic processing. Transport-private +handshake, heartbeat, renewal and close frames are outside this portable object +bundle and MUST be versioned and authenticated by the Cloud transport; they may +not be substituted for a portable object or model-visible tool input. + +- Canonical JSON is RFC 8785 JSON Canonicalization Scheme. +- Strings containing lone surrogates, control characters or invalid Unicode + fail before canonicalization. +- A digest is sha256 followed by a colon and 64 lowercase hexadecimal digits. +- A timestamp is UTC RFC 3339 with exactly millisecond precision and a trailing + Z. +- IDs are 8 to 128 printable ASCII characters from A-Z, a-z, 0-9, period, + underscore, colon and hyphen, beginning with an alphanumeric character. +- A schema ID is separate from the general ID grammar and matches + aether.[a-z0-9.-]+/[1-9][0-9]*, with a maximum of 128 ASCII characters. +- JSON integers are limited to the interoperable range 0 through 2^53 - 1. +- Floating-point numbers, NaN, Infinity and exponent notation are forbidden in + contract objects. Decimal values use canonical decimal strings. +- Arrays, strings, object depth, arguments, results and errors have explicit + schema bounds. Validation happens before logging or dispatch. +- A digest preimage is the ASCII schema identifier, a newline, then the RFC + 8785 bytes of the object with its own digest or signature field omitted. +- Python and TypeScript implementations MUST pass the same checked-in golden + byte and digest vectors. + +Portable JSON frames are at most 262,144 UTF-8 bytes and at most 16 object or +array levels deep. Unless a narrower field rule applies, strings are at most +256 Unicode scalar values and arrays contain at most 32 entries. Duplicate +members in raw JSON objects, duplicate values in set-like arrays and non- +canonical number spellings are rejected before JSON decoding. Raw JSON need +not arrive in canonical member order, but the original bytes MUST be retained +long enough to enforce the lexical rules before RFC 8785 canonicalization. + +The separator written as \n in digest and signature formulas is exactly one LF +byte (0x0a), never the two characters backslash and n. + +Schema documents use JSON Schema Draft 2020-12. A schema digest is computed as +sha256("aether.schema/1\n" + JCS(schema_document)); the entire closed schema +document, including $schema, $id and x-aether-schema-id, is in the preimage. +Schema documents have no self-digest member. Dynamic arguments and payloads +are first bounded and validated by their envelope, then validated a second time +against the exact registered schema ID and schema digest. JSON Schema alone is +not sufficient for canonical bytes, signatures, temporal ordering, byte +limits, unique semantic IDs or replay fencing; implementations MUST run the +semantic checks described here after closed-schema validation. + +The frozen schemas live under contracts/managed-ats-tool-host/v1. Each schema +uses the absolute $id +https://schemas.aethersystems.net/managed-ats-tool-host/v1/ and an +x-aether-schema-id equal to its normative aether.* wire identifier. The bundle +contains common definitions plus trust, device-proof, host-open-proof, observer +receipt, runtime capability, registry, host lease, invocation, cancellation, +result, workspace-status input and workspace-status output schemas. References +resolve locally; validation never requires a network fetch. + +Set-like arrays use ascending Unicode code-point order and contain no duplicate +values. Tool entries use ascending (name, version) order. A non-canonical order +fails validation rather than being silently reordered. + +Timestamp relationships use Cloud time for Cloud-issued objects and the +authenticated ATS channel time for ATS receipts. Implementations allow at most +30 seconds of positive or negative clock skew at receipt. expires_at MUST be +strictly later than issued_at, created_at or observed_at as applicable. + +account_scope_digest is derived exactly as: + +sha256("aether.account-scope/1\n" + JCS({"cloud_origin_id": origin, +"account_subject": subject})). + +origin is the normalized lowercase HTTPS origin with no path, query, fragment +or trailing slash. subject is the canonical subject returned by the +authenticated Cloud identity endpoint. The raw subject is used only for this +local derivation, never crosses the portable tool contract and cannot be +supplied by a model. + +### 4.1 Cloud and device trust bootstrap + +Cloud lease signatures use Ed25519 as specified by RFC 8032. Signatures and +public keys use unpadded base64url. The signed bytes are the ASCII schema ID, a +newline, then RFC 8785 bytes with cloud_signature omitted. + +Agent discovers Cloud verification keys only from the configured origin at +/.well-known/aether-managed-tool-host-v1.json over validated HTTPS. That closed +document uses schema aether.managed-tool-trust/1 and contains generated_at, +expires_at and keys, an array of 1 through 16 closed +{key_id, algorithm, public_key} rows. Its required schema field is exactly +aether.managed-tool-trust/1. algorithm MUST be Ed25519. key_id follows the ID +grammar, and public_key is an unpadded base64url encoding of exactly 32 bytes. +Duplicate key IDs fail semantic validation. The document lifetime is at most +24 hours. Unknown keys, expired key sets, redirect to another origin, TLS +failure or fetch failure makes host creation unavailable. Cached keys may be +used only until expires_at. + +Host enrollment uses EnrolledDeviceProofV1, schema +aether.managed-tool-device-proof/1. Required fields are schema, exactly that +identifier; cloud_origin_id, +account_scope_digest, device_id, device_public_key, issued_at, expires_at, +revocation_epoch, signature_key_id and cloud_signature. Cloud signs it with the +same rules. It also carries proof_digest, computed by the common digest rule +with proof_digest and cloud_signature omitted. device_id MUST use the scdev_ +namespace. device_public_key encodes exactly 32 bytes and cloud_signature +encodes exactly 64 bytes as unpadded base64url. The proof lifetime is at most +30 days. The Agent holds the +matching Ed25519 private key in an owner-private OS-backed key store; absence of +that key makes the host unavailable. + +proof_digest omits both proof_digest and cloud_signature. The Cloud signature +preimage omits only cloud_signature and therefore binds proof_digest. + +Cloud supplies a 32-byte random value encoded as exactly 43 unpadded base64url +characters with a five-minute maximum expiry. Agent proves key possession with +a closed HostOpenProofV1 object whose schema is +aether.managed-tool-host-open-proof/1 and whose required fields are schema, +challenge, device_proof_digest, agent_id, conversation_id, local_session_id, +session_generation, registry_digest and device_signature. device_signature is +an exactly 64-byte Ed25519 signature encoded as 86 unpadded base64url +characters. It signs the ASCII string +aether.managed-tool-host-open/1, a newline, then RFC 8785 bytes of +{challenge, device_proof_digest, agent_id, conversation_id, local_session_id, +session_generation, registry_digest}. The device_signature field is not part of +that signed object. The challenge is single-use. Cloud +verifies the device proof, scope, revocation epoch, expiry and possession +signature before issuing a host lease. + +### 4.2 ATS observer trust bootstrap + +ATS capability uses observer channel aether.ats.observer-channel/1. Agent sends +a 32-byte random challenge through ATS-MCP's private authenticated local +channel. ATS returns a closed ObserverChannelReceiptV1 containing schema exactly +aether.ats.observer-channel-receipt/1; receipt_id; channel_id; runtime_id; +runtime_version; runtime_build_digest; challenge; capability_digest; issued_at; +expires_at; authentication exactly ats_mcp_private_credential; and +receipt_digest. challenge uses the exact 43-character encoding defined above +and the receipt lifetime is at most 60 seconds. The private credential remains +outside every contract object. + +Agent accepts RuntimeCapabilityV1 only when the receipt challenge matches, the +receipt is fresh, capability_digest matches, the configured ATS credential +authenticated the response and runtime_build_digest matches the loaded build. +attestation_kind is exactly ats_observer_channel_v1 and attestation_ref is the +ObserverChannelReceiptV1 receipt_id. The capability digest is computed before +the receipt digest; the receipt then binds capability_digest. This ordering +avoids a cyclic digest dependency. + +## 5. RuntimeCapabilityV1 + +Schema: aether.ats.runtime-capability/1. + +This object describes runtime support. It grants no authority. + +Required fields: + +- schema, exactly aether.ats.runtime-capability/1; +- runtime_id, runtime_version and runtime_build_digest; +- attestation_kind and attestation_ref from an ATS-authenticated channel; +- supported_read_operations, a closed array of versioned operation IDs; +- effective_execution_mode: observe, paper, approve, auto or unknown; +- supports_paper_execution and supports_live_execution; +- observed_at and expires_at; +- grants_execution_authority, false; +- capability_digest. + +runtime_version is 1 to 64 printable ASCII characters. The runtime and build +IDs follow the common ID and digest grammars. supported_read_operations is the +single-value array ["aether.ats.workspace-status/1"] in E1. The capability +lifetime is at most 60 seconds. + +supports_* describes implementation support, not permission. In v1, +supports_live_execution MUST be false at the host boundary. A stale or +unverified capability blocks execution-related projections, but MUST NOT hide +bounded diagnostic status that reports degraded or unavailable state. + +Agent MUST NOT self-assert ATS runtime identity. Capability is accepted only +from the configured ATS-authenticated observer channel and only for the exact +loaded build digest. + +## 6. ToolRegistryManifestV1 + +Schema: aether.managed-tool-registry/1. + +Required top-level fields: + +- schema, exactly aether.managed-tool-registry/1; +- registry_id, account_scope_digest, agent_id and device_id; +- local_session_id and session_generation; +- created_at and expires_at; +- tools; +- grants_execution_authority, false; +- registry_digest. + +Each tool entry requires: + +- name and version; +- input_schema_id, input_schema_digest, output_schema_id and + output_schema_digest; +- effect_class, exactly read_only in v1; +- dependencies from the closed set foreground_session, verified_account, + ats_profile, memory_writer, ats_runtime and browser_observer; +- max_argument_bytes, max_result_bytes and max_duration_ms; +- data_classes from the closed set local_status, ats_status and + untrusted_browser_observation; +- grants_execution_authority, false. + +tools contains 1 through 32 entries with unique name/version pairs. name is 1 +through 64 lowercase ASCII letters, digits or underscores, beginning with a +letter. version is an integer from 1 through 65,535. dependencies contains 1 +through 6 unique values and data_classes contains 1 through 3 unique values. +The E1 canary manifest MUST contain exactly one entry: ats_workspace_status +version 1 with the schema IDs in section 11. The registry lifetime is at most +five minutes. + +max_argument_bytes is an integer from 2 through 65,536, +max_result_bytes is an integer from 256 through 65,536, and max_duration_ms is +an integer from 1 through 30,000. A tool may declare a lower bound. These are +hard envelope limits, not hints. + +Cloud and Agent select one exact name, version and schema-digest tuple. Unknown +versions, digest drift and duck typing fail closed. + +A tool is listed only while all of its declared dependencies are live. Resource +requirements are per tool; registry presence does not make one resource a proxy +for another. + +## 7. HostSessionLeaseV1 + +Schema: aether.managed-tool-host-lease/1. + +The lease authorizes only short-lived routing to one foreground local host. It +is not a trading credential. + +Required fields: + +- schema, exactly aether.managed-tool-host-lease/1; +- lease_id and host_session_id; +- cloud_origin_id and account_scope_digest; +- agent_id and enrolled device_id; +- local_session_id, session_generation and revocation_epoch; +- conversation_id for routing; +- registry_digest; +- issued_at, expires_at and max_calls; +- capabilities, exactly the single-value array ["local_read_tools"]; +- grants_execution_authority, false; +- signature_key_id and cloud_signature. + +max_calls is an integer from 1 through 256. cloud_signature encodes exactly 64 +bytes as unpadded base64url. A lease lifetime is at most five minutes and never +extends past the registry, device proof or verification-key expiry. + +Conversation identity is routing metadata, not authority. The account, agent, +device, local session, generation, registry and expiry jointly define the +lease scope. + +The local_ browser-owner fallback is not an enrolled device and MUST NOT open a +tool host. V1 requires a same-origin scdev_ identity with a valid +EnrolledDeviceProofV1 and proof of possession of its enrolled private key. + +Cloud signs the canonical lease. Agent validates the signature, key ID, origin, +scope, generation and expiry before accepting an invocation. Closing or +revoking a lease increments its fencing generation or revocation epoch; an old +lease can never be adopted by a restarted session. + +## 8. ToolInvocationV1 + +Schema: aether.managed-tool-invocation/1. + +Required fields: + +- schema, exactly aether.managed-tool-invocation/1; +- request_id and cloud_tool_call_id; +- lease_id, host_session_id, session_generation and revocation_epoch; +- cloud_origin_id, account_scope_digest, agent_id and device_id; +- local_session_id, conversation_id and run_id; +- sequence; +- tool_name and tool_version; +- input_schema_id and input_schema_digest; +- arguments and arguments_digest; +- issued_at, deadline_at and nonce; +- invocation_digest. + +nonce is an exactly 32-byte random value encoded as 43 unpadded base64url +characters. sequence is an integer from 1 through 2^53 - 1. tool_version is an +integer from 1 through 65,535. arguments is a JSON value no deeper than 8 levels +whose canonical encoding is no larger than the registered max_argument_bytes. +deadline_at MUST be later than issued_at, no later than both the lease expiry +and issued_at plus the registered max_duration_ms, and not expired after allowed +skew when claimed. + +arguments MUST satisfy the exact registered schema and size bound. The model +cannot select a local path, runtime, browser session, provider or account; +resource identifiers are injected by the bound host after validation. + +deadline_at is absolute and includes queue time. An AbortSignal is never placed +on the wire. + +Invocation and cancellation objects are authenticated by the already-bound, +mutually authenticated Cloud host transport and its monotonically fenced +sequence. They do not carry a second object signature. A portable invocation or +cancellation received outside that transport is invalid even if its digests +match. + +Forbidden fields and values include prompts, reasoning, credentials, cookies, +raw account subjects or numbers, arbitrary provider tool names, source code, +local paths and unfiltered page/provider payloads. + +## 9. ToolCancellationV1 + +Schema: aether.managed-tool-cancellation/1. + +Required fields: + +- schema, exactly aether.managed-tool-cancellation/1; +- cancellation_id, cloud_tool_call_id and invocation_digest; +- lease_id, host_session_id, session_generation and revocation_epoch; +- reason: user_cancelled, run_cancelled, session_closed, lease_revoked or + deadline_exceeded; +- issued_at; +- cancellation_digest. + +issued_at MUST fall within the live lease window after allowed skew. + +Cancellation is authenticated, idempotent and fenced by the lease generation. +Agent derives its local AbortSignal from chat shutdown, host shutdown, the +named cancellation and remaining absolute deadline. + +Cancellation for one call cannot cancel a different call. Agent records a +terminal result with an atomic first-terminal-record-wins compare-and-swap. A +success durably recorded before cancellation remains the stored success and is +redelivered. Cancellation or deadline durably recorded first wins; any later +tool completion is discarded and MUST NOT replace it with success. + +## 10. ToolResultV1 + +Schema: aether.managed-tool-result/1. + +Required fields: + +- schema, exactly aether.managed-tool-result/1; +- result_id, request_id and cloud_tool_call_id; +- lease_id, host_session_id, local_session_id, session_generation, + revocation_epoch and run_id; +- tool_name, tool_version, input_schema_id and input_schema_digest; +- invocation_digest and arguments_digest; +- state: succeeded, refused, cancelled, deadline_exceeded or unavailable; +- payload, output_schema_id and output_schema_digest, nullable unless + succeeded; +- error, nullable unless state is not succeeded; +- evidence_refs, a bounded array of opaque safe references; +- replay_status: fresh, stored_redelivery or interrupted_before_result; +- retry_class: none, redeliver_stored_result or new_call_after_recovery; +- started_at and completed_at; +- bounded_bytes and redaction_profile; +- grants_execution_authority, false; +- result_digest. + +error is a closed object containing code and a bounded safe display message. It +contains no exception body, path, token, page content or provider response. + +code MUST be one of the stable failure codes in section 14. The safe display +message is 1 to 256 characters. evidence_refs contains at most 16 unique opaque +safe references; each follows the common ID grammar and is not dereferenceable +by a model. bounded_bytes is the byte length of the RFC 8785 serialization of +payload alone, or zero when payload is null. It is an integer from 0 through the +registered max_result_bytes. The complete ToolResultV1 frame must also fit the +262,144-byte common frame limit. redaction_profile is exactly +aether.safe-display/1. + +When state is succeeded, payload, output_schema_id and output_schema_digest are +non-null and error is null. For every other state, those three output fields +are null and error is non-null. retry_class is redeliver_stored_result only for +a stored completed result; new_call_after_recovery never permits replay of the +same cloud_tool_call_id. + +retry_class redeliver_stored_result requires replay_status stored_redelivery. +replay_status interrupted_before_result requires state unavailable and +retry_class new_call_after_recovery. started_at is not earlier than the +invocation issued_at after allowed skew; completed_at is not earlier than +started_at and not later than the time the terminal record is durably stored. + +A succeeded payload MUST validate against the exact output_schema_id and +output_schema_digest registered for the selected tool version. Missing or +mismatched output identity makes the result unavailable, never succeeded. + +V1 read-only calls have no financial uncertain state. If Agent restarts after a +call was claimed but before its result was durably stored, the same call becomes +unavailable with replay_status interrupted_before_result and is never invoked a +second time. + +## 11. Initial tool: ats_workspace_status + +The first canary registry contains only ats_workspace_status version 1. Its +input schema ID is aether.ats.workspace-status-input/1 and accepts exactly an +empty object with no properties. + +Its manifest dependencies are foreground_session, verified_account and +ats_profile. It does not declare memory_writer, ats_runtime or browser_observer, +so it remains available to report those resources as degraded or unavailable. + +Its output schema ID is aether.ats.workspace-status/1. The object is closed and +contains exactly: + +- schema, exactly aether.ats.workspace-status/1; +- observed_at; +- binding_digest; +- local, containing only memory and strategies; +- data; +- browser; +- runtime; +- execution_authority, exactly none; +- orders_enabled, false; +- grants_execution_authority, false; +- diagnostics; +- status_digest. + +local.memory is closed with state ready, degraded or unavailable; +configured_gib as null or an integer from 1 through 16,384; and writer_lease as +held, lost, not_held or unavailable. It contains no path. + +local.strategies is closed with state scanned or unavailable; count as an +integer from 0 through 10,000; compiler as native_ats or unavailable; and +execution_enabled, always false. It contains no path, filename, source or +diagnostic body. + +data is closed with research_configuration as configured, not_configured or +unavailable; last_probe as fresh, stale, failed, never or unavailable; and +executable_evidence, exactly unavailable. + +browser is closed with state available, unavailable or cleanup_required. It +contains no URL, page text, screenshot, browser owner or session ID. + +runtime is closed with state ready, degraded, unavailable or unknown and +effective_execution_mode as observe, paper, approve, auto or unknown. The mode +is supplied only by ATS; Agent UI preferences cannot populate it. + +diagnostics is an array of at most 16 closed objects. Each contains code, a +1-to-64-character uppercase ID; severity as info, warning or error; and a safe +display summary of 1 to 256 characters. No arbitrary detail field exists. + +binding_digest is derived as: + +sha256("aether.ats.workspace-status-binding/1\n" + JCS({ +"account_scope_digest": account_scope_digest, "agent_id": agent_id, +"device_id": device_id, "local_session_id": local_session_id, +"session_generation": session_generation})). + +status_digest follows the common digest rule with status_digest omitted. + +The host injects the account/agent-scoped settings and strategy directory. A +model cannot provide either. Strategy scan is compile/preparation status only; +it does not activate a strategy. + +Maximum serialized result size is 64 KiB. The result MUST NOT contain prompts, +strategy source, full paths, raw account identifiers, credentials, environment +values or provider payloads. + +## 12. Protocol lifecycle + +1. Agent verifies the account and typed ATS profile, acquires required local + resources and resolves the canonical managed-agent conversation. +2. Agent opens an outbound authenticated host connection. V1 opens no inbound + listener and no browser/VNC route. +3. Cloud verifies origin, account, agent and enrolled device, then accepts the + exact registry manifest and issues a short-lived lease. +4. Cloud offers only manifest tools to a compatible admitted model run while + the lease and dependencies remain live. An unadmitted or text-incompatible + run sees no local tool. +5. Cloud persists the invocation key and body before delivery. +6. Agent validates signature, scope, generation, sequence, registry, schema, + size, deadline and digest before claiming the call. +7. Agent durably claims the call before reaching the backing read-only tool. +8. Agent invokes at most once, persists ToolResultV1 before delivery, then sends + the exact stored result with cloud_tool_call_id as the idempotency key. +9. Cloud stores the result before completing model/DM delivery. Delivery retry + reuses the stored result and never creates another local invocation. +10. Teardown stops admission first, closes the Cloud host lease, aborts active + calls, waits a bounded interval, closes browser resources, releases the + memory writer lease, and only then aborts the outer chat lifecycle signal. + +Account switch, logout, host-lease identity loss, device-proof revocation, +expiry or conversation close begins step 10 immediately. + +Loss of an individual resource such as the writer helper, ATS runtime or +browser observer removes only tools that declare that dependency. Agent +publishes a new manifest with an incremented session generation; Cloud revokes +the old lease before issuing one bound to the new registry digest. A diagnostic +tool that does not require the lost resource remains available to report the +degraded state. If a core dependency of every registered tool is lost, the host +closes. + +An offline or expired foreground host returns unavailable. Cloud MUST NOT queue +an invocation for a later process, device or session generation. + +## 13. Idempotency, replay and custody + +Cloud's canonical invocation key is the tuple: + +account_scope_digest, agent_id, device_id, host_session_id, local_session_id, +session_generation, revocation_epoch, run_id, cloud_tool_call_id, tool_name, +arguments_digest. + +Cloud persists invocation and result records. Agent keeps a bounded, +account/agent-scoped, symlink-safe local claim/result cache so replay cannot +reinvoke after reconnect or process restart. + +- Same key and invocation digest with a completed result returns the stored + result. +- Same key with different bytes is a protocol conflict and closes/refuses the + call. +- A claimed call with no durable result after restart is + interrupted_before_result and cannot run again. +- Result delivery may retry only with the byte-identical stored body and key. +- A DM delivery failure never reaches the backing tool. +- Sequence replay is ignored only when its exact digest is already known. +- A sequence gap, rollback or conflicting replay fails closed and tears down + the host. + +ATSv2 owns a separate order idempotency namespace in later execution contracts. +Tool-call IDs never authorize or identify an order. + +## 14. Transport and failure semantics + +The host connection is Agent-originated over authenticated TLS. It has a +versioned handshake, bounded heartbeat, sequence cursor, lease renewal and +explicit close. It cannot downgrade to legacy DM polling or coding dev-session +routes on 403, 404, protocol mismatch or capability absence. + +Stable failure codes: + +- TOOL_CONTRACT_INVALID; +- TOOL_SCOPE_MISMATCH; +- TOOL_LEASE_EXPIRED; +- TOOL_LEASE_REVOKED; +- TOOL_REGISTRY_MISMATCH; +- TOOL_SEQUENCE_INVALID; +- TOOL_IDEMPOTENCY_CONFLICT; +- TOOL_UNKNOWN; +- TOOL_ARGUMENT_INVALID; +- TOOL_DEADLINE_EXCEEDED; +- TOOL_CANCELLED; +- TOOL_DEPENDENCY_UNAVAILABLE; +- TOOL_RESULT_TOO_LARGE; +- TOOL_DELIVERY_UNAVAILABLE. + +Unknown codes fail operationally. Errors never become success. Retry metadata +cannot authorize another invocation of the same call. + +## 15. Browser observation follow-up + +aether_browser_observe is not in the first canary manifest. + +Before it can be added, BrowserSessionBindingV1 must bind Cloud origin, +account_scope_digest, agent, enrolled device, local session, session generation, +run, browser owner and expiry. The host injects the bound browser identity; the +model never supplies a session UUID. + +The tool remains observation-only, freshness-bounded and size-bounded. Its +result is untrusted_browser_observation and cannot provide price, account, fill, +strategy, approval or execution authority. + +## 16. Required tests + +### Common contract fixtures + +- identical Python and TypeScript canonical bytes and digests; +- closed-schema and unknown-version refusal; +- Unicode, decimal, timestamp, ID, depth and size boundaries; +- signature, expiry, generation and revocation fencing; +- arguments and result digest conflicts. + +### AETHER-CLOUD + +- account/agent/device ownership and foreground lease expiry; +- tools offered only after compatible run admission and a live exact manifest; +- text-only, unadmitted, expired and absent-host runs see no local tools; +- invocation persisted before delivery; +- same-call dedupe, conflicting replay refusal and result custody; +- DM delivery retry does not create another invocation; +- cancellation, host close and no delayed replay into a new generation; +- no order, approval, credential or execution mutation route. + +### Aether-Agent + +- contract parsing, closed fields, bounds and safe errors; +- conversation-known hook order and exact account/agent/device binding; +- durable claim, completed-result redelivery and interrupted-call refusal; +- sequence replay/gap, deadline and targeted cancellation; +- account switch, logout, chat close, lease loss and writer-helper death; +- tool host closes before browser/memory resources and outer abort; +- ordinary agents never load or advertise ATS tools; +- ats_workspace_status exact empty input and 64 KiB safe projection; +- no paths, source, prompt, page/provider payload, secrets or execution + authority in outputs. + +### ATSv2 + +- authenticated capability names the exact runtime build; +- read-only status operations are bounded and secret-redacted; +- degraded status remains readable while execution-related facts fail closed; +- no delegated review/submit tool appears in the E1 registry. + +### Cross-repository canary + +One admitted compatible model turn invokes ats_workspace_status exactly once +and receives its stored typed result in the same managed-agent DM. Tests cover +result delivery loss, reconnect, cancellation, account switch, lease expiry, +process restart before and after result persistence, and duplicate Cloud +delivery. The measured duplicate local invocation count must be zero. + +## 17. Sequential landing order + +1. Merge the common encoding, capability, manifest, lease, invocation, + cancellation, result schemas and golden fixtures. +2. Cloud implements enrolled foreground host leases, model tool-offer gating, + durable call dedupe, cancellation, result custody and DM redelivery. The + feature remains disabled. +3. ATSv2 exposes authenticated bounded read-only capability/status adapters. + No activation, review or submit tool enters E1. +4. Agent implements the outbound foreground host, durable local replay cache, + post-conversation hook, ordered teardown and ats_workspace_status. +5. Run the exact-commit cross-repository canary and failure battery, then enable + only the workspace-status tool for qualified accounts. +6. Define and qualify BrowserSessionBindingV1 before adding browser observation. +7. Begin E2 data-probe and strategy-activation contracts only after E1 is green. +8. Begin delegated paper review/approval integration only after E1 and E2 are + green, reusing ATSv2's controller, grants, durable approval/lifecycle stores + and paper fill evidence. Agent remains a host and operator UX, never a second + broker, risk engine, ledger or kill switch. + +A later dependency MUST NOT merge ahead of a failed earlier gate. Work inside a +numbered step may fan out only after the shared schemas and golden fixtures for +that step are frozen. + +## 18. Definition of done + +V1 is done only when the same admitted managed-agent run can discover exactly +one live, owner-bound read-only workspace-status tool, invoke it once, receive a +bounded typed result in the same DM, survive replay/delivery/restart drills with +zero duplicate local invocations, and close immediately on account, session, +device or lease-identity transitions. Loss of an individual optional resource +must remove its dependent tools through a newly fenced manifest while leaving +independent diagnostic tools available to report degradation. + +Passing v1 proves no broker connectivity, paper execution or live trading.