metaobjects 0.10.0__tar.gz → 0.11.0__tar.gz

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 (386) hide show
  1. {metaobjects-0.10.0 → metaobjects-0.11.0}/PKG-INFO +1 -1
  2. {metaobjects-0.10.0 → metaobjects-0.11.0}/pyproject.toml +1 -1
  3. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-authoring/SKILL.md +72 -1
  4. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-codegen/references/typescript.md +30 -0
  5. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-prompts/SKILL.md +41 -0
  6. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-verify/references/migration.md +34 -1
  7. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/extract_delegate_emitter.py +1 -1
  8. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/extract_schema_emitter.py +1 -1
  9. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/fr010_field_mapping.py +4 -4
  10. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/entity_model.py +4 -4
  11. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +1 -1
  12. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/m2m_codegen.py +1 -1
  13. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/payload_vo_generator.py +2 -2
  14. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/render_helper_generator.py +1 -1
  15. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/output_format_spec_emitter.py +2 -2
  16. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/type_map.py +2 -2
  17. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/core_types.py +37 -0
  18. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/errors.py +5 -0
  19. metaobjects-0.11.0/src/metaobjects/loader/registered_validation.py +95 -0
  20. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/validate_discriminator.py +1 -1
  21. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/validation_passes.py +53 -5
  22. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/validator/validator_constants.py +13 -0
  23. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/db/db_constants.py +18 -0
  24. metaobjects-0.11.0/src/metaobjects/meta/persistence/db/db_provider.py +141 -0
  25. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/parser.py +5 -0
  26. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/registry.py +14 -0
  27. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/db.json +17 -0
  28. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/identity.json +2 -0
  29. metaobjects-0.11.0/src/metaobjects/spec_metamodel/validator.json +98 -0
  30. metaobjects-0.11.0/src/metaobjects/validation_types.py +39 -0
  31. metaobjects-0.11.0/tests/codegen/test_inherit_without_restate_gate.py +54 -0
  32. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_loader.py +3 -1
  33. {metaobjects-0.10.0 → metaobjects-0.11.0}/uv.lock +1 -1
  34. metaobjects-0.10.0/src/metaobjects/meta/persistence/db/db_provider.py +0 -60
  35. metaobjects-0.10.0/src/metaobjects/spec_metamodel/validator.json +0 -56
  36. {metaobjects-0.10.0 → metaobjects-0.11.0}/.gitignore +0 -0
  37. {metaobjects-0.10.0 → metaobjects-0.11.0}/LICENSE +0 -0
  38. {metaobjects-0.10.0 → metaobjects-0.11.0}/README.md +0 -0
  39. {metaobjects-0.10.0 → metaobjects-0.11.0}/hatch_build.py +0 -0
  40. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/__init__.py +0 -0
  41. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/__init__.py +0 -0
  42. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/README.md +0 -0
  43. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/servers/csharp.meta.json +0 -0
  44. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/servers/java.meta.json +0 -0
  45. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/servers/kotlin.meta.json +0 -0
  46. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/servers/python.meta.json +0 -0
  47. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/servers/typescript.meta.json +0 -0
  48. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-codegen/SKILL.md +0 -0
  49. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-codegen/references/csharp.md +0 -0
  50. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-codegen/references/java.md +0 -0
  51. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-codegen/references/kotlin.md +0 -0
  52. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-prompts/references/csharp.md +0 -0
  53. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-prompts/references/java.md +0 -0
  54. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-prompts/references/kotlin.md +0 -0
  55. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-prompts/references/python.md +0 -0
  56. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-prompts/references/typescript.md +0 -0
  57. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-runtime-ui/SKILL.md +0 -0
  58. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-runtime-ui/references/java.md +0 -0
  59. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-runtime-ui/references/kotlin.md +0 -0
  60. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-runtime-ui/references/react.md +0 -0
  61. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-runtime-ui/references/tanstack.md +0 -0
  62. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-runtime-ui/references/typescript.md +0 -0
  63. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/skills/metaobjects-verify/SKILL.md +0 -0
  64. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/_content/templates/always-on.md.mustache +0 -0
  65. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/assemble.py +0 -0
  66. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/content_root.py +0 -0
  67. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/scaffold.py +0 -0
  68. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/agent_context/types.py +0 -0
  69. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/apidocs/__init__.py +0 -0
  70. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/apidocs/api_model.py +0 -0
  71. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/apidocs/builder.py +0 -0
  72. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/apidocs/naming.py +0 -0
  73. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/apidocs/paths.py +0 -0
  74. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/apidocs/renderer.py +0 -0
  75. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/attr_class_map.py +0 -0
  76. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/cli.py +0 -0
  77. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  78. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/__init__.py +0 -0
  79. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/config.py +0 -0
  80. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/constants.py +0 -0
  81. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/format.py +0 -0
  82. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generator.py +0 -0
  83. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generator_registry.py +0 -0
  84. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/__init__.py +0 -0
  85. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  86. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  87. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  88. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  89. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  90. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  91. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  92. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  93. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  94. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  95. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/runner.py +0 -0
  96. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  97. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  98. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/datatype.py +0 -0
  99. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/documentation/__init__.py +0 -0
  100. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/documentation/doc_constants.py +0 -0
  101. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/documentation/doc_provider.py +0 -0
  102. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/documentation/doc_schema.py +0 -0
  103. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/__init__.py +0 -0
  104. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/merge.py +0 -0
  105. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/meta_data_loader.py +0 -0
  106. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/sources/__init__.py +0 -0
  107. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/sources/directory_source.py +0 -0
  108. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/sources/file_source.py +0 -0
  109. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  110. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/sources/uri_source.py +0 -0
  111. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/validate_field_readonly.py +0 -0
  112. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  113. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  114. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/__init__.py +0 -0
  115. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/__init__.py +0 -0
  116. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  117. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  118. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  119. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/field/__init__.py +0 -0
  120. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  121. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  122. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  123. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  124. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  125. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/__init__.py +0 -0
  126. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  127. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  128. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  129. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  130. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  131. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/object/value_object.py +0 -0
  132. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  133. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  134. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  135. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  136. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  137. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/meta_data.py +0 -0
  138. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/meta_root.py +0 -0
  139. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/__init__.py +0 -0
  140. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  141. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  142. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  143. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  144. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  145. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  146. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  147. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/__init__.py +0 -0
  148. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  149. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  150. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  151. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  152. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  153. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  154. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  155. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  156. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/provider_extends.py +0 -0
  157. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/template/__init__.py +0 -0
  158. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/template/meta_template.py +0 -0
  159. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  160. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/meta/template/template_constants.py +0 -0
  161. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/naming_refs.py +0 -0
  162. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/parser_yaml.py +0 -0
  163. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/provider.py +0 -0
  164. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/py.typed +0 -0
  165. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/registry_manifest.py +0 -0
  166. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/__init__.py +0 -0
  167. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/email_document.py +0 -0
  168. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/escapers.py +0 -0
  169. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  170. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/__init__.py +0 -0
  171. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/coerce.py +0 -0
  172. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/extract.py +0 -0
  173. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/extract_map.py +0 -0
  174. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  175. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/locate.py +0 -0
  176. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/normalize.py +0 -0
  177. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/strip.py +0 -0
  178. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/types.py +0 -0
  179. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  180. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/filesystem_provider.py +0 -0
  181. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/prompt/__init__.py +0 -0
  182. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  183. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  184. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  185. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  186. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  187. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/renderer.py +0 -0
  188. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/render/verify.py +0 -0
  189. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/runtime/__init__.py +0 -0
  190. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/runtime/llm_recorder.py +0 -0
  191. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  192. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/runtime/object_manager.py +0 -0
  193. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/runtime/tph.py +0 -0
  194. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/serializer_json.py +0 -0
  195. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/shared/__init__.py +0 -0
  196. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/shared/base_types.py +0 -0
  197. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/shared/separators.py +0 -0
  198. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/shared/structural.py +0 -0
  199. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/source/__init__.py +0 -0
  200. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/source/error_source.py +0 -0
  201. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/source/json_path.py +0 -0
  202. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/source/semantic_diff.py +0 -0
  203. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/source/yaml_positions.py +0 -0
  204. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  205. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/attr.json +0 -0
  206. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  207. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/field.json +0 -0
  208. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/layout.json +0 -0
  209. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/object.json +0 -0
  210. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/origin.json +0 -0
  211. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  212. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  213. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/source.json +0 -0
  214. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/template.json +0 -0
  215. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/ui.json +0 -0
  216. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/spec_metamodel/view.json +0 -0
  217. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/super_resolve.py +0 -0
  218. {metaobjects-0.10.0 → metaobjects-0.11.0}/src/metaobjects/yaml_desugar.py +0 -0
  219. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/__init__.py +0 -0
  220. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/__init__.py +0 -0
  221. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  222. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/extends/expected/Program.py +0 -0
  223. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/extends/meta.json +0 -0
  224. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  225. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  226. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/nested-array/meta.json +0 -0
  227. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  228. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  229. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/scalars/meta.json +0 -0
  230. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  231. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/golden/vanilla/meta.json +0 -0
  232. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_abstract_conformance.py +0 -0
  233. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_api_docs_builder.py +0 -0
  234. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_api_docs_paths.py +0 -0
  235. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_cli.py +0 -0
  236. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_cli_registry.py +0 -0
  237. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  238. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  239. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_constants_config.py +0 -0
  240. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_entity_model.py +0 -0
  241. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_enum_conformance.py +0 -0
  242. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_extractor_generator.py +0 -0
  243. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  244. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_format.py +0 -0
  245. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_fr010_output_codegen.py +0 -0
  246. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  247. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_generator.py +0 -0
  248. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_generator_extension_seams.py +0 -0
  249. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_golden.py +0 -0
  250. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_inheritance_conformance.py +0 -0
  251. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_instance_artifacts.py +0 -0
  252. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_m2m_codegen.py +0 -0
  253. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_output_parser_generator.py +0 -0
  254. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_overwrite_policy.py +0 -0
  255. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_payload_vo_generator.py +0 -0
  256. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_render_helper_conformance.py +0 -0
  257. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_render_helper_generator.py +0 -0
  258. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_router_generator.py +0 -0
  259. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_runner.py +0 -0
  260. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_template_generator.py +0 -0
  261. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_tph_codegen.py +0 -0
  262. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_trace_helper_generator.py +0 -0
  263. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_type_map.py +0 -0
  264. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/codegen/test_validation_conformance.py +0 -0
  265. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/__init__.py +0 -0
  266. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/capabilities.py +0 -0
  267. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/conformance-expected-failures.json +0 -0
  268. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/conformance_adapter.py +0 -0
  269. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/corpus.py +0 -0
  270. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/expected_failures.py +0 -0
  271. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/fixture_discovery.py +0 -0
  272. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/navigator.py +0 -0
  273. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_agent_context_conformance.py +0 -0
  274. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  275. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_conformance.py +0 -0
  276. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_extract_conformance.py +0 -0
  277. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_extract_object_verdict.py +0 -0
  278. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  279. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_fr011_attrs.py +0 -0
  280. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_generator_registry_conformance.py +0 -0
  281. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_object_model_conformance.py +0 -0
  282. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_registry_conformance.py +0 -0
  283. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_runner_hardfail.py +0 -0
  284. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  285. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_strict_attr_load.py +0 -0
  286. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_template_generator_conformance.py +0 -0
  287. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/test_yaml_conformance.py +0 -0
  288. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  289. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/__init__.py +0 -0
  290. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/api_contract_assertions.py +0 -0
  291. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/api_contract_m2m_server.py +0 -0
  292. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/api_contract_server.py +0 -0
  293. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/generated_m2m_app.py +0 -0
  294. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/generated_router_app.py +0 -0
  295. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/generated_tph_app.py +0 -0
  296. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/meta_ai_trace.yaml +0 -0
  297. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/normalization.py +0 -0
  298. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/postgres_container.py +0 -0
  299. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/query_runner.py +0 -0
  300. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/scenarios.py +0 -0
  301. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_api_contract.py +0 -0
  302. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_api_contract_generated.py +0 -0
  303. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_api_contract_m2m.py +0 -0
  304. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  305. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_api_contract_tph_generated.py +0 -0
  306. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_llm_call_trace.py +0 -0
  307. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_normalization.py +0 -0
  308. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_query_scenarios.py +0 -0
  309. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/integration/test_runtime_return_types.py +0 -0
  310. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/open_closed_proof_test.py +0 -0
  311. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/__init__.py +0 -0
  312. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/__init__.py +0 -0
  313. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_coerce.py +0 -0
  314. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_extract.py +0 -0
  315. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_extract_map.py +0 -0
  316. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  317. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_locate.py +0 -0
  318. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_model.py +0 -0
  319. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_normalize.py +0 -0
  320. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_strip.py +0 -0
  321. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  322. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/prompt/__init__.py +0 -0
  323. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/prompt/test_output_format_renderer.py +0 -0
  324. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_email_document.py +0 -0
  325. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_filesystem_provider.py +0 -0
  326. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_output_format_renderer_nested.py +0 -0
  327. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_output_prompt_conformance.py +0 -0
  328. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_render_conformance.py +0 -0
  329. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_render_max_chars.py +0 -0
  330. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_verify.py +0 -0
  331. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/render/test_verify_conformance.py +0 -0
  332. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/__init__.py +0 -0
  333. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_fr5c_merge_attribution.py +0 -0
  334. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_fr5d_reference_resolution.py +0 -0
  335. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_fr5e_database_source_shape.py +0 -0
  336. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_json_path.py +0 -0
  337. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_semantic_diff.py +0 -0
  338. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_source_on_node.py +0 -0
  339. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/source/test_yaml_positions.py +0 -0
  340. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/test_api_docs_accuracy.py +0 -0
  341. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/__init__.py +0 -0
  342. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_agent_context_staleness.py +0 -0
  343. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_capabilities.py +0 -0
  344. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_common_attrs.py +0 -0
  345. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_core_types.py +0 -0
  346. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_effective_package.py +0 -0
  347. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_errors.py +0 -0
  348. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_field_enum.py +0 -0
  349. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  350. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  351. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_llm_recorder.py +0 -0
  352. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_loader_bom.py +0 -0
  353. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_loader_class.py +0 -0
  354. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_merge.py +0 -0
  355. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_meta_attr.py +0 -0
  356. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_meta_data.py +0 -0
  357. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_meta_source.py +0 -0
  358. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_module_shortcuts.py +0 -0
  359. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_n2m_resolver.py +0 -0
  360. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  361. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_one_primary_source.py +0 -0
  362. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_parser.py +0 -0
  363. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_parser_yaml.py +0 -0
  364. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_provider.py +0 -0
  365. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_provider_extension.py +0 -0
  366. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_registry.py +0 -0
  367. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_registry_completeness.py +0 -0
  368. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_registry_extend.py +0 -0
  369. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_registry_sealed.py +0 -0
  370. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_relationship_referential_actions.py +0 -0
  371. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_resolution_key.py +0 -0
  372. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  373. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_serializer.py +0 -0
  374. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_shared_constants.py +0 -0
  375. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_smoke.py +0 -0
  376. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_sources.py +0 -0
  377. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_strict_child_placement.py +0 -0
  378. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_super_resolve.py +0 -0
  379. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_template_toolcall.py +0 -0
  380. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  381. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_validation_attr_schema.py +0 -0
  382. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_validation_filter_values.py +0 -0
  383. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_validation_origin_paths.py +0 -0
  384. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_validation_sort_field.py +0 -0
  385. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_validation_warnings.py +0 -0
  386. {metaobjects-0.10.0 → metaobjects-0.11.0}/tests/unit/test_yaml_desugar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metaobjects
3
- Version: 0.10.0
3
+ Version: 0.11.0
4
4
  Summary: Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port.
5
5
  Project-URL: Homepage, https://metaobjects.dev
6
6
  Project-URL: Repository, https://github.com/metaobjectsdev/metaobjects
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "metaobjects"
3
- version = "0.10.0"
3
+ version = "0.11.0"
4
4
  description = "Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -165,6 +165,26 @@ Reuse a constraint set across entities with an abstract `field.enum` + `extends`
165
165
  { "field.object": { "name": "address", "@objectRef": "Address", "@storage": "flattened" } }
166
166
  ```
167
167
 
168
+ **Arrays of value objects** — set `isArray: true` with `@storage: jsonb`. The whole
169
+ array lives in **one** jsonb column (a JSON array), never a native `jsonb[]`. The
170
+ generated Postgres column is typed `.$type<VO[]>()` and the Zod schema is
171
+ `z.array(<VO>InsertSchema)`:
172
+
173
+ ```json
174
+ { "field.object": { "name": "triples", "@objectRef": "Triple",
175
+ "@storage": "jsonb", "isArray": true } }
176
+ ```
177
+
178
+ **Opaque jsonb (no value object)** — when the payload has no fixed shape (freeform
179
+ config, passthrough metadata, an open-keyed map), do NOT use `field.object` (it
180
+ requires `@objectRef`, and a partial VO would let the generated Zod strip unknown
181
+ keys → data loss). Model it as a `field.string` with the physical-type override
182
+ `@dbColumnType: jsonb` — the logical type stays string-bound, the column is jsonb:
183
+
184
+ ```json
185
+ { "field.string": { "name": "metadata", "@dbColumnType": "jsonb" } }
186
+ ```
187
+
168
188
  ## YAML sigil-free authoring + the coercion footgun
169
189
 
170
190
  In YAML, write the fused `type.subType` key with a **map body**, bare reserved
@@ -194,7 +214,7 @@ The `[]` key-suffix declares an array field: `field.long[]: weekIds` lowers to
194
214
  | Subtype | Purpose | Key attrs |
195
215
  |---|---|---|
196
216
  | `identity.primary` | the PK field(s) | `@fields`, `@generation` |
197
- | `identity.secondary` | a unique secondary index | `@fields` |
217
+ | `identity.secondary` | a unique secondary index | `@fields` (or `@expr` for a functional index) |
198
218
  | `identity.reference` | an inbound FK from this entity to another | `@fields`, `@references`, `@enforce` |
199
219
 
200
220
  `@generation` on a primary controls value generation (e.g. `increment`).
@@ -205,9 +225,27 @@ reference for navigation/typing/codegen only. Referential actions
205
225
  (`@onDelete`/`@onUpdate`) are NOT on `identity.reference` — they live on the
206
226
  `relationship.*` node (see Relationships below).
207
227
 
228
+ `@references` resolves cross-package by **fully-qualified name**
229
+ (`@references: "shared::billing::Account"`), the same rule as `extends`; a bare
230
+ name resolves within the current package. The FK target must be an entity with a
231
+ single-column primary key (the FK points at that PK); a target with a composite
232
+ PK needs the explicit dotted form `@references: "pkg::Target.fieldA,fieldB"`.
233
+
234
+ **A dangling reference fails the load (0.11.0+).** An unresolved
235
+ `identity.reference.@references` raises `ERR_INVALID_REFERENCE` and an unresolved
236
+ `relationship.@objectRef` raises `ERR_INVALID_RELATIONSHIP` — the target entity must
237
+ exist (previously such references loaded silently). So every `@references` /
238
+ `@objectRef` you author must name a real entity.
239
+
240
+ A `identity.secondary` can index an **expression** instead of plain columns: use
241
+ `@expr` (e.g. `"lower(email)"`) in place of `@fields`, optionally with `@using` (the
242
+ index method — `gin` / `gist` / `hash`; default `btree`) and `@where` (a partial-index
243
+ predicate).
244
+
208
245
  ```json
209
246
  { "identity.primary": { "name": "id", "@fields": ["id"], "@generation": "increment" } }
210
247
  { "identity.secondary": { "name": "byEmail", "@fields": ["email"] } }
248
+ { "identity.secondary": { "name": "byEmailCI", "@expr": "lower(email)" } }
211
249
  { "identity.reference": { "name": "fkAuthor", "@fields": ["authorId"], "@references": "Author", "@enforce": true } }
212
250
  ```
213
251
 
@@ -229,6 +267,39 @@ the two halves of one FK.
229
267
  "@cardinality": "many", "@onDelete": "cascade" } }
230
268
  ```
231
269
 
270
+ **Adoption footgun — pin BOTH actions.** `@onDelete` and `@onUpdate` each default to
271
+ `cascade` when omitted, but a plain SQL foreign key is `NO ACTION` on both. If you're
272
+ adopting an existing database (matching metadata to a live schema), omitting these
273
+ makes the metadata declare `CASCADE` where the DB has `NO ACTION` — a perpetual
274
+ `verify --db` drift. Pin **both** explicitly to the DB's real behavior:
275
+
276
+ ```json
277
+ { "relationship.composition": { "name": "author", "@objectRef": "User",
278
+ "@cardinality": "one", "@onDelete": "no-action", "@onUpdate": "no-action" } }
279
+ ```
280
+
281
+ ## Validators — cross-field rules
282
+
283
+ Entity-scoped `validator.*` children declare invariants that reference sibling fields
284
+ **by name** (the same name-reference pattern as `identity.*`). The backend derives the
285
+ enforcement (a CHECK constraint / cross-field assertion) — no raw expression is stored.
286
+
287
+ | Subtype | Rule | Key attrs |
288
+ |---|---|---|
289
+ | `validator.comparison` | two fields stand in a relational order (`@left @op @right`) | `@left`, `@op` (`gt`/`gte`/`lt`/`lte`/`ne`/`eq`), `@right` |
290
+ | `validator.requiredWhen` | `@field` is required when `@when` equals `@equals` | `@field`, `@when`, `@equals` |
291
+ | `validator.presentIff` | `@field` is present **iff** `@when` equals `@equals` (biconditional) | `@field`, `@when`, `@equals` |
292
+ | `validator.atLeastOne` | at least one of `@fields` (2+) is present | `@fields` |
293
+
294
+ ```json
295
+ { "validator.comparison": { "name": "hpInRange", "@left": "currentHp", "@op": "lte", "@right": "maxHp" } }
296
+ { "validator.requiredWhen": { "name": "reasonIfRejected", "@field": "rejectReason", "@when": "status", "@equals": "rejected" } }
297
+ { "validator.presentIff": { "name": "usedAtWhenUsed", "@field": "usedAt", "@when": "isUsed", "@equals": "true" } }
298
+ { "validator.atLeastOne": { "name": "emailOrPhone", "@fields": ["email", "phone"] } }
299
+ ```
300
+
301
+ These are children of `object.entity`, alongside its fields and identities.
302
+
232
303
  ## Sources — `source.rdb` + `@kind`
233
304
 
234
305
  `source.rdb` declares where an entity's data lives. Read-only-ness derives from
@@ -41,6 +41,11 @@ export default defineConfig({
41
41
  dialect: "postgres", // "postgres" | "sqlite" | "d1" (D1 is TS-only)
42
42
  apiPrefix: "/api", // flows to routes AND client fetch URLs
43
43
  columnNamingStrategy: "snake_case", // "snake_case" (default) | "literal" | "kebab-case"
44
+ timestampMode: "string", // "string" (default, ISO-8601 wire contract) | "date" (Drizzle native Date)
45
+ pluralizeCollections: true, // default; table VARS auto-pluralize (AgentConfig → agentConfigs)
46
+ collectionNameOverrides: { // per-entity escape hatch for names the rule gets wrong
47
+ AuditLog: "auditLog", LlmTierConfig: "llmTierConfig",
48
+ },
44
49
  generators: [
45
50
  entityFile(), queriesFile(), routesFile(), barrel(),
46
51
  formFile(), tanstackQuery(), tanstackGrid(),
@@ -48,6 +53,13 @@ export default defineConfig({
48
53
  });
49
54
  ```
50
55
 
56
+ Naming + timestamp knobs are **codegen config**, not metadata attributes — a
57
+ collection variable name and a Drizzle column mode are per-port rendering choices
58
+ with no meaning to the other language ports, so they carry no cross-port
59
+ conformance cost. `collectionNameOverrides` wins over `pluralizeCollections` and is
60
+ applied consistently to the table declaration, every FK reference, the `relations()`
61
+ block, and the inferred types.
62
+
51
63
  A second file, `.metaobjects/config.json`, holds static project state parseable by
52
64
  non-TS tooling; `meta init` scaffolds both plus the `metaobjects/` source dir.
53
65
 
@@ -133,3 +145,21 @@ Deterministic per dialect: `field.string` + `@maxLength` → `varchar(N)`,
133
145
  (Postgres) + `gen_random_uuid()`, `field.enum` → `varchar` + `CHECK`. Override a
134
146
  field's physical column name with `@column` on the field; the DB schema name lives
135
147
  on `source.rdb` via `@schema`.
148
+
149
+ ### Value-object jsonb columns
150
+
151
+ A `field.object` with `@storage: jsonb` (or the default `subdocument`) becomes a
152
+ single typed jsonb column — the referenced value-object's TS type is carried onto
153
+ the Drizzle column via `.$type<>()`, and its Zod schema is the VO's `InsertSchema`:
154
+
155
+ ```ts
156
+ // field.object @objectRef=LlmConfig @storage=jsonb
157
+ llmConfigJson: jsonb("llm_config_json").$type<LlmConfig>(),
158
+ // field.object @objectRef=Triple @storage=jsonb isArray=true
159
+ triples: jsonb("triples").$type<Triple[]>(), // one jsonb column, NOT a native jsonb[]
160
+ ```
161
+
162
+ The VO type, its Zod `InsertSchema`, and this `.$type<>()` all import the VO from
163
+ the same module (layout/package/`extStyle`-aware resolution). An opaque jsonb column
164
+ (`field.string @dbColumnType: jsonb`) gets no `.$type<>()` — it stays `unknown`,
165
+ which is the correct shape for freeform payloads with no fixed VO.
@@ -123,6 +123,47 @@ For the `xml`-format example above with payload `{ displayName: "Ada", postCount
123
123
  bytes. You render the prompt, call your LLM client (provider-agnostic — codegen
124
124
  emits no provider-side schema), then parse the response.
125
125
 
126
+ ## Conditional content: data and flags, never branched prose
127
+
128
+ When a prompt's wording varies along some dimension — audience, tier, mode,
129
+ locale, entitlement, a domain variant — do NOT branch the prose in code and
130
+ concatenate strings. Branching prompt text in a service is the anti-pattern this
131
+ pillar exists to remove: it scatters the same distinction across call sites, each
132
+ re-encoded and free to drift, and none of it snapshot-tested. The variation
133
+ belongs in exactly two places, with a third for the rare genuine divergence:
134
+
135
+ - **Vocabulary as payload data.** The words and values that differ become typed
136
+ payload fields, pre-computed once from the varying dimension — a noun, a label,
137
+ a set of verbs (a list), an example. The template stays single and references
138
+ `{{term}}` / `{{#items}}…{{/items}}`. The prose *structure* is identical across
139
+ variants; only the data differs, so there is nothing to branch.
140
+ - **Presence as boolean flags.** When a whole block exists-or-not for a variant,
141
+ gate it with a section flag the payload sets: `{{#showBlock}}…{{/showBlock}}`.
142
+ Reserve flags for entire blocks — never mid-sentence word swaps, which are
143
+ vocabulary.
144
+ - **Variant text only when prose truly diverges.** If a section's wording — not
145
+ just its vocabulary — genuinely differs, select a per-variant text through the
146
+ provider seam (a `@textRef` variant, or an included partial) so the shared
147
+ prose still lives in one place. Expect to need this rarely.
148
+
149
+ A single resolver maps the varying dimension to that payload (the flags + the
150
+ vocabulary), so the distinction is defined ONCE and every template that depends
151
+ on it stays consistent.
152
+
153
+ ```
154
+ // WRONG — prose branched and concatenated in a service:
155
+ if (tier.isPremium()) sb.append("Your plan includes priority support.");
156
+ else sb.append("Upgrade any time for priority support.");
157
+ ```
158
+ ```mustache
159
+ {{! RIGHT — text in the template; the variant is data + a flag }}
160
+ {{supportLine}}
161
+ {{#isPremium}}(Priority queue enabled.){{/isPremium}}
162
+ ```
163
+
164
+ This stays deterministic and golden-testable per variant: render the template
165
+ against each value of the dimension and snapshot every variant.
166
+
126
167
  ## `verify` fails the build on prompt-drift
127
168
 
128
169
  For every template, the verify step resolves the text, parses each `{{...}}`
@@ -66,7 +66,40 @@ A clean run is silent; a failure names the drifted table/column. Bias toward
66
66
  trusting the tool — a drift failure almost always means the metadata changed and the
67
67
  DB didn't follow.
68
68
 
69
+ ## Index modeling (Postgres)
70
+
71
+ Secondary indexes carry physical-shape attributes contributed by the db provider
72
+ (they live on `identity.secondary`, not core):
73
+
74
+ - `@orders` — per-key sort direction, positional to `@fields` (`["asc", "desc"]`).
75
+ Omit for all-ascending; drives `DESC`-ordered index keys (e.g. a recency index).
76
+ - `@where` — a partial-index predicate (raw SQL, e.g. `"delivered_at IS NULL"`),
77
+ emitted as `WHERE (<pred>)`. The index then covers only matching rows.
78
+
79
+ ```json
80
+ { "identity.secondary": { "@fields": ["userId", "createdAt"],
81
+ "@orders": ["asc", "desc"], "@where": "archived_at IS NULL" } }
82
+ ```
83
+
84
+ ## Adopting an existing database (non-destructive)
85
+
86
+ `meta verify --db` / `meta migrate` can reach **zero drift** against a hand-built
87
+ schema without a rewrite:
88
+
89
+ - **`meta migrate --from-db`** reverse-engineers a baseline from the live DB so the
90
+ first diff is empty.
91
+ - **Auto schema-scope** — the diff manages only the schemas the metadata *declares*
92
+ (via `source.rdb @schema`); tables in undeclared schemas belong to another owner
93
+ and are left untouched. This is what lets several apps share one database, each
94
+ owning its own schema, with a clean per-owner `verify --db` and no manual ignore
95
+ lists. A downstream app that extends the toolkit's DB declares its own `@schema`,
96
+ models only its tables, and runs its own migrate/verify against that scope.
97
+ - **`identity.reference @constraintName`** pins a foreign-key constraint name so the
98
+ metadata can match an existing DB's naming convention without a destructive
99
+ rename.
100
+
69
101
  ## Not yet shipped
70
102
 
71
- Triggers, generated columns, partial/exclusion/check constraints, MySQL, and data
103
+ Triggers, generated columns, exclusion + CHECK constraints, MySQL, and data
72
104
  migrations (column-type changes needing data transformation error out with a hint).
105
+ (Partial + descending **indexes** *are* supported — see Index modeling above.)
@@ -47,7 +47,7 @@ def ref_vo(field: MetaData, root: MetaData) -> MetaData | None:
47
47
  """The ``@objectRef`` target VO for a nested-object field, or ``None`` when
48
48
  unresolvable. Matches first on the full ref, then the trailing simple-name
49
49
  segment (mirrors the runtime ``_resolve_object_ref`` short-name fallback)."""
50
- ref = field.attr(fc.FIELD_ATTR_OBJECT_REF)
50
+ ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
51
51
  if not isinstance(ref, str) or not ref:
52
52
  return None
53
53
  direct = _find_object(root, ref)
@@ -53,7 +53,7 @@ def _field_spec_literal(field: MetaData, owner: MetaData) -> str:
53
53
 
54
54
  if field.sub_type == fc.FIELD_SUBTYPE_ENUM:
55
55
  values_lit = fm.string_list_literal(fm.enum_values(field))
56
- alias_lit = fm.properties_map_literal(field.attr(fc.FIELD_ATTR_ENUM_ALIAS))
56
+ alias_lit = fm.properties_map_literal(field.attrs().get(fc.FIELD_ATTR_ENUM_ALIAS))
57
57
  # FR-011: resolve the three new enum args (field → object.value → "strip" for
58
58
  # normalize). Keep the back-compat 4-arg form when nothing is set; otherwise
59
59
  # emit the 7-arg form (..., coerce_default, normalize, default_value).
@@ -34,12 +34,12 @@ def fields(vo: MetaData) -> list[MetaData]:
34
34
  def is_array(field: MetaData) -> bool:
35
35
  """Array-ness from either form: the node property (programmatic build) or the
36
36
  ``@isArray`` attr (how metadata loads from JSON)."""
37
- return bool(field.is_array) or field.attr(KEY_IS_ARRAY) is True
37
+ return bool(field.is_array) or field.attrs().get(KEY_IS_ARRAY) is True
38
38
 
39
39
 
40
40
  def is_required(field: MetaData) -> bool:
41
41
  """``@required`` — accepts a bool ``True`` or the string ``"true"``."""
42
- v = field.attr(fc.FIELD_ATTR_REQUIRED)
42
+ v = field.attrs().get(fc.FIELD_ATTR_REQUIRED)
43
43
  if v is True:
44
44
  return True
45
45
  return isinstance(v, str) and v.lower() == "true"
@@ -49,7 +49,7 @@ def xml_text(field: MetaData) -> bool:
49
49
  """``@xmlText`` — the XML text-content extract marker (accepts a bool ``True`` or the
50
50
  string ``"true"``). When set, codegen bakes a ``FieldSpec.text_content_field(...)``.
51
51
  Mirrors the TS ``xmlText(field)`` helper."""
52
- v = field.attr(TEMPLATE_ATTR_XML_TEXT)
52
+ v = field.attrs().get(TEMPLATE_ATTR_XML_TEXT)
53
53
  if v is True:
54
54
  return True
55
55
  return isinstance(v, str) and v.lower() == "true"
@@ -57,7 +57,7 @@ def xml_text(field: MetaData) -> bool:
57
57
 
58
58
  def enum_values(field: MetaData) -> list[str]:
59
59
  """The string members of an enum field's ``@values`` attr (empty when absent)."""
60
- v = field.attr(fc.FIELD_ATTR_VALUES)
60
+ v = field.attrs().get(fc.FIELD_ATTR_VALUES)
61
61
  if isinstance(v, (list, tuple)):
62
62
  return [str(x) for x in v]
63
63
  return []
@@ -57,7 +57,7 @@ def _validator_constraints(field: MetaField) -> dict[str, object]:
57
57
  # String length: validator.length @min/@max + field @maxLength (max wins per field attr).
58
58
  min_len = _first_attr(field, vc.VALIDATOR_SUBTYPE_LENGTH, vc.VALIDATOR_ATTR_MIN)
59
59
  max_len = _first_attr(field, vc.VALIDATOR_SUBTYPE_LENGTH, vc.VALIDATOR_ATTR_MAX)
60
- field_max = field.attr(fc.FIELD_ATTR_MAX_LENGTH)
60
+ field_max = field.attrs().get(fc.FIELD_ATTR_MAX_LENGTH)
61
61
  if _is_int(field_max):
62
62
  max_len = field_max
63
63
  if min_len is not None:
@@ -110,14 +110,14 @@ def _field_line(field: MetaField, imports: set[str], config: GenConfig) -> tuple
110
110
  imports.update(pt.imports)
111
111
  type_expr = pt.expr
112
112
  if field.sub_type == fc.FIELD_SUBTYPE_OBJECT:
113
- ref = field.attr(fc.FIELD_ATTR_OBJECT_REF)
113
+ ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
114
114
  if ref:
115
115
  # @objectRef is FQN-expanded at load time; the generated VOs live
116
116
  # flat in one package, so import by the bare class name.
117
117
  ref_name = str(ref).split("::")[-1]
118
118
  imports.add(f"from .{ref_name} import {ref_name}")
119
- required = field.attr(fc.FIELD_ATTR_REQUIRED) is True
120
- default_raw = field.attr(fc.FIELD_ATTR_DEFAULT)
119
+ required = field.attrs().get(fc.FIELD_ATTR_REQUIRED) is True
120
+ default_raw = field.attrs().get(fc.FIELD_ATTR_DEFAULT)
121
121
  has_default = default_raw is not None
122
122
  enum_type_name = type_name if shared is not None else None
123
123
 
@@ -117,7 +117,7 @@ def _is_filterable(field: MetaField) -> bool:
117
117
  matching the Java/Kotlin/C# tolerance for either YAML-bool or raw-string
118
118
  value forms.
119
119
  """
120
- raw = field.attr(fc.FIELD_ATTR_FILTERABLE)
120
+ raw = field.attrs().get(fc.FIELD_ATTR_FILTERABLE)
121
121
  if raw is True:
122
122
  return True
123
123
  if isinstance(raw, str):
@@ -96,7 +96,7 @@ def _column_of(field: MetaField | None, fallback: str) -> str:
96
96
  ``@column`` overrides)."""
97
97
  if field is None:
98
98
  return fallback
99
- col = field.attr(fc.FIELD_ATTR_COLUMN)
99
+ col = field.attrs().get(fc.FIELD_ATTR_COLUMN)
100
100
  return col if isinstance(col, str) and col else field.name
101
101
 
102
102
 
@@ -172,7 +172,7 @@ def is_field_required(field: MetaField) -> bool:
172
172
  additionally treat the string ``"true"`` as required. The payload type's optionality
173
173
  and the extractor mapper's None-guarding are kept in lockstep by sharing THIS
174
174
  predicate, so do not "reconcile" it with the runtime predicate."""
175
- return field.attr(fc.FIELD_ATTR_REQUIRED) is True
175
+ return field.attrs().get(fc.FIELD_ATTR_REQUIRED) is True
176
176
 
177
177
 
178
178
  def _resolve_object_field_type(
@@ -186,7 +186,7 @@ def _resolve_object_field_type(
186
186
  (array). The target VO is scheduled for in-file emission (per-file dedupe, same
187
187
  mechanism as ``origin.collection``). Falls back to the bare type-map form when the
188
188
  ``@objectRef`` can't be resolved (defensive — loader validation gates it first)."""
189
- ref = field.attr(fc.FIELD_ATTR_OBJECT_REF)
189
+ ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
190
190
  if not isinstance(ref, str) or not ref:
191
191
  return _fallback_type(field)
192
192
  target = _resolve_object_by_short_or_fqn(root, ref)
@@ -114,7 +114,7 @@ def _derive_payload_field_tree(
114
114
  if f.type != TYPE_FIELD or not isinstance(f, MetaField):
115
115
  continue
116
116
  if f.sub_type == fc.FIELD_SUBTYPE_OBJECT:
117
- ref = f.attr(fc.FIELD_ATTR_OBJECT_REF)
117
+ ref = f.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
118
118
  if isinstance(ref, str) and ref:
119
119
  target = _resolve_nested_object_ref(root, ref)
120
120
  if target is not None and target.sub_type == OBJECT_SUBTYPE_VALUE:
@@ -34,7 +34,7 @@ def _prompt_style_enum(template: MetaData) -> str:
34
34
 
35
35
 
36
36
  def _opt_string_attr(field: MetaData, attr_name: str) -> str:
37
- v = field.attr(attr_name)
37
+ v = field.attrs().get(attr_name)
38
38
  return fm.py_string_literal(v) if isinstance(v, str) else "None"
39
39
 
40
40
 
@@ -54,7 +54,7 @@ def _prompt_field_literal(field: MetaData) -> str:
54
54
 
55
55
  if field.sub_type == fc.FIELD_SUBTYPE_ENUM:
56
56
  values_lit = fm.string_list_literal(fm.enum_values(field))
57
- enum_doc_lit = fm.properties_map_literal(field.attr(fc.FIELD_ATTR_ENUM_DOC))
57
+ enum_doc_lit = fm.properties_map_literal(field.attrs().get(fc.FIELD_ATTR_ENUM_DOC))
58
58
  return (
59
59
  f'PromptField("{name}", FieldKind.ENUM, {req}, array={array}, '
60
60
  f"enum_values={values_lit}, enum_doc={enum_doc_lit}, "
@@ -35,7 +35,7 @@ _SCALAR: dict[str, PyType] = {
35
35
  def field_is_array(field: MetaField) -> bool:
36
36
  """Array-ness from either form: the node property (programmatic build) or the
37
37
  `@isArray` attr (how metadata loads from JSON — the conformance-fixture form)."""
38
- return field.is_array or field.attr(KEY_IS_ARRAY) is True
38
+ return field.is_array or field.attrs().get(KEY_IS_ARRAY) is True
39
39
 
40
40
 
41
41
  def _py_str_literal(value: str) -> str:
@@ -66,7 +66,7 @@ def py_type_for(field: MetaField) -> PyType:
66
66
  becomes ``list[Literal[...]]``. An enum WITHOUT declared values falls back to
67
67
  ``str``."""
68
68
  if field.sub_type == fc.FIELD_SUBTYPE_OBJECT:
69
- ref = field.attr(fc.FIELD_ATTR_OBJECT_REF)
69
+ ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
70
70
  # @objectRef is expanded to a package-qualified FQN at load time
71
71
  # (e.g. ``app::pkg::Thing``); the emitted VOs all live flat in one
72
72
  # generated package, so type by the bare class name.
@@ -107,6 +107,7 @@ from .meta.presentation.view.view_constants import (
107
107
  )
108
108
  from .provider import Provider
109
109
  from .registry import AttrSchema, ChildRule, NodeFactory, TypeDefinition, TypeRegistry
110
+ from .validation_types import ReferenceDescriptor
110
111
  from .shared.base_types import (
111
112
  SUBTYPE_BASE,
112
113
  SUBTYPE_ROOT,
@@ -149,6 +150,7 @@ def _register_subtypes(
149
150
  factory: NodeFactory,
150
151
  child_rules: list[ChildRule] | None = None,
151
152
  attrs: list[AttrSchema] | None = None,
153
+ references: list[ReferenceDescriptor] | None = None,
152
154
  ) -> None:
153
155
  """Register one TypeDefinition per subtype. Centralises loop boilerplate only —
154
156
  all type knowledge (subtypes tuple, node class, child rules) stays with the caller."""
@@ -160,6 +162,7 @@ def _register_subtypes(
160
162
  factory=factory,
161
163
  child_rules=list(child_rules) if child_rules else [],
162
164
  attrs=list(attrs) if attrs else [],
165
+ references=list(references) if references else [],
163
166
  )
164
167
  )
165
168
 
@@ -390,6 +393,12 @@ core_provider.add(
390
393
  ),
391
394
  ],
392
395
  child_rules=[ChildRule(TYPE_ATTR, "*")],
396
+ # max_occurs/default_name are hardcoded here (matching the values in
397
+ # spec_metamodel/identity.json, which this port does NOT yet read). Sourcing them from
398
+ # that JSON — true single-source-of-truth across all ports — is the config-driven-
399
+ # validation work tracked in issue #51.
400
+ max_occurs=1,
401
+ default_name="primary",
393
402
  )
394
403
  )
395
404
 
@@ -420,6 +429,10 @@ core_provider.add(
420
429
  AttrSchema(name=IDENTITY_REFERENCE_ATTR_ENFORCE, value_type=ATTR_SUBTYPE_BOOLEAN, required=False),
421
430
  ],
422
431
  child_rules=[ChildRule(TYPE_ATTR, "*")],
432
+ # @references is a cross-reference to a real object (FK target) — the loader's
433
+ # registry-derived validation resolves it; "Entity.field" resolves the entity head.
434
+ references=[ReferenceDescriptor(
435
+ IDENTITY_REFERENCE_ATTR_REFERENCES, TYPE_OBJECT, None, True, "ERR_INVALID_REFERENCE")],
423
436
  )
424
437
  )
425
438
 
@@ -460,6 +473,10 @@ _register_subtypes(
460
473
  factory=MetaRelationship,
461
474
  child_rules=[ChildRule(TYPE_ATTR, "*")],
462
475
  attrs=_RELATIONSHIP_ATTRS,
476
+ # @objectRef is a cross-reference to a real object (the relationship target); the
477
+ # loader's registry-derived validation resolves it (dangling target = load error).
478
+ references=[ReferenceDescriptor(
479
+ RELATIONSHIP_ATTR_OBJECT_REF, TYPE_OBJECT, None, False, "ERR_INVALID_RELATIONSHIP")],
463
480
  )
464
481
 
465
482
  # source.* — base (no attrs) + rdb (paradigm subtype with @table/@kind/@role/@schema).
@@ -628,6 +645,26 @@ _VALIDATOR_ATTRS_BY_SUBTYPE: dict[str, list[AttrSchema]] = {
628
645
  ],
629
646
  vc.VALIDATOR_SUBTYPE_NUMERIC: list(_VALIDATOR_MIN_MAX_ATTRS),
630
647
  vc.VALIDATOR_SUBTYPE_ARRAY: list(_VALIDATOR_MIN_MAX_ATTRS),
648
+ # Cross-field validators — entity-scoped, reference sibling fields by name.
649
+ vc.VALIDATOR_SUBTYPE_COMPARISON: [
650
+ AttrSchema(name=vc.VALIDATOR_ATTR_LEFT, value_type=ATTR_SUBTYPE_STRING, required=True),
651
+ AttrSchema(name=vc.VALIDATOR_ATTR_OP, value_type=ATTR_SUBTYPE_STRING, required=True,
652
+ allowed_values=("gt", "gte", "lt", "lte", "ne", "eq")),
653
+ AttrSchema(name=vc.VALIDATOR_ATTR_RIGHT, value_type=ATTR_SUBTYPE_STRING, required=True),
654
+ ],
655
+ vc.VALIDATOR_SUBTYPE_REQUIRED_WHEN: [
656
+ AttrSchema(name=vc.VALIDATOR_ATTR_FIELD, value_type=ATTR_SUBTYPE_STRING, required=True),
657
+ AttrSchema(name=vc.VALIDATOR_ATTR_WHEN, value_type=ATTR_SUBTYPE_STRING, required=True),
658
+ AttrSchema(name=vc.VALIDATOR_ATTR_EQUALS, value_type=ATTR_SUBTYPE_STRING, required=True),
659
+ ],
660
+ vc.VALIDATOR_SUBTYPE_PRESENT_IFF: [
661
+ AttrSchema(name=vc.VALIDATOR_ATTR_FIELD, value_type=ATTR_SUBTYPE_STRING, required=True),
662
+ AttrSchema(name=vc.VALIDATOR_ATTR_WHEN, value_type=ATTR_SUBTYPE_STRING, required=True),
663
+ AttrSchema(name=vc.VALIDATOR_ATTR_EQUALS, value_type=ATTR_SUBTYPE_STRING, required=True),
664
+ ],
665
+ vc.VALIDATOR_SUBTYPE_AT_LEAST_ONE: [
666
+ AttrSchema(name=vc.VALIDATOR_ATTR_FIELDS, value_type=ATTR_SUBTYPE_STRING, required=True, is_array=True),
667
+ ],
631
668
  }
632
669
  for _sub, _attrs in _VALIDATOR_ATTRS_BY_SUBTYPE.items():
633
670
  core_provider.add(
@@ -23,6 +23,8 @@ class ErrorCode(str, Enum):
23
23
  # Vocabulary-only here until FR-024 Phase E (the Python loader does not
24
24
  # enforce these yet); the enum tracks the shared corpus codes.
25
25
  ERR_IDENTITY_NAME_REQUIRED = "ERR_IDENTITY_NAME_REQUIRED"
26
+ # A type.subType declared with maxOccurs (e.g. identity.primary) appears more than allowed under one parent.
27
+ ERR_TOO_MANY_OCCURRENCES = "ERR_TOO_MANY_OCCURRENCES"
26
28
  ERR_PROJECTION_IDENTITY_NOT_EXTENDED = "ERR_PROJECTION_IDENTITY_NOT_EXTENDED"
27
29
  ERR_IDENTITY_KEY_MISMATCH = "ERR_IDENTITY_KEY_MISMATCH"
28
30
  # FR-024 (ADR-0028): a source.* on an object.projection has a writable
@@ -76,6 +78,9 @@ class ErrorCode(str, Enum):
76
78
  # references / sourceRefField-not-matching / M:N-attr-on-1:N). The symmetric-
77
79
  # on-hetero + symmetric+sourceRefField rules emit ERR_BAD_ATTR_VALUE instead.
78
80
  ERR_INVALID_RELATIONSHIP = "ERR_INVALID_RELATIONSHIP"
81
+ # identity.reference @references names an FK target object that does not resolve
82
+ # to any object in the loaded tree (a dangling cross-reference between metadata).
83
+ ERR_INVALID_REFERENCE = "ERR_INVALID_REFERENCE"
79
84
  ERR_BAD_ATTR_FILTER = "ERR_BAD_ATTR_FILTER"
80
85
  # Reserved structural body key authored as an @-attr (source-v2 / ADR-0007).
81
86
  ERR_RESERVED_ATTR = "ERR_RESERVED_ATTR"
@@ -0,0 +1,95 @@
1
+ """The recursive validation walk, DERIVED FROM THE TYPE REGISTRY.
2
+
3
+ Each node's TypeDefinition carries its reference descriptors + imperative validator, so a
4
+ downstream provider's type validates itself just by being registered. Per node: apply the
5
+ type's declared references (resolve against the symbol table), invoke its validator, recurse.
6
+ Mirrors the TS/Java/C# realization.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from ..errors import ErrorCode, MetaError
12
+ from ..meta.core.object.meta_object import MetaObject
13
+ from ..meta.meta_data import MetaData
14
+ from ..meta.meta_root import MetaRoot
15
+ from ..registry import TypeRegistry
16
+ from ..shared.base_types import TYPE_OBJECT
17
+
18
+
19
+ class SymbolTable:
20
+ """An index of every top-level object, built once per load (the binder analogue)."""
21
+
22
+ def __init__(self) -> None:
23
+ self._index: dict[str, MetaData] = {}
24
+
25
+ @classmethod
26
+ def build(cls, root: MetaData) -> "SymbolTable":
27
+ t = cls()
28
+ for child in root.own_children():
29
+ if child.type == TYPE_OBJECT and isinstance(child, MetaObject):
30
+ if child.name:
31
+ t._index[child.name] = child
32
+ t._index[child.fqn()] = child
33
+ t._index[child.resolution_key()] = child
34
+ return t
35
+
36
+ def resolve_object(self, reference: str) -> MetaData | None:
37
+ return self._index.get(reference)
38
+
39
+
40
+ class ValidationContext:
41
+ def __init__(self, symbols: SymbolTable) -> None:
42
+ self.symbols = symbols
43
+ self.errors: list[MetaError] = []
44
+
45
+ def error(self, code: str, node: MetaData, message: str) -> None:
46
+ # Core descriptors use built-in codes; a downstream provider's custom code (not in
47
+ # the enum) maps to ERR_UNKNOWN for now (the message carries the detail).
48
+ try:
49
+ ec = ErrorCode(code)
50
+ except ValueError:
51
+ ec = ErrorCode.ERR_UNKNOWN
52
+ self.errors.append(MetaError(message, ec, envelope=node.source))
53
+
54
+
55
+ def run(root: MetaRoot, registry: TypeRegistry) -> list[MetaError]:
56
+ ctx = ValidationContext(SymbolTable.build(root))
57
+ _walk(root, registry, ctx)
58
+ return ctx.errors
59
+
60
+
61
+ def _walk(node: MetaData, registry: TypeRegistry, ctx: ValidationContext) -> None:
62
+ type_def = registry.find(node.type, node.sub_type)
63
+ if type_def is not None:
64
+ for desc in type_def.references:
65
+ raw = node.attr(desc.attr)
66
+ if not isinstance(raw, str) or raw == "":
67
+ continue # absence is the required-attr pass's job
68
+ entity_ref = raw.split(".", 1)[0] if desc.dotted_field_path else raw
69
+ target = ctx.symbols.resolve_object(entity_ref)
70
+ # Qualify the node name with its owning entity (e.g. "Order.items") so the error
71
+ # is locatable from the message alone, not just the source envelope.
72
+ qname = f"{node.parent.name}.{node.name}" if node.parent and node.parent.name else node.name
73
+ if target is None:
74
+ ctx.error(
75
+ desc.error_code, node,
76
+ f'{node.type}.{node.sub_type} "{qname}" @{desc.attr} "{raw}" '
77
+ f"does not resolve to an object.",
78
+ )
79
+ elif target.type != desc.target_type or (
80
+ desc.target_sub_type is not None and target.sub_type != desc.target_sub_type
81
+ ):
82
+ want = (
83
+ f"{desc.target_type}.{desc.target_sub_type}"
84
+ if desc.target_sub_type
85
+ else desc.target_type
86
+ )
87
+ ctx.error(
88
+ desc.error_code, node,
89
+ f'{node.type}.{node.sub_type} "{qname}" @{desc.attr} "{raw}" '
90
+ f"resolves to {target.type}.{target.sub_type}, not a {want}.",
91
+ )
92
+ if type_def.validate is not None:
93
+ type_def.validate(node, ctx)
94
+ for child in node.own_children():
95
+ _walk(child, registry, ctx)
@@ -106,7 +106,7 @@ def validate_discriminator(root: MetaData, errors: list[MetaError]) -> None:
106
106
  continue # root's own ERR_DISCRIMINATOR_FIELD_NOT_FOUND already fires
107
107
 
108
108
  if field.sub_type == FIELD_SUBTYPE_ENUM:
109
- enum_values = field.attr(FIELD_ATTR_VALUES)
109
+ enum_values = field.attrs().get(FIELD_ATTR_VALUES)
110
110
  members = [str(v) for v in enum_values] if isinstance(enum_values, (list, tuple)) else []
111
111
  if value not in members:
112
112
  errors.append(