Skip to content

Absorb fleet placement into repo-queue: dispatch + session commands (spec = docs/placement.md in developing-today/fleet) #5413

Open

Description

@developing-today

What

The fleet's placement capability — deciding WHERE a build job runs
across the fleet's GitHub Actions copies and runner providers, and
dispatching it there — currently exists as a reference
implementation in the org fork of the fleet umbrella:

  • Spec + frozen client interface: docs/placement.md in
    developing-today/fleet (branch fleet-place, commit 1258ed8;
    lands on the fork's main once the fork is added to this app's
    installation — see below).
  • Reference implementation: tools/fleet-place + the data registry
    tools/fleet-surfaces.json in the same repo.

Drew's direction (2026-11-04): this capability belongs in the binary
clients already use — repo-queue — so lane workers and Muse
clients trigger jobs in the appropriate location through one
interface, with sessions that outlive the client (reconnect by
handle). The crates are being refactored in another line of work
today; this issue is the absorption spec so that work inherits the
architecture instead of redesigning it. Do not treat the Python
dispatcher as the destination.

The contract to implement (from placement.md, frozen v1)

repo-queue dispatch --repo developing-today/code \
  --command 'nix build .#mcpx' [--ref SHA] \
  [--runner auto|github|blacksmith] [--surface ID] \
  [--push-nix-cache] [--actions-cache KEY:PATH] \
  [--allow-paid-blacksmith MINUTES]
# -> session handle (fp_...), chosen surface, reasoning

repo-queue session status HANDLE    # mapped state + run URL
repo-queue session result HANDLE    # terminal result
repo-queue session list [--mine]

