Repository navigation
fix(cloud-connection): name the cloud-binding service in its contract, and read an empty controlPlaneUrl one way - #30956
Conversation
…, read an empty controlPlaneUrl once Export CLOUD_BINDING_SERVICE from @objectstack/spec/contracts beside ICloudBindingService; cloud-connection registers under it and service-push's relay sender reads it (its public export stays, as a re-export). The plugin's routes take their control-plane URL from the cloud-binding service, and the binding reads an explicit empty option as "no control plane", the reading the routes always gave it. Claude-Session: https://claude.ai/code/session_016WV4cwsvPqjJfJthsRiYpt Co-authored-by: Claude <noreply@anthropic.com>
…ING_SERVICE Claude-Session: https://claude.ai/code/session_016WV4cwsvPqjJfJthsRiYpt Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check6 anchor(s) derived from 3 changed package(s); no hand-written page names any of them. What this run could not see
Coarse fallback — 173 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin d7e8b1d00d9648d1727767dc040cf672ff2bfbce && git checkout d7e8b1d00d9648d1727767dc040cf672ff2bfbce
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 6ddf827236902c0ccaee56b65431a4c8a9c7ac09 937d74e1af20fa66477c4da26d3747b492a8205a && git checkout -B drift-repro 6ddf827236902c0ccaee56b65431a4c8a9c7ac09 && git merge --no-ff 937d74e1af20fa66477c4da26d3747b492a8205a
node scripts/docs-audit/affected-docs.mjs --json 6ddf827236902c0ccaee56b65431a4c8a9c7ac09 |
|
domain:server#5 · os-elon-musk · session_016WV4cyvF7SP65frVFAYLv7 Contract reviewServed-tier: Inputs: card #30762 (body; triage audit 6685166387; the seat's three claims 6685693761, 6685800461, 6685858377, the last carrying the widened surface; the dev's os-dev-report 6686963912), the source record 6673473934 on PR #30749 (④ items 1 and 2), PR #30956 body and file list (11 files, identical to the local net diff against merge-base 3479c33, +156/-18), and the check-runs on this head. Readings are against ① Derived judgments
② Semver level
③ Boundary flagsThe widened surface (claim 6685858377). Route A for item 2. The card offered two routes; the dev took the first (routes read the binding; the binding reads an explicit empty option the routes' way). Verified in the cited code: The two further behaviour changes the dev declares, hand-composed kernels only.
Noted by the dev, not filed: Serial constraints: the only open PR on ④ Design judgmentpackages/spec/src/contracts/cloud-binding-service.ts — holds for its consumers. Break attempts: (1) the string: the contract declares One should-fix on the hit:
packages/spec/api-surface/contracts.json, packages/spec/export-origins/contracts.json — hold: one row each, the row names the file and the kind ( No must-fix found. Check-runs on Implemented-by: VERDICT: PASS |
…alue as a third way to answer '' Claude-Session: https://claude.ai/code/session_016WV4cwsvPqjJfJthsRiYpt Co-authored-by: Claude <noreply@anthropic.com>
|
domain:server#5 · os-elon-musk · session_016WV4cyvF7SP65frVFAYLv7 Contract reviewServed-tier: ① Derived judgments — delta review on top of PASS 6687101841 (head d1e3182)This record judges the one commit
② Semver levelUnchanged from 6687101841: ③ Boundary flags
④ Design judgmentpackages/spec/src/contracts/cloud-binding-service.ts — holds, and the one open finding on it is closed. Re-read against its two consumers at packages/spec/api-surface/contracts.json, packages/spec/export-origins/contracts.json — not in the delta, hold as at Check-runs on Implemented-by: VERDICT: PASS |
|
domain:server#5 · os-elon-musk · session_016WV4cyvF7SP65frVFAYLv7 席位核对 · ACCEPTPR #30956 · head 维护者速读(席位校正)The body's six lines stand. They read the diff at 席位核对
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 42239869046 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Requested by Elon · project thread
Fixes #30762
Clause-②: yes (widening)
Metadata-protocol: none
domain:server#5 card thread · session
session_016WV4cwsvPqjJfJthsRiYpt· branchclaude/project-thread-ms359b(named in the seat's re-posted claim on the card, with the widened file surface). Branched frommainat 33043bd;origin/mainmerged at d1e3182. The two should-fixes of the contract review on PR #30749 (record 6673473934, ④ items 1 and 2). Item 2 takes the card's first route (A): the routes read the binding.维护者速读
cloud-binding这个服务名现在只在 spec 契约里写一次(CLOUD_BINDING_SERVICE,和另外六个契约的做法一样),cloud-connection 注册、service-push 推送中继读取都用它;② cloud-connection 插件的路由不再自己读controlPlaneUrl,改读它自己注册的cloud-binding服务,所以「显式传空字符串」对路由和推送中继都是「没配云端」。objectstack serve和 showcase 行为不变(它们只用resolveCloudUrl()的非空结果组装插件,两种读法对它返回同一值);只有手工组装内核时才有差别,见下方 Acceptance notes 三条。spec 只多一个导出;service-push 原有的CLOUD_BINDING_SERVICE导出保留(改为转导出,值不变)。回滚即 revert,无迁移。packages/cloud-connection/src/cloud-binding.ts的resolveBindingUrl;packages/cloud-connection/src/cloud-connection-plugin.ts里const cloudUrl = this.binding.controlPlaneUrl();那一行;packages/spec/src/contracts/cloud-binding-service.ts末尾的新导出。pnpm --filter @objectstack/cloud-connection exec vitest run src/cloud-connection-plugin.test.ts src/cloud-binding.test.ts,预期全绿,其中「the routes and the binding read the control-plane URL once」一组 6 条覆盖空值、空白、OS_CLOUD_URL=off、显式 URL、仅环境变量五种情况。packages/spec/src/**且Clause-②: yes,席位 ACCEPT 前需契约复核)。What changes
1. One spelling of the service name.
packages/spec/src/contracts/cloud-binding-service.tsexportsCLOUD_BINDING_SERVICE = 'cloud-binding'besideICloudBindingService, asEMBEDDER_SERVICE,KNOWLEDGE_SERVICE,OWNERSHIP_QUEUE_SERVICE,RLS_MEMBERSHIP_RESOLVER_SERVICE,SEED_SETTLEMENT_SERVICEandFILE_ATTACHMENT_SERVICEdo.api-surface/contracts.jsonandexport-origins/contracts.jsonregenerated (gen:api-surface,gen:export-origins): one row each,CLOUD_BINDING_SERVICE (const).@objectstack/cloud-connection: the local constant incloud-binding.tsis gone. It was not a public export of the package (src/index.tsnever re-exported it), so nothing outside the package loses a name.CloudConnectionPluginimports the contract's constant forprovidesServicesandregisterService.@objectstack/service-push:transports/relay.tsimports the contract's constant.CLOUD_BINDING_SERVICEwas a public export of the package (src/index.ts), sorelay.tskeeps it as a re-export (export { CLOUD_BINDING_SERVICE }), same name, same value;index.tsis untouched.2. One reading of an empty
controlPlaneUrl(route A). Atmain,createCloudBindingansweredresolveCloudUrl(option), which reads an explicit''as unset and falls through toOS_CLOUD_URLand the production default, while the plugin's routes read(option ?? OS_CLOUD_URL ?? '')and treated''as "cloud not configured".createCloudBinding'scontrolPlaneUrl()is nowresolveCloudUrl's answer except that an explicit empty or blank option answers'', the reading the routes always gave it.cloudUrlfromthis.binding.controlPlaneUrl()(still read once atkernel:ready, where the env was read before), so the routes and the push relay sender read one answer.controlPlaneUrl()is''when the deployment declared no control plane; a host composing the plugin withcontrolPlaneUrl: ''is that declaration, so the contract text is unchanged and the reading is written down on the option (CloudBindingOptions.controlPlaneUrl,CloudConnectionPluginConfig.controlPlaneUrl).One changeset,
.changeset/30762-cloud-binding-service-name.md:@objectstack/spec,@objectstack/cloud-connection,@objectstack/service-push, allpatch.Tests
cloud-connection/src/cloud-connection-plugin.test.ts, new top-level describe "the routes and the binding read the control-plane URL once": boots the plugin throughinit()andstart(), drivesGET /installed(multi-tenant, service key set) and reads the registered binding. An explicit''and' 'withOS_CLOUD_URLset: binding'', no control-plane call, the disconnected answer. A declinedOS_CLOUD_URL=offunder an absent option: binding'', no call. A configured URL and an env-only URL: the route calls exactly${binding}/api/v1/cloud/environments/env-123/packages.cloud-connection/src/cloud-binding.test.ts:controlPlaneUrl()is''for an explicit''or' ', with and withoutOS_CLOUD_URL;CLOUD_BINDING_SERVICEis'cloud-binding'(the wire name), and the registration test reads the contract's constant.service-push/src/push-plugin.test.ts: the two tests that place a binding now register it under the contract'sCLOUD_BINDING_SERVICEinstead of the literal, so the registrar's test and the reader's test meet on one constant (the cross-package pin the review asked for).Ablations (each red, each restored;
scripts/ablation-replace.mjsWRAP mode,git diff HEADempty after each)main's way (option ?? OS_CLOUD_URL ?? '')cloud-connection-plugin.test.tsOS_CLOUD_URLcase (main's routes calledoff/api/...)resolveCloudUrl(option)(main's shape)cloud-binding.test.ts+cloud-connection-plugin.test.tsrelay.tsdeclares its ownCLOUD_BINDING_SERVICE = 'cloud_binding'push-plugin.test.ts'cloud_binding'cloud-binding.test.ts+cloud-connection-plugin.test.tscloud-connectiontests import the plugin and the binding fromsrc/by relative path, andservice-pushaliases@objectstack/spec/contractsto source (below), so no dist rebuild sits between a mutation and its run.Acceptance notes
''. Reading the routes' URL through the binding also aligns two other options, both reachable only on a hand-composed kernel: (a) an absent option with a declinedOS_CLOUD_URL(off,none,local,disabled): the routes used'off'as a base URL and calledoff/api/v1/...; they now answerCLOUD_UNCONFIGURED, as the binding already did. (b) an absent option withOS_CLOUD_URLunset or empty: the routes answeredCLOUD_UNCONFIGURED; they now use the ObjectStack-operated default, as the binding,MarketplaceProxyPluginandMarketplaceInstallLocalPlugin(resolveCloudUrl(config.controlPlaneUrl)) already did, and as the config docblock now says.objectstack serveis unchanged.planMarketplaceWiringcomposes the plugin only whenresolveCloudUrl()is non-empty and passes that value (serve.ts,createCloudConnectionPlugin({ singleEnvironment: true, controlPlaneUrl: marketplaceUrl }));examples/app-showcasedoes the same. That value is already trimmed, slash-stripped and not a decline spelling, somain's route expression andresolveBindingUrlboth return it byte-for-byte.MarketplaceProxyPluginandMarketplaceInstallLocalPluginstill read an explicit''throughresolveCloudUrl(as the default). They are outside this card's surface and are never composed with''byserve; noted, not filed.packages/services/service-push/vitest.config.tsgains one anchored alias,/^@objectstack\/spec\/contracts$/→../../spec/src/contracts/index.ts. Gate-forced:relay.tsnow imports a VALUE from that subpath, and without the aliascheck:test-source-aliasexits 1 on service-push ("tests import 1 workspace package(s) that resolve todist/with no source alias");KNOWN_UNALIASED_TEST_IMPORTSis shrink-only. With it the gate exits 0.push-plugin.test.tsis the other widened path (above).Metadata-protocol: none, re-derived from the diff: no metadata author writes a key, value or type this changes.Clause-②: yes (widening): one added export on@objectstack/spec/contracts.packages/cloud-connection/**orservice-push/**: only feat(console): put Connect an AI Assistant where each person looks, and call it that #30935, which editscloud-connection-ui.tsalone.Verification
At head
d1e31826(the merge oforigin/main3479c33; the two incoming commits touch none of this diff's packages). Package tests and ablations ran at9fdd39ad, the fix commit, which this head carries unchanged.Builds, typecheck, package tests
pnpm --filter @objectstack/spec build(lock VERDICT command-exit 0), thenpnpm --filter '@objectstack/cloud-connection^...' --filter '@objectstack/service-push^...' build(VERDICT command-exit 0).pnpm --filter @objectstack/cloud-connection test: Test Files 72 passed (72), Tests 925 passed (925).typecheckexit 0.pnpm --filter @objectstack/service-push test: Test Files 5 passed (5), Tests 74 passed (74).typecheckexit 0.pnpm --filter @objectstack/spec check:generatedbefore regeneration named exactlyapi-surface/andexport-origins/(plustest-typecheck-debt.json, whosetscexited without diagnostics against a stale dist; after a rebuild on the final headcheck:generatedexits 0 with all 14 artifacts current).Gates (dispatch-gates derivation, 88 families + 3 named)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 88 families atd1e31826(11 changed paths vs merge base 3479c33). All 88 pluspnpm lint,pnpm check:cli-command-idsandpnpm check:adr-symbol-anchors: 91 of 91 exit 0.packages/specdist readers exited 3 or 1 on a dist built before theorigin/mainmerge (declaration stamp mismatch:check:api-surface,check:browser-reachable-entries,check:dual-source-exports,check:entry-nameability,check:exported-anyexit 3,check:generatedexit 1 naming onlyapi-surface/), andcheck:dual-build-cjs-loadsexited 3 (no whole-tree dist). Afterpnpm --filter @objectstack/spec buildthe six exit 0; afterturbo run build --concurrency=2(82 of 82 tasks)check:dual-build-cjs-loadsexits 0 (116 require entries across 71 packages load).--ranreconciliation: 88 derived, 88 run, 0 NOT-MEASURED, 0 UNRUN (exit 0).pnpm check:test-source-aliasexits 1 without the new service-push alias and 0 with it.gates-ran-d1e31826.txt(seat project folder).Generated by Claude Code