metaobjects 0.19.2__tar.gz → 0.19.3__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 (390) hide show
  1. {metaobjects-0.19.2 → metaobjects-0.19.3}/PKG-INFO +1 -1
  2. {metaobjects-0.19.2 → metaobjects-0.19.3}/pyproject.toml +1 -1
  3. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/payload_vo_generator.py +196 -34
  4. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/errors.py +3 -0
  5. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_payload_vo_generator.py +89 -0
  6. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_render_helper_conformance.py +43 -1
  7. {metaobjects-0.19.2 → metaobjects-0.19.3}/.gitignore +0 -0
  8. {metaobjects-0.19.2 → metaobjects-0.19.3}/LICENSE +0 -0
  9. {metaobjects-0.19.2 → metaobjects-0.19.3}/README.md +0 -0
  10. {metaobjects-0.19.2 → metaobjects-0.19.3}/hatch_build.py +0 -0
  11. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/__init__.py +0 -0
  12. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/agent_context/__init__.py +0 -0
  13. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/agent_context/scaffold.py +0 -0
  14. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/apidocs/__init__.py +0 -0
  15. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/apidocs/api_model.py +0 -0
  16. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/apidocs/builder.py +0 -0
  17. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/apidocs/naming.py +0 -0
  18. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/apidocs/paths.py +0 -0
  19. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/apidocs/renderer.py +0 -0
  20. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/attr_class_map.py +0 -0
  21. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/cli.py +0 -0
  22. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  23. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/__init__.py +0 -0
  24. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/config.py +0 -0
  25. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/constants.py +0 -0
  26. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  27. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  28. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/format.py +0 -0
  29. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  30. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generator.py +0 -0
  31. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generator_registry.py +0 -0
  32. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/__init__.py +0 -0
  33. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  34. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  35. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
  36. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  37. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  38. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  39. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  40. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  41. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  42. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  43. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  44. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  45. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  46. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  47. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  48. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/runner.py +0 -0
  49. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  50. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  51. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  52. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  53. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  54. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  55. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/codegen/type_map.py +0 -0
  56. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/core_types.py +0 -0
  57. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/datatype.py +0 -0
  58. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/documentation/__init__.py +0 -0
  59. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/documentation/doc_constants.py +0 -0
  60. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/documentation/doc_provider.py +0 -0
  61. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/documentation/doc_schema.py +0 -0
  62. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/__init__.py +0 -0
  63. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/merge.py +0 -0
  64. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/meta_data_loader.py +0 -0
  65. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/registered_validation.py +0 -0
  66. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/sources/__init__.py +0 -0
  67. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/sources/directory_source.py +0 -0
  68. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/sources/file_source.py +0 -0
  69. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  70. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/sources/uri_source.py +0 -0
  71. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/validate_discriminator.py +0 -0
  72. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/validate_field_readonly.py +0 -0
  73. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  74. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  75. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  76. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/loader/validation_passes.py +0 -0
  77. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/__init__.py +0 -0
  78. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/__init__.py +0 -0
  79. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  80. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  81. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  82. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/field/__init__.py +0 -0
  83. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  84. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  85. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  86. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  87. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  88. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/index/__init__.py +0 -0
  89. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  90. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  91. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/__init__.py +0 -0
  92. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  93. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  94. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  95. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  96. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  97. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/object/value_object.py +0 -0
  98. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  99. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  100. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  101. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  102. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  103. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  104. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/meta_data.py +0 -0
  105. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/meta_root.py +0 -0
  106. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/__init__.py +0 -0
  107. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  108. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  109. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  110. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  111. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  112. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  113. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  114. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  115. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  116. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/__init__.py +0 -0
  117. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  118. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  119. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  120. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  121. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  122. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  123. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  124. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  125. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/provider_extends.py +0 -0
  126. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/template/__init__.py +0 -0
  127. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/template/meta_template.py +0 -0
  128. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  129. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/meta/template/template_constants.py +0 -0
  130. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/naming_refs.py +0 -0
  131. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/parser.py +0 -0
  132. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/parser_yaml.py +0 -0
  133. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/provider.py +0 -0
  134. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/py.typed +0 -0
  135. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/registry.py +0 -0
  136. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/registry_manifest.py +0 -0
  137. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/__init__.py +0 -0
  138. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/email_document.py +0 -0
  139. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/escapers.py +0 -0
  140. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  141. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/__init__.py +0 -0
  142. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/coerce.py +0 -0
  143. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/extract.py +0 -0
  144. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/extract_map.py +0 -0
  145. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  146. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/locate.py +0 -0
  147. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/normalize.py +0 -0
  148. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/strip.py +0 -0
  149. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/types.py +0 -0
  150. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  151. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/filesystem_provider.py +0 -0
  152. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/prompt/__init__.py +0 -0
  153. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  154. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  155. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  156. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  157. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  158. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/renderer.py +0 -0
  159. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/render/verify.py +0 -0
  160. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/runtime/__init__.py +0 -0
  161. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/runtime/llm_recorder.py +0 -0
  162. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  163. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/runtime/object_manager.py +0 -0
  164. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/runtime/tph.py +0 -0
  165. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/serializer_json.py +0 -0
  166. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/shared/__init__.py +0 -0
  167. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/shared/base_types.py +0 -0
  168. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/shared/separators.py +0 -0
  169. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/shared/structural.py +0 -0
  170. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/source/__init__.py +0 -0
  171. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/source/error_source.py +0 -0
  172. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/source/json_path.py +0 -0
  173. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/source/semantic_diff.py +0 -0
  174. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/source/yaml_positions.py +0 -0
  175. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  176. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/attr.json +0 -0
  177. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/db.json +0 -0
  178. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  179. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/field.json +0 -0
  180. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/identity.json +0 -0
  181. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/index.json +0 -0
  182. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/layout.json +0 -0
  183. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/object.json +0 -0
  184. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/origin.json +0 -0
  185. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  186. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  187. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/source.json +0 -0
  188. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/template.json +0 -0
  189. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  190. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/ui.json +0 -0
  191. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/validator.json +0 -0
  192. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/spec_metamodel/view.json +0 -0
  193. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/super_resolve.py +0 -0
  194. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/validation_types.py +0 -0
  195. {metaobjects-0.19.2 → metaobjects-0.19.3}/src/metaobjects/yaml_desugar.py +0 -0
  196. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/__init__.py +0 -0
  197. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/__init__.py +0 -0
  198. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  199. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/extends/expected/Program.py +0 -0
  200. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/extends/meta.json +0 -0
  201. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  202. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  203. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/nested-array/meta.json +0 -0
  204. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  205. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  206. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/scalars/meta.json +0 -0
  207. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  208. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/golden/vanilla/meta.json +0 -0
  209. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_abstract_conformance.py +0 -0
  210. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_api_docs_builder.py +0 -0
  211. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_api_docs_paths.py +0 -0
  212. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_cli.py +0 -0
  213. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_cli_providers.py +0 -0
  214. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_cli_registry.py +0 -0
  215. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  216. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_cli_verify_strict.py +0 -0
  217. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  218. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_constants_config.py +0 -0
  219. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_entity_model.py +0 -0
  220. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_enum_conformance.py +0 -0
  221. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  222. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_extractor_generator.py +0 -0
  223. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  224. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_format.py +0 -0
  225. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  226. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_fr010_output_codegen.py +0 -0
  227. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  228. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_generator.py +0 -0
  229. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_generator_extension_seams.py +0 -0
  230. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_golden.py +0 -0
  231. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  232. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_inheritance_conformance.py +0 -0
  233. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_instance_artifacts.py +0 -0
  234. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_m2m_codegen.py +0 -0
  235. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_origin_nullability.py +0 -0
  236. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_output_parser_generator.py +0 -0
  237. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_overwrite_policy.py +0 -0
  238. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_projection_compile.py +0 -0
  239. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_render_helper_generator.py +0 -0
  240. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_reverse_finders.py +0 -0
  241. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_router_generator.py +0 -0
  242. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_runner.py +0 -0
  243. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_template_data.py +0 -0
  244. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_template_generator.py +0 -0
  245. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_template_output_pattern.py +0 -0
  246. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_template_scope_helpers.py +0 -0
  247. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_template_scope_walk.py +0 -0
  248. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_template_spec.py +0 -0
  249. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_tph_codegen.py +0 -0
  250. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_trace_helper_generator.py +0 -0
  251. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_type_map.py +0 -0
  252. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_validation_conformance.py +0 -0
  253. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/codegen/test_write_through.py +0 -0
  254. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/__init__.py +0 -0
  255. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/capabilities.py +0 -0
  256. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/conformance-expected-failures.json +0 -0
  257. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/conformance_adapter.py +0 -0
  258. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/corpus.py +0 -0
  259. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/expected_failures.py +0 -0
  260. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/fixture_discovery.py +0 -0
  261. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/navigator.py +0 -0
  262. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  263. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_conformance.py +0 -0
  264. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_extract_conformance.py +0 -0
  265. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_extract_object_verdict.py +0 -0
  266. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  267. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_fr011_attrs.py +0 -0
  268. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_generator_registry_conformance.py +0 -0
  269. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_object_model_conformance.py +0 -0
  270. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_provider_composition_conformance.py +0 -0
  271. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_registry_conformance.py +0 -0
  272. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_runner_hardfail.py +0 -0
  273. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  274. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_strict_attr_load.py +0 -0
  275. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_template_codegen_conformance.py +0 -0
  276. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_template_generator_conformance.py +0 -0
  277. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/test_yaml_conformance.py +0 -0
  278. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  279. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/__init__.py +0 -0
  280. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/api_contract_assertions.py +0 -0
  281. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/api_contract_jsonb_server.py +0 -0
  282. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/api_contract_m2m_server.py +0 -0
  283. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/api_contract_server.py +0 -0
  284. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/generated_jsonb_app.py +0 -0
  285. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/generated_m2m_app.py +0 -0
  286. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/generated_router_app.py +0 -0
  287. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/generated_tph_app.py +0 -0
  288. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/meta_ai_trace.yaml +0 -0
  289. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/normalization.py +0 -0
  290. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/postgres_container.py +0 -0
  291. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/query_runner.py +0 -0
  292. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/scenarios.py +0 -0
  293. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_api_contract.py +0 -0
  294. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_api_contract_generated.py +0 -0
  295. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_api_contract_jsonb.py +0 -0
  296. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_api_contract_m2m.py +0 -0
  297. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  298. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_api_contract_tph_generated.py +0 -0
  299. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  300. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_llm_call_trace.py +0 -0
  301. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_normalization.py +0 -0
  302. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_query_scenarios.py +0 -0
  303. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/integration/test_runtime_return_types.py +0 -0
  304. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/open_closed_proof_test.py +0 -0
  305. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/__init__.py +0 -0
  306. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/__init__.py +0 -0
  307. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_coerce.py +0 -0
  308. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_extract.py +0 -0
  309. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_extract_map.py +0 -0
  310. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  311. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_locate.py +0 -0
  312. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_model.py +0 -0
  313. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_normalize.py +0 -0
  314. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_strip.py +0 -0
  315. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  316. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/prompt/__init__.py +0 -0
  317. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/prompt/test_output_format_renderer.py +0 -0
  318. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_email_document.py +0 -0
  319. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_filesystem_provider.py +0 -0
  320. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_output_format_renderer_nested.py +0 -0
  321. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_output_prompt_conformance.py +0 -0
  322. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_render_conformance.py +0 -0
  323. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_render_max_chars.py +0 -0
  324. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_verify.py +0 -0
  325. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/render/test_verify_conformance.py +0 -0
  326. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/__init__.py +0 -0
  327. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_fr5c_merge_attribution.py +0 -0
  328. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_fr5d_reference_resolution.py +0 -0
  329. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_fr5e_database_source_shape.py +0 -0
  330. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_json_path.py +0 -0
  331. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_semantic_diff.py +0 -0
  332. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_source_on_node.py +0 -0
  333. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/source/test_yaml_positions.py +0 -0
  334. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/test_api_docs_accuracy.py +0 -0
  335. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/__init__.py +0 -0
  336. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_agent_context_staleness.py +0 -0
  337. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_capabilities.py +0 -0
  338. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_common_attrs.py +0 -0
  339. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_core_types.py +0 -0
  340. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_effective_package.py +0 -0
  341. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_errors.py +0 -0
  342. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_field_enum.py +0 -0
  343. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_field_map_validation.py +0 -0
  344. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  345. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  346. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_index_lookup.py +0 -0
  347. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_llm_recorder.py +0 -0
  348. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_loader.py +0 -0
  349. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_loader_bom.py +0 -0
  350. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_loader_class.py +0 -0
  351. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_merge.py +0 -0
  352. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_meta_attr.py +0 -0
  353. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_meta_data.py +0 -0
  354. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_meta_source.py +0 -0
  355. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_module_shortcuts.py +0 -0
  356. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_n2m_resolver.py +0 -0
  357. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  358. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  359. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  360. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_object_manager_write_through.py +0 -0
  361. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_one_primary_source.py +0 -0
  362. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_parser.py +0 -0
  363. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_parser_yaml.py +0 -0
  364. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_provider.py +0 -0
  365. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_provider_extension.py +0 -0
  366. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_registry.py +0 -0
  367. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_registry_completeness.py +0 -0
  368. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_registry_extend.py +0 -0
  369. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_registry_sealed.py +0 -0
  370. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_relationship_referential_actions.py +0 -0
  371. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_resolution_key.py +0 -0
  372. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  373. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_serializer.py +0 -0
  374. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_shared_constants.py +0 -0
  375. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_smoke.py +0 -0
  376. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_source_escapes.py +0 -0
  377. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_sources.py +0 -0
  378. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_strict_child_placement.py +0 -0
  379. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_super_resolve.py +0 -0
  380. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_template_toolcall.py +0 -0
  381. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  382. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_validation_attr_schema.py +0 -0
  383. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_validation_filter_values.py +0 -0
  384. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_validation_origin_195.py +0 -0
  385. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_validation_origin_paths.py +0 -0
  386. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_validation_sort_field.py +0 -0
  387. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_validation_warnings.py +0 -0
  388. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_write_coercion_arrays.py +0 -0
  389. {metaobjects-0.19.2 → metaobjects-0.19.3}/tests/unit/test_yaml_desugar.py +0 -0
  390. {metaobjects-0.19.2 → metaobjects-0.19.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: metaobjects
3
- Version: 0.19.2
3
+ Version: 0.19.3
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.19.2"
3
+ version = "0.19.3"
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"
@@ -69,6 +69,13 @@ from metaobjects.shared.separators import PACKAGE_SEP
69
69
 
70
70
  _GENERATOR_NAME = "payload-vo-generator"
71
71
 
72
+ # ADR-0044 backstop error code — a codegen-time (not loader) error, peer of the
73
+ # render tier's ERR_VAR_NOT_ON_PAYLOAD. Declared LOCALLY here for the same reason
74
+ # the TS reference (codegen-ts/src/payload-codegen.ts) declares it locally rather
75
+ # than in the shared cross-port ledger: promoting it to the ledger is coordinated
76
+ # with the Java/Kotlin follow-up so no port reddens on a code it doesn't yet emit.
77
+ ERR_PAYLOAD_NAME_COLLISION = "ERR_PAYLOAD_NAME_COLLISION"
78
+
72
79
 
73
80
  # ---------------------------------------------------------------------------
74
81
  # Naming helpers (snake_case mirrors the router/output-parser local helpers).
@@ -193,13 +200,17 @@ def _resolve_object_field_type(
193
200
  field: MetaField,
194
201
  root: MetaData,
195
202
  nested_emit_queue: list[tuple[MetaObject, str]],
196
- emitted_nested_fqns: set[str],
203
+ emitted_nested_keys: set[str],
204
+ name_map: dict[str, str],
197
205
  ) -> tuple[str, set[str]]:
198
206
  """A plain ``field.object`` (``@objectRef``, no origin child) — resolve to the
199
- nested ``<TargetShortName>Payload`` (single) or ``list[<TargetShortName>Payload]``
200
- (array). The target VO is scheduled for in-file emission (per-file dedupe, same
201
- mechanism as ``origin.collection``). Falls back to the bare type-map form when the
202
- ``@objectRef`` can't be resolved (defensive loader validation gates it first)."""
207
+ nested payload class (single) or ``list[...]`` (array). The class name comes
208
+ from the ADR-0044 *name_map* (bare ``<Short>Payload`` when unique in the module
209
+ closure, package-qualified on a cross-package short-name collision). The target
210
+ VO is scheduled for in-file emission, deduped by ``resolution_key()`` (NOT
211
+ ``fqn()``, which returns the bare name and would collapse two same-short-name
212
+ VOs from different packages into one). Falls back to the bare type-map form when
213
+ the ``@objectRef`` can't be resolved (defensive — loader validation gates it)."""
203
214
  ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
204
215
  if not isinstance(ref, str) or not ref:
205
216
  return _fallback_type(field)
@@ -211,12 +222,14 @@ def _resolve_object_field_type(
211
222
  # both loaded trees (file_default_package) and programmatic trees (root package).
212
223
  referrer_pkg = _pkg_of(field.parent) if field.parent is not None else ""
213
224
  target = resolve_object_ref(root, ref, referrer_pkg)
214
- if target is None:
225
+ if not isinstance(target, MetaObject): # narrows MetaData|None -> MetaObject
215
226
  return _fallback_type(field)
216
- nested_class = payload_class_name(target.name)
217
- target_fqn = target.fqn()
218
- if target_fqn not in emitted_nested_fqns:
219
- emitted_nested_fqns.add(target_fqn)
227
+ target_key = target.resolution_key()
228
+ # name_map was populated by the ADR-0044 closure walk (pass 1/2), which visits
229
+ # the identical targets; the fallback guards a defensive gap only.
230
+ nested_class = name_map.get(target_key) or payload_class_name(target.name)
231
+ if target_key not in emitted_nested_keys:
232
+ emitted_nested_keys.add(target_key)
220
233
  nested_emit_queue.append((target, nested_class))
221
234
  if type_map.field_is_array(field):
222
235
  return f"list[{nested_class}]", set()
@@ -345,16 +358,20 @@ def _resolve_collection_type(
345
358
  root: MetaData,
346
359
  fallback: MetaField,
347
360
  nested_emit_queue: list[tuple[MetaObject, str]],
348
- emitted_nested_fqns: set[str],
361
+ emitted_nested_keys: set[str],
362
+ name_map: dict[str, str],
349
363
  ) -> tuple[str, set[str]]:
350
364
  """``origin.collection @via "Parent.rel"`` — walk Parent's relationship to
351
- its ``@objectRef`` target, schedule a nested ``<TargetShortName>Payload``
352
- for in-file emission, return ``list[<TargetShortName>Payload]``.
353
-
354
- Dedupe is per-file via *emitted_nested_fqns* — if the same target is
355
- referenced by two fields in the same payload module, only one nested
356
- class is emitted. Cross-file dedupe would leave forward-references
357
- dangling (see the module docstring)."""
365
+ its ``@objectRef`` target, schedule a nested payload class for in-file
366
+ emission, return ``list[<NestedClass>]``. The class name comes from the
367
+ ADR-0044 *name_map* (bare when unique in the module closure, package-qualified
368
+ on a cross-package short-name collision).
369
+
370
+ Dedupe is per-file via *emitted_nested_keys*, keyed by ``resolution_key()`` —
371
+ if the same target is referenced by two fields in the same payload module,
372
+ only one nested class is emitted; two same-short-name targets in DIFFERENT
373
+ packages are NOT collapsed (each keeps its own key + qualified name).
374
+ Cross-file dedupe would leave forward-references dangling (module docstring)."""
358
375
  via = origin.attr(ORIGIN_ATTR_VIA) # ADR-0039 sanctioned own: origin.* never inherits (ADR-0029)
359
376
  if not isinstance(via, str) or not via:
360
377
  return _fallback_type(fallback)
@@ -374,11 +391,10 @@ def _resolve_collection_type(
374
391
  target = _resolve_object_by_short_or_fqn(root, target_ref)
375
392
  if target is None:
376
393
  return _fallback_type(fallback)
377
- # MetaData.name is the short name (no `::`); see _resolve_object_by_short_or_fqn.
378
- nested_class = payload_class_name(target.name)
379
- target_fqn = target.fqn()
380
- if target_fqn not in emitted_nested_fqns:
381
- emitted_nested_fqns.add(target_fqn)
394
+ target_key = target.resolution_key()
395
+ nested_class = name_map.get(target_key) or payload_class_name(target.name)
396
+ if target_key not in emitted_nested_keys:
397
+ emitted_nested_keys.add(target_key)
382
398
  nested_emit_queue.append((target, nested_class))
383
399
  return f"list[{nested_class}]", set()
384
400
 
@@ -393,8 +409,9 @@ def _resolve_field_type(
393
409
  field: MetaField,
394
410
  root: MetaData,
395
411
  nested_emit_queue: list[tuple[MetaObject, str]],
396
- emitted_nested_fqns: set[str],
412
+ emitted_nested_keys: set[str],
397
413
  enum_aliases: dict[str, str],
414
+ name_map: dict[str, str],
398
415
  ) -> tuple[str, set[str]]:
399
416
  """Resolve the Python annotation for one payload-VO field, honoring any
400
417
  ``origin.*`` child. Falls back to ``type_map.py_type_for`` when none.
@@ -415,7 +432,7 @@ def _resolve_field_type(
415
432
  # reference an undefined bare entity name (Pydantic "not fully defined").
416
433
  if field.sub_type == fc.FIELD_SUBTYPE_OBJECT:
417
434
  return _resolve_object_field_type(
418
- field, root, nested_emit_queue, emitted_nested_fqns
435
+ field, root, nested_emit_queue, emitted_nested_keys, name_map
419
436
  )
420
437
  # A ``field.enum`` → Literal[...] (inline) or a named module alias (shared).
421
438
  enum_type = _enum_field_type(field, enum_aliases)
@@ -429,11 +446,142 @@ def _resolve_field_type(
429
446
  return _resolve_aggregate_type(origin, root, field)
430
447
  if origin.sub_type == "collection":
431
448
  return _resolve_collection_type(
432
- origin, root, field, nested_emit_queue, emitted_nested_fqns
449
+ origin, root, field, nested_emit_queue, emitted_nested_keys, name_map
433
450
  )
434
451
  return _fallback_type(field)
435
452
 
436
453
 
454
+ # ---------------------------------------------------------------------------
455
+ # ADR-0044 — collision-scoped nested-payload naming (three-pass pipeline).
456
+ #
457
+ # A payload module is a SINGLE self-contained file, so its `@objectRef` /
458
+ # `origin.collection` closure is the collision domain (ADR-0044's "closure of the
459
+ # payload root(s) emitted into one artifact"). Two value-objects sharing a bare
460
+ # short name across packages (`acme::alpha::Note` + `acme::beta::Note`, both
461
+ # reachable from one payload) must emit as DISTINCT classes — the pre-ADR-0044
462
+ # code deduped by `fqn()` (which returns the BARE name here), collapsing them to
463
+ # one class, last-wins, silently dropping the second shape. Pass 1 collects the
464
+ # closure keyed by `resolution_key()` (the true package-qualified FQN); pass 2
465
+ # assigns names as a pure function of the closure (bare when unique, package-
466
+ # qualified on collision, hard fail on a still-colliding derived name); pass 3
467
+ # (the existing emit path) uses the name map for both declaration and reference.
468
+ # ---------------------------------------------------------------------------
469
+
470
+
471
+ def _package_qualified_name(pkg: str, short_name: str) -> str:
472
+ """ADR-0044 — PascalCase each ``::``-segment of *pkg*, concatenate, append the
473
+ bare *short_name* (``acme::alpha`` + ``Note`` → ``AcmeAlphaNote``). A root-level
474
+ (empty-package) node keeps its bare short name — the loader's own-package
475
+ uniqueness already precludes two root-level VOs sharing a name, so this can't
476
+ silently under-qualify."""
477
+ if pkg == "":
478
+ return short_name
479
+ return "".join(_pascal(seg) for seg in pkg.split(PACKAGE_SEP)) + short_name
480
+
481
+
482
+ def _nested_target_of(field: MetaField, root: MetaData) -> MetaObject | None:
483
+ """The nested-payload target VO a *field* contributes to the module closure,
484
+ or ``None`` when it contributes no nested class. Mirrors the resolution in
485
+ :func:`_resolve_object_field_type` (a plain ``field.object`` ``@objectRef``)
486
+ and :func:`_resolve_collection_type` (``origin.collection`` ``@via``) EXACTLY,
487
+ so the ADR-0044 closure walk and the emission walk agree on the target set.
488
+ ``origin.passthrough`` / ``origin.aggregate`` yield scalar types (no nested
489
+ class) and so contribute nothing."""
490
+ origin = _find_origin_child(field)
491
+ if origin is None:
492
+ if field.sub_type != fc.FIELD_SUBTYPE_OBJECT:
493
+ return None
494
+ ref = field.attrs().get(fc.FIELD_ATTR_OBJECT_REF)
495
+ if not isinstance(ref, str) or not ref:
496
+ return None
497
+ referrer_pkg = _pkg_of(field.parent) if field.parent is not None else ""
498
+ target = resolve_object_ref(root, ref, referrer_pkg)
499
+ return target if isinstance(target, MetaObject) else None
500
+ if origin.sub_type == "collection":
501
+ via = origin.attr(ORIGIN_ATTR_VIA) # ADR-0039 sanctioned own: origin.* never inherits
502
+ if not isinstance(via, str) or not via:
503
+ return None
504
+ parts = _split_dotted_ref(via)
505
+ if parts is None:
506
+ return None
507
+ parent_name, rel_name = parts
508
+ parent = _resolve_object_by_short_or_fqn(root, parent_name)
509
+ if parent is None:
510
+ return None
511
+ rel = _find_relationship_on(parent, rel_name)
512
+ if rel is None:
513
+ return None
514
+ target_ref = rel.object_ref()
515
+ if not target_ref:
516
+ return None
517
+ return _resolve_object_by_short_or_fqn(root, target_ref)
518
+ return None
519
+
520
+
521
+ def _collect_nested_closure(
522
+ root: MetaData,
523
+ payload_vo: MetaObject,
524
+ closure: dict[str, MetaObject],
525
+ seen: set[str],
526
+ ) -> None:
527
+ """ADR-0044 pass 1 — walk *payload_vo*'s transitive nested-payload closure,
528
+ collecting each target VO keyed by ``resolution_key()`` (never ``fqn()`` —
529
+ which returns the bare name and would collapse a cross-package short-name
530
+ collision). *seen* is seeded with the primary payload VO's key so the primary
531
+ (which is named after the TEMPLATE, outside the VO-short-name collision
532
+ domain) is never treated as a nested class, and doubles as the cycle guard."""
533
+ for field in payload_vo.fields():
534
+ if not isinstance(field, MetaField):
535
+ continue
536
+ target = _nested_target_of(field, root)
537
+ if target is None:
538
+ continue
539
+ key = target.resolution_key()
540
+ if key in seen:
541
+ continue
542
+ seen.add(key)
543
+ closure[key] = target
544
+ _collect_nested_closure(root, target, closure, seen)
545
+
546
+
547
+ def _assign_nested_names(closure: dict[str, MetaObject]) -> dict[str, str]:
548
+ """ADR-0044 pass 2 — ``resolution_key()`` → emitted class name. A PURE function
549
+ of the closure's ``(key, short-name, package)`` triples, never of traversal
550
+ order: a bare short name unique in the closure emits ``<Short>Payload``
551
+ (byte-identical to pre-ADR-0044 output); a short-name collision emits EVERY
552
+ member under its package-qualified derived name
553
+ (``<PkgSegmentsPascal><Short>Payload``). If two distinct keys still derive the
554
+ same name, fail loud with ``ERR_PAYLOAD_NAME_COLLISION`` — never silently
555
+ collide a second time."""
556
+ by_short: dict[str, list[str]] = {}
557
+ for key, node in closure.items():
558
+ by_short.setdefault(node.name, []).append(key)
559
+
560
+ name_map: dict[str, str] = {}
561
+ for short, keys in by_short.items():
562
+ if len(keys) == 1:
563
+ name_map[keys[0]] = payload_class_name(short)
564
+ continue
565
+ for key in keys:
566
+ node = closure[key]
567
+ name_map[key] = payload_class_name(_package_qualified_name(_pkg_of(node), short))
568
+
569
+ # Backstop — sorted by key so both the emptiness of the colliding set and the
570
+ # pair named in the message are a pure function of the closure, not dict order.
571
+ owner: dict[str, str] = {}
572
+ for key in sorted(name_map):
573
+ emitted = name_map[key]
574
+ existing = owner.get(emitted)
575
+ if existing is not None and existing != key:
576
+ raise ValueError(
577
+ f"{ERR_PAYLOAD_NAME_COLLISION}: payload record name collision: "
578
+ f'"{emitted}" derives from both "{existing}" and "{key}" — rename one '
579
+ "value-object or move it to a package that derives a distinct name"
580
+ )
581
+ owner[emitted] = key
582
+ return name_map
583
+
584
+
437
585
  # ---------------------------------------------------------------------------
438
586
  # Class-block emission.
439
587
  # ---------------------------------------------------------------------------
@@ -444,10 +592,11 @@ def _emit_payload_class(
444
592
  payload_vo: MetaObject,
445
593
  root: MetaData,
446
594
  nested_emit_queue: list[tuple[MetaObject, str]],
447
- emitted_nested_fqns: set[str],
595
+ emitted_nested_keys: set[str],
448
596
  extra_imports: set[str],
449
597
  enum_aliases: dict[str, str],
450
598
  docstring: str,
599
+ name_map: dict[str, str],
451
600
  ) -> list[str]:
452
601
  """Build the source lines for one Pydantic ``BaseModel`` subclass."""
453
602
  lines: list[str] = [f"class {class_name}(BaseModel):", f' """{docstring}"""']
@@ -456,7 +605,7 @@ def _emit_payload_class(
456
605
  if not isinstance(field, MetaField):
457
606
  continue
458
607
  annotation, imports = _resolve_field_type(
459
- field, root, nested_emit_queue, emitted_nested_fqns, enum_aliases
608
+ field, root, nested_emit_queue, emitted_nested_keys, enum_aliases, name_map
460
609
  )
461
610
  extra_imports.update(imports)
462
611
  # Optionality mirrors the cross-port (TS) payload-codegen: a ``@required``
@@ -515,9 +664,18 @@ def render_payload_vo(
515
664
  if payload is None:
516
665
  return None
517
666
 
667
+ # ADR-0044 pass 1/2 — the collision domain is this module's nested-payload
668
+ # closure. Seed `seen` with the primary VO's key so the primary (named after
669
+ # the TEMPLATE, not the VO) stays out of the VO-short-name collision domain.
670
+ closure: dict[str, MetaObject] = {}
671
+ _collect_nested_closure(root, payload, closure, {payload.resolution_key()})
672
+ name_map = _assign_nested_names(closure)
673
+
518
674
  # Per-file dedupe set: scoped to this single render call so each emitted
519
- # module is self-contained (no cross-template forward references).
520
- emitted_nested_fqns: set[str] = set()
675
+ # module is self-contained (no cross-template forward references). Keyed by
676
+ # ``resolution_key()`` (see _resolve_object_field_type) so two same-short-name
677
+ # VOs from different packages both emit.
678
+ emitted_nested_keys: set[str] = set()
521
679
  class_name = payload_class_name(template.name)
522
680
  extra_imports: set[str] = set()
523
681
  nested_emit_queue: list[tuple[MetaObject, str]] = []
@@ -541,13 +699,14 @@ def render_payload_vo(
541
699
  payload_vo=payload,
542
700
  root=root,
543
701
  nested_emit_queue=nested_emit_queue,
544
- emitted_nested_fqns=emitted_nested_fqns,
702
+ emitted_nested_keys=emitted_nested_keys,
545
703
  extra_imports=extra_imports,
546
704
  enum_aliases=enum_aliases,
547
705
  docstring=(
548
706
  f"GENERATED payload for template ``{template.name}``.\n\n"
549
707
  f" Field shape derived from the ``{payload.name}`` object.value."
550
708
  ),
709
+ name_map=name_map,
551
710
  )
552
711
  if strict_extras:
553
712
  primary_block = _with_strict_extras(primary_block)
@@ -564,12 +723,13 @@ def render_payload_vo(
564
723
  payload_vo=target,
565
724
  root=root,
566
725
  nested_emit_queue=nested_emit_queue,
567
- emitted_nested_fqns=emitted_nested_fqns,
726
+ emitted_nested_keys=emitted_nested_keys,
568
727
  extra_imports=extra_imports,
569
728
  enum_aliases=enum_aliases,
570
729
  docstring=(
571
730
  f"GENERATED nested payload for collection target ``{target.name}``."
572
731
  ),
732
+ name_map=name_map,
573
733
  )
574
734
  if strict_extras:
575
735
  block = _with_strict_extras(block)
@@ -650,10 +810,11 @@ class PayloadVoGenerator:
650
810
  payload_vo: MetaObject,
651
811
  root: MetaData,
652
812
  nested_emit_queue: list[tuple[MetaObject, str]],
653
- emitted_nested_fqns: set[str],
813
+ emitted_nested_keys: set[str],
654
814
  extra_imports: set[str],
655
815
  enum_aliases: dict[str, str],
656
816
  docstring: str,
817
+ name_map: dict[str, str],
657
818
  ) -> list[str]:
658
819
  """EXTENSION SEAM — the source lines for one Pydantic ``BaseModel`` subclass
659
820
  (primary OR a nested collection target). Defaults to the module-level
@@ -664,10 +825,11 @@ class PayloadVoGenerator:
664
825
  payload_vo,
665
826
  root,
666
827
  nested_emit_queue,
667
- emitted_nested_fqns,
828
+ emitted_nested_keys,
668
829
  extra_imports,
669
830
  enum_aliases,
670
831
  docstring,
832
+ name_map,
671
833
  )
672
834
 
673
835
  def _render_module(self, template: MetaTemplate, root: MetaData) -> str | None:
@@ -133,6 +133,9 @@ class ErrorCode(str, Enum):
133
133
  ERR_PARTIAL_UNRESOLVED = "ERR_PARTIAL_UNRESOLVED"
134
134
  ERR_REQUIRED_SLOT_UNUSED = "ERR_REQUIRED_SLOT_UNUSED"
135
135
  ERR_VAR_NOT_ON_PAYLOAD = "ERR_VAR_NOT_ON_PAYLOAD"
136
+ # Codegen (ADR-0044): two value-object FQNs in one payload artifact derive the same
137
+ # emitted record name even after package-qualification. Peer of ERR_VAR_NOT_ON_PAYLOAD.
138
+ ERR_PAYLOAD_NAME_COLLISION = "ERR_PAYLOAD_NAME_COLLISION"
136
139
  ERR_OUTPUT_TAG_MISSING = "ERR_OUTPUT_TAG_MISSING"
137
140
  # SP-H Unit9 — @filterable: true on a field subtype with no filter-operator
138
141
  # band (e.g. field.object). Would silently generate an empty-ops filter.
@@ -8,10 +8,13 @@ same target).
8
8
  """
9
9
  from __future__ import annotations
10
10
 
11
+ import pytest
12
+
11
13
  import metaobjects.core_types # noqa: F401 — side-effect: registers attr classes
12
14
  from metaobjects.codegen.config import GenConfig
13
15
  from metaobjects.codegen.generator import GenContext
14
16
  from metaobjects.codegen.generators.payload_vo_generator import (
17
+ ERR_PAYLOAD_NAME_COLLISION,
15
18
  PayloadVoGenerator,
16
19
  payload_class_name,
17
20
  payload_module_name,
@@ -428,6 +431,92 @@ def test_plain_object_field_strips_fqn_to_bare_nested_payload() -> None:
428
431
  assert "::" not in code
429
432
 
430
433
 
434
+ def test_cross_package_short_name_collision_qualifies_both_nested_classes() -> None:
435
+ """ADR-0044 — two ``object.value`` ``Note``s in different packages, both reachable
436
+ from one payload by FQN ``@objectRef``, emit as TWO distinct package-qualified
437
+ classes (``AcmeAlphaNotePayload`` / ``AcmeBetaNotePayload``) — never one shadowed
438
+ ``NotePayload`` that drops the second shape. The un-colliding ``Digest`` primary
439
+ stays bare (template-named)."""
440
+ alpha = _value_object("Note", [_field("alphaText", fc.FIELD_SUBTYPE_STRING)], package="acme::alpha")
441
+ beta = _value_object("Note", [_field("betaText", fc.FIELD_SUBTYPE_STRING)], package="acme::beta")
442
+ digest = _value_object(
443
+ "Digest",
444
+ [
445
+ _object_field("fromAlpha", "acme::alpha::Note"),
446
+ _object_field("fromBeta", "acme::beta::Note"),
447
+ ],
448
+ package="acme::app",
449
+ )
450
+ tmpl = _template("DigestOut", "Digest")
451
+ root = _root([alpha, beta, digest, tmpl])
452
+ out = render_payload_vo(tmpl, root)
453
+ assert out is not None
454
+ assert "class AcmeAlphaNotePayload(BaseModel):" in out
455
+ assert "class AcmeBetaNotePayload(BaseModel):" in out
456
+ assert "class NotePayload(BaseModel):" not in out
457
+ assert "fromAlpha: AcmeAlphaNotePayload | None = None" in out
458
+ assert "fromBeta: AcmeBetaNotePayload | None = None" in out
459
+ assert '__all__ = ["DigestOutPayload", "AcmeAlphaNotePayload", "AcmeBetaNotePayload"]' in out
460
+
461
+
462
+ def test_nested_of_nested_collision_qualifies_across_depths() -> None:
463
+ """ADR-0044 — the collision domain is the WHOLE transitive closure, not one
464
+ depth. A ``Note`` reached at depth 2 (via ``Outer.inner``) collides with a
465
+ ``Note`` reached at depth 1; both qualify (``AcmeBetaNotePayload`` /
466
+ ``AcmeGammaNotePayload``) while the un-colliding intermediate ``Outer`` stays
467
+ bare. Guards the recursive `_collect_nested_closure` walk."""
468
+ beta_note = _value_object("Note", [_field("betaText", fc.FIELD_SUBTYPE_STRING)], package="acme::beta")
469
+ gamma_note = _value_object("Note", [_field("gammaText", fc.FIELD_SUBTYPE_STRING)], package="acme::gamma")
470
+ outer = _value_object(
471
+ "Outer", [_object_field("inner", "acme::beta::Note")], package="acme::alpha"
472
+ )
473
+ digest = _value_object(
474
+ "Digest",
475
+ [
476
+ _object_field("fromOuter", "acme::alpha::Outer"),
477
+ _object_field("fromGamma", "acme::gamma::Note"),
478
+ ],
479
+ package="acme::app",
480
+ )
481
+ tmpl = _template("DigestOut", "Digest")
482
+ root = _root([beta_note, gamma_note, outer, digest, tmpl])
483
+ out = render_payload_vo(tmpl, root)
484
+ assert out is not None
485
+ assert "class OuterPayload(BaseModel):" in out # unique → bare
486
+ assert "class AcmeBetaNotePayload(BaseModel):" in out # depth-2 collision member
487
+ assert "class AcmeGammaNotePayload(BaseModel):" in out # depth-1 collision member
488
+ assert "class NotePayload(BaseModel):" not in out
489
+ assert "inner: AcmeBetaNotePayload | None = None" in out
490
+ assert "fromGamma: AcmeGammaNotePayload | None = None" in out
491
+
492
+
493
+ def test_derived_name_still_colliding_fails_loud() -> None:
494
+ """ADR-0044 §4 backstop — two DISTINCT package FQNs whose package-qualified derived
495
+ names still collide (``acme::alpha`` and ``acmeAlpha`` both PascalCase-fold to
496
+ ``AcmeAlpha``) must fail loud with ``ERR_PAYLOAD_NAME_COLLISION``, never silently
497
+ emit one class twice."""
498
+ a = _value_object("Note", [_field("a", fc.FIELD_SUBTYPE_STRING)], package="acme::alpha")
499
+ b = _value_object("Note", [_field("b", fc.FIELD_SUBTYPE_STRING)], package="acmeAlpha")
500
+ digest = _value_object(
501
+ "Digest",
502
+ [
503
+ _object_field("fromA", "acme::alpha::Note"),
504
+ _object_field("fromB", "acmeAlpha::Note"),
505
+ ],
506
+ package="acme::app",
507
+ )
508
+ tmpl = _template("DigestOut", "Digest")
509
+ root = _root([a, b, digest, tmpl])
510
+ with pytest.raises(ValueError) as ei:
511
+ render_payload_vo(tmpl, root)
512
+ msg = str(ei.value)
513
+ assert ERR_PAYLOAD_NAME_COLLISION in msg
514
+ assert "AcmeAlphaNotePayload" in msg
515
+ # Both source FQNs are named so the author can find and rename one.
516
+ assert "acme::alpha::Note" in msg
517
+ assert "acmeAlpha::Note" in msg
518
+
519
+
431
520
  # ---------------------------------------------------------------------------
432
521
  # Resolution edge cases.
433
522
  # ---------------------------------------------------------------------------
@@ -30,8 +30,8 @@ import metaobjects.core_types # noqa: F401 — side-effect: registers attr cla
30
30
  from metaobjects import InMemoryStringSource, MetaDataLoader
31
31
  from metaobjects.codegen.config import GenConfig
32
32
  from metaobjects.codegen.generator import GenContext
33
+ from metaobjects.codegen.generators.payload_vo_generator import PayloadVoGenerator
33
34
  from metaobjects.codegen.generators.render_helper_generator import RenderHelperGenerator
34
- from metaobjects.meta.template import template_constants as tc
35
35
  from metaobjects.render.email_document import EmailDocument
36
36
  from metaobjects.render.filesystem_provider import FilesystemProvider
37
37
 
@@ -194,6 +194,48 @@ def test_document_digest_doc_resolves_fqn_nested_object_ref_across_collision(tmp
194
194
  assert out == "Alpha=AA Beta=BB"
195
195
 
196
196
 
197
+ def test_payload_vo_collision_emits_distinct_package_qualified_classes(tmp_path) -> None:
198
+ """ADR-0044 — the two colliding ``Note`` VOs (``acme::alpha`` / ``acme::beta``)
199
+ reachable from one payload module MUST emit as TWO distinct classes under their
200
+ package-qualified derived names (``AcmeAlphaNotePayload`` / ``AcmeBetaNotePayload``),
201
+ never one shadowed ``NotePayload`` (which dropped ``betaText`` and typed BOTH
202
+ fields against the alpha shape). The payload record is GENERATOR-emitted and
203
+ exercised by construction — the corpus README prohibits hand-authoring it."""
204
+ dir_root = CORPUS / "xpkg-collision"
205
+ root = _load_root_from_files(
206
+ dir_root / "meta.alpha.json",
207
+ dir_root / "meta.beta.json",
208
+ dir_root / "meta.app.json",
209
+ )
210
+ files = [f for f in PayloadVoGenerator().generate(_ctx(root))
211
+ if f.path == "digest_doc_payload.py"]
212
+ assert len(files) == 1
213
+ src = files[0].content
214
+ # Two DISTINCT package-qualified classes — and never the shadowed bare name.
215
+ assert "class AcmeAlphaNotePayload(BaseModel):" in src
216
+ assert "class AcmeBetaNotePayload(BaseModel):" in src
217
+ assert "class NotePayload(BaseModel):" not in src
218
+ # Each field binds to its OWN package's shape.
219
+ assert "fromAlpha: AcmeAlphaNotePayload | None = None" in src
220
+ assert "fromBeta: AcmeBetaNotePayload | None = None" in src
221
+
222
+ _materialize_and_import(files, tmp_path)
223
+ mod = import_module("_rh_conf_pkg.digest_doc_payload")
224
+ # The classes are real and DISTINCT: alpha carries alphaText, beta betaText.
225
+ alpha = mod.AcmeAlphaNotePayload(alphaText="AA")
226
+ beta = mod.AcmeBetaNotePayload(betaText="BB")
227
+ assert "alphaText" in mod.AcmeAlphaNotePayload.model_fields
228
+ assert "betaText" not in mod.AcmeAlphaNotePayload.model_fields
229
+ assert "betaText" in mod.AcmeBetaNotePayload.model_fields
230
+ assert "alphaText" not in mod.AcmeBetaNotePayload.model_fields
231
+ # No shadowed bare class leaked into the module namespace.
232
+ assert not hasattr(mod, "NotePayload")
233
+ # The primary payload composes the two distinct shapes.
234
+ digest = mod.DigestDocPayload(fromAlpha=alpha, fromBeta=beta)
235
+ assert digest.fromAlpha.alphaText == "AA"
236
+ assert digest.fromBeta.betaText == "BB"
237
+
238
+
197
239
  # ---------------------------------------------------------------------------
198
240
  # drift/ → codegen FAILS (ValueError) with ERR_VAR_NOT_ON_PAYLOAD.
199
241
  # ---------------------------------------------------------------------------
File without changes
File without changes
File without changes