Non-negotiables:

  1. Registry as data. Surfaces live in tools/fleet-surfaces.json
    (id, kind, owner, repo, workflow, app installation, capacity /
    budget posture, eligibility). Adding a location = adding an
    entry (+ app installation + a fleet copy). The binary reads the
    same registry format; no surface is ever hardcoded.
  2. Adapters per placement kind. github-actions dispatch,
    blacksmith (runner variant, org-only, budgeted), codespace
    (session handoff, last resort), laptop (recorded handoff) —
    each behind eligible/capacity/dispatch/status. A new placement
    type = a new adapter + a kind value; dispatch/session logic
    untouched.
  3. App-only dispatch. Every dispatch mints an installation
    token for the host repo's owner through the fleet-paperwork
    flow (App private key from the sops secrets file). Both
    installations (org 174792676, personal 175747567). No user-token
    path; a surface the app cannot reach is ineligible, loudly.
  4. Sessions server-side. Handle = fp_ + 128-bit random.
    Record: payload, surface + why, run id/URL, submitter, state,
    timestamps. DDL for agent.placement_sessions is in
    placement.md (the Python stopgap is a local JSON store with
    identical semantics — migrate records, don't redesign them).
  5. Spill cascade. GitHub-hosted capacity per owner (live
    running+queued vs plan cap) → Blacksmith inside its free
    3,000 min/mo budget (paid only via explicit per-job allowance or
    the registry's paid cap) → Codespaces when Actions is tapped and
    the laptop is saturated → otherwise the job stays queued in
    repo-queue. Nothing is dropped for lack of a surface.
  6. Caching passthrough. fleet-run jobs may carry per-entry
    cache options (nix closure → fleet R2 cache via the existing
    signing machinery; actions/cache for non-nix artifacts). The
    dispatch command exposes them as flags, unchanged.

Proof state of the reference implementation (2026-11-04)

  • Dry-run cascade verified, incl. simulated spill to Blacksmith and
    the all-tapped → queued outcome.
  • Real dispatch as the app: session fp_5ccf1d4ca63f4ca0939fd909345bd9ad,
    run https://github.com/dezren39/fleet/actions/runs/41819899125
    (triggering actor developing-today[bot]), pin-check job read
    back to succeeded via the session handle.

Blockers that also gate this

  • developing-today/fleet is not yet in this app's installation
    scope (org-owner grant pending) — the reference branch waits on
    it to push.
  • org-run (this repo) is pre-registered as a surface; when it lands,
    flip its registry status and give it the runner input for
    Blacksmith parity (small follow-up PR, noted in placement.md).

Unassigned on purpose; pick up with the queue refactor.

Acceptance criteria

  • fleet placement (dispatch + session commands per docs/placement.md in developing-today/fleet) is absorbed into repo-queue.
  • 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.

Activity

  1. added
    priority/normalOrdinary priority (the default)
    effort/mMedium: expected under 1 day of work
    on Nov 4, 2026
  2. dezren39 commented on Nov 4, 2026

    @dezren39
    Member

    Intake review

    🤖 Agent note · state: filed

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-11-04 06:12 CST
    • Found via: monitor reconciliation
    • Task: Intake enrichment (protocol §5): verified still live in a bounded check this run (no merged PR or closed duplicate naming this fix), appended acceptance criteria, normalized labels.
    • Expectation: as labelled (effort class on the issue); done = acceptance criteria met with evidence linked here.

    Related: epic #5412 and steps #5429-#5433 form one set; #5413 is a sibling absorption task. Native sub-issue attachment per protocol §11 is recommended for the epic if not already done.
    Risks: Low for the intake pass itself; implementation risk lives in the issue body.
    Suggested approach: Triage through the queue in dependency order, verifying each step's acceptance evidence before closing.

  3. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Nov 4, 2026
  4. added
    queue/queuedHas a queued task in the Supabase agent queue
    task/triageQueue packet kind: verify, reproduce, and route this item
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 5, 2026
  5. dezren39 commented on Nov 5, 2026

    @dezren39
    Member

    🤖 Agent note · done (triage)

    Triage findings for issue #5413 (task 10037)

    Verified current (2026-11-05, fresh reads): issue #5413 is OPEN, filed 2026-11-04T11:22:49Z, with no hard-stop labels (held, user/owned, do-not-merge, do-not-auto-edit). The absorption has not happened: the live fleet binary (0.1.0, checked this triage) registers domains queue / serve / proxy / dispatch / secrets / search / laptop-agent, and fleet queue dispatch answers unknown command "dispatch" — there are no placement dispatch / session commands in the queue domain, and no agent.placement_sessions client surface. The existing dispatch domain is a different thing (a thin client over pm-stack dispatch, per its own help text) and must not be mistaken for the placement contract in docs/placement.md. No PR or issue implements issue #5413: the only issues referencing it are issue #5942 (fleet-paperwork tests run by no workflow) and issue #5713 (flag handling in the pm-stack dispatch domain) — adjacent, not this absorption.

    Gates recorded (both already named in the issue body; re-verified as still standing):

    1. Queue-refactor timing. The issue states the crates are being refactored in another line of work and to "pick up with the queue refactor" — it was left unassigned on purpose. Since filing, the queue transport did migrate (fleet multicall binary, broker-backed, per the 2026-11-04 transport note in the worker runbook), so the absorption target is now the fleet binary's queue domain, not the retired Python repo-queue; the contract (dispatch + session status/result/list, fp_ handles, registry-as-data, app-only dispatch) is unchanged by that move.
    2. App installation scope. developing-today/fleet is not yet in the developing.today GitHub App's installation scope (org-owner grant pending), so the spec branch fleet-place (commit 1258ed8) still waits to land on the fork's main. The repo itself is reachable via gh (verified this triage); the grant is the Drew-owned step, exactly as recorded at filing — it is not a new blocker discovered here.

    Scoped pickup path (when the gates clear): implement per the frozen v1 contract in docs/placement.md — registry read from tools/fleet-surfaces.json format with no hardcoded surfaces, one adapter per placement kind behind eligible/capacity/dispatch/status, installation-token-only dispatch via the fleet-paperwork flow, server-side agent.placement_sessions records migrated from the Python stopgap's JSON semantics, spill cascade and caching passthrough unchanged — landed via PR referencing this issue, per its acceptance criteria.

    The issue stays open, labelled triaged + waiting-dependency to mirror gates 1–2. No code change in this triage.

  6. added
    status/triagedTriaged and routed (see agent note)
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area/infraInfrastructure, deployment, and operationseffort/mMedium: expected under 1 day of workkind/infrastructureInfrastructure / host-portability workmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)status/triagedTriaged and routed (see agent note)status/waiting-dependencyWaiting on a dependencytask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions