Description
domain:server#5 · os-project-manager · session_01FEkQ5o8PE7ZtVjcor51wBZ
Filing gate: ② routed from the contract review of PR #31093 (record 6714650391, should-fix 1: outside that PR's claimed surface). Read from code, not run. ⛔ Not a claim.
Reader: the seat that owns packages/cloud-connection/src/marketplace-install-local-plugin.ts (the cloud branch of POST /marketplace/install-local, refusesEnvironmentHeldCatalogName).
Dedupe (open AND closed): install-local BareNameConflictError, refusesEnvironmentHeldCatalogName bare-name, install-local cloud branch hotLoaded false conflict → none.
reach: every install-local of a control-plane package (cloud branch, inlineManifest false) that declares a name another installed package already holds for a bare-name type (#30803 series: dataset, mapping, the request family, flow, webhook, connector, email template); read from code.
class: a · type: Bug
Grade: p2 — self-graded by the server seat (Ruling-ref: the maintainer, 「定级你可以自己决定」): the same grade as the #30803 series whose refusal this door loses.
维护者速读
本地安装的云端分支在注册失败时,只把「环境已持有的目录名」当拒绝。#30803 系列的「同名只能一个包持有」冲突(BareNameConflictError,持有者是另一个包或内置)被当作可以晚点再加载:写入安装记录、回答成功(hotLoaded: false),下次启动在封印之前恢复这个包,冷启动只告警一次就接受了冲突。应当和内联分支一样直接拒绝(422),什么都不写。
What is wrong (read from code)
- The inline branch of
POST /marketplace/install-localrefuses a bare-name clash with 422PLUGIN_REGISTER_FAILEDbefore any write (pinned by the Bare-name phase 1: refuse a second package holding a non-object name whose consumers resolve without package context (ruling C on #30798) #30803 dogfood files). - The cloud branch (control-plane download) catches the registry's refusal and asks
refusesEnvironmentHeldCatalogName, which recognises onlyexistingHolder.kind === 'environment'. A bare-name refusal carriespackageorbuilt-in, so the door takes install-local: a cloud install whose hot-register fails answers 200 withhotLoaded: true(the lenient path), so a console says the app "should now appear" over a kernel that does not have it #22695's lenient path: the ledger entry is written and the answer is success withhotLoaded: false. - On the next boot the package is rehydrated before the seal, so the cold boot admits the clash with one warning (ruling B on Bare-name phase 1: refuse a second package holding a non-object name whose consumers resolve without package context (ruling C on #30798) #30803) and the consumers resolve the name as before the series.
- Predates PR feat(objectql)!: a flow, a webhook, a connector and an email template hold one name per package (bare-name phase 1, 3/4) #31093: PR 1's mechanism (feat(objectql)!: a picklist, mapping or dataset name holds one package (bare-name phase 1, 1/4) #30836), every covered type since
2a6a28db.
Expected
- The cloud branch refuses a bare-name clash the way the inline branch does: 422, both holders and the rename named, nothing written to the ledger. One predicate on that branch (recognise the registry's bare-name refusal), never a copy of the holder rule.
- Pins: cloud-branch install of a package declaring a held flow name → 422, ledger unchanged, nothing hot-loaded; CONTROL: an environment-held catalog name keeps its current answer; CONTROL: a fresh name installs.
Activity
objectstack-fleet commentedon Nov 8, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 ·
domain:server· confirmed · 2026-11-08T00:01Z⛔ Not a claim.
BareNameConflictError, held by a package or a built-in) as a load-later case. It writes the ledger entry, answershotLoaded: false, and the next cold boot admits the clash with a warning. The inline branch refuses it with 422. Read from code; it predates PR feat(objectql)!: a flow, a webhook, a connector and an email template hold one name per package (bare-name phase 1, 3/4) #31093.domain:serverlane (packages/cloud-connection) are confirmed.pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 8, 2026
domain:server#5 · os-project-manager · session_01FEkQ5o8PE7ZtVjcor51wBZ
Claim: PM loop round 1 · 2026-11-08T04:06Z
Session:
session_01FEkQ5ktJb5rQ5n2GUXSQMR(card thread, dev) · seatsession_01FEkQ5o8PE7ZtVjcor51wBZAccount:
os-project-managerBranch:
claude/project-thread-f6p2x0Worktree:
objectstack-issue-31296Domain:
domain:serverSeat:
domain:server#5File surface:
packages/cloud-connection/src/marketplace-install-local-plugin.ts(the cloud branch's refusal predicate) + its test(s), root.changeset/Container & model: M,
mode:thread,model: default tier(dispatch-gates --tier: no path-derived mandate),effort: thread defaultClause-②: 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
Responsibility:
cloud-connectioninstall-local cloud branch (objectstack) |refusesEnvironmentHeldCatalogNamerecognises only an environment holder, so a bare-name refusal takes #22695's lenient path | every cloud-branch install-local of a package declaring a name another package or a built-in holdsThread-read: 6714782060
Premise: holds (read, not run): on
origin/mainthe cloud branch's catch still asks onlyexistingHolder.kind === 'environment'; the dev re-measures red firstSerial constraints cleared: cleared — install-local PRs #31243, #31280, #31286 merged; #31283 (same file) runs second in this thread
Scope: Fixes #31296. One predicate recognising the registry's bare-name refusal, no type list, nothing written on refusal. Then #31283 in the same thread after this PR merges. Order:
/mnt/project-files/pm-orders/server/order-31296.md. Summons: the maintainer's 「server 再开两个座位」「并发都是5」 (this project, 2026-11-07); grading per 「定级你可以自己决定」 is triage's here (graded on the card).objectstack-fleet commentedon Nov 8, 2026
domain:server#5 · os-project-manager · session_01FEkQ5ktJb5rQ5n2GUXSQMR
os-dev-report
{
"issue": 31296,
"status": "done",
"branch": "claude/project-thread-f6p2x0",
"pr": "#31388",
"session": "session_01FEkQ5ktJb5rQ5n2GUXSQMR",
"premise_still_valid": true,
"summary": "Premise measured red on main d0512c2: a cloud-branch install-local of a package declaring a flow name another package holds answered 200 with hotLoaded false and ledgered it. The cloud branch now asks one new predicate, refusesBareNameHeldElsewhere, beside #25366's, and answers 422 PLUGIN_REGISTER_FAILED with the registry's sentence before any write. The predicate reads the error's own brand (NAMESPACE_CONFLICT_CODE plus name BareNameConflictError, the code+name pair isGuestOrganizationUnresolvedError and the DuplicateRecordError readers use for an unexported class) and enumerates no types or holders, so PR #31375 (#30803 PR 4: agent and skill) is covered with no change here. Card assignee untouched; pr_create carried no assignees.",
"tests": "New packages/cloud-connection/src/marketplace-install-local-bare-name-conflict.test.ts (real ObjectKernel + ObjectQLPlugin, holders sealed): fresh install 422 + upgrade 422 (both holders, flow, rename routing_assign_technician named; registry and ledger as before; holder's flow kept), CONTROL environment-held permission set still 422, CONTROL fresh flow name 200 hotLoaded true. RED on base d0512c2: 'Tests 2 failed | 2 passed (4)', 'expected 200 to be 422' with hotLoaded false. GREEN on head with the catalog-collision and hot-loaded suites: 'Test Files 3 passed (3) Tests 26 passed (26)'. ABLATION via scripts/ablation-replace.mjs (anchor 'if (refusesEnvironmentHeldCatalogName(err) || refusesBareNameHeldElsewhere(err)) {' -> without the bare-name arm): 'ok mutation landed: anchor 1 -> 0, blob 09ac8e820728 -> 2268f74afe54', 'Tests 2 failed | 2 passed (4)', 'ok restored: blob == HEAD (09ac8e820728) and git diff HEAD is empty'; the suite imports the plugin from src relatively, so no build or dist preflight applies. Package: pnpm --filter @objectstack/cloud-connection test 'Test Files 74 passed (74) Tests 973 passed (973)' VERDICT 0; typecheck (src + tsconfig.test.json, new file listed) exit 0; all on head 7b59e00.",
"gates": "Head 7b59e00. dispatch-gates --commands --repo objectstack-ai/objectstack: 69 families, all exit 0 (record /mnt/project-files/pm-orders/server/31296-gates-ran.txt). First-run prerequisite exits rerun: check-plugin-teardown-shape --self-test 3 -> 0 (git fetch --depth=1 origin 621a487), check:dts-closure 1 -> 0 and check:dual-build-cjs-loads 3 -> 0 after pnpm turbo run build --concurrency=2 (VERDICT 0), check:type-check-debt 3 (lock queued behind dogfood) -> 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)'. eslint --no-inline-config on the two touched .ts files exit 0. CI families: PR #31388 check-runs in_progress at report time, read by the seat.",
"dogfood_battery": "7b59e006 · os-verify-lock: VERDICT command-exit 0 (held 35m08s) · Test Files 437 passed | 3 skipped (440) · Tests 3618 passed | 41 skipped (3659) · no failures",
"mcp_calls": "0",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches, fleet-write run 42450892873, read-back identical, PR #31388) and this report comment via post-stamped.mjs; git push is not a REST write",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": [
"class: a · reach: POST /api/v1/marketplace/install-local cloud branch, measured with this PR's harness on a throwaway probe (not committed): a package shipping a permission set another installed package ships answers 200, hotLoaded false, not registered, ledgered; read from code: the package door's security catalog check (refuseSecurityCatalogNameConflicts) has no seal, so the rehydrate at the next boot is refused the same way and the package never loads, the false 'loads at next restart' #25366 closed for an environment holder only · evidence: refusesEnvironmentHeldCatalogName keeps existingHolder.kind === 'environment' · dedupe words: install-local security catalog package holder lenient, refusesEnvironmentHeldCatalogName package built-in, SecurityCatalogNameConflictError hotLoaded false"
],
"deviations": "none on file surface (one source file, one new test file, one changeset). Merged origin/main once (8b90442) before the PR; main moved 11 commits after, not re-merged. PR #31375 (agent/skill) had not landed at report time, so no AI-family pin (seat note: not owed)."
}
Generated by Claude Code