Repository navigation
Description
Important
Problem — With the relay skeleton (#1261) the engine data plane is proxied to the host, but /amicode/* is still served locally by the client's amicode_service. Dispatch order matters: registered /amicode/* routes are served by the exact-match table (server.ts:235) before the :247 catch-all 404 — so merely flipping the :247 precedence would NOT proxy GET /amicode/problems, POST /amicode/connections, etc. Split-state persists: the client shows its OWN problems / catalog / runs while chat + solves live on the host — the Run Inspector desyncs from where compute actually happens.
Approach — In fleet mode, bypass the local /amicode/* dispatch entirely — both the exact-match route table (server.ts:235) and the :247 catch-all — and route /amicode/* to the host's authoritative amicode_service (reads → HubProxy, non-GET → the write-failure path), over the host's ~/.amico. Equivalently: do not register the /amicode/* routes on a client-role boot. Mutations land loopback-side on the host, so the mutation guard is satisfied.
Scope — in: fleet-mode /amicode/* proxying to the host for BOTH registered routes and the catch-all (reads + mutations); routing /amicode/* non-GETs through the fleet write-failure contract (extend it — today it serves only engine routes and deriveRefetchPath is session-shaped) with an /amicode/* refetch variant; the multi-client concurrency contract on shared host state. · out: engine routes (#1261); WebSocket/PTY (#1263); SSE (#1264).
Assumptions — #1261's relay + credential translation is in; the host's amicode_service owns /amicode/* over its own ~/.amico.
Acceptance Criteria
- On a fleet client, a registered
/amicode/*path (GET /amicode/problems, profile / catalog / runs) returns the host's state, not the client's local~/.amico— proving the exact-match table (server.ts:235) no longer shadows the proxy in fleet mode. - A credential/solver MUTATION (
POST /amicode/connections, solver-mode) issued from the client lands on the host and is accepted (the host'samicode_servicebinds loopback, so the mutation guard passes). - Proxied
/amicode/*non-GETs resolve through the write-failure contract (delivered / failed / ambiguous) with an/amicode/*-appropriate refetch (not the session-shaped one), never a raw proxy that hides a partial write. - Multi-client concurrency: with ≥2 clients mutating the same host
/amicode/*resource, the defined policy holds (one-writer or last-write-wins with a stated lost-update rule) — a two-client concurrent-POST test asserts no interleaved partial write. - Standalone (non-fleet) behavior is unchanged:
/amicode/*still served locally.
Testing Decisions
- Extend Fleet thin client — Slice 1: client relay skeleton (local UI + engine proxy + inject-auth, reload-tolerant) #1261's stub-host relay test: a registered
/amicode/*GET proxies to the host; a mutation is accepted host-side (loopback); standalone still serves/amicode/*locally (no regression). - New: a two-client concurrent-mutation test for the concurrency contract.
Key Decisions
- Fleet mode bypasses the entire local
/amicode/*dispatch (exact-match table + catch-all), not just the:247precedence — the exact-match table is why a bare:247flip is insufficient. - Host owns all
/amicode/*state; the client proxies in fleet mode only. - Mutation safety: the host's loopback bind satisfies the guard. (Note: today
connections.ts's ownsetBindHostnameis never wired — onlybind_host.ts's is — so the connections guard currently passes via the unset/loopback default; wire it at listen or explicitly state the SSH mesh is the boundary.) - Concurrency: choose and state the policy (one-writer vs last-write-wins) for shared host
/amicode/*files.
Constraints & Invariants
- Loopback-only mutation guard (ADR 0002) holds — the host bind stays loopback.
- Standalone path untouched.
Prior Art
- The
/amicode/*exact-match route table (server.ts:235) + the:247catch-all + the fleet routing branch (:262). - The fleet write-failure contract (
fleet_writes.ts, session-shapedderiveRefetchPath). - The bind-host loopback allowlist +
connections.ts's unwiredsetBindHostname.
Activity
fleet(#1262): proxy /amicode/* to the host in client mode — bypass lo…
fleet(#1262): /amicode/* write refetch variant + multi-client concurr…
docs(adr): 0026 generalizable machine capabilities + host-owned roster
fleet(#1261): version-skew relay-start gate (AC7)
fleet(#1262): proxy /amicode/* to the host in client mode — bypass lo…
fleet(#1262): /amicode/* write refetch variant + multi-client concurr…
fleet(#1267): amico-host:// FileSystemProvider — native Explorer show…
docs(adr): 0026 generalizable machine capabilities + host-owned roster