Add services.LookupAny + fix 6 binary-service silent failures#62
Merged
munezaclovis merged 8 commits intomainfrom Apr 15, 2026
Merged
Add services.LookupAny + fix 6 binary-service silent failures#62munezaclovis merged 8 commits intomainfrom
munezaclovis merged 8 commits intomainfrom
Conversation
Closes the silent-failure gaps left over from the rustfs and mailpit binary-service migrations. Six callsites currently consult only the Docker registry via services.Lookup and silently mishandle binary services (s3, mail) — the wizard hides them, post-wizard provisioning skips them, doctor reports them as broken, install validation rejects them, and `pv service:env` errors on them. Spec introduces a single new helper services.LookupAny returning a tagged-union (Kind, BinaryService, Service, error), then walks each of the six callsites with a small kind-branched fix. Out of scope: the dispatcher's resolveKind (different invariant), stop.go's applyFallbacks issue (different bug shape), and the ReadyCheck sum-type tightening (separate type-design PR).
Six tasks executing the design from docs/superpowers/specs/2026-04-15-services-lookupany-design.md: 1. Pre-flight verification of service.RunAdd's arg shape. 2. services.LookupAny + 4 unit tests (TDD). 3. cmd/setup.go: extract buildServiceOptions + post-wizard branch. 4. internal/commands/service/env.go: extract envVarsFor dispatch helper so both call sites and the test exercise the same code path. 5. cmd/doctor.go: skip binary services in per-service Docker check. 6. cmd/install.go: parseWith validation accepts binary services. Each task ends with a commit; six commits to land on the branch.
Resolves a service name across both Docker and binary registries, returning a tagged union (Kind, BinaryService, Service, error). Binary wins on a hypothetical collision — matching the order used by the service:* command dispatcher's private resolveKind helper. Closes the gap that left several callsites only consulting the Docker registry and silently mishandling binary services (s3, mail). Per-callsite fixes follow in subsequent commits.
Extracts buildServiceOptions() so the wizard's service multi-select includes both Docker and binary services (mail, s3). The post-wizard provisioning loop now branches on kind and calls service:add with the appropriate arg form for each kind — the binary branch uses the single-arg form which routes through resolveKind correctly. Fixes two of the six silent failures called out in the mailpit PR review.
Extracts an envVarsFor helper that resolves the service name via LookupAny and dispatches to the right EnvVars signature for each kind (BinaryService.EnvVars(projectName) vs Service.EnvVars(projectName, port)). Both call sites in envCmd now go through it, eliminating the duplicated branching and giving us a real test surface. Previously "pv service:env mail" hard-errored and "pv service:env" with no args printed "Skipping unknown service" for each registered binary service. Fixes two of the six silent failures from the mailpit PR review.
Doctor previously reported every registered binary service (mail, s3) as "unknown service type — registry may be out of date" because the loop fed every name through services.Lookup, which only consults the Docker registry. Binary services have first-class observability via pv service:list / pv service:status / pv service:logs; doctor's job is cross-cutting infra health, not per-binary-service supervision health. Fixes one of the six silent failures from the mailpit PR review.
parseWith now uses services.LookupAny, so --with=service[s3] and --with=service[mail] no longer falsely error as 'unknown service'. Validation behavior for genuinely unknown names is unchanged. Closes the last of the six silent failures from the mailpit PR review.
The pre-existing absence-of-error-strings checks only fire when Docker is reachable, because the lookup_error branch in cmd/doctor.go is gated behind `engine != nil`. In CI environments without Docker (or local runs without Colima), the test passed regardless of whether the fix in 6f19458 was applied — empirically verified by reverting the fix and seeing the test still pass. Add a positive assertion that the output does not suggest "pv service:start mail" — pre-fix code surfaces mail as a failing check with that Fix message even when engine is nil. Confirmed catches the regression: with the fix temporarily reverted, the test now FAILS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
services.Lookupand silently mishandled binary services (s3, mail).services.LookupAny(name) (Kind, BinaryService, Service, error)— using the same binary-first lookup-order convention as the privateresolveKinddispatcher.Bugs fixed
cmd/install.go:61(parseWith)pv install --with=service[mail]errors "unknown service"cmd/setup.go:70(wizard list)DisplayName()cmd/setup.go:251(post-wizard provisioning)RunAddcmd/doctor.go:621service:list/status/logs)internal/commands/service/env.go:45(loop)internal/commands/service/env.go:71(single)pv service:env mailhard-errorsMAIL_*keys correctlyOut of scope (deliberately deferred)
internal/commands/service/dispatch.go's privateresolveKindenforces an extra registry-collision invariant; collapsing it intoLookupAnywould weaken the dispatcher contract.internal/commands/service/stop.go'sapplyFallbacksToLinkedProjectsrewrites linked.envfor binary services even when supervised — different bug shape, separate follow-up PR.ReadyChecksum-type tightening,TestBuildSupervisorProcess_Mailpit, E2E.envinjection assertions — separate PRs.Test plan
go build ./...cleango vet ./...cleango test ./...— 30 packages pass, 0 failuresTestLookupAny_*(4),TestBuildServiceOptions_*(2),TestEnvVarsFor_*(3),TestDoctor_SkipsBinaryServices(1),TestParseWith_BinaryService*/_UnknownServiceMongodb(3), plus the Docker-less regression assertion in the doctor testTestDoctor_SkipsBinaryServicesto FAIL with "doctor output should not suggest restarting binary service mail"Design + plan docs
docs/superpowers/specs/2026-04-15-services-lookupany-design.mddocs/superpowers/plans/2026-04-15-services-lookupany.md