metaobjects 0.22.1__tar.gz → 0.23.0__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.
- {metaobjects-0.22.1 → metaobjects-0.23.0}/PKG-INFO +1 -1
- {metaobjects-0.22.1 → metaobjects-0.23.0}/pyproject.toml +1 -1
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/core_types.py +44 -8
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/requirement/meta_requirement.py +44 -8
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/requirement/requirement_constants.py +31 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/documentation.json +4 -4
- metaobjects-0.23.0/src/metaobjects/spec_metamodel/requirement.json +209 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/postgres_container.py +84 -14
- metaobjects-0.22.1/src/metaobjects/spec_metamodel/requirement.json +0 -140
- {metaobjects-0.22.1 → metaobjects-0.23.0}/.gitignore +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/LICENSE +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/README.md +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/hatch_build.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/agent_context/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/agent_context/scaffold.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/apidocs/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/apidocs/api_model.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/apidocs/builder.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/apidocs/naming.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/apidocs/paths.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/apidocs/renderer.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/attr_class_map.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/cli.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/KNOWN_GAPS.md +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/collision_names.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/config.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/extract_delegate_emitter.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/extract_schema_emitter.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/format.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/fr010_field_mapping.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generator_registry.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/entity_model.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/extractor_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/filter_allowlist_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/fr019_shared_enum.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/m2m_codegen.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/output_parser_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/output_prompt_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/payload_vo_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/render_helper_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/router_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/template_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/tph_plan.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/generators/trace_helper_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/instance_artifacts.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/metaobjects-config.schema.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/output_format_spec_emitter.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/overwrite_policy.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/project_config.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/runner.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/runtime/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/runtime/filter_parser.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/template_codegen/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/template_codegen/output_pattern.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/template_codegen/template_data.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/template_codegen/template_spec.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/codegen/type_map.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/datatype.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/documentation/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/documentation/doc_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/documentation/doc_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/documentation/doc_schema.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/errors.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/merge.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/meta_data_loader.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/registered_validation.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/sources/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/sources/directory_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/sources/file_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/sources/meta_data_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/sources/uri_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validate_discriminator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validate_enum_normalize_ambiguity.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validate_field_readonly.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validate_source_escapes.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validate_source_parameter_ref.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validate_source_physical_names.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/loader/validation_passes.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/attr/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/attr/attr_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/attr/meta_attr.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/field/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/field/field_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/field/meta_field.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/identity/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/identity/identity_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/identity/meta_identity.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/index/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/index/index_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/index/meta_index.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/meta_object.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/meta_object_aware.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/object_class_registry.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/object_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/object_extract.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/object/value_object.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/relationship/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/relationship/derive_m2m_fields.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/relationship/meta_relationship.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/relationship/relationship_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/requirement/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/validator/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/validator/validator_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/meta_data.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/meta_root.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/db/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/db/db_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/db/db_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/origin/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/origin/meta_origin.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/origin/origin_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/source/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/source/meta_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/persistence/source/source_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/layout/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/layout/layout_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/layout/meta_layout.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/ui/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/ui/ui_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/view/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/view/meta_view.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/presentation/view/view_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/provider_extends.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/template/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/template/meta_template.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/template/prompt_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/template/template_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/naming_refs.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/parser.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/parser_yaml.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/py.typed +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/registry.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/registry_manifest.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/email_document.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/escapers.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/KNOWN_GAPS.md +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/coerce.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/extract.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/extract_map.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/json_forgiving_reader.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/locate.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/normalize.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/strip.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/types.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/extract/xml_forgiving_reader.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/filesystem_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/prompt/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/prompt/output_format_renderer.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/prompt/output_format_spec.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/prompt/prompt_field.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/prompt/prompt_overrides.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/prompt/prompt_style.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/renderer.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/render/verify.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/runtime/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/runtime/llm_recorder.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/runtime/n2m_resolver.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/runtime/object_manager.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/runtime/tph.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/serializer_json.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/shared/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/shared/base_types.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/shared/separators.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/shared/structural.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/source/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/source/error_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/source/json_path.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/source/semantic_diff.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/source/yaml_positions.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/attr.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/db.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/field.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/identity.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/index.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/layout.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/object.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/origin.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/prompt.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/relationship.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/source.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/template.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/ui-web.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/ui.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/validator.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/spec_metamodel/view.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/super_resolve.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/validation_types.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/yaml_desugar.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/extends/expected/BaseEntity.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/extends/expected/Program.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/extends/meta.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/nested-array/expected/AuthorBrief.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/nested-array/expected/PostBrief.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/nested-array/meta.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/scalars/expected/Metric.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/scalars/expected/Report.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/scalars/meta.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/vanilla/expected/Subscriber.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/golden/vanilla/meta.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_abstract_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_api_docs_builder.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_api_docs_paths.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_config_gen.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_config_verify.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_providers.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_registry.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_staleness_nudge.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_verify_strict.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_cli_verify_subverbs.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_constants_config.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_entity_model.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_enum_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_extends_abstract_field_inheritance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_extract_tier_collision.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_extractor_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_filter_allowlist_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_format.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_fr010_nested_object_prompt.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_fr010_output_codegen.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_fr019_shared_provided_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_generator_extension_seams.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_golden.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_inherit_without_restate_gate.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_inheritance_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_instance_artifacts.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_m2m_codegen.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_origin_nullability.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_output_parser_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_overwrite_policy.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_payload_vo_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_project_config.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_projection_compile.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_render_helper_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_render_helper_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_reverse_finders.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_router_autoset.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_router_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_runner.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_sourceless_projection.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_template_data.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_template_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_template_output_pattern.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_template_scope_helpers.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_template_scope_walk.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_template_spec.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_tph_codegen.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_trace_helper_generator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_type_map.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_validation_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/codegen/test_write_through.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/capabilities.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/conformance-expected-failures.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/conformance_adapter.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/corpus.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/expected_failures.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/fixture_discovery.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/navigator.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_api_docs_cross_port_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_extract_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_extract_object_verdict.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_fr010_loader_attrs.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_fr011_attrs.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_generator_registry_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_object_model_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_provider_composition_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_registry_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_runner_hardfail.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_spec_metamodel_embed.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_strict_attr_load.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_template_codegen_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_template_generator_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/test_yaml_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/conformance/yaml-conformance-expected-failures.json +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/api_contract_assertions.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/api_contract_jsonb_server.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/api_contract_m2m_server.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/api_contract_server.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/generated_jsonb_app.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/generated_m2m_app.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/generated_router_app.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/generated_tph_app.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/meta_ai_trace.yaml +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/normalization.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/query_runner.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/scenarios.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_api_contract.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_api_contract_generated.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_api_contract_jsonb.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_api_contract_m2m.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_api_contract_m2m_generated.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_api_contract_tph_generated.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_generated_router_uuid_pk.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_llm_call_trace.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_normalization.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_query_scenarios.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/integration/test_runtime_return_types.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/loader/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/loader/test_enum_extends_values_conflict.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/loader/test_template_payload_target_210.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/open_closed_proof_test.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_coerce.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_extract.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_extract_map.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_json_forgiving_reader.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_locate.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_model.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_normalize.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_strip.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/extract/test_xml_forgiving_reader.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/prompt/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/prompt/test_output_format_renderer.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_email_document.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_filesystem_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_output_format_renderer_nested.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_output_prompt_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_render_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_render_max_chars.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_verify.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/render/test_verify_conformance.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_fr5c_merge_attribution.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_fr5d_reference_resolution.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_fr5e_database_source_shape.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_json_path.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_semantic_diff.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_source_on_node.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/source/test_yaml_positions.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/test_api_docs_accuracy.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/__init__.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_agent_context_staleness.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_capabilities.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_common_attrs.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_core_types.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_effective_package.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_errors.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_field_enum.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_field_map_validation.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_field_uuid_dbcolumntype.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_fr016_source_name_and_kind_aliases.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_index_lookup.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_llm_recorder.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_loader.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_loader_bom.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_loader_class.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_merge.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_meta_attr.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_meta_data.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_meta_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_module_shortcuts.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_n2m_resolver.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_n2m_resolver_inherited.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_object_manager_autoset_stamping.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_object_manager_uuid_coercion.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_object_manager_write_through.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_one_primary_source.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_parser.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_parser_yaml.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_provider.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_provider_extension.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_registry.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_registry_completeness.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_registry_extend.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_registry_sealed.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_relationship_referential_actions.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_resolution_key.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_runtime_resolution_key_binding.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_serializer.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_shared_constants.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_smoke.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_source_escapes.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_sources.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_strict_child_placement.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_super_resolve.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_template_toolcall.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_template_wrong_subtype_attrs.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_validation_attr_schema.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_validation_filter_values.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_validation_origin_195.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_validation_origin_paths.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_validation_sort_field.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_validation_warnings.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_write_coercion_arrays.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/tests/unit/test_yaml_desugar.py +0 -0
- {metaobjects-0.22.1 → metaobjects-0.23.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: metaobjects
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.23.0
|
|
4
4
|
Summary: Cross-language metadata standard: declare typed entities once, generate idiomatic drift-checked code across languages — Python port.
|
|
5
5
|
Project-URL: Homepage, https://metaobjects.dev
|
|
6
6
|
Project-URL: Repository, https://github.com/metaobjectsdev/metaobjects
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "metaobjects"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.23.0"
|
|
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"
|
|
@@ -64,13 +64,16 @@ from .meta.core.object.object_constants import (
|
|
|
64
64
|
from .meta.core.relationship.meta_relationship import MetaRelationship
|
|
65
65
|
from .meta.core.requirement.meta_requirement import MetaRequirement
|
|
66
66
|
from .meta.core.requirement.requirement_constants import (
|
|
67
|
+
REQUIREMENT_ATTR_DISPOSITION,
|
|
67
68
|
REQUIREMENT_ATTR_IMPLEMENTED_BY,
|
|
68
69
|
REQUIREMENT_ATTR_LEVEL,
|
|
69
70
|
REQUIREMENT_ATTR_STATEMENT,
|
|
70
71
|
REQUIREMENT_ATTR_STATUS,
|
|
71
72
|
REQUIREMENT_ATTR_SUPERSEDED_BY,
|
|
73
|
+
REQUIREMENT_ATTR_TRACKED_BY,
|
|
72
74
|
REQUIREMENT_ATTR_VERIFIED_BY,
|
|
73
75
|
REQUIREMENT_ATTR_VIOLATION,
|
|
76
|
+
REQUIREMENT_DISPOSITIONS,
|
|
74
77
|
REQUIREMENT_STATUSES,
|
|
75
78
|
REQUIREMENT_SUBTYPE_ARCHITECTURAL,
|
|
76
79
|
REQUIREMENT_SUBTYPE_FUNCTIONAL,
|
|
@@ -589,6 +592,23 @@ _REQUIREMENT_COMMON_ATTRS = [
|
|
|
589
592
|
required=True,
|
|
590
593
|
allowed_values=REQUIREMENT_STATUSES,
|
|
591
594
|
),
|
|
595
|
+
# What was DECIDED about the outstanding work -- a different question from
|
|
596
|
+
# whether the work is done, which is what @status answers. ABSENT means
|
|
597
|
+
# UNDECIDED, a real state and the one a review exists to find.
|
|
598
|
+
AttrSchema(
|
|
599
|
+
name=REQUIREMENT_ATTR_DISPOSITION,
|
|
600
|
+
value_type=ATTR_SUBTYPE_STRING,
|
|
601
|
+
required=False,
|
|
602
|
+
allowed_values=REQUIREMENT_DISPOSITIONS,
|
|
603
|
+
),
|
|
604
|
+
# Issue/ticket references for outstanding work. Free-form and never resolved:
|
|
605
|
+
# verify has no network, so unlike @verifiedBy nothing here is checked to exist.
|
|
606
|
+
AttrSchema(
|
|
607
|
+
name=REQUIREMENT_ATTR_TRACKED_BY,
|
|
608
|
+
value_type=ATTR_SUBTYPE_STRING,
|
|
609
|
+
required=False,
|
|
610
|
+
is_array=True,
|
|
611
|
+
),
|
|
592
612
|
AttrSchema(name=REQUIREMENT_ATTR_STATEMENT, value_type=ATTR_SUBTYPE_STRING, required=True),
|
|
593
613
|
AttrSchema(name=REQUIREMENT_ATTR_VIOLATION, value_type=ATTR_SUBTYPE_STRING, required=True),
|
|
594
614
|
AttrSchema(
|
|
@@ -597,6 +617,12 @@ _REQUIREMENT_COMMON_ATTRS = [
|
|
|
597
617
|
required=False,
|
|
598
618
|
is_array=True,
|
|
599
619
|
),
|
|
620
|
+
AttrSchema(
|
|
621
|
+
name=REQUIREMENT_ATTR_VERIFIED_BY,
|
|
622
|
+
value_type=ATTR_SUBTYPE_STRING,
|
|
623
|
+
required=False,
|
|
624
|
+
is_array=True,
|
|
625
|
+
),
|
|
600
626
|
AttrSchema(name=REQUIREMENT_ATTR_SUPERSEDED_BY, value_type=ATTR_SUBTYPE_STRING, required=False),
|
|
601
627
|
]
|
|
602
628
|
core_provider.add(
|
|
@@ -605,14 +631,10 @@ core_provider.add(
|
|
|
605
631
|
sub_type=REQUIREMENT_SUBTYPE_FUNCTIONAL,
|
|
606
632
|
factory=MetaRequirement,
|
|
607
633
|
attrs=[
|
|
634
|
+
# REQUIRED on functional: levels are the object-in-focus decomposition
|
|
635
|
+
# and a functional requirement always sits at one.
|
|
608
636
|
AttrSchema(name=REQUIREMENT_ATTR_LEVEL, value_type=ATTR_SUBTYPE_INT, required=True),
|
|
609
637
|
*_REQUIREMENT_COMMON_ATTRS,
|
|
610
|
-
AttrSchema(
|
|
611
|
-
name=REQUIREMENT_ATTR_VERIFIED_BY,
|
|
612
|
-
value_type=ATTR_SUBTYPE_STRING,
|
|
613
|
-
required=False,
|
|
614
|
-
is_array=True,
|
|
615
|
-
),
|
|
616
638
|
],
|
|
617
639
|
child_rules=[
|
|
618
640
|
ChildRule(TYPE_ATTR, "*"),
|
|
@@ -626,8 +648,22 @@ core_provider.add(
|
|
|
626
648
|
type=TYPE_REQUIREMENT,
|
|
627
649
|
sub_type=REQUIREMENT_SUBTYPE_ARCHITECTURAL,
|
|
628
650
|
factory=MetaRequirement,
|
|
629
|
-
attrs=
|
|
630
|
-
|
|
651
|
+
attrs=[
|
|
652
|
+
# OPTIONAL on architectural: absent means a flat, object-independent
|
|
653
|
+
# policy (the original and still the default form); present opts the
|
|
654
|
+
# node into a levelled tree, e.g. a quality taxonomy over the
|
|
655
|
+
# non-functional set. Opt-in precisely so that adding a taxonomy over
|
|
656
|
+
# existing flat policies cannot invalidate them.
|
|
657
|
+
AttrSchema(name=REQUIREMENT_ATTR_LEVEL, value_type=ATTR_SUBTYPE_INT, required=False),
|
|
658
|
+
*_REQUIREMENT_COMMON_ATTRS,
|
|
659
|
+
],
|
|
660
|
+
child_rules=[
|
|
661
|
+
ChildRule(TYPE_ATTR, "*"),
|
|
662
|
+
# BOTH subtypes nest. Declaring this on `functional` only was an
|
|
663
|
+
# omission, not a design: it made an architectural node nestable under
|
|
664
|
+
# a FUNCTIONAL parent but never under another architectural one.
|
|
665
|
+
ChildRule(TYPE_REQUIREMENT, "*"),
|
|
666
|
+
],
|
|
631
667
|
)
|
|
632
668
|
)
|
|
633
669
|
|
{metaobjects-0.22.1 → metaobjects-0.23.0}/src/metaobjects/meta/core/requirement/meta_requirement.py
RENAMED
|
@@ -9,12 +9,16 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
from ...meta_data import MetaData
|
|
11
11
|
from .requirement_constants import (
|
|
12
|
+
REQUIREMENT_ATTR_DISPOSITION,
|
|
12
13
|
REQUIREMENT_ATTR_IMPLEMENTED_BY,
|
|
13
14
|
REQUIREMENT_ATTR_LEVEL,
|
|
14
15
|
REQUIREMENT_ATTR_STATUS,
|
|
16
|
+
REQUIREMENT_ATTR_TRACKED_BY,
|
|
15
17
|
REQUIREMENT_ATTR_VERIFIED_BY,
|
|
16
18
|
REQUIREMENT_LINK_FLOOR_LEVEL,
|
|
19
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
17
20
|
REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES,
|
|
21
|
+
REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK,
|
|
18
22
|
REQUIREMENT_SUBTYPE_ARCHITECTURAL,
|
|
19
23
|
REQUIREMENT_SUBTYPE_FUNCTIONAL,
|
|
20
24
|
)
|
|
@@ -31,8 +35,9 @@ class MetaRequirement(MetaData):
|
|
|
31
35
|
|
|
32
36
|
def level(self) -> int | None:
|
|
33
37
|
"""ADR-0039: resolving. 1 solution · 2 segment · 3 service · 4 object ·
|
|
34
|
-
5 member.
|
|
35
|
-
object-independent
|
|
38
|
+
5 member. REQUIRED on functional; OPTIONAL on architectural, where absent
|
|
39
|
+
means a flat object-independent policy and present opts the node into a
|
|
40
|
+
levelled tree (e.g. a quality taxonomy over the non-functional set)."""
|
|
36
41
|
v = self.get_meta_attr(REQUIREMENT_ATTR_LEVEL)
|
|
37
42
|
return v if isinstance(v, int) and not isinstance(v, bool) else None
|
|
38
43
|
|
|
@@ -53,15 +58,46 @@ class MetaRequirement(MetaData):
|
|
|
53
58
|
v = self.get_meta_attr(REQUIREMENT_ATTR_VERIFIED_BY)
|
|
54
59
|
return [str(x) for x in v] if isinstance(v, list) else []
|
|
55
60
|
|
|
61
|
+
def disposition(self) -> str | None:
|
|
62
|
+
"""ADR-0039: resolving. What was DECIDED about the outstanding work — a
|
|
63
|
+
different question from whether the work is done, which is what
|
|
64
|
+
``status`` answers. ``None`` means UNDECIDED, a real state and the one a
|
|
65
|
+
review exists to find."""
|
|
66
|
+
v = self.get_meta_attr(REQUIREMENT_ATTR_DISPOSITION)
|
|
67
|
+
return v if isinstance(v, str) else None
|
|
68
|
+
|
|
69
|
+
def tracked_by(self) -> list[str]:
|
|
70
|
+
"""ADR-0039: resolving. Issue/ticket references for outstanding work.
|
|
71
|
+
Free-form and NEVER resolved — verify has no network, so unlike
|
|
72
|
+
``verified_by`` nothing here is checked to exist."""
|
|
73
|
+
v = self.get_meta_attr(REQUIREMENT_ATTR_TRACKED_BY)
|
|
74
|
+
return [str(x) for x in v] if isinstance(v, list) else []
|
|
75
|
+
|
|
76
|
+
def is_planned(self) -> bool:
|
|
77
|
+
"""Intended but not built. Its nodes may legitimately not exist yet, and
|
|
78
|
+
it must NOT count toward object coverage — planning a capability cannot
|
|
79
|
+
be allowed to silence the warning that nothing implements it."""
|
|
80
|
+
return self.status() == REQUIREMENT_STATUS_PLANNED
|
|
81
|
+
|
|
82
|
+
def has_outstanding_work(self) -> bool:
|
|
83
|
+
"""True when there is outstanding work, so a ``disposition`` says
|
|
84
|
+
something."""
|
|
85
|
+
s = self.status()
|
|
86
|
+
return s is not None and s in REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK
|
|
87
|
+
|
|
56
88
|
def may_reference_model(self) -> bool:
|
|
57
89
|
"""True when this requirement is permitted to reference the model at all.
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
90
|
+
|
|
91
|
+
An UNLEVELLED architectural requirement always may — its claim set is the
|
|
92
|
+
whole point, and that is the original flat form. Once a level is PRESENT
|
|
93
|
+
the node has opted into a tree, and the link floor applies to it exactly
|
|
94
|
+
as it does to a functional one, so an "ISO 25010 Security" grouping node
|
|
95
|
+
cannot quietly start naming entities. Levelling is the opt-in; enforcing
|
|
96
|
+
the floor unconditionally would have broken every existing flat policy."""
|
|
63
97
|
lvl = self.level()
|
|
64
|
-
|
|
98
|
+
if lvl is None:
|
|
99
|
+
return self.is_architectural()
|
|
100
|
+
return lvl >= REQUIREMENT_LINK_FLOOR_LEVEL
|
|
65
101
|
|
|
66
102
|
def requires_live_nodes(self) -> bool:
|
|
67
103
|
"""True when a dangling ``@implementedBy`` is an ERROR rather than
|
|
@@ -26,6 +26,8 @@ REQUIREMENT_SUBTYPES = (
|
|
|
26
26
|
#: 1 solution · 2 segment (app/library) · 3 service · 4 object · 5 member.
|
|
27
27
|
REQUIREMENT_ATTR_LEVEL = "level"
|
|
28
28
|
REQUIREMENT_ATTR_STATUS = "status"
|
|
29
|
+
REQUIREMENT_ATTR_DISPOSITION = "disposition"
|
|
30
|
+
REQUIREMENT_ATTR_TRACKED_BY = "trackedBy"
|
|
29
31
|
REQUIREMENT_ATTR_STATEMENT = "statement"
|
|
30
32
|
REQUIREMENT_ATTR_VIOLATION = "violation"
|
|
31
33
|
REQUIREMENT_ATTR_IMPLEMENTED_BY = "implementedBy"
|
|
@@ -35,12 +37,17 @@ REQUIREMENT_ATTR_SUPERSEDED_BY = "supersededBy"
|
|
|
35
37
|
# ---------------------------------------------------------------------------
|
|
36
38
|
# Status — a closed enum, enforced by the registry via allowed_values.
|
|
37
39
|
# ---------------------------------------------------------------------------
|
|
40
|
+
# Intended but not built. Its references may legitimately dangle, and it never
|
|
41
|
+
# contributes to object coverage -- planning a capability must not silence the
|
|
42
|
+
# warning that nothing implements it.
|
|
43
|
+
REQUIREMENT_STATUS_PLANNED = "planned"
|
|
38
44
|
REQUIREMENT_STATUS_LIVE = "live"
|
|
39
45
|
REQUIREMENT_STATUS_PARTIAL = "partial"
|
|
40
46
|
REQUIREMENT_STATUS_ABANDONED = "abandoned"
|
|
41
47
|
REQUIREMENT_STATUS_SUPERSEDED = "superseded"
|
|
42
48
|
|
|
43
49
|
REQUIREMENT_STATUSES = (
|
|
50
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
44
51
|
REQUIREMENT_STATUS_LIVE,
|
|
45
52
|
REQUIREMENT_STATUS_PARTIAL,
|
|
46
53
|
REQUIREMENT_STATUS_ABANDONED,
|
|
@@ -59,6 +66,30 @@ REQUIREMENT_STATUSES_REQUIRING_LIVE_NODES = (
|
|
|
59
66
|
# ---------------------------------------------------------------------------
|
|
60
67
|
# Levels — organisational above the link floor, model-referencing at or below.
|
|
61
68
|
# ---------------------------------------------------------------------------
|
|
69
|
+
# Statuses with outstanding work, so a @disposition is meaningful on them. On any
|
|
70
|
+
# other status the decision IS the status, and recording a second one can only
|
|
71
|
+
# agree with it or contradict it.
|
|
72
|
+
REQUIREMENT_STATUSES_WITH_OUTSTANDING_WORK = (
|
|
73
|
+
REQUIREMENT_STATUS_PLANNED,
|
|
74
|
+
REQUIREMENT_STATUS_PARTIAL,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# Disposition -- what was DECIDED about the outstanding work. Orthogonal to
|
|
79
|
+
# status, which says whether the work is done. ABSENT means UNDECIDED, and that
|
|
80
|
+
# is the state a review exists to find; collapsing it into the status enum would
|
|
81
|
+
# make "there is a gap" and "we chose to live with it" the same fact.
|
|
82
|
+
# ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
REQUIREMENT_DISPOSITION_ACCEPTED = "accepted"
|
|
85
|
+
REQUIREMENT_DISPOSITION_DEFERRED = "deferred"
|
|
86
|
+
|
|
87
|
+
# Declaration order is contractual -- see REQUIREMENT_STATUSES.
|
|
88
|
+
REQUIREMENT_DISPOSITIONS = (
|
|
89
|
+
REQUIREMENT_DISPOSITION_ACCEPTED,
|
|
90
|
+
REQUIREMENT_DISPOSITION_DEFERRED,
|
|
91
|
+
)
|
|
92
|
+
|
|
62
93
|
REQUIREMENT_LEVEL_SOLUTION = 1
|
|
63
94
|
REQUIREMENT_LEVEL_SEGMENT = 2
|
|
64
95
|
REQUIREMENT_LEVEL_SERVICE = 3
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"name": "description",
|
|
13
13
|
"min": 0,
|
|
14
14
|
"max": 1,
|
|
15
|
-
"description": "
|
|
15
|
+
"description": "What this element IS and COVERS, written for someone using it. Markdown allowed, multi-line via YAML '|' block scalar. Flows into doc-gen surfaces (JSDoc / XML-doc / Postgres COMMENT / Mermaid prose). State scope and boundary — what it covers, what it deliberately does NOT, and which sibling owns the rest — all of which is derivable from the model itself. Anything you had to read the implementation to learn belongs in @notes, not here."
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
18
|
"type": "attr",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"name": "summary",
|
|
21
21
|
"min": 0,
|
|
22
22
|
"max": 1,
|
|
23
|
-
"description": "Short single-line
|
|
23
|
+
"description": "Short single-line SENTENCE (OpenAPI `summary` pattern) — used in index tables, sidebar previews, and AI prompts where the full @description is too long. Distinct from @title, which is a noun label rather than a sentence. When @summary is unset, doc surfaces typically fall back to the first sentence of @description."
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"type": "attr",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"name": "title",
|
|
29
29
|
"min": 0,
|
|
30
30
|
"max": 1,
|
|
31
|
-
"description": "Short single-line human label (e.g. 'Email' for a `field.string email`).
|
|
31
|
+
"description": "Short single-line human label — a NOUN PHRASE naming the element (e.g. 'Email' for a `field.string email`), never a sentence. What a tab, an index row or a sidebar shows when the name is an identifier rather than a label. See @summary for the one-line sentence form."
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
34
|
"type": "attr",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"name": "notes",
|
|
37
37
|
"min": 0,
|
|
38
38
|
"max": 1,
|
|
39
|
-
"description": "Internal-only rationale
|
|
39
|
+
"description": "Internal-only rationale, never emitted to user-facing docs — the slot for what you had to look OUTSIDE the model to learn: evidence, measurements, citations, the control that proved an absence was real, and what breaks if this changes. It is NOT a longer @description, and restating the description here is the failure mode this slot invites. Mechanical test: a sentence belongs in @notes exactly when it would have to change because the IMPLEMENTATION changed while the model did not."
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"type": "attr",
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
{
|
|
2
|
+
"provider": "metaobjects-core-types",
|
|
3
|
+
"types": [
|
|
4
|
+
{
|
|
5
|
+
"type": "requirement",
|
|
6
|
+
"subType": "functional",
|
|
7
|
+
"description": "What the product does for a user, stated as one violable claim. Its check is EXISTENCE: it fails when nothing implements it. Hierarchy is nesting — an L1 solution contains its L2 segments, which contain L3 services, and so on down to the levels that reference the model.",
|
|
8
|
+
"whenToUse": "Something exists because someone asked for it. L1-L3 are levels of ABSTRACTION AND OWNERSHIP in the problem domain — whose need is this, and at what altitude — and are never a directory, package, deployable or module. Binding to technical constructs happens only at L4 (an object) and L5 (a member), which is the allocation step. Test every node: if a refactor that changes no behaviour would force it to move, its level is wrong.",
|
|
9
|
+
"children": [
|
|
10
|
+
{
|
|
11
|
+
"type": "attr",
|
|
12
|
+
"subType": "int",
|
|
13
|
+
"name": "level",
|
|
14
|
+
"min": 1,
|
|
15
|
+
"max": 1,
|
|
16
|
+
"description": "1 solution, 2 segment, 3 service, 4 object, 5 member. L1-L3 are levels of abstraction and ownership in the problem domain, NOT of code structure. Nesting depth must agree with it; skipping a level is legal, going back up is not."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"type": "attr",
|
|
20
|
+
"subType": "string",
|
|
21
|
+
"name": "status",
|
|
22
|
+
"min": 1,
|
|
23
|
+
"max": 1,
|
|
24
|
+
"allowedValues": [
|
|
25
|
+
"planned",
|
|
26
|
+
"live",
|
|
27
|
+
"partial",
|
|
28
|
+
"abandoned",
|
|
29
|
+
"superseded"
|
|
30
|
+
],
|
|
31
|
+
"description": "planned intended but not built yet; live implemented and in use; partial implemented with known gaps; abandoned built then deliberately retired; superseded replaced by a different mechanism. A dangling @implementedBy is an ERROR on live/partial (the model moved, the requirement is stale) and ALLOWED on planned/abandoned/superseded — on planned the nodes do not exist YET, on the other two they are meant to be gone, and that is the entry doing its job. A planned requirement also never contributes to object coverage: planning a capability must not silence the warning that nothing implements it."
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "attr",
|
|
35
|
+
"subType": "string",
|
|
36
|
+
"name": "disposition",
|
|
37
|
+
"min": 0,
|
|
38
|
+
"max": 1,
|
|
39
|
+
"allowedValues": [
|
|
40
|
+
"accepted",
|
|
41
|
+
"deferred"
|
|
42
|
+
],
|
|
43
|
+
"description": "What has been DECIDED about outstanding work — a different question from whether the work is done, which is what @status answers. accepted: the gap is understood and deliberately not being closed. deferred: it will be closed, but not now. ABSENT MEANS UNDECIDED, which is a real and useful state — it is what an unreviewed gap looks like, and it is the one a review should be able to find. Meaningful on planned and partial only; on a status with no outstanding work it is a WARNING. Deliberately NOT a workflow vocabulary: which sprint, who owns it and whether it is in progress belong in the tracker named by @trackedBy, because two systems holding that answer will drift and only one of them is refreshed daily."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"type": "attr",
|
|
47
|
+
"subType": "string",
|
|
48
|
+
"name": "trackedBy",
|
|
49
|
+
"isArray": true,
|
|
50
|
+
"min": 0,
|
|
51
|
+
"max": 1,
|
|
52
|
+
"description": "Issue or ticket references for outstanding work — a URL, an owner/repo#123 shorthand, or a tracker key. Free-form and NOT resolved by verify, which does not reach the network; unlike @verifiedBy, nothing here is checked to exist. Its job is to stop a deferred gap becoming invisible, so verify warns when a deferred requirement names no ticket. Also the right place to link the ticket that a planned requirement will be built under."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"type": "attr",
|
|
56
|
+
"subType": "string",
|
|
57
|
+
"name": "statement",
|
|
58
|
+
"min": 1,
|
|
59
|
+
"max": 1,
|
|
60
|
+
"description": "What the capability is, in one sentence."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"type": "attr",
|
|
64
|
+
"subType": "string",
|
|
65
|
+
"name": "violation",
|
|
66
|
+
"min": 1,
|
|
67
|
+
"max": 1,
|
|
68
|
+
"description": "What breaking it looks like, in one sentence. A requirement MUST be violable: 'every entity has a uuid primary key' is (point at one with a composite string key); 'things are persisted' is not, and is a description rather than a requirement."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"type": "attr",
|
|
72
|
+
"subType": "string",
|
|
73
|
+
"name": "implementedBy",
|
|
74
|
+
"isArray": true,
|
|
75
|
+
"min": 0,
|
|
76
|
+
"max": 1,
|
|
77
|
+
"description": "FQN references to the model nodes realising this requirement. Legal on level 4 (an object) and level 5 (a field, view or identity) only; an organisational level carrying it is ERR_REQUIREMENT_LINK_ABOVE_FLOOR. Many-to-many by construction — several requirements may name the same node."
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "attr",
|
|
81
|
+
"subType": "string",
|
|
82
|
+
"name": "verifiedBy",
|
|
83
|
+
"isArray": true,
|
|
84
|
+
"min": 0,
|
|
85
|
+
"max": 1,
|
|
86
|
+
"description": "Names of the tests proving the behaviour. verify checks each exists and is not skipped; it never runs them."
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
"type": "attr",
|
|
90
|
+
"subType": "string",
|
|
91
|
+
"name": "supersededBy",
|
|
92
|
+
"min": 0,
|
|
93
|
+
"max": 1,
|
|
94
|
+
"description": "The requirement that replaced this one. Expected on status=superseded."
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "requirement",
|
|
98
|
+
"subType": "*",
|
|
99
|
+
"name": "*",
|
|
100
|
+
"min": 0,
|
|
101
|
+
"max": null,
|
|
102
|
+
"description": "Nested child requirements. Hierarchy IS nesting — an L1 solution contains its L2 segments, which contain L3 services — so regrouping moves a node rather than editing a parent string, and a requirement is addressable by the same dotted child-name path as every other node."
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"type": "requirement",
|
|
108
|
+
"subType": "architectural",
|
|
109
|
+
"description": "How the system is built, applied uniformly across the model. Its check is UNIVERSALITY: it fails when something VIOLATES it, which is the opposite polarity to a functional requirement. Flat by default and object-independent; it may optionally sit in a levelled tree when a quality taxonomy is being used to organise non-functional requirements.",
|
|
110
|
+
"whenToUse": "Something exists because every entity here looks like this — a uuid primary key, an @autoSet createdAt, a change-attribution column, tenant scoping. The discriminator is mechanical: did this exist because someone asked for something, or because it is the architecture? For a non-functional tree, an established quality taxonomy makes a good fixed upper structure (e.g. an ISO/IEC 25010 characteristic at L1, its sub-characteristic or a control-catalogue category at L2), with the model-binding claims at L4 and L5 as usual.",
|
|
111
|
+
"children": [
|
|
112
|
+
{
|
|
113
|
+
"type": "attr",
|
|
114
|
+
"subType": "int",
|
|
115
|
+
"name": "level",
|
|
116
|
+
"min": 0,
|
|
117
|
+
"max": 1,
|
|
118
|
+
"description": "OPTIONAL here, unlike on a functional requirement where it is required. ABSENT means a flat, object-independent policy that may reference the model directly — the original and still the default form. PRESENT means this node sits in a levelled tree, and then the same rules as functional apply: nesting must agree with the level, and only L4/L5 may carry @implementedBy. Levelling is opt-in so that adding a taxonomy on top of existing flat policies does not invalidate them."
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"type": "attr",
|
|
122
|
+
"subType": "string",
|
|
123
|
+
"name": "status",
|
|
124
|
+
"min": 1,
|
|
125
|
+
"max": 1,
|
|
126
|
+
"allowedValues": [
|
|
127
|
+
"planned",
|
|
128
|
+
"live",
|
|
129
|
+
"partial",
|
|
130
|
+
"abandoned",
|
|
131
|
+
"superseded"
|
|
132
|
+
],
|
|
133
|
+
"description": "As on requirement.functional. A live or partial architectural requirement claimed by NOTHING is an error: a policy declared and applied to nothing. A planned one is exempt from that check — it is not applied yet by definition."
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"type": "attr",
|
|
137
|
+
"subType": "string",
|
|
138
|
+
"name": "disposition",
|
|
139
|
+
"min": 0,
|
|
140
|
+
"max": 1,
|
|
141
|
+
"allowedValues": [
|
|
142
|
+
"accepted",
|
|
143
|
+
"deferred"
|
|
144
|
+
],
|
|
145
|
+
"description": "As on requirement.functional. On an architectural requirement, accepted is the common and important case: a policy that is genuinely not universal, where the exceptions are known and tolerated, is more honest as partial+accepted than as a live claim nobody audits."
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"type": "attr",
|
|
149
|
+
"subType": "string",
|
|
150
|
+
"name": "trackedBy",
|
|
151
|
+
"isArray": true,
|
|
152
|
+
"min": 0,
|
|
153
|
+
"max": 1,
|
|
154
|
+
"description": "As on requirement.functional. Issue or ticket references for outstanding work; free-form, not resolved."
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": "attr",
|
|
158
|
+
"subType": "string",
|
|
159
|
+
"name": "statement",
|
|
160
|
+
"min": 1,
|
|
161
|
+
"max": 1,
|
|
162
|
+
"description": "The policy, in one sentence."
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"type": "attr",
|
|
166
|
+
"subType": "string",
|
|
167
|
+
"name": "violation",
|
|
168
|
+
"min": 1,
|
|
169
|
+
"max": 1,
|
|
170
|
+
"description": "What breaking it looks like — the node that would contradict it. This is what makes universality checkable."
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"type": "attr",
|
|
174
|
+
"subType": "string",
|
|
175
|
+
"name": "implementedBy",
|
|
176
|
+
"isArray": true,
|
|
177
|
+
"min": 0,
|
|
178
|
+
"max": 1,
|
|
179
|
+
"description": "FQN references to the nodes applying this policy. High fan-out is normal and expected: one uuid-primary-key requirement is claimed by every entity."
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"type": "attr",
|
|
183
|
+
"subType": "string",
|
|
184
|
+
"name": "verifiedBy",
|
|
185
|
+
"isArray": true,
|
|
186
|
+
"min": 0,
|
|
187
|
+
"max": 1,
|
|
188
|
+
"description": "Names of the tests proving the policy holds. verify checks each exists and is not skipped; it never runs them."
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"type": "attr",
|
|
192
|
+
"subType": "string",
|
|
193
|
+
"name": "supersededBy",
|
|
194
|
+
"min": 0,
|
|
195
|
+
"max": 1,
|
|
196
|
+
"description": "The requirement that replaced this one. Expected on status=superseded."
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"type": "requirement",
|
|
200
|
+
"subType": "*",
|
|
201
|
+
"name": "*",
|
|
202
|
+
"min": 0,
|
|
203
|
+
"max": null,
|
|
204
|
+
"description": "Nested child requirements. Present so a non-functional tree can be organised by a quality taxonomy the same way a functional tree is organised by capability — the absence of this rule, while requirement.functional had it, is what previously made an architectural node nestable UNDER a functional one but never under another architectural one."
|
|
205
|
+
}
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
@@ -42,6 +42,9 @@ class PostgresContainer:
|
|
|
42
42
|
"""Context manager around ``docker run`` for a per-scenario Postgres."""
|
|
43
43
|
|
|
44
44
|
IMAGE = "postgres:16-alpine"
|
|
45
|
+
|
|
46
|
+
#: Fresh-port retries before giving up -- see the port-race note in __init__.
|
|
47
|
+
START_ATTEMPTS = 3
|
|
45
48
|
USER = "postgres"
|
|
46
49
|
PASSWORD = "test"
|
|
47
50
|
DATABASE = "postgres"
|
|
@@ -57,19 +60,45 @@ class PostgresContainer:
|
|
|
57
60
|
self._shared = False
|
|
58
61
|
self._admin_url = None
|
|
59
62
|
self._name = f"metaobjects-test-{uuid.uuid4().hex[:8]}"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
# PORT RACE. _pick_free_port() closes its probe socket and hands the number to
|
|
64
|
+
# docker, which binds it LATER -- a check-then-act gap. Alone it never bites;
|
|
65
|
+
# under a full CI run several ports start containers at once and two can be
|
|
66
|
+
# handed the same number. The loser's container is created and then dies, and a
|
|
67
|
+
# readiness probe that only asks `docker exec` cannot tell that from a slow
|
|
68
|
+
# boot. Retry on a FRESH port.
|
|
69
|
+
#
|
|
70
|
+
# Deliberately NOT `--rm`: an auto-removed container takes its logs with it, so
|
|
71
|
+
# the one artefact explaining the failure vanishes exactly when it is needed.
|
|
72
|
+
# close() force-removes, so nothing leaks.
|
|
73
|
+
last_failure: Exception | None = None
|
|
74
|
+
for _attempt in range(self.START_ATTEMPTS):
|
|
75
|
+
self._port = _pick_free_port()
|
|
76
|
+
self._info = PostgresInfo(
|
|
77
|
+
host="localhost", port=self._port, database=self.DATABASE,
|
|
78
|
+
user=self.USER, password=self.PASSWORD,
|
|
79
|
+
)
|
|
80
|
+
try:
|
|
81
|
+
_docker(
|
|
82
|
+
"run", "-d",
|
|
83
|
+
"--name", self._name,
|
|
84
|
+
"-e", f"POSTGRES_PASSWORD={self.PASSWORD}",
|
|
85
|
+
"-p", f"{self._port}:5432",
|
|
86
|
+
self.IMAGE,
|
|
87
|
+
)
|
|
88
|
+
except Exception as e: # noqa: BLE001 — docker refused the bind; retry on a new port
|
|
89
|
+
last_failure = e
|
|
90
|
+
self._force_remove()
|
|
91
|
+
continue
|
|
92
|
+
try:
|
|
93
|
+
self._wait_ready()
|
|
94
|
+
return
|
|
95
|
+
except Exception as e: # noqa: BLE001 — died on startup; retry on a new port
|
|
96
|
+
last_failure = e
|
|
97
|
+
self._force_remove()
|
|
98
|
+
raise RuntimeError(
|
|
99
|
+
f"postgres container '{self._name}' failed to start in "
|
|
100
|
+
f"{self.START_ATTEMPTS} attempts; last err: {last_failure}"
|
|
71
101
|
)
|
|
72
|
-
self._wait_ready()
|
|
73
102
|
|
|
74
103
|
# -- Shared-sidecar mode -------------------------------------------------
|
|
75
104
|
# CREATE a fresh, uniquely-named database on the already-running Postgres
|
|
@@ -138,11 +167,50 @@ class PostgresContainer:
|
|
|
138
167
|
# finishes; mirrors the TS/Java two-phase wait).
|
|
139
168
|
# -----------------------------------------------------------------------
|
|
140
169
|
|
|
170
|
+
# READINESS WINDOW. 30s was too tight: under a FULL local-CI run several ports
|
|
171
|
+
# spin their own Postgres concurrently, and a container that is merely slow to
|
|
172
|
+
# boot produces a red gate indistinguishable from a real failure -- it fires
|
|
173
|
+
# BEFORE any test logic. Raising the bound costs nothing when the container is
|
|
174
|
+
# ready quickly (the loop polls every 250ms and returns immediately) and only
|
|
175
|
+
# changes how long the pathological case takes to give up.
|
|
176
|
+
def _force_remove(self) -> None:
|
|
177
|
+
"""Best-effort teardown between start attempts."""
|
|
178
|
+
try:
|
|
179
|
+
_docker("rm", "-f", self._name)
|
|
180
|
+
except Exception: # noqa: BLE001 — already gone
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
def _inspect_state(self) -> str:
|
|
184
|
+
"""The container's docker state, or 'gone' when it cannot be determined."""
|
|
185
|
+
r = subprocess.run(
|
|
186
|
+
["docker", "inspect", "-f", "{{.State.Status}}", self._name],
|
|
187
|
+
capture_output=True, text=True,
|
|
188
|
+
)
|
|
189
|
+
return r.stdout.strip() if r.returncode == 0 else "gone"
|
|
190
|
+
|
|
191
|
+
def _tail_logs(self) -> str:
|
|
192
|
+
"""Last few log lines, for an error that would otherwise name only a symptom."""
|
|
193
|
+
r = subprocess.run(
|
|
194
|
+
["docker", "logs", "--tail", "40", self._name], capture_output=True, text=True,
|
|
195
|
+
)
|
|
196
|
+
return (r.stdout + r.stderr).strip() if r.returncode == 0 else "(docker logs unavailable)"
|
|
197
|
+
|
|
141
198
|
def _wait_ready(self) -> None:
|
|
142
199
|
import pg8000.dbapi # local import — pg8000 lives in the `integration` extra
|
|
143
|
-
|
|
200
|
+
timeout_s = int(os.environ.get("MO_PG_READY_TIMEOUT_S", "120"))
|
|
201
|
+
deadline = time.monotonic() + timeout_s
|
|
144
202
|
last_err: Exception | None = None
|
|
145
203
|
while time.monotonic() < deadline:
|
|
204
|
+
# FAIL FAST ON A DEAD CONTAINER. `docker exec` alone cannot tell "still
|
|
205
|
+
# booting" from "exited seconds ago" -- both just fail -- so a container that
|
|
206
|
+
# died on startup used to burn the whole window and report a TIMEOUT, which
|
|
207
|
+
# reads as slowness and is not. Ask docker for its state and surface its logs.
|
|
208
|
+
state = self._inspect_state()
|
|
209
|
+
if state != "running":
|
|
210
|
+
raise RuntimeError(
|
|
211
|
+
f"postgres container '{self._name}' is '{state}', not running -- it died "
|
|
212
|
+
f"during startup rather than being slow. docker logs:\n{self._tail_logs()}"
|
|
213
|
+
)
|
|
146
214
|
ready = subprocess.run(
|
|
147
215
|
["docker", "exec", self._name, "pg_isready", "-U", self.USER],
|
|
148
216
|
capture_output=True,
|
|
@@ -159,7 +227,9 @@ class PostgresContainer:
|
|
|
159
227
|
last_err = e
|
|
160
228
|
time.sleep(0.25)
|
|
161
229
|
raise RuntimeError(
|
|
162
|
-
f"postgres container '{self._name}' did not become ready within
|
|
230
|
+
f"postgres container '{self._name}' did not become ready within {timeout_s}s "
|
|
231
|
+
f"(state={self._inspect_state()}); last err: {last_err}. "
|
|
232
|
+
f"docker logs:\n{self._tail_logs()}"
|
|
163
233
|
)
|
|
164
234
|
|
|
165
235
|
|