LearnNewsExamplesServices
Frontmatter
id16949
titleThe bridge''s residency allowlist can name a service it never observes, so providerResidency and providerActivity report null forever
stateClosed
labels
bugai
assigneesneo-opus-ada
createdAtAug 11, 2026, 10:27 AM
updatedAtAug 11, 2026, 5:11 PM
githubUrlhttps://github.com/neomjs/neo/issues/16949
authorneo-opus-ada
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 11, 2026, 5:11 PM

The bridge's residency allowlist can name a service it never observes, so providerResidency and providerActivity report null forever

neo-opus-ada
neo-opus-ada commented on Aug 11, 2026, 10:27 AM

Context

Found while attacking the residency question on the #16706 escalation. It is not that escalation's cause — @neo-opus-vega measured that plane's compose and @neo-opus-grace ran the discriminator on that plane's snapshot; there the intersection is non-empty, residency populates, and the real defect turned out to be #16948. This is a distinct defect measured on our own plane, filed so it stops being rediscovered.

Distinct from #16859, which concerns residencyDisposition in the TextEmbeddingService → VectorService → IngestionService chain — a different subsystem that shares only the word residency.

The Problem

A residency allowlist naming a service the bridge never enumerates is a control that cannot fire, and it is indistinguishable from a healthy null.

DeploymentStateBridgeService.collectServiceSnapshot() iterates getServiceKeys() — the allowedServices leaf. isProviderResidencyServiceKey() is therefore only ever evaluated against an already-enumerated key. When a configured residency key is outside allowedServices, the predicate can never return true for that key, so it contributes nothing while any enumerated peer keeps observing normally — the effect is per key. Only a zero intersection, where no configured key is enumerated, makes collectProviderResidency() return null on every service, on every snapshot, forever.

Measured on this plane with local-model running and healthy for 22h:

NEO_DEPLOYMENT_STATE_BRIDGE_ALLOWED_SERVICES : chroma,kb-server,mc-server,fleet-server,orchestrator
providerResidencyServiceKeys (leaf default)  : ['local-model','model']
running containers                           : …, local-model, ingress
enumerated                                   : chroma, kb-server, mc-server, fleet-server, orchestrator
intersection                                 : EMPTY

ai/deploy/docker-compose.local-agent-os.yml:68-69 is how it happened — a YAML anchor binds the bridge's observation set to the orchestrator's runtime-access set:

NEO_ORCHESTRATOR_RUNTIME_ACCESS_ALLOWED_SERVICES: &local-runtime-services chroma,kb-server,mc-server,fleet-server,orchestrator
NEO_DEPLOYMENT_STATE_BRIDGE_ALLOWED_SERVICES: *local-runtime-services

Corrected 2026-08-11: the alias is deliberate, not accidental. A comment directly above it reads "This profile uses host LM Studio, not the optional local-model container. Monitor only the Compose services it actually starts." The base docker-compose.yml:433 sets the runtime-access list including local-model; this profile intentionally narrows it. The alias is therefore not the defect — it is one deployment correctly expressing that a container is out of its scope, which makes the misleading null a permanent steady state rather than a misconfiguration anyone would fix.

providerActivity dies on the same gate. Its JSDoc states the pairing exists "so a configured service can never receive one half of the residual-load evidence pair without the other." Under this misconfiguration it receives neither half — and both report null, the same value a correctly-configured non-model container reports.

Why the null is unreadable

Three defects compound so a reader cannot tell a disabled instrument from a working one:

  1. The discriminator is computed and discarded. providerResidencyEligible: this.isProviderResidencyServiceKey(serviceKey) is passed into ContainerHealthDiagnosisService.diagnose() (DeploymentStateBridgeService.mjs:642) and never emitted. A scalar-path census of a real snapshot finds the only providerResidency* paths anywhere are bridgeDiagnostics.bridgeConfig.providerResidencyServiceKeys.*.
  2. A branch that looks dead advertises a second meaning the SHIPPED probe cannot produce. if (!result) return null in collectProviderResidency is unreachable: probeProviderParallelModelCapacity has five exit paths — three throw new TypeError, two object literals — and cannot return falsy. Even the degenerate case returns {ready:true, skipped:true, reason:'missing-host'|'unsupported-provider'}. A probe failure surfaces as probeFailed:true, never null.
  3. Nothing validates the subset relation at config time, so the misconfiguration is silent for the life of the deployment.

Blast radius is diagnostic, not runtime — no request path changes. The cost is that provider-load questions become unanswerable exactly when someone is asking them, which is what happened here: three maintainers spent a morning on it and each attached a real finding to a subject they had not measured.

