@metaobjectsdev/metadata 1.0.13 → 1.1.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (233) hide show
  1. package/README.md +2 -0
  2. package/dist/attr-schema-validate.d.ts.map +1 -1
  3. package/dist/attr-schema-validate.js +9 -12
  4. package/dist/attr-schema-validate.js.map +1 -1
  5. package/dist/constants.d.ts +1 -0
  6. package/dist/constants.d.ts.map +1 -1
  7. package/dist/constants.js +1 -0
  8. package/dist/constants.js.map +1 -1
  9. package/dist/core/attr/meta-attr-filter.d.ts.map +1 -1
  10. package/dist/core/attr/meta-attr-filter.js +8 -2
  11. package/dist/core/attr/meta-attr-filter.js.map +1 -1
  12. package/dist/core/attr/meta-attr.d.ts +14 -0
  13. package/dist/core/attr/meta-attr.d.ts.map +1 -1
  14. package/dist/core/attr/meta-attr.js +23 -1
  15. package/dist/core/attr/meta-attr.js.map +1 -1
  16. package/dist/core/field/shared-enum.d.ts +21 -0
  17. package/dist/core/field/shared-enum.d.ts.map +1 -0
  18. package/dist/core/field/shared-enum.js +49 -0
  19. package/dist/core/field/shared-enum.js.map +1 -0
  20. package/dist/core/identity/meta-identity.d.ts +1 -1
  21. package/dist/core/identity/meta-identity.d.ts.map +1 -1
  22. package/dist/core/identity/meta-identity.js +8 -13
  23. package/dist/core/identity/meta-identity.js.map +1 -1
  24. package/dist/core/index.d.ts +2 -0
  25. package/dist/core/index.d.ts.map +1 -1
  26. package/dist/core/index.js +3 -0
  27. package/dist/core/index.js.map +1 -1
  28. package/dist/core/object/object-constants.d.ts +14 -1
  29. package/dist/core/object/object-constants.d.ts.map +1 -1
  30. package/dist/core/object/object-constants.js +18 -0
  31. package/dist/core/object/object-constants.js.map +1 -1
  32. package/dist/core/object/object-definition.embedded.d.ts.map +1 -1
  33. package/dist/core/object/object-definition.embedded.js +80 -0
  34. package/dist/core/object/object-definition.embedded.js.map +1 -1
  35. package/dist/core/relationship/derive-m2m-fields.d.ts +1 -1
  36. package/dist/core/relationship/derive-m2m-fields.d.ts.map +1 -1
  37. package/dist/core/relationship/derive-m2m-fields.js +15 -44
  38. package/dist/core/relationship/derive-m2m-fields.js.map +1 -1
  39. package/dist/core/relationship/find-reference.d.ts.map +1 -1
  40. package/dist/core/relationship/find-reference.js +4 -2
  41. package/dist/core/relationship/find-reference.js.map +1 -1
  42. package/dist/core/relationship/resolve-relationship-reference.d.ts +6 -5
  43. package/dist/core/relationship/resolve-relationship-reference.d.ts.map +1 -1
  44. package/dist/core/relationship/resolve-relationship-reference.js +9 -7
  45. package/dist/core/relationship/resolve-relationship-reference.js.map +1 -1
  46. package/dist/core/reporting/meta-dimension.d.ts +13 -0
  47. package/dist/core/reporting/meta-dimension.d.ts.map +1 -0
  48. package/dist/core/reporting/meta-dimension.js +30 -0
  49. package/dist/core/reporting/meta-dimension.js.map +1 -0
  50. package/dist/core/reporting/meta-measure.d.ts +24 -0
  51. package/dist/core/reporting/meta-measure.d.ts.map +1 -0
  52. package/dist/core/reporting/meta-measure.js +54 -0
  53. package/dist/core/reporting/meta-measure.js.map +1 -0
  54. package/dist/core/reporting/meta-segment.d.ts +6 -0
  55. package/dist/core/reporting/meta-segment.d.ts.map +1 -0
  56. package/dist/core/reporting/meta-segment.js +13 -0
  57. package/dist/core/reporting/meta-segment.js.map +1 -0
  58. package/dist/core/reporting/report-accessors.d.ts +27 -0
  59. package/dist/core/reporting/report-accessors.d.ts.map +1 -0
  60. package/dist/core/reporting/report-accessors.js +56 -0
  61. package/dist/core/reporting/report-accessors.js.map +1 -0
  62. package/dist/core/reporting/report-describe.d.ts +59 -0
  63. package/dist/core/reporting/report-describe.d.ts.map +1 -0
  64. package/dist/core/reporting/report-describe.js +182 -0
  65. package/dist/core/reporting/report-describe.js.map +1 -0
  66. package/dist/core/reporting/report-read-model.d.ts +34 -0
  67. package/dist/core/reporting/report-read-model.d.ts.map +1 -0
  68. package/dist/core/reporting/report-read-model.js +165 -0
  69. package/dist/core/reporting/report-read-model.js.map +1 -0
  70. package/dist/core/reporting/report-shape.d.ts +103 -0
  71. package/dist/core/reporting/report-shape.d.ts.map +1 -0
  72. package/dist/core/reporting/report-shape.js +398 -0
  73. package/dist/core/reporting/report-shape.js.map +1 -0
  74. package/dist/core/reporting/reporting-constants.d.ts +65 -0
  75. package/dist/core/reporting/reporting-constants.d.ts.map +1 -0
  76. package/dist/core/reporting/reporting-constants.js +84 -0
  77. package/dist/core/reporting/reporting-constants.js.map +1 -0
  78. package/dist/core/reporting/reporting-definition.embedded.d.ts +3 -0
  79. package/dist/core/reporting/reporting-definition.embedded.d.ts.map +1 -0
  80. package/dist/core/reporting/reporting-definition.embedded.js +185 -0
  81. package/dist/core/reporting/reporting-definition.embedded.js.map +1 -0
  82. package/dist/core/requirement/resolve-claim.d.ts +8 -0
  83. package/dist/core/requirement/resolve-claim.d.ts.map +1 -1
  84. package/dist/core/requirement/resolve-claim.js +21 -0
  85. package/dist/core/requirement/resolve-claim.js.map +1 -1
  86. package/dist/core/yaml-desugar.d.ts.map +1 -1
  87. package/dist/core/yaml-desugar.js +12 -82
  88. package/dist/core/yaml-desugar.js.map +1 -1
  89. package/dist/core-types.d.ts.map +1 -1
  90. package/dist/core-types.js +28 -1
  91. package/dist/core-types.js.map +1 -1
  92. package/dist/docs-ref.d.ts +19 -0
  93. package/dist/docs-ref.d.ts.map +1 -0
  94. package/dist/docs-ref.js +37 -0
  95. package/dist/docs-ref.js.map +1 -0
  96. package/dist/errors.d.ts +1 -1
  97. package/dist/errors.d.ts.map +1 -1
  98. package/dist/errors.js +17 -6
  99. package/dist/errors.js.map +1 -1
  100. package/dist/fmt.d.ts.map +1 -1
  101. package/dist/fmt.js +3 -1
  102. package/dist/fmt.js.map +1 -1
  103. package/dist/index.d.ts +15 -4
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +18 -4
  106. package/dist/index.js.map +1 -1
  107. package/dist/loader/declared-duplicate-fields.d.ts +19 -0
  108. package/dist/loader/declared-duplicate-fields.d.ts.map +1 -0
  109. package/dist/loader/declared-duplicate-fields.js +97 -0
  110. package/dist/loader/declared-duplicate-fields.js.map +1 -0
  111. package/dist/loader/meta-data-loader.d.ts.map +1 -1
  112. package/dist/loader/meta-data-loader.js +18 -1
  113. package/dist/loader/meta-data-loader.js.map +1 -1
  114. package/dist/loader/reporting-validation.d.ts +11 -0
  115. package/dist/loader/reporting-validation.d.ts.map +1 -0
  116. package/dist/loader/reporting-validation.js +883 -0
  117. package/dist/loader/reporting-validation.js.map +1 -0
  118. package/dist/loader/resolve-references.d.ts +8 -0
  119. package/dist/loader/resolve-references.d.ts.map +1 -0
  120. package/dist/loader/resolve-references.js +132 -0
  121. package/dist/loader/resolve-references.js.map +1 -0
  122. package/dist/loader/validation-passes.d.ts.map +1 -1
  123. package/dist/loader/validation-passes.js +14 -9
  124. package/dist/loader/validation-passes.js.map +1 -1
  125. package/dist/loader/validation-registry.d.ts.map +1 -1
  126. package/dist/loader/validation-registry.js +33 -10
  127. package/dist/loader/validation-registry.js.map +1 -1
  128. package/dist/metamodel-docs/index.js +3 -3
  129. package/dist/metamodel-docs/index.js.map +1 -1
  130. package/dist/metamodel-docs/render.js +4 -4
  131. package/dist/metamodel-docs/render.js.map +1 -1
  132. package/dist/naming-refs.d.ts +102 -50
  133. package/dist/naming-refs.d.ts.map +1 -1
  134. package/dist/naming-refs.js +223 -97
  135. package/dist/naming-refs.js.map +1 -1
  136. package/dist/naming.d.ts +42 -7
  137. package/dist/naming.d.ts.map +1 -1
  138. package/dist/naming.js +43 -5
  139. package/dist/naming.js.map +1 -1
  140. package/dist/object-serializer.d.ts.map +1 -1
  141. package/dist/object-serializer.js +6 -9
  142. package/dist/object-serializer.js.map +1 -1
  143. package/dist/parser-core.d.ts.map +1 -1
  144. package/dist/parser-core.js +18 -48
  145. package/dist/parser-core.js.map +1 -1
  146. package/dist/persistence/db/db-definition.embedded.js +2 -2
  147. package/dist/persistence/db/db-definition.embedded.js.map +1 -1
  148. package/dist/persistence/source/meta-source.d.ts +5 -3
  149. package/dist/persistence/source/meta-source.d.ts.map +1 -1
  150. package/dist/persistence/source/meta-source.js +8 -6
  151. package/dist/persistence/source/meta-source.js.map +1 -1
  152. package/dist/registry-manifest-exclusions.js +2 -2
  153. package/dist/registry-manifest-exclusions.js.map +1 -1
  154. package/dist/registry-manifest.d.ts +1 -1
  155. package/dist/registry-manifest.js +1 -1
  156. package/dist/release-docs.d.ts +11 -0
  157. package/dist/release-docs.d.ts.map +1 -0
  158. package/dist/release-docs.js +48 -0
  159. package/dist/release-docs.js.map +1 -0
  160. package/dist/serializer-json.d.ts +15 -1
  161. package/dist/serializer-json.d.ts.map +1 -1
  162. package/dist/serializer-json.js +55 -17
  163. package/dist/serializer-json.js.map +1 -1
  164. package/dist/shared/base-types.d.ts +7 -1
  165. package/dist/shared/base-types.d.ts.map +1 -1
  166. package/dist/shared/base-types.js +9 -0
  167. package/dist/shared/base-types.js.map +1 -1
  168. package/dist/shared/meta-data.d.ts +10 -0
  169. package/dist/shared/meta-data.d.ts.map +1 -1
  170. package/dist/shared/meta-data.js +22 -1
  171. package/dist/shared/meta-data.js.map +1 -1
  172. package/dist/shared/meta-root.d.ts +13 -1
  173. package/dist/shared/meta-root.d.ts.map +1 -1
  174. package/dist/shared/meta-root.js +19 -1
  175. package/dist/shared/meta-root.js.map +1 -1
  176. package/dist/super-resolve.d.ts +4 -1
  177. package/dist/super-resolve.d.ts.map +1 -1
  178. package/dist/super-resolve.js +44 -65
  179. package/dist/super-resolve.js.map +1 -1
  180. package/dist/vocabulary-catalog.js +2 -2
  181. package/dist/vocabulary-catalog.js.map +1 -1
  182. package/package.json +6 -1
  183. package/src/attr-schema-validate.ts +9 -13
  184. package/src/constants.ts +1 -0
  185. package/src/core/attr/meta-attr-filter.ts +8 -1
  186. package/src/core/attr/meta-attr.ts +24 -1
  187. package/src/core/field/shared-enum.ts +53 -0
  188. package/src/core/identity/meta-identity.ts +9 -12
  189. package/src/core/index.ts +5 -0
  190. package/src/core/object/object-constants.ts +19 -0
  191. package/src/core/object/object-definition.embedded.ts +80 -0
  192. package/src/core/relationship/derive-m2m-fields.ts +15 -48
  193. package/src/core/relationship/find-reference.ts +4 -2
  194. package/src/core/relationship/resolve-relationship-reference.ts +11 -9
  195. package/src/core/reporting/meta-dimension.ts +41 -0
  196. package/src/core/reporting/meta-measure.ts +75 -0
  197. package/src/core/reporting/meta-segment.ts +14 -0
  198. package/src/core/reporting/report-accessors.ts +73 -0
  199. package/src/core/reporting/report-describe.ts +206 -0
  200. package/src/core/reporting/report-read-model.ts +177 -0
  201. package/src/core/reporting/report-shape.ts +493 -0
  202. package/src/core/reporting/reporting-constants.ts +104 -0
  203. package/src/core/reporting/reporting-definition.embedded.ts +192 -0
  204. package/src/core/requirement/resolve-claim.ts +20 -0
  205. package/src/core/yaml-desugar.ts +9 -89
  206. package/src/core-types.ts +41 -0
  207. package/src/docs-ref.ts +41 -0
  208. package/src/errors.ts +17 -6
  209. package/src/fmt.ts +3 -1
  210. package/src/index.ts +72 -4
  211. package/src/loader/declared-duplicate-fields.ts +114 -0
  212. package/src/loader/meta-data-loader.ts +25 -1
  213. package/src/loader/reporting-validation.ts +1137 -0
  214. package/src/loader/resolve-references.ts +144 -0
  215. package/src/loader/validation-passes.ts +13 -9
  216. package/src/loader/validation-registry.ts +37 -9
  217. package/src/metamodel-docs/index.ts +3 -3
  218. package/src/metamodel-docs/render.ts +4 -4
  219. package/src/naming-refs.ts +237 -94
  220. package/src/naming.ts +75 -11
  221. package/src/object-serializer.ts +7 -9
  222. package/src/parser-core.ts +19 -56
  223. package/src/persistence/db/db-definition.embedded.ts +2 -2
  224. package/src/persistence/source/meta-source.ts +8 -6
  225. package/src/registry-manifest-exclusions.ts +2 -2
  226. package/src/registry-manifest.ts +1 -1
  227. package/src/release-docs.ts +48 -0
  228. package/src/serializer-json.ts +79 -12
  229. package/src/shared/base-types.ts +9 -0
  230. package/src/shared/meta-data.ts +22 -1
  231. package/src/shared/meta-root.ts +20 -1
  232. package/src/super-resolve.ts +49 -63
  233. package/src/vocabulary-catalog.ts +2 -2
@@ -0,0 +1,114 @@
1
+ // declaredDuplicateFields — structural pre-parse walk for the `meta verify` field lint.
2
+ //
3
+ // Two `field.*` children with the same `name` in ONE object's `children` list load
4
+ // with no error on every port, and the loaded model keeps no trace of it: the parser's
5
+ // merge rule folds the later declaration into the first (a different subtype is
6
+ // discarded outright). So the question "was this field declared twice?" can only be
7
+ // answered from the document, before the merge — the same reason
8
+ // `declaredTopLevelKeys` exists for the overlay lint.
9
+ //
10
+ // Scope, deliberately narrow:
11
+ // - ONE children list. The same field declared in a base file and again in an
12
+ // overlay file is the overlay merge working as designed, and a subtype
13
+ // redeclaring an inherited field is an override. Neither is in one list.
14
+ // - Root-level objects only, addressed by the resolution key the parser gives them.
15
+
16
+ import { TYPE_FIELD, TYPE_METADATA, TYPE_OBJECT, SUBTYPE_ROOT } from "../shared/base-types.js";
17
+ import {
18
+ PACKAGE_SEPARATOR,
19
+ RESERVED_KEY_CHILDREN,
20
+ RESERVED_KEY_NAME,
21
+ RESERVED_KEY_PACKAGE,
22
+ TYPE_SUBTYPE_SEPARATOR,
23
+ } from "../shared/structural.js";
24
+ import { expandPackageForPath } from "../parser-core.js";
25
+ import { parseYamlWithPositions } from "../core/yaml-positions-walker.js";
26
+ import type { MetaDataFormat } from "./meta-data-source.js";
27
+
28
+ /** The YAML authoring sugar for `isArray: true` — a suffix on the wrapper key. */
29
+ const ARRAY_SUFFIX = "[]";
30
+
31
+ /** One field name declared more than once in one object's `children` list. */
32
+ export interface DeclaredDuplicateField {
33
+ /** The declaring object's resolution key (`<package>::<name>`, or the bare name). */
34
+ object: string;
35
+ /** The repeated field name. */
36
+ field: string;
37
+ /** How many times the list declares it (always 2 or more). */
38
+ count: number;
39
+ }
40
+
41
+ function isRecord(v: unknown): v is Record<string, unknown> {
42
+ return typeof v === "object" && v !== null && !Array.isArray(v);
43
+ }
44
+
45
+ /** The TYPE segment of a wrapper key: `field.string[]` and the bare `field` are both `field`. */
46
+ function wrapperType(key: string): string {
47
+ const dot = key.indexOf(TYPE_SUBTYPE_SEPARATOR);
48
+ const head = dot < 0 ? key : key.slice(0, dot);
49
+ return head.endsWith(ARRAY_SUFFIX) ? head.slice(0, -ARRAY_SUFFIX.length) : head;
50
+ }
51
+
52
+ /** A node's declared name: the body's `name`, or the body itself when YAML wrote a scalar. */
53
+ function declaredName(body: unknown): string | undefined {
54
+ const name = isRecord(body) ? body[RESERVED_KEY_NAME] : body;
55
+ return typeof name === "string" && name !== "" ? name : undefined;
56
+ }
57
+
58
+ /**
59
+ * Structurally scan a source's raw content and report every field name a root-level
60
+ * object declares more than once in its own `children` list, in document order.
61
+ *
62
+ * Malformed shapes return `[]` rather than throwing — the real parse is where a
63
+ * structural error surfaces. A syntax error does throw, as `declaredTopLevelKeys` does.
64
+ */
65
+ export function declaredDuplicateFields(
66
+ content: string,
67
+ format: MetaDataFormat,
68
+ ): ReadonlyArray<DeclaredDuplicateField> {
69
+ // Strip UTF-8 BOM if present (mirrors parseJson / parseYaml).
70
+ const normalized = content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;
71
+ let parsed: unknown;
72
+ if (format === "json") parsed = JSON.parse(normalized);
73
+ else if (format === "yaml") parsed = parseYamlWithPositions(normalized).value;
74
+ else return [];
75
+ if (!isRecord(parsed)) return [];
76
+
77
+ // JSON fuses the subtype onto the root key; sigil-free YAML may write the bare type.
78
+ const rootBody = parsed[`${TYPE_METADATA}${TYPE_SUBTYPE_SEPARATOR}${SUBTYPE_ROOT}`] ?? parsed[TYPE_METADATA];
79
+ if (!isRecord(rootBody)) return [];
80
+ const rawRootPkg = rootBody[RESERVED_KEY_PACKAGE];
81
+ const rootPkg = typeof rawRootPkg === "string" ? rawRootPkg : "";
82
+ const children = rootBody[RESERVED_KEY_CHILDREN];
83
+ if (!Array.isArray(children)) return [];
84
+
85
+ const out: DeclaredDuplicateField[] = [];
86
+ for (const child of children) {
87
+ if (!isRecord(child)) continue;
88
+ for (const [wrapperKey, body] of Object.entries(child)) {
89
+ if (wrapperType(wrapperKey) !== TYPE_OBJECT || !isRecord(body)) continue;
90
+ const name = declaredName(body);
91
+ const members = body[RESERVED_KEY_CHILDREN];
92
+ if (name === undefined || !Array.isArray(members)) continue;
93
+
94
+ const counts = new Map<string, number>();
95
+ for (const member of members) {
96
+ if (!isRecord(member)) continue;
97
+ for (const [memberKey, memberBody] of Object.entries(member)) {
98
+ if (wrapperType(memberKey) !== TYPE_FIELD) continue;
99
+ const fieldName = declaredName(memberBody);
100
+ if (fieldName !== undefined) counts.set(fieldName, (counts.get(fieldName) ?? 0) + 1);
101
+ }
102
+ }
103
+
104
+ const rawOwnPkg = body[RESERVED_KEY_PACKAGE];
105
+ const pkg =
106
+ typeof rawOwnPkg === "string" && rawOwnPkg !== "" ? expandPackageForPath(rootPkg, rawOwnPkg) : rootPkg;
107
+ const object = pkg !== "" ? `${pkg}${PACKAGE_SEPARATOR}${name}` : name;
108
+ for (const [field, count] of counts) {
109
+ if (count > 1) out.push({ object, field, count });
110
+ }
111
+ }
112
+ }
113
+ return out;
114
+ }
@@ -26,6 +26,7 @@ import type { LoaderWarning } from "../source.js";
26
26
  import { codeSource, resolvedSource } from "../source.js";
27
27
  import { parseJson } from "../parser-json.js";
28
28
  import { validateDataGridSortFields, validateFilterableHasIndex, validateFilterableHasSupportedOps, validateSortableHasSupportedSubtype, validateOriginPaths, validateDerivedFieldProvidability, validateDataGridFilterValues, validateFieldObjectStorage, validateFieldMap, validateTemplatePayloadRefs, validateFieldDefaults, validateRelationships, validateOneSideReferenceResolution, validateM2MJunctionPairing, validateIndexLookupFields, validateProjectionFilter, validateRetiredRequirementLinks } from "./validation-passes.js";
29
+ import { validateReporting } from "./reporting-validation.js";
29
30
  import { runRegisteredValidation } from "./validation-registry.js";
30
31
  import { validateSourceRoles } from "../persistence/source/validate-source-roles.js";
31
32
  import { validateSourceEscapes } from "../persistence/source/validate-source-escapes.js";
@@ -35,6 +36,7 @@ import { validateFieldMutability } from "../core/field/validate-field-mutability
35
36
  import { validateEnumNormalizeAmbiguity } from "../core/field/validate-enum-normalize-ambiguity.js";
36
37
  import { validateDiscriminator } from "../core/object/validate-discriminator.js";
37
38
  import { resolveDeferredSupers, EXTENDS_TARGET_MISMATCH_RULE } from "../super-resolve.js";
