Repository navigation
fix(metadata-protocol): duplicatePackage renames a name that is also a field key only at object-reference sites - #24475
Conversation
…a field key only at object-reference sites A prefixed package object's name that is also a field key of a package object is no longer rewritten by the free-text rename: it may name the field (a list view's columns, a form's sections[].fields), which keeps its key. It is rewritten only at object-reference properties, as a bare object name already is. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D6F9axfoPzR7t8G1J7Ytzz
…plicate-object-name-token
📓 Docs Drift Check1 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 — 11 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 325c2fa7c14367abb5a9b52adb7896d5fb4435b9 && git checkout 325c2fa7c14367abb5a9b52adb7896d5fb4435b9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 31ce45c071bbcb6e92a730ce19ebf30dcfa361cb e7a7b375ed6e61d61346c7e4eae7cf7c93542b3b && git checkout -B drift-repro 31ce45c071bbcb6e92a730ce19ebf30dcfa361cb && git merge --no-ff e7a7b375ed6e61d61346c7e4eae7cf7c93542b3b
node scripts/docs-audit/affected-docs.mjs --json 31ce45c071bbcb6e92a730ce19ebf30dcfa361cb |
Review: ACCEPT · PR #24475 @
|
Fixes #23561
Clause-②: no
What this does
duplicatePackage(packages/metadata-protocol/src/protocol.ts, ADR-0070 D4) renamed a token that is BOTH a prefixed package object's name AND a field key as if it were the object, in free text. A field keyeddupsrc_customeron the objectdupsrc_customerkept its key on the copy, but a copied list view'scolumnsand a copied form'ssections[].fieldswere rewritten todupdst_customer, a field the copy does not have. Since PR #23559 the list view was refused at the copy (list-view-field-unknown). The form copied silently, with a dangling field.Triage ruling (comment 6181968665), direction B: "Rename such a name only at object-reference sites, never in free text. That extends the landed bare-name policy". C (also renaming the field) is ruled out.
The mechanism: before the free-text regex is built,
duplicatePackagecollects thefieldsrecord keys of every object row in the source package. A prefixed renamed object name that is also one of those keys is left out of the free-text regex. Such a name is then rewritten only by the existing object-reference path (REFERENCE_SITEStargetobject:object,reference,objectName, a permission set'sobjectskeys, and the rest), which is exactly how a bare object name is already handled. No second mechanism is added, andreference-sites.tsis not edited.acme_customeronacme_orderraises the same ambiguity in that order's list view. Package-wide is the superset of the two readings.description) naming such an object is now left as stored. A prefixed object that no field key spells is still renamed in free text, as a whole identifier, as before.Pins (
packages/objectql/src/protocol-duplicate-package-names-in-step.test.ts, real kernel: ObjectKernel + ObjectQLPlugin, memory driver)res.failedis empty (the list view is no longer refused) and both views are copied;['full_name', 'dupsrc_customer', 'x_dupsrc_customer'];sections[0].fieldsstay['full_name', 'dupsrc_customer'];objectandconfig.data.object, two lookupreferences, the actionobjectName, and the permission set'sobjectskey;engine.insertthrough the copied field key lands.Linked from dupdst_customernow reads the description unchanged, by the ruled semantics. The whole-identifier (left-boundary) rule it also guarded is re-pinned on a new prefixed object with no matching field key,dupsrc_note. That case expectsAttached to dupdst_note; see x_dupsrc_note., and the fieldx_dupsrc_notekeeps both its key and its name. So the guarded surface does not shrink.dupsrc_note, an ordinary prefixed object, is still renamed in free text.Ablation (through
scripts/ablation-replace.mjs). The anchorrenameMap.has(name) && !fieldKeys.has(name)went from 1 hit to 0 and was replaced by a marker literal (blob49c970959c61to1ea7b74ba948). Then: rebuild@objectstack/metadata-protocol, andablation-dist-preflightfound the marker in 2 built files. The pin file then readTests 5 failed | 1 passed (6). That is MORE diagnostics than the 2 red cases predicted: the copied list view'sdupdst_customercolumn is refused at the copy, sofailed[]is non-empty and cases 1, 3 and 4 go red as well. Restore: blob == HEAD,git diff HEADempty, rebuild,--absentpreflight (marker absent from all 24 built files), then the pin file readTests 6 passed (6).Tests and gates (head
e7a7b375ed, after mergingorigin/main26501ae24f)@objectstack/objectqlclosure was rebuilt after the merge (VERDICT command-exit 0).names-in-step,unprefixed-object,permission-field-keys,objects-key-collision,package-lifecycle):Test Files 5 passed (5),Tests 30 passed (30).pnpm --filter @objectstack/metadata-protocol exec vitest run:Test Files 246 passed | 3 skipped (249),Tests 20655 passed | 19 skipped.pnpm --filter @objectstack/metadata-protocol typecheckandpnpm --filter @objectstack/objectql typecheckboth exited 0 (check:test-typecheck: OK).--no-inline-config --format jsongives 2 files, 0 errors, 0 warnings.eslint.config.mjs, noparserOptions.project), so this diff cannot move any untouched file's verdict.@objectstack/spectest:repo:Test Files 61 passed (61),Tests 1033 passed (1033). This was measured atefed56ba5b, before the merge. This diff touches nopackages/specfile.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 69 commands ate7a7b375ed. Every exit was captured before any pipe.--ranprinted:69 derived famil(ies) accounted for — 68 run, 1 NOT-MEASURED.pnpm check:dual-build-cjs-loads, exit 3, PREREQUISITE NOT MET. It needs every package'sdist/, and a full build is outside this card's local scope. CI'sLint & Repo Gatesruns it.Acceptance notes
protocol.tsregion, the sibling pin file inpackages/objectql(where the family's pins live, see PR fix(metadata-protocol): duplicatePackage keeps a copied field's key and name, and a bare object's view item name, in step with what they name #23559), and the changeset.reference-sites.tsneeded no edit.ticket_views) is still renamed by the prefix swap alone. It is not addressed here.Changeset:
.changeset/23561-duplicate-object-name-token.md,@objectstack/metadata-protocolpatch.Session
session_01D6F9axfoPzR7t8G1J7Ytzz, os-dev fordomain:spec.Generated by Claude Code