matrx-orm 3.1.245__tar.gz → 3.1.246__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.
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/PKG-INFO +2 -2
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/associations.py +6 -1
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/transaction.py +26 -2
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/entity.py +2 -1
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/platform_access.py +1 -1
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/items.py +3 -1
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/org_service.py +3 -5
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/service.py +3 -2
- matrx_orm-3.1.246/matrx_orm/secrets_battery/use_stamp.py +27 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/fallback.py +55 -1
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/pyproject.toml +2 -2
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_call_function.py +4 -4
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_db_function_field.py +2 -2
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_deadlock_retry.py +2 -2
- matrx_orm-3.1.246/tests/level1/test_registry_reads_outside_the_person_session.py +49 -0
- matrx_orm-3.1.246/tests/session/test_record_error_group_open.py +152 -0
- matrx_orm-3.1.246/tests/test_a_failed_use_stamp_never_fails_the_read.py +48 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/.gitignore +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/AGENTS.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/CHANGELOG.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/CLAUDE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/MODEL_API.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/docs/migrations.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/admin_lane.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/base.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/foreign_session_state.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/read_write.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/session_context.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/statement_ceiling.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/write_retry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/no_org_assignment.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/catalog_select.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/create.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/pytest_lock_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/pytest_plugin.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/executor.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/resources/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/excluded_targets.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/FEATURE.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/backup_restore.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/host_authorization.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/model.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_enable.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_source.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/vault_history.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/write_actor.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/scripts/release.sh +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/conftest.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_adapter_registry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_association_trigger_actor_naming.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_associations_wiring.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_borrowed_role_never_reaches_server_calls.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_column_scoped_writes.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_committed_row_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_count_limit_param_leak.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fetch_on_init_holds_whole_table.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fk_cycle_resolution.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_guarded_read_never_reruns_empty.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_lock_contention_retry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_org_assignment_inventory.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_percentile_cont.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_persisted_count.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_create_never_wedges.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_read_connection_retry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_read_write_declared.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_standalone_write_session_context.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_sync_pool_declares_read_write.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_transaction_database_identity.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_write_queue_deadline.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/native_source_cases.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/native_source_oracle.rs +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_excluded_fk_targets.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_schema_analysis.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_enum_array_column.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_never_filter_columns.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_a_grouped_update_writes_only_each_rows_own_fields.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_disk_spill_fallback.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_pending_insert_honors_operator_filters.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_record_error_bounded_insert.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_record_error_storm.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_spill_guard_plugin.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_tests_never_write_live_system_error.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_bulk_cache_never_stalls_the_loop.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_keyword_column_refuses_generation.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_list_of_uuids_binds_as_uuid_array.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_sealed_field_shows_no_character_of_its_value.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_array_arg_element_type.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_attachment_mutation_serialization.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_backup_alias_conflict.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_backup_history_restore.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_backup_restore_live.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_call_function_as.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_call_function_none_mode.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_dsn_password_masking.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_dynamic_select_unregistered.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_first_asks_the_database_for_one_row.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_foreign_session_state.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_immutable_insert_or_exact_verify.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_instance_update_runs_expressions.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_keyed_digest.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_enable.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_lifecycle.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_lifecycle_fences.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_passkey_receipts.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_source.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_order_by_desc_nulls_last.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_org_vault_gate.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_package_wiring_views.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_secret_audit_names_its_organization.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_secrets_battery.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_secrets_minting_keys.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_shared_lock_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_state_cache_sweeps_stale.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_statement_ceiling_warning.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_sync_twins_guard.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_update_result_truthiness.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_user_visible_lookup.py +0 -0
- {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: matrx-orm
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.246
|
|
4
4
|
Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching
|
|
5
5
|
Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream-current
|
|
6
6
|
Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream-current
|
|
@@ -26,7 +26,7 @@ Requires-Dist: asyncpg>=0.31.0
|
|
|
26
26
|
Requires-Dist: cbor2<7,>=6.1.3
|
|
27
27
|
Requires-Dist: cryptography>=43.0
|
|
28
28
|
Requires-Dist: gitpython>=3.1.40
|
|
29
|
-
Requires-Dist: matrx-utils>=2.0.
|
|
29
|
+
Requires-Dist: matrx-utils>=2.0.84
|
|
30
30
|
Requires-Dist: psycopg-pool>=3.2.5
|
|
31
31
|
Requires-Dist: psycopg[binary]>=3.2.5
|
|
32
32
|
Requires-Dist: python-dotenv>=1.0
|
|
@@ -71,6 +71,8 @@ from collections.abc import Awaitable, Callable
|
|
|
71
71
|
|
|
72
72
|
from matrx_utils import vcprint
|
|
73
73
|
|
|
74
|
+
from matrx_orm.core.transaction import outside_transaction
|
|
75
|
+
|
|
74
76
|
if TYPE_CHECKING:
|
|
75
77
|
from matrx_orm.core.base import Model
|
|
76
78
|
|
|
@@ -209,7 +211,10 @@ class EntityRegistry:
|
|
|
209
211
|
return self._cache[token]
|
|
210
212
|
model: type[Model] | None = None
|
|
211
213
|
if self._etype_model is not None:
|
|
212
|
-
|
|
214
|
+
# Vocabulary, never person data: read off the caller's session, or a person's RLS
|
|
215
|
+
# hides the row and the miss below is cached for every later caller.
|
|
216
|
+
etype_model = self._etype_model
|
|
217
|
+
row = await outside_transaction(lambda: etype_model.get_or_none(**{self._token_field: token}))
|
|
213
218
|
active = self._active_field is None or getattr(row, self._active_field, True)
|
|
214
219
|
if row is not None and active:
|
|
215
220
|
schema = getattr(row, self._schema_field, None)
|
|
@@ -36,16 +36,19 @@ reuses the connection when present — this behavior is unchanged.
|
|
|
36
36
|
from __future__ import annotations
|
|
37
37
|
|
|
38
38
|
import asyncio
|
|
39
|
+
import contextvars
|
|
39
40
|
import os
|
|
40
41
|
import re
|
|
41
42
|
import uuid
|
|
42
|
-
from collections.abc import AsyncIterator
|
|
43
|
+
from collections.abc import AsyncIterator, Awaitable, Callable
|
|
43
44
|
from contextlib import asynccontextmanager
|
|
44
45
|
from contextvars import ContextVar, Token
|
|
45
|
-
from typing import Any
|
|
46
|
+
from typing import Any, TypeVar
|
|
46
47
|
|
|
47
48
|
from matrx_orm.exceptions import DatabaseError
|
|
48
49
|
|
|
50
|
+
_T = TypeVar("_T")
|
|
51
|
+
|
|
49
52
|
# ContextVar holding the active connection (if any) for the current task tree.
|
|
50
53
|
_active_connection: ContextVar[Any | None] = ContextVar("_active_connection", default=None)
|
|
51
54
|
# The canonical registered database that owns ``_active_connection``. A raw
|
|
@@ -69,6 +72,27 @@ def in_person_scoped_session() -> bool:
|
|
|
69
72
|
_savepoint_depth: ContextVar[int] = ContextVar("_savepoint_depth", default=0)
|
|
70
73
|
|
|
71
74
|
|
|
75
|
+
async def outside_transaction(fn: Callable[[], Awaitable[_T]]) -> _T:
|
|
76
|
+
"""Await ``fn()`` on the process's own connection, outside the caller's transaction.
|
|
77
|
+
|
|
78
|
+
For process-wide VOCABULARY reads (the entity-type registry) whose answer must not
|
|
79
|
+
depend on who is acting: inside ``rls_session`` a person's RLS may hide the row, and a
|
|
80
|
+
cached answer outlives the person. The read runs as its own task with every transaction
|
|
81
|
+
ContextVar at its default, so it never touches (or ends) the caller's pinned connection,
|
|
82
|
+
and the caller's session is unchanged when it returns. Never use it for person data.
|
|
83
|
+
"""
|
|
84
|
+
ctx = contextvars.copy_context()
|
|
85
|
+
|
|
86
|
+
def _clear() -> None:
|
|
87
|
+
_active_connection.set(None)
|
|
88
|
+
_active_database.set(None)
|
|
89
|
+
_person_scoped.set(False)
|
|
90
|
+
_savepoint_depth.set(0)
|
|
91
|
+
|
|
92
|
+
ctx.run(_clear)
|
|
93
|
+
return await asyncio.get_running_loop().create_task(fn(), context=ctx)
|
|
94
|
+
|
|
95
|
+
|
|
72
96
|
def get_active_connection() -> Any | None:
|
|
73
97
|
"""Return the connection bound to the current transaction context, or None."""
|
|
74
98
|
return _active_connection.get()
|
|
@@ -40,7 +40,8 @@ if TYPE_CHECKING:
|
|
|
40
40
|
# The canonical version log + restore function. Identical in every Matrx database
|
|
41
41
|
# (verified live on both the main and CMS projects):
|
|
42
42
|
# history.row_versions(entity_type, row_id, version, operation, row_data, actor_id, occurred_at)
|
|
43
|
-
# public.version_restore(token text, id uuid, version int) -> int (the new version)
|
|
43
|
+
# public.version_restore(token text, id uuid, version int) -> int (the new version) —
|
|
44
|
+
# a thin SQL wrapper over platform.version_restore; both exist live, the ORM calls the public door
|
|
44
45
|
VERSION_LOG_SCHEMA = "history"
|
|
45
46
|
VERSION_LOG_MODEL = "RowVersions"
|
|
46
47
|
VERSION_RESTORE_SCHEMA = "public"
|
|
@@ -1745,7 +1745,9 @@ async def resolve_field_by_id(field_id: str) -> str:
|
|
|
1745
1745
|
f"credential field {field_id} exists but does not decrypt with the "
|
|
1746
1746
|
"configured CREDENTIALS_ENCRYPTION_KEY (key drift)"
|
|
1747
1747
|
) from exc
|
|
1748
|
-
|
|
1748
|
+
from .use_stamp import stamp_last_used
|
|
1749
|
+
|
|
1750
|
+
await stamp_last_used(UserSecret, {"id": field_id})
|
|
1749
1751
|
return value
|
|
1750
1752
|
|
|
1751
1753
|
|
|
@@ -753,11 +753,9 @@ async def resolve_org_secrets(
|
|
|
753
753
|
# the same row locks in opposite orders and Postgres kills one as a
|
|
754
754
|
# deadlock victim (40P01) — four ``ai.agent.start`` invocations over 185
|
|
755
755
|
# rows of one org killed a live workflow run on 2026-09-12.
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
last_used_at=datetime.now(UTC),
|
|
760
|
-
)
|
|
756
|
+
from .use_stamp import stamp_last_used
|
|
757
|
+
|
|
758
|
+
await stamp_last_used(UserSecret, {"id__in": sorted(used_ids)}, lock_rows_in_pk_order=True)
|
|
761
759
|
return resolved
|
|
762
760
|
|
|
763
761
|
|
|
@@ -21,6 +21,7 @@ from typing import Any
|
|
|
21
21
|
|
|
22
22
|
from .crypto import decrypt_value, encrypt_value, mask_value
|
|
23
23
|
from .model import CredentialItem, UserSecret, UserSecretGrant
|
|
24
|
+
from .use_stamp import stamp_last_used
|
|
24
25
|
|
|
25
26
|
logger = logging.getLogger(__name__)
|
|
26
27
|
|
|
@@ -243,7 +244,7 @@ async def get_user_secret(
|
|
|
243
244
|
)
|
|
244
245
|
plaintext = None
|
|
245
246
|
if touch_last_used:
|
|
246
|
-
await UserSecret
|
|
247
|
+
await stamp_last_used(UserSecret, {"id": row["id"]})
|
|
247
248
|
return _row_to_dataclass(row, decrypted_value=plaintext)
|
|
248
249
|
|
|
249
250
|
|
|
@@ -312,7 +313,7 @@ async def get_org_secret(
|
|
|
312
313
|
)
|
|
313
314
|
plaintext = None
|
|
314
315
|
if touch_last_used:
|
|
315
|
-
await UserSecret
|
|
316
|
+
await stamp_last_used(UserSecret, {"id": row["id"]})
|
|
316
317
|
return _row_to_dataclass(row, decrypted_value=plaintext)
|
|
317
318
|
|
|
318
319
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""``last_used_at`` stamps are telemetry: a failed stamp never fails the read that used the secret."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from datetime import UTC, datetime
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def stamp_last_used(model: Any, filters: dict[str, Any], **options: Any) -> bool:
|
|
13
|
+
"""Stamp ``last_used_at`` on the rows ``filters`` names; announce and drop any failure.
|
|
14
|
+
|
|
15
|
+
A timeout or lock collision on this bookkeeping UPDATE once ended a whole Notion import
|
|
16
|
+
(2026-10-22). The caller already holds the value it read, so losing the stamp loses
|
|
17
|
+
nothing a person needs. Returns whether the stamp landed.
|
|
18
|
+
"""
|
|
19
|
+
try:
|
|
20
|
+
await model.update_where(filters, last_used_at=datetime.now(UTC), **options)
|
|
21
|
+
return True
|
|
22
|
+
except Exception as exc:
|
|
23
|
+
logger.warning(
|
|
24
|
+
"[secrets] last_used_at stamp on %s skipped (%s: %s); the read continues",
|
|
25
|
+
getattr(model, "__name__", model), type(exc).__name__, exc,
|
|
26
|
+
)
|
|
27
|
+
return False
|
|
@@ -693,6 +693,7 @@ async def record_error(
|
|
|
693
693
|
payload: Any | None = None,
|
|
694
694
|
context: dict[str, Any] | None = None,
|
|
695
695
|
database: str | None = None,
|
|
696
|
+
group_open: bool = False,
|
|
696
697
|
) -> None:
|
|
697
698
|
"""Universal failure capture for NON-write errors → ``system_error``.
|
|
698
699
|
|
|
@@ -737,6 +738,16 @@ async def record_error(
|
|
|
737
738
|
indistinguishable from a Codex one.
|
|
738
739
|
payload: request args/body to capture (jsonb). Serialized defensively.
|
|
739
740
|
context: free-form context (debug_label, task_name, partial cost, …).
|
|
741
|
+
group_open: ONE OPEN ROW PER SIGNATURE (error-capture rule "a count is a
|
|
742
|
+
number on an existing row, never a new row"). When True, a capture whose
|
|
743
|
+
``(kind, route, error_type)`` already has an UNRESOLVED row bumps that row's
|
|
744
|
+
``context.occurrences`` (exact, atomic, across every process and deploy) and
|
|
745
|
+
``context.last_seen_at`` instead of filing a new row; with none open it files
|
|
746
|
+
the row with ``occurrences=1``. Resolving the row zeroes the count — the next
|
|
747
|
+
occurrence reopens as one new row. For announcements that are a COUNT of a
|
|
748
|
+
known condition per site (legacy lanes, runtime bypasses), never for a crash
|
|
749
|
+
whose every instance carries its own inputs. The storm budget does not apply
|
|
750
|
+
(the grouping is the budget).
|
|
740
751
|
"""
|
|
741
752
|
# Both attribution halves ride the carried request context; a capture site
|
|
742
753
|
# that declared neither still files a fully categorized row.
|
|
@@ -755,7 +766,7 @@ async def record_error(
|
|
|
755
766
|
else:
|
|
756
767
|
tb_text = "".join(_tb.format_exception(type(exc), exc, exc.__traceback__))
|
|
757
768
|
|
|
758
|
-
admitted, folded = _storm_admit(kind, resolved_error_type, route)
|
|
769
|
+
admitted, folded = (True, 0) if group_open else _storm_admit(kind, resolved_error_type, route)
|
|
759
770
|
if not admitted:
|
|
760
771
|
# Counted, never silent: the next admitted row for this signature
|
|
761
772
|
# carries the total. ONE stdout line per window (the first fold) — a line per
|
|
@@ -803,12 +814,14 @@ async def record_error(
|
|
|
803
814
|
"route": route,
|
|
804
815
|
"context": context,
|
|
805
816
|
"payload": payload,
|
|
817
|
+
**({"group_open": True} if group_open else {}),
|
|
806
818
|
}
|
|
807
819
|
)
|
|
808
820
|
return
|
|
809
821
|
|
|
810
822
|
try:
|
|
811
823
|
await _insert_error(
|
|
824
|
+
**({"group_open": True} if group_open else {}),
|
|
812
825
|
kind=kind,
|
|
813
826
|
request_id=request_id,
|
|
814
827
|
user_id=user_id,
|
|
@@ -912,6 +925,7 @@ async def _insert_error(
|
|
|
912
925
|
payload: Any | None,
|
|
913
926
|
context: dict[str, Any] | None,
|
|
914
927
|
database: str | None,
|
|
928
|
+
group_open: bool = False,
|
|
915
929
|
) -> None:
|
|
916
930
|
from matrx_orm.adapters import AdapterRegistry
|
|
917
931
|
from matrx_orm.core.config import get_all_database_project_names
|
|
@@ -947,6 +961,13 @@ async def _insert_error(
|
|
|
947
961
|
# capture fast instead of parking a pool slot behind it.
|
|
948
962
|
await conn.execute(f"SET LOCAL lock_timeout = '{CAPTURE_LOCK_TIMEOUT_MS}ms'")
|
|
949
963
|
await conn.execute(f"SET LOCAL statement_timeout = '{CAPTURE_STATEMENT_TIMEOUT_MS}ms'")
|
|
964
|
+
if group_open:
|
|
965
|
+
if await _bump_open_error(conn, kind=kind, route=route, error_type=error_type):
|
|
966
|
+
return
|
|
967
|
+
context_json = json.dumps(
|
|
968
|
+
{**(context or {}), "occurrences": 1, "grouped": GROUPED_NOTE},
|
|
969
|
+
default=_json_default,
|
|
970
|
+
)
|
|
950
971
|
await _execute_error_insert(
|
|
951
972
|
conn,
|
|
952
973
|
kind=kind,
|
|
@@ -967,6 +988,39 @@ async def _insert_error(
|
|
|
967
988
|
|
|
968
989
|
|
|
969
990
|
|
|
991
|
+
#: Stamped on a grouped row (``record_error(group_open=True)``) so a reader knows what the count means.
|
|
992
|
+
GROUPED_NOTE = (
|
|
993
|
+
"one open row per kind+route+error_type; context.occurrences counts every capture since the row "
|
|
994
|
+
"was last resolved (all processes), context.last_seen_at the latest"
|
|
995
|
+
)
|
|
996
|
+
|
|
997
|
+
# The bump is ONE statement under a transaction-scoped advisory lock on the signature, so two
|
|
998
|
+
# processes seeing the same site at once neither lose a count nor both file a row.
|
|
999
|
+
_GROUP_LOCK_SQL = "SELECT pg_advisory_xact_lock(hashtextextended($1::text, 0))"
|
|
1000
|
+
_GROUP_BUMP_SQL = """
|
|
1001
|
+
UPDATE ops.system_error
|
|
1002
|
+
SET context = coalesce(context, '{}'::jsonb) || jsonb_build_object(
|
|
1003
|
+
'occurrences', coalesce((context->>'occurrences')::bigint, 1) + 1,
|
|
1004
|
+
'last_seen_at', now())
|
|
1005
|
+
WHERE id = (
|
|
1006
|
+
SELECT id FROM ops.system_error
|
|
1007
|
+
WHERE kind = $1::text
|
|
1008
|
+
AND route IS NOT DISTINCT FROM $2::text
|
|
1009
|
+
AND error_type IS NOT DISTINCT FROM $3::text
|
|
1010
|
+
AND resolved_at IS NULL
|
|
1011
|
+
ORDER BY occurred_at
|
|
1012
|
+
LIMIT 1)
|
|
1013
|
+
RETURNING id
|
|
1014
|
+
"""
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
async def _bump_open_error(conn: Any, *, kind: str, route: str | None, error_type: str | None) -> bool:
|
|
1018
|
+
"""Count this capture on the signature's open row; False when none is open (file one)."""
|
|
1019
|
+
await conn.fetch(_GROUP_LOCK_SQL, f"system_error:{kind}|{route or ''}|{error_type or ''}")
|
|
1020
|
+
rows = await conn.fetch(_GROUP_BUMP_SQL, kind, route, error_type)
|
|
1021
|
+
return bool(rows)
|
|
1022
|
+
|
|
1023
|
+
|
|
970
1024
|
_LIVE_INSERT_ERROR = _insert_error
|
|
971
1025
|
|
|
972
1026
|
async def _execute_error_insert(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.246"
|
|
4
4
|
description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -41,7 +41,7 @@ dependencies = [
|
|
|
41
41
|
"gitpython>=3.1.40",
|
|
42
42
|
"psycopg[binary]>=3.2.5",
|
|
43
43
|
"psycopg-pool>=3.2.5",
|
|
44
|
-
"matrx-utils>=2.0.
|
|
44
|
+
"matrx-utils>=2.0.84",
|
|
45
45
|
"pyyaml>=6.0.3",
|
|
46
46
|
"python-dotenv>=1.0",
|
|
47
47
|
"cryptography>=43.0",
|
|
@@ -159,11 +159,11 @@ class TestArrayArgBinding:
|
|
|
159
159
|
lambda database: _FakeConnCtx(conn),
|
|
160
160
|
)
|
|
161
161
|
result = await call_function(
|
|
162
|
-
"db", "
|
|
162
|
+
"db", "context", "resolve_full_context", "user-id", ArrayArg(["scope-1", "scope-2"])
|
|
163
163
|
)
|
|
164
164
|
assert result == "ok"
|
|
165
165
|
conn.fetchval.assert_awaited_once_with(
|
|
166
|
-
'SELECT "
|
|
166
|
+
'SELECT "context"."resolve_full_context"($1, $2)',
|
|
167
167
|
"user-id",
|
|
168
168
|
["scope-1", "scope-2"], timeout=None
|
|
169
169
|
)
|
|
@@ -174,9 +174,9 @@ class TestArrayArgBinding:
|
|
|
174
174
|
"matrx_orm.core.db_function.AsyncDatabaseManager.get_connection",
|
|
175
175
|
lambda database: _FakeConnCtx(conn),
|
|
176
176
|
)
|
|
177
|
-
await call_function("db", "
|
|
177
|
+
await call_function("db", "context", "resolve_full_context", "user-id", ArrayArg(None))
|
|
178
178
|
conn.fetchval.assert_awaited_once_with(
|
|
179
|
-
'SELECT "
|
|
179
|
+
'SELECT "context"."resolve_full_context"($1, $2)', "user-id", None, timeout=None
|
|
180
180
|
)
|
|
181
181
|
|
|
182
182
|
async def test_array_arg_distinct_from_plain_list_jsonb_cast(self, monkeypatch) -> None:
|
|
@@ -110,11 +110,11 @@ class TestCallFunctionRows:
|
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
result = await call_function(
|
|
113
|
-
"main", "
|
|
113
|
+
"main", "dictionary", "dict_list_entries_for", "user-1", "user", None, mode="rows"
|
|
114
114
|
)
|
|
115
115
|
assert result == [{"id": "1", "term": "foo"}, {"id": "2", "term": "bar"}]
|
|
116
116
|
assert conn.calls[0]["sql"] == (
|
|
117
|
-
'SELECT * FROM "
|
|
117
|
+
'SELECT * FROM "dictionary"."dict_list_entries_for"($1, $2, $3)'
|
|
118
118
|
)
|
|
119
119
|
assert conn.calls[0]["args"] == ("user-1", "user", None)
|
|
120
120
|
|
|
@@ -328,7 +328,7 @@ async def test_call_function_retries_a_rolled_back_rpc(monkeypatch):
|
|
|
328
328
|
monkeypatch.setattr("matrx_orm.core.write_retry.resolve_policy", _fake_policy)
|
|
329
329
|
clear_policy_cache()
|
|
330
330
|
|
|
331
|
-
await db_function.call_function("test", "
|
|
331
|
+
await db_function.call_function("test", "rag", "library_revoke", "g1", mode="none")
|
|
332
332
|
|
|
333
333
|
assert calls[0] == 2, (
|
|
334
334
|
f"A deadlocked RPC must be retried on its own fresh connection. Got {calls[0]} attempts."
|
|
@@ -352,7 +352,7 @@ async def test_call_function_inside_a_transaction_does_not_retry(monkeypatch):
|
|
|
352
352
|
clear_policy_cache()
|
|
353
353
|
|
|
354
354
|
with pytest.raises(LockContentionError) as caught:
|
|
355
|
-
await db_function.call_function("test", "
|
|
355
|
+
await db_function.call_function("test", "rag", "library_revoke", "g1", mode="none")
|
|
356
356
|
assert calls[0] == 1, f"expected exactly one attempt inside a transaction, got {calls[0]}"
|
|
357
357
|
assert caught.value.details["in_transaction"] is True
|
|
358
358
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Level 1: a noun lookup never depends on who is acting.
|
|
2
|
+
|
|
3
|
+
``platform.entity_types`` is vocabulary, and a non-admin person's RLS hides it (a restrictive
|
|
4
|
+
``platform_admin_only`` policy). ``EntityRegistry.resolve`` read it on whatever connection the
|
|
5
|
+
caller held, so inside ``acting_as_user`` it found no row, answered ``None`` and CACHED that
|
|
6
|
+
miss for the life of the process: every later ``sources_to(..., "fc_card")`` raised
|
|
7
|
+
``UnknownEntityType('fc_card')`` — the Education Guide lost a study-media record's source (a
|
|
8
|
+
flashcard deck) on 2026-10-22. The registry now reads the noun outside the caller's session.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
|
|
13
|
+
from matrx_orm.associations import EntityRegistry
|
|
14
|
+
from matrx_orm.core import transaction as tx
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _Card:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _HiddenUnderRls:
|
|
22
|
+
"""An entity_types stand-in that answers only off the person's session, like the live table."""
|
|
23
|
+
|
|
24
|
+
seen: list[tuple[bool, object]] = []
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
async def get_or_none(cls, **filters):
|
|
28
|
+
cls.seen.append((tx.in_person_scoped_session(), tx.get_active_connection()))
|
|
29
|
+
if tx.in_person_scoped_session() or tx.get_active_connection() is not None:
|
|
30
|
+
return None
|
|
31
|
+
row = type("Row", (), {})()
|
|
32
|
+
row.schema_name, row.table_name, row.is_active = "education", "fc_card", True
|
|
33
|
+
return row if filters.get("token") == "fc_card" else None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.mark.asyncio
|
|
37
|
+
async def test_a_person_session_never_hides_a_registered_noun() -> None:
|
|
38
|
+
reg = EntityRegistry(entity_type_model=_HiddenUnderRls,
|
|
39
|
+
model_lookup=lambda s, t: _Card if (s, t) == ("education", "fc_card") else None)
|
|
40
|
+
marks = (tx._active_connection.set(object()), tx._person_scoped.set(True))
|
|
41
|
+
try:
|
|
42
|
+
assert await reg.resolve("fc_card") is _Card
|
|
43
|
+
assert await reg.require("fc_card") is _Card
|
|
44
|
+
finally:
|
|
45
|
+
tx._person_scoped.reset(marks[1])
|
|
46
|
+
tx._active_connection.reset(marks[0])
|
|
47
|
+
assert _HiddenUnderRls.seen and all(scoped is False and conn is None for scoped, conn in _HiddenUnderRls.seen)
|
|
48
|
+
# the caller's session is untouched by the lookup
|
|
49
|
+
assert tx.in_person_scoped_session() is False and tx.get_active_connection() is None
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""ONE OPEN ROW PER SIGNATURE: ``record_error(group_open=True)`` counts on the existing row.
|
|
2
|
+
|
|
3
|
+
SUT: :func:`matrx_orm.session.fallback.record_error` with ``group_open=True`` (and ``_insert_error``).
|
|
4
|
+
|
|
5
|
+
2026-10-22: the mandate runner's legacy-lane announcements were "announced once per site" with a
|
|
6
|
+
per-PROCESS set, so every process and every 30-minute deploy re-filed the same site: 413
|
|
7
|
+
``mandate_offer_eager_legacy`` rows for ~60 sites, 56 ``mandate_bypass_runtime`` rows for 2 lines, in
|
|
8
|
+
12 hours. The error-capture rule: "a count is a number on an existing row, never a new row".
|
|
9
|
+
|
|
10
|
+
Breaks these tests name: a second capture of an open signature filing a new row, the count not being
|
|
11
|
+
exact across "processes" (fresh storm state, fresh per-process sets), a resolved row swallowing a
|
|
12
|
+
recurrence instead of reopening as one, or distinct sites collapsing into one row.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import uuid
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
import pytest
|
|
22
|
+
from matrx_orm.session import fallback
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _Table:
|
|
26
|
+
"""``ops.system_error`` as far as the grouped door touches it."""
|
|
27
|
+
|
|
28
|
+
def __init__(self) -> None:
|
|
29
|
+
self.rows: list[dict[str, Any]] = []
|
|
30
|
+
|
|
31
|
+
def open_row(self, kind: str, route: str | None, error_type: str | None) -> dict[str, Any] | None:
|
|
32
|
+
for row in self.rows:
|
|
33
|
+
if (row["kind"], row["route"], row["error_type"]) == (kind, route, error_type) and row["resolved_at"] is None:
|
|
34
|
+
return row
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class _Txn:
|
|
39
|
+
async def __aenter__(self):
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
async def __aexit__(self, *exc):
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class _Conn:
|
|
47
|
+
def __init__(self, table: _Table) -> None:
|
|
48
|
+
self.table = table
|
|
49
|
+
|
|
50
|
+
def transaction(self):
|
|
51
|
+
return _Txn()
|
|
52
|
+
|
|
53
|
+
async def execute(self, sql: str, *args: Any) -> None:
|
|
54
|
+
if "ops.record_system_error" in sql:
|
|
55
|
+
self.table.rows.append(
|
|
56
|
+
{
|
|
57
|
+
"id": str(uuid.uuid4()),
|
|
58
|
+
"kind": args[0],
|
|
59
|
+
"route": args[8],
|
|
60
|
+
"error_type": args[9],
|
|
61
|
+
"context": json.loads(args[13]) if args[13] else {},
|
|
62
|
+
"resolved_at": None,
|
|
63
|
+
}
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
async def fetch(self, sql: str, *args: Any) -> list[dict[str, Any]]:
|
|
67
|
+
if "UPDATE ops.system_error" in sql:
|
|
68
|
+
row = self.table.open_row(*args)
|
|
69
|
+
if row is None:
|
|
70
|
+
return []
|
|
71
|
+
row["context"]["occurrences"] = int(row["context"].get("occurrences", 1)) + 1
|
|
72
|
+
row["context"]["last_seen_at"] = "now"
|
|
73
|
+
return [{"id": row["id"]}]
|
|
74
|
+
return []
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _Adapter:
|
|
78
|
+
def __init__(self, table: _Table) -> None:
|
|
79
|
+
self.table = table
|
|
80
|
+
|
|
81
|
+
def get_connection(self, timeout: float = 10.0):
|
|
82
|
+
conn = _Conn(self.table)
|
|
83
|
+
|
|
84
|
+
class _Ctx:
|
|
85
|
+
async def __aenter__(self_inner):
|
|
86
|
+
return conn
|
|
87
|
+
|
|
88
|
+
async def __aexit__(self_inner, *exc):
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
return _Ctx()
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@pytest.fixture
|
|
95
|
+
def table(monkeypatch) -> _Table:
|
|
96
|
+
table = _Table()
|
|
97
|
+
monkeypatch.setattr("matrx_orm.adapters.AdapterRegistry.get", lambda name: _Adapter(table))
|
|
98
|
+
|
|
99
|
+
async def live(**kwargs: Any) -> None: # the real insert path, against the fake table
|
|
100
|
+
await fallback._LIVE_INSERT_ERROR(**kwargs)
|
|
101
|
+
|
|
102
|
+
monkeypatch.setattr(fallback, "_insert_error", live)
|
|
103
|
+
fallback.reset_capture_storm_state()
|
|
104
|
+
yield table
|
|
105
|
+
fallback.reset_capture_storm_state()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
async def _sighting(site: str, kind: str = "mandate_offer_eager_legacy") -> None:
|
|
109
|
+
fallback.reset_capture_storm_state() # every sighting may be a different process / deploy
|
|
110
|
+
await fallback.record_error(
|
|
111
|
+
RuntimeError(f"legacy at {site}"), kind=kind, route=site, context={"site": site},
|
|
112
|
+
database="t", group_open=True,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@pytest.mark.asyncio
|
|
117
|
+
async def test_one_open_row_per_site_with_an_exact_count(table: _Table) -> None:
|
|
118
|
+
for _ in range(7):
|
|
119
|
+
await _sighting("seo.job @ aidream/services/seo/run.py:12")
|
|
120
|
+
assert len(table.rows) == 1, "seven sightings of one site are ONE open row"
|
|
121
|
+
assert table.rows[0]["context"]["occurrences"] == 7, "and the row counts every one of them"
|
|
122
|
+
assert table.rows[0]["context"]["site"] == "seo.job @ aidream/services/seo/run.py:12"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@pytest.mark.asyncio
|
|
126
|
+
async def test_distinct_sites_and_kinds_stay_distinct_rows(table: _Table) -> None:
|
|
127
|
+
await _sighting("a.job @ x.py:1")
|
|
128
|
+
await _sighting("a.job @ x.py:2")
|
|
129
|
+
await _sighting("a.job @ x.py:1", kind="mandate_by_name_legacy")
|
|
130
|
+
await _sighting("a.job @ x.py:1")
|
|
131
|
+
assert len(table.rows) == 3, "never merge genuinely distinct signatures"
|
|
132
|
+
counts = sorted(r["context"]["occurrences"] for r in table.rows)
|
|
133
|
+
assert counts == [1, 1, 2]
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.mark.asyncio
|
|
137
|
+
async def test_a_recurrence_after_resolve_reopens_as_one_new_row(table: _Table) -> None:
|
|
138
|
+
await _sighting("b.job @ y.py:9")
|
|
139
|
+
await _sighting("b.job @ y.py:9")
|
|
140
|
+
table.rows[0]["resolved_at"] = "2026-10-22T23:00:00Z"
|
|
141
|
+
await _sighting("b.job @ y.py:9")
|
|
142
|
+
await _sighting("b.job @ y.py:9")
|
|
143
|
+
assert len(table.rows) == 2
|
|
144
|
+
assert [r["context"]["occurrences"] for r in table.rows] == [2, 2], "resolve zeroes the count"
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@pytest.mark.asyncio
|
|
148
|
+
async def test_without_group_open_every_capture_is_still_its_own_row(table: _Table) -> None:
|
|
149
|
+
for _ in range(2):
|
|
150
|
+
fallback.reset_capture_storm_state()
|
|
151
|
+
await fallback.record_error(RuntimeError("crash"), kind="request_crash", route="/r", database="t")
|
|
152
|
+
assert len(table.rows) == 2, "grouping is opt-in: a crash keeps its own inputs per row"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""A ``last_used_at`` stamp is telemetry: its failure never ends the read (or the run) that used the secret.
|
|
2
|
+
|
|
3
|
+
2026-10-22: a timed-out ``UPDATE users.user_secrets SET last_used_at`` stopped a whole Notion import.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import pathlib
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
from matrx_orm.secrets_battery.use_stamp import stamp_last_used
|
|
13
|
+
|
|
14
|
+
ROOT = pathlib.Path(__file__).resolve().parents[3]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _TimesOut:
|
|
18
|
+
calls = 0
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
async def update_where(cls, filters, **kw):
|
|
22
|
+
cls.calls += 1
|
|
23
|
+
raise TimeoutError("statement timeout")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_a_timed_out_stamp_is_dropped_not_raised():
|
|
27
|
+
assert asyncio.run(stamp_last_used(_TimesOut, {"id": "x"})) is False
|
|
28
|
+
assert _TimesOut.calls == 1
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Inside a held transaction a swallowed error would poison it, so those two stamps stay raw.
|
|
32
|
+
_TRANSACTIONAL = {"packages/matrx-orm/matrx_orm/secrets_battery/attachments.py"}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_no_bare_user_secret_stamp_outside_the_helper():
|
|
36
|
+
"""Every non-transactional ``last_used_at`` stamp on a vault row goes through ``stamp_last_used``."""
|
|
37
|
+
offenders = []
|
|
38
|
+
for base in ("packages/matrx-orm/matrx_orm/secrets_battery", "aidream/services/user_secrets"):
|
|
39
|
+
for path in (ROOT / base).rglob("*.py"):
|
|
40
|
+
rel = path.relative_to(ROOT).as_posix()
|
|
41
|
+
if rel in _TRANSACTIONAL or path.name == "use_stamp.py" or "/tests/" in rel:
|
|
42
|
+
continue
|
|
43
|
+
text = path.read_text()
|
|
44
|
+
for m in re.finditer(r"UserSecret\.update_where\((?:[^()]|\([^()]*\))*?last_used_at\s*=", text, re.S):
|
|
45
|
+
if "_stamp_used_secrets" in text[max(0, m.start() - 1500): m.start()]:
|
|
46
|
+
continue # retries lock collisions itself and swallows every other failure
|
|
47
|
+
offenders.append(f"{rel}:{text[: m.start()].count(chr(10)) + 1}")
|
|
48
|
+
assert not offenders, f"raw last_used_at stamps that can fail a run: {offenders}"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|