Merge worktree-route-hostnames (#151) — one claim writer, one wire contract
#151's internal/domains claim surface (AttachClaim/DetachClaim/ListClaims,
NormalizeAliasHost, HostDenied, ErrHostUnavailable) supersedes the interim
internal/domainclaim stub, and its /api/cli domains door + carlos domains
CLI pin the wire: POST /domains with a JSON body (200 {host,route,created}),
DELETE /domains/{host} (always-200 {host,removed}), GET rows carrying
status/dns_status/cert_expires_at. Resolved in their favour throughout:
- apimode.go: their apiDomainRecord/domainAttach/domainDetach/domainList
land; my apiDomain client is folded in — domainAttach grows optional
kind/channel body fields (deploy's first-route extras), domainList keeps
the domainListError status wrapper deploy's degrade paths read, and the
record shape gains the additive guidance field.
- internal/domainclaim is DELETED; the attach/detach core, Settings list
and every test now speak internal/domains. Same-owner re-attach is now
idempotent (their titogo contract) instead of a 409; the neutral refusal
is "hostname unavailable" everywhere; audit + serial gate on an actual
write (their changed rule).
- domainpolicy.go is DELETED: shape is NormalizeAliasHost, platform space
is HostDenied over deniedDomains() (origin + apps domain + redirect
hosts + CONSOLE_DENY_DOMAINS) — one validation spot, both doors.
- their POST handler gains the kind=static first-route branch: an app with
no ready route short-circuits route resolution into the shared
attachDomain core (claim + declared static provision record); route and
kind together are a 400. GET rows compute guidance exactly as the
Settings page does (domainGuidance, EdgeIPs).
- deploy.go / deploy_test.go adapt to the pinned wire (dns_status,
POST-body attach, 200-not-201, 'carlos domains list -app' wording).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
37 files changed,
+4366
−506
apimode.go+86 −49cmd/console/main.go+20 −0deploy.go+17 −17deploy_test.go+45 −38docs/superpowers/plans/2026-08-12-route-extra-hostnames.md+548 −0docs/superpowers/specs/2026-08-12-route-extra-hostnames-design.md+288 −0domains_cli.go+150 −0domains_cli_test.go+393 −0internal/console/apidomains.go+388 −0internal/console/apidomains_test.go+480 −0internal/console/appdomains_test.go+6 −6internal/console/appsettings.go+5 −2internal/console/authcli.go+9 −2internal/console/domainattach.go+101 −56internal/console/domainattach_test.go+70 −46internal/console/domainpolicy.go+0 −30internal/console/domainpolicy_test.go+0 −27internal/console/server.go+9 −0internal/console/view.go+1 −1internal/domainclaim/domainclaim.go+0 −96internal/domainclaim/domainclaim_test.go+0 −106internal/domains/aliases.go+74 −0internal/domains/aliases_test.go+245 −0internal/domains/claims.go+251 −0internal/domains/claims_test.go+256 −0internal/domains/reconcile.go+43 −10internal/domains/reconcile_test.go+77 −0internal/edge/alias_test.go+277 −0internal/edge/edge.go+35 −1internal/edge/storedoor.go+43 −7internal/edge/storedoor_test.go+20 −0internal/host/agent.go+21 −3internal/registry/registry.go+121 −3internal/registry/registry_test.go+186 −0internal/status/snapshot.go+59 −6internal/status/status_test.go+38 −0main.go+4 −0
apimode.goLoading diff…
cmd/console/main.goLoading diff…
deploy.goLoading diff…
deploy_test.goLoading diff…
docs/superpowers/plans/2026-08-12-route-extra-hostnames.mdLoading diff…
docs/superpowers/specs/2026-08-12-route-extra-hostnames-design.mdLoading diff…
domains_cli.goLoading diff…
domains_cli_test.goLoading diff…
internal/console/apidomains.goLoading diff…
internal/console/apidomains_test.goLoading diff…
internal/console/appdomains_test.goLoading diff…
internal/console/appsettings.goLoading diff…
internal/console/authcli.goLoading diff…
internal/console/domainattach.goLoading diff…
internal/console/domainattach_test.goLoading diff…
internal/console/domainpolicy.goLoading diff…
internal/console/domainpolicy_test.goLoading diff…
internal/console/server.goLoading diff…
internal/console/view.goLoading diff…
internal/domainclaim/domainclaim.goLoading diff…
internal/domainclaim/domainclaim_test.goLoading diff…
internal/domains/aliases.goLoading diff…
internal/domains/aliases_test.goLoading diff…
internal/domains/claims.goLoading diff…
internal/domains/claims_test.goLoading diff…
internal/domains/reconcile.goLoading diff…
internal/domains/reconcile_test.goLoading diff…
internal/edge/alias_test.goLoading diff…
internal/edge/edge.goLoading diff…
internal/edge/storedoor.goLoading diff…
internal/edge/storedoor_test.goLoading diff…
internal/host/agent.goLoading diff…
internal/registry/registry.goLoading diff…
internal/registry/registry_test.goLoading diff…
internal/status/snapshot.goLoading diff…
internal/status/status_test.goLoading diff…
main.goLoading diff…