metaobjects 0.24.4__tar.gz → 0.24.5__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 (427) hide show
  1. {metaobjects-0.24.4 → metaobjects-0.24.5}/PKG-INFO +1 -1
  2. {metaobjects-0.24.4 → metaobjects-0.24.5}/pyproject.toml +1 -1
  3. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/agent_context/scaffold.py +62 -3
  4. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/config.py +9 -0
  5. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/entity_model.py +14 -7
  6. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/m2m_codegen.py +22 -11
  7. metaobjects-0.24.5/src/metaobjects/naming.py +90 -0
  8. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/object_manager.py +40 -23
  9. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_entity_model.py +27 -14
  10. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_agent_context_staleness.py +38 -0
  11. metaobjects-0.24.5/tests/unit/test_column_naming_strategy.py +78 -0
  12. {metaobjects-0.24.4 → metaobjects-0.24.5}/uv.lock +1 -1
  13. {metaobjects-0.24.4 → metaobjects-0.24.5}/.gitignore +0 -0
  14. {metaobjects-0.24.4 → metaobjects-0.24.5}/LICENSE +0 -0
  15. {metaobjects-0.24.4 → metaobjects-0.24.5}/README.md +0 -0
  16. {metaobjects-0.24.4 → metaobjects-0.24.5}/hatch_build.py +0 -0
  17. {metaobjects-0.24.4 → metaobjects-0.24.5}/scripts/generate_embedded_library.py +0 -0
  18. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/__init__.py +0 -0
  19. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/agent_context/__init__.py +0 -0
  20. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/__init__.py +0 -0
  21. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/api_model.py +0 -0
  22. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/builder.py +0 -0
  23. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/naming.py +0 -0
  24. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/paths.py +0 -0
  25. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/apidocs/renderer.py +0 -0
  26. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/attr_class_map.py +0 -0
  27. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/cli.py +0 -0
  28. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  29. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/__init__.py +0 -0
  30. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/collision_names.py +0 -0
  31. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/constants.py +0 -0
  32. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  33. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  34. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/format.py +0 -0
  35. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  36. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generator.py +0 -0
  37. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generator_registry.py +0 -0
  38. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/__init__.py +0 -0
  39. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  40. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
  41. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
  42. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  43. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  44. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  45. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
  46. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  47. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  48. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  49. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  50. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  51. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  52. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
  53. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  54. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  55. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/project_config.py +0 -0
  56. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/runner.py +0 -0
  57. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  58. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  59. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  60. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  61. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  62. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  63. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/codegen/type_map.py +0 -0
  64. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/config/__init__.py +0 -0
  65. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/config/neutral_config.py +0 -0
  66. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/config/source_resolver.py +0 -0
  67. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/core_types.py +0 -0
  68. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/datatype.py +0 -0
  69. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/__init__.py +0 -0
  70. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/doc_constants.py +0 -0
  71. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/doc_provider.py +0 -0
  72. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/documentation/doc_schema.py +0 -0
  73. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/errors.py +0 -0
  74. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/library/__init__.py +0 -0
  75. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/library/embedded_library.py +0 -0
  76. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/library/library_sources.py +0 -0
  77. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/__init__.py +0 -0
  78. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/merge.py +0 -0
  79. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/meta_data_loader.py +0 -0
  80. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/registered_validation.py +0 -0
  81. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/__init__.py +0 -0
  82. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/directory_source.py +0 -0
  83. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/file_source.py +0 -0
  84. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  85. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/sources/uri_source.py +0 -0
  86. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_discriminator.py +0 -0
  87. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  88. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_field_mutability.py +0 -0
  89. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  90. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  91. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  92. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/loader/validation_passes.py +0 -0
  93. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/__init__.py +0 -0
  94. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/__init__.py +0 -0
  95. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  96. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  97. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  98. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/field/__init__.py +0 -0
  99. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  100. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  101. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  102. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  103. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  104. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/index/__init__.py +0 -0
  105. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  106. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  107. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/__init__.py +0 -0
  108. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  109. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  110. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  111. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  112. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  113. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/object/value_object.py +0 -0
  114. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  115. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  116. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  117. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  118. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  119. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
  120. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  121. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  122. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  123. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/meta_data.py +0 -0
  124. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/meta_root.py +0 -0
  125. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/__init__.py +0 -0
  126. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  127. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  128. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  129. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  130. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  131. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  132. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  133. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  134. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  135. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/__init__.py +0 -0
  136. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  137. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  138. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  139. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  140. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  141. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  142. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  143. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  144. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/provider_extends.py +0 -0
  145. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/__init__.py +0 -0
  146. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/meta_template.py +0 -0
  147. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  148. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/meta/template/template_constants.py +0 -0
  149. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/naming_refs.py +0 -0
  150. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/parser.py +0 -0
  151. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/parser_yaml.py +0 -0
  152. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/provider.py +0 -0
  153. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/py.typed +0 -0
  154. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/registry.py +0 -0
  155. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/registry_manifest.py +0 -0
  156. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/__init__.py +0 -0
  157. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/email_document.py +0 -0
  158. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/escapers.py +0 -0
  159. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  160. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/__init__.py +0 -0
  161. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/coerce.py +0 -0
  162. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/extract.py +0 -0
  163. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/extract_map.py +0 -0
  164. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  165. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/locate.py +0 -0
  166. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/normalize.py +0 -0
  167. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/strip.py +0 -0
  168. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/types.py +0 -0
  169. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  170. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/filesystem_provider.py +0 -0
  171. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/payload_accessors.py +0 -0
  172. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/__init__.py +0 -0
  173. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  174. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  175. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  176. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  177. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  178. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/renderer.py +0 -0
  179. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/render/verify.py +0 -0
  180. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/__init__.py +0 -0
  181. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/llm_recorder.py +0 -0
  182. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  183. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/runtime/tph.py +0 -0
  184. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/serializer_json.py +0 -0
  185. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/__init__.py +0 -0
  186. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/base_types.py +0 -0
  187. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/separators.py +0 -0
  188. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/shared/structural.py +0 -0
  189. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/__init__.py +0 -0
  190. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/error_source.py +0 -0
  191. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/json_path.py +0 -0
  192. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/semantic_diff.py +0 -0
  193. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/source/yaml_positions.py +0 -0
  194. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  195. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/attr.json +0 -0
  196. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/db.json +0 -0
  197. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  198. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/field.json +0 -0
  199. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/identity.json +0 -0
  200. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/index.json +0 -0
  201. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/layout.json +0 -0
  202. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/object.json +0 -0
  203. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/origin.json +0 -0
  204. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  205. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  206. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/requirement.json +0 -0
  207. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/source.json +0 -0
  208. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/template.json +0 -0
  209. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  210. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/ui.json +0 -0
  211. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/validator.json +0 -0
  212. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/spec_metamodel/view.json +0 -0
  213. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/super_resolve.py +0 -0
  214. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/validation_types.py +0 -0
  215. {metaobjects-0.24.4 → metaobjects-0.24.5}/src/metaobjects/yaml_desugar.py +0 -0
  216. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/__init__.py +0 -0
  217. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/__init__.py +0 -0
  218. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  219. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/extends/expected/Program.py +0 -0
  220. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/extends/meta.json +0 -0
  221. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  222. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  223. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/nested-array/meta.json +0 -0
  224. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  225. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  226. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/scalars/meta.json +0 -0
  227. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  228. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/golden/vanilla/meta.json +0 -0
  229. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_abstract_conformance.py +0 -0
  230. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_api_docs_builder.py +0 -0
  231. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_api_docs_paths.py +0 -0
  232. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli.py +0 -0
  233. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_config_gen.py +0 -0
  234. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_config_verify.py +0 -0
  235. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_providers.py +0 -0
  236. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_registry.py +0 -0
  237. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  238. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_verify_strict.py +0 -0
  239. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  240. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_constants_config.py +0 -0
  241. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_enum_conformance.py +0 -0
  242. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  243. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_extract_tier_collision.py +0 -0
  244. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_extractor_generator.py +0 -0
  245. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  246. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_format.py +0 -0
  247. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  248. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_fr010_output_codegen.py +0 -0
  249. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  250. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_generator.py +0 -0
  251. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_generator_extension_seams.py +0 -0
  252. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_golden.py +0 -0
  253. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  254. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_inheritance_conformance.py +0 -0
  255. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_instance_artifacts.py +0 -0
  256. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_m2m_codegen.py +0 -0
  257. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_origin_nullability.py +0 -0
  258. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_output_parser_generator.py +0 -0
  259. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_overwrite_policy.py +0 -0
  260. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_overwrite_policy_hash.py +0 -0
  261. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_payload_vo_generator.py +0 -0
  262. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_project_config.py +0 -0
  263. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_projection_compile.py +0 -0
  264. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_render_helper_conformance.py +0 -0
  265. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_render_helper_generator.py +0 -0
  266. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_reverse_finders.py +0 -0
  267. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_router_autoset.py +0 -0
  268. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_router_generator.py +0 -0
  269. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_runner.py +0 -0
  270. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_sourceless_projection.py +0 -0
  271. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_data.py +0 -0
  272. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_generator.py +0 -0
  273. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_output_pattern.py +0 -0
  274. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_scope_helpers.py +0 -0
  275. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_scope_walk.py +0 -0
  276. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_template_spec.py +0 -0
  277. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_tph_codegen.py +0 -0
  278. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_trace_helper_generator.py +0 -0
  279. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_type_map.py +0 -0
  280. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_validation_conformance.py +0 -0
  281. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/codegen/test_write_through.py +0 -0
  282. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/config/__init__.py +0 -0
  283. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/config/test_neutral_config.py +0 -0
  284. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/config/test_source_resolver.py +0 -0
  285. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/__init__.py +0 -0
  286. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/capabilities.py +0 -0
  287. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/conformance-expected-failures.json +0 -0
  288. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/conformance_adapter.py +0 -0
  289. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/corpus.py +0 -0
  290. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/expected_failures.py +0 -0
  291. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/fixture_discovery.py +0 -0
  292. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/navigator.py +0 -0
  293. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  294. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_conformance.py +0 -0
  295. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_extract_conformance.py +0 -0
  296. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_extract_object_verdict.py +0 -0
  297. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  298. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_fr011_attrs.py +0 -0
  299. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_generator_registry_conformance.py +0 -0
  300. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_object_model_conformance.py +0 -0
  301. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_provider_composition_conformance.py +0 -0
  302. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_registry_conformance.py +0 -0
  303. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_runner_hardfail.py +0 -0
  304. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_source_resolution_conformance.py +0 -0
  305. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  306. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_strict_attr_load.py +0 -0
  307. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_template_codegen_conformance.py +0 -0
  308. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_template_generator_conformance.py +0 -0
  309. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/test_yaml_conformance.py +0 -0
  310. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  311. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/__init__.py +0 -0
  312. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_assertions.py +0 -0
  313. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_jsonb_server.py +0 -0
  314. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_m2m_server.py +0 -0
  315. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/api_contract_server.py +0 -0
  316. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_jsonb_app.py +0 -0
  317. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_m2m_app.py +0 -0
  318. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_router_app.py +0 -0
  319. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/generated_tph_app.py +0 -0
  320. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/meta_ai_trace.yaml +0 -0
  321. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/normalization.py +0 -0
  322. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/postgres_container.py +0 -0
  323. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/query_runner.py +0 -0
  324. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/scenarios.py +0 -0
  325. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract.py +0 -0
  326. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_generated.py +0 -0
  327. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_jsonb.py +0 -0
  328. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_m2m.py +0 -0
  329. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  330. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_api_contract_tph_generated.py +0 -0
  331. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  332. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_llm_call_trace.py +0 -0
  333. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_normalization.py +0 -0
  334. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_query_scenarios.py +0 -0
  335. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/integration/test_runtime_return_types.py +0 -0
  336. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/__init__.py +0 -0
  337. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  338. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_field_mutability_order.py +0 -0
  339. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_shipped_library_ai.py +0 -0
  340. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/loader/test_template_payload_target_210.py +0 -0
  341. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/open_closed_proof_test.py +0 -0
  342. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/__init__.py +0 -0
  343. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/__init__.py +0 -0
  344. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_coerce.py +0 -0
  345. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_extract.py +0 -0
  346. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_extract_map.py +0 -0
  347. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  348. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_locate.py +0 -0
  349. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_model.py +0 -0
  350. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_normalize.py +0 -0
  351. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_strip.py +0 -0
  352. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  353. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/prompt/__init__.py +0 -0
  354. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/prompt/test_output_format_renderer.py +0 -0
  355. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_email_document.py +0 -0
  356. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_filesystem_provider.py +0 -0
  357. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_output_format_renderer_nested.py +0 -0
  358. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_output_prompt_conformance.py +0 -0
  359. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_render_conformance.py +0 -0
  360. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_render_max_chars.py +0 -0
  361. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_verify.py +0 -0
  362. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/render/test_verify_conformance.py +0 -0
  363. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
  364. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/__init__.py +0 -0
  365. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_fr5c_merge_attribution.py +0 -0
  366. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_fr5d_reference_resolution.py +0 -0
  367. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_fr5e_database_source_shape.py +0 -0
  368. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_json_path.py +0 -0
  369. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_semantic_diff.py +0 -0
  370. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_source_on_node.py +0 -0
  371. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/source/test_yaml_positions.py +0 -0
  372. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/test_api_docs_accuracy.py +0 -0
  373. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/__init__.py +0 -0
  374. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_capabilities.py +0 -0
  375. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_common_attrs.py +0 -0
  376. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_core_types.py +0 -0
  377. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_effective_package.py +0 -0
  378. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_errors.py +0 -0
  379. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_enum.py +0 -0
  380. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_enum_intvaluemap.py +0 -0
  381. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_map_validation.py +0 -0
  382. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  383. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  384. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_index_lookup.py +0 -0
  385. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_llm_recorder.py +0 -0
  386. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_loader.py +0 -0
  387. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_loader_bom.py +0 -0
  388. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_loader_class.py +0 -0
  389. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_merge.py +0 -0
  390. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_meta_attr.py +0 -0
  391. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_meta_data.py +0 -0
  392. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_meta_source.py +0 -0
  393. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_module_shortcuts.py +0 -0
  394. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_n2m_resolver.py +0 -0
  395. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  396. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  397. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  398. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_object_manager_write_through.py +0 -0
  399. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_one_primary_source.py +0 -0
  400. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_parser.py +0 -0
  401. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_parser_yaml.py +0 -0
  402. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_provider.py +0 -0
  403. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_provider_extension.py +0 -0
  404. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry.py +0 -0
  405. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry_completeness.py +0 -0
  406. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry_extend.py +0 -0
  407. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_registry_sealed.py +0 -0
  408. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_relationship_referential_actions.py +0 -0
  409. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_resolution_key.py +0 -0
  410. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  411. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_serializer.py +0 -0
  412. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_shared_constants.py +0 -0
  413. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_smoke.py +0 -0
  414. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_source_escapes.py +0 -0
  415. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_sources.py +0 -0
  416. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_strict_child_placement.py +0 -0
  417. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_super_resolve.py +0 -0
  418. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_template_toolcall.py +0 -0
  419. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  420. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_attr_schema.py +0 -0
  421. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_filter_values.py +0 -0
  422. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_origin_195.py +0 -0
  423. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_origin_paths.py +0 -0
  424. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_sort_field.py +0 -0
  425. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_validation_warnings.py +0 -0
  426. {metaobjects-0.24.4 → metaobjects-0.24.5}/tests/unit/test_write_coercion_arrays.py +0 -0
  427. {metaobjects-0.24.4 → metaobjects-0.24.5}/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.24.4
3
+ Version: 0.24.5
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.24.4"
3
+ version = "0.24.5"
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"
@@ -10,6 +10,7 @@ installed MetaObjects version.
10
10
 
11
11
  from __future__ import annotations
12
12
 
13
+ import re
13
14
  from dataclasses import dataclass
14
15
  from importlib.metadata import PackageNotFoundError, version as _pkg_version
15
16
 
@@ -76,6 +77,61 @@ class Manifest:
76
77
  )
77
78
 
78
79
 
80
+ # The sentinel a port stamps when it cannot resolve its own installed version.
81
+ _UNRESOLVED_VERSION = "0.0.0"
82
+
83
+ _RELEASE_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
84
+
85
+
86
+ def _release_series(version: object) -> tuple[int, int] | None:
87
+ """Ordered release coordinate ``(minor, patch)``, or ``None`` when not orderable.
88
+
89
+ The MAJOR is deliberately dropped. It is a per-registry constant, not information:
90
+ npm/PyPI/NuGet ship ``0.<m>.<p>`` and Maven Central the same ``<m>.<p>`` on its
91
+ historical major ``7``, so minor.patch IS the shared release coordinate across all
92
+ four ports.
93
+
94
+ ``None`` means "not orderable, so nudge", and deliberately covers prereleases
95
+ (``0.24.5-rc.1``), build metadata (``0.24.5+abc``) and the ``0.0.0`` sentinel. Each
96
+ must keep nudging: an RC-scaffolded context against a final release is still worth
97
+ refreshing, and an unknown install must never assert "in sync".
98
+ """
99
+ if not isinstance(version, str):
100
+ return None
101
+ v = version.strip()
102
+ if v == _UNRESOLVED_VERSION:
103
+ return None
104
+ m = _RELEASE_RE.match(v)
105
+ if m is None:
106
+ return None
107
+ return int(m.group(2)), int(m.group(3))
108
+
109
+
110
+ def _context_is_ahead_of_install(generated_by: object, current_version: str) -> bool:
111
+ """True when the manifest was stamped by a release STRICTLY NEWER than the install.
112
+
113
+ The one exemption from "any drift nudges", and it exists because of the
114
+ publish-what-changed rule (docs/RELEASING.md): a registry publishes only when it has
115
+ a changed product file, so a port legitimately sits behind npm — while
116
+ ``meta agent-docs``, the canonical scaffolder for EVERY port, stamps the npm version
117
+ it was run from. A Python install at ``0.24.4`` whose context was scaffolded by npm
118
+ ``0.24.7`` is correct, and nudging it is issue #347 exactly: the remedy re-runs the
119
+ scaffolder, which re-stamps ``0.24.7``, so the advisory can never be satisfied and
120
+ fires on every build forever.
121
+
122
+ KNOWN BOUND, stated rather than hidden: ordering on minor.patch assumes both versions
123
+ sit in the same release SERIES. That holds for every release to date and after the
124
+ 1.0/8.0 cut, but not ACROSS it — there a ``0.24.x`` context against a ``1.0.0``
125
+ install reads as "ahead" and the nudge is suppressed once. A missed advisory, never a
126
+ wrong action.
127
+ """
128
+ stamped = _release_series(generated_by)
129
+ installed = _release_series(current_version)
130
+ if stamped is None or installed is None:
131
+ return False # not orderable → nudge
132
+ return stamped > installed
133
+
134
+
79
135
  def agent_context_staleness(
80
136
  manifest: dict[str, object] | None, current_version: str
81
137
  ) -> str | None:
