fix(build): give the compose stage the inputs it actually needs #128

Merged
coilysiren merged 1 commit from fix/compose-stage-inputs into main 2026-08-12 02:29:38 +00:00
Member

main is red. Run 148, the merge of #124, failed in publish-echo-image.

Two faults, both in the compose stage

The stage copied agent/compose and scripts/stage-compose-sources.sh and nothing else, but the script builds cmd/sirens-echo-compose, which needs go.mod, go.sum, cmd, and internal. It also never received the script at all: .dockerignore excludes scripts/*.

Why it reached main

Pull-request CI runs build, policy-check, vet, test, and pre-commit. It does not build the image. publish-echo-image is gated on github.ref == 'refs/heads/main', so the first execution of this stage in its entire life was the merge commit.

I introduced the first fault when I moved staging from bash into a Go expander and did not revisit the Dockerfile. The second predates that and was simply never exercised.

The fix

The build stage compiles sirens-echo-compose alongside the other binaries. The compose stage consumes that binary through SIRENS_ECHO_COMPOSE_BIN, so it needs no Go toolchain work and runs the same expander the suite exercises. .dockerignore keeps excluding scripts/* with one negation for the file the stage needs.

Verified

  • Both script paths, toolchain and prebuilt binary, produce creator at 23 skills // 27 files.
  • A build-context check confirms all 14 COPY sources exist and survive .dockerignore.
  • ward exec test, policy-check, vet, prompt-check, pre-commit run --all-files pass.

Still a gap

The image has never been built outside CI. Docker is not running on this host, so I could not build it locally, and PR CI will not build it either. This PR going green does not prove the stage works; only the next push to main does. Worth considering whether PR CI should build the image, since that is the specific hole this fell through.

**main is red.** Run 148, the merge of https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/pulls/124, failed in `publish-echo-image`. ## Two faults, both in the compose stage The stage copied `agent/compose` and `scripts/stage-compose-sources.sh` and nothing else, but the script builds `cmd/sirens-echo-compose`, which needs `go.mod`, `go.sum`, `cmd`, and `internal`. It also never received the script at all: `.dockerignore` excludes `scripts/*`. ## Why it reached main Pull-request CI runs build, policy-check, vet, test, and pre-commit. It does not build the image. `publish-echo-image` is gated on `github.ref == 'refs/heads/main'`, so the first execution of this stage in its entire life was the merge commit. I introduced the first fault when I moved staging from bash into a Go expander and did not revisit the Dockerfile. The second predates that and was simply never exercised. ## The fix The build stage compiles `sirens-echo-compose` alongside the other binaries. The compose stage consumes that binary through `SIRENS_ECHO_COMPOSE_BIN`, so it needs no Go toolchain work and runs the same expander the suite exercises. `.dockerignore` keeps excluding `scripts/*` with one negation for the file the stage needs. ## Verified * Both script paths, toolchain and prebuilt binary, produce creator at 23 skills // 27 files. * A build-context check confirms all 14 `COPY` sources exist and survive `.dockerignore`. * `ward exec test`, `policy-check`, `vet`, `prompt-check`, `pre-commit run --all-files` pass. ## Still a gap The image has never been built outside CI. Docker is not running on this host, so I could not build it locally, and PR CI will not build it either. This PR going green does **not** prove the stage works; only the next push to main does. Worth considering whether PR CI should build the image, since that is the specific hole this fell through.
fix(build): give the compose stage the inputs it actually needs
All checks were successful
ci / test (pull_request) Successful in 54s
ci / publish-echo-image (pull_request) Has been skipped
fc08227c79
The compose stage could never have worked. It copied agent/compose and
the script and nothing else, while the script builds
cmd/sirens-echo-compose, which needs go.mod, cmd, and internal. Worse,
.dockerignore excludes scripts/*, so the one file the stage runs never
reached the build context either.

Neither showed up until now because pull-request CI does not build the
image. Only a push to main runs publish-echo-image, so the first
execution of this stage was the merge, and it went red.

The build stage now compiles the expander alongside the other binaries
and the compose stage consumes that binary, so it needs no toolchain work
and runs the same expander the suite exercises. .dockerignore keeps
excluding scripts/* with one negation for the file the stage needs.

Verified: both script paths produce creator at 23 skills // 27 files, and
a build-context check proves all 14 COPY sources are present and not
ignored. The image itself still has not been built anywhere but CI, which
is the gap that let this land.

Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Author
Member

Now verified by an actual image build

Docker came up locally, so the caveat in the description is discharged. docker build on this branch succeeds end to end.

Inside the compose stage:

bundle verified: 23 skills // 27 files

The bundle reaches the runtime image at /app/agent/bundles/creator, carrying manifest.json, trace.json, a 2487-byte identity card, the 19 admitted aos-public sources, and roster:core with role-creator plus the three personalities.

Both runtime directions check out against the built image:

  • Default role: the container starts and stays up, so resolveBundlePath, LoadBundle, and the inverted ValidateSystemPrompt all pass on a real bundle.
  • SIRENS_DEEP_ROLE=director, which has no baked bundle, exits immediately:
config: no composed bundle for role "director" under /app/agent/bundles: stat /app/agent/bundles/director/manifest.json: no such file or directory

That is the fail-closed behaviour #98 asked for, confirmed in the shipped artifact rather than a unit test.

Worth noting only creator bakes, because it is the only role agent/compose/roles.kdl declares. Any other value of SIRENS_DEEP_ROLE stops the process, which is the correct behaviour but makes the deploy-time flip a two-step change today: declare the role, then set the variable.

The pull-request CI gap this fell through is filed as #129.

## Now verified by an actual image build Docker came up locally, so the caveat in the description is discharged. `docker build` on this branch succeeds end to end. Inside the compose stage: ``` bundle verified: 23 skills // 27 files ``` The bundle reaches the runtime image at `/app/agent/bundles/creator`, carrying `manifest.json`, `trace.json`, a 2487-byte identity card, the 19 admitted `aos-public` sources, and `roster:core` with `role-creator` plus the three personalities. Both runtime directions check out against the built image: * Default role: the container starts and stays up, so `resolveBundlePath`, `LoadBundle`, and the inverted `ValidateSystemPrompt` all pass on a real bundle. * `SIRENS_DEEP_ROLE=director`, which has no baked bundle, exits immediately: ``` config: no composed bundle for role "director" under /app/agent/bundles: stat /app/agent/bundles/director/manifest.json: no such file or directory ``` That is the fail-closed behaviour https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/98 asked for, confirmed in the shipped artifact rather than a unit test. Worth noting only `creator` bakes, because it is the only role `agent/compose/roles.kdl` declares. Any other value of `SIRENS_DEEP_ROLE` stops the process, which is the correct behaviour but makes the deploy-time flip a two-step change today: declare the role, then set the variable. The pull-request CI gap this fell through is filed as https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/129.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!128
No description provided.