metaobjects 1.0.9rc5__tar.gz → 1.0.10__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 (479) hide show
  1. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/PKG-INFO +1 -1
  2. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/pyproject.toml +1 -1
  3. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/cli.py +76 -10
  4. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +10 -2
  5. metaobjects-1.0.10/src/metaobjects/codegen/instance_artifacts.py +43 -0
  6. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/object_extract.py +25 -0
  7. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/extract.py +15 -1
  8. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/json_forgiving_reader.py +39 -3
  9. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/locate.py +14 -2
  10. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/types.py +13 -0
  11. metaobjects-1.0.10/tests/codegen/test_cli_gen_unknown_attr.py +70 -0
  12. metaobjects-1.0.10/tests/codegen/test_sourceless_entity_surface.py +74 -0
  13. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_extract_conformance.py +16 -1
  14. metaobjects-1.0.10/tests/conformance/test_extract_object_array_bounds.py +58 -0
  15. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/uv.lock +1 -1
  16. metaobjects-1.0.9rc5/src/metaobjects/codegen/instance_artifacts.py +0 -18
  17. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/.gitignore +0 -0
  18. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/LICENSE +0 -0
  19. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/README.md +0 -0
  20. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/hatch_build.py +0 -0
  21. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/scripts/generate_embedded_library.py +0 -0
  22. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/__init__.py +0 -0
  23. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/agent_context/__init__.py +0 -0
  24. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/agent_context/scaffold.py +0 -0
  25. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/apidocs/__init__.py +0 -0
  26. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/apidocs/api_model.py +0 -0
  27. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/apidocs/builder.py +0 -0
  28. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/apidocs/naming.py +0 -0
  29. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/apidocs/paths.py +0 -0
  30. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/apidocs/renderer.py +0 -0
  31. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/attr_class_map.py +0 -0
  32. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  33. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/__init__.py +0 -0
  34. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/collision_names.py +0 -0
  35. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/config.py +0 -0
  36. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/constants.py +0 -0
  37. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/eject.py +0 -0
  38. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  39. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  40. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/format.py +0 -0
  41. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  42. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generator.py +0 -0
  43. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generator_registry.py +0 -0
  44. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/__init__.py +0 -0
  45. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  46. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  47. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
  48. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  49. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  50. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/names_generator.py +0 -0
  51. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  52. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  53. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  54. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  55. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  56. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  57. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  58. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
  59. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/model_walk.py +0 -0
  60. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  61. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  62. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/project_config.py +0 -0
  63. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/runner.py +0 -0
  64. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  65. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
  66. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  67. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  68. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  69. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  70. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  71. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/type_map.py +0 -0
  72. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/codegen/value_objects.py +0 -0
  73. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/config/__init__.py +0 -0
  74. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/config/dependencies.py +0 -0
  75. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/config/neutral_config.py +0 -0
  76. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/config/source_resolver.py +0 -0
  77. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/core_types.py +0 -0
  78. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/datatype.py +0 -0
  79. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/documentation/__init__.py +0 -0
  80. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/documentation/doc_constants.py +0 -0
  81. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/documentation/doc_provider.py +0 -0
  82. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/documentation/doc_schema.py +0 -0
  83. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/errors.py +0 -0
  84. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/library/__init__.py +0 -0
  85. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/library/embedded_library.py +0 -0
  86. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/library/library_sources.py +0 -0
  87. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/__init__.py +0 -0
  88. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/merge.py +0 -0
  89. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/meta_data_loader.py +0 -0
  90. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/registered_validation.py +0 -0
  91. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/sources/__init__.py +0 -0
  92. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/sources/directory_source.py +0 -0
  93. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/sources/file_source.py +0 -0
  94. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  95. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/sources/uri_source.py +0 -0
  96. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validate_discriminator.py +0 -0
  97. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  98. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validate_field_mutability.py +0 -0
  99. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  100. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  101. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  102. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/loader/validation_passes.py +0 -0
  103. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/__init__.py +0 -0
  104. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/__init__.py +0 -0
  105. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  106. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  107. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  108. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/field/__init__.py +0 -0
  109. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  110. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  111. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  112. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  113. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  114. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/index/__init__.py +0 -0
  115. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  116. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  117. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/__init__.py +0 -0
  118. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  119. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  120. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  121. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  122. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/object/value_object.py +0 -0
  123. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  124. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  125. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  126. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  127. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
  128. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  129. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
  130. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  131. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  132. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  133. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/meta_data.py +0 -0
  134. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/meta_root.py +0 -0
  135. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/__init__.py +0 -0
  136. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  137. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  138. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  139. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  140. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  141. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  142. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  143. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  144. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  145. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/__init__.py +0 -0
  146. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  147. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  148. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  149. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  150. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  151. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  152. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  153. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  154. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/provider_extends.py +0 -0
  155. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/template/__init__.py +0 -0
  156. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/template/meta_template.py +0 -0
  157. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  158. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta/template/template_constants.py +0 -0
  159. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/meta_endpoint.py +0 -0
  160. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/naming.py +0 -0
  161. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/naming_refs.py +0 -0
  162. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/parser.py +0 -0
  163. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/parser_yaml.py +0 -0
  164. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/provider.py +0 -0
  165. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/py.typed +0 -0
  166. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/registry.py +0 -0
  167. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/registry_manifest.py +0 -0
  168. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/__init__.py +0 -0
  169. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/email_document.py +0 -0
  170. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/escapers.py +0 -0
  171. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  172. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/__init__.py +0 -0
  173. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/coerce.py +0 -0
  174. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/extract_map.py +0 -0
  175. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/normalize.py +0 -0
  176. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/strip.py +0 -0
  177. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  178. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/filesystem_provider.py +0 -0
  179. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/payload_accessors.py +0 -0
  180. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/prompt/__init__.py +0 -0
  181. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  182. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  183. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  184. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  185. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  186. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/renderer.py +0 -0
  187. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/render/verify.py +0 -0
  188. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/runtime/__init__.py +0 -0
  189. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/runtime/llm_recorder.py +0 -0
  190. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  191. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/runtime/object_manager.py +0 -0
  192. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/runtime/tph.py +0 -0
  193. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/scope.py +0 -0
  194. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/serializer_json.py +0 -0
  195. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/shared/__init__.py +0 -0
  196. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/shared/base_types.py +0 -0
  197. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/shared/separators.py +0 -0
  198. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/shared/structural.py +0 -0
  199. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/source/__init__.py +0 -0
  200. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/source/error_source.py +0 -0
  201. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/source/json_path.py +0 -0
  202. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/source/semantic_diff.py +0 -0
  203. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/source/yaml_positions.py +0 -0
  204. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/source_resolution.py +0 -0
  205. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  206. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/attr.json +0 -0
  207. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/db.json +0 -0
  208. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  209. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/field.json +0 -0
  210. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/identity.json +0 -0
  211. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/index.json +0 -0
  212. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/layout.json +0 -0
  213. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/object.json +0 -0
  214. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/origin.json +0 -0
  215. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  216. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  217. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/requirement.json +0 -0
  218. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/source.json +0 -0
  219. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/template.json +0 -0
  220. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  221. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/ui.json +0 -0
  222. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/validator.json +0 -0
  223. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/spec_metamodel/view.json +0 -0
  224. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/super_resolve.py +0 -0
  225. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/validation_types.py +0 -0
  226. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/src/metaobjects/yaml_desugar.py +0 -0
  227. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/__init__.py +0 -0
  228. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/__init__.py +0 -0
  229. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/gen_suite.py +0 -0
  230. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  231. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/extends/expected/Program.py +0 -0
  232. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/extends/meta.json +0 -0
  233. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  234. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  235. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/nested-array/meta.json +0 -0
  236. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  237. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  238. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/scalars/meta.json +0 -0
  239. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  240. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/golden/vanilla/meta.json +0 -0
  241. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_abstract_conformance.py +0 -0
  242. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_api_docs_builder.py +0 -0
  243. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_api_docs_paths.py +0 -0
  244. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli.py +0 -0
  245. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_config_gen.py +0 -0
  246. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_config_verify.py +0 -0
  247. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_dependencies.py +0 -0
  248. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_providers.py +0 -0
  249. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_registry.py +0 -0
  250. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
  251. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  252. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_verify_strict.py +0 -0
  253. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  254. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_codegen_compile_conformance.py +0 -0
  255. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_constants_config.py +0 -0
  256. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_eject.py +0 -0
  257. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_eject_runtime.py +0 -0
  258. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_entity_model.py +0 -0
  259. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_enum_conformance.py +0 -0
  260. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  261. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_extract_tier_collision.py +0 -0
  262. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_extractor_generator.py +0 -0
  263. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  264. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_format.py +0 -0
  265. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  266. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_fr010_output_codegen.py +0 -0
  267. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  268. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_gen_state_keying.py +0 -0
  269. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_generator.py +0 -0
  270. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_generator_extension_seams.py +0 -0
  271. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_golden.py +0 -0
  272. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  273. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_inheritance_conformance.py +0 -0
  274. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_instance_artifacts.py +0 -0
  275. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_m2m_codegen.py +0 -0
  276. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_names_extends_chain.py +0 -0
  277. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_names_generator.py +0 -0
  278. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_no_magic_physical_names.py +0 -0
  279. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_origin_nullability.py +0 -0
  280. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_output_parser_generator.py +0 -0
  281. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_overwrite_policy.py +0 -0
  282. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_overwrite_policy_hash.py +0 -0
  283. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_project_config.py +0 -0
  284. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_projection_compile.py +0 -0
  285. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_recipe_generators.py +0 -0
  286. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_render_helper_conformance.py +0 -0
  287. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_render_helper_generator.py +0 -0
  288. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_reverse_finders.py +0 -0
  289. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_route_path_naming.py +0 -0
  290. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_router_autoset.py +0 -0
  291. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_router_generator.py +0 -0
  292. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
  293. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
  294. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
  295. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_runner.py +0 -0
  296. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_source_resolution.py +0 -0
  297. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_sourceless_projection.py +0 -0
  298. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_template_data.py +0 -0
  299. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_template_generator.py +0 -0
  300. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_template_output_pattern.py +0 -0
  301. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_template_scope_helpers.py +0 -0
  302. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_template_scope_walk.py +0 -0
  303. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_template_spec.py +0 -0
  304. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_tph_codegen.py +0 -0
  305. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_trace_helper_generator.py +0 -0
  306. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_type_map.py +0 -0
  307. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_validation_conformance.py +0 -0
  308. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_value_objects.py +0 -0
  309. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/codegen/test_write_through.py +0 -0
  310. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/config/__init__.py +0 -0
  311. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/config/test_dependencies.py +0 -0
  312. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/config/test_library_package_guard.py +0 -0
  313. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/config/test_neutral_config.py +0 -0
  314. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/config/test_source_resolver.py +0 -0
  315. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/__init__.py +0 -0
  316. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/capabilities.py +0 -0
  317. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/conformance-expected-failures.json +0 -0
  318. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/conformance_adapter.py +0 -0
  319. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/corpus.py +0 -0
  320. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/expected_failures.py +0 -0
  321. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/fixture_discovery.py +0 -0
  322. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/navigator.py +0 -0
  323. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  324. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_conformance.py +0 -0
  325. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_dependency_conformance.py +0 -0
  326. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_extract_object_verdict.py +0 -0
  327. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  328. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_fr011_attrs.py +0 -0
  329. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_generator_registry_conformance.py +0 -0
  330. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_object_model_conformance.py +0 -0
  331. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_provider_composition_conformance.py +0 -0
  332. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_registry_conformance.py +0 -0
  333. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_runner_hardfail.py +0 -0
  334. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_scope_conformance.py +0 -0
  335. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_source_resolution_conformance.py +0 -0
  336. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  337. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_strict_attr_load.py +0 -0
  338. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_template_codegen_conformance.py +0 -0
  339. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_template_generator_conformance.py +0 -0
  340. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/test_yaml_conformance.py +0 -0
  341. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  342. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/__init__.py +0 -0
  343. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/api_contract_assertions.py +0 -0
  344. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/api_contract_jsonb_server.py +0 -0
  345. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/api_contract_m2m_server.py +0 -0
  346. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/api_contract_server.py +0 -0
  347. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/generated_jsonb_app.py +0 -0
  348. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/generated_m2m_app.py +0 -0
  349. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/generated_projection_app.py +0 -0
  350. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/generated_router_app.py +0 -0
  351. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/generated_tph_app.py +0 -0
  352. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/meta_ai_trace.yaml +0 -0
  353. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/normalization.py +0 -0
  354. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/postgres_container.py +0 -0
  355. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/query_runner.py +0 -0
  356. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/scenarios.py +0 -0
  357. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract.py +0 -0
  358. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract_generated.py +0 -0
  359. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract_jsonb.py +0 -0
  360. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract_m2m.py +0 -0
  361. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  362. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract_projection.py +0 -0
  363. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_api_contract_tph_generated.py +0 -0
  364. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  365. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_llm_call_trace.py +0 -0
  366. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_m2m_target_tph_generated.py +0 -0
  367. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_normalization.py +0 -0
  368. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_query_scenarios.py +0 -0
  369. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_runtime_return_types.py +0 -0
  370. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_tph_m2m_generated.py +0 -0
  371. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
  372. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/__init__.py +0 -0
  373. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/test_abstract_subtype_authored.py +0 -0
  374. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/test_child_wrapper_body_shape.py +0 -0
  375. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  376. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/test_field_mutability_order.py +0 -0
  377. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/test_shipped_library_ai.py +0 -0
  378. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/loader/test_template_payload_target_210.py +0 -0
  379. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/open_closed_proof_test.py +0 -0
  380. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/__init__.py +0 -0
  381. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/__init__.py +0 -0
  382. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_coerce.py +0 -0
  383. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_extract.py +0 -0
  384. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_extract_map.py +0 -0
  385. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  386. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_locate.py +0 -0
  387. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_model.py +0 -0
  388. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_normalize.py +0 -0
  389. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_strip.py +0 -0
  390. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  391. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/prompt/__init__.py +0 -0
  392. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/prompt/test_output_format_renderer.py +0 -0
  393. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_email_document.py +0 -0
  394. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_filesystem_provider.py +0 -0
  395. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_output_format_renderer_nested.py +0 -0
  396. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_output_prompt_conformance.py +0 -0
  397. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_render_conformance.py +0 -0
  398. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_render_max_chars.py +0 -0
  399. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_render_model_payload.py +0 -0
  400. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_verify.py +0 -0
  401. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/render/test_verify_conformance.py +0 -0
  402. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/runtime/test_constraint_errors.py +0 -0
  403. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/runtime/test_object_manager_currency_read.py +0 -0
  404. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
  405. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/runtime/test_object_manager_table_name.py +0 -0
  406. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/__init__.py +0 -0
  407. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_fr5c_merge_attribution.py +0 -0
  408. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_fr5d_reference_resolution.py +0 -0
  409. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_fr5e_database_source_shape.py +0 -0
  410. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_json_path.py +0 -0
  411. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_semantic_diff.py +0 -0
  412. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_source_on_node.py +0 -0
  413. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/source/test_yaml_positions.py +0 -0
  414. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/test_api_docs_accuracy.py +0 -0
  415. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/test_meta_endpoint.py +0 -0
  416. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/__init__.py +0 -0
  417. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_agent_context_staleness.py +0 -0
  418. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_capabilities.py +0 -0
  419. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_column_naming_strategy.py +0 -0
  420. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_common_attrs.py +0 -0
  421. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_core_types.py +0 -0
  422. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
  423. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
  424. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_effective_package.py +0 -0
  425. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_errors.py +0 -0
  426. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_field_enum.py +0 -0
  427. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_field_enum_intvaluemap.py +0 -0
  428. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_field_map_validation.py +0 -0
  429. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  430. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_file_source_id.py +0 -0
  431. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  432. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_index_lookup.py +0 -0
  433. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_llm_recorder.py +0 -0
  434. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_loader.py +0 -0
  435. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_loader_bom.py +0 -0
  436. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_loader_class.py +0 -0
  437. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_merge.py +0 -0
  438. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_meta_attr.py +0 -0
  439. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_meta_data.py +0 -0
  440. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_meta_source.py +0 -0
  441. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_module_shortcuts.py +0 -0
  442. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_n2m_resolver.py +0 -0
  443. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  444. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_no_dead_config_fields.py +0 -0
  445. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  446. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  447. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_object_manager_write_through.py +0 -0
  448. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_one_primary_source.py +0 -0
  449. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_parser.py +0 -0
  450. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_parser_yaml.py +0 -0
  451. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_provider.py +0 -0
  452. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_provider_extension.py +0 -0
  453. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_registry.py +0 -0
  454. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_registry_completeness.py +0 -0
  455. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_registry_extend.py +0 -0
  456. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_registry_sealed.py +0 -0
  457. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_relationship_m2m_validation.py +0 -0
  458. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_relationship_references.py +0 -0
  459. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_relationship_referential_actions.py +0 -0
  460. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_resolution_key.py +0 -0
  461. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  462. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_serializer.py +0 -0
  463. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_serializer_shared_document.py +0 -0
  464. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_shared_constants.py +0 -0
  465. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_smoke.py +0 -0
  466. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_source_escapes.py +0 -0
  467. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_sources.py +0 -0
  468. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_strict_child_placement.py +0 -0
  469. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_super_resolve.py +0 -0
  470. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_template_toolcall.py +0 -0
  471. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  472. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_validation_attr_schema.py +0 -0
  473. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_validation_filter_values.py +0 -0
  474. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_validation_origin_195.py +0 -0
  475. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_validation_origin_paths.py +0 -0
  476. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_validation_sort_field.py +0 -0
  477. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_validation_warnings.py +0 -0
  478. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_write_coercion_arrays.py +0 -0
  479. {metaobjects-1.0.9rc5 → metaobjects-1.0.10}/tests/unit/test_yaml_desugar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: metaobjects
3
- Version: 1.0.9rc5
3
+ Version: 1.0.10
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 = "1.0.9rc5"
3
+ version = "1.0.10"
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"
@@ -57,7 +57,7 @@ from pathlib import Path
57
57
  from typing import Callable
58
58
 
59
59
  from metaobjects import MetaDataLoader
60
- from metaobjects.errors import ParseError
60
+ from metaobjects.errors import ErrorCode, MetaError, ParseError
61
61
  from metaobjects.config.dependencies import (
62
62
  Collection,
63
63
  imported_from,
@@ -276,9 +276,14 @@ def _load_root(
276
276
  strict: bool = False,
277
277
  providers: list[object] | None = None,
278
278
  libraries: list[str] | None = None,
279
+ unknown_attr_out: list[str] | None = None,
279
280
  ) -> tuple[MetaData | None, list[str]]:
280
281
  """Load metadata; return ``(root, error_messages)``. ``root`` is None on error.
281
282
 
283
+ ``unknown_attr_out`` — when given on a LENIENT load, a second strict load of the
284
+ same metadata is run and its ``ERR_UNKNOWN_ATTR`` findings are appended, formatted,
285
+ so ``gen`` can warn about what ``verify`` would reject instead of staying silent.
286
+
282
287
  ``strict`` (ADR-0023, #96) — when True, an undeclared own ``@attr`` →
283
288
  ``ERR_UNKNOWN_ATTR``. Defaults False so ``gen`` / ``docs`` keep the legacy
284
289
  open-attr load; only ``verify`` opts in (strict-by-default with a ``--lax``
@@ -312,20 +317,24 @@ def _load_root(
312
317
  return None, [f"{exc.code}: {exc}"]
313
318
  all_libraries = _merge_libraries(neutral.libraries if neutral is not None else None, libraries)
314
319
 
315
- try:
320
+ def load(strict_load: bool) -> LoadResult:
316
321
  if providers:
317
322
  from metaobjects.core_types import core_providers
318
323
 
319
- result = MetaDataLoader.from_directory(
324
+ return MetaDataLoader.from_directory(
320
325
  metadata_dir,
321
326
  providers=[*core_providers, *providers],
322
- strict=strict,
327
+ strict=strict_load,
323
328
  libraries=all_libraries,
324
329
  )
325
- else:
326
- result = MetaDataLoader.from_directory(
327
- metadata_dir, strict=strict, libraries=all_libraries
328
- )
330
+ return MetaDataLoader.from_directory(
331
+ metadata_dir, strict=strict_load, libraries=all_libraries
332
+ )
333
+
334
+ try:
335
+ result = load(strict)
336
+ if unknown_attr_out is not None and not strict and not result.errors:
337
+ unknown_attr_out.extend(_unknown_attr_findings(load(True)))
329
338
  except OSError as e:
330
339
  # `DirectorySource.expand()` walks via `iterdir()` (not `rglob()`, so it
331
340
  # can follow a symlinked subdirectory — the I1 fix) and raises a plain
@@ -416,6 +425,7 @@ def _load_root_from_collection(
416
425
  strict: bool = False,
417
426
  providers: list[object] | None = None,
418
427
  libraries: list[str] | None = None,
428
+ unknown_attr_out: list[str] | None = None,
419
429
  ) -> tuple[MetaData | None, list[str]]:
420
430
  """Load a resolved `Collection` — the source-resolution ladder's
421
431
  ``.metaobjects/config.json`` rung (:func:`resolve_metadata_location`), which
@@ -432,9 +442,58 @@ def _load_root_from_collection(
432
442
  if result.errors:
433
443
  msgs = [f"{e.code}: {e.message}" for e in result.errors]
434
444
  return None, msgs
445
+ if unknown_attr_out is not None and not strict:
446
+ # See `_load_root`: what a strict load (`verify`) would reject, for `gen` to warn.
447
+ try:
448
+ strict_result = _load_collection_result(
449
+ collection, strict=True, providers=providers, libraries=libraries
450
+ )
451
+ except ParseError:
452
+ strict_result = None
453
+ if strict_result is not None:
454
+ unknown_attr_out.extend(_unknown_attr_findings(strict_result))
435
455
  return result.root, []
436
456
 
437
457
 
458
+ #: Trailing advice after ``gen``'s unknown-attribute warnings. ``gen`` has no strict
459
+ #: flag of its own; ``verify`` is the strict door (ADR-0023), so that is what it names.
460
+ UNKNOWN_ATTR_GEN_ADVICE = (
461
+ "metaobjects gen loads leniently and generated anyway, but `metaobjects verify` "
462
+ "rejects this metadata (ADR-0023): fix or remove the attribute - a typo'd one "
463
+ "(`isAbstrakt`, `requird`) silently changes what is generated."
464
+ )
465
+
466
+
467
+ def _format_unknown_attr(err: MetaError) -> str:
468
+ """One ``gen`` warning: code + message (naming attribute and node), then the file."""
469
+ env = getattr(err, "envelope", None)
470
+ files = [f for f in (getattr(env, "files", None) or ()) if f]
471
+ json_path = getattr(env, "json_path", None)
472
+ where = " ".join(
473
+ p for p in (", ".join(files) if files else None, f"at {json_path}" if json_path else None) if p
474
+ )
475
+ head = f"{err.code.value if hasattr(err.code, 'value') else err.code}: {err.message}"
476
+ return f"{head}\n in {where}" if where else head
477
+
478
+
479
+ def _unknown_attr_findings(result: LoadResult) -> list[str]:
480
+ """The ERR_UNKNOWN_ATTR findings of a STRICT load, formatted for ``gen``."""
481
+ return [
482
+ _format_unknown_attr(e) for e in result.errors
483
+ if (e.code.value if hasattr(e.code, "value") else e.code) == ErrorCode.ERR_UNKNOWN_ATTR.value
484
+ ]
485
+
486
+
487
+ def _print_unknown_attr_warnings(findings: list[str]) -> None:
488
+ """``gen`` loads leniently; an unknown attribute ``verify`` would reject is named here
489
+ as a warning (attribute, node, file). Advisory only: the exit code is unchanged."""
490
+ if not findings:
491
+ return
492
+ for f in findings:
493
+ print(f"warning: {f}", file=sys.stderr)
494
+ print(f"warning: {UNKNOWN_ATTR_GEN_ADVICE}", file=sys.stderr)
495
+
496
+
438
497
  def _strict_load_hint() -> str:
439
498
  """Actionable next-steps when strict verify rejects an undeclared @attr."""
440
499
  return (
@@ -1099,12 +1158,16 @@ def _cmd_gen(args: argparse.Namespace) -> int:
1099
1158
  return 1
1100
1159
  # Load the metadata ONCE; both the default suite and the (optional)
1101
1160
  # --template-spec pass run against this single loaded root.
1102
- root, load_errors = _load_root(args.metadata_dir, providers=providers)
1161
+ unknown_attrs: list[str] = []
1162
+ root, load_errors = _load_root(
1163
+ args.metadata_dir, providers=providers, unknown_attr_out=unknown_attrs
1164
+ )
1103
1165
  if root is None:
1104
1166
  print("error: failed to load metadata:", file=sys.stderr)
1105
1167
  for msg in load_errors:
1106
1168
  print(f" {msg}", file=sys.stderr)
1107
1169
  return 1
1170
+ _print_unknown_attr_warnings(unknown_attrs)
1108
1171
  gen_state = gen_state_dir_for(args.metadata_dir)
1109
1172
  # Same anchor the manifest itself uses. Both passes below key against it, so a
1110
1173
  # `--template-spec` artifact and a default-suite artifact land in one key space.
@@ -1368,14 +1431,17 @@ def _cmd_gen_config(args: argparse.Namespace) -> int:
1368
1431
  if collection is None:
1369
1432
  return 1
1370
1433
 
1434
+ unknown_attrs: list[str] = []
1371
1435
  root, load_errors = _load_root_from_collection(
1372
- collection, providers=providers, libraries=config.libraries
1436
+ collection, providers=providers, libraries=config.libraries,
1437
+ unknown_attr_out=unknown_attrs,
1373
1438
  )
1374
1439
  if root is None:
1375
1440
  print("error: failed to load metadata:", file=sys.stderr)
1376
1441
  for msg in load_errors:
1377
1442
  print(f" {msg}", file=sys.stderr)
1378
1443
  return 1
1444
+ _print_unknown_attr_warnings(unknown_attrs)
1379
1445
 
1380
1446
  for t in targets:
1381
1447
  imported_refusal = _refuse_imported_entities(t.entities, root, collection)
@@ -39,6 +39,7 @@ from metaobjects.codegen.generator import EmittedFile, GenContext, Generator, pe
39
39
  from metaobjects.codegen.generators.m2m_codegen import build_object_index
40
40
  from metaobjects.codegen.generators.router_generator import emits_router
41
41
  from metaobjects.codegen.generators.tph_plan import tph_plan_for
42
+ from metaobjects.codegen.instance_artifacts import is_sourceless_entity
42
43
  from metaobjects.meta.core.field import field_constants as fc
43
44
  from metaobjects.meta.core.field.meta_field import MetaField
44
45
  from metaobjects.meta.core.object.meta_object import MetaObject
@@ -179,7 +180,9 @@ class FilterAllowlistGenerator:
179
180
 
180
181
  Skips entities without a ``source.rdb`` child and read-only kinds
181
182
  (view / materializedView / storedProc / tableFunction) — same gate as
182
- ``RouterGenerator``, so the two generators emit in lock-step.
183
+ ``RouterGenerator``, so the two generators emit in lock-step. The exception is a
184
+ sourceless entity (``is_sourceless_entity``): no router, but an allowlist for the
185
+ adopter's own endpoint.
183
186
  """
184
187
 
185
188
  name = "filter-allowlist-generator"
@@ -271,7 +274,12 @@ class FilterAllowlistGenerator:
271
274
  # again at F22 when the router learned to serve view-only projections and
272
275
  # this module did not — the emitted router imported an allowlist nothing
273
276
  # had generated.
274
- if not emits_router(entity):
277
+ #
278
+ # The one addition: a sourceless entity (identity, no source — a record in a store
279
+ # MetaObjects does not manage) gets no router but does get the allowlist, for the
280
+ # list endpoint its adopter writes. Nothing generated imports it, so the lock-step
281
+ # rule above is not at stake.
282
+ if not emits_router(entity) and not is_sourceless_entity(entity):
275
283
  return None
276
284
 
277
285
  short_name = entity.name
@@ -0,0 +1,43 @@
1
+ """Guard for the abstract concept (mirrors the TS instance-artifacts module).
2
+
3
+ An abstract entity must never produce instance/write artifacts (routers, filter
4
+ allowlists, CREATE TABLE DDL). The Pydantic base *model* is a separate concern: this
5
+ port ALWAYS emits it (concretes subclass it). It was described here as "a configurable
6
+ shape concern (emit_abstract_shapes, default on) handled in entity_model" — that config
7
+ field was read by nothing and entity_model never consulted it, so `GenConfig` now
8
+ refuses to accept a value it cannot honour.
9
+ """
10
+ from metaobjects.meta.core.object.meta_object import MetaObject
11
+
12
+
13
+ def is_abstract(entity: MetaObject) -> bool:
14
+ return entity.is_abstract is True
15
+
16
+
17
+ def emits_instance_artifacts(entity: MetaObject) -> bool:
18
+ return not is_abstract(entity)
19
+
20
+
21
+ def is_sourceless_entity(entity: MetaObject) -> bool:
22
+ """A record whose store MetaObjects does not manage: a concrete object with a primary
23
+ identity and no ``source.*`` at all, declared or inherited (a MongoDB collection, a
24
+ Cassandra table, a Neo4j node, a remote API). #248 gives it no router, table or
25
+ migration; the adopter owns the data access.
26
+
27
+ It still has a wire contract, because the identity makes it addressable: a client can
28
+ create, fetch and PATCH it. So it gets the filter allowlist its own list endpoint needs
29
+ (the Create/Patch models come from the entity generator already).
30
+
31
+ Keyed on the identity, not the object subtype (#248): ADR-0028 forbids a value object
32
+ any identity. The projection exclusion is ADR-0028's own rule — a projection is
33
+ read-only because of its subtype. Mirrors the TypeScript ``isSourcelessEntity``.
34
+ """
35
+ from metaobjects.meta.core.object.object_constants import OBJECT_SUBTYPE_PROJECTION
36
+ from metaobjects.meta.persistence.source.meta_source import MetaSource
37
+
38
+ if is_abstract(entity) or entity.sub_type == OBJECT_SUBTYPE_PROJECTION:
39
+ return False
40
+ if entity.primary_identity() is None:
41
+ return False
42
+ # ADR-0039: children() resolves — an inherited source makes the object persistable.
43
+ return not any(isinstance(c, MetaSource) for c in entity.children())
@@ -158,6 +158,31 @@ def _field_spec_for(
158
158
  format: Format,
159
159
  visited: set[int],
160
160
  depth: int,
161
+ ) -> FieldSpec:
162
+ spec = _field_shape_for(field, owner, format, visited, depth)
163
+ if not _is_array(field):
164
+ return spec
165
+ # Element-count bounds: the field's array validator (@min/@max) is the single source of
166
+ # truth, as the numeric validator is for a scalar's range.
167
+ for c in field.children():
168
+ if c.type == TYPE_VALIDATOR and c.sub_type == vc.VALIDATOR_SUBTYPE_ARRAY:
169
+ # ADR-0039 sanctioned own: a validator's @min/@max are its own declared bounds,
170
+ # read exactly as _numeric_bound reads the numeric validator's.
171
+ lo = c.attr(vc.VALIDATOR_ATTR_MIN)
172
+ hi = c.attr(vc.VALIDATOR_ATTR_MAX)
173
+ return spec.with_item_bounds(
174
+ lo if isinstance(lo, int) and not isinstance(lo, bool) else None,
175
+ hi if isinstance(hi, int) and not isinstance(hi, bool) else None,
176
+ )
177
+ return spec
178
+
179
+
180
+ def _field_shape_for(
181
+ field: MetaField,
182
+ owner: MetaObject,
183
+ format: Format,
184
+ visited: set[int],
185
+ depth: int,
161
186
  ) -> FieldSpec:
162
187
  name = field.name
163
188
  required = _is_required(field)
@@ -143,8 +143,22 @@ def _extract(
143
143
  # Cross-port contract: a MALFORMED array still places its successfully-coerced
144
144
  # elements into data (partial extraction), UNLIKE a MALFORMED scalar which is
145
145
  # absent from data.
146
+ # validator.array bounds. Too many: NORMAL/LOOSE keep the first max_items (a
147
+ # "truncate" coercion, like a numeric clamp); STRICT rejects. Too few: nothing can
148
+ # repair it, so it is MALFORMED under every tolerance.
149
+ out_of_bounds = False
150
+ if not any_malformed and f.max_items is not None and len(out) > f.max_items:
151
+ if o.tolerance == Tolerance.STRICT:
152
+ out_of_bounds = True
153
+ else:
154
+ report.add_coercion(
155
+ Coercion(path, str(len(out)), str(f.max_items), "truncate")
156
+ )
157
+ out = out[: f.max_items]
158
+ if not any_malformed and f.min_items is not None and len(out) < f.min_items:
159
+ out_of_bounds = True
146
160
  data[f.name] = out
147
- if any_malformed:
161
+ if any_malformed or out_of_bounds:
148
162
  _mark_malformed(report, path, f)
149
163
  else:
150
164
  report.set(path, FieldExtraction.EXTRACTED)
@@ -179,7 +179,16 @@ class JsonForgivingReader:
179
179
 
180
180
  def _read_bare_scalar(self) -> object | None:
181
181
  start = self._i
182
- while self._i < len(self._s) and self._s[self._i] not in ",}]":
182
+ # A comment after an unquoted value (`7 // good`) ends it; `http://x` does not.
183
+ while (
184
+ self._i < len(self._s)
185
+ and self._s[self._i] not in ",}]"
186
+ and not (
187
+ self._i > start
188
+ and self._s[self._i - 1].isspace()
189
+ and comment_opens_at(self._s, self._i)
190
+ )
191
+ ):
183
192
  self._i += 1
184
193
  result = self._s[start : self._i].strip()
185
194
  if not result:
@@ -189,8 +198,35 @@ class JsonForgivingReader:
189
198
  return result
190
199
 
191
200
  def _ws(self) -> None:
192
- while self._i < len(self._s) and self._s[self._i].isspace():
193
- self._i += 1
201
+ """Skip whitespace AND ``//`` / ``/* */`` comments. Only ever called between tokens,
202
+ so a comment marker inside a string literal is never reached here."""
203
+ while True:
204
+ while self._i < len(self._s) and self._s[self._i].isspace():
205
+ self._i += 1
206
+ end = comment_end(self._s, self._i)
207
+ if end < 0:
208
+ return
209
+ self._i = end
210
+
211
+
212
+ def comment_opens_at(s: str, i: int) -> bool:
213
+ """True when a ``//`` or ``/*`` comment opens at ``i``."""
214
+ return i + 1 < len(s) and s[i] == "/" and s[i + 1] in "/*"
215
+
216
+
217
+ def comment_end(s: str, i: int) -> int:
218
+ """Models write JSONC: ``{"score": 7, // good`` drops every field after it in a strict
219
+ reader. When a comment opens at ``i``, the index just past it (a line comment runs to the
220
+ end of its line, a block comment to its ``*/`` or the end of the text); otherwise -1."""
221
+ if not comment_opens_at(s, i):
222
+ return -1
223
+ if s[i + 1] == "/":
224
+ j = i + 2
225
+ while j < len(s) and s[j] not in "\n\r":
226
+ j += 1
227
+ return j
228
+ close = s.find("*/", i + 2)
229
+ return len(s) if close < 0 else close + 2
194
230
 
195
231
 
196
232
  def _unescape(c: str) -> str:
@@ -7,6 +7,8 @@ from __future__ import annotations
7
7
 
8
8
  import re
9
9
 
10
+ from metaobjects.render.extract.json_forgiving_reader import comment_end
11
+
10
12
 
11
13
  def json(text: str | None) -> str | None:
12
14
  """First balanced ``{...}``; if none closes, first ``{`` to end; ``None`` if no ``{``."""
@@ -46,11 +48,16 @@ def json_candidates(text: str | None) -> list[str]:
46
48
 
47
49
 
48
50
  def _scan_balanced(s: str, open_idx: int) -> int:
49
- """Return index of the matching ``}``, or -1 if unterminated. String-aware."""
51
+ """Return index of the matching ``}``, or -1 if unterminated. String-aware, and
52
+ comment-aware: a ``//`` / ``/* */`` comment opening after whitespace or a separator is
53
+ skipped, so a brace or quote inside it cannot close the object early (``http://x`` is
54
+ not a comment)."""
50
55
  depth = 0
51
56
  in_str = False
52
57
  esc = False
53
- for i in range(open_idx, len(s)):
58
+ i = open_idx - 1
59
+ while i + 1 < len(s):
60
+ i += 1
54
61
  c = s[i]
55
62
  if in_str:
56
63
  if esc:
@@ -60,6 +67,11 @@ def _scan_balanced(s: str, open_idx: int) -> int:
60
67
  elif c == '"':
61
68
  in_str = False
62
69
  continue
70
+ if i > open_idx and (s[i - 1].isspace() or s[i - 1] in ",{["):
71
+ end = comment_end(s, i)
72
+ if end >= 0:
73
+ i = end - 1
74
+ continue
63
75
  if c == '"':
64
76
  in_str = True
65
77
  elif c == "{":
@@ -11,6 +11,8 @@ runner maps the schema-json tokens onto these enums.
11
11
  """
12
12
  from __future__ import annotations
13
13
 
14
+ import dataclasses
15
+
14
16
  from dataclasses import dataclass, field
15
17
  from enum import Enum
16
18
  from typing import Callable, Generic, TypeVar
@@ -115,6 +117,17 @@ class FieldSpec:
115
117
  # reads it from the ``#text`` sentinel the lenient XML reader carries when an element has
116
118
  # both attributes and a text body, instead of a same-named child. False for normal/JSON.
117
119
  text_content: bool = False
120
+ # Element-count bounds for an ARRAY field, from its ``validator.array`` (``@min``/``@max``).
121
+ # None = unbounded. Under NORMAL/LOOSE tolerance a list longer than ``max_items`` keeps its
122
+ # first ``max_items`` elements (a "truncate" coercion, the array analogue of a numeric
123
+ # clamp); under STRICT it is MALFORMED. A list shorter than ``min_items`` is MALFORMED under
124
+ # every tolerance: there is nothing to repair it with.
125
+ min_items: int | None = None
126
+ max_items: int | None = None
127
+
128
+ def with_item_bounds(self, min_items: int | None, max_items: int | None) -> "FieldSpec":
129
+ """This field with ``validator.array`` element-count bounds (None = unbounded)."""
130
+ return dataclasses.replace(self, min_items=min_items, max_items=max_items)
118
131
 
119
132
  @staticmethod
120
133
  def scalar(
@@ -0,0 +1,70 @@
1
+ """`metaobjects gen` loads leniently, `verify` strictly (ADR-0023).
2
+
3
+ An unknown attribute — `isAbstrakt: true` meant as `abstract`, a misspelt `required` —
4
+ used to pass `gen` without a word while `verify` rejected the same file with
5
+ ERR_UNKNOWN_ATTR, and the typo changed the output (the "abstract" base got a model
6
+ file). `gen` now names each finding (attribute, node, file) as a warning on stderr and
7
+ keeps its exit code.
8
+ """
9
+ from __future__ import annotations
10
+
11
+ from pathlib import Path
12
+
13
+ from metaobjects.cli import main
14
+
15
+ TYPO_YAML = """
16
+ metadata:
17
+ package: app
18
+ children:
19
+ - object.entity:
20
+ name: BaseThing
21
+ isAbstrakt: true
22
+ children:
23
+ - field.long: { name: id }
24
+ - object.entity:
25
+ name: Talk
26
+ extends: BaseThing
27
+ children:
28
+ - source.rdb: { table: talks }
29
+ - field.string: { name: title, requird: true }
30
+ - identity.primary: { name: pk, fields: [id] }
31
+ """
32
+
33
+ CLEAN_YAML = TYPO_YAML.replace("isAbstrakt: true", "abstract: true").replace("requird", "required")
34
+
35
+
36
+ def _meta(tmp_path: Path, text: str) -> str:
37
+ d = tmp_path / "metaobjects"
38
+ d.mkdir()
39
+ (d / "meta.app.yaml").write_text(text)
40
+ return str(d)
41
+
42
+
43
+ def test_gen_warns_on_each_unknown_attribute_and_keeps_exit_code(tmp_path: Path, capsys) -> None:
44
+ meta_dir = _meta(tmp_path, TYPO_YAML)
45
+ rc = main(["gen", "--generators", "entity", meta_dir, "--out", str(tmp_path / "out")])
46
+ assert rc == 0
47
+ err = capsys.readouterr().err
48
+ assert "ERR_UNKNOWN_ATTR" in err
49
+ assert "isAbstrakt" in err and "BaseThing" in err
50
+ assert "requird" in err and "title" in err
51
+ assert "meta.app.yaml" in err
52
+ assert "metaobjects verify" in err
53
+
54
+
55
+ def test_gen_config_mode_warns_too(tmp_path: Path, capsys) -> None:
56
+ _meta(tmp_path, TYPO_YAML)
57
+ cfg = tmp_path / "metaobjects.config.yaml"
58
+ cfg.write_text("targets:\n models:\n outDir: gen/models\n generators: [entity]\n")
59
+ rc = main(["gen", "--config", str(cfg)])
60
+ assert rc == 0
61
+ err = capsys.readouterr().err
62
+ assert "ERR_UNKNOWN_ATTR" in err
63
+ assert "requird" in err
64
+
65
+
66
+ def test_gen_clean_model_prints_no_unknown_attr_warning(tmp_path: Path, capsys) -> None:
67
+ meta_dir = _meta(tmp_path, CLEAN_YAML)
68
+ rc = main(["gen", "--generators", "entity", meta_dir, "--out", str(tmp_path / "out")])
69
+ assert rc == 0
70
+ assert "ERR_UNKNOWN_ATTR" not in capsys.readouterr().err
@@ -0,0 +1,74 @@
1
+ """A SOURCELESS entity — ``object.entity`` with an ``identity.primary`` and no ``source.*`` —
2
+ is a record in a store MetaObjects does not manage (a MongoDB collection, a Cassandra table, a
3
+ Neo4j node, a remote API). It gets no router and no table (#248); the adopter owns the data
4
+ access. What it still needs is the wire contract: the ``<E>Create`` / ``<E>Patch`` models (the
5
+ entity generator already emits them for every entity) and the filter allowlist its own list
6
+ endpoint validates a query against. Value objects are unchanged: ADR-0028 forbids them an
7
+ identity.
8
+
9
+ Mirror of the TypeScript ``sourceless-entity-surface.test.ts``.
10
+ """
11
+ import json
12
+
13
+ from metaobjects import InMemoryStringSource, MetaDataFormat, MetaDataLoader
14
+ from metaobjects.codegen.generators.entity_model import EntityModelGenerator
15
+ from metaobjects.codegen.generators.filter_allowlist_generator import render_filter_allowlist
16
+ from metaobjects.codegen.generators.router_generator import render_router
17
+ from metaobjects.codegen.generator import GenContext
18
+ from metaobjects.codegen.config import GenConfig
19
+ from metaobjects.codegen.instance_artifacts import is_sourceless_entity
20
+ from metaobjects.meta.core.object.meta_object import MetaObject
21
+
22
+ MODEL = {"metadata.root": {"package": "shop", "children": [
23
+ {"object.value": {"name": "LineItem", "children": [
24
+ {"field.string": {"name": "sku", "@required": True}},
25
+ ]}},
26
+ {"object.entity": {"name": "Order", "children": [
27
+ {"field.string": {"name": "id"}},
28
+ {"field.string": {"name": "customerEmail", "@required": True, "@filterable": True}},
29
+ {"field.enum": {"name": "status", "@values": ["NEW", "SHIPPED"], "@filterable": True}},
30
+ {"identity.primary": {"name": "id", "@fields": "id"}},
31
+ ]}},
32
+ {"object.entity": {"name": "Note", "children": [
33
+ {"field.string": {"name": "text"}},
34
+ ]}},
35
+ ]}}
36
+
37
+
38
+ def _objects() -> dict[str, MetaObject]:
39
+ result = MetaDataLoader().load(
40
+ [InMemoryStringSource(json.dumps(MODEL), id="m.json", format=MetaDataFormat.JSON)]
41
+ )
42
+ assert not result.errors, result.errors
43
+ return {o.name: o for o in result.root.own_children() if isinstance(o, MetaObject)}
44
+
45
+
46
+ def test_is_sourceless_entity_needs_an_identity_and_no_source() -> None:
47
+ objs = _objects()
48
+ assert is_sourceless_entity(objs["Order"]) is True
49
+ assert is_sourceless_entity(objs["LineItem"]) is False # a value: no identity, ever
50
+ assert is_sourceless_entity(objs["Note"]) is False # no identity: nothing to address
51
+
52
+
53
+ def test_sourceless_entity_gets_a_filter_allowlist_but_no_router() -> None:
54
+ order = _objects()["Order"]
55
+ assert render_router(order) is None
56
+ out = render_filter_allowlist(order)
57
+ assert out is not None
58
+ assert '"customerEmail"' in out
59
+ assert '"status"' in out
60
+
61
+
62
+ def test_value_object_gets_no_filter_allowlist() -> None:
63
+ assert render_filter_allowlist(_objects()["LineItem"]) is None
64
+
65
+
66
+ def test_sourceless_entity_gets_create_and_patch_models() -> None:
67
+ objs = _objects()
68
+ root_objs = list(objs.values())
69
+ ctx = GenContext(entities=root_objs, loaded_root=root_objs[0].parent, matches=lambda _e: True,
70
+ config=GenConfig(out_dir=""), warn=lambda _m: None)
71
+ files = {f.path: f.content for f in EntityModelGenerator().generate(ctx)}
72
+ order = next(c for p, c in files.items() if p.endswith("Order.py"))
73
+ assert "class OrderCreate(BaseModel)" in order
74
+ assert "class OrderPatch(BaseModel)" in order
@@ -23,6 +23,7 @@ from metaobjects.render.extract import (
23
23
  FieldSpec,
24
24
  Format,
25
25
  ExtractSchema,
26
+ Tolerance,
26
27
  extract,
27
28
  )
28
29
 
@@ -60,7 +61,7 @@ def _cases() -> list[str]:
60
61
  def test_discovers_all_extract_conformance_cases() -> None:
61
62
  """FR-011: lock the corpus size so a deleted fixture fails CI rather than
62
63
  silently reducing coverage. Mirrors the TS / Java / C# count guards."""
63
- assert len(_cases()) == 42
64
+ assert len(_cases()) == 48
64
65
 
65
66
 
66
67
  _NORMALIZE_MODES = {"none", "collapse", "strip"}
@@ -76,6 +77,13 @@ def _parse_normalize(s: object) -> str:
76
77
 
77
78
 
78
79
  def _parse_field(f: dict[str, object]) -> FieldSpec:
80
+ # validator.array element-count bounds (array fields only).
81
+ min_items = int(f["minItems"]) if "minItems" in f else None # type: ignore[arg-type]
82
+ max_items = int(f["maxItems"]) if "maxItems" in f else None # type: ignore[arg-type]
83
+ return _parse_field_shape(f).with_item_bounds(min_items, max_items)
84
+
85
+
86
+ def _parse_field_shape(f: dict[str, object]) -> FieldSpec:
79
87
  name = str(f["name"])
80
88
  kind = _KINDS[str(f["kind"])]
81
89
  required = bool(f.get("required", False))
@@ -116,6 +124,10 @@ def _parse_field(f: dict[str, object]) -> FieldSpec:
116
124
  max_v = float(f["max"]) if "max" in f else None # type: ignore[arg-type]
117
125
  return FieldSpec.range_(name, kind, required, min_v, max_v)
118
126
 
127
+ # A scalar array (`tags: ["a", "b"]`): each element coerced to kind.
128
+ if bool(f.get("array", False)):
129
+ return FieldSpec.scalar_array(name, kind, required)
130
+
119
131
  # @xmlText: a scalar field that receives its element's text content (the #text sentinel).
120
132
  if bool(f.get("textContent", False)):
121
133
  return FieldSpec.text_content_field(name, kind, required)
@@ -165,6 +177,9 @@ def test_classification_and_canonical_value_match(case_name: str) -> None:
165
177
  opts = ExtractOptions.defaults()
166
178
  if bool(schema_node.get("rootless", False)):
167
179
  opts = opts.with_rootless(True)
180
+ # Optional per-fixture tolerance (default NORMAL).
181
+ if "tolerance" in schema_node:
182
+ opts = opts.with_tolerance(Tolerance[str(schema_node["tolerance"])])
168
183
 
169
184
  outcome = extract(text, schema, opts)
170
185