Skip to content

chore(sync): develop → main — cross-cluster address for the three surfaces - #418

Merged
beyondnetPeru merged 1 commit into
mainfrom
develop
Aug 4, 2026
Merged

chore(sync): develop → main — cross-cluster address for the three surfaces#418
beyondnetPeru merged 1 commit into
mainfrom
develop

Conversation

@beyondnetPeru

Copy link
Copy Markdown
Contributor

Brings #417 to main: pinned node ports for core-api (30080), mcp (30081) and agent-runtime (30082), a kind config that maps all three, and local-test.sh url proving both the host and the cross-cluster path.

Scope, stated plainly: this is a TRANSPORT proof. It shows a pod in a second kind cluster can GET /health on all three surfaces, and that the addresses survive a rollout. No Tracker was deployed, no product endpoint was called, and no robot suite was run.

🤖 Generated with Claude Code

…e surfaces (#417)

* feat(infra): give the Core a stable address other clusters can hold

Core and Tracker are separate products in separate repositories that talk
over HTTP, so validating them in ONE cluster would hand them in-cluster
DNS and hide the defects that only appear across a network boundary. Two
clusters is the honest topology and already the de-facto one — the
Tracker's manifest deploys into its own `evolith-tracker` cluster.

What was missing was the link. Everything was reached with
`kubectl port-forward`, which is right inside one cluster and wrong
between two: it is a host process nothing in another cluster can point
at, and it dies on every rollout of the target — so redeploying the Core
breaks the Tracker and the symptom looks like a Tracker defect.

There are TWO addresses now, and they are not interchangeable:

  FROM ANOTHER CLUSTER  http://<cluster>-control-plane:30080
  FROM THIS MACHINE     http://localhost:30080

The cross-cluster one does not use the host mapping at all. Every kind
cluster joins the same `kind` Docker network, so the consumer's pod
reaches the node container by name and hits the NodePort directly. The
host mapping serves the other consumer — browser, curl, CLI — and is
bound to 127.0.0.1, which is also precisely why it cannot serve the first
case.

`host.docker.internal` was the first thing written here and it is WRONG:
it fails with `Could not resolve host` inside a kind pod, which resolves
through CoreDNS in the node and never sees the Docker Desktop entry. The
comments say so, because the wrong URL is the plausible one.

Measured on a throwaway pair of clusters with the real core-api image,
then torn down: a pod in a second cluster got `{"status":"OK"}` by name
and by IP, the host port answered, and both survived `rollout restart`.

`local-test.sh url` proves BOTH paths on demand rather than asserting
them — they fail independently, so one check would cover for the other.
It picks a RUNNING peer: the first version picked a stopped cluster,
reported the network as broken, and the real cause was a node container
dead for two days.

The port mapping is fixed at cluster creation and cannot be added later,
so `kind_create` says when the existing cluster predates the config
instead of leaving a port that was never bound to be discovered by a
refused connection.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(infra): extend the stable address to all three surfaces, and fix the probe three times

"Evolith Core and its interfaces" is REST, MCP and the agent runtime. The
first version gave a stable address to core-api alone, which would have
let a consumer reach one surface of three while the docs implied parity —
so mcp (30081) and agent-runtime (30082) now carry pinned node ports too,
and the kind config maps all three.

The probe that proves it needed fixing three times, each a different way
of reporting a defect that was not there:

  - it picked a STOPPED peer cluster, failed, and blamed the Docker
    network; the node container had been dead for two days;
  - it matched `"status":"OK"` literally, so mcp and agent-runtime — which
    answer with a bare `"status":"ok"` rather than the ADR-0073 envelope
    core-api uses — were reported unreachable while serving fine;
  - it used `kubectl run -i --rm`, which attaches AFTER creating the pod
    and loses the stdout of a container that already exited. Two
    consecutive runs disagreed about which surface was reachable.

All three are pinned in the comments, because each produced a confident
red that pointed at the wrong layer.

Measured, not asserted: three clean clusters' worth of runs with the real
images. Three consecutive `url` invocations agreed 3/3 on both paths, and
all six checks held after `rollout restart` of all three deployments.
Test clusters torn down; `evolith-cluster` untouched (it has been stopped
for 47h, exit 137).

Worth a look separately: the three surfaces disagree on the /health
shape. core-api returns the ADR-0073 envelope, the other two a bare
object. Not changed here — that is a contract question, not an infra one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@beyondnetPeru
beyondnetPeru requested a review from a team as a code owner August 4, 2026 03:23
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

📊 Bilingual Coverage Impact

PR Changes

  • Paired EN/ES files modified: 0
  • New EN files needing ES translation: 0

Repository Coverage

Metric Value
Total EN files 526
Total ES files 500
Paired files 0
Coverage 0%

Good: All EN changes have ES counterparts.


Generated by GitHub Actions

@beyondnetPeru
beyondnetPeru merged commit f6901a2 into main Aug 4, 2026
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant