Skip to content

fix(orchestration): a module page's entry may be a Connect endpoint - #1246

Merged
antoinetoussaint-byte merged 1 commit into
mainfrom
fix/module-page-connect-entry
Oct 30, 2026
Merged

antoinetoussaint-byte merged 1 commit into
mainfrom
fix/module-page-connect-entry

Conversation

@antoinetoussaint-byte

@antoinetoussaint-byte antoinetoussaint-byte commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

The gap

A module or solution declares a page with solution.frontend.codefly.yaml beside its service-entry. componentBackendRoutes (pkg/orchestration/host_route_carriers.go) forwarded the component's /<alias>/ route only to one http or rest endpoint of that entry. A module whose backend is gRPC + Connect — the platform's standard since REST was deprecated — could therefore not own a page: every composition with a host gateway refused it ("declares no http or rest endpoint").

Real case: obin-ai/module-directory modules/org-directory/services/directory declares grpc and connect. Its page, services/fe-remote (a Module Federation remote exposing ./Page), calls the backend through the host's module proxy /v1/<alias>. Declaring the page was blocked on this (obin-ai/module-directory#13).

The fix

pageEntryEndpoint selects the page's entry endpoint:

  • exactly one http, rest or connect endpoint → that one. Connect is HTTP (HTTP/1.1 + JSON) on its own listener, so the carrier routes the page's calls to it exactly as to an HTTP endpoint;
  • exactly one rest beside exactly one connect → connect, stated in the doc comment (REST is deprecated; Connect serves the same API);
  • anything else (none, several of one kind, http beside connect) → still refused, and the message now names every endpoint the entry declares with its kind, e.g. declares no http, rest or connect endpoint (it declares: grpc (grpc)).

Nothing else moves: the carrier, the mesh edges and the cell's consumer edges all read the same derivation (HostRouteTargets), so a Connect entry gets its carrier, its gateway mesh edge and its cell consumer edge from the existing code. docs/commands.md states the rule.

Reuse. The existing route derivation, carrier rendering (hostRouteCarrier) and standards.CONNECT; no new mechanism. Deliberately not done: routing a module page through the host's moduleApiBase instead (a second path for a job the backend route already does).

Tests

  • TestModulePageGetsACarrierWithoutASolutionConsumer now runs an http and a grpc + connect module page, in snapshot and run mode; the Connect case gets the …__CONNECT carrier. Against the old selection rule the Connect cases fail with declares no http or rest endpoint (checked).
  • TestAPageEntryIsOneHTTPRestOrConnectEndpoint: grpc+connect → connect; rest+connect → connect; grpc only, nothing, two connect, http+connect → refused, naming the endpoints.
  • TestASolutionBackendIsOneHTTPEndpointOfItsEntry: the refusal messages updated.
  • GOWORK=off go test ./pkg/orchestration/... ./pkg/gitops/... passes; go build ./..., go vet ./pkg/orchestration/, golangci-lint run ./pkg/orchestration/ (0 issues).

End-to-end proof

On the real case: obin-ai/module-directory feat/module-page-declared with service-entry: directory and services/directory/solution.frontend.codefly.yaml (obin-ai/module-directory#13), composed into platform-obin (a detached worktree of the po checkout at 6cfc960f, with codefly.local.yaml resolving org-directory to that checkout). The composition was loaded exactly as deploy gitops render loads it (common.ResolvePinnedModules, common.LoadWorkspace), and the host gateway's routes were derived by orchestration.HostRouteTargets. The render's carriers, mesh edges and cell consumer edges all read that derivation. The probe was a throwaway program and is not committed.

CLI env blue env local
main 7c237690 (v0.1.227) REFUSED: component org-directory's entry service directory declares no http or rest endpoint; the host forwards /org-directory/ to one same refusal
this branch /org-directory/ -> org-directory/directory/connect, beside /wiki/, /proposals/ and /robin-builder/ -> …/backend/http same

What I did not verify:

  • A full deploy gitops render org-directory --env blue. It builds and pushes the directory image and publishes the page bundle to the blue registry, and that registry was out of bounds for this change.
  • A full render with --env local. It reached the image builds and stopped on an unrelated image: authority/local at the pinned authority has a relative replace ../../../../../libraries/authority-core/go, which does not exist inside the build context. That happens before route derivation.
  • The host gateway at runtime. I did not check that it serves the page's /v1/org-directory calls from the Connect carrier: no composed run was started.

Classification

Fix at the owning place: the CLI owns the host route derivation; the refusal was the CLI's rule, not the module's.

🤖 Generated with Claude Code

componentBackendRoutes forwarded a component's /<alias>/ route only to one
http or rest endpoint of its service-entry, so a module whose backend is
gRPC + Connect (the platform's standard) could not declare a page: every
composition with a host gateway refused it. Connect is HTTP on its own
listener, so the host forwards a page's calls to it exactly as to an HTTP
endpoint. pageEntryEndpoint now selects the one http, rest or connect
endpoint; one rest beside one connect goes to connect (REST is deprecated);
none or several is still refused, naming the endpoints the entry declares.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 8b28ac3 Oct 30, 2026
20 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