Service Discovery & Edge Routing — runtime endpoint registry in Koder DNS, consumed by Koder Jet; Koder Gate reserved for public product APIs
Status
Draft — ratifies the /k-arch deliberation of 2026-06-08 (owner-approved via /k-go). This RFC fills a decision slot that until now existed only implicitly (id-RFC-008-api-gateway is the ID service's internal gateway, a different scope; there was no Stack-wide service-discovery decision on record).
Problem
The Koder Cloud has no runtime source of truth for where a service lives. Today a component finds another by one of three brittle means:
- Hardcoded URLs (
*.koder.dev) baked into binaries and apps. - Hardcoded container IPs / env vars (
10.0.1.128:7800,KODER_NOTIFY_URL=…). - A hand-edited static map:
meta/docs/stack/registries/koder-service-ports.toml(the port registry) +
infra/net/jet/sites.toml(205 vhosts, edited by hand,incus file push+ reload).
When the topology moves — every migration does (s.r1 → s.forge → s.khost1) — the hand-maintained routing drifts, and consumers break with no warning.
Concrete incident (the motivation). voice.koder.dev (the Dek app's shipped transcription backend) accumulated three layers of drift across migrations: a dev auth-gate swept it behind a browser-only approval (→ every mobile transcription 403, DEK-AUT-003), and the jet upstream target drifted across 177.93.107.3:7779 / 10.0.1.126:7803 / 10.0.1.128:7803 while the app hardcoded voice.koder.dev. Each was a manual config edit with no registry to reconcile against. A runtime registry + dynamic, health-aware routing makes "move a service" a re-registration, not a hand-edit-and-pray.
This is the root cause (architecture-quality D12 — fix the cause, not the symptom): the absence of a runtime endpoint source of truth + hand-edited routing.
Decision
Adopt the separation of two concerns that the current stack conflates:
| Concern | Plane | Owner (REUSE existing, do not add a server) |
|---|---|---|
| Service discovery — "where is service X right now?" | control-plane (source of truth) | Koder DNS (infra/net/dns) — already ships an SRV-based service registry (internal/discovery/registry.go) |
| Edge routing — TLS, proxy, auth, cache, rate-limit | data-plane | Koder Jet (infra/net/jet) — already the official, production edge (205 vhosts) |
| Registration + health contract | control-plane contract | Koder Mesh (infra/net/mesh, #002) — the registerheartbeathealth schema both sides honour |
Koder Gate (infra/net/gate) is explicitly NOT the internal router. It is a complete, well-designed but experimental, never-deployed API gateway. Deploying it as the internal data-plane would stand up a second edge overlapping Jet (TLSproxycache/auth duplicated) — an anti-pattern under reuse-first (D10) and a boundary violation (D2). Gate is reserved for its real use case: a public, product-grade API gateway (third-party API keys, quotas, monetization, developer portal) — a future need, not internal discovery.
Why this over the alternatives (the /k-arch rubric)
- vs. "deploy Koder Gate as central gateway" (rejected): duplicates Jet's edge
(D2