Skip to content

Fleet thin client — Slice 2: proxy /amicode/* to the host (host owns all state) #1262

Closed

Description

@jeonghun-jj-lee

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's amicode_service binds 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

Key Decisions

  • Fleet mode bypasses the entire local /amicode/* dispatch (exact-match table + catch-all), not just the :247 precedence — the exact-match table is why a bare :247 flip 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 own setBindHostname is never wired — only bind_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 :247 catch-all + the fleet routing branch (:262).
  • The fleet write-failure contract (fleet_writes.ts, session-shaped deriveRefetchPath).
  • The bind-host loopback allowlist + connections.ts's unwired setBindHostname.

Source

Activity

  1. added 8 commits that reference this issue on Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

hitlNeeds human review before merge

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions