Repository navigation
Closed
Labels
area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpm:blockingDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-setDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-setpriority:p1High: required for production / M2High: required for production / M2
Description
domain:server#3 · os-steve · session_01ADHkmQXLfvyB5R53VDm3Ka
Epic: ADR-0150 (#31527). Split from #32071 by seat 3's step-0 ruling. Blocked-by: #32071 (same file, same seat, serial). Blocks: #31700. Lane: domain:server.
Today (after #32071)
POST /data/:object/importwithmappingNameresolves the mapping by D3 with no caller package. That fits an HTTP door with no package context: every one-holder answer stays as today, including a mapping imported into an object another package owns.- A name two packages hold answers 409 naming both, and the door has no way to name the holder. Once objectql: narrow the phase-1 one-holder refusal from environment to namespace for picklist, mapping, dataset, api and function (ADR-0150 child B, picklist family) #31700 lets two namespaces hold one mapping name, neither holder's mapping can be imported by name.
- Resolving by the target object's owner is ruled out. Step 0 of rest: import mappingName and connector pull resolve the mapping by package (ADR-0150 D3; reader before #31700) #32071 measured a narrowing: a third package's mapping that imports into a dependency's object goes from 200 to 409
outside-closure.
Do
- Step 0: propose the qualified spelling for the import door, for example
mappingNameaccepting the qualified address, or a package parameter. Reuse G1's qualifier and G2's namespace→package mapping, and never build a second one. Show that every unqualified request keeps rest: import mappingName and connector pull resolve the mapping by package (ADR-0150 D3; reader before #31700) #32071's answer. The seat rules on the name. - A qualified request reaches exactly its holder. A qualifier naming a non-holder is refused with the same shape as the
/metadoor'snot-held-by-qualifier.
Clause-②: yes (widening) is expected, because only a new optional spelling is added. Step 0 confirms it.
Pins: a bare request with two holders still answers 409; each qualified request answers 200 against its own holder; a non-holder qualifier is refused; with one holder, every answer is byte-identical to today; ablating the qualifier arm turns the pins red.
Epic red-line review before landing.
Metadata
Metadata
Assignees
Labels
area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterateThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:serverDomain lane — seat card indexed by label:pm:seatDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestNew feature or requestpm:blockingDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-setDerived cache from the Blocked-by reverse index: open card with open dependents — never hand-setpriority:p1High: required for production / M2High: required for production / M2
Activity
objectstack-fleet commentedon Nov 10, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: confirmed ·
domain:server· p1 ·pm:blocked·pm:blocking· 2026-11-10T06:56ZBlocked-by: #32071
⛔ Not a claim.
**Blocked-by:** #32071mid-line, which the sweep does not read. The line above makes it readable. rest: import mappingName and connector pull resolve the mapping by package (ADR-0150 D3; reader before #31700) #32071 is open and dispatched, and is the same seat's serial predecessor on the same file.domain:server(the import door's qualified mapping address). p1 is inherited from design(metadata): address behavioural metadata by package — key flows, actions, jobs and other non-object types by (package, name); re-open ADR-0028 (replaces #30806 phase 3 renames) #31527.Blocked-by: #32079, sopm:blockingis added. It is linked as a sub-issue of design(metadata): address behavioural metadata by package — key flows, actions, jobs and other non-object types by (package, name); re-open ADR-0028 (replaces #30806 phase 3 renames) #31527 this round.Generated by Claude Code
fix(objectql, rest, service-automation): a mapping name two packages …
objectstack-fleet commentedon Nov 11, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: unblocked →
pm:queue·domain:server· p1 · 2026-11-11T00:55Z⛔ Not a claim.
domain:server#3(the seat that split it) was sentNotify: unblocked.Generated by Claude Code
objectstack-fleet commentedon Nov 11, 2026
domain:server#6 · huangyiirene · session_01J8VVAnTcb4cZVkPdhkPicW
Claim: PM loop round 3
Session:
session_01J8VVAnTcb4cZVkPdhkPicWAccount:
huangyiireneBranch:
claude/issue-32079-import-mapping-qualifierWorktree:
objectstack-issue-32079Domain:
domain:serverSeat:
domain:server#6File surface:
packages/rest/src/import-prepare.tsandpackages/rest/src/import-mapping.ts(the import door'smappingNameresolution and its qualified spelling), their tests, the import docs page undercontent/docs/**if the new spelling needs a line; root.changeset/. ⛔ Read-only reuse of metadata-protocolprotocol-exact-qualifier.ts(G1's qualifier) and the G2 namespace→package mapping: open PRs #32214 and #32361 edit that file, so this card never edits it. ⛔ Notpackages/spec/**: stop and report if the spelling needs a schema change. (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default tier (dispatch-gates --tier: "floor sonnet · default opus · ceiling fable"; PM judgment: default),effort: xhighClause-②: yes
Metadata-protocol: none
Responsibility:
n/a — not a defect cardThread-read: 6783698935
Premise: holds (#32071 closed as completed via PR #32294, merged 2026-11-11T00:42Z;
import-mapping.ts:96on origin/main resolvesgetMetaItem({ type: 'mapping', name: mappingName })with no qualifier)Serial constraints cleared: #32071 landed (the card's named predecessor). No open PR touches
packages/rest/src/import-*.ts(every open PR's file list read at claim). #31700 is blocked by this card. #32183 (seat 3, PR #32327) changespackageScopedHoldersOf, which this card reads throughgetMetaItem; step 0 re-reads it on the tip.Maintainer scope order: the maintainer, in this seat's session, 2026-11-11T05:23Z: 「后续只处理 p1 任务」. This seat now dispatches only p1 cards.
Claimed at 2026-11-11T05:27Z.
objectstack-fleet commentedon Nov 11, 2026
domain:server#6 · huangyiirene · session_01J8VVAnTcb4cZVkPdhkPicW
os-dev-report
{ "issue": 32079, "status": "done", "branch": "claude/issue-32079-import-mapping-qualifier", "pr": "https://github.com/objectstack-ai/objectstack/pull/32413", "head": "280e939300d4e2a2fb6485e5e1cba697a6e0cb2f", "session": "session_01J8VVAnTcb4cZVkPdhkPicW", "premise_still_valid": true, "summary": "Step 0 follows the seat's ruling: the import door reuses the /meta door's qualified address and adds no key. mappingName 'NAMESPACE/NAME' or '_env/NAME' goes to the protocol's own resolveMetaItemAddress and then the exact qualifier (getMetaItem with packageId, i.e. admitExactQualifier) or admitEnvironmentQualifier. That is G1's qualifier and the namespace-to-package mapping in protocol-exact-qualifier.ts, read as a service and not edited. The holder's mapping is imported. A non-holder qualifier is refused 409 RESOURCE_CONFLICT with the not-held-by-qualifier sentence; its code and error equal GET /meta/mapping/NS/NAME on the same server. A name with no '/' sends the identical getMetaItem argument, and its answers are byte-identical to the base tree (pinned). A string that is no address reads the whole string as before (404), never the part after the '/'. A 'package' body key was measured and not built: ImportRequestSchema.parse drops an undeclared 'package' key, so it needs a spec change, which is the stop condition. On the card's own texts: Do 2 asks for the /meta door's shape, and the pins ask that bare answers stay #32071's. The import 409 matches /meta on status, code and sentence, but carries no details.candidates. /meta has carried that member since #32272, which landed after the card was written. Adding it would change the bare two-holder bytes, and the body is written in data-action-routes.ts, outside the surface. This is stated in the PR's Acceptance notes for the seat to judge.", "tests": "packages/rest/src/import-integration.test.ts gains a #32079 block on the real ObjectQL engine, protocol and sqlite store: two-holder qualified 200s; non-holder 409 equal to /meta; one-holder own/other namespace; the _env pair; no-address 404s; one-holder byte identity. At 280e939300 (locked: rebuild of rest^... exit 0, then the import files plus meta-qualified-item-route.test.ts): Test Files 4 passed (4), Tests 105 passed (105), rest typecheck exit 0, VERDICT command-exit 0. At a994aa8593: rest local suite Test Files 404 passed (404), Tests 7831 passed | 332 skipped. At ea9dee067f: rest local suite 404 files, 7824 passed | 332 skipped. Ablation at ea9dee067f via scripts/ablation-replace.mjs (WRAP mode): the qualifier arm was replaced by 'return bare;', and the anchor going 1 to 0 and blob 831e0167 to 29366dac show it landed. -t 3207 answered Tests 4 failed | 5 passed: the 4 qualified pins red, #32071's 3 pins plus the no-address and byte-identity pins green. Restore proven: blob 831e0167 equals HEAD and git diff HEAD is empty. Base measurement: under an EXIT INT TERM trap, the base tree 662fbf80's import-mapping.ts was swapped in. The byte pin's reads assertion passed and the five answers were captured as BARE_ONE_HOLDER_WIRE. Restored, and both blobs equal HEAD. eslint --no-inline-config on the 3 changed .ts files: exit 0. test:repo was not run locally (no file of that project is touched); CI's Test Core covers it.", "gates": "dispatch-gates --commands names 95 families for the 5 paths, the same list at ea9dee067f, a994aa8593 and 280e939300. --ran reconciliation at 280e939300: 95 derived, 95 run, 0 unrun. Local sweep at 280e939300: 91 exited 0 on the first pass. check:docs (1), check:skill-examples (3) and check:lean-entry-closure (1) read a dist that the concurrent locked rebuild was rewriting. Each was re-run after the rebuild and exited 0 ('247 generated files in sync', '344 prose examples type-check', 'Admitted set held exactly'). check:type-check-debt hit its own lock queue-timeout (exit 3), so it is NOT MEASURED locally; CI 'Type Check · debt ledger' is success at 280e939300. Sweep at a994aa8593: 93 exit 0; check:skill-examples was re-run, exit 0; check:dual-build-cjs-loads was a prerequisite refusal there and exited 0 at 280e939300 (122 entries across 72 packages load). CI at 280e939300 (53 check-runs: 38 success, 15 skipped, 0 failure): Lint & Repo Gates success, TypeScript Type Check success, Test Core success (8/8 shards), Build Core success, Governed Surface Queue Guard success, Check Changeset success, Test UI success, Live E2E UI success, Dogfood Regression Gate success. Lint UI, Type Check UI and Build & E2E UI were skipped by their path selectors. The dogfood shards are queue-only.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0 — no MCP GitHub calls", "api_writes": "2 relay strokes — fleet-write pr_create (POST /repos/objectstack-ai/objectstack/dispatches; the relay ran POST /repos/objectstack-ai/objectstack/pulls and POST /repos/objectstack-ai/objectstack/issues/32413/assignees, read back identical, assignee huangyiirene) and this os-dev-report comment through post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/32079/comments); git push is not counted", "files_changed": [ ".changeset/32079-import-mapping-qualifier.md +12/-0", "content/docs/data-modeling/import-mappings.mdx +19/-6", "packages/rest/src/import-integration.test.ts +199/-1", "packages/rest/src/import-mapping.ts +74/-4", "packages/rest/src/import-prepare.ts +2/-0" ], "line_budget": "n/a — no skills/** path; 317 changed lines (+306/-11), under the 3000 human-merge threshold", "deviations": [ "Merged origin/main twice: a994aa8593 before the PR opened (AGENTS §10), and 280e939300 on the resume order. The 7 later main commits touch none of the 5 paths, nor rest, core, objectql or metadata-protocol, and are not merged.", "The PR body is create-only. It cites readings up to a994aa8593 and points to this comment for the 280e939300 re-check.", "Four stray files were written to the filesystem root by a shell-variable scoping slip in background launches: /build.pid, /gates.pid, /rest-test2.pid, /run-gates.out. Removing them was refused by a safety check, so they are left for a person to delete; they are not in the repository.", "One test run spelled with a bare '--' was stopped by its recorded pids before any reading was used, and was re-run as 'vitest run --project local --maxWorkers=2'.", "The two merge commits carry git's default merge message without the trailer pair; the pre-push hook accepted them." ], "open_questions": [], "security_findings": "none", "out_of_scope_findings": [ "carrier: domain:server#6 · noted, not filed — the import door's 409s (#32071's bare one and this qualified one) carry no details.candidates, while /meta's do since #32272. Seam: rest data-action-routes.ts writes { code, error } for every prepare failure. Adding the member widens both answers; it is the seat's call against card #32079's 'same shape'.", "carrier: none · noted in Acceptance notes — ImportRequestSchema.mappingName's .describe() (packages/spec/src/api/export.zod.ts) still describes the pre-#32071 resolution and not the qualified spelling: spec prose, no schema change needed.", "carrier: none · noted — a 501 NOT_IMPLEMENTED from the qualifier (an engine without the package-scoped reads, never a production composition) is answered 404 by the import door's catch, as the bare read already is on main.", "carrier: ui lane, after #31700 · noted — the Console import wizard (ui/packages/plugin-grid ImportWizard.tsx) sends bare mapping names and would need NAMESPACE/NAME once two namespaces hold one name; plugin-auth's identity import passes only getMetaItem, so the qualified spelling is no address there.", "carrier: none · noted — two packages of a shareable namespace (base, system, sys) holding one mapping name, or a mapping named like a /meta sub-resource literal, have no qualified import spelling. This is the /meta qualified path's own limit (seat ruling Q1 = A on #31691); /meta reaches them with ?package=." ] }objectstack-fleet commentedon Nov 11, 2026
domain:server#6 · huangyiirene · session_01J8VVAnTcb4cZVkPdhkPicW
Landed · #32079 · 2026-11-11T15:44Z
PR #32413 merged through the queue at 2026-11-11T15:35Z as
f97a2d9a. The import door'smappingNamenow also takes the/metadoor's qualified addresses,NAMESPACE/NAMEand_env/NAME, through the same exact-qualifier resolution. A non-holder qualifier answers as/metadoes. Bare names are byte-identical to before. The card was closed byFixes; the seat removespm:dispatched. #31700, blocked by this card, is triage's to re-check for unblocking.