@@ -85,15 +141,18 @@ def agent_context_staleness(
85
141
  is in sync — and a one-line advisory message otherwise. Pure + advisory:
86
142
  never raises, never blocks, never writes.
87
143
 
88
- The comparison is **exact equality** on purpose: ANY drift nudges (a
89
- re-scaffold is cheap + idempotent). Do NOT "fix" this into a semver compare —
90
- a prerelease/build-metadata difference is still a reason to refresh.
144
+ The comparison is **exact equality** first: ANY drift nudges (a re-scaffold is
145
+ cheap + idempotent), so this is not a semver compare — a prerelease or
146
+ build-metadata difference is still a reason to refresh. See
147
+ ``_context_is_ahead_of_install`` for the ONE case that is exempt.
91
148
  """
92
149
  if manifest is None:
93
150
  return None # no agent context here → nothing to nudge
94
151
  generated_by = manifest.get("generatedBy")
95
152
  if generated_by == current_version:
96
153
  return None # in sync
154
+ if _context_is_ahead_of_install(generated_by, current_version):
155
+ return None # scaffolded by a NEWER release than this install — see below
97
156
  frm = generated_by if generated_by else "an older MetaObjects"
98
157
  return (
99
158
  f"MetaObjects agent context was generated by {frm}; "
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
 
4
4
  from dataclasses import dataclass, field
5
5
 
6
+ from metaobjects.naming import DEFAULT_COLUMN_NAMING
7
+
6
8
 
7
9
  @dataclass
8
10
  class GenConfig:
@@ -23,5 +25,12 @@ class GenConfig:
23
25
  # maps a declaring metadata package ("acme::shop") to the Python import module; with a
24
26
  # single ``provided_enum_namespace`` fallback for the one-module case. A referenced
25
27
  # @provided enum whose package resolves to no module is a codegen-time error.
28
+ # How a field with no explicit `@column` becomes a physical column name
29
+ # ("literal" | "snake_case" | "kebab-case"). Config, never metadata: the same model
30
+ # must be able to drive a snake_case schema and a literal-column one. Defaults to
31
+ # `literal`, this port's historical behaviour — but `meta migrate`, which owns
32
+ # schema for EVERY port (ADR-0015), defaults to `snake_case`, so a project whose
33
+ # tables it created wants `snake_case` here or an explicit `@column` per field.
34
+ column_naming: str = DEFAULT_COLUMN_NAMING
26
35
  provided_enum_namespace: str | None = None
27
36
  provided_enum_packages: dict[str, str] = field(default_factory=dict)
@@ -339,13 +339,20 @@ def _field_line(field: MetaField, imports: set[str], config: GenConfig) -> tuple
339
339
  else:
340
340
  assignment = " = None"
341
341
 
342
- # Pydantic field name = @column when present, else field.name. A cross-port
343
- # entity carries the camelCase field.name (the TS property) AND the snake_case
344
- # @column (the physical DB column); the Python model field IS the column, so it
345
- # binds straight to the row. Backward-compatible: snake-authored models with no
346
- # @column emit field.name unchanged.
347
- py_name = field.attrs().get(fc.FIELD_ATTR_COLUMN) or field.name
348
- return f" {py_name}: {annotation}{assignment}", uses_field
342
+ # Pydantic field name = field.name, ALWAYS. `@column` is the physical column name,
343
+ # a different axis: it is what the persistence layer binds to, never what the model
344
+ # calls the field. Every other surface in this port already keyed by field.name
345
+ # the FR-036 create/patch models, the generated router, and the runtime, whose
346
+ # ObjectManager maps {_column_of(f): f.name} on every read and RETURNING clause
347
+ # "for cross-port row-shape parity" — so keying the read model by @column made one
348
+ # generated module disagree with itself, and its stated reason (that the model field
349
+ # binds straight to the row) was never true.
350
+ #
351
+ # Idiomatic snake_case for a Python consumer is a real goal and this is not the
352
+ # lever for it: `columnNamingStrategy` applied to field.name is, because @column is
353
+ # free-form — `callPurpose` + `@column: purpose_code` used to emit a field
354
+ # `purpose_code`, which is neither the wire name nor derived from the field name.
355
+ return f" {field.name}: {annotation}{assignment}", uses_field
349
356
 
350
357
 
351
358
  def _primary_identity_field_names(entity: MetaObject) -> list[str]:
@@ -26,6 +26,11 @@ from __future__ import annotations
26
26
  from dataclasses import dataclass
27
27
 
28
28
  from metaobjects.meta.core.field import field_constants as fc
29
+ from metaobjects.naming import (
30
+ DEFAULT_COLUMN_NAMING,
31
+ apply_column_naming_strategy,
32
+ resolve_column_name,
33
+ )
29
34
  from metaobjects.meta.core.field.meta_field import MetaField
30
35
  from metaobjects.meta.meta_data import MetaData
31
36
  from metaobjects.meta.core.identity.identity_constants import (
@@ -92,15 +97,18 @@ def _physical_table(entity: MetaObject) -> str:
92
97
  return entity.name
93
98
 
94
99
 
95
- def _column_of(field: MetaField | None, fallback: str) -> str:
96
- """Physical column name for a metadata field name: its ``@column`` override,
97
- else the field's own name. Mirrors the runtime ``object_manager._column_of``
98
- (no implicit snake_case the metadata field name IS the column unless
99
- ``@column`` overrides)."""
100
+ def _column_of(
101
+ field: MetaField | None, fallback: str, strategy: str = DEFAULT_COLUMN_NAMING
102
+ ) -> str:
103
+ """Physical column name for a junction FK. Delegates to the shared
104
+ :func:`metaobjects.naming.resolve_column_name` — the SAME resolver the runtime uses,
105
+ so generated junction SQL and runtime SQL cannot disagree about a column name.
106
+
107
+ *fallback* covers the case where the field could not be resolved at all; it is a
108
+ bare metadata name, so it goes through the strategy too."""
100
109
  if field is None:
101
- return fallback
102
- col = field.attrs().get(fc.FIELD_ATTR_COLUMN)
103
- return col if isinstance(col, str) and col else field.name
110
+ return apply_column_naming_strategy(fallback, strategy)
111
+ return resolve_column_name(field, strategy)
104
112
 
105
113
 
106
114
  def _field_named(entity: MetaObject, field_name: str) -> MetaField | None:
@@ -144,7 +152,9 @@ def m2m_relationships(entity: MetaObject) -> list[MetaRelationship]:
144
152
 
145
153
 
146
154
  def resolve_m2m_descriptors(
147
- entity: MetaObject, object_index: dict[str, MetaObject]
155
+ entity: MetaObject,
156
+ object_index: dict[str, MetaObject],
157
+ column_naming: str = DEFAULT_COLUMN_NAMING,
148
158
  ) -> list[M2mDescriptor]:
149
159
  """Resolve every M:N navigation on *entity* into a build-time descriptor.
150
160
 
@@ -181,11 +191,12 @@ def resolve_m2m_descriptors(
181
191
  target_plural=plural_lowercase(target.name),
182
192
  junction_table=_physical_table(junction),
183
193
  target_table=_physical_table(target),
184
- source_column=_column_of(source_fk, fields.source_field),
185
- target_column=_column_of(target_fk, fields.target_field),
194
+ source_column=_column_of(source_fk, fields.source_field, column_naming),
195
+ target_column=_column_of(target_fk, fields.target_field, column_naming),
186
196
  target_pk_column=_column_of(
187
197
  _field_named(target, pk_field_name(target)),
188
198
  pk_field_name(target),
199
+ column_naming,
189
200
  ),
190
201
  symmetric=rel.symmetric(),
191
202
  )
@@ -0,0 +1,90 @@
1
+ """Physical naming: how a metadata name becomes a database identifier.
2
+
3
+ The column-naming strategy is CONFIG, not metadata (ADR-0023 does not apply). The same
4
+ model has to be able to drive a snake_case Postgres schema and a literal-column one —
5
+ which is exactly why it lives beside the persistence layer rather than in the metadata,
6
+ and why the byte-gated registry prose for ``@column`` describes the default as coming
7
+ "via columnNamingStrategy".
8
+
9
+ Cross-port siblings, sharing this vocabulary and this algorithm:
10
+ * TypeScript ``metadata/src/naming.ts`` (``applyColumnNamingStrategy``)
11
+ * C# ``MetaObjects.Codegen`` (``ColumnNamingStrategy``)
12
+ * Kotlin ``KotlinGenUtil`` (``applyColumnNamingStrategy``)
13
+
14
+ **This port's default is ``literal``** — ``@column`` or the field name verbatim — which
15
+ is what it has always done. Note that the ports deliberately differ here (TypeScript
16
+ defaults to ``snake_case``, the Postgres convention; C# to ``literal``, EF's
17
+ property=column convention), so a polyglot project either sets the strategy explicitly
18
+ or declares ``@column``.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ from metaobjects.meta.core.field import field_constants as fc
23
+ from metaobjects.meta.core.field.meta_field import MetaField
24
+
25
+ COLUMN_NAMING_SNAKE_CASE = "snake_case"
26
+ COLUMN_NAMING_LITERAL = "literal"
27
+ COLUMN_NAMING_KEBAB_CASE = "kebab-case"
28
+
29
+ COLUMN_NAMING_STRATEGIES = (
30
+ COLUMN_NAMING_SNAKE_CASE,
31
+ COLUMN_NAMING_LITERAL,
32
+ COLUMN_NAMING_KEBAB_CASE,
33
+ )
34
+
35
+ #: This port's default. Not the same as TypeScript's — see the module docstring.
36
+ DEFAULT_COLUMN_NAMING = COLUMN_NAMING_LITERAL
37
+
38
+
39
+ def to_snake_case(name: str) -> str:
40
+ """``displayName`` → ``display_name``, ``URLPath`` → ``url_path``.
41
+
42
+ Byte-for-byte the algorithm the other ports use: insert ``_`` before an uppercase
43
+ letter preceded by a lowercase letter or digit, OR before an uppercase letter that
44
+ both follows another uppercase and precedes a lowercase (so an acronym splits once,
45
+ ``URLPath`` → ``url_path``, not ``u_r_l_path``). A port-local approximation would put
46
+ the two halves of one schema out of step.
47
+ """
48
+ if not name:
49
+ return name
50
+ out: list[str] = []
51
+ for i, c in enumerate(name):
52
+ if i > 0 and c.isupper():
53
+ prev = name[i - 1]
54
+ nxt = name[i + 1] if i + 1 < len(name) else None
55
+ if prev.islower() or prev.isdigit() or (
56
+ prev.isupper() and nxt is not None and nxt.islower()
57
+ ):
58
+ out.append("_")
59
+ out.append(c.lower())
60
+ return "".join(out)
61
+
62
+
63
+ def apply_column_naming_strategy(name: str, strategy: str = DEFAULT_COLUMN_NAMING) -> str:
64
+ """Apply a strategy to a bare name.
65
+
66
+ An unknown strategy RAISES rather than falling back to the default: a typo would
67
+ otherwise bind a whole schema to the wrong columns and report success.
68
+ """
69
+ if strategy == COLUMN_NAMING_LITERAL:
70
+ return name
71
+ if strategy == COLUMN_NAMING_SNAKE_CASE:
72
+ return to_snake_case(name)
73
+ if strategy == COLUMN_NAMING_KEBAB_CASE:
74
+ return to_snake_case(name).replace("_", "-")
75
+ raise ValueError(
76
+ f"unknown column-naming strategy {strategy!r}; "
77
+ f"expected one of: {', '.join(COLUMN_NAMING_STRATEGIES)}"
78
+ )
79
+
80
+
81
+ def resolve_column_name(field: MetaField, strategy: str = DEFAULT_COLUMN_NAMING) -> str:
82
+ """THE physical column name for a field: its explicit ``@column`` when present,
83
+ else ``field.name`` through the project's strategy.
84
+
85
+ ADR-0039: read RESOLVING — ``@column`` may be inherited through ``extends``.
86
+ """
87
+ col = field.get_meta_attr(fc.FIELD_ATTR_COLUMN)
88
+ if isinstance(col, str) and col:
89
+ return col
90
+ return apply_column_naming_strategy(field.name, strategy)
@@ -36,6 +36,7 @@ from ..meta.meta_root import MetaRoot
36
36
  from ..meta.core.object.meta_object import MetaObject
37
37
  from ..meta.core.field.meta_field import MetaField
38
38
  from ..meta.core.field import field_constants as fc
39
+ from ..naming import DEFAULT_COLUMN_NAMING, resolve_column_name
39
40
  from ..meta.core.identity import identity_constants as ic
40
41
  from ..meta.persistence.db import db_constants as dbc
41
42
  from ..meta.persistence.source.meta_source import MetaSource
@@ -176,9 +177,21 @@ class PostgresDriver:
176
177
  class ObjectManager:
177
178
  """Method-based read API. Translates Filter dicts → parameterized SQL."""
178
179
 
179
- def __init__(self, root: MetaRoot, driver: PostgresDriver) -> None:
180
+ def __init__(
181
+ self,
182
+ root: MetaRoot,
183
+ driver: PostgresDriver,
184
+ column_naming: str = DEFAULT_COLUMN_NAMING,
185
+ ) -> None:
180
186
  self._root = root
181
187
  self._driver = driver
188
+ # How a field with no explicit `@column` becomes a physical column name.
189
+ # Config, never metadata: the same model must be able to drive a snake_case
190
+ # schema and a literal-column one. Defaults to `literal`, this port's
191
+ # historical behaviour — but note `meta migrate`, which owns schema for EVERY
192
+ # port (ADR-0015), defaults to `snake_case`, so a project whose tables it
193
+ # created wants `snake_case` here or an explicit `@column` per field.
194
+ self._column_naming = column_naming
182
195
  self._entity_by_name: dict[str, MetaObject] = {}
183
196
  # ADR-0039 sanctioned own: top-level entity scan on the loader ROOT
184
197
  # (metadata.root is never extended, so own == effective) — mirrors the TS
@@ -278,7 +291,7 @@ class ObjectManager:
278
291
  # model, which carries derived fields) must not try to INSERT it; drop it here.
279
292
  if f.is_derived():
280
293
  continue
281
- insert_cols.append(_column_of(f))
294
+ insert_cols.append(_column_of(f, self._column_naming))
282
295
  params.append(_coerce_write_value(f, raw))
283
296
 
284
297
  # RETURNING the physical column set so the inserted row — including any
@@ -287,8 +300,8 @@ class ObjectManager:
287
300
  # column on the write table (it is computed by the replica view), so it is
288
301
  # excluded from RETURNING; the write-through re-read below fetches it via the view.
289
302
  returning_fields = [f for f in entity.fields() if not f.is_derived()]
290
- all_cols = [_column_of(f) for f in returning_fields]
291
- col_to_field = {_column_of(f): f.name for f in returning_fields}
303
+ all_cols = [_column_of(f, self._column_naming) for f in returning_fields]
304
+ col_to_field = {_column_of(f, self._column_naming): f.name for f in returning_fields}
292
305
 
293
306
  if insert_cols:
294
307
  col_list = ", ".join(_q(c) for c in insert_cols)
@@ -355,7 +368,7 @@ class ObjectManager:
355
368
  entity = self._require_entity(entity_name)
356
369
  table = self._table_name(entity)
357
370
  pk_field = self._primary_pk_field(entity)
358
- pk_col = _column_of(entity.find_field(pk_field))
371
+ pk_col = _column_of(entity.find_field(pk_field), self._column_naming)
359
372
 
360
373
  # #203 — @autoSet: bump every onUpdate column to now(), and NEVER rewrite an
361
374
  # onCreate column — strip it even if the caller supplied a (stale) value.
@@ -389,7 +402,7 @@ class ObjectManager:
389
402
  # UPDATE it; drop it from the SET list.
390
403
  if f.is_derived():
391
404
  continue
392
- set_cols.append(_column_of(f))
405
+ set_cols.append(_column_of(f, self._column_naming))
393
406
  params.append(_coerce_write_value(f, raw))
394
407
  if not set_cols:
395
408
  # No columns to set → just read the (scoped) row back by PK (no-op update).
@@ -400,13 +413,13 @@ class ObjectManager:
400
413
  # the write table (computed by the replica view); the write-through re-read below
401
414
  # fetches them via the view.
402
415
  returning_fields = [f for f in entity.fields() if not f.is_derived()]
403
- all_cols = [_column_of(f) for f in returning_fields]
404
- col_to_field = {_column_of(f): f.name for f in returning_fields}
416
+ all_cols = [_column_of(f, self._column_naming) for f in returning_fields]
417
+ col_to_field = {_column_of(f, self._column_naming): f.name for f in returning_fields}
405
418
  assignments = ", ".join(f"{_q(c)} = %s" for c in set_cols)
406
419
  params.append(_coerce_write_value(entity.find_field(pk_field), id_value))
407
420
  where = f"{_q(pk_col)} = %s"
408
421
  if tph is not None:
409
- where += f" AND {_q(_column_of(entity.find_field(tph.field)))} = %s"
422
+ where += f" AND {_q(_column_of(entity.find_field(tph.field), self._column_naming))} = %s"
410
423
  params.append(tph.value)
411
424
  sql = (
412
425
  f"UPDATE {_q(table)} SET {assignments} WHERE {where} "
@@ -456,14 +469,14 @@ class ObjectManager:
456
469
  entity = self._require_entity(entity_name)
457
470
  table = self._table_name(entity)
458
471
  pk_field = self._primary_pk_field(entity)
459
- pk_col = _column_of(entity.find_field(pk_field))
472
+ pk_col = _column_of(entity.find_field(pk_field), self._column_naming)
460
473
  params: list[Any] = [_coerce_write_value(entity.find_field(pk_field), id_value)]
461
474
  where = f"{_q(pk_col)} = %s"
462
475
  # FR-017 TPH: a subtype delete is scoped to its discriminator (cross-subtype
463
476
  # delete matches no row → False, mirroring the per-subtype route's 404).
464
477
  tph = tph_subtype_of(entity)
465
478
  if tph is not None:
466
- where += f" AND {_q(_column_of(entity.find_field(tph.field)))} = %s"
479
+ where += f" AND {_q(_column_of(entity.find_field(tph.field), self._column_naming))} = %s"
467
480
  params.append(tph.value)
468
481
  sql = f"DELETE FROM {_q(table)} WHERE {where}"
469
482
  return self._driver.execute_rowcount(sql, tuple(params)) > 0
@@ -482,14 +495,14 @@ class ObjectManager:
482
495
  # derived origin.* columns), else the entity's own primary source. All effective
483
496
  # fields (incl. derived) are selected — the view exposes them.
484
497
  table = self._read_source_name(entity)
485
- cols = [_column_of(f) for f in entity.fields()]
498
+ cols = [_column_of(f, self._column_naming) for f in entity.fields()]
486
499
  sql = f'SELECT {", ".join(_q(c) for c in cols)} FROM {_q(table)}'
487
500
  params: list[Any] = []
488
501
  # FR-017 TPH: a subtype read is scoped to its discriminator value (a row of
489
502
  # a different subtype is invisible); the base entity (no @discriminatorValue)
490
503
  # reads polymorphically across the single table.
491
504
  filter = self._scope_filter(filter, tph_subtype_of(entity))
492
- where = _compile_filter(filter, entity) if filter else None
505
+ where = _compile_filter(filter, entity, self._column_naming) if filter else None
493
506
  if where is not None:
494
507
  sql += " WHERE " + where[0]
495
508
  params.extend(where[1])
@@ -497,7 +510,7 @@ class ObjectManager:
497
510
  order_parts = []
498
511
  for field_name, direction in sort:
499
512
  f = entity.find_field(field_name)
500
- col = _column_of(f) if f is not None else field_name
513
+ col = _column_of(f, self._column_naming) if f is not None else field_name
501
514
  d = "DESC" if direction.lower() == "desc" else "ASC"
502
515
  order_parts.append(f"{_q(col)} {d}")
503
516
  if order_parts:
@@ -509,7 +522,7 @@ class ObjectManager:
509
522
  result = self._driver.select(sql, tuple(params))
510
523
  # Map raw column → metadata field name for cross-port row-shape parity.
511
524
  # Values stay native (ADR-0019); the boundary canonicalizes them.
512
- col_to_field = {_column_of(f): f.name for f in entity.fields()}
525
+ col_to_field = {_column_of(f, self._column_naming): f.name for f in entity.fields()}
513
526
  self.last_column_oids = {
514
527
  col_to_field.get(c, c): oid for c, oid in result.column_oids.items()
515
528
  }
@@ -528,7 +541,7 @@ class ObjectManager:
528
541
  sql = f"SELECT COUNT(*) FROM {_q(table)}"
529
542
  params: list[Any] = []
530
543
  filter = self._scope_filter(filter, tph_subtype_of(entity)) # FR-017 TPH subtype scope
531
- where = _compile_filter(filter, entity) if filter else None
544
+ where = _compile_filter(filter, entity, self._column_naming) if filter else None
532
545
  if where is not None:
533
546
  sql += " WHERE " + where[0]
534
547
  params.extend(where[1])
@@ -670,7 +683,7 @@ class ObjectManager:
670
683
  raise ValueError(
671
684
  f"Junction '{junction.name}' has no field '{field_name}'"
672
685
  )
673
- return _column_of(f)
686
+ return _column_of(f, self._column_naming)
674
687
 
675
688
  def primary_key_field(self, entity_name: str) -> str:
676
689
  """The single-field primary-key NAME for an entity, from its
@@ -695,7 +708,9 @@ class ObjectManager:
695
708
  # ----------------------------------------------------------------------------
696
709
 
697
710
 
698
- def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any]] | None:
711
+ def _compile_filter(
712
+ f: Filter | None, entity: MetaObject, column_naming: str = DEFAULT_COLUMN_NAMING
713
+ ) -> tuple[str, list[Any]] | None:
699
714
  if not f:
700
715
  return None
701
716
  # Top-level `and: [filter, filter, ...]` combinator.
@@ -703,7 +718,7 @@ def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any
703
718
  parts: list[str] = []
704
719
  params: list[Any] = []
705
720
  for child in f["and"]:
706
- compiled = _compile_filter(child, entity)
721
+ compiled = _compile_filter(child, entity, column_naming)
707
722
  if compiled is None:
708
723
  continue
709
724
  parts.append("(" + compiled[0] + ")")
@@ -716,7 +731,7 @@ def _compile_filter(f: Filter | None, entity: MetaObject) -> tuple[str, list[Any
716
731
  params = []
717
732
  for field_name, ops in f.items():
718
733
  mf = entity.find_field(field_name)
719
- col = _column_of(mf) if mf is not None else field_name
734
+ col = _column_of(mf, column_naming) if mf is not None else field_name
720
735
  if not isinstance(ops, dict):
721
736
  # Shortcut: {field: value} → equality. Encoded like any other bound
722
737
  # value (see _op_clause) so an int-backed enum reaches SQL as its int.
@@ -992,11 +1007,13 @@ def _parse_datetime(text: str, *, tz_aware: bool) -> _dt.datetime:
992
1007
  return dt.replace(tzinfo=None)
993
1008
 
994
1009
 
995
- def _column_of(field: MetaField | None) -> str:
1010
+ def _column_of(field: MetaField | None, strategy: str = DEFAULT_COLUMN_NAMING) -> str:
1011
+ """Physical column for a field. Module-level shim over the shared
1012
+ :func:`metaobjects.naming.resolve_column_name` so the runtime and codegen cannot
1013
+ drift on what a column is called."""
996
1014
  if field is None:
997
1015
  return ""
998
- col = field.get_meta_attr(fc.FIELD_ATTR_COLUMN) # ADR-0039 resolving: @column may be inherited
999
- return col if isinstance(col, str) and col else field.name
1016
+ return resolve_column_name(field, strategy)
1000
1017
 
1001
1018
 
1002
1019
  def _q(ident: str) -> str:
@@ -128,22 +128,34 @@ def test_nested_object_array_imports_ref() -> None:
128
128
  assert "posts: list[PostBrief] | None = None" in out
129
129
 
130
130
 
131
- def test_column_attr_overrides_python_field_name() -> None:
132
- """A field's ``@column`` (the physical DB column) is the READ-model Pydantic field
133
- name when present, falling back to ``field.name``. This lets one entity carry the
134
- camelCase ``field.name`` the TS port emits as a property AND the snake_case
135
- ``@column`` the Python read model emits as the model field (= DB column), so a single
136
- cross-port entity feeds both languages idiomatically. The FR-036 create/patch
137
- VALIDATION models, by contrast, key by the WIRE name (field.name) — the router
138
- validates the raw wire body (see test_create_model_validates_against_wire_name)."""
131
+ def test_column_attr_does_not_rename_the_read_model_field() -> None:
132
+ """``@column`` is the PHYSICAL column name. It must not become the Pydantic field
133
+ name that is a different axis, and conflating them made one generated module
134
+ disagree with itself.
135
+
136
+ The read model used to key by ``@column``. Everything else in this port keys by
137
+ ``field.name``: the FR-036 create/patch models, the generated router (it stamps
138
+ ``dto["createdAt"]``), and the runtime ``ObjectManager`` maps
139
+ ``{_column_of(f): f.name}`` on every read and RETURNING clause, commented "for
140
+ cross-port row-shape parity". So the read model's stated reason ("the Python model
141
+ field IS the column, so it binds straight to the row") was false: the runtime never
142
+ hands out column-keyed rows.
143
+
144
+ It also leaked. ``@column`` is a free-form override, so a field ``callPurpose`` with
145
+ ``@column: purpose_code`` produced a Pydantic field ``purpose_code`` — neither the
146
+ wire name nor anything derived from the field name, just the DB column surfacing in
147
+ the API shape. Idiomatic snake_case for Python is a real goal; the lever for it is
148
+ ``columnNamingStrategy`` applied to ``field.name``, not the column override.
149
+ """
139
150
  f = _f("callPurpose", fc.FIELD_SUBTYPE_STRING, required=True)
140
- f.set_attr(fc.FIELD_ATTR_COLUMN, "call_purpose")
151
+ # Deliberately NOT the snake_case of the field name — that coincidence is what made
152
+ # the old behaviour look right.
153
+ f.set_attr(fc.FIELD_ATTR_COLUMN, "purpose_code")
141
154
  e = _entity("LlmCall", [f], package="app::telemetry")
142
155
  out = render_entity_model(e)
143
- # Scope to the read model (before the first validation model): it binds @column.
144
156
  read_model = out.split("class LlmCallCreate")[0]
145
- assert "call_purpose: str" in read_model
146
- assert "callPurpose" not in read_model
157
+ assert "callPurpose: str" in read_model
158
+ assert "purpose_code" not in read_model
147
159
 
148
160
 
149
161
  def test_field_name_used_when_no_column_attr() -> None:
@@ -301,8 +313,9 @@ def test_create_model_validates_against_wire_name_not_column() -> None:
301
313
  f.set_attr(fc.FIELD_ATTR_COLUMN, "full_name")
302
314
  mod = _load_models(_entity("Person", [f], package="app::p"))
303
315
 
304
- # Read model keeps the @column name; the create model keys by the wire name.
305
- assert "full_name" in mod.Person.model_fields
316
+ # BOTH key by the wire name now — the read model no longer renames itself to
317
+ # @column, so one module no longer disagrees with itself about what a field is called.
318
+ assert "fullName" in mod.Person.model_fields
306
319
  assert "fullName" in mod.PersonCreate.model_fields
307
320
  # An over-length WIRE value is now actually rejected (was silently dropped before).
308
321
  with pytest.raises(ValidationError):
@@ -62,3 +62,41 @@ def test_installed_version_is_a_string() -> None:
62
62
  v = installed_metaobjects_version()
63
63
  assert isinstance(v, str)
64
64
  assert v # non-empty
65
+
66
+
67
+ # ── the context is AHEAD of the install (publish-what-changed, docs/RELEASING.md) ──
68
+ # A registry publishes only when it has a changed product file, so Python legitimately
69
+ # sits behind npm — and ``meta agent-docs`` (npm, canonical for every port) stamps the
70
+ # NEWER version. Nudging there is #347's shape: the remedy re-stamps the same newer
71
+ # version, so the advisory can never be satisfied and fires forever on a correct setup.
72
+ def test_context_from_a_newer_release_is_silent() -> None:
73
+ assert agent_context_staleness({"generatedBy": "0.24.7"}, "0.24.4") is None
74
+
75
+
76
+ def test_context_newer_only_in_the_patch_is_silent() -> None:
77
+ assert agent_context_staleness({"generatedBy": "0.24.5"}, "0.24.4") is None
78
+
79
+
80
+ def test_context_older_than_the_install_still_nudges() -> None:
81
+ msg = agent_context_staleness({"generatedBy": "0.24.4"}, "0.24.7")
82
+ assert msg is not None
83
+ assert "0.24.4" in msg
84
+ assert "0.24.7" in msg
85
+
86
+
87
+ # The suppression is deliberately narrow: anything not orderable as a plain release
88
+ # still nudges, preserving the documented "ANY drift nudges" property.
89
+ def test_prerelease_context_still_nudges() -> None:
90
+ assert agent_context_staleness({"generatedBy": "0.24.5-rc.1"}, "0.24.4") is not None
91
+
92
+
93
+ def test_build_metadata_still_nudges() -> None:
94
+ assert agent_context_staleness({"generatedBy": "0.24.5+abc"}, "0.24.4") is not None
95
+
96
+
97
+ def test_unresolved_install_never_asserts_in_sync() -> None:
98
+ assert agent_context_staleness({"generatedBy": "0.24.7"}, "0.0.0") is not None
99
+
100
+
101
+ def test_non_numeric_version_still_nudges() -> None:
102
+ assert agent_context_staleness({"generatedBy": "dev"}, "0.24.4") is not None