The Architectural Reality

  • ai/daemons/orchestrator/services/DeploymentStateBridgeService.mjsgetServiceKeys() (enumeration), isProviderResidencyServiceKey() (:820), collectProviderResidency() (:777), the discarded flag (:642).
  • ai/configBase.mjs:1247 allowedServices, :1252 providerResidencyServiceKeys — the two leaves whose relation is never checked.
  • ai/services/graph/providerReadinessHelper.mjs:2374 probeProviderParallelModelCapacity — the producer whose total return surface makes that branch unreachable for the shipped path (an injected test double can still return null).
  • ai/deploy/docker-compose.local-agent-os.yml:68-69 — the alias.

No new file or service boundary. The existing bridge owns all of it.

Amended 2026-08-11 after @neo-gpt's RC on PR #16958. Fix 4 and two ACs are withdrawn — the Compose alias they targeted is deliberate and documented. The defect restated correctly is not "the alias is wrong": it is that the bridge accepts a residency allowlist outside its observation set and reports null forever, with no way for a reader to tell that from a working instrument — and on a profile that excludes deliberately, that misleading null is the permanent steady state rather than a misconfiguration anyone eventually fixes. The diagnostic slice is the whole fix.

The Fix

  1. Refuse or warn at config time when providerResidencyServiceKeys ⊄ allowedServices, naming the unobservable keys. A residency allowlist the bridge cannot evaluate is a misconfiguration, not a preference.
  2. Emit providerResidencyEligible on the service record so null is readable from the artifact alone.
  3. Delete the dead if (!result) return null, so null has exactly one meaning: not eligible. AMENDED — the guard is RETAINED. It is unreachable for the shipped probe but reachable through the injectable seam: the spec's own default is providerResidencyProbe = async () => null, and without the guard a null probe spreads into {...null, targetIdentity} and emits a degenerate record claiming an observation nobody made. Deliver the readability instead — a comment stating which meaning is reachable where — which is what providerResidencyEligible on the record exists to separate.
  4. Give NEO_DEPLOYMENT_STATE_BRIDGE_ALLOWED_SERVICES its own list including local-model, rather than aliasing the runtime-access anchor. WITHDRAWN — invalid premise. docker-compose.local-agent-os.yml:66-67 carries a comment directly above the anchor: "This profile uses host LM Studio, not the optional local-model container. Monitor only the Compose services it actually starts." The alias is deliberate, not accidental DRY, and adding local-model would make the bridge watch a container this profile excludes on purpose. I filed this prescription without reading the two lines above the anchor I cited.

Acceptance Criteria

  • A config whose residency keys are not a subset of allowedServices produces a named diagnostic that identifies the unobservable keys; a spec asserts it, and asserts a valid subset stays silent.
  • providerResidencyEligible is present on every emitted service record, and a spec reads it from the produced snapshot rather than from the call arguments — the emission is the claim, and the absence of that check is what made this unreadable.
  • Mutation control: deleting the subset validation reddens the first AC; deleting the emission reddens the second.
  • An enumerated residency key yields a non-null providerResidency on that entry — the positive control that the pair is live. (Amended: provable at unit level; does not require the withdrawn compose edit.)
  • providerActivity is asserted alongside it, since it shares the gate and its JSDoc promises they travel together.
  • A partial-overlap control: with some configured keys enumerated and some not, the diagnostic names only the unobservable ones while the enumerated peer keeps observing. The effect is per key — only a zero intersection silences the pair across every service.
  • The two compose lists no longer share a YAML anchor, and a comment states why they must not. WITHDRAWN with fix 4 above — the anchor is intentional.

Out of Scope

  • #16948 (:latest canonicalization) — the actual #16706 root cause, owned by @neo-opus-grace.
  • Any change to what the residency probe measures. This is about whether it is ever asked.
  • #16859's residencyDisposition chain — different subsystem, shared word.

Avoided Traps

  • Widening allowedServices alone. That fixes one plane and leaves the silent-disjoint class intact for the next deployment that narrows it.
  • Making null mean "ineligible" by documentation. It already does mean that; the defect is that a reader cannot see it. Documentation does not reach the artifact.
  • Removing the residency keys leaf and deriving from allowedServices. Not every observed service is a provider host, so the two lists are legitimately different — collapsing them would make the bridge probe residency on containers that have no provider. (Amended: this trap stands on its own; it is NOT evidence that any particular profile's alias is wrong. A profile that deliberately narrows its observation set is expressing scope, not making a mistake.)

Authored by Ada (Claude Opus 5, Claude Code). Session 87f453f9-aa80-4487-9ed1-b5d91e052c43.

tobiu referenced in commit 9e241e5 - "fix(bridge): a residency allowlist the bridge never enumerates is now visible, not silently inert (#16949) (#16958) on Aug 11, 2026, 5:11 PM
tobiu closed this issue on Aug 11, 2026, 5:11 PM