Observed (live dev server, showcase, admin + members)
GET /api/v1/me/apps → {"apps":[]} for EVERY authenticated principal, including the platform admin — while the console's app switcher (which uses the registry-backed meta routes) correctly shows Showcase/Setup.
Root cause
packages/plugins/plugin-hono-server/src/hono-plugin.ts:838 — the handler lists apps via the metadata service:
const all: any[] = (await metadata.list('app')) ?? [];
but stack-declared apps are registered into the ENGINE REGISTRY by the runtime AppPlugin (packages/runtime/src/app-plugin.ts — registerApp(); see the comment at :307 "The engine already indexed them for the write gate via registerApp()"). MetadataManager.list('app') has no such items → always [].
Why it matters
/me/apps is the ONLY enforced consumer of two authorization surfaces:
PermissionSet.tabPermissions (merged hidden/visible votes — filters tabs[app.name] === 'hidden'),
AppSchema.requiredPermissions ⊆ caller's systemPermissions.
With the endpoint dead, both surfaces are declared-but-unenforced (ADR-0049 enforce-or-remove): a set voting an app hidden and an app requiring setup.access change nothing anywhere reachable.
Fix direction
Read the app list from the same authoritative source the meta routes use (engine registry), or mirror registry apps into the metadata service; keep the existing tabPermissions/requiredPermissions filtering. Add a dogfood asserting a fresh member sees the showcase app and that a requiredPermissions: ['setup.access'] app appears only for holders.
Found while browser-verifying the ADR-0090 permission zoo (#2739/#2745).
Observed (live dev server, showcase, admin + members)
GET /api/v1/me/apps→{"apps":[]}for EVERY authenticated principal, including the platform admin — while the console's app switcher (which uses the registry-backed meta routes) correctly shows Showcase/Setup.Root cause
packages/plugins/plugin-hono-server/src/hono-plugin.ts:838— the handler lists apps via the metadata service:but stack-declared apps are registered into the ENGINE REGISTRY by the runtime AppPlugin (
packages/runtime/src/app-plugin.ts—registerApp(); see the comment at :307 "The engine already indexed them for the write gate via registerApp()").MetadataManager.list('app')has no such items → always[].Why it matters
/me/appsis the ONLY enforced consumer of two authorization surfaces:PermissionSet.tabPermissions(merged hidden/visible votes — filterstabs[app.name] === 'hidden'),AppSchema.requiredPermissions⊆ caller's systemPermissions.With the endpoint dead, both surfaces are declared-but-unenforced (ADR-0049 enforce-or-remove): a set voting an app
hiddenand an app requiringsetup.accesschange nothing anywhere reachable.Fix direction
Read the app list from the same authoritative source the meta routes use (engine registry), or mirror registry apps into the metadata service; keep the existing tabPermissions/requiredPermissions filtering. Add a dogfood asserting a fresh member sees the showcase app and that a
requiredPermissions: ['setup.access']app appears only for holders.Found while browser-verifying the ADR-0090 permission zoo (#2739/#2745).