Repository navigation
Re-key the API Console storage catalog to storage once @objectstack/spec publishes the canonical slot #5291
Description
Activity
Triage: graded
pm:on-hold(2026-08-19, triage seat, first-touch). Reason: the re-key cannot land until the locally pinned@objectstack/specpublishesstorageas aCoreServiceNamemember — 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 thefile-storagemirror 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-keySERVICE_ENDPOINT_CATALOG, deleteDEPRECATED_SERVICE_SLOT_ALIASESand 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
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 23, 2026 Triage:
domain:ui(lane only —pm:on-holduntouched). 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
objectstack-fleet commented
on Sep 24, 2026 ContributorMore actions解除挂起 →
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
- objectui 的
- added and removed
on Sep 24, 2026 objectstack-fleet commented
on Sep 25, 2026 ContributorMore actionsClaim: PM loop round 4 —
domain:uiexecution 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_CATALOGre-keyed from'file-storage'to'storage';DEPRECATED_SERVICE_SLOT_ALIASESanddiscover()'s special case removed), its testuseApiDiscovery.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 touchesapps/console/src/pages/developer/. Livepm:dispatchedclaims name no file there. Restart condition (triage5805869684): the installed@objectstack/spec17.4.0 publishesstorageinCoreServiceName, anduseApiDiscovery.ts:225is still keyed'file-storage'onorigin/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
objectstack-fleet commented
on Sep 25, 2026 ContributorMore actionsos-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
objectstack-fleet commented
on Sep 25, 2026 ContributorMore actions✅ ACCEPT: objectui#10498 at
b609d15; ready + auto-merge in this actdomain:uiseat #2,session_014mXUNuFomfj24w7s1pZzhN. I checked this against the diff and CI, not against the report's own account. It delivers what triage5805869684named, which the maintainer returned to the queue with 「5291 放回队列」.Implemented-by: claude/issue-5291-api-console-storage-slot Reviewed-by: session_014mXUNuFomfj24w7s1pZzhNitem reading the re-key SERVICE_ENDPOINT_CATALOGis keyedstorage.DEPRECATED_SERVICE_SLOT_ALIASESand the special case indiscover()are gone, and the page readsservices.storageonly. The tripwire now assertsstorageis defined andfile-storageis not. No other reader offile-storageexists underapps/orpackages/second behaviour change routes.storagenow supplies the prefix when the service row has no route. The oldfile-storagekey never matchedApiRoutesSchema.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_TIERon this head, record5827354410(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 mapgoverned NOT GOVERNED (3 paths) CI 43 check-runs on b609d15: 40 success, 3 skipped by design, 0 redclosing keywords the body's only closing reference is Fixes #5291The 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-storagewithoutstorage. The reviewer measured the npm tarballs.@objectstack/runtime/metadata-protocol17.0.0 (GA 2026-08-14, plus its seven-rc.x) announcefile-storageonly. Every release from 17.1.0 (2026-08-20) through 17.4.0 announces both, byte-equal (spec CHANGELOG593c4bf).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 needstorage(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.tsandprotocol.tsname "objectui's console endpoint catalog" as a reader of thefile-storagekey, 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
readyand auto-merge (squash) go through the relay opspr_ready+automerge_enablein this act. The PR assignee is already the card's.
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Follow-up to #5286 (framework#9683).
apps/console/src/pages/developer/hooks/useApiDiscovery.ts'sSERVICE_ENDPOINT_CATALOGstays keyed by the deprecatedfile-storageslot name — not re-keyed to the now-canonicalstorage— because the locally pinned@objectstack/specdependency has not publishedstorageas aCoreServiceNameenum member yet:Re-keying now would fail the
SERVICE_ENDPOINT_CATALOG keys are canonical service-slot namestripwire (#4240) against these real, currently-installed types. #5286 instead added a smallDEPRECATED_SERVICE_SLOT_ALIASEStable that maps the catalog'sfile-storagekey to the canonicalservices.storagediscovery key to read first, withfile-storagekept as a fallback.Why this needs its own tracking
Nothing forces a revisit once the dependency does bump:
file-storagestays a validCoreServiceNamemember 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 includesstorageinCoreServiceName)@objectstack/specdependency (this is likely already covered by routine dependency-bump PRs — no action needed beyond noticingstorageis now available).SERVICE_ENDPOINT_CATALOG's'file-storage'entry to'storage'.DEPRECATED_SERVICE_SLOT_ALIASESand the special-cased lookup inuseApiDiscovery'sdiscover().useApiDiscovery.test.ts's tripwire block accordingly (theSERVICE_ENDPOINT_CATALOG.storage/.file-storageassertions 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-storagemirror row for all of v17 either way.Generated by Claude Code