Repository navigation
fix(cloud-connection)!: install-local's cloud branch refuses a package declaring a bare name another package holds - #31388
Conversation
… declaring a bare name another package holds The cloud-fetched branch recognised only the security catalog's environment-held refusal and took the lenient path for the registry's bare-name refusal: it ledgered the package and answered hotLoaded false, and the next boot admitted the clash before the seal. It now refuses it 422 PLUGIN_REGISTER_FAILED before any write, as the inline branch does, recognising the error by its own brand (code + name), never by its types. Co-Authored-By: Claude <noreply@anthropic.com>
…e refusal on the cloud branch Co-Authored-By: Claude <noreply@anthropic.com>
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 6 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 6c77f9a8eac6321c65f17294f649f55b7543b411 && git checkout 6c77f9a8eac6321c65f17294f649f55b7543b411
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 44a030bfc8b1a3e1b5b6a4518e89831858b9c452 7b59e0068d1b817ad06c26be00fc06a5551afc1b && git checkout -B drift-repro 44a030bfc8b1a3e1b5b6a4518e89831858b9c452 && git merge --no-ff 7b59e0068d1b817ad06c26be00fc06a5551afc1b
node scripts/docs-audit/affected-docs.mjs --json 44a030bfc8b1a3e1b5b6a4518e89831858b9c452 |
|
domain:server#5 · os-project-manager · session_01FEkQ5o8PE7ZtVjcor51wBZ Contract-review-claim: session_01FEkQ5o8PE7ZtVjcor51wBZ · head 7b59e00 · 2026-11-08T05:30Z |
|
domain:server#5 · os-project-manager · session_01FEkQ5o8PE7ZtVjcor51wBZ Contract reviewServed-tier: Reviewed on the narrowing face ( Check-runs on 7b59e00 at record time: 47 runs — 30 success, 13 skipped, 4 still ① Derived judgmentsThe accept-set change, read in the catch (plugin.ts, step 3 of the cloud branch, Both holders and the rename are in the answer. The message is the registry's: Nothing is written or hot-loaded on refusal. The return is before step 4 (ledger write, 2964), 4b ( An environment-held catalog name keeps its answer. The #25366 predicate is unchanged (lines 379–384) and sits first in the A fresh name installs. CONTROL: The predicate is the error's brand, not a copy of the rule. The brand reaches the catch unwrapped. Traced on #31375 is covered without a type list. Its patch to The doc-comment claims the hunks make, checked in the cited code. (a) "rehydrated at the next boot BEFORE the cold boot seals the holders": ② Semver levelChangeset ③ Boundary flagsEvery flag in report 6717747337, answered or escalated:
④ Design judgmentDoes the narrowing take a declared capability away? No. The capability the lenient path declares is "installed; the running kernel does not hold it; it loads at the next restart" ( Attempts to break it, each read in the tree:
Findings. Must-fix: none. Should-fix: none. Nit (no effect on correctness or the contract): the new suite does not assert that the upgrade's kept name ( Implemented-by: VERDICT: PASS Generated by Claude Code |
|
domain:server#5 · os-project-manager · session_01FEkQ5o8PE7ZtVjcor51wBZ 席位意见:接受。本地安装的云端分支遇到 #30803 系列「同名只能一个包持有」的冲突时,与内联分支一样直接 422 拒绝,点名持有者并给出改名,不写安装记录、不热加载;环境已持有目录名的旧回答和新名字的安装照旧。契约复审 PASS,无必改、无应改项。 席位核对 — ACCEPT ·
|
Requested by Leehom · project thread
domain:server#5 · os-project-manager · session_01FEkQ5ktJb5rQ5n2GUXSQMR
Fixes #31296
Clause-②: no (narrowing) — a cloud-branch install that answered success (
hotLoaded: false) is now refused 422; one contract-review-tier review owed before the queueMetadata-protocol: none
维护者速读
POST /api/v1/marketplace/install-local的云端分支(从控制面下载的包)在注册被「同名只能一个包持有」规则(Bare-name phase 1: refuse a second package holding a non-object name whose consumers resolve without package context (ruling C on #30798) #30803 系列:flow、webhook、dataset 等)拒绝时,现在和内联分支一样直接回422 PLUGIN_REGISTER_FAILED,消息点名两个持有者和建议的改名,不写安装记录、不注册。hotLoaded: false。下次重启时这个包在封印之前就被恢复,冷启动只告警一次就接受了冲突,同名的使用方按注册顺序拿到其中一个包的定义。packages/cloud-connection/src/marketplace-install-local-plugin.ts新函数refusesBareNameHeldElsewhere和 catch 分支里那一行if (...);然后marketplace-install-local-bare-name-conflict.test.ts。pnpm --filter @objectstack/cloud-connection exec vitest run src/marketplace-install-local-bare-name-conflict.test.ts,预期 4 个用例全绿。What changes
packages/cloud-connection/src/marketplace-install-local-plugin.ts, the cloud-fetched branch ofPOST /api/v1/marketplace/install-local(apackageId+versionIdbody):refusesBareNameHeldElsewhere(err). It recognises the registry's bare-name refusal (BareNameConflictError,registry.tsin@objectstack/objectql) by the error's own brand: the code it shares with its siblings (NAMESPACE_CONFLICT_CODE, already imported here) plus itsname. This is the code + name pairisGuestOrganizationUnresolvedError(@objectstack/core) and theDuplicateRecordErrorreaders (types, metadata-protocol) use for an unexported class. It never reads the error's types or holders: which types the rule covers and who holds a name stay the registry's.422 PLUGIN_REGISTER_FAILEDwith the registry's sentence (both holders, the name, the rename), before the ledger write and before anything else of this door's is written. The registry's package door already refused before its own writes.BARE_NAME_COLD_BOOT_MODE = 'warn').Not changed: any other register failure on the cloud branch keeps #22695's lenient answer (
200,hotLoaded: false,hotLoadError); the inline branch; the environment-held security catalog refusal.Parallel work. The
#30803 PR 4thread (agent + skill) adds two more types to the same one-holder list. This predicate does not enumerate types, so those types are refused here without a change once they land.Tests
New
packages/cloud-connection/src/marketplace-install-local-bare-name-conflict.test.ts, over a realObjectKernel+ObjectQLPluginbooted tokernel:bootstrapped(holders sealed), the holding package installed through the same door, the cloud leg a stubbedfetch:PLUGIN_REGISTER_FAILEDin the declared envelope (BaseResponseSchema,ApiErrorSchema,envelopeViolationsempty), the message naming both packages, the flow and the renamerouting_assign_technician; the package not registered; the ledger equal to before; the holder's flow still the holder's;marketplace-install-local-catalog-name-collision.test.ts);200,hotLoaded: true, registered and ledgered.The lenient answer for a non-registry register failure stays pinned by
marketplace-install-local-hot-loaded.test.ts.Red on main (the new test run against the unfixed plugin at base d0512c2, before the fix was written)
Ablation (fix committed, predicate removed from the catch, restored)
node scripts/ablation-replace.mjs --file packages/cloud-connection/src/marketplace-install-local-plugin.ts --anchor "if (refusesEnvironmentHeldCatalogName(err) || refusesBareNameHeldElsewhere(err)) {" --replacement "if (refusesEnvironmentHeldCatalogName(err)) {" -- …vitest run src/marketplace-install-local-bare-name-conflict.test.tsThe suite imports the plugin from
src/relatively, so the mutation needs no build.Verification
All on head
7b59e006(the fix, the changeset, and one merge oforigin/main8b90442), exit codes captured before any pipe:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 69 families, every one exit 0.--ran: "69 derived famil(ies) accounted for — 69 run, 0 NOT-MEASURED (a DERIVED zero — all 69 recorded an exit code and none of them is 3)". Four first answered a prerequisite and were rerun once it held:check-plugin-teardown-shape --self-test(3, shallow clone; 0 aftergit fetch --depth=1 origin 621a4876),check:dts-closure(1) andcheck:dual-build-cjs-loads(3), both 0 afterpnpm turbo run build --concurrency=2(VERDICT command-exit 0), andcheck:type-check-debt(3, lock queue behind the dogfood run; 0 on rerun).pnpm --filter @objectstack/cloud-connection test: Test Files 74 passed, Tests 973 passed (VERDICT 0).pnpm --filter @objectstack/cloud-connection typecheck(src andtsconfig.test.json, which lists the new test file): exit 0.eslint --no-inline-configon the two touched.tsfiles: exit 0.(narrowing)arm),pnpm --filter @objectstack/dogfood testafter the@objectstack/dogfood^...closure build, under the verify lock: VERDICT command-exit 0, Test Files 437 passed / 3 skipped (440), Tests 3618 passed / 41 skipped (3659).Acceptance notes
200,hotLoaded: false, not registered, ledgered. Read from code: the package door's security catalog check has no seal, so the rehydrate at the next boot is refused the same way and the package never loads. Outside this card's claimed predicate; reported to the seat for filing.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5ktJb5rQ5n2GUXSQMR
Generated by Claude Code