Skip to content

health: the container roster lists every container on the docker socket β€” scope it to the station's compose project (#567 follow-up)Β #629

Description

@genwave-radio

πŸ› Sighting (dev box thor, main @ 257c801, 2026-08-2x β€” THOUGHTS.md tail, triaged 08-28)

The admin Health page lists containers that are not GenWave's: a foreign buildx builder (buildx_buildkit_daemonfm-builder0, moby/buildkit) sits in the roster permanently, and the test-suite's throwaway Postgres containers (DatabaseFixture) flicker through it during every dotnet test.

πŸ” Why #567 didn't cover it

PR #567 (closes #283) made utility-labeled compose services invisible: genwave.role: utility β†’ dropped at DockerContainerStatsSource before any stats call. That contract is right for our own one-shot helpers (ollama-init), but it only ever sees our labels. Anything the station didn't launch β€” another project's builder, a test fixture, whatever else shares the docker socket on a dev box or a homelab host β€” carries no genwave.* label and no com.docker.compose.project matching ours, so it sails through .Where(summary => !IsUtility(summary)) and gets a stats + inspect fan-out per poll on top of the listing.

src/GenWave.Host/Stats/DockerContainerStatsSource.cs:66

πŸ”§ Proposed contract

Scope the roster to the station's own compose project, then apply the utility exclusion inside it:

  • The api learns its own project name once at startup β€” read its own container's com.docker.compose.project label via the same dockerproxy (/containers/{self}/json, hostname = container id), or COMPOSE_PROJECT_NAME from env as the override β€” and filters /containers/json on label=com.docker.compose.project=<name> server-side (docker's filters query param), so foreign containers never even cost a listing entry.
  • Fallback when the label can't be determined (non-compose deployments): today's behaviour, logged once at Information so the field can tell which mode it's in.
  • Spec pins: a foreign container in the summary list is absent from the roster; a genwave.role: utility container inside the project is still absent; the fallback path lists everything (pinned as deliberate).

Cheap, and it also shrinks the per-poll dockerproxy ceremony on shared hosts β€” a sliver of the #558 volume story.

🎯 Where it bites in the field

A homelab host is exactly the shared-socket case β€” Dockge/Portainer, Home Assistant, whatever else β€” and the Health page is the first thing a new operator reads. Foreign containers there read as "GenWave is running things I didn't ask for."

Refs: #283 / #567 (the utility contract), #558 (poll ceremony volume), #364 (per-container caps discussion).

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low prioritybugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions