CI parity: run eco-app CI inside the pinned aos dev-base container via ward verbs #57

Closed
opened 2026-07-05 02:10:39 +00:00 by coilysiren · 2 comments
Owner

Ask

Switch eco-app CI to run inside the pinned aos dev-base container via ward exec verbs, so eco-app's CI gate is the same gate its headless agents run. eco-app is the first mover / reference implementation for the fleet-wide CI-parity convention (aos umbrella, linked below).

Why here, why now

eco-app is where the divergence bit: CI (runs-on: docker + astral-sh/setup-uv) stayed green while three dispatched warded runs died on the smoke gate in the dev-base container (#56). Running CI in the same image, through the same verbs, would have caught #56 on a PR instead of in a silent dispatch failure.

Shape

  • .forgejo/workflows/build-publish.yml: run the test job in container: <registry>/dev-base:<pinned-tag> and replace the hand-rolled uv run pytest / uv run ruff / uv run mypy steps with ward exec test and ward exec lint. Add ward exec smoke so the MCP round-trip is gated in CI too (it is the gate agents must pass).
  • Keep the docker build/publish job as is - only the validation job moves into the pinned container.
  • Pin the dev-base tag, do not track :latest, so a dev-base bump is a deliberate PR that re-validates eco-app.

Dependencies

  • Blocked on the dev-base image fix (aos, companion issue) so uv can install 3.13 in-container - or lands after #56's Makefile workaround, which makes ward exec pass inside the current image. Either unblocks this. Simplest order: land #56 first, then this rides on it and stays green.
  • Part of the aos fleet-wide CI-parity umbrella (linked in the epic thread / filed alongside).

Acceptance

  • eco-app CI runs its validation job inside the pinned dev-base container using ward exec test / ward exec lint / ward exec smoke.
  • CI is red if an agent could not land the change (parity), green otherwise.
  • The dev-base tag is pinned and bumping it is a visible PR.
## Ask Switch eco-app CI to run **inside the pinned aos dev-base container** via `ward exec` verbs, so eco-app's CI gate is the same gate its headless agents run. eco-app is the first mover / reference implementation for the fleet-wide CI-parity convention (aos umbrella, linked below). ## Why here, why now eco-app is where the divergence bit: CI (`runs-on: docker` + `astral-sh/setup-uv`) stayed green while three dispatched `warded` runs died on the smoke gate in the dev-base container ([#56](https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/56)). Running CI in the same image, through the same verbs, would have caught #56 on a PR instead of in a silent dispatch failure. ## Shape * `.forgejo/workflows/build-publish.yml`: run the test job in `container: <registry>/dev-base:<pinned-tag>` and replace the hand-rolled `uv run pytest` / `uv run ruff` / `uv run mypy` steps with `ward exec test` and `ward exec lint`. Add `ward exec smoke` so the MCP round-trip is gated in CI too (it is the gate agents must pass). * Keep the docker build/publish job as is - only the validation job moves into the pinned container. * Pin the dev-base tag, do not track `:latest`, so a dev-base bump is a deliberate PR that re-validates eco-app. ## Dependencies * Blocked on the dev-base image fix (aos, companion issue) so `uv` can install 3.13 in-container - or lands after [#56](https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/56)'s Makefile workaround, which makes `ward exec` pass inside the current image. Either unblocks this. Simplest order: land [#56](https://forgejo.coilysiren.me/coilyco-gaming/eco-app/issues/56) first, then this rides on it and stays green. * Part of the aos fleet-wide CI-parity umbrella (linked in the epic thread / filed alongside). ## Acceptance * eco-app CI runs its validation job inside the pinned dev-base container using `ward exec test` / `ward exec lint` / `ward exec smoke`. * CI is red if an agent could not land the change (parity), green otherwise. * The dev-base tag is pinned and bumping it is a visible PR.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-eco-app-57 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-05T05:33:24Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-eco-app-57` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-05T05:33:24Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - test job now runs in pinned dev-base (agentic-os:v0.195.0) via ward exec test/lint/smoke; landed on main as 9956116.

Retrospective: this one was gentler than the issue's dependency notes braced me for. The #56 Makefile workaround (UV_PYTHON_INSTALL_DIR pointed at a HOME-writable dir) was already merged, so the hard part - making uv install a 3.13 in-container - was solved before I arrived. The workflow edit itself was small: swap setup-uv + three uv run steps for the three ward verbs and pin the container.

The nice surprise was that this container is a dev-base container, so I ran the exact CI gate here before committing rather than trusting it blind: lint clean, 453 tests green, smoke exits 0 with all six MCP responses. That's real parity confidence, not a guess. One small wrinkle - uv grabbed a managed 3.14 (latest satisfying requires-python >=3.13), not 3.13. Harmless and CI will do the same, but worth knowing the pin is a floor, not an exact match.

Confidence is high on the Python job. Two honest rough edges worth a follow-up: (1) I pinned v0.195.0 off the substrate checkout's HEAD tag and confirmed it resolves in the registry, but nothing automatically bumps eco-app's pin when dev-base moves - that's the "deliberate PR" by design, though a reminder mechanism might be nice. (2) I deliberately left the mods and frontend jobs alone per the issue's "only the validation job moves" scope, but the mods job carries a TODO(eco-app#60) to drop its .NET self-install now that dev-base ships the SDK - that's the natural next parity step and already has a home in #60.

WARD-OUTCOME: done - test job now runs in pinned dev-base (agentic-os:v0.195.0) via `ward exec test`/`lint`/`smoke`; landed on main as 9956116. Retrospective: this one was gentler than the issue's dependency notes braced me for. The #56 Makefile workaround (`UV_PYTHON_INSTALL_DIR` pointed at a HOME-writable dir) was already merged, so the hard part - making `uv` install a 3.13 in-container - was solved before I arrived. The workflow edit itself was small: swap setup-uv + three `uv run` steps for the three ward verbs and pin the container. The nice surprise was that this container **is** a dev-base container, so I ran the exact CI gate here before committing rather than trusting it blind: lint clean, 453 tests green, smoke exits 0 with all six MCP responses. That's real parity confidence, not a guess. One small wrinkle - `uv` grabbed a managed 3.14 (latest satisfying `requires-python >=3.13`), not 3.13. Harmless and CI will do the same, but worth knowing the pin is a floor, not an exact match. Confidence is high on the Python job. Two honest rough edges worth a follow-up: (1) I pinned `v0.195.0` off the substrate checkout's HEAD tag and confirmed it resolves in the registry, but nothing automatically bumps eco-app's pin when dev-base moves - that's the "deliberate PR" by design, though a reminder mechanism might be nice. (2) I deliberately left the `mods` and `frontend` jobs alone per the issue's "only the validation job moves" scope, but the mods job carries a `TODO(eco-app#60)` to drop its .NET self-install now that dev-base ships the SDK - that's the natural next parity step and already has a home in #60.
Sign in to join this conversation.
No description provided.