Context
queuezero's cohort core reconciles named, single-entity launches and depends on two provider-seam guarantees (q0 non-negotiables #4 and #5):
spawn's pkg/aws.Client.Launch(ctx, LaunchConfig) (*LaunchResult, error) already has the right shape (one named instance per call, rich tag-driven config), which is exactly why it's the natural candidate to back cohort's Actuator once cohort graduates into this monorepo (ARCHITECTURE §15). But two gaps block that today:
1. No ClientToken on RunInstances
pkg/aws/client.go (~line 352) issues RunInstances with MinCount=1, MaxCount=1 and no ClientToken. Without it, a retry after a network timeout can double-launch, and the caller can't distinguish "launch succeeded but the response was lost" from "launch never happened" — that's the Ambiguous fault class cohort is designed never to see.
2. Opaque errors
The launch path wraps failures as fmt.Errorf("failed to run instances: %w", err). The verbatim AWS error code (InsufficientInstanceCapacity, RequestLimitExceeded, Unsupported, spot MaxSpotInstanceCountExceeded, …) survives in the %w chain but there's no exported way to get it as a classifiable value — cohort needs to branch on capacity-vs-quota-vs-config to drive fast-fail vs fallback-rung vs lagotto-watch.
(For reference, pkg/orchestrator.scaleUp uses the MinCount==MaxCount==count count-based fleet pattern — that one is the count-based abstraction cohort retires wholesale and is not what this issue asks to fix; this is only about the single-entity Launch.)
Ask
So that spawn/pkg/aws.Launch can legitimately fill cohort's Actuator:
- Add a
ClientToken string field to LaunchConfig (or accept it as an explicit arg) and pass it through to RunInstancesInput.ClientToken. Caller supplies the deterministic token; spawn just plumbs it.
- Either (a) return the underlying
smithy.APIError unwrapped/typed so callers can classify on ErrorCode(), or (b) expose a small exported error type carrying the verbatim code. Do not paraphrase the code.
Neither change alters spawn's existing CLI behavior (token optional → today's behavior; error wrapping can stay, just stop hiding the code).
Acceptance
Launch accepts a caller-supplied ClientToken and forwards it to RunInstances.
- A capacity/quota/config failure from
Launch is recoverable as a Go value with the verbatim AWS error code intact.
Filed from queuezero's spawn/spored leverage review (post Phase 2m, the first spore.host dep — truffle — having landed). This is the launch-side half of the convergence; the readiness/sensor half is #333.
Migrated from spore-host/spore-host#335 — spawn issues belong on this repo.
Context
queuezero's cohort core reconciles named, single-entity launches and depends on two provider-seam guarantees (q0 non-negotiables #4 and #5):
(cluster, entity, generation). They collapse theAmbiguousfault class (did myRunInstancessucceed before the timeout?) so it never reaches the reconciler.spawn's
pkg/aws.Client.Launch(ctx, LaunchConfig) (*LaunchResult, error)already has the right shape (one named instance per call, rich tag-driven config), which is exactly why it's the natural candidate to back cohort'sActuatoronce cohort graduates into this monorepo (ARCHITECTURE §15). But two gaps block that today:1. No
ClientTokenonRunInstancespkg/aws/client.go(~line 352) issuesRunInstanceswithMinCount=1, MaxCount=1and noClientToken. Without it, a retry after a network timeout can double-launch, and the caller can't distinguish "launch succeeded but the response was lost" from "launch never happened" — that's theAmbiguousfault class cohort is designed never to see.2. Opaque errors
The launch path wraps failures as
fmt.Errorf("failed to run instances: %w", err). The verbatim AWS error code (InsufficientInstanceCapacity,RequestLimitExceeded,Unsupported, spotMaxSpotInstanceCountExceeded, …) survives in the%wchain but there's no exported way to get it as a classifiable value — cohort needs to branch on capacity-vs-quota-vs-config to drive fast-fail vs fallback-rung vs lagotto-watch.(For reference,
pkg/orchestrator.scaleUpuses theMinCount==MaxCount==countcount-based fleet pattern — that one is the count-based abstraction cohort retires wholesale and is not what this issue asks to fix; this is only about the single-entityLaunch.)Ask
So that
spawn/pkg/aws.Launchcan legitimately fill cohort'sActuator:ClientToken stringfield toLaunchConfig(or accept it as an explicit arg) and pass it through toRunInstancesInput.ClientToken. Caller supplies the deterministic token; spawn just plumbs it.smithy.APIErrorunwrapped/typed so callers can classify onErrorCode(), or (b) expose a small exported error type carrying the verbatim code. Do not paraphrase the code.Neither change alters spawn's existing CLI behavior (token optional → today's behavior; error wrapping can stay, just stop hiding the code).
Acceptance
Launchaccepts a caller-suppliedClientTokenand forwards it toRunInstances.Launchis recoverable as a Go value with the verbatim AWS error code intact.Filed from queuezero's spawn/spored leverage review (post Phase 2m, the first spore.host dep — truffle — having landed). This is the launch-side half of the convergence; the readiness/sensor half is #333.
Migrated from spore-host/spore-host#335 — spawn issues belong on this repo.