metaobjects 0.23.0__tar.gz → 0.23.2__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 (410) hide show
  1. {metaobjects-0.23.0 → metaobjects-0.23.2}/PKG-INFO +1 -1
  2. {metaobjects-0.23.0 → metaobjects-0.23.2}/pyproject.toml +1 -1
  3. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +39 -4
  4. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/fr019_shared_enum.py +15 -6
  5. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/core_types.py +13 -0
  6. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/errors.py +6 -0
  7. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validation_passes.py +215 -14
  8. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/attr/attr_constants.py +8 -0
  9. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/attr/meta_attr.py +17 -0
  10. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/field_constants.py +7 -0
  11. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/requirement/meta_requirement.py +2 -1
  12. metaobjects-0.23.2/src/metaobjects/render/payload_accessors.py +134 -0
  13. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/renderer.py +5 -1
  14. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/verify.py +11 -1
  15. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/runtime/object_manager.py +94 -6
  16. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/attr.json +6 -0
  17. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/field.json +2 -1
  18. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/requirement.json +2 -2
  19. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/capabilities.py +7 -3
  20. metaobjects-0.23.2/tests/runtime/test_object_manager_enum_intvaluemap.py +192 -0
  21. metaobjects-0.23.2/tests/unit/test_field_enum_intvaluemap.py +185 -0
  22. {metaobjects-0.23.0 → metaobjects-0.23.2}/uv.lock +1 -1
  23. {metaobjects-0.23.0 → metaobjects-0.23.2}/.gitignore +0 -0
  24. {metaobjects-0.23.0 → metaobjects-0.23.2}/LICENSE +0 -0
  25. {metaobjects-0.23.0 → metaobjects-0.23.2}/README.md +0 -0
  26. {metaobjects-0.23.0 → metaobjects-0.23.2}/hatch_build.py +0 -0
  27. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/__init__.py +0 -0
  28. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/agent_context/__init__.py +0 -0
  29. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/agent_context/scaffold.py +0 -0
  30. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/apidocs/__init__.py +0 -0
  31. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/apidocs/api_model.py +0 -0
  32. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/apidocs/builder.py +0 -0
  33. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/apidocs/naming.py +0 -0
  34. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/apidocs/paths.py +0 -0
  35. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/apidocs/renderer.py +0 -0
  36. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/attr_class_map.py +0 -0
  37. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/cli.py +0 -0
  38. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  39. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/__init__.py +0 -0
  40. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/collision_names.py +0 -0
  41. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/config.py +0 -0
  42. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/constants.py +0 -0
  43. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  44. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  45. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/format.py +0 -0
  46. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  47. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generator.py +0 -0
  48. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generator_registry.py +0 -0
  49. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/__init__.py +0 -0
  50. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  51. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  52. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  53. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  54. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  55. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
  56. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  57. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  58. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  59. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  60. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  61. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  62. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
  63. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  64. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  65. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/project_config.py +0 -0
  66. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/runner.py +0 -0
  67. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  68. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  69. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  70. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  71. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  72. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  73. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/codegen/type_map.py +0 -0
  74. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/datatype.py +0 -0
  75. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/documentation/__init__.py +0 -0
  76. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/documentation/doc_constants.py +0 -0
  77. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/documentation/doc_provider.py +0 -0
  78. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/documentation/doc_schema.py +0 -0
  79. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/__init__.py +0 -0
  80. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/merge.py +0 -0
  81. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/meta_data_loader.py +0 -0
  82. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/registered_validation.py +0 -0
  83. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/sources/__init__.py +0 -0
  84. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/sources/directory_source.py +0 -0
  85. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/sources/file_source.py +0 -0
  86. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  87. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/sources/uri_source.py +0 -0
  88. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validate_discriminator.py +0 -0
  89. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  90. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validate_field_readonly.py +0 -0
  91. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  92. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  93. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  94. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/__init__.py +0 -0
  95. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/__init__.py +0 -0
  96. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  97. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/__init__.py +0 -0
  98. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  99. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  100. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  101. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  102. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/index/__init__.py +0 -0
  103. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  104. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  105. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/__init__.py +0 -0
  106. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  107. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  108. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  109. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  110. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  111. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/object/value_object.py +0 -0
  112. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  113. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  114. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  115. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  116. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  117. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  118. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  119. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  120. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/meta_data.py +0 -0
  121. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/meta_root.py +0 -0
  122. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/__init__.py +0 -0
  123. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  124. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  125. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  126. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  127. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  128. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  129. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  130. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  131. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  132. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/__init__.py +0 -0
  133. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  134. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  135. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  136. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  137. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  138. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  139. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  140. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  141. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/provider_extends.py +0 -0
  142. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/template/__init__.py +0 -0
  143. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/template/meta_template.py +0 -0
  144. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  145. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/meta/template/template_constants.py +0 -0
  146. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/naming_refs.py +0 -0
  147. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/parser.py +0 -0
  148. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/parser_yaml.py +0 -0
  149. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/provider.py +0 -0
  150. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/py.typed +0 -0
  151. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/registry.py +0 -0
  152. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/registry_manifest.py +0 -0
  153. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/__init__.py +0 -0
  154. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/email_document.py +0 -0
  155. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/escapers.py +0 -0
  156. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  157. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/__init__.py +0 -0
  158. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/coerce.py +0 -0
  159. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/extract.py +0 -0
  160. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/extract_map.py +0 -0
  161. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  162. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/locate.py +0 -0
  163. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/normalize.py +0 -0
  164. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/strip.py +0 -0
  165. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/types.py +0 -0
  166. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  167. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/filesystem_provider.py +0 -0
  168. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/prompt/__init__.py +0 -0
  169. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  170. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  171. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  172. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  173. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  174. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/runtime/__init__.py +0 -0
  175. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/runtime/llm_recorder.py +0 -0
  176. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  177. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/runtime/tph.py +0 -0
  178. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/serializer_json.py +0 -0
  179. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/shared/__init__.py +0 -0
  180. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/shared/base_types.py +0 -0
  181. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/shared/separators.py +0 -0
  182. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/shared/structural.py +0 -0
  183. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/source/__init__.py +0 -0
  184. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/source/error_source.py +0 -0
  185. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/source/json_path.py +0 -0
  186. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/source/semantic_diff.py +0 -0
  187. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/source/yaml_positions.py +0 -0
  188. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  189. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/db.json +0 -0
  190. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  191. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/identity.json +0 -0
  192. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/index.json +0 -0
  193. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/layout.json +0 -0
  194. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/object.json +0 -0
  195. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/origin.json +0 -0
  196. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  197. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  198. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/source.json +0 -0
  199. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/template.json +0 -0
  200. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  201. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/ui.json +0 -0
  202. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/validator.json +0 -0
  203. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/spec_metamodel/view.json +0 -0
  204. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/super_resolve.py +0 -0
  205. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/validation_types.py +0 -0
  206. {metaobjects-0.23.0 → metaobjects-0.23.2}/src/metaobjects/yaml_desugar.py +0 -0
  207. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/__init__.py +0 -0
  208. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/__init__.py +0 -0
  209. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  210. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/extends/expected/Program.py +0 -0
  211. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/extends/meta.json +0 -0
  212. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  213. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  214. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/nested-array/meta.json +0 -0
  215. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  216. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  217. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/scalars/meta.json +0 -0
  218. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  219. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/golden/vanilla/meta.json +0 -0
  220. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_abstract_conformance.py +0 -0
  221. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_api_docs_builder.py +0 -0
  222. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_api_docs_paths.py +0 -0
  223. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli.py +0 -0
  224. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_config_gen.py +0 -0
  225. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_config_verify.py +0 -0
  226. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_providers.py +0 -0
  227. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_registry.py +0 -0
  228. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  229. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_verify_strict.py +0 -0
  230. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  231. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_constants_config.py +0 -0
  232. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_entity_model.py +0 -0
  233. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_enum_conformance.py +0 -0
  234. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  235. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_extract_tier_collision.py +0 -0
  236. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_extractor_generator.py +0 -0
  237. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  238. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_format.py +0 -0
  239. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  240. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_fr010_output_codegen.py +0 -0
  241. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  242. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_generator.py +0 -0
  243. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_generator_extension_seams.py +0 -0
  244. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_golden.py +0 -0
  245. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  246. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_inheritance_conformance.py +0 -0
  247. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_instance_artifacts.py +0 -0
  248. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_m2m_codegen.py +0 -0
  249. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_origin_nullability.py +0 -0
  250. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_output_parser_generator.py +0 -0
  251. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_overwrite_policy.py +0 -0
  252. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_payload_vo_generator.py +0 -0
  253. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_project_config.py +0 -0
  254. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_projection_compile.py +0 -0
  255. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_render_helper_conformance.py +0 -0
  256. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_render_helper_generator.py +0 -0
  257. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_reverse_finders.py +0 -0
  258. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_router_autoset.py +0 -0
  259. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_router_generator.py +0 -0
  260. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_runner.py +0 -0
  261. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_sourceless_projection.py +0 -0
  262. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_template_data.py +0 -0
  263. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_template_generator.py +0 -0
  264. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_template_output_pattern.py +0 -0
  265. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_template_scope_helpers.py +0 -0
  266. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_template_scope_walk.py +0 -0
  267. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_template_spec.py +0 -0
  268. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_tph_codegen.py +0 -0
  269. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_trace_helper_generator.py +0 -0
  270. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_type_map.py +0 -0
  271. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_validation_conformance.py +0 -0
  272. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/codegen/test_write_through.py +0 -0
  273. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/__init__.py +0 -0
  274. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/conformance-expected-failures.json +0 -0
  275. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/conformance_adapter.py +0 -0
  276. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/corpus.py +0 -0
  277. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/expected_failures.py +0 -0
  278. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/fixture_discovery.py +0 -0
  279. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/navigator.py +0 -0
  280. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  281. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_conformance.py +0 -0
  282. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_extract_conformance.py +0 -0
  283. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_extract_object_verdict.py +0 -0
  284. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  285. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_fr011_attrs.py +0 -0
  286. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_generator_registry_conformance.py +0 -0
  287. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_object_model_conformance.py +0 -0
  288. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_provider_composition_conformance.py +0 -0
  289. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_registry_conformance.py +0 -0
  290. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_runner_hardfail.py +0 -0
  291. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  292. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_strict_attr_load.py +0 -0
  293. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_template_codegen_conformance.py +0 -0
  294. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_template_generator_conformance.py +0 -0
  295. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/test_yaml_conformance.py +0 -0
  296. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  297. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/__init__.py +0 -0
  298. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/api_contract_assertions.py +0 -0
  299. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/api_contract_jsonb_server.py +0 -0
  300. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/api_contract_m2m_server.py +0 -0
  301. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/api_contract_server.py +0 -0
  302. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/generated_jsonb_app.py +0 -0
  303. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/generated_m2m_app.py +0 -0
  304. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/generated_router_app.py +0 -0
  305. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/generated_tph_app.py +0 -0
  306. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/meta_ai_trace.yaml +0 -0
  307. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/normalization.py +0 -0
  308. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/postgres_container.py +0 -0
  309. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/query_runner.py +0 -0
  310. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/scenarios.py +0 -0
  311. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_api_contract.py +0 -0
  312. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_api_contract_generated.py +0 -0
  313. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_api_contract_jsonb.py +0 -0
  314. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_api_contract_m2m.py +0 -0
  315. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  316. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_api_contract_tph_generated.py +0 -0
  317. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  318. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_llm_call_trace.py +0 -0
  319. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_normalization.py +0 -0
  320. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_query_scenarios.py +0 -0
  321. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/integration/test_runtime_return_types.py +0 -0
  322. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/loader/__init__.py +0 -0
  323. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  324. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/loader/test_template_payload_target_210.py +0 -0
  325. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/open_closed_proof_test.py +0 -0
  326. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/__init__.py +0 -0
  327. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/__init__.py +0 -0
  328. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_coerce.py +0 -0
  329. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_extract.py +0 -0
  330. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_extract_map.py +0 -0
  331. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  332. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_locate.py +0 -0
  333. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_model.py +0 -0
  334. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_normalize.py +0 -0
  335. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_strip.py +0 -0
  336. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  337. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/prompt/__init__.py +0 -0
  338. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/prompt/test_output_format_renderer.py +0 -0
  339. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_email_document.py +0 -0
  340. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_filesystem_provider.py +0 -0
  341. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_output_format_renderer_nested.py +0 -0
  342. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_output_prompt_conformance.py +0 -0
  343. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_render_conformance.py +0 -0
  344. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_render_max_chars.py +0 -0
  345. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_verify.py +0 -0
  346. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/render/test_verify_conformance.py +0 -0
  347. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/__init__.py +0 -0
  348. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_fr5c_merge_attribution.py +0 -0
  349. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_fr5d_reference_resolution.py +0 -0
  350. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_fr5e_database_source_shape.py +0 -0
  351. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_json_path.py +0 -0
  352. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_semantic_diff.py +0 -0
  353. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_source_on_node.py +0 -0
  354. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/source/test_yaml_positions.py +0 -0
  355. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/test_api_docs_accuracy.py +0 -0
  356. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/__init__.py +0 -0
  357. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_agent_context_staleness.py +0 -0
  358. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_capabilities.py +0 -0
  359. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_common_attrs.py +0 -0
  360. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_core_types.py +0 -0
  361. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_effective_package.py +0 -0
  362. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_errors.py +0 -0
  363. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_field_enum.py +0 -0
  364. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_field_map_validation.py +0 -0
  365. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  366. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  367. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_index_lookup.py +0 -0
  368. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_llm_recorder.py +0 -0
  369. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_loader.py +0 -0
  370. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_loader_bom.py +0 -0
  371. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_loader_class.py +0 -0
  372. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_merge.py +0 -0
  373. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_meta_attr.py +0 -0
  374. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_meta_data.py +0 -0
  375. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_meta_source.py +0 -0
  376. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_module_shortcuts.py +0 -0
  377. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_n2m_resolver.py +0 -0
  378. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  379. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  380. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  381. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_object_manager_write_through.py +0 -0
  382. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_one_primary_source.py +0 -0
  383. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_parser.py +0 -0
  384. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_parser_yaml.py +0 -0
  385. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_provider.py +0 -0
  386. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_provider_extension.py +0 -0
  387. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_registry.py +0 -0
  388. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_registry_completeness.py +0 -0
  389. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_registry_extend.py +0 -0
  390. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_registry_sealed.py +0 -0
  391. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_relationship_referential_actions.py +0 -0
  392. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_resolution_key.py +0 -0
  393. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  394. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_serializer.py +0 -0
  395. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_shared_constants.py +0 -0
  396. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_smoke.py +0 -0
  397. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_source_escapes.py +0 -0
  398. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_sources.py +0 -0
  399. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_strict_child_placement.py +0 -0
  400. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_super_resolve.py +0 -0
  401. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_template_toolcall.py +0 -0
  402. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  403. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_validation_attr_schema.py +0 -0
  404. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_validation_filter_values.py +0 -0
  405. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_validation_origin_195.py +0 -0
  406. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_validation_origin_paths.py +0 -0
  407. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_validation_sort_field.py +0 -0
  408. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_validation_warnings.py +0 -0
  409. {metaobjects-0.23.0 → metaobjects-0.23.2}/tests/unit/test_write_coercion_arrays.py +0 -0
  410. {metaobjects-0.23.0 → metaobjects-0.23.2}/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.23.0
3
+ Version: 0.23.2
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.23.0"
3
+ version = "0.23.2"
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"
@@ -53,6 +53,11 @@ _OPS_STRING: tuple[str, ...] = ("eq", "ne", "in", "like", "isNull")
53
53
  # uuid: identity-comparison only — no `like` (not a substring type), no ordering.
54
54
  _OPS_UUID: tuple[str, ...] = ("eq", "ne", "in", "isNull")
55
55
  _OPS_NUMERIC: tuple[str, ...] = ("eq", "ne", "gt", "gte", "lt", "lte", "in", "isNull")
56
+ # int-backed enum (@intValueMap, design D5): the enum band minus `like` — the column
57
+ # is an integer, and a substring match against an integer is meaningless. Distinct
58
+ # constant from _OPS_UUID despite the identical members: they narrow for different
59
+ # reasons and would diverge independently.
60
+ _OPS_ENUM_INT_BACKED: tuple[str, ...] = ("eq", "ne", "in", "isNull")
56
61
  _OPS_BOOLEAN: tuple[str, ...] = ("eq", "isNull")
57
62
 
58
63
 
@@ -118,6 +123,36 @@ def ops_for_subtype_ordered(sub_type: str | None) -> tuple[str, ...]:
118
123
  return ()
119
124
 
120
125
 
126
+ def ops_for_field_ordered(field: MetaField) -> tuple[str, ...]:
127
+ """The operator tuple for a FIELD, in canonical operator order.
128
+
129
+ The ordered counterpart of ``validation_passes.ops_for_field``, and the entry
130
+ point for every consumer that has a field in hand: the codegen allowlist emit
131
+ and the cross-port ``field.filter-ops`` conformance capability.
132
+
133
+ Identical to :func:`ops_for_subtype_ordered` except for ONE case: an int-backed
134
+ ``field.enum`` (one declaring ``@intValueMap``, design D5) persists as an INTEGER
135
+ column, so ``like`` -- a substring match -- is dropped. ``eq``/``ne``/``in``
136
+ survive because the member symbol encodes to its integer before it reaches SQL;
137
+ ``like`` has no such encoding, and an unencoded ``LIKE 'DRAFT'`` against an integer
138
+ column is a request-time type error.
139
+
140
+ ADR-0039: the ``@intValueMap`` read is RESOLVING (``attrs()``, NOT ``attr()`` --
141
+ Python inverts the TS naming, ``attr()`` here is own-only). Post-#246 the map lives
142
+ on a shared root-level abstract declaration and consuming fields INHERIT it, so an
143
+ own-only read would see it absent on exactly the shape adopters are steered toward
144
+ and wrongly keep ``like``.
145
+
146
+ Cross-port: ``fixtures/conformance/filter-ops-matrix`` pins ``fEnum`` vs
147
+ ``fEnumInt`` in all five ports.
148
+ """
149
+ if field.sub_type == fc.FIELD_SUBTYPE_ENUM and isinstance(
150
+ field.attrs().get(fc.FIELD_ATTR_INT_VALUE_MAP), dict
151
+ ):
152
+ return _OPS_ENUM_INT_BACKED
153
+ return ops_for_subtype_ordered(field.sub_type)
154
+
155
+
121
156
  def _is_filterable(field: MetaField) -> bool:
122
157
  """True iff ``field`` carries ``@filterable: true`` as a metadata attribute.
123
158
 
@@ -166,10 +201,10 @@ class FilterAllowlistGenerator:
166
201
  name = "filter-allowlist-generator"
167
202
 
168
203
  def _ops_for_field(self, field: MetaField) -> tuple[str, ...]:
169
- """The operator tuple allowed for ``field`` (FR-009 §5 per-subtype matrix by
170
- default). Override to customize the per-field operator vocabulary; returning
171
- an empty tuple excludes the field from the allowlist."""
172
- return ops_for_subtype_ordered(field.sub_type)
204
+ """The operator tuple allowed for ``field`` (FR-009 §5 matrix by default).
205
+ Override to customize the per-field operator vocabulary; returning an empty
206
+ tuple excludes the field from the allowlist."""
207
+ return ops_for_field_ordered(field)
173
208
 
174
209
  def _compute_filterable_ops(
175
210
  self, entity: MetaObject, object_index: dict[str, MetaObject] | None = None
@@ -66,12 +66,21 @@ def resolve_shared_enum_decl(field: MetaField) -> MetaData | None:
66
66
 
67
67
 
68
68
  def is_provided(decl: MetaData) -> bool:
69
- """Effective ``@provided`` truth of an enum declaration.
70
-
71
- ADR-0039 resolves through ``extends`` (``get_meta_attr``): a concrete enum
72
- extending an abstract ``@provided`` enum inherits the flag, so an own-only read
73
- would misclassify it."""
74
- return decl.get_meta_attr(fc.FIELD_ATTR_PROVIDED) is True
69
+ """``@provided`` truth of an enum DECLARATION.
70
+
71
+ ADR-0039 sanctioned own (Python naming inversion: ``attr()`` is the OWN read,
72
+ ``get_meta_attr()`` resolves). ``@provided`` is a declaration-layer provenance
73
+ marker "THIS type is supplied by hand-written/third-party code", like
74
+ ``is_abstract`` and does not flow down an ``extends`` chain.
75
+
76
+ This is only ever called on the resolved declaration (see
77
+ ``shared_enum_for_field``), never on the consuming field, so own and resolving
78
+ agree for a plain ``field extends @provided decl``. They diverge on a CHAINED
79
+ declaration (root abstract ``B extends`` root abstract ``@provided A``): a
80
+ resolving read reports B provided and emits a reference to a hand-written ``B``
81
+ the adopter never declared, instead of materializing B. Matches the JVM ports.
82
+ """
83
+ return decl.attr(fc.FIELD_ATTR_PROVIDED) is True
75
84
 
76
85
 
77
86
  def _meta_package_of(decl: MetaData) -> str:
@@ -9,6 +9,7 @@ from .meta.core.attr.attr_constants import (
9
9
  ATTR_SUBTYPE_EXPRESSION,
10
10
  ATTR_SUBTYPE_FILTER,
11
11
  ATTR_SUBTYPE_INT,
12
+ ATTR_SUBTYPE_INT_MAP,
12
13
  ATTR_SUBTYPE_STRING,
13
14
  ATTR_SUBTYPES,
14
15
  )
@@ -19,6 +20,7 @@ from .meta.core.field.field_constants import (
19
20
  FIELD_ATTR_AUTO_SET,
20
21
  FIELD_ATTR_CURRENCY,
21
22
  FIELD_ATTR_DEFAULT,
23
+ FIELD_ATTR_INT_VALUE_MAP,
22
24
  FIELD_ATTR_PROVIDED,
23
25
  FIELD_ATTR_MAX_LENGTH,
24
26
  FIELD_ATTR_OBJECT_REF,
@@ -472,6 +474,17 @@ core_provider.add(
472
474
  value_type=ATTR_SUBTYPE_BOOLEAN,
473
475
  required=False,
474
476
  ),
477
+ # int-backed-enum-values plan — @intValueMap: optional per-member int
478
+ # values ({member: int}) switching this enum field's DB persistence
479
+ # from string+CHECK to integer+CHECK. Keys must exactly match @values;
480
+ # values must be unique integers (enforced in _validate_enum_values,
481
+ # Rule 4). Structural (core), like @values / @provided — not a
482
+ # TS-web-only / prompt-domain overlay.
483
+ AttrSchema(
484
+ name=FIELD_ATTR_INT_VALUE_MAP,
485
+ value_type=ATTR_SUBTYPE_INT_MAP,
486
+ required=False,
487
+ ),
475
488
  # FR-033 — the field.enum tolerant-extract overlays (@enumAlias / @enumDoc /
476
489
  # @coerceDefault / @normalize) are NO LONGER declared here; they are re-homed
477
490
  # to the prompt domain provider (`prompt_provider`, metaobjects-prompt) via
@@ -194,6 +194,12 @@ class ErrorCode(str, Enum):
194
194
  # own @values would be silently dropped in codegen. Remove the own @values
195
195
  # to inherit the shared set, or extend a concrete (non-shared) enum instead.
196
196
  ERR_ENUM_EXTENDS_VALUES_CONFLICT = "ERR_ENUM_EXTENDS_VALUES_CONFLICT"
197
+ # A field.enum carries @intValueMap together with isArray=true. Int-backing is
198
+ # a persistence-layer codec and no port implements it element-wise over an
199
+ # array column, so the combination would silently persist member SYMBOLS into
200
+ # an integer array. An array-of-enum stays string-backed: drop @intValueMap,
201
+ # or make the field scalar.
202
+ ERR_ENUM_INT_VALUE_MAP_ARRAY = "ERR_ENUM_INT_VALUE_MAP_ARRAY"
197
203
  ERR_UNKNOWN = "ERR_UNKNOWN"
198
204
 
199
205
 
@@ -23,6 +23,7 @@ from ..meta.core.field.field_constants import (
23
23
  ENUM_MEMBER_PATTERN,
24
24
  FIELD_ATTR_COERCE_DEFAULT,
25
25
  FIELD_ATTR_DEFAULT,
26
+ FIELD_ATTR_INT_VALUE_MAP,
26
27
  FIELD_ATTR_OBJECT_REF,
27
28
  FIELD_ATTR_REQUIRED,
28
29
  FIELD_ATTR_STORAGE,
@@ -60,6 +61,7 @@ from ..meta.persistence.source.source_constants import (
60
61
  SOURCE_ROLE_PRIMARY,
61
62
  )
62
63
  from ..meta.core.attr.attr_constants import (
64
+ ATTR_SUBTYPE_INT_MAP,
63
65
  ATTR_SUBTYPE_PROPERTIES,
64
66
  ATTR_SUBTYPE_STRINGARRAY,
65
67
  )
@@ -281,6 +283,26 @@ def _type_ok(value: object, value_type: str) -> bool:
281
283
  # fails here → ERR_BAD_ATTR_VALUE, matching TS + Java (fail-closed); an object
282
284
  # @expr then flows to the closed-grammar check in the origin pass.
283
285
  return isinstance(value, dict)
286
+ if value_type == ATTR_SUBTYPE_INT_MAP:
287
+ # attr.intMap (int-backed-enum-values plan): an object whose every member
288
+ # value is an integer (e.g. field.enum's @intValueMap). This port has no
289
+ # per-attr-class validateValue dispatch (that's TS's architecture); the
290
+ # generic shape check lives here, mirroring C#'s ValueMatchesType
291
+ # ATTR_SUBTYPE_INT_MAP case. field.enum's own key-set/uniqueness content
292
+ # rules run separately in _validate_enum_values (Rule 4), which skips
293
+ # re-reporting a non-integer member already caught here.
294
+ #
295
+ # Final-review fix: also bound every value to the 32-bit signed int range
296
+ # (inclusive) — the eventual DB column for an int-backed enum is a 32-bit
297
+ # Postgres/SQLite `integer` (design doc D5), matching Java's
298
+ # IntMapAttribute#setValueAsString bound check exactly. Python ints have
299
+ # no fixed width, so this is the only place that boundary is enforced.
300
+ return isinstance(value, dict) and all(
301
+ isinstance(v, int)
302
+ and not isinstance(v, bool)
303
+ and -2147483648 <= v <= 2147483647
304
+ for v in value.values()
305
+ )
284
306
  # Unknown value types (e.g. "class") — allow anything.
285
307
  return True
286
308
 
@@ -544,6 +566,32 @@ def _validate_attr_schema(
544
566
  _ENUM_MEMBER_RE = re.compile(ENUM_MEMBER_PATTERN)
545
567
 
546
568
 
569
+ def _shared_enum_super(node: MetaData) -> MetaData | None:
570
+ """The shared-enum super of ``node``, or ``None`` when it has none.
571
+
572
+ "Shared" (FR-019 / #246) means the immediate super is abstract AND declared at
573
+ metadata-root — its parent is the ``metadata.root`` node, not an object. Such a
574
+ declaration is materialized ONCE per port as a single named type, so anything a
575
+ consuming field re-declares that belongs to the shared TYPE's contract (its
576
+ ``@values`` member set, or the ``@intValueMap`` integer backing of that set) is a
577
+ conflict. A concrete super, or a non-root abstract super (e.g. one nested inside
578
+ an object), is legal and not flagged.
579
+
580
+ Immediate-super-only, matching codegen's ``resolve_shared_enum_decl``
581
+ (``codegen/generators/fr019_shared_enum.py``) so the validator and the
582
+ shared-enum collapse agree on what "shared" means.
583
+ """
584
+ sup = node.super_data
585
+ if (
586
+ sup is not None
587
+ and sup.is_abstract
588
+ and sup.parent is not None
589
+ and sup.parent.type == TYPE_METADATA
590
+ ):
591
+ return sup
592
+ return None
593
+
594
+
547
595
  def _validate_enum_values(
548
596
  root: MetaData,
549
597
  errors: list[MetaError],
@@ -556,6 +604,21 @@ def _validate_enum_values(
556
604
  # @coerceDefault / @default / @normalize while inheriting @values).
557
605
  _validate_enum_fr011_attrs(node, errors)
558
606
 
607
+ # Rule 4 (@intValueMap content rules) is independent of whether @values is
608
+ # own or inherited on THIS node — it must run whenever this node owns
609
+ # @intValueMap, using the EFFECTIVE @values (own-or-inherited) as the
610
+ # membership set. Mirrors TS/C#/Java, which all check this unconditionally
611
+ # (Java's `validateEnumIntValueMap` is a standalone call at the top of
612
+ # `validateEnumNode`). Deliberately called BEFORE the `own_values is None:
613
+ # continue` gate below so a concrete field.enum that inherits @values via
614
+ # `extends` but declares its own @intValueMap is still validated.
615
+ _validate_enum_int_value_map(node, errors)
616
+
617
+ # Design D7, narrowed: int-backing is scalar-only. Separate from the content
618
+ # rules above because it must fire on the node that combines the two halves,
619
+ # which is NOT necessarily the node that declares the map.
620
+ _validate_enum_int_value_map_not_array(node, errors)
621
+
559
622
  # ADR-0039 sanctioned own: validates the AUTHORED @values membership on THIS
560
623
  # node (mirrors the TS attr-schema-validate `node.ownAttrs()`); an inherited
561
624
  # @values yields None here and is validated on its declaring node.
@@ -607,19 +670,9 @@ def _validate_enum_values(
607
670
 
608
671
  # #246: own @values AND extends a shared package-level abstract enum —
609
672
  # one shared enum type has one member set, so the own @values would be
610
- # silently dropped by the shared-enum codegen collapse. "Shared" means
611
- # the resolved super is abstract AND declared at metadata-root (its
612
- # parent is the metadata.root node, not nested inside an object) — a
613
- # concrete super, or a non-root abstract super (e.g. nested inside an
614
- # object), is legal and not flagged. Mirrors the TS reference
615
- # (attr-schema-validate.ts).
616
- sup = node.super_data
617
- if (
618
- sup is not None
619
- and sup.is_abstract
620
- and sup.parent is not None
621
- and sup.parent.type == TYPE_METADATA
622
- ):
673
+ # silently dropped by the shared-enum codegen collapse. Mirrors the TS
674
+ # reference (attr-schema-validate.ts).
675
+ if _shared_enum_super(node) is not None:
623
676
  errors.append(
624
677
  MetaError(
625
678
  f"{label} declares its own '@{FIELD_ATTR_VALUES}' but extends "
@@ -633,6 +686,113 @@ def _validate_enum_values(
633
686
  )
634
687
 
635
688
 
689
+ def _validate_enum_int_value_map_not_array(node: MetaData, errors: list[MetaError]) -> None:
690
+ """``@intValueMap`` is scalar-only (design D7, narrowed).
691
+
692
+ Int-backing is a persistence-layer CODEC, and no port implements it
693
+ element-wise over an array column: this port's ``ObjectManager`` would bind the
694
+ symbol LIST straight into an ``integer[]``, OMDB's ``EnumCodec`` and Kotlin's
695
+ ``customEnumeration`` are scalar by construction, and TypeScript's sqlite branch
696
+ serializes an array as JSON text before the enum case is reached. Two ports that
697
+ happen to compose (TS/Postgres, C#) are not a feature — shipping a claim four
698
+ ports silently get wrong is the ``field.byte``/``short``/``class`` mistake.
699
+
700
+ BOTH halves are read RESOLVING, unlike the content rules: the illegal thing is
701
+ the EFFECTIVE combination. Post-#246 the map must live on the shared abstract
702
+ declaration, so the field that inherits it is exactly where ``isArray`` gets
703
+ declared — an own-only read would see the two halves on different nodes and
704
+ never fire.
705
+ """
706
+ if not isinstance(node.get_meta_attr(FIELD_ATTR_INT_VALUE_MAP), dict):
707
+ return
708
+ if not node.resolved_is_array():
709
+ return
710
+ errors.append(
711
+ MetaError(
712
+ f"{_node_label(node)} declares '@{FIELD_ATTR_INT_VALUE_MAP}' with isArray=true; "
713
+ f"int-backing is scalar-only — an array-of-enum persists its member symbols. "
714
+ f"Remove '@{FIELD_ATTR_INT_VALUE_MAP}', or make the field scalar.",
715
+ ErrorCode.ERR_ENUM_INT_VALUE_MAP_ARRAY,
716
+ envelope=node.source,
717
+ )
718
+ )
719
+
720
+
721
+ def _validate_enum_int_value_map(node: MetaData, errors: list[MetaError]) -> None:
722
+ """``@intValueMap`` content rules (optional), independent of whether ``@values``
723
+ is own or inherited on this node. Mirrors TS/C#/Java, which all run this check
724
+ unconditionally against the node's EFFECTIVE ``@values`` — a concrete
725
+ ``field.enum`` that inherits ``@values`` via ``extends`` but declares its own
726
+ ``@intValueMap`` locally must still have that map validated.
727
+
728
+ a. Key set must exactly match the EFFECTIVE ``@values`` (own or inherited).
729
+ b. No two members may share the same int (protobuf's stance — no alias
730
+ opt-in). Every-value-is-an-integer is already enforced by ``_type_ok``'s
731
+ ATTR_SUBTYPE_INT_MAP case at parse time.
732
+ """
733
+ int_value_map = node.attr(FIELD_ATTR_INT_VALUE_MAP)
734
+ if not isinstance(int_value_map, dict):
735
+ return
736
+
737
+ label = _node_label(node)
738
+
739
+ # #246 (int-backed twin): the symbol->int mapping is a property of the enum
740
+ # VOCABULARY, not of one column that uses it -- it is @values' numeric half. A
741
+ # shared enum is materialized once as a single type, so a per-field map would
742
+ # give one logical type N storage encodings (and, where a port emits per-TYPE
743
+ # codec artifacts, two same-named declarations). Same remedy as the @values
744
+ # half: declare it on the shared declaration and inherit it.
745
+ shared_super = _shared_enum_super(node)
746
+ if shared_super is not None:
747
+ errors.append(
748
+ MetaError(
749
+ f"{label} declares its own '@{FIELD_ATTR_INT_VALUE_MAP}' but extends "
750
+ f"a shared package-level abstract enum — a shared enum's integer "
751
+ f"backing is owned by the shared declaration. Move "
752
+ f"'@{FIELD_ATTR_INT_VALUE_MAP}' onto the shared declaration to "
753
+ f"inherit it, or extend a concrete (non-shared) enum instead",
754
+ ErrorCode.ERR_ENUM_EXTENDS_VALUES_CONFLICT,
755
+ envelope=node.source,
756
+ )
757
+ )
758
+ effective_values = _effective_enum_values(node)
759
+ member_set = set(effective_values)
760
+ key_set = set(int_value_map.keys())
761
+ missing = [m for m in effective_values if m not in key_set]
762
+ extra = [k for k in int_value_map if k not in member_set]
763
+ if missing or extra:
764
+ parts = []
765
+ if missing:
766
+ parts.append(f"missing: {', '.join(missing)}")
767
+ if extra:
768
+ parts.append(f"unknown: {', '.join(extra)}")
769
+ errors.append(
770
+ MetaError(
771
+ f"{label} attribute '@{FIELD_ATTR_INT_VALUE_MAP}' keys must exactly match "
772
+ f"'@{FIELD_ATTR_VALUES}' members ({'; '.join(parts)}).",
773
+ ErrorCode.ERR_BAD_ATTR_VALUE,
774
+ envelope=node.source,
775
+ )
776
+ )
777
+
778
+ seen_values: dict[int, str] = {}
779
+ for member, value in int_value_map.items():
780
+ if not isinstance(value, int) or isinstance(value, bool):
781
+ continue # _type_ok already reported this
782
+ owner = seen_values.get(value)
783
+ if owner is not None:
784
+ errors.append(
785
+ MetaError(
786
+ f"{label} attribute '@{FIELD_ATTR_INT_VALUE_MAP}' members {owner!r} and {member!r} "
787
+ f"share the same value {value}; every member must have a unique int.",
788
+ ErrorCode.ERR_BAD_ATTR_VALUE,
789
+ envelope=node.source,
790
+ )
791
+ )
792
+ else:
793
+ seen_values[value] = member
794
+
795
+
636
796
  def _effective_enum_values(node: MetaData) -> list[str]:
637
797
  """The effective ``@values`` members of an enum node (own or inherited via
638
798
  ``extends:``). Empty list when absent. Mirrors Java ``effectiveEnumValues``."""
@@ -913,6 +1073,45 @@ def ops_for_subtype(field_subtype: str) -> frozenset[str]:
913
1073
  return frozenset()
914
1074
 
915
1075
 
1076
+ # The int-backed-enum band: the enum band minus `like`. Named so the narrowing is
1077
+ # one constant rather than a set rebuilt at every call.
1078
+ _OPS_ENUM_INT_BACKED: frozenset[str] = frozenset({"eq", "ne", "in", "isNull"})
1079
+
1080
+
1081
+ def ops_for_field(field: MetaData) -> frozenset[str]:
1082
+ """The filter-operator band for a FIELD.
1083
+
1084
+ The entry point every consumer that has a field in hand must use (loader
1085
+ validation, the codegen filter-allowlist generator, the cross-port
1086
+ ``field.filter-ops`` capability).
1087
+
1088
+ Identical to :func:`ops_for_subtype` except for ONE case: an int-backed
1089
+ ``field.enum`` (one declaring ``@intValueMap``, design D5) persists as an
1090
+ INTEGER column, so ``like`` -- a substring match -- is dropped.
1091
+ ``eq``/``ne``/``in`` survive because the member symbol encodes to its integer
1092
+ before it reaches SQL; ``like`` has no such encoding, and an unencoded
1093
+ ``LIKE 'DRAFT'`` against an integer column is a request-time type error.
1094
+
1095
+ ``ops_for_subtype`` cannot express this -- it only ever sees the subtype
1096
+ ``"enum"`` -- and is deliberately left unchanged for the one caller that
1097
+ genuinely has no field: the expression grammar's declared operand type.
1098
+
1099
+ ADR-0039: the ``@intValueMap`` read is RESOLVING (``attrs()``, NOT ``attr()``
1100
+ -- Python inverts the TS naming, ``attr()`` here is own-only). Post-#246 the
1101
+ map lives on a shared root-level abstract declaration and consuming fields
1102
+ INHERIT it, so an own-only read would see it absent on exactly the shape
1103
+ adopters are steered toward and wrongly keep ``like``.
1104
+
1105
+ Cross-port: ``fixtures/conformance/filter-ops-matrix`` pins ``fEnum`` vs
1106
+ ``fEnumInt`` in all five ports.
1107
+ """
1108
+ if field.sub_type == FIELD_SUBTYPE_ENUM and isinstance(
1109
+ field.attrs().get(FIELD_ATTR_INT_VALUE_MAP), dict
1110
+ ):
1111
+ return _OPS_ENUM_INT_BACKED
1112
+ return ops_for_subtype(field.sub_type)
1113
+
1114
+
916
1115
  # ---------------------------------------------------------------------------
917
1116
  # #195 — attr.expression closed grammar (validate + infer)
918
1117
  # ---------------------------------------------------------------------------
@@ -1095,8 +1294,10 @@ def _validate_datagrid_filter_values(
1095
1294
  continue
1096
1295
 
1097
1296
  # Build filterable map: field_name → allowed ops set
1297
+ # ops_for_field, not ops_for_subtype — an int-backed field.enum
1298
+ # (@intValueMap) stores as an integer, so `like` is not in its band.
1098
1299
  filterable: dict[str, frozenset[str]] = {
1099
- f.name: ops_for_subtype(f.sub_type)
1300
+ f.name: ops_for_field(f)
1100
1301
  for f in node.fields()
1101
1302
  if f.attrs().get("filterable") is True
1102
1303
  }
@@ -14,6 +14,13 @@ ATTR_SUBTYPE_CLASS = "class"
14
14
  # ATTR_SUBTYPE_EXPRESSION / meta-attr-expression.ts.
15
15
  ATTR_SUBTYPE_EXPRESSION = "expression"
16
16
 
17
+ # attr.intMap (int-backed-enum-values plan) — an object-shaped attribute whose
18
+ # values are all integers (e.g. field.enum's @intValueMap: {memberSymbol: int}).
19
+ # Generic shape check only; field.enum layers its own semantic rules (key-set
20
+ # membership, uniqueness) in its own content-rule validation pass. Mirrors TS
21
+ # ATTR_SUBTYPE_INT_MAP / C# AttrConstants.ATTR_SUBTYPE_INT_MAP.
22
+ ATTR_SUBTYPE_INT_MAP = "intMap"
23
+
17
24
  # The retired "stringarray" array attr subtype. It is NO LONGER a registered
18
25
  # (attr, sub_type) (not in ATTR_SUBTYPES) — array-ness is modeled as a "string"
19
26
  # attr with the orthogonal AttrSchema.is_array flag (matching Java's
@@ -33,4 +40,5 @@ ATTR_SUBTYPES = (
33
40
  ATTR_SUBTYPE_PROPERTIES,
34
41
  ATTR_SUBTYPE_CLASS,
35
42
  ATTR_SUBTYPE_EXPRESSION,
43
+ ATTR_SUBTYPE_INT_MAP,
36
44
  )
@@ -12,6 +12,7 @@ from .attr_constants import (
12
12
  ATTR_SUBTYPE_EXPRESSION,
13
13
  ATTR_SUBTYPE_FILTER,
14
14
  ATTR_SUBTYPE_INT,
15
+ ATTR_SUBTYPE_INT_MAP,
15
16
  ATTR_SUBTYPE_LONG,
16
17
  ATTR_SUBTYPE_PROPERTIES,
17
18
  ATTR_SUBTYPE_STRING,
@@ -134,6 +135,21 @@ class PropertiesAttr(MetaAttr):
134
135
  return DataType.OBJECT
135
136
 
136
137
 
138
+ class IntMapAttr(MetaAttr):
139
+ """attr.intMap (int-backed-enum-values plan) — an object-shaped attribute
140
+ whose values are all integers (e.g. field.enum's @intValueMap). Generic
141
+ shape check only; the deeper "every value is an int" check is enforced by
142
+ `_type_ok`'s ATTR_SUBTYPE_INT_MAP case in validation_passes.py (this port
143
+ has no per-attr-class validate_value dispatch — TS's is the one port that
144
+ does; C# mirrors the same "static type-check function" architecture this
145
+ port uses). field.enum's own key-set/uniqueness content rules run in a
146
+ separate pass. Mirrors TS IntMapAttr / C# ATTR_SUBTYPE_INT_MAP shape."""
147
+
148
+ @property
149
+ def data_type(self) -> DataType:
150
+ return DataType.OBJECT
151
+
152
+
137
153
  class ClassAttr(MetaAttr):
138
154
  @property
139
155
  def data_type(self) -> DataType:
@@ -145,4 +161,5 @@ register_attr_class(ATTR_SUBTYPE_STRINGARRAY, StringArrayAttr)
145
161
  register_attr_class(ATTR_SUBTYPE_FILTER, FilterAttr)
146
162
  register_attr_class(ATTR_SUBTYPE_PROPERTIES, PropertiesAttr)
147
163
  register_attr_class(ATTR_SUBTYPE_EXPRESSION, ExpressionAttr)
164
+ register_attr_class(ATTR_SUBTYPE_INT_MAP, IntMapAttr)
148
165
  register_attr_class(ATTR_SUBTYPE_CLASS, ClassAttr)
@@ -150,3 +150,10 @@ SORT_ORDER_VALUES = (SORT_ORDER_ASC, SORT_ORDER_DESC)
150
150
  # Regex pattern for enum member symbols — must be identifier-safe.
151
151
  # Cross-language contract: every port enforces this pattern.
152
152
  ENUM_MEMBER_PATTERN = r"^[A-Za-z_][A-Za-z0-9_]*$"
153
+
154
+ # int-backed-enum-values plan — @intValueMap (field.enum only): optional
155
+ # per-member int values ({member: int}) switching this enum field's DB
156
+ # persistence from string+CHECK to integer+CHECK. Keys must exactly match
157
+ # @values; values must be unique integers. The generated native type and wire
158
+ # format are unchanged in every language. Mirrors TS FIELD_ATTR_INT_VALUE_MAP.
159
+ FIELD_ATTR_INT_VALUE_MAP = "intValueMap"
@@ -54,7 +54,8 @@ class MetaRequirement(MetaData):
54
54
  return [str(x) for x in v] if isinstance(v, list) else []
55
55
 
56
56
  def verified_by(self) -> list[str]:
57
- """ADR-0039: resolving. Names of the tests proving the behaviour."""
57
+ """ADR-0039: resolving. Names of tests that ASSERT the behaviour — existence
58
+ evidence only; verify cannot tell whether a named test verifies this."""
58
59
  v = self.get_meta_attr(REQUIREMENT_ATTR_VERIFIED_BY)
59
60
  return [str(x) for x in v] if isinstance(v, list) else []
60
61
 
@@ -0,0 +1,134 @@
1
+ """Derived boolean accessors — ``{{#hasFoo}}`` over a payload field ``foo``.
2
+
3
+ A prompt needs conditional sections ("include the abilities block only when there ARE
4
+ abilities"), and the payload contract answers that with a DERIVED accessor rather than an
5
+ authored boolean field: the author declares ``abilities`` and ``hasAbilities`` follows
6
+ from it. Declaring both would let them disagree.
7
+
8
+ THE RULE IS SHARED ACROSS PORTS ON PURPOSE. The JVM has carried it since 7.7.7
9
+ (``com.metaobjects.render.PayloadAccessors``, emitted onto every generated payload record
10
+ and accepted by its ``Verify``), and its comment says the emitter and the verifier share
11
+ one rule so they "can never drift apart". Python had neither half, so the same template
12
+ verified clean on the JVM and reported drift here — and rendered WRONG rather than
13
+ failing, silently dropping the section. Gated cross-port by the
14
+ ``render-derived-has-accessor`` conformance case.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import numbers
20
+ from collections.abc import Mapping, Sequence
21
+ from typing import Any
22
+
23
+ __all__ = [
24
+ "HAS_PREFIX",
25
+ "has_accessor_name",
26
+ "capitalize",
27
+ "accessor_value",
28
+ "with_derived_accessors",
29
+ "is_boolean_accessor",
30
+ ]
31
+
32
+ #: The ``has`` prefix every derived boolean accessor carries.
33
+ HAS_PREFIX = "has"
34
+
35
+ _MAX_DEPTH = 32
36
+
37
+
38
+ def capitalize(s: str) -> str:
39
+ """Capitalize the first character, leaving an already-uppercase one untouched.
40
+
41
+ Deliberately NOT ``str.capitalize()``, which also lowercases the remainder.
42
+ """
43
+ if not s:
44
+ return s
45
+ if s[0].isupper():
46
+ return s
47
+ return s[0].upper() + s[1:]
48
+
49
+
50
+ def has_accessor_name(field_name: str) -> str:
51
+ """``"has" + capitalize(name)`` (``abilities`` → ``hasAbilities``).
52
+
53
+ Byte-identical to the JVM's ``PayloadAccessors.hasAccessorName``.
54
+ """
55
+ return HAS_PREFIX + capitalize(field_name)
56
+
57
+
58
+ def accessor_value(value: Any) -> bool | None:
59
+ """Is ``value`` "present" for the purposes of ``has<Field>``?
60
+
61
+ Mirrors the JVM emitter's per-type bodies exactly: string → non-null and non-blank;
62
+ collection → non-null and non-empty; reference → non-null.
63
+
64
+ Returns ``None`` for numbers and booleans, which the JVM deliberately emits NO
65
+ accessor for — they are always-present scalars, and ``{{#hasCount}}`` over an int is
66
+ drift rather than a conditional. Returning ``None`` (rather than ``False``) keeps that
67
+ distinction: nothing is injected, so the name stays unresolved exactly as it is on a
68
+ generated record with no such method.
69
+ """
70
+ if value is None:
71
+ return False
72
+ if isinstance(value, str):
73
+ return bool(value.strip())
74
+ # bool before int — bool IS an int in Python, and a boolean field gets no accessor.
75
+ if isinstance(value, numbers.Number):
76
+ return None
77
+ if isinstance(value, Mapping):
78
+ return True
79
+ if isinstance(value, (Sequence, set, frozenset)):
80
+ return len(value) > 0
81
+ return True
82
+
83
+
84
+ def with_derived_accessors(payload: Any, depth: int = 0) -> Any:
85
+ """A view over ``payload`` carrying its derived ``has<Field>`` accessors, recursively.
86
+
87
+ NON-MUTATING — the caller's payload is never touched, because a render must not be
88
+ able to change the object it was handed. An AUTHORED key always wins: if a payload
89
+ genuinely carries ``hasFoo``, that value is kept rather than shadowed.
90
+
91
+ Recursion follows Mustache's own scoping: every nested mapping and every sequence
92
+ ELEMENT becomes a context in its own right, so a section over ``abilities`` sees the
93
+ accessors of the ability it is currently iterating.
94
+ """
95
+ if depth > _MAX_DEPTH:
96
+ return payload # pathological graph; render is not a validator
97
+ if isinstance(payload, Mapping):
98
+ out: dict[str, Any] = {
99
+ k: with_derived_accessors(v, depth + 1) for k, v in payload.items()
100
+ }
101
+ for k, v in payload.items():
102
+ if not isinstance(k, str):
103
+ continue
104
+ name = has_accessor_name(k)
105
+ if name in payload: # authored wins
106
+ continue
107
+ derived = accessor_value(v)
108
+ if derived is not None:
109
+ out[name] = derived
110
+ return out
111
+ if isinstance(payload, (str, bytes)):
112
+ return payload
113
+ if isinstance(payload, Sequence):
114
+ return [with_derived_accessors(v, depth + 1) for v in payload]
115
+ return payload
116
+
117
+
118
+ def is_boolean_accessor(stack: list[list[Any]], name: str) -> bool:
119
+ """True when ``name`` is a derived accessor over a field reachable on ``stack``.
120
+
121
+ Mirrors the JVM's ``Verify.isBooleanAccessor``, including its deliberate
122
+ permissiveness: acceptance keys off the FIELD EXISTING, not off its type. Accessors
123
+ are simple (undotted) names; a dotted path is never an accessor.
124
+ """
125
+ if "." in name:
126
+ return False
127
+ if not name.startswith(HAS_PREFIX):
128
+ return False
129
+ # Mustache outward walk (innermost → outermost).
130
+ for frame in reversed(stack):
131
+ for f in frame:
132
+ if name == has_accessor_name(f.name):
133
+ return True
134
+ return False