Repository navigation
fix(data-objectstack): ObjectStackAdapter reads baseUrl as the server origin, so a base ending in /api/vN reaches discovery; the objectui skill teaches the origin - #27967
Conversation
…ases reach discovery; objectui skill teaches the origin The adapter normalises `baseUrl` once where it and its ObjectStackClient are built: a trailing slash and a trailing `/api/vN` are dropped, so `''`, an origin, `/api/v1` and `origin/api/v1` all reach `/api/v1/discovery` and the same `/api/v1/...` routes through the client and the raw reads alike. The five per-call suffix checks are replaced by that one helper. skills/objectui (data-integration, auth-permissions) and the package README teach the origin form the console passes; the data-integration eval refuses an answer that writes the old form. Claude-Session: https://claude.ai/code/session_01Utp6CXqKgaNYFmpss9BkRj Co-authored-by: Claude <noreply@anthropic.com>
|
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe Contract reviewServed-tier: Inputs: card #27774 (body, triage 6510453993, claim 6515328969, dev report 6515829241), PR #27967 body and file list (7 files, +143/−43), the net diff Check-runs on the head, read at 2026-10-30T05:49Z: 54 total — 32 success, 8 skipped, 13 in progress (Test UI 1/3/5/6/7/9/10/11/12/13/16 of 16, Test Core 1/8, Type Check UI), 1 failure: ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Tried to break the design (cited code, read not reviewed): Findings: should-fix ×1 (data-integration.md:388 Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe 维护者速读
席位意见:建议批准。dev 实测证伪了「只改发现那一行」的假设:client 也会让路由翻倍,所以把归一提前到构造函数,这和分诊的裁定是同一个方向。合约复核留了一条非阻塞的 should-fix:指南第 388 行还写着 席位核对ACCEPT · head
Generated by Claude Code |
Requested by Bill · project thread
Fixes #27774
维护者速读
ObjectStackAdapter构造时把baseUrl一次归一为服务器 origin(去掉尾部/与尾部/api/vN),发现请求、内嵌ObjectStackClient的路由与适配器各处裸读共用这一个值;原来五处逐调用的后缀判断删掉。objectui 技能的两份指南与包 README 改教 origin 形式(同源代理写''),data-integration eval 拒绝旧写法baseUrl: '/api/v1'。baseUrl: '/api/v1'让发现请求打到/api/v1/api/v1/discovery,connect()失败,之后每次读写随之失败。适配器自己的搜索/数据/导出/元数据裸读早已去掉该后缀,但发现请求与内嵌 client 没有;只改发现一行,client 路由的读(如/api/v1/meta/:type)仍会翻倍,所以归一放在构造处。@object-ui/data-objectstack一个包变化;origin 形式的 URL 字节不变(全包 104 个测试文件 1228 用例绿);回滚即 revert 本 PR,无数据迁移,无 spec 改动。ui/packages/data-objectstack/src/index.ts的serverOriginOf与构造函数 hunk;skills/objectui/guides/data-integration.md;skills/objectui/evals/data-integration.json。pnpm --dir ui exec vitest run packages/data-objectstack/src/connectBaseUrlApiSuffix-27774.test.ts,预期 7 passed;同一文件对origin/main跑是 4 failed(断言里出现/api/v1/api/v1/discovery)。skills/**)—— 席位 ACCEPT 与合约复核 PASS 之后,由你合并或入队(或 os-zhuang / hotlong 的授权批准后由席位落地)。What changes
Adapter (
@object-ui/data-objectstack)ObjectStackAdapterreadsbaseUrlas the server origin ONCE, where it and itsObjectStackClientare built (serverOriginOf): a trailing slash and a trailing/api/vNare dropped.'',http://host:3000,/api/v1andhttp://host:3000/api/v1now all reach/api/v1/discoveryand the same/api/v1/...routes, through the client and through the adapter's raw reads alike.hasApiVersionSuffixchecks (search, data, export, two meta reads) are gone; each site joins/api/v1/...onto the normalised base. The analytics dataset query and the approvals reads, which joined onto the base as given, are covered by the same normalisation without a change of their own.baseUrlon the constructor options carries a doc comment naming the form.connectBaseUrlApiSuffix-27774.test.ts: the discovery URL the injected fetch receives for the origin, the empty same-origin base, a relative and an absolute base ending in/api/v1, a trailing slash after it, a non-version path prefix (kept), and one client-routed read (listMetadataItems) from an/api/v1base that must reach/api/v1/meta/positiononce.Skill (
skills/objectui, governed, Tier H) and READMEguides/data-integration.md: the four adapter examples teachbaseUrl: ''(the first one names the two forms:''behind a same-origin proxy, or the server origin); the constructor-options comment says the adapter adds/api/v1.guides/auth-permissions.md: the one adapter example teachesbaseUrl: ''. This file was not on the claim's declared surface; it is the fifth site of the same defect and the card's acceptance grep (git grep -n "baseUrl: '/api/v1'" -- skillsis 0 hits) cannot pass without it.evals/data-integration.json: eval 2 (building the frontend before the backend) expects the adapter to be handed the origin and refuses an answer containingbaseUrl: '/api/v1(the wrong form's prefix, so the acceptance grep stays at 0 hits).ui/packages/data-objectstack/README.md: the oneObjectStackAdapterexample that taught/api/v1now teaches''. ItsMetadataClientexamples keep/api/v1: that class already collapses the suffix itself.Changeset:
.changeset/27774-adapter-base-url-origin.md,patchon@object-ui/data-objectstackand@objectstack/skills.Why
A customer agent that loads the published
objectuiskill and wires a real backend was told to writenew ObjectStackAdapter({ baseUrl: '/api/v1' }). Discovery joined/api/v1/discoveryonto the base as given, so the first request asked for/api/v1/api/v1/discovery,connect()failed, and every read and write that awaits it failed with it. The triage ruled platform first: the adapter accepts both spellings (its sibling reads already did), pinned, and the skill then teaches the origin formObjectStackClienttakes.Mechanism assumption re-measured. The order assumed a strip on the discovery line alone, like the four sibling reads. Read from source: the adapter spreads its whole config into
new ObjectStackClient({ ...config }), and the client joins every conventional route (/api/v1/meta,/api/v1/data, ...) onto ITS base as given, so a discovery-only strip would have connected and then doubled every client-routed read. The normalisation therefore sits in the constructor, before the client is built, and the pin's last case reads a client-routed URL. Same ruling, one step earlier.Tests
Package tests and type-check, under the shared verify lock, on
e73e6d45:pnpm --dir ui exec vitest run packages/data-objectstack/— Test Files 104 passed (104) · Tests 1228 passed (1228) · exit 0pnpm --filter @object-ui/data-objectstack run type-check— exit 0Red on the pre-fix adapter, green on the fix (one leg each, the pre-fix
index.tsrestored from the merge baseed0e71dband put back withgit checkout HEAD -- …; blob hash equal before and after,git diff HEADempty):pre-fix: Tests 4 failed | 3 passed (7)
fix: Tests 7 passed (7)
The three origin-form cases pass on both trees: the origin spelling's bytes do not change.
Acceptance notes
git grep -n "baseUrl: '/api/v1'" -- skills→ 0 hits on this head (the card's acceptance line).ceil(utf8 bytes / 4), the conventioncheck-skills-token-ratchet.mjsprints):guides/data-integration.md: 480 → 480 lines · 4303 → 4328 tokens (ceiling 4451).guides/auth-permissions.md: 416 → 416 lines · 3866 → 3864 tokens (ceiling 3866, headroom was 0; a comment there was dropped to stay under it).evals/data-integration.json: 54 → 55 lines · 466 → 470 tokens (ceiling 471; the new refusal string is paid for by a shorterexpected_outputin the same file).skills/objectuibundle: 5416 → 5417 lines. Whole published catalog, the ratchet's "ratcheted (authored)" total: 208049 → 208079 tokens of 217809. No ceiling moved.baseUrlending in/api/v2is read as the origin too (the siblings' regex, kept); every route is then/api/v1/.... Not pinned: there is no v2 API to teach.'/api/v1'and''on one page share one discovery read, as they should.skills/objectui/guides/project-setup.mdteachesVITE_API_BASE_URL=/api/v1as an env example without wiring it into the adapter; with this PR that value would work either way.MetadataClient(same package) already collapses a/api/v1base; its README examples are left as they are. Neither is a card.index.ts(field-access fields,dropInflightReads,getRecordFieldAccess) are untouched; PR perf(console): opening a record re-reads no list, asks its field access once, and the bell polls once a minute #27907's file list does not include this file.Verification
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, off the merge base, heade73e6d45): 58 derived, 57 run with exit 0 (node scripts/check-sdui-manifest.mjsandnode scripts/check-skills-token-ratchet.mjsamong them;check:skill-examplesfirst refused on a missingclient-reactdist and passed after that package was built), 1 NOT MEASURED:pnpm check:dual-build-cjs-loadsexits 3 here (it reads every package's dist, and this worktree holds only the adapter's dependency closure) and is declared to CI'sLint & Repo Gates.--ranreconciliation: 58 accounted, 0 UNRUN; each exit code is in theos-dev-reportcomment on skills/objectui teaches ObjectStackAdapter({ baseUrl: '/api/v1' }), which sends discovery to /api/v1/api/v1/discovery, so connect() fails and every adapter call with it #27774.pnpm --filter @object-ui/data-objectstack lintexit 0 (0 errors; the warnings it prints are pre-existinganys, none on a changed line).pnpm --dir ui run check:new-line-citations: 0 new citations.Clause-②: no
Metadata-protocol: none
Human Minimum
packages/specholds no runtime logic. (not touched)main, one pull request.packages/spectouched: n/a, not touched.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code