LearnNewsExamplesServices
Frontmatter
id15323
titleinstallFleetBridge hardcodes its endpoint, forcing every Fleet E2E witness to squat the dev fleet server''s port
stateOpen
labels
enhancementaitesting
assigneesneo-gpt-emmy
createdAt1:24 AM
updatedAt4:02 AM
githubUrlhttps://github.com/neomjs/neo/issues/15323
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]

installFleetBridge hardcodes its endpoint, forcing every Fleet E2E witness to squat the dev fleet server's port

Open Backlog/active-chunk-6 enhancementaitesting
neo-opus-ada
neo-opus-ada commented on 1:24 AM

Context

Surfaced while running a reviewer falsifier on PR #15318 (native Fleet drill witnesses). Not that PR's defect — #15212 explicitly forbids touching production, so the author took the only option available. The friction is in production and it constrains every Fleet E2E witness.

The Problem

installFleetBridge() hardcodes its endpoint with no runtime override, and the app calls it with no arguments:

// apps/agentos/app.mjs:7
installFleetBridge();

// src/ai/fleet/installFleetBridge.mjs:21
export function installFleetBridge({url = 'http://127.0.0.1:8083/fleet', fetchImpl = globalThis.fetch, target = globalThis} = {}) {

The opts.url seam exists but nothing reaches it — no env read, no config leaf, no call-site argument. So any E2E witness needing a test-owned Fleet bridge must squat the exact port the app dials, which is also devFleetServer's default:

// ai/services/fleet/devFleetServer.mjs:32
const port = Number(process.env.NEO_FLEET_PORT) || 8083;

FleetGridKeyboardA11y.spec.mjs therefore hardcodes startFleetBridgeServer({port: 8083}).

The sharpest tell: fleetBridgeServer.mjs:19 advertises an affordance no consumer can use —

@param {Number} [opts.port=8083]0 selects an ephemeral port (tests).

The module offers ephemeral-port binding for tests, and the test cannot use it, because the dial target is fixed at the consumer.

Consequences (verified, not assumed):

  • No false-green risk. playwright.config.e2e.mjs sets workers: 1, fullyParallel: false, so no intra-run collision; an occupied port throws EADDRINUSE in beforeEach — fail-loud.
  • But the witness cannot run in a standard dev environment. Anyone with devFleetServer up (the normal setup) gets an opaque bind error — precisely when they most want to run the Fleet witnesses.
  • devFleetServer honors NEO_FLEET_PORT, so the server side is already configurable. The client side is not. The asymmetry is the bug: one half of the transport reads an env var, the other half ignores it.

The Architectural Reality

  • src/ai/fleet/installFleetBridge.mjs:21url default, injectable in signature, never injected.
  • apps/agentos/app.mjs:7 — the only production call site, zero args.
  • ai/services/fleet/devFleetServer.mjs:32 — server honors NEO_FLEET_PORT, defaults 8083.
  • ai/services/fleet/fleetBridgeServer.mjs:19,25 — documents port: 0 as the test affordance.
  • test/playwright/e2e/agentos/FleetGridKeyboardA11y.spec.mjs — forced to port: 8083.

This is App-Worker code (src/), so the endpoint cannot simply read process.env; the resolution has to reach the worker through whatever the established seam is (build-time config, Neo.config, or an explicit call-site argument from app.mjs). That choice is the substance of this ticket and should not be guessed — ADR-0019's require+inject+fail-loud discipline is the nearest governing precedent, and a hidden default is exactly what it forbids.

The Fix

Give the client half a real resolution path so a test can point the app at its own loopback:

  1. Resolve the fleet endpoint at the app.mjs call site rather than defaulting inside installFleetBridge, so the default is visible at one place instead of buried in a parameter.
  2. Let an E2E harness override it (ephemeral port → app dials it), making fleetBridgeServer's documented port: 0 reachable.
  3. Then drop the hardcoded 8083 in FleetGridKeyboardA11y.spec.mjs.

Explicitly not proposed: a defensive ?. or a second hidden default. If the endpoint cannot be resolved, fail loud.

Acceptance Criteria

  • A Fleet E2E witness can bind an ephemeral port and have the app dial it — verified by running the witness with devFleetServer occupying 8083 and seeing it pass.
  • FleetGridKeyboardA11y.spec.mjs no longer hardcodes 8083.
  • No hidden default: an unresolvable endpoint fails loud rather than silently dialing a fallback.
  • installFleetBridge's JSDoc stops advertising an opts.url seam that no call site exercises, or the seam becomes genuinely exercised.
  • Existing Fleet witnesses stay green (PR #15318's two specs are the regression set).

Out of Scope

  • The witnesses themselves (PR #15318 — approved, merge-eligible).
  • Fleet lifecycle/product semantics.
  • Hosted-CI E2E coverage (the separate and larger question #15212 surfaced: these witnesses are not hosted-CI gated at all).

Avoided Traps

  • Blaming PR #15318. The hardcode is forced by production; the author had no legal alternative under AC-4.
  • Reading process.env inside src/. App-Worker code cannot; the seam must be a real injection, not an env peek.
  • Adding a second default to paper over the first. The defect IS the unreachable default.

Related

  • PR #15318 / #15212 — where this surfaced (reviewer falsifier).
  • #14619 / PR #15094 — the native-button convergence these witnesses guard.

Live latest-open sweep: latest open issues checked 2026-07-16 ~23:30Z; searched installFleetBridge port 8083 and fleet bridge ephemeral port test across open+closed — no equivalent found.

Retrieval Hint: installFleetBridge hardcoded 8083 endpoint no override fleet E2E squat devFleetServer ephemeral port

Origin Session ID: ad475320-6bdc-4555-ba3f-b78d51de0b17