dev-base: ship the .NET SDK (+ ICU) so C# mods compile in-container (sibling of #327 uv fix) #329

Closed
opened 2026-07-05 03:46:36 +00:00 by coilysiren · 2 comments
Owner

Problem

dev-base ships no .NET SDK, so any repo with C# to compile cannot build in-container. The eco-app#8 engineer run hit this: to compile the Eco mods (mods/*, dotnet build) it had to hand-install the .NET 10 SDK mid-run, and because the base image also lacks ICU, it needed DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 to get a green build.

This is the same class as #327 (dev-base couldn't install the Python a repo required): a toolchain a consumer needs is absent from the image, so each run reinvents the install, and CI never catches C# breakage because CI is not the dev-base container.

Ask

Add the .NET SDK to docker/dev-base/Dockerfile (pin a version - .NET 10 is what eco-app's mods build against), so C# compiles in-container with no per-run install. Handle globalization deliberately, one of:

  1. Install ICU (libicu) so globalization works normally (preferred - no surprising invariant-mode behavior), or
  2. Set DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 in the image env and document why.

Prefer installing ICU unless image size argues otherwise.

Why it matters fleet-wide

Once dev-base carries dotnet, eco-app's mod-compile CI stage (sibling eco-app issue) drops its self-install, and CI-in-dev-base parity (#328) covers C# mod compilation for free - a mod that does not build fails CI, not deploy. Any future C# consumer gets a working toolchain out of the box.

Acceptance

  • In a fresh dev-base container, dotnet build of an Eco mod .csproj succeeds with no hand-install and no globalization error.
  • The image rebuild flows through the existing publish-image path on push to main.
  • The globalization choice (ICU vs invariant) is documented in the Dockerfile.

Origin

Found by the eco-app#8 engineer, 2026-07-05 (hand-installed .NET 10 + invariant-globalization to avoid shipping a C# mod blind). Sibling: eco-app CI mod-compile stage. Precedent: #327 (uv/Python). Umbrella: #328 (CI-in-dev-base parity).

## Problem dev-base ships no **.NET SDK**, so any repo with C# to compile cannot build in-container. The eco-app#8 engineer run hit this: to compile the Eco mods (`mods/*`, `dotnet build`) it had to hand-install the .NET 10 SDK mid-run, and because the base image also lacks **ICU**, it needed `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1` to get a green build. This is the same class as [#327](https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/issues/327) (dev-base couldn't install the Python a repo required): a toolchain a consumer needs is absent from the image, so each run reinvents the install, and CI never catches C# breakage because CI is not the dev-base container. ## Ask Add the **.NET SDK** to `docker/dev-base/Dockerfile` (pin a version - **.NET 10** is what eco-app's mods build against), so C# compiles in-container with no per-run install. Handle globalization deliberately, one of: 1. Install **ICU** (`libicu`) so globalization works normally (preferred - no surprising invariant-mode behavior), or 2. Set `DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1` in the image env and document why. Prefer installing ICU unless image size argues otherwise. ## Why it matters fleet-wide Once dev-base carries dotnet, eco-app's mod-compile CI stage (sibling eco-app issue) drops its self-install, and **CI-in-dev-base parity ([#328](https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/issues/328)) covers C# mod compilation for free** - a mod that does not build fails CI, not deploy. Any future C# consumer gets a working toolchain out of the box. ## Acceptance * In a fresh dev-base container, `dotnet build` of an Eco mod `.csproj` succeeds with no hand-install and no globalization error. * The image rebuild flows through the existing publish-image path on push to main. * The globalization choice (ICU vs invariant) is documented in the Dockerfile. ## Origin Found by the eco-app#8 engineer, 2026-07-05 (hand-installed .NET 10 + invariant-globalization to avoid shipping a C# mod blind). Sibling: eco-app CI mod-compile stage. Precedent: [#327](https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/issues/327) (uv/Python). Umbrella: [#328](https://forgejo.coilysiren.me/coilyco-flight-deck/agentic-os/issues/328) (CI-in-dev-base parity).
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-agentic-os-329 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-05T03:46:47Z). 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-agentic-os-329` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-05T03:46:47Z). 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 - dev-base now bakes the .NET 10 SDK (10.0.301) + libicu74, C# mods compile in-container with full ICU globalization, landed on main (a4d6126).

This one was a clean sibling of #327 and mostly went to plan. The install path is Microsoft's dotnet-install.sh pinned to an exact SDK, world-readable under /usr/local/dotnet like every other tool, plus a DOTNET_ARCH row in the arch map and a conservative auto-bump resolver that stays on the .NET 10 channel (the NODE_VERSION major-pin rationale).

What fought back: docs/dev-base-image.md was already sitting at 3965/4000 against the hard doc-size cap, so a single new bullet blew it over. There's no per-file cap override for a generic doc (only AGENTS/README/trifecta get one), so I had to tighten several existing bullets to buy room - routine upkeep for a growing inventory doc, but more fiddly than the actual feature.

Confidence is high. I couldn't build the real multi-arch image here (no daemon), but I validated the exact Dockerfile commands locally: 10.0.301 installs and compiles a net10.0 mod-shaped classlib with 0 errors, and a no-ICU box reproduces the precise crash libicu74 fixes - so the ICU-over-invariant choice is proven, not assumed. Real proof arrives when the publish-image job rebuilds :latest on this push.

Rough edges / follow-ups: (1) libicu74 is spelled for Ubuntu 24.04's ICU major; a base-image bump needs it re-pinned to that release's libicuNN (noted in the Dockerfile comment). (2) The sibling eco-app CI mod-compile stage can now drop its self-install. (3) Unrelated: tests/test_check_commit_closes_issue.py has 6 pre-existing failures on clean HEAD (stale test for the retired closes-issue hook) - worth a cleanup issue, untouched here.

WARD-OUTCOME: done - dev-base now bakes the .NET 10 SDK (10.0.301) + libicu74, C# mods compile in-container with full ICU globalization, landed on main (a4d6126). This one was a clean sibling of #327 and mostly went to plan. The install path is Microsoft's `dotnet-install.sh` pinned to an exact SDK, world-readable under `/usr/local/dotnet` like every other tool, plus a `DOTNET_ARCH` row in the arch map and a conservative auto-bump resolver that stays on the .NET 10 channel (the NODE_VERSION major-pin rationale). What fought back: `docs/dev-base-image.md` was already sitting at 3965/4000 against the hard doc-size cap, so a single new bullet blew it over. There's no per-file cap override for a generic doc (only AGENTS/README/trifecta get one), so I had to tighten several existing bullets to buy room - routine upkeep for a growing inventory doc, but more fiddly than the actual feature. Confidence is high. I couldn't build the real multi-arch image here (no daemon), but I validated the exact Dockerfile commands locally: 10.0.301 installs and compiles a `net10.0` mod-shaped classlib with 0 errors, and a no-ICU box reproduces the precise crash `libicu74` fixes - so the ICU-over-invariant choice is proven, not assumed. Real proof arrives when the publish-image job rebuilds `:latest` on this push. Rough edges / follow-ups: (1) `libicu74` is spelled for Ubuntu 24.04's ICU major; a base-image bump needs it re-pinned to that release's `libicuNN` (noted in the Dockerfile comment). (2) The sibling eco-app CI mod-compile stage can now drop its self-install. (3) Unrelated: `tests/test_check_commit_closes_issue.py` has 6 pre-existing failures on clean HEAD (stale test for the retired closes-issue hook) - worth a cleanup issue, untouched here.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
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-flight-deck/agentic-os#329
No description provided.