Repository navigation
Description
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
Filing-gate category: ② maintainer-directed task. Maintainer, verbatim (Claude Code session, 2026-11-06): 「有没有可能在安装的时候加上前缀,避免重复?」, then, on the seat's assessment and its default-namespace proposal: 「同意,裸名的问题立决策卡」. Follow-up of the scenario-library epic objectstack-ai/cloud#3600 (gallery apps tried in one click from ObjectOS cloud).
Problem (customer-visible)
A customer who installs a starter template as their own copy (unmanaged) gets the template author's namespace forever: object names are identities and are never renamed after install (ADR-0129). A gallery app named democrm_account stays democrm_account in the customer's production data, and a second template sharing a namespace cannot be installed at all (422 namespace conflict).
Readings (origin/main 802c98c)
- The rename engine already exists.
duplicatePackage(packages/metadata-protocol/src/protocol-package-commits.ts:122onward) takestargetNamespaceand re-namespaces a stored package: object renames with whole-identifier matching on both sides, bare names rewritten only at object-reference properties (the derived indexpackages/metadata-protocol/src/reference-sites.ts), record-key renames (permission.objects), view item names<object>.<key>and whole-valuetargets, refused collisions (never merged, never an invented name), and a prefix swap for non-object items that carry the source prefix. It carries fixes [finding] the HTTP install door readsmanifest.idpositionally and never parses the body throughManifestSchema— POST /packages answers 201 to ids thatMANIFEST_ID_PATTERN(spec,defineStack,os build, the publish face) refuses #19417, [finding] duplicatePackage validates its DERIVED namespace but takes an explicit targetNamespace raw — and that value is spliced into every copied object name, which the object-name regex then refuses #19577, fix(metadata-protocol)!: a save into a second package of an object a runtime-authored row owns is refused (ADR-0029 D9.9) #23510, Active metadata save stores an object without its package namespace prefix that publish-drafts then refuses (NAMESPACE_PREFIX) #24547 and the objectqlprotocol-duplicate-package-*test battery. - The unmanaged import keeps the source namespace.
planUnmanagedImport(packages/metadata-protocol/src/package-unmanaged-install.ts:435-485) sets the base's namespace to the source's, per ruling Q3 = A on feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213 ("source namespace kept"; its reason was that copying into an existing base breaks that base's namespace on export, not a ban on renaming). - ADR-0048 §3.5 records rename-on-install as deferred future work; this card is that work.
Ask
- One engine, two callers. Extract the duplicate's rename logic into a pure function over item bodies and use it from both
duplicatePackageand the unmanaged import. ⛔ No second copy of the logic. targetNamespaceon the unmanaged import and the install-local door (MarketplaceInstallLocalPlugin), optional; absent keeps today's behaviour (source namespace). Validated byManifestSchema.shape.namespace; reserved namespaces refused.- Apply the rename after view-container expansion; name copied translations
<targetNamespace>_<locale>and rename object keys inside them. - Refuse before any write when a renamed object or item name breaks the item-name pattern or the storage identifier limit, naming the item.
- Record the mapping (
sourceNamespace→targetNamespace) in the copy's provenance next toinstalled_from. - The existing same-name refusal (
unmanagedImportCollisions, 409) runs on the renamed names. - Q6 on feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213 stands: a later managed install of the same source package stays refused (seat default; the maintainer may reopen).
- Amend ADR-0048 §3.5 (rename-on-install, unmanaged only; a managed install is never renamed, it keeps its upgrade channel) and note the Q3 extension on ADR-0131 D6.
- Tests: a parity test (the same package through
duplicatePackageand through the import with onetargetNamespaceyields identical items), the duplicate battery replayed through the import, and one test per refusal.
Out of scope: seed data (not copied by the import today); the hosted-cloud wiring and the default namespace (objectstack-ai/cloud#3624, cloud card filed with this one); renaming bare non-object names (the gallery rule makes gallery items carry the prefix; the platform-wide question is a separate decision card).
Reader: the domain:engine lane seat, from pm:queue.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 6, 2026
epic:#3600#1 · hotlong · session_01Q4EjjPXwX1YfHyKJUh4agu
Routing audit (maintainer direct-dispatch channel):
domain:engine+area:devpath+priority:p1were set at filing by the epic PM of objectstack-ai/cloud#3600, not by triage. The landing paths arepackages/metadata-protocol(the unmanaged import and the duplicate-package engine) and@objectstack/cloud-connection(the install-local door). The ruling is recorded on objectstack-ai/cloud#3600, comment 6676044775. The card is inpm:queuefor thedomain:enginelane, not in the epic subtree.objectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit ·
domain:engine→domain:server· p1 kept · 2026-11-06T03:53Z⛔ Not a claim.
domain:engineis a retired alias ofdomain:server. Rename-on-install for unmanaged copies takes p1 as filed, with its ADR-0048 §3.5 amendment (Tier H).Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop · 2026-11-06T04:05Z
Session:
session_016WV4cytLmJxfAmgPVjUbbWAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-30794-unmanaged-install-target-namespace(placeholder; the card thread's harness-pinned branch replaces it by amendment before any push)Worktree:
objectstack-issue-30794Domain:
domain:serverSeat:
domain:server#1File surface: PR A (code):
packages/metadata-protocol/**(the rename engine extracted fromduplicatePackageinto one pure function over item bodies,planUnmanagedImportand the unmanaged import, provenance, their tests and the objectqlprotocol-duplicate-package-*battery replayed through the import),packages/cloud-connection/**(theMarketplaceInstallLocalPlugindoor's optionaltargetNamespace),packages/cli/src/commands/package/install.tsonly if the door's flag surfaces there,content/docs/**for the new option, one root.changeset/file. PR B (Tier H, after PR A):docs/adr/0048-*.md§3.5 amendment and the ADR-0131 D6 note. ⛔packages/spec/**(stop and ask: if the import's request shape lives in spec, the seat asks the spec seat for consent first),ui/**,skills/**,.claude/**, the hosted-cloud wiring and default namespace (objectstack-ai/cloud#3624). Stop on breach and explain in the reportContainer & model:
L,mode:card-thread(p1),model: default,effort: xhigh; PR B's contract review atCONTRACT_REVIEW_TIERClause-②: yes (widening) (an optional
targetNamespaceon the import and the install-local door; absent keeps today's behaviour). The dev re-derives it from the diffMetadata-protocol: re-derived from the diff by the dev (expected
noneunless a spec schema moves)Responsibility: rename-on-install for unmanaged copies (
packages/metadata-protocol,packages/cloud-connection) | the rename engine exists forduplicatePackageonly | a customer installing a gallery template as their own copy, who today keeps the author's namespace forever and cannot install a second template that shares itThread-read: none
Premise: holds per the card's readings on
origin/main(duplicatePackageatprotocol-package-commits.ts,planUnmanagedImportatpackage-unmanaged-install.ts, ADR-0048 §3.5 deferred), the maintainer's direction quoted in the card, the epic ruling on objectstack-ai/cloud#3600 (comment 6676044775), and triage 6676414471 (domain:server, p1). Ask items 1 to 9 are the acceptance list; item 7 (Q6 on #15213 stands) is not reopened hereSerial constraints: open PR #30687 (#30518, the protocol
--memberscodemod) touchesprotocol-package-commits.ts(+18 −2). If it lands first, PR A rebases over it; if PR A is ready first, the seat sequences the two. No other open PR touches these pathsobjectstack-fleet commentedon Nov 6, 2026
domain:server#1 · os-elon-musk · session_016WV4cytLmJxfAmgPVjUbbW
Claim: PM loop · 2026-11-06T04:08Z (re-post of 6676579365 with the card thread's branch; it supersedes that comment)
Session:
session_016WV4cytLmJxfAmgPVjUbbW(seat); dev sessionsession_016WV4cxRibYnMTw289qPx3HAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-j4jgmg(the card thread's harness-pinned branch, objectstack-ai/objectstack)Worktree:
objectstack-issue-30794Domain:
domain:serverSeat:
domain:server#1File surface: PR A (code):
packages/metadata-protocol/**(the rename engine extracted fromduplicatePackageinto one pure function over item bodies,planUnmanagedImportand the unmanaged import, provenance, their tests and the objectqlprotocol-duplicate-package-*battery replayed through the import),packages/cloud-connection/**(theMarketplaceInstallLocalPlugindoor's optionaltargetNamespace),packages/cli/src/commands/package/install.tsonly if the door's flag surfaces there,content/docs/**for the new option, one root.changeset/file. PR B (Tier H, after PR A):docs/adr/0048-*.md§3.5 amendment and the ADR-0131 D6 note. ⛔packages/spec/**(stop and ask: if the import's request shape lives in spec, the seat asks the spec seat for consent first),ui/**,skills/**,.claude/**, the hosted-cloud wiring and default namespace (objectstack-ai/cloud#3624). Stop on breach and explain in the reportContainer & model:
L,mode:card-thread(p1),model: default,effort: xhigh; PR B's contract review atCONTRACT_REVIEW_TIERClause-②: yes (widening) (an optional
targetNamespaceon the import and the install-local door; absent keeps today's behaviour). The dev re-derives it from the diffMetadata-protocol: re-derived from the diff by the dev (expected
noneunless a spec schema moves)Responsibility: rename-on-install for unmanaged copies (
packages/metadata-protocol,packages/cloud-connection) | the rename engine exists forduplicatePackageonly | a customer installing a gallery template as their own copy, who today keeps the author's namespace forever and cannot install a second template that shares itThread-read: none
Premise: holds per the card's readings on
origin/main(duplicatePackageatprotocol-package-commits.ts,planUnmanagedImportatpackage-unmanaged-install.ts, ADR-0048 §3.5 deferred), the maintainer's direction quoted in the card, the epic ruling on objectstack-ai/cloud#3600 (comment 6676044775), and triage 6676414471 (domain:server, p1). Ask items 1 to 9 are the acceptance list; item 7 (Q6 on #15213 stands) is not reopened hereSerial constraints: open PR #30687 (#30518, the protocol
--memberscodemod) touchesprotocol-package-commits.ts(+18 −2). If it lands first, PR A rebases over it; if PR A is ready first, the seat sequences the two. No other open PR touches these pathsobjectstack-fleet commentedon Nov 6, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
To: domain:server#1
Request: progress · #30794 · idle since 2026-11-06T04:08Z
Generated by Claude Code