π 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).
π 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 everydotnet test.π Why #567 didn't cover it
PR #567 (closes #283) made utility-labeled compose services invisible:
genwave.role: utilityβ dropped atDockerContainerStatsSourcebefore 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 nogenwave.*label and nocom.docker.compose.projectmatching 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:
com.docker.compose.projectlabel via the same dockerproxy (/containers/{self}/json, hostname = container id), orCOMPOSE_PROJECT_NAMEfrom env as the override β and filters/containers/jsononlabel=com.docker.compose.project=<name>server-side (docker'sfiltersquery param), so foreign containers never even cost a listing entry.genwave.role: utilitycontainer 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).