head -n -1 fails on BSD/macOS, making the plan's local verification steps
unrunnable. Bash parameter expansion is portable and drops two subprocesses
per endpoint.
Claude-Session: https://claude.ai/code/session_01S3aqJ4tvaPezQhsGNCybut
One instance per server, each owning its local Docker daemon; Gitea CI
posts /update to every instance. Records why MODE exclusivity is correct
rather than a limitation, and the alternatives rejected.
Claude-Session: https://claude.ai/code/session_01S3aqJ4tvaPezQhsGNCybut
req.Tag was only echoed in the HTTP response, never used to match jobs.
Compose mode didn't care (ComposeExecutor re-pulls the compose file's own
pinned tag), but SwarmExecutor sets the service image directly from
Job.Image, which was built from the untagged req.Image alone -- so a
Swarm deploy silently rewrote the service to :latest instead of the
requested tag. Build the full image:tag reference once in the handler
and pass it into FindJobs; NormaliseImage/ImagesMatch already strip
tags before matching, so this doesn't change which jobs match in either
mode.
Adds the Swarm-mode counterpart to ComposeExecutor: updates a Swarm
service's image directly through the Docker SDK (ServiceInspectWithRaw +
ServiceUpdate with QueryRegistry=true so floating tags resolve to a fresh
digest), gated by the same Refused guard used in Compose mode. Satisfies
the existing Executor interface unchanged, so Queue needs no changes.
Verified the Docker SDK v28.5.2+incompatible ServiceList signature via go doc
before implementing: the options type is swarm.ServiceListOptions, not
types.ServiceListOptions as the brief assumed. Everything else (Service.ID,
Service.Spec via embedded Annotations for Name/Labels, TaskTemplate.ContainerSpec.Image)
matched the brief exactly.
Reuses discovery.ImagesMatch and discovery.HasOptIn rather than duplicating
matching/opt-in logic. Opt-in label is read from the service spec's own
labels since Swarm services have no local compose file to anchor a
STACKS_ROOT path check against (unlike Compose mode).
Captures design intent, gotchas, and references that aren't obvious
from code alone — single-worker queue rationale, defense-in-depth
security model, the not-yet-wired selfupdate package, and pointers
to the design spec and implementation plan in docs/superpowers/.