metaobjects 1.0.10__tar.gz → 1.0.12__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 (482) hide show
  1. {metaobjects-1.0.10 → metaobjects-1.0.12}/PKG-INFO +1 -1
  2. {metaobjects-1.0.10 → metaobjects-1.0.12}/pyproject.toml +1 -1
  3. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/agent_context/scaffold.py +2 -2
  4. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/cli.py +179 -12
  5. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/metaobjects-config.schema.json +1 -1
  6. metaobjects-1.0.12/src/metaobjects/fmt.py +214 -0
  7. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/__init__.py +2 -0
  8. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/extract.py +34 -2
  9. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/types.py +28 -1
  10. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli.py +19 -0
  11. metaobjects-1.0.12/tests/codegen/test_cli_fmt.py +137 -0
  12. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_extractor_generator.py +41 -0
  13. metaobjects-1.0.12/tests/codegen/test_fmt_format_file.py +45 -0
  14. metaobjects-1.0.12/tests/conformance/test_fmt_conformance.py +54 -0
  15. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_extract.py +100 -0
  16. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_agent_context_staleness.py +8 -2
  17. {metaobjects-1.0.10 → metaobjects-1.0.12}/uv.lock +1 -1
  18. {metaobjects-1.0.10 → metaobjects-1.0.12}/.gitignore +0 -0
  19. {metaobjects-1.0.10 → metaobjects-1.0.12}/LICENSE +0 -0
  20. {metaobjects-1.0.10 → metaobjects-1.0.12}/README.md +0 -0
  21. {metaobjects-1.0.10 → metaobjects-1.0.12}/hatch_build.py +0 -0
  22. {metaobjects-1.0.10 → metaobjects-1.0.12}/scripts/generate_embedded_library.py +0 -0
  23. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/__init__.py +0 -0
  24. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/agent_context/__init__.py +0 -0
  25. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/__init__.py +0 -0
  26. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/api_model.py +0 -0
  27. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/builder.py +0 -0
  28. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/naming.py +0 -0
  29. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/paths.py +0 -0
  30. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/apidocs/renderer.py +0 -0
  31. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/attr_class_map.py +0 -0
  32. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
  33. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/__init__.py +0 -0
  34. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/collision_names.py +0 -0
  35. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/config.py +0 -0
  36. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/constants.py +0 -0
  37. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/eject.py +0 -0
  38. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
  39. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
  40. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/format.py +0 -0
  41. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
  42. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generator.py +0 -0
  43. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generator_registry.py +0 -0
  44. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/__init__.py +0 -0
  45. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/entity_model.py +0 -0
  46. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
  47. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
  48. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/find_inbound.py +0 -0
  49. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
  50. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
  51. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/names_generator.py +0 -0
  52. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
  53. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
  54. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
  55. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/router_generator.py +0 -0
  56. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/template_generator.py +0 -0
  57. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
  58. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
  59. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/instance_artifacts.py +0 -0
  60. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/model_walk.py +0 -0
  61. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
  62. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/overwrite_policy.py +0 -0
  63. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/project_config.py +0 -0
  64. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runner.py +0 -0
  65. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/__init__.py +0 -0
  66. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/constraint_errors.py +0 -0
  67. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
  68. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
  69. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
  70. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
  71. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
  72. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/type_map.py +0 -0
  73. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/codegen/value_objects.py +0 -0
  74. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/__init__.py +0 -0
  75. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/dependencies.py +0 -0
  76. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/neutral_config.py +0 -0
  77. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/config/source_resolver.py +0 -0
  78. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/core_types.py +0 -0
  79. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/datatype.py +0 -0
  80. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/__init__.py +0 -0
  81. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_constants.py +0 -0
  82. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_provider.py +0 -0
  83. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/documentation/doc_schema.py +0 -0
  84. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/errors.py +0 -0
  85. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/library/__init__.py +0 -0
  86. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/library/embedded_library.py +0 -0
  87. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/library/library_sources.py +0 -0
  88. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/__init__.py +0 -0
  89. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/merge.py +0 -0
  90. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/meta_data_loader.py +0 -0
  91. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/registered_validation.py +0 -0
  92. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/__init__.py +0 -0
  93. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/directory_source.py +0 -0
  94. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/file_source.py +0 -0
  95. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
  96. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/sources/uri_source.py +0 -0
  97. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_discriminator.py +0 -0
  98. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
  99. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_field_mutability.py +0 -0
  100. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_escapes.py +0 -0
  101. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
  102. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
  103. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/loader/validation_passes.py +0 -0
  104. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/__init__.py +0 -0
  105. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/__init__.py +0 -0
  106. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/__init__.py +0 -0
  107. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
  108. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
  109. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/__init__.py +0 -0
  110. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/field_constants.py +0 -0
  111. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/field/meta_field.py +0 -0
  112. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/__init__.py +0 -0
  113. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
  114. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
  115. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/__init__.py +0 -0
  116. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/index_constants.py +0 -0
  117. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/index/meta_index.py +0 -0
  118. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/__init__.py +0 -0
  119. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/meta_object.py +0 -0
  120. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
  121. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
  122. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_constants.py +0 -0
  123. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/object_extract.py +0 -0
  124. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/object/value_object.py +0 -0
  125. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
  126. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
  127. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
  128. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
  129. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/relationship/relationship_references.py +0 -0
  130. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
  131. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/meta_requirement.py +0 -0
  132. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/requirement/requirement_constants.py +0 -0
  133. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/validator/__init__.py +0 -0
  134. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
  135. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/meta_data.py +0 -0
  136. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/meta_root.py +0 -0
  137. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/__init__.py +0 -0
  138. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
  139. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
  140. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
  141. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
  142. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
  143. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
  144. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
  145. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
  146. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
  147. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/__init__.py +0 -0
  148. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
  149. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
  150. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
  151. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
  152. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
  153. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
  154. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
  155. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
  156. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/provider_extends.py +0 -0
  157. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/__init__.py +0 -0
  158. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/meta_template.py +0 -0
  159. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/prompt_provider.py +0 -0
  160. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta/template/template_constants.py +0 -0
  161. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/meta_endpoint.py +0 -0
  162. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/naming.py +0 -0
  163. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/naming_refs.py +0 -0
  164. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/parser.py +0 -0
  165. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/parser_yaml.py +0 -0
  166. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/provider.py +0 -0
  167. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/py.typed +0 -0
  168. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/registry.py +0 -0
  169. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/registry_manifest.py +0 -0
  170. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/__init__.py +0 -0
  171. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/email_document.py +0 -0
  172. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/escapers.py +0 -0
  173. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
  174. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/coerce.py +0 -0
  175. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/extract_map.py +0 -0
  176. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
  177. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/locate.py +0 -0
  178. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/normalize.py +0 -0
  179. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/strip.py +0 -0
  180. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
  181. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/filesystem_provider.py +0 -0
  182. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/payload_accessors.py +0 -0
  183. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/__init__.py +0 -0
  184. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
  185. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
  186. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_field.py +0 -0
  187. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
  188. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/prompt/prompt_style.py +0 -0
  189. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/renderer.py +0 -0
  190. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/render/verify.py +0 -0
  191. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/__init__.py +0 -0
  192. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/llm_recorder.py +0 -0
  193. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/n2m_resolver.py +0 -0
  194. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/object_manager.py +0 -0
  195. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/runtime/tph.py +0 -0
  196. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/scope.py +0 -0
  197. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/serializer_json.py +0 -0
  198. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/__init__.py +0 -0
  199. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/base_types.py +0 -0
  200. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/separators.py +0 -0
  201. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/shared/structural.py +0 -0
  202. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/__init__.py +0 -0
  203. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/error_source.py +0 -0
  204. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/json_path.py +0 -0
  205. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/semantic_diff.py +0 -0
  206. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source/yaml_positions.py +0 -0
  207. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/source_resolution.py +0 -0
  208. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/__init__.py +0 -0
  209. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/attr.json +0 -0
  210. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/db.json +0 -0
  211. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/documentation.json +0 -0
  212. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/field.json +0 -0
  213. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/identity.json +0 -0
  214. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/index.json +0 -0
  215. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/layout.json +0 -0
  216. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/object.json +0 -0
  217. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/origin.json +0 -0
  218. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/prompt.json +0 -0
  219. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/relationship.json +0 -0
  220. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/requirement.json +0 -0
  221. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/source.json +0 -0
  222. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/template.json +0 -0
  223. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
  224. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/ui.json +0 -0
  225. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/validator.json +0 -0
  226. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/spec_metamodel/view.json +0 -0
  227. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/super_resolve.py +0 -0
  228. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/validation_types.py +0 -0
  229. {metaobjects-1.0.10 → metaobjects-1.0.12}/src/metaobjects/yaml_desugar.py +0 -0
  230. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/__init__.py +0 -0
  231. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/__init__.py +0 -0
  232. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/gen_suite.py +0 -0
  233. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
  234. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/extends/expected/Program.py +0 -0
  235. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/extends/meta.json +0 -0
  236. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
  237. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
  238. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/nested-array/meta.json +0 -0
  239. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
  240. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/scalars/expected/Report.py +0 -0
  241. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/scalars/meta.json +0 -0
  242. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
  243. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/golden/vanilla/meta.json +0 -0
  244. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_abstract_conformance.py +0 -0
  245. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_api_docs_builder.py +0 -0
  246. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_api_docs_paths.py +0 -0
  247. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_config_gen.py +0 -0
  248. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_config_verify.py +0 -0
  249. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_dependencies.py +0 -0
  250. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_gen_unknown_attr.py +0 -0
  251. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_providers.py +0 -0
  252. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_registry.py +0 -0
  253. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_render_helper_template_root.py +0 -0
  254. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_staleness_nudge.py +0 -0
  255. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_verify_strict.py +0 -0
  256. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_cli_verify_subverbs.py +0 -0
  257. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_codegen_compile_conformance.py +0 -0
  258. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_constants_config.py +0 -0
  259. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_eject.py +0 -0
  260. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_eject_runtime.py +0 -0
  261. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_entity_model.py +0 -0
  262. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_enum_conformance.py +0 -0
  263. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
  264. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_extract_tier_collision.py +0 -0
  265. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_filter_allowlist_generator.py +0 -0
  266. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_format.py +0 -0
  267. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
  268. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_fr010_output_codegen.py +0 -0
  269. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
  270. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_gen_state_keying.py +0 -0
  271. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_generator.py +0 -0
  272. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_generator_extension_seams.py +0 -0
  273. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_golden.py +0 -0
  274. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
  275. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_inheritance_conformance.py +0 -0
  276. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_instance_artifacts.py +0 -0
  277. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_m2m_codegen.py +0 -0
  278. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_names_extends_chain.py +0 -0
  279. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_names_generator.py +0 -0
  280. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_no_magic_physical_names.py +0 -0
  281. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_origin_nullability.py +0 -0
  282. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_output_parser_generator.py +0 -0
  283. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_overwrite_policy.py +0 -0
  284. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_overwrite_policy_hash.py +0 -0
  285. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_project_config.py +0 -0
  286. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_projection_compile.py +0 -0
  287. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_recipe_generators.py +0 -0
  288. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_render_helper_conformance.py +0 -0
  289. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_render_helper_generator.py +0 -0
  290. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_reverse_finders.py +0 -0
  291. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_route_path_naming.py +0 -0
  292. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_autoset.py +0 -0
  293. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator.py +0 -0
  294. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator_m2m_target_tph.py +0 -0
  295. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator_tph_m2m.py +0 -0
  296. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_router_generator_tph_m2m_shadowed.py +0 -0
  297. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_runner.py +0 -0
  298. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_source_resolution.py +0 -0
  299. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_sourceless_entity_surface.py +0 -0
  300. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_sourceless_projection.py +0 -0
  301. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_data.py +0 -0
  302. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_generator.py +0 -0
  303. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_output_pattern.py +0 -0
  304. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_scope_helpers.py +0 -0
  305. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_scope_walk.py +0 -0
  306. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_template_spec.py +0 -0
  307. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_tph_codegen.py +0 -0
  308. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_trace_helper_generator.py +0 -0
  309. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_type_map.py +0 -0
  310. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_validation_conformance.py +0 -0
  311. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_value_objects.py +0 -0
  312. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/codegen/test_write_through.py +0 -0
  313. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/__init__.py +0 -0
  314. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_dependencies.py +0 -0
  315. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_library_package_guard.py +0 -0
  316. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_neutral_config.py +0 -0
  317. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/config/test_source_resolver.py +0 -0
  318. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/__init__.py +0 -0
  319. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/capabilities.py +0 -0
  320. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/conformance-expected-failures.json +0 -0
  321. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/conformance_adapter.py +0 -0
  322. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/corpus.py +0 -0
  323. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/expected_failures.py +0 -0
  324. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/fixture_discovery.py +0 -0
  325. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/navigator.py +0 -0
  326. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
  327. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_conformance.py +0 -0
  328. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_dependency_conformance.py +0 -0
  329. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_extract_conformance.py +0 -0
  330. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_extract_object_array_bounds.py +0 -0
  331. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_extract_object_verdict.py +0 -0
  332. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_fr010_loader_attrs.py +0 -0
  333. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_fr011_attrs.py +0 -0
  334. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_generator_registry_conformance.py +0 -0
  335. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_object_model_conformance.py +0 -0
  336. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_provider_composition_conformance.py +0 -0
  337. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_registry_conformance.py +0 -0
  338. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_runner_hardfail.py +0 -0
  339. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_scope_conformance.py +0 -0
  340. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_source_resolution_conformance.py +0 -0
  341. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_spec_metamodel_embed.py +0 -0
  342. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_strict_attr_load.py +0 -0
  343. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_template_codegen_conformance.py +0 -0
  344. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_template_generator_conformance.py +0 -0
  345. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/test_yaml_conformance.py +0 -0
  346. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
  347. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/__init__.py +0 -0
  348. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_assertions.py +0 -0
  349. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_jsonb_server.py +0 -0
  350. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_m2m_server.py +0 -0
  351. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/api_contract_server.py +0 -0
  352. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_jsonb_app.py +0 -0
  353. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_m2m_app.py +0 -0
  354. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_projection_app.py +0 -0
  355. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_router_app.py +0 -0
  356. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/generated_tph_app.py +0 -0
  357. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/meta_ai_trace.yaml +0 -0
  358. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/normalization.py +0 -0
  359. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/postgres_container.py +0 -0
  360. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/query_runner.py +0 -0
  361. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/scenarios.py +0 -0
  362. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract.py +0 -0
  363. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_generated.py +0 -0
  364. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_jsonb.py +0 -0
  365. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_m2m.py +0 -0
  366. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_m2m_generated.py +0 -0
  367. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_projection.py +0 -0
  368. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_api_contract_tph_generated.py +0 -0
  369. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_generated_router_uuid_pk.py +0 -0
  370. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_llm_call_trace.py +0 -0
  371. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_m2m_target_tph_generated.py +0 -0
  372. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_normalization.py +0 -0
  373. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_query_scenarios.py +0 -0
  374. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_runtime_return_types.py +0 -0
  375. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_tph_m2m_generated.py +0 -0
  376. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/integration/test_tph_m2m_shadowed_generated.py +0 -0
  377. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/__init__.py +0 -0
  378. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_abstract_subtype_authored.py +0 -0
  379. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_child_wrapper_body_shape.py +0 -0
  380. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_enum_extends_values_conflict.py +0 -0
  381. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_field_mutability_order.py +0 -0
  382. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_shipped_library_ai.py +0 -0
  383. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/loader/test_template_payload_target_210.py +0 -0
  384. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/open_closed_proof_test.py +0 -0
  385. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/__init__.py +0 -0
  386. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/__init__.py +0 -0
  387. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_coerce.py +0 -0
  388. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_extract_map.py +0 -0
  389. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_json_forgiving_reader.py +0 -0
  390. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_locate.py +0 -0
  391. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_model.py +0 -0
  392. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_normalize.py +0 -0
  393. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_strip.py +0 -0
  394. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
  395. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/prompt/__init__.py +0 -0
  396. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/prompt/test_output_format_renderer.py +0 -0
  397. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_email_document.py +0 -0
  398. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_filesystem_provider.py +0 -0
  399. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_output_format_renderer_nested.py +0 -0
  400. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_output_prompt_conformance.py +0 -0
  401. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_render_conformance.py +0 -0
  402. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_render_max_chars.py +0 -0
  403. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_render_model_payload.py +0 -0
  404. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_verify.py +0 -0
  405. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/render/test_verify_conformance.py +0 -0
  406. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_constraint_errors.py +0 -0
  407. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_object_manager_currency_read.py +0 -0
  408. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_object_manager_enum_intvaluemap.py +0 -0
  409. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/runtime/test_object_manager_table_name.py +0 -0
  410. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/__init__.py +0 -0
  411. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_fr5c_merge_attribution.py +0 -0
  412. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_fr5d_reference_resolution.py +0 -0
  413. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_fr5e_database_source_shape.py +0 -0
  414. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_json_path.py +0 -0
  415. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_semantic_diff.py +0 -0
  416. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_source_on_node.py +0 -0
  417. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/source/test_yaml_positions.py +0 -0
  418. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/test_api_docs_accuracy.py +0 -0
  419. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/test_meta_endpoint.py +0 -0
  420. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/__init__.py +0 -0
  421. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_capabilities.py +0 -0
  422. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_column_naming_strategy.py +0 -0
  423. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_common_attrs.py +0 -0
  424. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_core_types.py +0 -0
  425. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_derive_m2m_declaring_entity.py +0 -0
  426. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_effective_children_sibling_shadowing.py +0 -0
  427. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_effective_package.py +0 -0
  428. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_errors.py +0 -0
  429. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_enum.py +0 -0
  430. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_enum_intvaluemap.py +0 -0
  431. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_map_validation.py +0 -0
  432. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
  433. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_file_source_id.py +0 -0
  434. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
  435. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_index_lookup.py +0 -0
  436. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_llm_recorder.py +0 -0
  437. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_loader.py +0 -0
  438. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_loader_bom.py +0 -0
  439. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_loader_class.py +0 -0
  440. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_merge.py +0 -0
  441. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_meta_attr.py +0 -0
  442. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_meta_data.py +0 -0
  443. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_meta_source.py +0 -0
  444. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_module_shortcuts.py +0 -0
  445. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_n2m_resolver.py +0 -0
  446. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_n2m_resolver_inherited.py +0 -0
  447. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_no_dead_config_fields.py +0 -0
  448. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
  449. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
  450. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_object_manager_write_through.py +0 -0
  451. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_one_primary_source.py +0 -0
  452. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_parser.py +0 -0
  453. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_parser_yaml.py +0 -0
  454. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_provider.py +0 -0
  455. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_provider_extension.py +0 -0
  456. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry.py +0 -0
  457. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry_completeness.py +0 -0
  458. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry_extend.py +0 -0
  459. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_registry_sealed.py +0 -0
  460. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_relationship_m2m_validation.py +0 -0
  461. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_relationship_references.py +0 -0
  462. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_relationship_referential_actions.py +0 -0
  463. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_resolution_key.py +0 -0
  464. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
  465. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_serializer.py +0 -0
  466. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_serializer_shared_document.py +0 -0
  467. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_shared_constants.py +0 -0
  468. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_smoke.py +0 -0
  469. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_source_escapes.py +0 -0
  470. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_sources.py +0 -0
  471. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_strict_child_placement.py +0 -0
  472. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_super_resolve.py +0 -0
  473. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_template_toolcall.py +0 -0
  474. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
  475. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_attr_schema.py +0 -0
  476. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_filter_values.py +0 -0
  477. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_origin_195.py +0 -0
  478. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_origin_paths.py +0 -0
  479. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_sort_field.py +0 -0
  480. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_validation_warnings.py +0 -0
  481. {metaobjects-1.0.10 → metaobjects-1.0.12}/tests/unit/test_write_coercion_arrays.py +0 -0
  482. {metaobjects-1.0.10 → metaobjects-1.0.12}/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.10
3
+ Version: 1.0.12
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.10"
3
+ version = "1.0.12"
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"
@@ -240,6 +240,6 @@ def agent_context_staleness(
240
240
  frm = generated_by if generated_by else "an older MetaObjects"
241
241
  return (
242
242
  f"MetaObjects agent context was generated by {frm}; "
243
- f"you're on {current_version}. Run 'npx meta agent-docs --server python' to "
244
- f"refresh the .claude/skills docs."
243
+ f"you're on {current_version}. Run 'npx meta agent-docs' to refresh the "
244
+ f".claude/skills docs (it keeps the stack recorded in .metaobjects/)."
245
245
  )
@@ -1069,6 +1069,132 @@ def _cmd_list(_args: argparse.Namespace) -> int:
1069
1069
  return 0
1070
1070
 
1071
1071
 
1072
+ def _describe_fmt_report(report: "object", cwd: Path) -> str:
1073
+ from metaobjects import fmt
1074
+
1075
+ try:
1076
+ rel = report.path.relative_to(cwd)
1077
+ except ValueError:
1078
+ rel = report.path
1079
+ if report.status == fmt.STATUS_FORMATTED:
1080
+ return f" reformatted {rel}"
1081
+ if report.status == fmt.STATUS_WOULD_FORMAT:
1082
+ return f" not canonical {rel}"
1083
+ if report.status == fmt.STATUS_UNCHANGED:
1084
+ return f" ok {rel}"
1085
+ if report.status == fmt.STATUS_SKIPPED_YAML:
1086
+ return f" skipped (yaml) {rel} — {report.detail}"
1087
+ if report.status == fmt.STATUS_SKIPPED_OVERLAY:
1088
+ return (
1089
+ f" skipped (overlay) {rel} — this file declares an overlay fmt "
1090
+ "cannot resolve standalone"
1091
+ )
1092
+ if report.status == fmt.STATUS_ERROR:
1093
+ return f" error {rel} — {report.detail}"
1094
+ return f" {report.status} {rel}" # pragma: no cover — exhaustive in practice
1095
+
1096
+
1097
+ def _cmd_fmt(args: argparse.Namespace) -> int:
1098
+ """``fmt`` (#304) — rewrite metadata files into canonical form; ``--check``
1099
+ lists non-canonical files and exits non-zero without changing anything.
1100
+
1101
+ Mirrors the TS reference surface exactly: no ``metadata_dir`` positional —
1102
+ files come from the neutral ``.metaobjects/config.json`` ladder
1103
+ (:func:`resolve_metadata_location`, rungs 3-4; this command does not read
1104
+ this port's own ``metaobjects.config.yaml`` rung 2, matching the scope the
1105
+ C# and Java ports also keep for `fmt`), optionally narrowed by explicit
1106
+ file arguments.
1107
+ """
1108
+ from metaobjects import fmt
1109
+ from metaobjects.core_types import core_providers
1110
+ from metaobjects.library import library_sources
1111
+ from metaobjects.provider import compose_registry
1112
+
1113
+ providers_extra, providers_ok = _providers_from_args(args)
1114
+ if not providers_ok:
1115
+ return 1
1116
+ providers = [*core_providers, *providers_extra]
1117
+ registry = compose_registry(providers)
1118
+
1119
+ cwd = Path.cwd()
1120
+ collection = _resolve_metadata_location_or_print_error(None, cwd)
1121
+ if collection is None:
1122
+ return 1
1123
+
1124
+ all_files = list(collection.files)
1125
+ own_files = list(collection.own_files)
1126
+
1127
+ if args.files:
1128
+ wanted = [Path(f).resolve() for f in args.files]
1129
+ owned_set = {p.resolve() for p in own_files}
1130
+ missing = [str(p) for p in wanted if p not in owned_set]
1131
+ if missing:
1132
+ print(
1133
+ "error: not among this project's resolved metadata sources: "
1134
+ + ", ".join(missing),
1135
+ file=sys.stderr,
1136
+ )
1137
+ print(
1138
+ "metaobjects fmt only formats files the metadata-location ladder "
1139
+ "already resolves — pass no arguments to format every one of them.",
1140
+ file=sys.stderr,
1141
+ )
1142
+ return 1
1143
+ wanted_set = {p for p in wanted}
1144
+ targets = [p for p in own_files if p.resolve() in wanted_set]
1145
+ else:
1146
+ targets = own_files
1147
+
1148
+ lib_sources = library_sources(list(collection.libraries)) if collection.libraries else []
1149
+
1150
+ result = fmt.run(
1151
+ all_files=all_files,
1152
+ target_files=targets,
1153
+ file_ids=dict(collection.file_ids),
1154
+ registry=registry,
1155
+ lib_sources=lib_sources,
1156
+ check=bool(args.check),
1157
+ providers=providers,
1158
+ )
1159
+
1160
+ if result.fatal is not None:
1161
+ print(f"error: {result.fatal}", file=sys.stderr)
1162
+ return 1
1163
+
1164
+ if not result.files:
1165
+ print("metaobjects fmt — no metadata files to format.")
1166
+ return 0
1167
+
1168
+ for report in result.files:
1169
+ print(_describe_fmt_report(report, cwd))
1170
+
1171
+ errored = sum(1 for r in result.files if r.status == fmt.STATUS_ERROR)
1172
+ needs_format = sum(1 for r in result.files if r.status == fmt.STATUS_WOULD_FORMAT)
1173
+ reformatted = sum(1 for r in result.files if r.status == fmt.STATUS_FORMATTED)
1174
+
1175
+ if args.check:
1176
+ if needs_format or errored:
1177
+ suffix = f", {errored} error(s)" if errored else ""
1178
+ print(
1179
+ f"metaobjects fmt --check — {needs_format} file(s) not canonical{suffix}. "
1180
+ "Run `metaobjects fmt` to fix.",
1181
+ file=sys.stderr,
1182
+ )
1183
+ return 1
1184
+ print("metaobjects fmt --check — every file is already canonical.")
1185
+ return 0
1186
+
1187
+ if errored:
1188
+ print(
1189
+ f"metaobjects fmt — {errored} file(s) could not be formatted safely (left unchanged).",
1190
+ file=sys.stderr,
1191
+ )
1192
+ return 1
1193
+
1194
+ print(f"metaobjects fmt — {reformatted} file(s) reformatted.")
1195
+ return 0
1196
+
1197
+
1072
1198
  def _cmd_eject(args: argparse.Namespace) -> int:
1073
1199
  """Copy reference generators into ``codegen/generators/`` to own (ADR-0034 Am. 3)."""
1074
1200
  root = Path(args.root) if args.root else Path.cwd()
@@ -1612,6 +1738,32 @@ def _diff_report(
1612
1738
  return 1
1613
1739
 
1614
1740
 
1741
+
1742
+ def _no_generators_selected(out_dir: str) -> int:
1743
+ """``verify --codegen`` with nothing selected: pass only if nothing would go unchecked.
1744
+
1745
+ There is no default suite (1.0.4), so with no ``--generators`` nothing is regenerated.
1746
+ If ``out_dir`` already holds generated files, reporting success would be a false green
1747
+ — a gate written before 1.0.4, relying on the default, silently stopped checking
1748
+ anything. That is an error; an empty or absent ``out_dir`` is not.
1749
+ """
1750
+ committed = [p for p in Path(out_dir).rglob("*.py") if p.name != "__init__.py"] if Path(out_dir).is_dir() else []
1751
+ if committed:
1752
+ print(
1753
+ f"error: verify --codegen: no generators selected, but {out_dir} holds "
1754
+ f"{len(committed)} generated file(s) that would go unchecked. There is no "
1755
+ "default suite: pass --generators <a,b,c> naming the same suite `gen` ran "
1756
+ "(metaobjects gen --list is the catalog).",
1757
+ file=sys.stderr,
1758
+ )
1759
+ return 1
1760
+ print(
1761
+ "verify --codegen: no generators selected and no generated output to check. "
1762
+ "Pass --generators <a,b,c> naming the same suite `gen` ran "
1763
+ "(metaobjects gen --list is the catalog).",
1764
+ )
1765
+ return 0
1766
+
1615
1767
  def _verify_codegen(args: argparse.Namespace) -> int:
1616
1768
  """``verify --codegen`` — regenerate to a temp dir + diff vs committed ``--out``.
1617
1769
 
@@ -1676,12 +1828,7 @@ def _verify_codegen(args: argparse.Namespace) -> int:
1676
1828
  print(f" {msg}", file=sys.stderr)
1677
1829
  return 1
1678
1830
  elif not spec_gens:
1679
- print(
1680
- "verify --codegen: no generators selected, so there is no generated output "
1681
- "to check. Pass --generators <a,b,c> naming the same suite `gen` ran "
1682
- "(metaobjects gen --list is the catalog).",
1683
- )
1684
- return 0
1831
+ return _no_generators_selected(args.out)
1685
1832
 
1686
1833
  with tempfile.TemporaryDirectory() as tmp:
1687
1834
  entities = _parse_entities(getattr(args, "entities", None))
@@ -1767,12 +1914,7 @@ def _verify_codegen_neutral_fallback(args: argparse.Namespace) -> int:
1767
1914
  # Same rule as _verify_codegen: the selection must be named, because there is no
1768
1915
  # default suite to regenerate and diff against.
1769
1916
  if not getattr(args, "generators", None):
1770
- print(
1771
- "verify --codegen: no generators selected, so there is no generated output "
1772
- "to check. Pass --generators <a,b,c> naming the same suite `gen` ran "
1773
- "(metaobjects gen --list is the catalog).",
1774
- )
1775
- return 0
1917
+ return _no_generators_selected(args.out)
1776
1918
  selection, gen_errors = _resolve_generators(
1777
1919
  args.generators, GeneratorBuildContext(_template_root_for(args)))
1778
1920
  if gen_errors:
@@ -2477,6 +2619,31 @@ def _build_parser() -> argparse.ArgumentParser:
2477
2619
  )
2478
2620
  verify.set_defaults(func=_cmd_verify)
2479
2621
 
2622
+ fmt_p = sub.add_parser(
2623
+ "fmt",
2624
+ help="rewrite metadata files into canonical form (#304)",
2625
+ )
2626
+ fmt_p.add_argument(
2627
+ "files",
2628
+ nargs="*",
2629
+ metavar="FILE",
2630
+ help="optional explicit file(s) to format — must be members of this "
2631
+ "project's resolved metadata sources; omit to format every one of them",
2632
+ )
2633
+ fmt_p.add_argument(
2634
+ "--check",
2635
+ action="store_true",
2636
+ help="list files that are not canonical and exit non-zero; changes nothing",
2637
+ )
2638
+ fmt_p.add_argument(
2639
+ "--provider",
2640
+ action="append",
2641
+ default=None,
2642
+ metavar="MODULE:SYMBOL",
2643
+ help="consumer-registered Provider(s), repeatable (module:symbol)",
2644
+ )
2645
+ fmt_p.set_defaults(func=_cmd_fmt)
2646
+
2480
2647
  eject_p = sub.add_parser(
2481
2648
  "eject",
2482
2649
  help="copy reference generators into codegen/generators/ to own and edit",
@@ -38,7 +38,7 @@
38
38
  "generators": {
39
39
  "type": "array",
40
40
  "items": { "type": "string" },
41
- "description": "Stable generator names (see `metaobjects gen --list`). Omit to run the default suite."
41
+ "description": "Stable generator names (see `metaobjects gen --list`). Required: there is no default suite, so a target that names none generates nothing and `verify --codegen` checks nothing."
42
42
  },
43
43
  "entities": {
44
44
  "type": "array",
@@ -0,0 +1,214 @@
1
+ """``metaobjects fmt`` (#304) — rewrite metadata files into the canonical form
2
+ the cross-port canonical serializer already produces. ``--check`` lists files
3
+ that are not canonical and exits non-zero without changing anything.
4
+
5
+ Mirrors the TS reference (``packages/metadata/src/fmt.ts`` +
6
+ ``packages/cli/src/lib/fmt-engine.ts``) and the C#/Java ports exactly:
7
+
8
+ - Each file is formatted STANDALONE — own-mode, declared-here layer only
9
+ (ADR-0039). ``parse_document`` already builds a fresh, unmerged tree per
10
+ document (this port's loader does parse -> merge -> super-resolve as three
11
+ separate steps, unlike TS/C#'s accumulating-root parser) — calling it
12
+ directly and never running ``merge_roots``/``resolve_supers`` is what makes
13
+ a cross-file ``extends`` round-trip untouched (the raw ``super_ref`` string
14
+ is read directly by ``canonical_serialize``, never its resolution) and an
15
+ ``overlay: true`` node never even attempt a merge.
16
+ - An ``overlay: true`` node is tagged (``is_overlay``) by the parser but never
17
+ resolved here — Python's overlay MERGE only happens in ``loader/merge.py``,
18
+ which this module never calls. A file containing one anywhere in its tree
19
+ (detected by :func:`_contains_overlay`) is reported as a skip rather than
20
+ guessed at — the concrete shape of "overlay files stay overlays".
21
+ - YAML is always skipped: no canonical YAML emitter exists (ADR-0006).
22
+ - Before writing, the whole project is reloaded with the candidate
23
+ substituted in via an in-memory source (never touching disk until proven
24
+ safe) and the write is refused unless that reload has no errors AND its
25
+ canonical form is byte-identical to the untouched baseline.
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import json
31
+ from dataclasses import dataclass, field
32
+ from pathlib import Path
33
+ from typing import Callable
34
+
35
+ from metaobjects.errors import MetaError
36
+ from metaobjects.loader.meta_data_loader import MetaDataLoader
37
+ from metaobjects.loader.sources.file_source import FileSource
38
+ from metaobjects.loader.sources.meta_data_source import InMemoryStringSource, MetaDataSource
39
+ from metaobjects.meta.meta_data import MetaData
40
+ from metaobjects.parser import parse_document
41
+ from metaobjects.registry import TypeRegistry
42
+ from metaobjects.serializer_json import canonical_serialize
43
+
44
+ #: Statuses a single file's run can report.
45
+ STATUS_FORMATTED = "formatted"
46
+ STATUS_WOULD_FORMAT = "would-format"
47
+ STATUS_UNCHANGED = "unchanged"
48
+ STATUS_SKIPPED_YAML = "skipped-yaml"
49
+ STATUS_SKIPPED_OVERLAY = "skipped-overlay"
50
+ STATUS_ERROR = "error"
51
+
52
+
53
+ @dataclass
54
+ class FormatFileResult:
55
+ ok: bool
56
+ overlay: bool = False
57
+ text: str | None = None
58
+ message: str | None = None
59
+
60
+
61
+ def _contains_overlay(node: MetaData) -> bool:
62
+ """Whether *node* or any descendant (own children only — this tree was
63
+ never merged, so every child already is its own) carries ``overlay: true``.
64
+ """
65
+ if getattr(node, "is_overlay", False):
66
+ return True
67
+ return any(_contains_overlay(child) for child in node.own_children())
68
+
69
+
70
+ def format_file(content: str, registry: TypeRegistry, source_id: str) -> FormatFileResult:
71
+ """Format one file's own content. Parses *content* standalone via
72
+ :func:`parse_document` — never merged with any other file, super
73
+ resolution never run — and, on a clean parse with no overlay anywhere in
74
+ the tree, returns the canonical serialization of the resulting file root.
75
+ Never raises for a malformed file; that comes back as ``ok=False``.
76
+ """
77
+ # Strip a UTF-8 BOM before parsing — json.loads rejects one outright
78
+ # ("Unexpected UTF-8 BOM (decode using utf-8-sig)"), and Java-authored
79
+ # files often carry one.
80
+ normalized = content[1:] if content.startswith("") else content
81
+ try:
82
+ doc = json.loads(normalized)
83
+ except json.JSONDecodeError as exc:
84
+ return FormatFileResult(ok=False, message=f"invalid JSON: {exc}")
85
+
86
+ try:
87
+ result = parse_document(doc, registry, source_id)
88
+ except Exception as exc: # a few structural failures raise rather than record
89
+ return FormatFileResult(ok=False, message=str(exc))
90
+
91
+ if result.errors:
92
+ message = "; ".join(e.message for e in result.errors)
93
+ return FormatFileResult(ok=False, message=message)
94
+
95
+ if _contains_overlay(result.root):
96
+ return FormatFileResult(
97
+ ok=False,
98
+ overlay=True,
99
+ message="this file declares an overlay fmt cannot resolve standalone",
100
+ )
101
+
102
+ return FormatFileResult(ok=True, text=canonical_serialize(result.root))
103
+
104
+
105
+ @dataclass
106
+ class FileReport:
107
+ path: Path
108
+ status: str
109
+ detail: str | None = None
110
+
111
+
112
+ @dataclass
113
+ class RunResult:
114
+ files: list[FileReport] = field(default_factory=list)
115
+ fatal: str | None = None
116
+
117
+
118
+ def run(
119
+ all_files: list[Path],
120
+ target_files: list[Path],
121
+ file_ids: dict[Path, str],
122
+ registry: TypeRegistry,
123
+ lib_sources: list[MetaDataSource],
124
+ check: bool,
125
+ providers: list[object] | None = None,
126
+ ) -> RunResult:
127
+ """Run fmt over *target_files* (a subset of *all_files* — the project's
128
+ FULL resolved file set, needed for the whole-project safety-check reload
129
+ regardless of which files are in scope to format).
130
+
131
+ *providers* must be the SAME provider list *registry* (used for every
132
+ standalone per-file parse) was composed from — the whole-project baseline
133
+ and safety-check reloads build their own `MetaDataLoader`, which recomposes
134
+ a registry from *providers* itself rather than taking `registry` directly,
135
+ so passing a different set here would silently check two vocabularies
136
+ against each other.
137
+ """
138
+
139
+ def source_id(path: Path) -> str:
140
+ return file_ids.get(path) or path.name
141
+
142
+ def build_sources(
143
+ override_path: Path | None = None, override_text: str | None = None
144
+ ) -> list[MetaDataSource]:
145
+ sources: list[MetaDataSource] = list(lib_sources)
146
+ for p in all_files:
147
+ if override_path is not None and p == override_path:
148
+ sources.append(InMemoryStringSource(override_text or "", id=source_id(p)))
149
+ else:
150
+ sources.append(FileSource(p, id=source_id(p)))
151
+ return sources
152
+
153
+ baseline = MetaDataLoader(providers=providers, strict=False).load(build_sources())
154
+ if baseline.errors:
155
+ detail = "\n".join(f" {e.code}: {e.message}" for e in baseline.errors)
156
+ return RunResult(
157
+ fatal=(
158
+ "this project's metadata does not currently load cleanly — fix the "
159
+ f"error(s) below, then re-run fmt:\n{detail}"
160
+ )
161
+ )
162
+ baseline_canonical = canonical_serialize(baseline.root)
163
+
164
+ reports: list[FileReport] = []
165
+ for path in target_files:
166
+ ext = path.suffix.lower()
167
+ if ext in (".yaml", ".yml"):
168
+ reports.append(
169
+ FileReport(
170
+ path,
171
+ STATUS_SKIPPED_YAML,
172
+ "no canonical YAML emitter exists (ADR-0006: JSON is the canonical "
173
+ "interchange form) — left untouched",
174
+ )
175
+ )
176
+ continue
177
+
178
+ content = path.read_text(encoding="utf-8")
179
+ formatted = format_file(content, registry, source_id(path))
180
+ if not formatted.ok:
181
+ reports.append(
182
+ FileReport(
183
+ path,
184
+ STATUS_SKIPPED_OVERLAY if formatted.overlay else STATUS_ERROR,
185
+ formatted.message,
186
+ )
187
+ )
188
+ continue
189
+
190
+ if formatted.text == content:
191
+ reports.append(FileReport(path, STATUS_UNCHANGED))
192
+ continue
193
+
194
+ test_load = MetaDataLoader(providers=providers, strict=False).load(
195
+ build_sources(path, formatted.text)
196
+ )
197
+ safe = not test_load.errors and canonical_serialize(test_load.root) == baseline_canonical
198
+ if not safe:
199
+ reports.append(
200
+ FileReport(
201
+ path,
202
+ STATUS_ERROR,
203
+ "formatting this file would change the loaded model's meaning — left unchanged",
204
+ )
205
+ )
206
+ continue
207
+
208
+ if check:
209
+ reports.append(FileReport(path, STATUS_WOULD_FORMAT))
210
+ else:
211
+ path.write_text(formatted.text, encoding="utf-8")
212
+ reports.append(FileReport(path, STATUS_FORMATTED))
213
+
214
+ return RunResult(files=reports)
@@ -25,6 +25,7 @@ from metaobjects.render.extract.types import (
25
25
  Format,
26
26
  Normalizer,
27
27
  OnField,
28
+ OnLocate,
28
29
  ExtractOptions,
29
30
  ExtractionOutcome,
30
31
  ExtractSchema,
@@ -45,6 +46,7 @@ __all__ = [
45
46
  "JsonForgivingReader",
46
47
  "Normalizer",
47
48
  "OnField",
49
+ "OnLocate",
48
50
  "ExtractOptions",
49
51
  "ExtractionOutcome",
50
52
  "ExtractSchema",
@@ -38,23 +38,55 @@ def extract(
38
38
  stripped = _strip.strip(text)
39
39
  ci = o.tolerance != Tolerance.STRICT
40
40
 
41
+ # FR-364: the document-level on_locate hook runs BEFORE the default locator. A non-None
42
+ # return is the payload span, fed into the same format-specific forgiving reader a
43
+ # default-located span would be — tolerance/coercion/normalizers/on_field downstream are
44
+ # unaffected. A None return (or no hook) falls through to the default locate strategy
45
+ # unchanged. A raised exception propagates (not swallowed), matching on_field.
46
+ located: str | None = None if o.on_locate is None else o.on_locate(text if text is not None else "", schema.format)
47
+
41
48
  # XML rootless (opts.rootless): the payload's fields ARE the top-level elements — there
42
49
  # is no enclosing root to locate — so parse the whole stripped text's top-level elements
43
50
  # directly. Otherwise locate the <rootName> span as before. JSON is unaffected. Mirrors
44
51
  # Java Extract.extract.
45
52
  span: str | None
46
53
  raw: dict[str, object]
47
- if schema.format == Format.JSON:
54
+ # Whether the SELECTED region (not the original reply) was itself empty/blank — the signal
55
+ # mark_empty() keys on below. For the default path this is the pre-existing "nothing to
56
+ # parse" test (stripped == "" or span is None); for on_locate it must be judged against the
57
+ # hook's OWN return, not the original text — otherwise an empty located span (e.g. the hook
58
+ # deliberately returning "") reports "not empty" while every field is LOST, because the
59
+ # original reply was non-blank even though the thing on_locate chose to parse was.
60
+ region_blank: bool
61
+ if located is not None:
62
+ span = located
63
+ if schema.format == Format.JSON:
64
+ raw = JsonForgivingReader().read(located)
65
+ elif o.rootless:
66
+ raw = XmlForgivingReader().read_rootless(located, ci)
67
+ else:
68
+ raw = XmlForgivingReader().read(located, ci)
69
+ # `from_` is deliberately left empty rather than the original text: a document-level
70
+ # audit entry that copied the whole raw reply (which can be arbitrarily large) into the
71
+ # report on every call would make the report itself heavy for no benefit `to`'s length
72
+ # doesn't already give. `to` is the located span's LENGTH, not the span text, for the
73
+ # same reason.
74
+ report.add_coercion(Coercion("", "", str(len(located)), "onLocate"))
75
+ region_blank = located.strip() == ""
76
+ elif schema.format == Format.JSON:
48
77
  span = _select_json(text, stripped, schema.fields, ci)
49
78
  raw = {} if span is None else JsonForgivingReader().read(span)
79
+ region_blank = stripped == "" or span is None
50
80
  elif o.rootless:
51
81
  span = None if stripped == "" else stripped
52
82
  raw = {} if span is None else XmlForgivingReader().read_rootless(stripped, ci)
83
+ region_blank = stripped == "" or span is None
53
84
  else:
54
85
  span = _locate.xml(stripped, schema.root_name, ci)
55
86
  raw = {} if span is None else XmlForgivingReader().read(span, ci)
87
+ region_blank = stripped == "" or span is None
56
88
 
57
- if not raw and (stripped == "" or span is None):
89
+ if not raw and region_blank:
58
90
  report.mark_empty()
59
91
 
60
92
  _extract(schema.fields, raw, "", data, report, o, ci)
@@ -27,6 +27,17 @@ T = TypeVar("T")
27
27
  OnField = Callable[[str, str, "FieldSpec"], object | None]
28
28
  Normalizer = Callable[[str], object | None]
29
29
 
30
+ # FR-364: the document-level locate hook: (text, format) -> payload substring | None.
31
+ # Receives the RAW reply text (never None; an absent document is normalized to ``""``
32
+ # before the hook runs) and the schema's declared ``Format``. Returning ``None`` falls
33
+ # back to the default locator (the fenced-then-first-object rule #363 fixed). A non-None
34
+ # return is parsed by the normal pipeline exactly like a default-located span —
35
+ # tolerance, coercion, ``normalizers``, and ``on_field`` downstream are unaffected — so
36
+ # this hook only decides WHICH text is the payload, never how it is parsed. The returned
37
+ # text need not be a literal substring of the input (the hook may synthesize it). A
38
+ # raised exception propagates (it is not swallowed), matching ``on_field``.
39
+ OnLocate = Callable[[str, "Format"], "str | None"]
40
+
30
41
 
31
42
  class Format(Enum):
32
43
  """Document format the extract pipeline targets."""
@@ -248,7 +259,8 @@ class ExtractOptions:
248
259
  """Bounded runtime override surface (the "20%").
249
260
 
250
261
  ``aliases``/``normalizers`` are MERGED with the schema's, runtime winning on key
251
- conflict. ``on_field`` is the single bespoke-coercion hook.
262
+ conflict. ``on_field`` is the single per-field bespoke-coercion hook; ``on_locate``
263
+ is the single document-level (payload-location) hook.
252
264
 
253
265
  ``rootless`` (XML only): when ``True``, the input has NO enclosing root element —
254
266
  the payload's fields ARE the top-level elements (a flat sequence like
@@ -259,6 +271,7 @@ class ExtractOptions:
259
271
  aliases: dict[str, str] = field(default_factory=dict)
260
272
  normalizers: dict[str, Normalizer] = field(default_factory=dict)
261
273
  on_field: OnField | None = None
274
+ on_locate: OnLocate | None = None
262
275
  rootless: bool = False
263
276
 
264
277
  @staticmethod
@@ -271,6 +284,19 @@ class ExtractOptions:
271
284
  aliases=dict(self.aliases),
272
285
  normalizers=dict(self.normalizers),
273
286
  on_field=self.on_field,
287
+ on_locate=self.on_locate,
288
+ rootless=self.rootless,
289
+ )
290
+
291
+ def with_on_locate(self, hook: OnLocate | None) -> "ExtractOptions":
292
+ """The single document-level locate hook. See ``OnLocate``. Returns a copy
293
+ with ``on_locate`` set."""
294
+ return ExtractOptions(
295
+ tolerance=self.tolerance,
296
+ aliases=dict(self.aliases),
297
+ normalizers=dict(self.normalizers),
298
+ on_field=self.on_field,
299
+ on_locate=hook,
274
300
  rootless=self.rootless,
275
301
  )
276
302
 
@@ -282,6 +308,7 @@ class ExtractOptions:
282
308
  aliases=dict(self.aliases),
283
309
  normalizers=dict(self.normalizers),
284
310
  on_field=self.on_field,
311
+ on_locate=self.on_locate,
285
312
  rootless=r,
286
313
  )
287
314
 
@@ -495,3 +495,22 @@ def test_prompts_and_templates_root_are_the_same_flag(tmp_path: Path) -> None:
495
495
  rc = main(["verify", "--codegen", "--generators", GEN_SUITE, str(root / "meta"), "--out", str(out),
496
496
  "--prompts", str(root / "no-such-dir")])
497
497
  assert rc != 0, "--prompts value was ignored — a missing dir still regenerated the spec files"
498
+
499
+
500
+ # `verify --codegen` with no --generators used to print a note and exit 0. Since 1.0.4
501
+ # there is no default suite, so a CI step written before then — naming no generators
502
+ # because the default used to be implied — regenerated nothing and passed while the
503
+ # committed output went unchecked (found upgrading an adopter: 159 generated files, gate
504
+ # green). With committed generated output present and nothing selected, it now fails.
505
+ def test_verify_without_generators_fails_when_committed_output_would_go_unchecked(tmp_path: Path) -> None:
506
+ meta_dir = _meta_dir(tmp_path)
507
+ out = tmp_path / "out"
508
+ assert main(["gen", "--generators", GEN_SUITE, meta_dir, "--out", str(out)]) == 0
509
+ assert main(["verify", meta_dir, "--out", str(out)]) != 0
510
+
511
+
512
+ def test_verify_without_generators_still_passes_with_no_generated_output(tmp_path: Path) -> None:
513
+ meta_dir = _meta_dir(tmp_path)
514
+ out = tmp_path / "out"
515
+ out.mkdir()
516
+ assert main(["verify", meta_dir, "--out", str(out)]) == 0