Skip to content

[finding] GET /meta/app/NAME answers 200 with an item-less envelope for a nonexistent name — the spec declares item required and the rest pin declares a 404 #18066

Description

@os-tesla

Measured while implementing objectstack-ai/objectui#9262 (the console's by-name app probe),
on a real server: objectstack commit 60b9955, examples/app-showcase,
objectstack dev --seed-admin --fresh -p 4262, API 17.4.0, authenticated as the seeded admin.

The reading

GET /api/v1/meta/app/NAME for a name with nothing behind it answers 200 with the
declared envelope MINUS its item member — it does not answer 404 RESOURCE_NOT_FOUND.

GET /api/v1/meta/app/no_such_app_xyz
200 {"type":"app","name":"no_such_app_xyz","lock":"none","editable":true,"deletable":true,"resettable":false}

GET /api/v1/meta/app/showcase_app        (the one app in this session's list)
200 {"type":"app","name":"showcase_app","item":{...},"lock":"none",...}

Four names measured; every absent one behaved identically. The response carries lock, so
it came from the UNCACHED arm of the route — the app types are diverted there and the RBAC
gate did run.

Why it looks like a divergence from this repo's own declaration

Two declarations say absence is an error, not an item-less success:

  1. GetMetaItemResponseSchema (packages/spec/src/api/protocol.zod.ts) declares the
    response as z.object({ type, name, item, ... }) with item a REQUIRED member. The
    envelope above omits it.
  2. packages/rest/src/meta-app-publish-gate.test.ts, in the case titled
    "criterion 3: ...and the real producer miss is still the 404 it has always been",
    states it in as many words: "The fixture's getMetaItem answers undefined for an
    unknown name; metadata-protocol REJECTS with a declared RESOURCE_NOT_FOUND /
    status: 404"
    . That case passes because its fixture REJECTS. The live objectql
    provider RESOLVES with the item-less envelope instead, so the pin and the server do not
    describe the same behaviour.

Mechanism, read off packages/rest/src/rest-server.ts: the 403 PERMISSION_DENIED and
the 404 RESOURCE_NOT_FOUND both sit inside if (isAppType && visible), where visible
is the document. For a name that resolves to nothing visible is undefined, the whole gate
is skipped, and the envelope falls through to res.json. So the 404 branch is reachable
only for an app that EXISTS and is withheld for a NON-permission reason (unpublished, or
gated by an absent optional service).

Why it mattered downstream

ObjectStackDataSource.probeAppAccess in objectui returned granted whenever the call did
not throw, so it reported granted for every nonexistent app. That console-side reading is
being corrected on objectstack-ai/objectui#9262 — it now reads the envelope and treats both
dialects as absence — so nothing downstream is blocked on this card. It is filed because
the platform's declared contract and its live behaviour disagree, which is a decision for
this repo rather than something a consumer should quietly absorb.

Not measured, deliberately left open

  • Whether the item-less 200 is intended (Studio's create-vs-edit probe may want exactly
    this descriptor for a name that does not yet exist) or a provider-level miss. That is the
    decision this card asks for, and it is why no fix is proposed here.
  • Whether other metadata types behave the same way. Only app was measured.
  • Whether the cached arm behaves the same way. The app reads observed here all took the
    uncached arm.

Filed by the objectui os-dev seat while implementing objectstack-ai/objectui#9262,
generated with Claude Code, session session_011QreXiyMEqKLN4U5daMPVa.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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