39
+ import { resolveReferences } from "./resolve-references.js";
38
40
  import { validateSubtypeRules } from "../subtype-rules.js";
39
41
  import { validateMaxOccurs } from "../validate-max-occurs.js";
40
42
  import { validateIdentityPassthrough } from "../core/identity/validate-identity-passthrough.js";
@@ -43,6 +45,7 @@ import type { MetaDataFormat, MetaDataSource } from "./meta-data-source.js";
43
45
  import { InMemoryStringSource } from "./meta-data-source.js";
44
46
  import type { ParseOptions, ParseResult, PendingOverlay } from "../parser-core.js";
45
47
  import { expandPackageForPath, applyPendingOverlays } from "../parser-core.js";
48
+ import { didYouMeanSuperHint } from "../naming-refs.js";
46
49
 
47
50
  // Local mirror of DirectorySource's options shape. Deliberately inlined here
48
51
  // (instead of `import type`'d from ./sources/directory-source.js) so the
@@ -589,9 +592,22 @@ export class MetaDataLoader {
589
592
  );
590
593
  continue;
591
594
  }
595
+ if (failure.kind === "over-drop") {
596
+ // ADR-0059 R2 — `..::` dropped more segments than the package has.
597
+ errors.push(
598
+ new ParseError(
599
+ `the extends ref '${failure.ref}' on ${failure.nodeFqn} climbs above the root package — each '..::' drops one segment of the declaring package`,
600
+ {
601
+ code: "ERR_BAD_ATTR_VALUE",
602
+ source: resolvedSource(failure.source, failure.nodeFqn, failure.ref),
603
+ },
604
+ ),
605
+ );
606
+ continue;
607
+ }
592
608
  errors.push(
593
609
  new ParseError(
594
- `the SuperClass '${failure.ref}' does not exist (referenced by ${failure.nodeFqn})`,
610
+ `the SuperClass '${failure.ref}' does not exist (referenced by ${failure.nodeFqn})${didYouMeanSuperHint(root, failure.ref)}`,
595
611
  {
596
612
  code: "ERR_UNRESOLVED_SUPER",
597
613
  source: resolvedSource(failure.source, failure.nodeFqn, failure.ref),
@@ -646,6 +662,10 @@ export class MetaDataLoader {
646
662
  // an aggregate-derived or dangling ref is fail-closed (ERR_BAD_ATTR_FILTER).
647
663
  errors.push(...validateProjectionFilter(root));
648
664
 
665
+ // FR-044 — reporting vocabulary cross-node rules (dimensions, measures,
666
+ // segments, reports, relative-date filter values).
667
+ errors.push(...validateReporting(root));
668
+
649
669
  // FR-017 — M:N relationship validation (deferred-resolution): @through names a
650
670
  // junction declaring two identity.reference children; @sourceRefField matches one;
651
671
  // @symmetric is self-join-only + mutually exclusive with @sourceRefField; M:N attrs
@@ -745,6 +765,10 @@ export class MetaDataLoader {
745
765
  // finite number, boolean → true|false). Enum @default membership is validated
746
766
  // by validateAttrSchema (Check 5). Cross-port parity with Java/Python/C#.
747
767
  errors.push(...validateFieldDefaults(root));
768
+
769
+ // ADR-0059 R5 — after the last validation pass, before freeze: resolve every
770
+ // reference once, record its target and rewrite it to its canonical spelling.
771
+ resolveReferences(root);
748
772
  }
749
773
 
750
774
  // If nothing parsed successfully, synthesize an empty root so callers