Skip to content

The default-project slot has 3 production readers, 0 production registrants — and 6 comments name a registrant function that exists in neither repo #5958

Description

@os-zhuang

Found while sweeping the REST composition root for #4251 (B4, PR #5953). Typing that file's lookup meant establishing what occupies the slot — and nothing does.

Evidence

Three production readers, all resolving the literal 'default-project':

packages/rest/src/rest-api-plugin.ts        defaultEnvironmentIdProvider() → dp?.environmentId
packages/runtime/src/http-dispatcher.ts:618 resolveDefaultProject() → memoized for the process
../cloud objectos-runtime/src/kernel-resolver.ts:193  resolution level 6

Zero production registrants. In objectstack, grep -rn "registerService(\s*['\"]default" over packages/ returns nothing, and the only occurrences of the string at all are the three readers plus comments. In cloud, the only occurrence is a test stub (objectos-runtime/src/kernel-resolver.test.ts:143, getService: (n) => n === 'default-project' ? { environmentId: 'proj_local' } : undefined).

Six comments name the registrant, and it does not exist. createSingleEnvironmentPlugin is referenced as the thing that registers this slot in:

packages/rest/src/rest-server.ts:1796
packages/rest/src/rest-server.ts:1877
packages/rest/src/rest-api-plugin.ts:146
packages/runtime/src/http-dispatcher.ts:252
packages/runtime/src/http-dispatcher.ts:614   ([#5155])
packages/runtime/src/domain-handler-registry.ts:213

grep -rn "createSingleEnvironmentPlugin" over both repos returns only those comments — no declaration, no export, no call. Same for the cloud checkout.

Why this is observation-class and not a live outage

Every reader has a working fallback and degrades by design:

  • rest-api-plugin's provider is wrapped in try/catch returning undefined; RestServer then falls through its hostname/header chain.
  • http-dispatcher.resolveDefaultProject() catches with the comment "service not registered — single-environment plugin not in stack".
  • kernel-resolver's level 6 is the last of six, and its own comment already hedges ("may register a default-project service for the lone env").

So nothing a user hits today — single-environment local dev works, because other resolution levels cover it. What is dormant is the "single-environment default" resolution level itself: it is documented in a resolution chain, referenced by #5155, and can never fire. That makes it the ADR-0049 declared-but-unenforced shape, one layer up from a metadata key: a capability advertised in six places that the composition cannot deliver, kept plausible by the comments naming a plausible-sounding provider.

It is also the exact input that makes an agent reason confidently from dead code — the hazard "One route, one owner" in AGENTS.md is written about, and the same shape as the IHttpServer dead shadow (#4393) and the false http.server exemption, both from this work line: the file being read never says the thing it names is gone.

Two ways to close it, opposite directions

  1. The plugin should existcreateSingleEnvironmentPlugin was planned or removed, and single-environment hosts genuinely want bare /api/v1/data/... to route into the lone environment's kernel without a hostname. Then write it, register the slot, and the three readers start working as documented. Worth checking HttpDispatcher 把「本请求解析出的 kernel」存在实例字段上(this.kernel),多租户 host 上并发请求会互相串改 #5155's history first: it may have been dropped deliberately when the per-request kernel landed.
  2. The slot should go — the other five resolution levels are sufficient and this level is speculative surface. Then delete the three reads and the six comments, per enforce-or-remove. Note the readers are cheap but not free: http-dispatcher memoizes the answer for the process lifetime.

I did not guess between them: PR #5953 only names the field its own file reads ({ environmentId: string }, a narrow slice of the fuller { environmentId, orgId? } that runtime declares) and changes no behaviour. Filed unassigned.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions