metaobjects 0.25.0__tar.gz → 1.0.0rc5__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 (439) hide show
  1. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/PKG-INFO +1 -1
  2. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/pyproject.toml +1 -1
  3. metaobjects-1.0.0rc5/src/metaobjects/codegen/format.py +72 -0
  4. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/names_generator.py +20 -16
  5. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/router_generator.py +46 -4
  6. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/registry_manifest.py +1 -1
  7. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source_resolution.py +26 -6
  8. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/ui.json +2 -2
  9. metaobjects-1.0.0rc5/tests/codegen/test_format.py +85 -0
  10. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_names_extends_chain.py +42 -10
  11. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_server.py +15 -1
  12. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/uv.lock +1 -1
  13. metaobjects-0.25.0/src/metaobjects/codegen/format.py +0 -42
  14. metaobjects-0.25.0/tests/codegen/test_format.py +0 -30
  15. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/.gitignore +0 -0
  16. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/LICENSE +0 -0
  17. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/README.md +0 -0
  18. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/hatch_build.py +0 -0
  19. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/scripts/generate_embedded_library.py +0 -0
  20. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/__init__.py +0 -0
  21. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/agent_context/__init__.py +0 -0
  22. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/agent_context/scaffold.py +0 -0
  23. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/__init__.py +0 -0
  24. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/api_model.py +0 -0
  25. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/builder.py +0 -0
  26. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/naming.py +0 -0
  27. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/paths.py +0 -0
  28. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/apidocs/renderer.py +0 -0
  29. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/attr_class_map.py +0 -0
  30. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/cli.py +0 -0
  31. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  32. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/__init__.py +0 -0
  33. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/collision_names.py +0 -0
  34. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/config.py +0 -0
  35. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/constants.py +0 -0
  36. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  37. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  38. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  39. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generator.py +0 -0
  40. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generator_registry.py +0 -0
  41. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/__init__.py +0 -0
  42. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  43. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  44. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
  45. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
  46. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  47. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  48. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  49. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  50. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
  51. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  52. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  53. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  54. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  55. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  56. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
  57. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  58. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  59. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/project_config.py +0 -0
  60. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/runner.py +0 -0
  61. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  62. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  63. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  64. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  65. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  66. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  67. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/codegen/type_map.py +0 -0
  68. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/config/__init__.py +0 -0
  69. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/config/neutral_config.py +0 -0
  70. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/config/source_resolver.py +0 -0
  71. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/core_types.py +0 -0
  72. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/datatype.py +0 -0
  73. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/__init__.py +0 -0
  74. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/doc_constants.py +0 -0
  75. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/doc_provider.py +0 -0
  76. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/documentation/doc_schema.py +0 -0
  77. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/errors.py +0 -0
  78. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/library/__init__.py +0 -0
  79. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/library/embedded_library.py +0 -0
  80. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/library/library_sources.py +0 -0
  81. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/__init__.py +0 -0
  82. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/merge.py +0 -0
  83. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/meta_data_loader.py +0 -0
  84. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/registered_validation.py +0 -0
  85. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/__init__.py +0 -0
  86. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/directory_source.py +0 -0
  87. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/file_source.py +0 -0
  88. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  89. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/sources/uri_source.py +0 -0
  90. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_discriminator.py +0 -0
  91. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  92. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_field_mutability.py +0 -0
  93. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  94. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  95. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  96. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/loader/validation_passes.py +0 -0
  97. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/__init__.py +0 -0
  98. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/__init__.py +0 -0
  99. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  100. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  101. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  102. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/field/__init__.py +0 -0
  103. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  104. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  105. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  106. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  107. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  108. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/index/__init__.py +0 -0
  109. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  110. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  111. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/__init__.py +0 -0
  112. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  113. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  114. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  115. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  116. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  117. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/object/value_object.py +0 -0
  118. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  119. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  120. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  121. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  122. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  123. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
  124. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  125. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  126. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  127. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/meta_data.py +0 -0
  128. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/meta_root.py +0 -0
  129. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/__init__.py +0 -0
  130. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  131. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  132. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  133. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  134. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  135. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  136. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  137. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  138. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  139. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/__init__.py +0 -0
  140. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  141. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  142. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  143. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  144. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  145. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  146. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  147. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  148. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/provider_extends.py +0 -0
  149. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/__init__.py +0 -0
  150. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/meta_template.py +0 -0
  151. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  152. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/meta/template/template_constants.py +0 -0
  153. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/naming.py +0 -0
  154. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/naming_refs.py +0 -0
  155. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/parser.py +0 -0
  156. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/parser_yaml.py +0 -0
  157. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/provider.py +0 -0
  158. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/py.typed +0 -0
  159. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/registry.py +0 -0
  160. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/__init__.py +0 -0
  161. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/email_document.py +0 -0
  162. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/escapers.py +0 -0
  163. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  164. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/__init__.py +0 -0
  165. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/coerce.py +0 -0
  166. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/extract.py +0 -0
  167. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/extract_map.py +0 -0
  168. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  169. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/locate.py +0 -0
  170. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/normalize.py +0 -0
  171. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/strip.py +0 -0
  172. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/types.py +0 -0
  173. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  174. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/filesystem_provider.py +0 -0
  175. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/payload_accessors.py +0 -0
  176. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/__init__.py +0 -0
  177. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  178. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  179. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  180. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  181. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  182. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/renderer.py +0 -0
  183. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/render/verify.py +0 -0
  184. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/__init__.py +0 -0
  185. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/llm_recorder.py +0 -0
  186. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  187. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/object_manager.py +0 -0
  188. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/runtime/tph.py +0 -0
  189. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/serializer_json.py +0 -0
  190. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/__init__.py +0 -0
  191. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/base_types.py +0 -0
  192. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/separators.py +0 -0
  193. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/shared/structural.py +0 -0
  194. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/__init__.py +0 -0
  195. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/error_source.py +0 -0
  196. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/json_path.py +0 -0
  197. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/semantic_diff.py +0 -0
  198. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/source/yaml_positions.py +0 -0
  199. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  200. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/attr.json +0 -0
  201. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/db.json +0 -0
  202. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  203. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/field.json +0 -0
  204. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/identity.json +0 -0
  205. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/index.json +0 -0
  206. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/layout.json +0 -0
  207. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/object.json +0 -0
  208. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/origin.json +0 -0
  209. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  210. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  211. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/requirement.json +0 -0
  212. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/source.json +0 -0
  213. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/template.json +0 -0
  214. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  215. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/validator.json +0 -0
  216. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/spec_metamodel/view.json +0 -0
  217. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/super_resolve.py +0 -0
  218. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/validation_types.py +0 -0
  219. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/src/metaobjects/yaml_desugar.py +0 -0
  220. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/__init__.py +0 -0
  221. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/__init__.py +0 -0
  222. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  223. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/extends/expected/Program.py +0 -0
  224. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/extends/meta.json +0 -0
  225. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  226. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  227. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/nested-array/meta.json +0 -0
  228. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  229. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  230. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/scalars/meta.json +0 -0
  231. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  232. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/golden/vanilla/meta.json +0 -0
  233. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_abstract_conformance.py +0 -0
  234. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_api_docs_builder.py +0 -0
  235. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_api_docs_paths.py +0 -0
  236. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli.py +0 -0
  237. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_config_gen.py +0 -0
  238. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_config_verify.py +0 -0
  239. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_providers.py +0 -0
  240. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_registry.py +0 -0
  241. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  242. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_verify_strict.py +0 -0
  243. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  244. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_constants_config.py +0 -0
  245. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_entity_model.py +0 -0
  246. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_enum_conformance.py +0 -0
  247. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  248. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_extract_tier_collision.py +0 -0
  249. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_extractor_generator.py +0 -0
  250. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  251. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  252. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_fr010_output_codegen.py +0 -0
  253. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  254. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_generator.py +0 -0
  255. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_generator_extension_seams.py +0 -0
  256. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_golden.py +0 -0
  257. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  258. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_inheritance_conformance.py +0 -0
  259. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_instance_artifacts.py +0 -0
  260. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_m2m_codegen.py +0 -0
  261. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_names_generator.py +0 -0
  262. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_no_magic_physical_names.py +0 -0
  263. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_origin_nullability.py +0 -0
  264. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_output_parser_generator.py +0 -0
  265. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_overwrite_policy.py +0 -0
  266. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_overwrite_policy_hash.py +0 -0
  267. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_payload_vo_generator.py +0 -0
  268. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_project_config.py +0 -0
  269. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_projection_compile.py +0 -0
  270. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_render_helper_conformance.py +0 -0
  271. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_render_helper_generator.py +0 -0
  272. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_reverse_finders.py +0 -0
  273. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_router_autoset.py +0 -0
  274. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_router_generator.py +0 -0
  275. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_runner.py +0 -0
  276. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_source_resolution.py +0 -0
  277. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_sourceless_projection.py +0 -0
  278. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_data.py +0 -0
  279. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_generator.py +0 -0
  280. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_output_pattern.py +0 -0
  281. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_scope_helpers.py +0 -0
  282. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_scope_walk.py +0 -0
  283. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_template_spec.py +0 -0
  284. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_tph_codegen.py +0 -0
  285. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_trace_helper_generator.py +0 -0
  286. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_type_map.py +0 -0
  287. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_validation_conformance.py +0 -0
  288. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/codegen/test_write_through.py +0 -0
  289. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/config/__init__.py +0 -0
  290. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/config/test_neutral_config.py +0 -0
  291. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/config/test_source_resolver.py +0 -0
  292. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/__init__.py +0 -0
  293. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/capabilities.py +0 -0
  294. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/conformance-expected-failures.json +0 -0
  295. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/conformance_adapter.py +0 -0
  296. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/corpus.py +0 -0
  297. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/expected_failures.py +0 -0
  298. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/fixture_discovery.py +0 -0
  299. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/navigator.py +0 -0
  300. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  301. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_conformance.py +0 -0
  302. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_extract_conformance.py +0 -0
  303. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_extract_object_verdict.py +0 -0
  304. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  305. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_fr011_attrs.py +0 -0
  306. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_generator_registry_conformance.py +0 -0
  307. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_object_model_conformance.py +0 -0
  308. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_provider_composition_conformance.py +0 -0
  309. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_registry_conformance.py +0 -0
  310. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_runner_hardfail.py +0 -0
  311. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_source_resolution_conformance.py +0 -0
  312. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  313. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_strict_attr_load.py +0 -0
  314. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_template_codegen_conformance.py +0 -0
  315. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_template_generator_conformance.py +0 -0
  316. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/test_yaml_conformance.py +0 -0
  317. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  318. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/__init__.py +0 -0
  319. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_assertions.py +0 -0
  320. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_jsonb_server.py +0 -0
  321. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/api_contract_m2m_server.py +0 -0
  322. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_jsonb_app.py +0 -0
  323. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_m2m_app.py +0 -0
  324. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_router_app.py +0 -0
  325. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/generated_tph_app.py +0 -0
  326. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/meta_ai_trace.yaml +0 -0
  327. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/normalization.py +0 -0
  328. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/postgres_container.py +0 -0
  329. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/query_runner.py +0 -0
  330. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/scenarios.py +0 -0
  331. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract.py +0 -0
  332. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_generated.py +0 -0
  333. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_jsonb.py +0 -0
  334. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_m2m.py +0 -0
  335. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  336. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_api_contract_tph_generated.py +0 -0
  337. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  338. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_llm_call_trace.py +0 -0
  339. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_normalization.py +0 -0
  340. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_query_scenarios.py +0 -0
  341. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/integration/test_runtime_return_types.py +0 -0
  342. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/__init__.py +0 -0
  343. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_abstract_subtype_authored.py +0 -0
  344. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  345. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_field_mutability_order.py +0 -0
  346. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_shipped_library_ai.py +0 -0
  347. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/loader/test_template_payload_target_210.py +0 -0
  348. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/open_closed_proof_test.py +0 -0
  349. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/__init__.py +0 -0
  350. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/__init__.py +0 -0
  351. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_coerce.py +0 -0
  352. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_extract.py +0 -0
  353. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_extract_map.py +0 -0
  354. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  355. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_locate.py +0 -0
  356. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_model.py +0 -0
  357. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_normalize.py +0 -0
  358. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_strip.py +0 -0
  359. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  360. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/prompt/__init__.py +0 -0
  361. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/prompt/test_output_format_renderer.py +0 -0
  362. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_email_document.py +0 -0
  363. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_filesystem_provider.py +0 -0
  364. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_output_format_renderer_nested.py +0 -0
  365. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_output_prompt_conformance.py +0 -0
  366. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_render_conformance.py +0 -0
  367. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_render_max_chars.py +0 -0
  368. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_verify.py +0 -0
  369. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/render/test_verify_conformance.py +0 -0
  370. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
  371. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/runtime/test_object_manager_table_name.py +0 -0
  372. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/__init__.py +0 -0
  373. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_fr5c_merge_attribution.py +0 -0
  374. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_fr5d_reference_resolution.py +0 -0
  375. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_fr5e_database_source_shape.py +0 -0
  376. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_json_path.py +0 -0
  377. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_semantic_diff.py +0 -0
  378. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_source_on_node.py +0 -0
  379. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/source/test_yaml_positions.py +0 -0
  380. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/test_api_docs_accuracy.py +0 -0
  381. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/__init__.py +0 -0
  382. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_agent_context_staleness.py +0 -0
  383. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_capabilities.py +0 -0
  384. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_column_naming_strategy.py +0 -0
  385. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_common_attrs.py +0 -0
  386. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_core_types.py +0 -0
  387. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
  388. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_effective_package.py +0 -0
  389. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_errors.py +0 -0
  390. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_enum.py +0 -0
  391. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_enum_intvaluemap.py +0 -0
  392. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_map_validation.py +0 -0
  393. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  394. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  395. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_index_lookup.py +0 -0
  396. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_llm_recorder.py +0 -0
  397. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_loader.py +0 -0
  398. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_loader_bom.py +0 -0
  399. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_loader_class.py +0 -0
  400. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_merge.py +0 -0
  401. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_meta_attr.py +0 -0
  402. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_meta_data.py +0 -0
  403. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_meta_source.py +0 -0
  404. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_module_shortcuts.py +0 -0
  405. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_n2m_resolver.py +0 -0
  406. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  407. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_no_dead_config_fields.py +0 -0
  408. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  409. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  410. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_object_manager_write_through.py +0 -0
  411. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_one_primary_source.py +0 -0
  412. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_parser.py +0 -0
  413. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_parser_yaml.py +0 -0
  414. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_provider.py +0 -0
  415. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_provider_extension.py +0 -0
  416. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry.py +0 -0
  417. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry_completeness.py +0 -0
  418. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry_extend.py +0 -0
  419. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_registry_sealed.py +0 -0
  420. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_relationship_referential_actions.py +0 -0
  421. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_resolution_key.py +0 -0
  422. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  423. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_serializer.py +0 -0
  424. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_shared_constants.py +0 -0
  425. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_smoke.py +0 -0
  426. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_source_escapes.py +0 -0
  427. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_sources.py +0 -0
  428. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_strict_child_placement.py +0 -0
  429. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_super_resolve.py +0 -0
  430. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_template_toolcall.py +0 -0
  431. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  432. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_attr_schema.py +0 -0
  433. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_filter_values.py +0 -0
  434. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_origin_195.py +0 -0
  435. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_origin_paths.py +0 -0
  436. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_sort_field.py +0 -0
  437. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_validation_warnings.py +0 -0
  438. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_write_coercion_arrays.py +0 -0
  439. {metaobjects-0.25.0 → metaobjects-1.0.0rc5}/tests/unit/test_yaml_desugar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: metaobjects
3
- Version: 0.25.0
3
+ Version: 1.0.0rc5
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.25.0"
3
+ version = "1.0.0rc5"
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"
@@ -0,0 +1,72 @@
1
+ """Canonicalize emitted source via ruff: sort imports (isort), then format.
2
+
3
+ Both passes read stdin / write stdout, so generated code is import-sorted AND
4
+ formatted — i.e. `ruff check`- and `ruff format`-clean for downstream consumers."""
5
+ from __future__ import annotations
6
+
7
+ import importlib.util
8
+ import subprocess
9
+ import sys
10
+
11
+ _STDIN_NAME = "generated.py"
12
+
13
+ #: ruff is a codegen-time convenience (import-sort + format), not a runtime requirement
14
+ #: of the emitted code. When it's absent we emit valid-but-unformatted Python rather
15
+ #: than hard-failing the whole ``gen``.
16
+ _RUFF_AVAILABLE = importlib.util.find_spec("ruff") is not None
17
+
18
+
19
+ def _run_ruff(args: list[str], source: str) -> str:
20
+ proc = subprocess.run(
21
+ [sys.executable, "-m", "ruff", *args],
22
+ input=source,
23
+ capture_output=True,
24
+ text=True,
25
+ )
26
+ if proc.returncode != 0:
27
+ # A non-zero exit is read by the caller as "ruff rejected the source" — a
28
+ # generator bug. Two things make that reading unsafe, so record what actually
29
+ # happened instead of asserting a cause.
30
+ #
31
+ # First, ruff reports a source it cannot parse as exit 2 WITH stderr (measured,
32
+ # ruff 0.15.14: `error: Failed to parse at 1:7: ...`). So an EMPTY stderr is not
33
+ # a source rejection — the process did not get far enough to say anything.
34
+ # Second, a NEGATIVE returncode is death by signal, which is not a verdict on
35
+ # the source at all.
36
+ #
37
+ # This branch used to raise `ruff format failed:` — trailing off after the colon
38
+ # whenever stderr was empty, naming neither the exit status nor the fact that
39
+ # ruff never looked at the source, and sending a reader hunting a syntax error
40
+ # that did not exist. Always carry the status; never claim a source error for a
41
+ # process that did not finish, and do not guess at WHY it did not finish.
42
+ detail = proc.stderr.strip()
43
+ if proc.returncode < 0:
44
+ raise RuntimeError(
45
+ f"ruff {args[0]} was killed by signal {-proc.returncode} before it could "
46
+ f"format the source — this is not a source error; the formatter never ran "
47
+ f"to completion" + (f": {detail}" if detail else "")
48
+ )
49
+ raise RuntimeError(
50
+ f"ruff {args[0]} failed (exit {proc.returncode})"
51
+ + (
52
+ f": {detail}"
53
+ if detail
54
+ else " and wrote nothing to stderr — ruff reports an unparseable source"
55
+ " WITH stderr, so this is not a source error"
56
+ )
57
+ )
58
+ return proc.stdout
59
+
60
+
61
+ def ruff_format(source: str) -> str:
62
+ """Sort imports then format *source*; return the canonical text.
63
+
64
+ A no-op (returns *source* unchanged) when ruff is not installed — the emitted
65
+ code is still valid Python, just unformatted. Still raises RuntimeError if ruff
66
+ IS present but fails (e.g. a syntax error in emitted code — that's a generator bug)."""
67
+ if not _RUFF_AVAILABLE:
68
+ return source
69
+ sorted_src = _run_ruff(
70
+ ["check", "--select", "I", "--fix", "--stdin-filename", _STDIN_NAME, "-"], source
71
+ )
72
+ return _run_ruff(["format", "-"], sorted_src)
@@ -286,24 +286,28 @@ def _sources_by_role(entity: MetaObject) -> dict[str, MetaSource]:
286
286
  ADR-0039: ``children()`` RESOLVES — a source inherited via ``extends`` (the TPH
287
287
  pattern) is seen; ``own_children()`` would miss it.
288
288
 
289
- The refusal is about DISAGREEMENT, not about the count — deliberately the SAME
290
- rule :func:`primary_rdb_source` already enforces for the physical name, rather
291
- than a stricter one invented here. An abstract base and the child that extends it
292
- may each declare a ``@role: primary`` source naming the same relation; that is
293
- legal today, and refusing it would make this module stricter than the invariant
294
- it exists to serve.
289
+ The refusal is about DISAGREEMENT, not about the count — the SAME rule
290
+ :func:`primary_rdb_source` enforces, which now compares the whole ADDRESS
291
+ (:func:`source_address_key`: kind, schema, physical name) rather than the bare
292
+ name. An abstract base and the child that extends it may each declare a
293
+ ``@role: primary`` source naming the same relation; that is legal, and refusing it
294
+ would make this module stricter than the invariant it exists to serve.
295
295
 
296
296
  Two sources in one role that resolve DIFFERENTLY is the real problem, and silently
297
297
  keeping one is the failure mode this artifact makes impossible: the second name is
298
298
  carried nowhere, read by nobody, and the binding quietly takes the first's.
299
299
 
300
- What this sees that :func:`primary_rdb_source` cannot is the non-name half —
301
- ``@kind`` and ``@schema``. That function compares physical NAMES, so two primaries
302
- agreeing on the name and differing on which schema it lives in get past it and land
303
- on one role key here. (Two sources reach one role key only when both are OWN
304
- children or both carry an explicit structural ``name``: effective-children
305
- shadowing matches on ``(type, name)``, so two UNNAMED sources across an ``extends``
306
- boundary collapse into one before this ever runs.)
300
+ This docstring used to claim the two were "deliberately the SAME rule" while
301
+ describing, two paragraphs later, exactly how they differed — that function
302
+ compared physical NAMES, so two primaries agreeing on the name and differing on
303
+ ``@schema`` got past it and landed on one role key here. They are the same rule
304
+ now. What remains for this loop is every NON-primary role: the authority knows only
305
+ about ``@role: primary``, so two disagreeing REPLICAs still land here.
306
+
307
+ (Two sources reach one role key only when both are OWN children or both carry an
308
+ explicit structural ``name``: effective-children shadowing matches on
309
+ ``(type, name)``, so two UNNAMED sources across an ``extends`` boundary collapse
310
+ into one before this ever runs.)
307
311
  """
308
312
  out: dict[str, MetaSource] = {}
309
313
  for child in entity.children():
@@ -329,9 +333,9 @@ def _sources_by_role(entity: MetaObject) -> dict[str, MetaSource]:
329
333
  )
330
334
  raise ValueError(
331
335
  f'{entity.name} declares more than one source.rdb with @role: "{role}", '
332
- f'and they do not agree — "{existing.physical_name()}" vs '
333
- f'"{child.physical_name()}" ({detail}). The names module keys sources '
334
- f"by role, so the second has nowhere to go."
336
+ f"and they disagree on the object's physical address — "
337
+ f'"{existing.physical_name()}" vs "{child.physical_name()}" ({detail}). '
338
+ f"The names module keys sources by role, so the second has nowhere to go."
335
339
  )
336
340
  return out
337
341
 
@@ -201,6 +201,27 @@ def _py_set_literal(names: list[str], *, frozen: bool = False) -> str:
201
201
  return f"frozenset({body})" if frozen else body
202
202
 
203
203
 
204
+ def _py_sort_default_order_literal(fields: list[MetaField]) -> str:
205
+ """A ``dict[str, str]`` literal of each field's DECLARED ``@sortableDefaultOrder``.
206
+
207
+ Declared orders only — a field with no ``@sortableDefaultOrder`` is absent and the
208
+ generated ``_parse_sort`` supplies ``"asc"``. That split matches the other four
209
+ ports: one place per port spells the fallback, so no port can drift by baking a
210
+ different default into its map.
211
+
212
+ ADR-0039: ``attrs()`` is the RESOLVING accessor in Python (``attr()`` is own-only),
213
+ so an ``@sortableDefaultOrder`` inherited via ``extends`` is honoured.
214
+ """
215
+ rows = []
216
+ for f in fields:
217
+ v = f.attrs().get(fc.FIELD_ATTR_SORTABLE_DEFAULT_ORDER)
218
+ if v in ("asc", "desc"):
219
+ rows.append(f' "{f.name}": "{v}",\n')
220
+ if not rows:
221
+ return "{}"
222
+ return "{\n" + "".join(rows) + "}"
223
+
224
+
204
225
  def _pk_py_type(entity: MetaObject) -> PyType:
205
226
  """The Python type of the entity's primary-key path/id parameter, derived
206
227
  from the PK field's declared subtype via ``type_map.py_type_for`` — the same
@@ -542,14 +563,17 @@ class RouterGenerator:
542
563
 
543
564
  # Sort allowlist = base scalar fields ∪ every subtype's own scalar fields, so a
544
565
  # per-subtype list can sort on a subtype-only column too. Stable order.
545
- sort_fields: list[str] = [f.name for f in _scalar_fields(entity)]
566
+ sort_field_nodes = list(_scalar_fields(entity))
567
+ sort_fields: list[str] = [f.name for f in sort_field_nodes]
546
568
  seen = set(sort_fields)
547
569
  for st in plan.subtypes:
548
570
  for f in _scalar_fields(st.entity):
549
571
  if f.name not in seen:
550
572
  seen.add(f.name)
551
573
  sort_fields.append(f.name)
574
+ sort_field_nodes.append(f)
552
575
  sort_set_body = _py_set_literal(sort_fields)
576
+ sort_default_order_body = _py_sort_default_order_literal(sort_field_nodes)
553
577
  # FR-035 PATCH-2: @required fields across the base AND every subtype — an
554
578
  # explicit null on any of these is a 400 (the per-subtype update handlers
555
579
  # guard against it before the repo call). Union, stable order.
@@ -632,6 +656,9 @@ class RouterGenerator:
632
656
  parts.append(f"_SORT_ALLOWLIST: set[str] = {sort_set_body}")
633
657
  parts.append("")
634
658
  parts.append("")
659
+ parts.append(f"_SORT_DEFAULT_ORDER: dict[str, str] = {sort_default_order_body}")
660
+ parts.append("")
661
+ parts.append("")
635
662
  parts.append(f"_REQUIRED_FIELDS: frozenset[str] = {required_set_body}")
636
663
  parts.append("")
637
664
  parts.append("")
@@ -646,7 +673,12 @@ class RouterGenerator:
646
673
  parts.append(' parts = raw.split(":", 1)')
647
674
  parts.append(" if not parts or parts[0] not in _SORT_ALLOWLIST:")
648
675
  parts.append(" return None")
649
- parts.append(' direction = parts[1].lower() if len(parts) == 2 else "asc"')
676
+ # `?sort=field` with no `:order` takes the field's DECLARED @sortableDefaultOrder.
677
+ # The "asc" fallback stays at the READ, one place per port.
678
+ parts.append(' direction = (')
679
+ parts.append(' parts[1].lower() if len(parts) == 2')
680
+ parts.append(' else _SORT_DEFAULT_ORDER.get(parts[0], "asc")')
681
+ parts.append(' )')
650
682
  parts.append(' if direction not in ("asc", "desc"):')
651
683
  parts.append(" return None")
652
684
  parts.append(" return _SortClause(field=parts[0], direction=direction)")
@@ -847,13 +879,15 @@ class RouterGenerator:
847
879
  pk = _pk_py_type(entity)
848
880
  pk_type = pk.expr
849
881
  repo_class = f"{short_name}Repository"
850
- sort_fields = [f.name for f in _scalar_fields(entity)]
882
+ sort_field_nodes = list(_scalar_fields(entity))
883
+ sort_fields = [f.name for f in sort_field_nodes]
851
884
  upper = short_name.upper()
852
885
  fields_const = f"{upper}_FILTER_FIELDS"
853
886
  ops_const = f"{upper}_FILTER_OPS_BY_FIELD"
854
887
  allowlist_module = f"{snake}_filter_allowlist"
855
888
 
856
889
  sort_set_body = _py_set_literal(sort_fields)
890
+ sort_default_order_body = _py_sort_default_order_literal(sort_field_nodes)
857
891
  # FR-035 PATCH-2: an explicit null on a @required field (scalar or jsonb)
858
892
  # is a 400 — the update handler guards these before the repo call.
859
893
  required_set_body = _py_set_literal(_required_field_names(entity), frozen=True)
@@ -928,6 +962,9 @@ class RouterGenerator:
928
962
  parts.append(f"_SORT_ALLOWLIST: set[str] = {sort_set_body}")
929
963
  parts.append("")
930
964
  parts.append("")
965
+ parts.append(f"_SORT_DEFAULT_ORDER: dict[str, str] = {sort_default_order_body}")
966
+ parts.append("")
967
+ parts.append("")
931
968
  parts.append(f"_REQUIRED_FIELDS: frozenset[str] = {required_set_body}")
932
969
  parts.append("")
933
970
  parts.append("")
@@ -942,7 +979,12 @@ class RouterGenerator:
942
979
  parts.append(' parts = raw.split(":", 1)')
943
980
  parts.append(" if not parts or parts[0] not in _SORT_ALLOWLIST:")
944
981
  parts.append(" return None")
945
- parts.append(' direction = parts[1].lower() if len(parts) == 2 else "asc"')
982
+ # `?sort=field` with no `:order` takes the field's DECLARED @sortableDefaultOrder.
983
+ # The "asc" fallback stays at the READ, one place per port.
984
+ parts.append(' direction = (')
985
+ parts.append(' parts[1].lower() if len(parts) == 2')
986
+ parts.append(' else _SORT_DEFAULT_ORDER.get(parts[0], "asc")')
987
+ parts.append(' )')
946
988
  parts.append(' if direction not in ("asc", "desc"):')
947
989
  parts.append(" return None")
948
990
  parts.append(" return _SortClause(field=parts[0], direction=direction)")
@@ -255,7 +255,7 @@ def _sorted_children(definition: TypeDefinition) -> list[dict[str, object]]:
255
255
  return children
256
256
 
257
257
 
258
- METAMODEL_VERSION = "0.14"
258
+ METAMODEL_VERSION = "1.0"
259
259
  """Rolled-up spec-version for the cross-port registry manifest.
260
260
 
261
261
  ``"0"`` = pre-1.0 / unstable (semver major-0). Flips to ``"1.0"`` at the
@@ -45,6 +45,24 @@ from metaobjects.meta.persistence.source.meta_source import MetaSource
45
45
  from metaobjects.meta.persistence.source.source_constants import SOURCE_ROLE_PRIMARY
46
46
 
47
47
 
48
+ def source_address_key(source: MetaSource) -> str:
49
+ """The RESOLVED address of *source* — the same three parts the names artifact
50
+ compares, so the shared authority and the generated artifact cannot answer
51
+ "is this one object?" differently. Rendered rather than structural because
52
+ every port must produce a byte-identical message from it.
53
+
54
+ RAW, deliberately: an absent ``@schema`` is NOT folded into a dialect default.
55
+ On Postgres absent and ``"public"`` address the same relation, but on
56
+ SQLite/D1 they do not — the expected-schema builder rejects ANY declared
57
+ schema, ``"public"`` included, while an absent one is fine. Deciding what
58
+ "absent" means belongs to the caller's dialect, not to this layer, so
59
+ normalizing here would import one dialect's rule into a dialect-free tier.
60
+ """
61
+ schema = source.schema()
62
+ qualifier = f'"{schema}".' if schema else ""
63
+ return f'{qualifier}"{source.physical_name()}" ({source.effective_kind()})'
64
+
65
+
48
66
  def primary_rdb_source(entity: MetaObject) -> MetaSource | None:
49
67
  """THE primary ``source.rdb`` for *entity*, or ``None``.
50
68
 
@@ -61,7 +79,8 @@ def primary_rdb_source(entity: MetaObject) -> MetaSource | None:
61
79
 
62
80
  Raises :class:`ValueError` — mirroring the other four ports' wording exactly —
63
81
  when the resolving children carry MORE THAN ONE ``@role: primary`` source and
64
- they do not agree on a physical name. Direction-blind: it compares every
82
+ they do not agree on a physical ADDRESS (kind, schema, physical name; see
83
+ :func:`source_address_key`). Direction-blind: it compares every
65
84
  primary against every other, so it does not matter which of them is writable,
66
85
  nor which was declared first. See the module docstring for why that matters.
67
86
  No downstream consumer re-checks this; the refusal lives here, once, so every
@@ -75,13 +94,14 @@ def primary_rdb_source(entity: MetaObject) -> MetaSource | None:
75
94
  if not primaries:
76
95
  return None
77
96
 
78
- names = sorted({s.physical_name() for s in primaries})
79
- if len(names) > 1:
80
- joined = ", ".join(f'"{n}"' for n in names)
97
+ addresses = sorted({source_address_key(s) for s in primaries})
98
+ if len(addresses) > 1:
99
+ joined = " vs ".join(addresses)
81
100
  raise ValueError(
82
101
  f"{entity.name}: role=primary sources disagree on the object's physical "
83
- f"name — {joined}. Every consumer binds ONE name. Give them matching "
84
- f"physical names, or drop the extra role=primary declaration."
102
+ f"address — {joined}. Every consumer binds ONE address. Give them a "
103
+ f"matching @kind, @schema and physical name, or drop the extra "
104
+ f"role=primary declaration."
85
105
  )
86
106
  return primaries[0]
87
107
 
@@ -7,7 +7,7 @@
7
7
  "children": [
8
8
  { "type": "attr", "subType": "boolean", "name": "filterable", "min": 0, "max": 1, "description": "When true, the field is exposed in generated CRUD filter allowlists (Project D filter layer)." },
9
9
  { "type": "attr", "subType": "boolean", "name": "sortable", "min": 0, "max": 1, "description": "When true, the field is exposed in generated CRUD sort allowlists. Inherits from @filterable by default; set false to opt out." },
10
- { "type": "attr", "subType": "string", "name": "sortableDefaultOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Default sort direction applied when this field is the default sort field." },
10
+ { "type": "attr", "subType": "string", "name": "sortableDefaultOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Direction a sort takes when it names this field but omits the order: a ?sort=<field> with no :order, and a layout.dataGrid whose @defaultSortField names it with no @defaultSortOrder. Defaults to 'asc'." },
11
11
  { "type": "attr", "subType": "boolean", "name": "formExclude", "min": 0, "max": 1, "description": "When true, the field is omitted from generated forms. Inert on fields for which no form is generated (e.g. projection/derived fields)." }
12
12
  ]
13
13
  },
@@ -24,7 +24,7 @@
24
24
  "children": [
25
25
  { "type": "attr", "subType": "int", "name": "pageSize", "min": 0, "max": 1, "description": "Number of rows per page in the generated data grid." },
26
26
  { "type": "attr", "subType": "string", "name": "defaultSortField", "min": 0, "max": 1, "description": "Field name the grid is sorted by on initial render. Must reference an actual field on the entity." },
27
- { "type": "attr", "subType": "string", "name": "defaultSortOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Initial sort direction for the default sort field: 'asc' or 'desc'." },
27
+ { "type": "attr", "subType": "string", "name": "defaultSortOrder", "min": 0, "max": 1, "allowedValues": ["asc", "desc"], "description": "Initial sort direction for the default sort field: 'asc' or 'desc'. When omitted, the named field's @sortableDefaultOrder applies." },
28
28
  { "type": "attr", "subType": "boolean", "name": "filterable", "min": 0, "max": 1, "description": "When true, the generated grid exposes column filtering UI." },
29
29
  { "type": "attr", "subType": "filter", "name": "filter", "min": 0, "max": 1, "description": "Structured preset filter object applied to the grid at the metadata level. Desugared to canonical { field: { op: value } } form at parse time." },
30
30
  { "type": "attr", "subType": "string", "name": "columns", "isArray": true, "min": 0, "max": 1, "description": "Flat ordered list of field names to display as grid columns." }
@@ -0,0 +1,85 @@
1
+ from metaobjects.codegen.format import ruff_format
2
+
3
+
4
+ def test_ruff_format_canonicalizes() -> None:
5
+ messy = "x={'a':1,'b':2}\n"
6
+ out = ruff_format(messy)
7
+ assert out == 'x = {"a": 1, "b": 2}\n'
8
+
9
+
10
+ def test_ruff_format_is_idempotent() -> None:
11
+ src = "y = [1, 2, 3]\n"
12
+ assert ruff_format(ruff_format(src)) == ruff_format(src)
13
+
14
+
15
+ def test_ruff_format_sorts_imports() -> None:
16
+ # stdlib before third-party before first-party-relative (PEP 8 / isort groups).
17
+ src = "from .local import L\nimport os\n\nfrom pydantic import BaseModel\n"
18
+ out = ruff_format(src)
19
+ assert out.index("import os") < out.index("from pydantic") < out.index("from .local import L")
20
+
21
+
22
+ def test_ruff_format_no_op_when_ruff_absent(monkeypatch) -> None:
23
+ """ruff is a codegen-time convenience, not a runtime requirement — when it's not
24
+ installed, ruff_format returns the source unformatted (still valid Python) rather
25
+ than crashing the whole gen run."""
26
+ import metaobjects.codegen.format as fmt
27
+
28
+ monkeypatch.setattr(fmt, "_RUFF_AVAILABLE", False)
29
+ messy = "x={'a':1}\n"
30
+ assert fmt.ruff_format(messy) == messy
31
+
32
+
33
+ def test_killed_ruff_says_it_was_killed_and_names_the_signal(monkeypatch) -> None:
34
+ """A ruff process killed by a signal must not be reported as a source error.
35
+
36
+ `_run_ruff` treats a non-zero exit as "ruff rejected the source", which is the
37
+ generator bug `ruff_format`'s docstring describes. But a process killed by a
38
+ signal returns a NEGATIVE code and writes no stderr, so that path produced
39
+ `ruff format failed:` — a message naming neither the cause nor the fact that
40
+ ruff never ran. Observed on a CI box running five lanes at once.
41
+ """
42
+ import subprocess
43
+
44
+ import metaobjects.codegen.format as fmt
45
+
46
+ def killed(*_a, **_k):
47
+ return subprocess.CompletedProcess(args=[], returncode=-9, stdout="", stderr="")
48
+
49
+ monkeypatch.setattr(fmt.subprocess, "run", killed)
50
+
51
+ try:
52
+ fmt.ruff_format("x = 1\n")
53
+ except RuntimeError as e:
54
+ msg = str(e)
55
+ else:
56
+ raise AssertionError("expected RuntimeError")
57
+
58
+ # It must say the process was killed, and by which signal, so the reader is not
59
+ # left hunting a syntax error in emitted code that ruff never looked at.
60
+ assert "killed" in msg
61
+ assert "9" in msg
62
+ assert msg.rstrip().endswith(")") or "signal" in msg
63
+
64
+
65
+ def test_nonzero_ruff_with_no_stderr_still_names_the_exit_code(monkeypatch) -> None:
66
+ """The other half: a genuine non-zero exit that happens to print nothing must
67
+ still carry its exit code, rather than trailing off after the colon."""
68
+ import subprocess
69
+
70
+ import metaobjects.codegen.format as fmt
71
+
72
+ def quiet_failure(*_a, **_k):
73
+ return subprocess.CompletedProcess(args=[], returncode=2, stdout="", stderr="")
74
+
75
+ monkeypatch.setattr(fmt.subprocess, "run", quiet_failure)
76
+
77
+ try:
78
+ fmt.ruff_format("x = 1\n")
79
+ except RuntimeError as e:
80
+ msg = str(e)
81
+ else:
82
+ raise AssertionError("expected RuntimeError")
83
+
84
+ assert "2" in msg
85
+ assert not msg.rstrip().endswith(":")
@@ -389,18 +389,22 @@ def test_two_sources_in_one_role_that_AGREE_are_legal() -> None:
389
389
  assert src.count("ROLECHILD_SOURCE_PRIMARY_TABLE: Final") == 1
390
390
 
391
391
 
392
- def test_two_sources_in_one_role_that_DISAGREE_are_refused_naming_both() -> None:
392
+ def test_a_schema_disagreement_in_the_primary_role_is_refused_by_the_AUTHORITY() -> None:
393
393
  """...and the disagreement is the real problem, because keeping one silently is the
394
394
  failure this artifact makes impossible: the second name would be carried nowhere,
395
395
  read by nobody, while the binding quietly took the first's.
396
396
 
397
- A ``@schema`` disagreement is the arm this module owns, and it is what makes the
398
- check non-redundant: ``primary_rdb_source`` compares physical NAMES only, so two
399
- primaries agreeing on the name and differing on which SCHEMA it lives in get past
400
- it and land on one role key here. (A ``@kind`` disagreement in the primary role is
401
- unreachable — the loader refuses a read-only primary outright,
402
- ``ERR_ENTITY_PRIMARY_SOURCE_READONLY``; a physical-NAME disagreement is refused one
403
- level down, by ``primary_rdb_source``.)
397
+ This test used to assert the message came from THIS module, and documented why:
398
+ ``primary_rdb_source`` compared physical NAMES only, so two primaries agreeing on
399
+ the name and differing on which SCHEMA it lives in got past it and landed on one
400
+ role key here. That gap is closed — the authority now compares the whole ADDRESS
401
+ (kind, schema, physical name), so it refuses one level down and this module never
402
+ sees the shape.
403
+
404
+ Why it was closed rather than left: the weaker key did not merely accept the model,
405
+ it made the accepted answer PORT-DEPENDENT. ``primaries[0]`` is the inherited source
406
+ in Python/TS/C# (``children()`` puts the super's entries first) and the own source
407
+ on the JVM, so this exact model bound one schema in three ports and the other in two.
404
408
  """
405
409
  model = _role_model(
406
410
  {"source.rdb": {"name": "child_src", "@table": "zz_shared", "@schema": "zz_other"}}
@@ -408,8 +412,36 @@ def test_two_sources_in_one_role_that_DISAGREE_are_refused_naming_both() -> None
408
412
  with pytest.raises(ValueError) as exc:
409
413
  _render(model, "RoleChild")
410
414
  message = str(exc.value)
411
- assert '@role: "primary"' in message
412
- assert "zz_shared" in message
415
+ assert "disagree on the object's physical address" in message
416
+ # The ADDRESS, not the bare name: the names agree here, so a message naming only
417
+ # "zz_shared" would describe two identical things as different.
418
+ assert '"zz_other"."zz_shared"' in message
419
+ assert '"zz_shared" (table)' in message
420
+
421
+
422
+ def test_two_REPLICAS_that_disagree_are_still_refused_by_this_module() -> None:
423
+ """The per-role check here is not redundant with the authority: the authority only
424
+ knows about ``@role: primary``. Two sources sharing any OTHER role key still land
425
+ here, and the second still has nowhere to go in a map keyed by role.
426
+
427
+ Without this case, closing the primary-role gap would leave the whole per-role loop
428
+ unexercised — a check nothing reaches is a check that can rot.
429
+ """
430
+ # The child keeps a primary that AGREES with the base's — `validate_source_roles` is
431
+ # own-only, so a child declaring replicas alone fails the load with
432
+ # ERR_SOURCE_NO_PRIMARY before this module is ever reached.
433
+ model = _role_model({"source.rdb": {"name": "child_src", "@table": "zz_shared"}})
434
+ model["metadata.root"]["children"][1]["object.entity"]["children"].extend(
435
+ [
436
+ {"source.rdb": {"name": "r1", "@table": "zz_replica", "@role": "replica"}},
437
+ {"source.rdb": {"name": "r2", "@table": "zz_elsewhere", "@role": "replica"}},
438
+ ]
439
+ )
440
+ with pytest.raises(ValueError) as exc:
441
+ _render(model, "RoleChild")
442
+ message = str(exc.value)
443
+ assert '@role: "replica"' in message
444
+ assert "disagree on the object's physical address" in message
413
445
 
414
446
 
415
447
  TPH_MODEL = {
@@ -40,6 +40,14 @@ from .postgres_container import PostgresInfo
40
40
  # fields outside it elicit the cross-port 400 invalid_sort envelope.
41
41
  _SORT_ALLOWLIST: frozenset[str] = frozenset({"id", "name", "createdAt"})
42
42
 
43
+ # Cross-port contract: each field's DECLARED @sortableDefaultOrder — the direction a
44
+ # `?sort=<field>` carrying no `:dir` takes. Hardcoded from meta.json for the same reason
45
+ # the allowlist above is: this is the hand-rolled fixed point the generated routers are
46
+ # measured against, so it must not reach the generator's code to agree with it. A field
47
+ # absent here declares nothing and takes the "asc" fallback at the read — one place per
48
+ # port spells the default.
49
+ _SORT_DEFAULT_ORDER: dict[str, str] = {"createdAt": "desc"}
50
+
43
51
  # Per-entity FR-009 filter allowlist for Author. Mirror of what
44
52
  # `filter_allowlist_generator` would emit for the Author entity (the
45
53
  # integration test is hand-wired so we duplicate the constants here; the
@@ -446,7 +454,13 @@ def make_app(repo: AuthorRepository) -> FastAPI:
446
454
  field = parts[0]
447
455
  if field not in _SORT_ALLOWLIST:
448
456
  return JSONResponse(status_code=400, content={"error": "invalid_sort"})
449
- direction = parts[1].lower() if len(parts) == 2 else "asc"
457
+ # No `:dir` supplied -> the named field's declared @sortableDefaultOrder, and
458
+ # "asc" when it declares none. The explicit branch is untouched, so a
459
+ # caller-supplied order always beats the declaration.
460
+ direction = (
461
+ parts[1].lower() if len(parts) == 2
462
+ else _SORT_DEFAULT_ORDER.get(field, "asc")
463
+ )
450
464
  if direction not in ("asc", "desc"):
451
465
  return JSONResponse(status_code=400, content={"error": "invalid_sort"})
452
466
  sort_field, sort_dir = field, direction.upper()
@@ -250,7 +250,7 @@ wheels = [
250
250
 
251
251
  [[package]]
252
252
  name = "metaobjects"
253
- version = "0.24.5"
253
+ version = "0.25.0"
254
254
  source = { editable = "." }
255
255
  dependencies = [
256
256
  { name = "pyyaml" },
@@ -1,42 +0,0 @@
1
- """Canonicalize emitted source via ruff: sort imports (isort), then format.
2
-
3
- Both passes read stdin / write stdout, so generated code is import-sorted AND
4
- formatted — i.e. `ruff check`- and `ruff format`-clean for downstream consumers."""
5
- from __future__ import annotations
6
-
7
- import importlib.util
8
- import subprocess
9
- import sys
10
-
11
- _STDIN_NAME = "generated.py"
12
-
13
- #: ruff is a codegen-time convenience (import-sort + format), not a runtime requirement
14
- #: of the emitted code. When it's absent we emit valid-but-unformatted Python rather
15
- #: than hard-failing the whole ``gen``.
16
- _RUFF_AVAILABLE = importlib.util.find_spec("ruff") is not None
17
-
18
-
19
- def _run_ruff(args: list[str], source: str) -> str:
20
- proc = subprocess.run(
21
- [sys.executable, "-m", "ruff", *args],
22
- input=source,
23
- capture_output=True,
24
- text=True,
25
- )
26
- if proc.returncode != 0:
27
- raise RuntimeError(f"ruff {args[0]} failed: {proc.stderr.strip()}")
28
- return proc.stdout
29
-
30
-
31
- def ruff_format(source: str) -> str:
32
- """Sort imports then format *source*; return the canonical text.
33
-
34
- A no-op (returns *source* unchanged) when ruff is not installed — the emitted
35
- code is still valid Python, just unformatted. Still raises RuntimeError if ruff
36
- IS present but fails (e.g. a syntax error in emitted code — that's a generator bug)."""
37
- if not _RUFF_AVAILABLE:
38
- return source
39
- sorted_src = _run_ruff(
40
- ["check", "--select", "I", "--fix", "--stdin-filename", _STDIN_NAME, "-"], source
41
- )
42
- return _run_ruff(["format", "-"], sorted_src)
@@ -1,30 +0,0 @@
1
- from metaobjects.codegen.format import ruff_format
2
-
3
-
4
- def test_ruff_format_canonicalizes() -> None:
5
- messy = "x={'a':1,'b':2}\n"
6
- out = ruff_format(messy)
7
- assert out == 'x = {"a": 1, "b": 2}\n'
8
-
9
-
10
- def test_ruff_format_is_idempotent() -> None:
11
- src = "y = [1, 2, 3]\n"
12
- assert ruff_format(ruff_format(src)) == ruff_format(src)
13
-
14
-
15
- def test_ruff_format_sorts_imports() -> None:
16
- # stdlib before third-party before first-party-relative (PEP 8 / isort groups).
17
- src = "from .local import L\nimport os\n\nfrom pydantic import BaseModel\n"
18
- out = ruff_format(src)
19
- assert out.index("import os") < out.index("from pydantic") < out.index("from .local import L")
20
-
21
-
22
- def test_ruff_format_no_op_when_ruff_absent(monkeypatch) -> None:
23
- """ruff is a codegen-time convenience, not a runtime requirement — when it's not
24
- installed, ruff_format returns the source unformatted (still valid Python) rather
25
- than crashing the whole gen run."""
26
- import metaobjects.codegen.format as fmt
27
-
28
- monkeypatch.setattr(fmt, "_RUFF_AVAILABLE", False)
29
- messy = "x={'a':1}\n"
30
- assert fmt.ruff_format(messy) == messy
File without changes
File without changes
File without changes