Skip to content

ADR 023 Project-Owned Remote Image Build

The development Compose file owned a local build: definition and Mutagen started the stage with docker compose up --build. Workstation disk, daemon state, cache contents, and CPU capacity therefore became release inputs. GitHub-hosted image builds would add cold caches, execution limits, duplicated workflow code, and unnecessary cost.

FractalOps already operates the company Kubernetes BuildKit plane. Using shared compute must not place Sanmopia source, images, releases, or domain decisions under FractalOps ownership.

Sanmopia owns:

  • repository source and .fractalops/image-build.json;
  • the ghcr.io/yamonco/sanmopia-modernization-assembly image namespace;
  • immutable image digest selection and deployment promotion;
  • release lifecycle, rollback, and integrated evidence.

yamonco/.github owns the reusable GitHub contract company-remote-build-v4. The assembly caller references only that contract, validates a default-branch source revision, dispatches, links execution status, and exits. GitHub-hosted compute does not run BuildKit, scans, or signing.

FractalOps owns only the versioned remote build executor adapter and shared build plane. remote-build-executor-v4 validates the bounded project profile, attaches the Kubernetes fractalops-buildx builder, uses isolated registry cache, builds and pushes the project-owned image, scans high/critical vulnerabilities, signs with Cosign, verifies the digest, and emits immutable evidence. FractalOps names may appear as provider provenance but never as the project image namespace or release authority.

Compose contains no build: definitions. Mutagen contains no --build command. Stage startup only pulls the digest in SANMOPIA_ASSEMBLY_IMAGE. Local Docker builds, GitHub-hosted builds, per-project BuildKit daemons, and the BuildKit remote driver are not fallback paths.

Only image compilation belongs to Buildx. Pulling an already-built immutable runtime image is acquisition, not a fallback build. The project must reuse the existing self-hosted Supabase stage; supabase start and supabase stop are not project lifecycle commands because they bypass that stage and may pull a second runtime stack onto the workstation.

  • pnpm stage:check rejects local Compose builds, Mutagen --build, mutable or foreign image namespaces, unpinned Dockerfile bases, profile drift, local Buildx implementation, --load, local Supabase CLI lifecycle commands, and drift away from the fractalops-buildx Kubernetes builder or buildx-cluster-build preview phase.
  • Organization contract company-remote-build-v4 resolves to c130121a176f55ffeac15fc3f48a95e80d810ffe.
  • FractalOps execution adapter remote-build-executor-v4 resolves to 11c43fa6d7b01907d86cd98d42dcffccecb47a6f.
  • Execution 29155893875 published source 86c2c0ac652969979fc4373716c30b2cb24f595d through the Kubernetes driver, passed the high/critical vulnerability gate, uploaded and registry-verified a Cosign signature, and retained a Sigstore v0.3 bundle.
  • Stage pins ghcr.io/yamonco/sanmopia-modernization-assembly at sha256:41ee2a09368b02f829cc8dd7bfd129eee8ba4b6059baf02b895b71d241dd632f.

Developer machines and GitHub-hosted runners no longer compile Sanmopia images. Shared cache and compute reduce latency without changing project ownership. A build-plane outage fails the release visibly instead of falling back to a workstation. Contract and executor changes require separate reviewed version bumps.

  • 2026-07-11: accepted project-owned image releases with organization-owned GitHub contract and FractalOps remote execution adapter.
  • 2026-07-13: made the FractalOps Buildx builder and preview phase executable stage-gate invariants; prohibited local Supabase CLI lifecycle fallback.