Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

API Console never renders the Storage group on any host — the catalog key is storage while /discovery names the slot file-storage, so the fail-closed branch hides 3 endpoints #4240

Closed

Description

@os-zhuang

Provenance: moved from objectstack-ai/objectstack#7564 by the triage seat (file-at-destination, objectstack-ai/objectstack#7165 rule 1 / #7167 recreate shape — transfer API unavailable to this credential). Original filed by the QA extraction from run objectstack-ai/objectstack#7463 (framework a86db175). Original text follows, refs rewritten to full form.

Symptom

The API Console page (developer:api-console, Studio → Developer → API Console) renders no Storage group at all — on any host, whether or not a storage service is registered and healthy.

Three endpoints are consequently unreachable from that page:

method path description
POST /api/v1/storage/upload Upload file (multipart/form-data)
GET /api/v1/storage/:fileId Download file
DELETE /api/v1/storage/:fileId Delete file

Expected: the Storage group renders wherever the storage slot is filled and usable, exactly like the other service-gated groups (the rest of the QA item passed — the tree matched /discovery 10/10 and executed real 200/404/400 calls).

Root cause

Located — a name mismatch across the two sides of one lookup:

  • this repo's catalog declares the group under the key storage (apps/console/src/pages/developer/hooks/useApiDiscovery.ts, SERVICE_ENDPOINT_CATALOG — key at :208 on current main);
  • /discovery reports the service under its canonical slot name file-storage (framework packages/spec/src/system/core-services.zod.ts:27 lists 'file-storage' as the storage-driver slot, mapped to @objectstack/service-storage at :90);
  • the render loop looks the catalog key up directly in the discovery payload — const serviceInfo = discoveredServices[serviceName] — so it always misses, and the next line is the fail-closed branch: const usable = serviceInfo ? isServiceUsable(serviceInfo) : false; ("no entry → no endpoint group").

The fail-closed posture is correct and deliberate (ADR-0076 D12); it is the key that is wrong. The framework side is canonical — file-storage is the declared slot name — so the fix is the console catalog key in this repo, not /discovery.

Reproduction

  1. Boot showcase (or any host with the storage service registered) and open Studio → Developer → API Console.
  2. Wait for discovery to resolve; enumerate the rendered endpoint groups.
  3. Observe: no Storage group, on every host tried.
  4. Confirm the service is really there: GET /api/v1/discovery reports the slot under the name file-storage, not storage.

Triage verification (2026-08-11, objectui origin/main @ 5e2e9fa)

  • useApiDiscovery.ts:208 key is storage (with defaultRoute: '/api/v1/storage' at :210) — present;
  • git grep file-storage -- apps/console → 0 hits (counter-probed);
  • framework slot name verified at core-services.zod.ts:27/:90/:212 on objectstack origin/main @ 34c01a5.

Activity

  1. self-assigned this
    on Aug 11, 2026
  2. yinlianghui commented on Aug 11, 2026

    @yinlianghui
    Contributor

    CLAIM — session session_017Qqyix2QcnpUC9XeYVDzx3(objectui whole-repo PM seat),dispatching now。Branch: claude/issue-4240-storage-slot-key。

    修复方向按卡片结论执行:framework 侧规范(file-storage 是声明的槽名),改 console 目录键;fail-closed 姿态(ADR-0076 D12)不动。派单附加一条绊线令:这个错拼能活到今天,是因为没有任何东西把目录键钉在规范槽名词汇上——dev 须实测 vendored spec 是否可导入槽名词汇(core-services 的槽枚举);可导入则加派生 pin(服务门控的目录键 ⊆ 规范槽名,未来改名即红),不可导入则至少把 file-storage 键与测试用 discovery fixture 互钉。

    Surface:apps/console/src/pages/developer/**(useApiDiscovery.ts + 测试);与在飞 #4233(RootLandingRedirect/AppManagementPage)、#4292(FormPage/ActionRunner)同目录不同文件,互斥令已写入派单。


    Generated by Claude Code

  3. yinlianghui commented on Aug 11, 2026

    @yinlianghui
    Contributor

    ACCEPT — PM review of record (session session_017Qqyix2QcnpUC9XeYVDzx3)。

    PR #4310 验收要点:

    • 行为变化恰为一处:目录键 storage → 规范槽名 file-storage;ADR-0076 D12 fail-closed 姿态未动;显示名 'Storage' 经验证不由键派生,零 i18n 迁移;不加宽容别名并用 pin 钉住"legacy 拼写不复活分组"——消费端不为生产端词汇打补丁,方向正确。
    • 绊线令超额完成:CoreServiceName 实测可从 vendored spec 的 ./system 子路径导入(root 无此导出,连这一点都探过),派生 pin 是真的——目录键 ⊆ 槽名枚举,任一侧改名即红。测量顺带把卡片没预料的暴露出来:十键中三键出词汇表(workflow/feed 同机制永久隐藏 7 个端点,但 server 侧这两个槽也不存在——workflow 已在 objectstack#4451 退役、feed 零路由命中,隐藏歪打正着)。不并入本卡正确:无正确槽可改名,retire-or-repoint 是产品决策 → API Console carries two more service-gated catalog keys that name no canonical slot — workflow (retired) and feed (never a slot), so 7 endpoints are permanently unrenderable #4303 observation 级立卡,pin 写成引注例外集的子集断言(例外移除保持绿、新非槽键即红)。
    • 验证方向按实测报告:5 个 fail-closed 对照在 revert 态是空洞绿(键 miss 而非门拒)——如实声明其守卫对象是"未来的过度修正"而非本修复的证据;degraded 用例与 legacy-不复活 pin(反向)承担变更探测。诚实的形状胜过硬凑的统一红绿。
    • 反向验证走 commit-then-revert(流程令已生效);CI 20 项收敛全绿,mergeable clean。

    Flipping ready + auto-merge。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions