Repository navigation
Closed
Labels
area/infraInfrastructure, deployment, and operationsInfrastructure, deployment, and operationseffort/mMedium: expected under 1 day of workMedium: expected under 1 day of workkind/enhancementmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)Ordinary priority (the default)status/needs-triageNot yet triaged; needs a first lookNot yet triaged; needs a first look
Description
Part of epic #5412. Design of record: #5425 (§4, §5, §7 step 3 — "Proxy"). Predecessor: step 2 (queue pilot). Gate for step 4: negotiation demonstrated across protocol majors, shim regeneration proven against a changing services map, and the SSH proof period completed before the ProxyCommand re-point.
Scope
fleet-proxylands both roles in one program:fleet proxy serve— the broker (unix socket at today's path, per-port connection pools for 4799/4800/4801, auto-start on missing socket, 1-hour idle exit retained) — andfleet proxy connect/fleet init— the client, whose autostart is an idempotent no-op when the broker already answers.- Protocol (D8): today's length-prefixed JSON framing is kept — no redesign. A versioned hello/capability frame becomes the first frame on every pooled connection; its services map is the routing table. The broker accepts protocol majors N and N−1; within a major, fields are additive-only. The framing and hello live in
fleet-proxy-protoand nowhere else. - PATH shims are regenerated from the negotiated services map on every connect/init. No shim survives from an older negotiation, so what is on PATH always matches what the broker actually routes — the anti-drift mechanism behind "repo-queue on PATH the moment you're connected." Per §8's scope-gravity risk, the shim layer advertising external tools (id, omnibin-resolved programs) is advertising only — it must not become ownership of them.
- Serve side persists nothing: the routing table is config, pooled tunnels are memory, and keepalive must not reset the idle exit (§5).
- Takeover order:
fleet proxy servetakes over the sandbox socket path (the Python broker keeps its socket until the flip; the flip is a restart with the same path) →connect/initreplace the client autostart habits →fleet-connectships to codespaces/CI from here. - SSH retires last.
laptop-proxy-connect.py(SSH's ProxyCommand) re-points tofleet proxy connect's stdio mode only after SSH-through-fleet has been proven over days, not minutes. The laptop-agent daemon itself stays Python in v1 (D5); fleet manages its lifecycle/health only.
Gate
- Hello/capability negotiation demonstrated between a current build and an N−1 build in both directions.
- Shim regeneration shown to add and remove tools as the negotiated services map changes.
proxy serve+connectround-trip green on the real socket path; idle-exit behavior unchanged.- SSH-through-fleet proof period (days) completed and recorded before the ProxyCommand re-point, which is itself a separate reversible flip.
Acceptance criteria
- proxy domains (hello/capability frame, PATH shim regeneration, fleet init) work as described.
- No regression: existing tests/checks for the touched area remain green, and the change lands via PR referencing this issue.
- Evidence (PR link, test/CI output, or verification note) is posted on this issue before it is closed.
Metadata
Metadata
Assignees
Labels
area/infraInfrastructure, deployment, and operationsInfrastructure, deployment, and operationseffort/mMedium: expected under 1 day of workMedium: expected under 1 day of workkind/enhancementmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)Ordinary priority (the default)status/needs-triageNot yet triaged; needs a first lookNot yet triaged; needs a first look
Activity
dezren39 commentedon Nov 4, 2026
Intake review
🤖 Agent note · state: filed
Related: epic #5412 and steps #5429-#5433 form one set; #5413 is a sibling absorption task.
Notes: Newly filed this morning with no priority label and no acceptance-criteria section; both now supplied.
Risks: Sequencing: steps are gated in order (notably #5433 on the #5350 step 6 cutover); starting out of order risks rework.
Suggested approach: Triage through the queue in dependency order, one step per task, verifying each step's acceptance evidence before closing.
Merge pull request #5515 from developing-today/fleet-step3-proxy
dezren39 commentedon Nov 4, 2026
Step 3 landed — the proxy domain (PR #5515, merged
5521f3f11)Sandbox
~/tools/fleetruns the merged head rev0377b9a11; the session broker on the sandbox ISfleet proxy serveas of this comment.Gates
~/tools/laptop-agent.py healthreturns the real daemon health through fleet serve on the production socket. Legacy broker → fleet client: before the flip,fleet proxy connect --request GET /healthagainst the still-running Python broker negotiated the legacy fallback and round-tripped (200, real health body). Out-of-window hello →proto_too_oldframe → client exit 69 (proto-crate unit tests).~/.local/state/fleet/shimsholdslaptop-agent+repo-queue, regenerated at the flip — links re-pointed from the proof binary to~/tools/fleetwhen the source binary changed, untouched when nothing changed.fleet initno-op. Live:fleet: proxy already running (proto 1); shims current, and exactly one broker process before and after (pid-verified). Smoke asserts the same hermetically.repo-queue health(the production queue, port 4801),laptop-agent.py health(4799), and secrets-broker/health(4800, token file named per request — no secret fetched) all green through fleet serve.ssh -o ProxyCommand="$HOME/tools/fleet proxy connect --stdio --host %h --port %p" … 'echo SSH_THROUGH_FLEET_OK; hostname'→ OK /amd, ~2 s.Retirement gate — exact state
The note (§4 takeover order, §7): "SSH retires last: laptop-proxy-connect.py (SSH's ProxyCommand) re-points to fleet proxy connect stdio mode only after SSH-through-fleet proven over days, not minutes." Not taken.
laptop-proxy-connect.pyand~/tools/laptop-ssh.share untouched and remain the default SSH route; the proof period started 2026-11-04. Rollback inventory intact:~/tools/fleet.step2-bak(previous binary), the Python broker (still whatlaptop-agent.pyauto-starts if the socket dies, and init-ensure's fallback), thefleet-brokersstandalone package.~/tools/init-ensure.shnow prefersfleet proxy servewith the Python spawn as fallback when no fleet binary exists, and its running-gate accepts either broker process (hatch-personal6d6e98c3c).What the note (and step 1) got wrong about the live system
struct.pack(">Q")— Python broker, Python client, and step 2's fleet-queue all agree). Step 1's fleet-proxy-proto implemented 4-byte, which silently broke fleet-secrets' broker source — it could never have completed a round-trip with the live broker; the failure was masked by its bws fallback. Separately, fleet-config's secrets-token default pointed at.config/secrets-broker/token, a path nothing on the live system has; the live file is~/tools/secrets-broker-token. Both fixed here; the proto crate carries the erratum in its docs.fleet initexisted only on paper. Step 2's dispatch rework dropped the top-level verb (unrecognized subcommand 'init'); §8 and this issue both name it as the autostart entry. Restored, laddered on the proxy-serve capability like the other verbs.std::io::copylowers to splice on Linux; throughfleet proxy connect --stdio, the SSH handshake froze mid-stream (stall point varied by run — banner, KEX, ECDH) whilelaptop-proxy-connect.py's recv/sendall ran the identical path instantly. Traced live with strace. The relay now uses explicit read/write pumps — the Python's syscall shape — and the SSH proof above runs on it. Any future stdio/splice use in this sandbox should treat splice as suspect.