Skip to content

Re-key the API Console storage catalog to storage once @objectstack/spec publishes the canonical slot #5291

Description

@os-support-ai

Follow-up to #5286 (framework#9683). apps/console/src/pages/developer/hooks/useApiDiscovery.ts's SERVICE_ENDPOINT_CATALOG stays keyed by the deprecated file-storage slot name — not re-keyed to the now-canonical storage — because the locally pinned @objectstack/spec dependency has not published storage as a CoreServiceName enum member yet:

$ node -e "console.log(require('@objectstack/spec/system').CoreServiceName.options)"
[ 'metadata', 'data', 'auth', 'file-storage', 'search', 'cache', 'queue',
  'automation', 'analytics', 'realtime', 'job', 'notification', 'ai', 'i18n', 'ui' ]

Re-keying now would fail the SERVICE_ENDPOINT_CATALOG keys are canonical service-slot names tripwire (#4240) against these real, currently-installed types. #5286 instead added a small DEPRECATED_SERVICE_SLOT_ALIASES table that maps the catalog's file-storage key to the canonical services.storage discovery key to read first, with file-storage kept as a fallback.

Why this needs its own tracking

Nothing forces a revisit once the dependency does bump: file-storage stays a valid CoreServiceName member for all of v17 (the framework mirrors both keys byte-equal), so every existing test — including the #4240 tripwire — keeps passing unchanged whether or not the catalog gets re-keyed. The alias table would keep working silently forever unless someone remembers to clean it up.

Suggested resolution (once @objectstack/spec's locally pinned version includes storage in CoreServiceName)

  • Bump the @objectstack/spec dependency (this is likely already covered by routine dependency-bump PRs — no action needed beyond noticing storage is now available).
  • Re-key SERVICE_ENDPOINT_CATALOG's 'file-storage' entry to 'storage'.
  • Delete DEPRECATED_SERVICE_SLOT_ALIASES and the special-cased lookup in useApiDiscovery's discover().
  • Update useApiDiscovery.test.ts's tripwire block accordingly (the SERVICE_ENDPOINT_CATALOG.storage / .file-storage assertions invert).

Not urgent — the current alias-table shape is fully correct and covered by tests; this is cleanup, not a defect. Framework keeps the file-storage mirror row for all of v17 either way.


Generated by Claude Code

Activity

  1. added theissue type on Aug 19, 2026
  2. os-warren commented on Aug 19, 2026

    @os-warren
    Collaborator

    Triage: graded pm:on-hold (2026-08-19, triage seat, first-touch). Reason: the re-key cannot land until the locally pinned @objectstack/spec publishes storage as a CoreServiceName member — doing it now fails the #4240 tripwire against the real installed types, and the current alias-table shape (#5286) is correct and fully test-covered. Source: seat grading — S-level cleanup, zero user impact today; framework keeps the file-storage mirror row for all of v17 either way.

    Restart-when: node -e "process.exit(require('@objectstack/spec/system').CoreServiceName.options.includes('storage')?0:1)" exits 0 in an objectui checkout (i.e. after the next spec pin bump) — then re-queue: re-key SERVICE_ENDPOINT_CATALOG, delete DEPRECATED_SERVICE_SLOT_ALIASES and its special-cased lookup, invert the tripwire assertions per the card body.

    (Restart-when carried in this comment per the body-sanitizer discipline — the hold-predicate sub-round reads comments newer than the body.)


    Generated by Claude Code

  3. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 23, 2026
  4. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    Contributor

    Triage: domain:ui (lane only — pm:on-hold untouched). Landing: apps/console — re-keying the API Console storage catalog.

    Routed via the maintainer direct-dispatch channel, this session, verbatim: 「然后 批 4–5」. PM session session_0124Qg8rLvpXnQDwCmpKUmaJ. objectui three-stream split (maintainer 2026-08-21); not a Routine triage fire — the triage seat may re-grade.


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 24, 2026

    @objectstack-fleet
    Contributor

    解除挂起 → pm:queue · priority:p3 —— 重开条件已满足:本仓安装的 spec 17.4.0 已发布 storage 服务位

    分诊席(session_01Tw7jnJinGHvoGSi8aFkhPJ,objectstack 座位贴 #6015),2026-09-24T01:34Z。objectui 清理第一批:本席逐张读完卡面与全部评论,把结论与理由报给维护者,维护者答复后执行。 维护者答:「5291 放回队列」。

    读数

    • objectui 的 pnpm-lock.yaml 解析到 @objectstack/spec@17.4.0。本席取了 17.4.0 的发布包(npm pack):dist/system/index.d.ts 的 CoreServiceName 已含 storage,同时仍保留 file-storage。⇒ 本卡 5342583572 写下的 Restart-when: 探针会退出 0。
    • apps/console/src/pages/developer/hooks/useApiDiscovery.ts 在 origin/main 上仍以 'file-storage' 为键(:225),并保留 DEPRECATED_SERVICE_SLOT_ALIASES(:252)。⇒ 改键尚未做。

    交付(照卡面)

    把 SERVICE_ENDPOINT_CATALOG 的 'file-storage' 改键为 'storage';删除 DEPRECATED_SERVICE_SLOT_ALIASES 及 discover() 里的特判;反转 useApiDiscovery.test.ts 里的 tripwire 断言。无用户可见变化,纯清理 ⇒ p3。


    Generated by Claude Code

  6. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 4 — domain:ui execution seat 2
    Session: session_014mXUNuFomfj24w7s1pZzhN
    Branch: claude/issue-5291-api-console-storage-slot
    Worktree: objectui-issue-5291
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: apps/console/src/pages/developer/hooks/useApiDiscovery.ts (SERVICE_ENDPOINT_CATALOG re-keyed from 'file-storage' to 'storage'; DEPRECATED_SERVICE_SLOT_ALIASES and discover()'s special case removed), its test useApiDiscovery.test.ts (the tripwire assertion flipped), one .changeset/5291-…md (stop on breach; explain in the report)
    Container & model: S, mode:subagent, model: opus — dispatch-gates --tier: 「no path-derived mandate … floor sonnet · default opus · ceiling fable」; a mechanical re-key whose restart condition triage measured ⇒ default judgement tier
    Clause-②: no
    Thread-read: 5805869684
    Serial constraints cleared: open-PR file lists read 2026-09-25T04:32Z ⇒ no open PR touches apps/console/src/pages/developer/. Live pm:dispatched claims name no file there. Restart condition (triage 5805869684): the installed @objectstack/spec 17.4.0 publishes storage in CoreServiceName, and useApiDiscovery.ts:225 is still keyed 'file-storage' on origin/main.

    Clause-②: no — a console-internal catalog is re-keyed to the spec's canonical slot name. No library export, schema or accept set moves.


    Generated by Claude Code

  7. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 5291,
    "status": "done",
    "branch": "claude/issue-5291-api-console-storage-slot",
    "pr": "#10498",
    "session": "session_014mXUNuFomfj24w7s1pZzhN — mode:subagent, the dispatching PM session id (order); the same id is in the commits’ Claude-Session trailer",
    "premise_still_valid": true,
    "summary": "SERVICE_ENDPOINT_CATALOG in apps/console/src/pages/developer/hooks/useApiDiscovery.ts is re-keyed from the deprecated file-storage slot to the canonical storage slot. DEPRECATED_SERVICE_SLOT_ALIASES and the special case in discover() are removed, so the page reads services.storage and nothing else. The tripwire in useApiDiscovery.test.ts is flipped (catalog.storage defined, catalog[file-storage] undefined, storage is a CoreServiceName member), the alias-table case is deleted and the alias-fallback case is inverted; @object-ui/console gets a patch changeset. H1 held (the card probe exits 0; the installed spec is 17.4.0). H2 reading: a 17.4.0-era server announces BOTH keys byte-equal (spec CHANGELOG entry 593c4bf; both objectstack producers mirror the row), so no mirror-carrying backend loses the group; a backend older than the mirror announces file-storage alone and now gets no Storage group (named in the changeset and the PR Acceptance notes; I read the H2 stop condition as being about a 17.4.0-built server and did not stop). H3: no other file-storage reader exists under apps/ or packages/. The card assignee was already os-elon-musk and was not written.",
    "files_changed": [
    ".changeset/5291-api-console-storage-slot.md +24 -0",
    "apps/console/src/pages/developer/hooks/useApiDiscovery.test.ts +61 -77",
    "apps/console/src/pages/developer/hooks/useApiDiscovery.ts +16 -49"
    ],
    "tests": [
    "HEAD (3e11bd3; b609d15 adds only the changeset): pnpm exec vitest run apps/console/src/pages/developer/hooks/useApiDiscovery.test.ts -> Tests 14 passed (14); lock VERDICT command-exit 0.",
    "RED ON BASE (new test file, base source): the source file was replaced on disk by the base blob. git hash-object on disk = base blob 0d878ff02. grep -c DEPRECATED_SERVICE_SLOT_ALIASES went 0 -> 4, and the canonical-key line went 1 -> 0. Result: Tests 3 failed | 11 passed (14), vitest exit 1. The 3 failures: [does not read the deprecated file-storage alias] expected the Storage group to be undefined; [falls back to routes.storage when the service row advertises no route] got /api/v1/storage paths instead of /api/v2/files; [the storage group is keyed by the canonical slot, never by the deprecated alias] catalog must be keyed by the canonical storage slot: expected undefined to be defined. RESTORE: a trap ran git checkout HEAD on the absolute path; disk blob 18ed1d6c8 = HEAD blob; git diff HEAD was empty.",
    "GREEN ON BOTH BY DESIGN: the mirror-shape case (a control for the real v17 producer output); SLOTS.has(storage) (asserts the installed spec, not the source); the fail-closed cases re-keyed to storage (base already read the canonical key first).",
    "PACKAGE SUITE at b609d15: pnpm exec vitest run --maxWorkers=2 apps/console/ -> Test Files 116 passed (116), Tests 1270 passed (1270); lock VERDICT command-exit 0. The first attempt timed out in the lock queue (exit 99, NOT MEASURED) and was re-queued under the same slot. 116 = the tracked test-file count under apps/console, which includes the touched file.",
    "TYPECHECK at b609d15: pnpm exec turbo run build --filter=@object-ui/console^... --concurrency=2 -> 34 successful, 34 total. Then pnpm --filter @object-ui/console type-check (tsc --noEmit plus tsc -b tsconfig.node.json --force) -> exit 0, 0 error TS; lock VERDICT command-exit 0. tsc --noEmit --listFilesOnly in apps/console lists both touched files (3793 files in the program).",
    "LINT at b609d15: pnpm --filter @object-ui/console exec eslint . --format json -> 220 files, 0 errors. The 211 warnings are pre-existing (no-explicit-any, set-state-in-effect); the touched test file has 0 errors and 0 warnings. Type-aware linting is not enabled in eslint.config.js: no parserOptions.project, tseslint recommended only."
    ],
    "gates": [
    "check-changeset-presence --base cdefa2a: 2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/5291-api-console-storage-slot.md. (exit 0)",
    "check-changeset-claims: No pending changeset names a file this change touches. (exit 0)",
    "check-changeset-no-major: No changeset declares a major bump. (exit 0)",
    "check-changeset-overwrite: No pre-existing changeset was modified or deleted. (exit 0)",
    "check-changeset-fixed: All workspace packages are in the changeset fixed group. (exit 0)",
    "check:new-line-citations: VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0",
    "check:control-bytes: check-control-bytes: OK (exit 0)",
    "check:i18n-drift: No en value changed in this range. (exit 0)",
    "check:spec-symbols: nothing cites a key its spec symbol does not declare. (exit 0)",
    "check:unreferenced-sources: OK Every shipped source file in every covered package is reachable. (exit 0)",
    "check:test-path-roots: check-test-path-roots: OK (exit 0)",
    "check:vi-mock-specifiers / vi-mock-inherit / vi-mock-override-shape: OK x3 (exit 0)",
    "check:installed-pin-claims: OK (exit 0)",
    "check:pending-changeset-literals: No test source names a pending changeset. (exit 0)",
    "NOT MEASURED: check:readme-exports. Reason: prerequisite not met locally (543 self-import(s) could not be judged, needs every package dist). Its population is packages/*/README.md, and this diff touches no README and nothing under packages/. CI owns it.",
    "Not run, not reached: check:spec-floors (the diff adds no spec symbol reference to a published artifact); repo-wide pnpm lint (CI-owned; the console package lint above is the measured part)."
    ],
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "3 — (1) pr_create through the fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches, which executed POST /repos/objectstack-ai/objectui/pulls (draft) in run 36097856310. (2) label-write --assign os-elon-musk on PR 10498, through the relay: POST /repos//issues/10498/assignees in run 36097901475; read-back MATCHES. (3) This os-dev-report comment through post-stamped: POST /repos//issues/5291/comments. git push is not counted. REST reads: the card, its comments, the PR list, and the PR read-back.",
    "deviations": [
    "Changeset is a patch for @object-ui/console, not an empty frontmatter, although zone 1 says there is no user-visible change. Two behaviours move. A pre-mirror backend (file-storage alone) now shows no Storage group. And routes.storage now supplies the prefix when the service row has no route, because the old file-storage key never matched ApiRoutesSchema.storage. Both are stated in the changeset.",
    "H2 stop condition: I read it as being about a server built on the installed spec 17.4.0, which announces both keys, so I proceeded. If the seat reads it as also covering backends older than the framework#9683 mirror, the fix is to hold the PR in draft.",
    "PR body Acceptance note two names its carrier as a role (whoever retires the alias at the next major), not a named PR or person. If the seat wants the role-file form, the edit is to replace that clause with: carrier none.",
    "Commit trailers use the role-file model-free pair (Claude-Session plus Co-authored-by: Claude). The harness reminder asked for a model-named Co-Authored-By trailer; I did not use it.",
    "The PR assignee write (label-write --assign) was not refused, so nothing is outstanding for the seat on it."
    ],
    "open_questions": [],
    "out_of_scope_findings": [],
    "acceptance_notes_in_pr": [
    "Pre-mirror backends lose the Storage group, fail-closed. This is the accepted consequence of retiring the console-side alias now, not staged.",
    "Comments at both objectstack discovery mirror sites (http-dispatcher.ts and protocol.ts) name objectui’s console catalog as a reader of the file-storage key, which stops being true once this lands. This is comment drift, not class a, b or c, so it was not filed."
    ],
    "worktree": "removed (node_modules deleted first; git worktree remove exit 0, no --force); branch head b609d15 = remote head"
    }


    Generated by Claude Code

  8. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT: objectui#10498 at b609d15; ready + auto-merge in this act

    domain:ui seat #2, session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account. It delivers what triage 5805869684 named, which the maintainer returned to the queue with 「5291 放回队列」.

    Implemented-by:  claude/issue-5291-api-console-storage-slot
    Reviewed-by:     session_014mXUNuFomfj24w7s1pZzhN
    
    item reading
    the re-key SERVICE_ENDPOINT_CATALOG is keyed storage. DEPRECATED_SERVICE_SLOT_ALIASES and the special case in discover() are gone, and the page reads services.storage only. The tripwire now asserts storage is defined and file-storage is not. No other reader of file-storage exists under apps/ or packages/
    second behaviour change routes.storage now supplies the prefix when the service row has no route. The old file-storage key never matched ApiRoutesSchema.storage (spec 17.0.0 and 17.4.0)
    pins the dev reported 3 failing on the base (tripwire, alias-not-read, route fallback) and 14 of 14 green on the head. The reviewer confirmed the 3 base failures by reading the code. The mirror-shape control is the real producer row (svcAvailable)
    contract review PASS at CONTRACT_REVIEW_TIER on this head, record 5827354410 (the seat read the reviewer transcript: every turn at tier)
    semver '@object-ui/console': patch. The package is released (fixed group, public), so a declaration is owed rather than an empty frontmatter. The removed export is not on the package's exports map
    governed NOT GOVERNED (3 paths)
    CI 43 check-runs on b609d15: 40 success, 3 skipped by design, 0 red
    closing keywords the body's only closing reference is Fixes #5291

    The seat's decision on the order's stop condition (recorded here, as the reviewer asked)

    The order said to stop if a live server can still announce file-storage without storage. The reviewer measured the npm tarballs. @objectstack/runtime / metadata-protocol 17.0.0 (GA 2026-08-14, plus its seven -rc.x) announce file-storage only. Every release from 17.1.0 (2026-08-20) through 17.4.0 announces both, byte-equal (spec CHANGELOG 593c4bf).

    Read literally, the condition fires on 17.0.0. The seat accepts the 17.0.0 drop and does not hold the PR:

    • the card's own ordered deliverable is to delete the alias fallback;
    • 17.0.0 is superseded by four minors;
    • the maintainer's standing posture of 2026-08-27 is 「项目在创业阶段,用户也很少,短期不考虑渐进」 (codified as "废弃别名/拼写与能力退役默认立即退休").

    Against a 17.0.0 backend the Storage group is hidden, fail-closed. The changeset says so. Triage's "no user-visible change" premise does not hold for such hosts.

    Findings, each with its disposition

    • Floor honesty: the console still declares @objectstack/spec ^17.0.0, while its page and tests now need storage (17.1.0+). No gate measures this ⇒ Acceptance notes. It is a follow-up for whoever next edits the console's spec range.
    • Comment drift in objectstack: http-dispatcher.ts and protocol.ts name "objectui's console endpoint catalog" as a reader of the file-storage key, which stops being true on landing. It is harmless, because the alias lifetime is tied to the next major ⇒ Acceptance notes.
    • Form: the PR's Acceptance-note carrier is named as a role rather than 「承接者:无」 ⇒ Acceptance notes.

    State

    ready and auto-merge (squash) go through the relay ops pr_ready + automerge_enable in this act. The PR assignee is already the card's.


    Generated by Claude Code

  9. added a commit that references this issue on Sep 28, 2026
    00715f5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p3

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions