feat: cross-package reference resolution contract (ADR-0041) — all 5 ports + conformance matrix#173
Merged
Merged
Conversation
…ence) + conformance matrix (ADR-0041) Every reference that names another object (@objectref, @references, origin @from/@of/@via, extends, @through, template refs) may cross package boundaries, but the ports had no shared, tested contract for name collisions across packages and ZERO cross-package conformance fixtures — which hid a real cross-port bug (Java resolves an explicit FQN to the wrong same-named package; investigation this session). Contract (ADR-0041): an FQN reference resolves EXACTLY to its package (never a bare-tail fallback); a BARE reference prefers the referrer's own package, else a unique object of that name anywhere, else ERR_AMBIGUOUS_REF (new). Preserves every unique-name case; only collisions change — from silent, arbitrary, port-divergent mis-binding to same-package preference or a loud, portable error. TS reference implementation: - `resolveObjectRef(root, ref, referrerPkg)` (naming-refs.ts) — the single object-ref resolver: FQN-exact; bare prefers referrer pkg, else unique, else ambiguous. - `validateCrossPackageRefs` loader pass emits ERR_AMBIGUOUS_REF for a bare ref that names an object in >1 package with none in the referrer's package (covers every REF_BEARING_ATTR_NAMES attr; strips origin dotted `.child` tails to the owner). extends stays FQN-strict via its own FR-032 super-resolver (bare cross-package extends → ERR_UNRESOLVED_SUPER). - ERR_AMBIGUOUS_REF registered in errors.ts + fixtures/conformance/ERROR-CODES.json. Conformance matrix (fixtures/conformance/xpkg-*, error-xpkg-*): every ref-bearing attr cross-package (unique-name working cases) + the collision contract (FQN-exact-across-collision via extends effective serialization — the fixture that catches the Java FQN-discard bug; bare same-package preference; bare-ambiguous → error). TS green: metadata 2111, codegen-ts 909, cli/render, typecheck clean. Residual (follow-up): codegen-ts resolution (relation-resolver/import-path) still bare-name first-match on a same-name collision — loader now guards it, codegen same-package preference is a separate pass. Port fan-out (Java/Python/C#/Kotlin) next, all conformance-gated against this matrix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ew1XfYSbEAezxjs9opynAe
…ion contract (ADR-0041) Fan-out of the TS reference (60bd97d). All 5 ports now pass the shared cross-package conformance matrix byte-identically. - Java (the confirmed bug): SymbolTable.nameMatches / ValidationPhase.nameMatches matched the ref's bare TAIL before the exact-FQN check, so an explicit FQN `xpkg::vendor::Customer` silently bound `xpkg::crm::Customer` (wrong package / wrong FK table). Now: an FQN ref (`ref.contains("::")`) resolves EXACTLY (`ref.equals(child.getName())`), never a bare-tail fallback; bare refs match the short name. Fixes xpkg-collision-extends-fqn (effective serialization now inherits from the correct package). - All ports: ERR_AMBIGUOUS_REF registered + a validateCrossPackageRefs pass emitting it for a bare object-ref that names an object in >1 package with none in the referrer's own package (mirrors the TS validateCrossPackageRefs). Python and C# already resolved FQNs exactly (no matcher bug), so they only added the ambiguity pass + resolver helper. - Codegen touched where it shared the bare-match bug (codegen-spring SpringM2mSupport, codegen-kotlin render helper); codegen same-package target-selection remains a follow-up (matching the TS residual note). Verified: Java ConformanceTest 420/0 + Kotlin conformance green; Python 323/0; C# 710/0. All emit ERR_AMBIGUOUS_REF on the ambiguity fixture and resolve the FQN-collision fixture to the correct package. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ew1XfYSbEAezxjs9opynAe
dmealing
added a commit
that referenced
this pull request
Jul 5, 2026
…ollision fixture Follow-up to PR #173. A code review found the Java M:N runtime/derivation resolvers still carried the exact bare-tail FQN mis-bind bug ADR-0041 closes (the same class as the confirmed bug, in the M:N path, Java-only — TS/Kotlin/C#/ Python M:N were already FQN-safe): - metadata M2MFields (the cross-port FK-derivation SSOT): findObject stripped an FQN to its bare tail and matched getShortName(); isSelfJoin / findRefToEntity compared stripped bare tails — so a cross-package hetero M:N with a same-named entity mis-classified as a self-join / bound the wrong junction reference. - omdb runtime M2MResolver.mustGetEntity: same stripPackage-then-short-name match on the FQN @objectRef/@through at runtime traversal. Fix (mirrors the SpringM2mSupport fix from #173): resolve the @objectRef/@through to an object FQN-exact (an FQN matches getName() exactly, never a bare-tail fallback), and classify self-join / match junction references by RESOLVED object identity, never a stripped tail. Bare-name/same-package behavior unchanged (the broader bare-collision same-package preference stays #174). Gated: new conformance fixture xpkg-m2n-collision (a cross-package M:N where the target + junction share a bare name with entities in other packages, referenced by FQN) — a bare-tail match would bind the wrong package. Expected generated from the TS oracle. Green in all metamodel-conformance ports: TS 422, Java 422, Python 324, C# 712 (Kotlin rides the shared Java loader). ADR-0041 Consequences corrected to name the files actually changed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ew1XfYSbEAezxjs9opynAe
dmealing
added a commit
that referenced
this pull request
Jul 5, 2026
…ollision fixture (#175) Follow-up to PR #173. A code review found the Java M:N runtime/derivation resolvers still carried the exact bare-tail FQN mis-bind bug ADR-0041 closes (the same class as the confirmed bug, in the M:N path, Java-only — TS/Kotlin/C#/ Python M:N were already FQN-safe): - metadata M2MFields (the cross-port FK-derivation SSOT): findObject stripped an FQN to its bare tail and matched getShortName(); isSelfJoin / findRefToEntity compared stripped bare tails — so a cross-package hetero M:N with a same-named entity mis-classified as a self-join / bound the wrong junction reference. - omdb runtime M2MResolver.mustGetEntity: same stripPackage-then-short-name match on the FQN @objectRef/@through at runtime traversal. Fix (mirrors the SpringM2mSupport fix from #173): resolve the @objectRef/@through to an object FQN-exact (an FQN matches getName() exactly, never a bare-tail fallback), and classify self-join / match junction references by RESOLVED object identity, never a stripped tail. Bare-name/same-package behavior unchanged (the broader bare-collision same-package preference stays #174). Gated: new conformance fixture xpkg-m2n-collision (a cross-package M:N where the target + junction share a bare name with entities in other packages, referenced by FQN) — a bare-tail match would bind the wrong package. Expected generated from the TS oracle. Green in all metamodel-conformance ports: TS 422, Java 422, Python 324, C# 712 (Kotlin rides the shared Java loader). ADR-0041 Consequences corrected to name the files actually changed. Claude-Session: https://claude.ai/code/session_01Ew1XfYSbEAezxjs9opynAe Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Every reference that names another object (
@objectRef,@references, origin@from/@of/@via,extends,@through, template refs) can cross package boundaries, but the ports had no shared, tested contract for name collisions across packages and zero cross-package conformance fixtures. That hid a real cross-port bug: with same-named entities in different packages, an explicit FQN@objectRef: "acme::vendor::Customer"resolved correctly in TS/C#/Python but bound the wrong package in Java (SymbolTable.nameMatches/ValidationPhase.nameMatchesmatched the ref's bare tail before the exact-FQN check → wrong FK table). Kotlin bare collisions were arbitrary first-match.Contract (ADR-0041)
ERR_AMBIGUOUS_REF(new). Author qualifies with the FQN to disambiguate.Preserves every unique-name case (bare or FQN); only collisions change — from silent, arbitrary, port-divergent mis-binding to same-package preference or a loud, portable error.
What's here
resolveObjectRef+validateCrossPackageRefsloader pass +ERR_AMBIGUOUS_REF.fixtures/conformance/xpkg-*,error-xpkg-*): every ref-bearing attr cross-package + the collision cases, incl.xpkg-collision-extends-fqnwhose effective serialization catches the Java FQN-discard bug.Verified — all 5 ports byte-identical green
Residual (follow-up, documented)
Codegen resolution (
codegen-tsrelation-resolver/import-path, and the JVM codegen helpers) still bare-name-first-match on a same-name collision — the loader now guards this (ERR_AMBIGUOUS_REF); codegen same-package target-selection is a separate pass, tracked for follow-up.🤖 Generated with Claude Code