Repository navigation
fix(objectql): the object fold names a field two extensions declare, and which definition it serves - #28876
Conversation
…lds, with the definition served The registry fold spreads each extension's fields, so a field name two extensions declare, or an extension redeclaring an owner field, serves the last contribution the fold applies. The fold now writes one warning per object, field and set of packages, naming every declaring package and the one served. The served definition is unchanged. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5nbGTknnd7qupVJNmN
…red-field line Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5nbGTknnd7qupVJNmN
…field branch # Conflicts: # packages/objectql/src/registry.ts
…t's key name Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5nbGTknnd7qupVJNmN
📓 Docs Drift CheckThis PR changes 1 package(s): 5 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 20 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 d923a25a156068d70ee9fdba31f14bd2e5f01b3d && git checkout d923a25a156068d70ee9fdba31f14bd2e5f01b3d
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 69c9f7c61a404bb7415f12f47878714aff411c99 ce7c7fa344c746dd5adcc9cf2c6ec45795f8bb08 && git checkout -B drift-repro 69c9f7c61a404bb7415f12f47878714aff411c99 && git merge --no-ff ce7c7fa344c746dd5adcc9cf2c6ec45795f8bb08
node scripts/docs-audit/affected-docs.mjs --json 69c9f7c61a404bb7415f12f47878714aff411c99
|
|
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo 席位核对ACCEPT · The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」.
Generated by Claude Code |
Requested by Leehom · project thread
Fixes #28835
Clause-②: no
Metadata-protocol: none
维护者速读
fields里声明了同名字段,或某个扩展在fields里重新声明了所有者自己的字段,注册表现在会在日志里记一行:对象、字段、按合并顺序列出的所有声明包,以及最终生效的是哪个包的定义。同一注册表只记一次。priority升序、同优先级按注册先后,后者直接覆盖前者,之前没有任何提示。feat(metadata-protocol,objectql): an object extension is an authorable item of a writable package, saved, published and exported through the existing doors (#28574) #28811 开放object_extension条目后,Studio 也能走到这条路径。warn,生效的定义一个字节不变,不拒绝任何东西,保存、发布、os validate都没动。仓库里出货的包和示例没有一处这样冲突。回滚即还原本 PR。packages/objectql/src/registry.ts的reportRedeclaredFields,以及foldExtendersOntoDefinition循环里新增的folded.push一行。pnpm --filter @objectstack/objectql exec vitest run src/registry-extension-redeclared-field.test.ts,预期 10/10。What changes
foldExtendersOntoDefinitionrecords each extension'sfieldsas the merge took them (after the audit andqueuegovernance), in fold order. After the loop,reportRedeclaredFieldsfinds every field name declared by more than one contributor: two extensions, or an extension and the owner (a name inownFieldNamesOf(owner), the set the field-patch judge already uses). For each, it writes oneconsole.warnnaming the object, the field, every declaring package in fold order (the owner first when it declares the field), and the package whose definition is served, which is the last one the fold applies.object|field|packagesin a per-registry set, besidefieldPatchMissesWarned. Repeated reads (getObject,foldObjectExtendersOnto, the code layer) do not repeat it; a second registry says it again.foldObjectExtendersOnto, a stored overlay row) is not read as a redeclaration.fieldPatches(not a declaration; a patch that misses is already named). A.custompair's__cfield and a dependent's plain field never share a name, so they never meet here; the__cjudge is untouched.os validateor the install door.content/docs/data-modeling/object-extensions.mdxsaid "nothing warns when they do"; it now says what the log names, and that the one registered last wins at equal priority.Why
The PR #28811 contract review (record
6565271420, should-fix 2) found that two extenders of one object declaring the same field name resolve last-writer-wins with no refusal and no report. The seat's route: report at the fold, keep today's winner, refuse nothing.Tests
packages/objectql/src/registry-extension-redeclared-field.test.ts, 10 cases.Warning cases (each asserts the served definition first, then the line):
regionat priority 200: the one registered last is served, one line names both and the served one;industry: one line names the owner, the extension and the served one;.custompairs both addingregion__c;Controls (nothing named): one extension adding its own field; a pair's
region__cbeside a dependent'sregion;fieldPatchesbeside an added field; a folded body handed back to the fold. Every case readsgetObject,foldObjectExtendersOntoandgetArtifactItemthree times with the cache dropped between.Red first and ablation (head ce7c7fa)
registry.tschecked out from main7e60dc23:Tests 6 failed | 4 passed (10). All six fail on the line count (expected [] to have a length of 1 but got +0); the served-definition assertions before them pass, so the winner is the same on main. Restore:git checkout HEAD -- packages/objectql/src/registry.ts,git diff HEADempty, porcelain empty.scripts/ablation-replace.mjs, thethis.reportRedeclaredFields(...)call replaced byvoid 0), run over this file andregistry-extension-field-patches.test.ts:Tests 6 failed | 21 passed (27), the same six warning cases; the four controls and objectql/cloud-connection: an option patch on an owner field that an extension takes over throughfieldsapplies in the registry fold but is refused at the install door and byos validate#28809's 17 stay green.ok restored: blob == HEAD (c47d8f140f3c) and git diff HEAD is empty, marker count 0../registry.jsfromsrc/, so nodist/leg is involved.Suites, typecheck, lint, gates (head ce7c7fa)
After merging main (with #28836) and a whole-repo
pnpm build(VERDICT command-exit 0):Test Files 524 passed (524),Tests 10036 passed (10036).pnpm typecheck: exit 0,check:test-typecheck: OK(39 files / 233 errors / 64 signatures held, unchanged).eslint --no-inline-configon the two touched source files: exit 0.console.warnbeside anextendregistration in other packages: restrest-exposure-gate-one-object-read37/37, runtimepackage-uninstall-store-refusal.integration5/5, cloud-connectionmarketplace-install-local-field-patch-targets8/8.dispatch-gates.mjs --commands: 92 derived, 92 run, all exit 0.--ran: 92 derived, 92 run, 0 NOT-MEASURED.check-nul-bytes.mjs: exit 0.Acceptance notes
packages/**,examples/**and HotCRM hold twoobjectExtensionsentries:examples/app-showcaseextends its ownshowcase_account(priority 210,loyalty_tier,linkedin_url,csat_score, none declared by the owner), andplugin-authextendssys_sso_provider(oidc_client_secret, not declared inplatform-objects). Different objects, so no fold sees two declarers. HotCRM declares none.packages/qa/downstream-contract(private) has one fixture extension ofdc_account, alone.dist/, every one of 54 objects read throughgetObjectandfoldObjectExtendersOnto: 0 lines. Positive control (a third extension redeclaringshowcase_account.nameandlinkedin_url): 2 lines, each naming the served package. Script: project filespm-orders/server/evidence/28835/boot-probe.mts.registry-object-overlay-layer.test.ts(a package extending its own object withname, the overlay counter-factual) and an audit-governance test (an extender declaringcreated_at, served with the platform'sreadonly). Neither asserts on warnings.fieldPatches, and their takeover cases redeclareindustry, so my line's first wording ("throughfieldPatches") matched their filter and failed 2 of their cases. The line now says "patch an owner field's display properties instead of redeclaring it", and both files pass 27/27.objectql/src/registry.tsor the docs page. Main is 4 commits ahead (fix(metadata-protocol)!: an object_extension item's refusals fit the item door, and its target is the key the object is registered under (#28834) #28853, fix(metadata-protocol): the per-package layer stamps a row with its own package's envelope, never another package's (#28831) #28857 and two others);git merge-treeis clean and none touches these files.patchfor@objectstack/objectql, withClause-②: noandMetadata-protocol: noneat line start: one log line, no accept set or served shape moves.Verification
Expect
Tests 10 passed (10).Human Minimum
packages/specchange.pnpm lintis CI's).packages/specnot touched.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5nbGTknnd7qupVJNmN