matrx-orm 3.1.97__tar.gz → 3.1.99__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.97 → matrx_orm-3.1.99}/PKG-INFO +1 -1
- matrx_orm-3.1.99/matrx_orm/FEATURE.md +55 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/FEATURE.md +45 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/model.py +6 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/org_service.py +11 -1
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/fallback.py +73 -8
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/pyproject.toml +1 -1
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_disk_spill_fallback.py +1 -1
- matrx_orm-3.1.97/matrx_orm/FEATURE.md +0 -21
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/.gitignore +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/AGENTS.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/BASE_CLASS_METHODS.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/CLAUDE.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/MODEL_API.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/database/orm/extended/managers/ai_model_base.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/docs/migrations.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/async_postgresql.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/base_adapter.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/postgresql.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/adapters/supabase_adapter.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/admin/FEATURE.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/admin/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/admin/router.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/api/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/api/auth.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/api/config.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/api/handlers.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/api/protocol.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/api/server.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/associations.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/cache_debug.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/catalog.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/catalog_sql.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/postgres_connection.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/postgrest.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/supabase_auth.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/supabase_config.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/client/supabase_manager.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/EXTENDED-TASK.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/TASKS.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/async_db_manager.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/base.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/config.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/connections.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/db_function.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/diagnostics.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/expressions.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/extended.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/fields.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/introspection.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/listen.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/loop_filters.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/model_dto.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/model_view.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/one_database.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/paginator.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/pool_maintenance.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/pool_watch.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/pooler_role.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/pydantic_bridge.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/registry.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/relations.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/resilience.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/rls_session.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/signals.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/tls.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/transaction.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/types.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/core/write_queue.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/entity.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/error_handling.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/exceptions.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/extended/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/extended/app_error_handler.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/identity_rule.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/local_sqlite.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/middleware/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/middleware/base.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/cli.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/ddl.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/diff.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/executor.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/integration.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/loader.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/operations.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/state.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/migrations/table_filter.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/FEATURE.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/bulk_update_values.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/conflict.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/conflict_writes.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/create.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/db_functions.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/delete.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/dynamic_admin.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/dynamic_crud.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/graph_walk.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/latest_rows.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/queue_claim.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/read.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/relational_backfill.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/staging_load.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/operations/update.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/platform_db.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/py.typed +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/python_sql/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/python_sql/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/python_sql/db_objects.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/query/FEATURE.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/query/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/query/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/query/builder.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/query/executor.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/FEATURE.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/code_handler.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/codegen_writer.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/columns.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/common.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/diff_preview.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/generator.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/package_wiring.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/relationships.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/runner.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/schema.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/schema_manager.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/tables.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/schema_builder/views.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/FEATURE.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/attachments.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/crypto.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/items.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/secrets_battery/service.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/coalesce.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/dag.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/errors.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/flush.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/lifecycle.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/managed.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/op.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/reads.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/session.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/session/telemetry.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/executor.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/queries.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/registry.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/types.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/sql_executor/utils.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/state.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/utils/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/utils/sql_utils.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/matrx_orm/utils/type_converters.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/scripts/git-branches.sh +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/scripts/publish.sh +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/scripts/release.sh +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/conftest.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_admin_db_columns.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_admin_response_rendering.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_admin_search_negation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_admin_search_sentinels.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_advisory_lock.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_agent_message.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_api_auth.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_api_config.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_api_handlers.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_api_protocol.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_array_agg_order_by.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_associations.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_bulk_hydration_offload.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_bulk_update_by_pk.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_cache_debug.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_call_function.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_case_when.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_catalog.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_composite_pk_filter.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_composite_pk_write_paths.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_config.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_conflict_target.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_conflict_writes.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_connection_codecs.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_connection_poison_guard.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_connection_primitives.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_count_composite_distinct.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_db_function_field.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_ddl_generator.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_derived_table.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_dirty_tracking.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_dynamic_crud.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_exceptions.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_expression_primitives.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_fields.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_from_alias.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_fts.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_func_expression_args.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_graph_walk.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_having_annotate_alias.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_introspect_rls_policies.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_join_and_aggregate.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_latest_rows.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_listen_notify.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_local_sqlite.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_managed_write_guard.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_matrx_entity.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_migration_diff_types.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_migration_loader.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_model_instance.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_model_meta.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_optimistic_concurrency.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_order_by_expression.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_parameter_name_hydration.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_patch_jsonb_path.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_pool_holder_census.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_pool_loop_recreation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_pool_maintenance.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_postgrest_filters.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_pydantic_bridge.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_query_builder.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_query_error_detail.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_query_executor_sql.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_query_timeout.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_queue_claim.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_registry.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_registry_multi_database.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_registry_multi_schema.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_relational_backfill.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_relations.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_resilience.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_rls_session_scope.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_schema_exists.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_session_advisory_lock.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_state_cache.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_subquery_filter_raw.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_subquery_in_filter.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_subquery_nested_expressions.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_supabase_auth.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_supabase_config.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_tls.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_typed_join_projection.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_typed_predicates.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_update_case_expression.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_update_subquery.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_update_with_rebase.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_upsert_default_leak.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_upsert_with_conflict.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_values_jsonb_decode.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_watched_lifecycle.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level1/test_write_retry_semantics.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/MODULE_README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/conftest.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_bulk_ops.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_cache_integration.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_crud.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_foreign_keys.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_m2m.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_manager.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_migrations_live.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_query_execution.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/level2/test_schema_diff.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/live_pooler_role.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/.env.example +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/generate.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/generated/.gitkeep +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/matrx_orm.yaml +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project/test_schema_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/.env.example +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/README.md +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/client_example.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/client_example.ts +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/client_supabase_example.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/sample_project_desktop/server.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/entity_tests.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_base_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_composite_pk_fk_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_composite_unique_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_dto_identity_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_entity_capability_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_enum_ordering.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_generate_schema.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_junction_analysis.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_multi_schema_output.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_sql_expression_defaults.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_table_relationships_query.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema/test_view_generation.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema_builder/test_array_default_parsing.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema_builder/test_focused_generation_plan.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/schema_builder/test_host_models_aggregator.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/__init__.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/conftest.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_cache_no_downgrade.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_capture_poison_proof.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_coalesce.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_dag.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_flush_individual_fallback.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_governed_write.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_managed.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_op_enqueue_site.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_reads.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/session/test_session.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_database_name_alias.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_db_functions.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_model_cls_refactor.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_no_blocking_asyncpg_tls.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_one_database.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_pooler_role_guard.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_secrets_battery.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_sql_param_casts.py +0 -0
- {matrx_orm-3.1.97 → matrx_orm-3.1.99}/tests/test_sync_twins_guard.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.99
|
|
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
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Matrx ORM runtime contracts
|
|
2
|
+
|
|
3
|
+
## Exception diagnostics stay event-loop safe
|
|
4
|
+
|
|
5
|
+
- **Caller capture is metadata-only.** `_capture_caller_frames()` walks live Python frames and reads only code filename, function name, and line number.
|
|
6
|
+
- **Source-file reads are forbidden during exception construction.** Never use `traceback.extract_stack()` here: it enters `linecache.checkcache()` and synchronously stats source files, which can freeze every request in an async server.
|
|
7
|
+
- **Diagnostic value is preserved.** `ORMException._caller_frames` retains up to three external application frames in oldest-to-newest order while excluding ORM, site-package, frozen-import, and runpy frames.
|
|
8
|
+
- **The regression guard is direct.** `tests/level1/test_exceptions.py::TestORMExceptionBase::test_caller_capture_never_reads_source_files` makes traceback extraction fail and proves exception construction still captures the application call site.
|
|
9
|
+
|
|
10
|
+
## The capture lane is never NULL-org
|
|
11
|
+
|
|
12
|
+
`session/fallback.py` owns both failure-capture tables — `ops.system_error`
|
|
13
|
+
(`record_error`) and `ops.system_write_failure` (`record_failures`,
|
|
14
|
+
`drain_spilled_ops`, `create_or_capture`). Both carry `organization_id NOT NULL`.
|
|
15
|
+
|
|
16
|
+
- **Every capture row is org-stamped by `_capture_org()`.** Three rungs: an org
|
|
17
|
+
the caller passed, else `None` — handing the row to the DB's
|
|
18
|
+
`public._stamp_org_default`, which resolves the actor's personal org — else
|
|
19
|
+
`SYSTEM_ORGANIZATION_ID`.
|
|
20
|
+
- **The system-org rung is the point, not a shrug.** A boot step, a cron sweep,
|
|
21
|
+
an orphan task and an idle-txn stall have **no acting user by definition**.
|
|
22
|
+
NULL is not a scope for them (db-rules §2 NO NULL ORG); the system org is.
|
|
23
|
+
- **Never let this raise.** Both writers swallow their own failures by contract,
|
|
24
|
+
so a `23502` here would make the error queue silently fail to record errors.
|
|
25
|
+
`_capture_org()` cannot return `None` when there is no actor, and DB trigger
|
|
26
|
+
`_120_stamp_capture_org` re-stamps anything that still arrives org-less.
|
|
27
|
+
- **`SYSTEM_ORGANIZATION_ID` lives in this package deliberately.** matrx-orm may
|
|
28
|
+
never import aidream; the system org is part of the database structure this
|
|
29
|
+
package exists to enforce.
|
|
30
|
+
- **Passing an explicit org always wins** — `record_error(..., organization_id=...)`
|
|
31
|
+
and `record_failures(..., organization_id=...)`.
|
|
32
|
+
|
|
33
|
+
## Entry points
|
|
34
|
+
|
|
35
|
+
- Runtime hierarchy and formatting: `exceptions.py`
|
|
36
|
+
- Failure capture + org stamping: `session/fallback.py`
|
|
37
|
+
- Focused unit coverage: `tests/level1/test_exceptions.py`
|
|
38
|
+
|
|
39
|
+
## Change Log
|
|
40
|
+
|
|
41
|
+
- 2026-08-21 — NO NULL ORG on the capture lane (db-rules §2). Both capture
|
|
42
|
+
writers now stamp `organization_id` (`_capture_org()`); `ops.system_error` and
|
|
43
|
+
`ops.system_write_failure` are `NOT NULL` with backstop trigger
|
|
44
|
+
`_120_stamp_capture_org` (aidream migration 0443). `ops.system_error` left the
|
|
45
|
+
`known_null_org_writers` allowlist in both ratchet baselines.
|
|
46
|
+
- 2026-08-21 — Fixed the `ON CONFLICT` retry counter in `_bulk_insert_failures`:
|
|
47
|
+
it qualified the target as `public.system_write_failure`, which no longer
|
|
48
|
+
exists, so every retry-conflict capture raised `UndefinedTableError` and
|
|
49
|
+
spilled to disk instead of incrementing `retry_count`.
|
|
50
|
+
- 2026-08-21 — Repointed the poison-proof error capture primitive to the live
|
|
51
|
+
`ops.system_error` table after the schema reorganization.
|
|
52
|
+
- 2026-08-18 — Replaced traceback extraction with live-frame metadata walking so ordinary ORM exceptions cannot synchronously stat source files on the event loop.
|
|
53
|
+
|
|
54
|
+
Verified against `exceptions.py` and `tests/level1/test_exceptions.py` on 2026-08-18;
|
|
55
|
+
`session/fallback.py` and live `ops.*` triggers/constraints on 2026-08-21.
|
|
@@ -126,7 +126,52 @@ Pinned by `tests/level1/test_rls_session_scope.py` and
|
|
|
126
126
|
|
|
127
127
|
Verified against code: 2026-08-17.
|
|
128
128
|
|
|
129
|
+
## Idle-in-transaction ceiling and long-transaction naming
|
|
130
|
+
|
|
131
|
+
**A pooled connection may not sit idle inside a transaction.** Every pool ships
|
|
132
|
+
`idle_in_transaction_session_timeout = IDLE_IN_TRANSACTION_TIMEOUT_MS` (60s) in
|
|
133
|
+
`server_settings`, so Postgres ends a session that opens a transaction and then
|
|
134
|
+
stops talking. A long-*running* statement is `active` and is never affected —
|
|
135
|
+
the timeout counts idle time only. A caller with a genuine need overrides the
|
|
136
|
+
key through its own `server_settings`.
|
|
137
|
+
|
|
138
|
+
Why it is not optional: an open transaction holds its locks (DDL queues behind
|
|
139
|
+
it for the WHOLE database) and pins the cluster xmin horizon, which stops
|
|
140
|
+
autovacuum from reclaiming dead tuples everywhere, not just on the tables that
|
|
141
|
+
session touched. On 2026-08-21 one session sat idle in a transaction for 18+
|
|
142
|
+
minutes; every `CREATE POLICY` on the live database blocked to `lock_timeout`
|
|
143
|
+
while the migration applier told each agent to fix SQL that was correct.
|
|
144
|
+
|
|
145
|
+
**Startup parameters do not survive a pooler.** Supavisor drops non-allowlisted
|
|
146
|
+
startup parameters in both transaction and session mode (measured 2026-08-21:
|
|
147
|
+
`SHOW idle_in_transaction_session_timeout` returns `0` on a connection that
|
|
148
|
+
requested 2000ms, and `PGOPTIONS` is dropped the same way). The package default
|
|
149
|
+
therefore governs direct-Postgres deployments; behind a pooler the same ceiling
|
|
150
|
+
has to be a server-side role or database default. That split is the
|
|
151
|
+
package-vs-implementation boundary, not a bug in either half.
|
|
152
|
+
|
|
153
|
+
**The one session that legitimately needs an exemption is a backup.** A
|
|
154
|
+
parallel `pg_dump` leader holds its snapshot `idle in transaction` for the whole
|
|
155
|
+
dump by design, so it must be exempt — and because a pooler eats the exemption,
|
|
156
|
+
a dump belongs on the DIRECT host, which is what it wants anyway (one long-lived
|
|
157
|
+
session is the opposite of what a pooler is for). That is the standard shape
|
|
158
|
+
everywhere: tight ceiling for application sessions, explicit exemption for the
|
|
159
|
+
backup session, and the exemption VERIFIED before the dump starts rather than
|
|
160
|
+
assumed (`db/mirror/refresh.py::resolve_dump_endpoint`).
|
|
161
|
+
|
|
162
|
+
**`long_transactions()` names the blocker.** `matrx_orm.long_transactions`
|
|
163
|
+
(async) and `matrx_orm.long_transactions_sql` (a parameter-free SQL string, so
|
|
164
|
+
sync psycopg tooling runs the identical query) return every transaction open
|
|
165
|
+
past a threshold, categorized `idle_in_transaction` or `long_active`, with
|
|
166
|
+
`describe_transaction(s)` for the human line. One primitive serves the
|
|
167
|
+
in-process guard and the migration applier, so an alarm and an error message
|
|
168
|
+
can never disagree about who the blocker was.
|
|
169
|
+
|
|
170
|
+
Verified against the live database: 2026-08-21.
|
|
171
|
+
|
|
129
172
|
## Change log
|
|
173
|
+
- 2026-08-21: Added the idle-in-transaction ceiling on every pool and the
|
|
174
|
+
`long_transactions` blocker-naming primitive (feedback c72a32ac).
|
|
130
175
|
|
|
131
176
|
- 2026-08-18: Indexed ModelMeta-derived table names so generated models remain
|
|
132
177
|
discoverable by exact schema/table identity.
|
|
@@ -158,6 +158,12 @@ class UserSecretAudit(Model):
|
|
|
158
158
|
|
|
159
159
|
id = IntegerField(primary_key=True, null=False)
|
|
160
160
|
user_secret_id = UUIDField()
|
|
161
|
+
# NOT NULL in Postgres (NO NULL ORG, db-rules §2) but NULLABLE here on
|
|
162
|
+
# purpose: this package has no tenancy model, so a caller that does not
|
|
163
|
+
# already hold the org passes None and the BEFORE-INSERT resolver
|
|
164
|
+
# `users._stamp_secret_audit_org` fills it (migration 0444). Flipping this
|
|
165
|
+
# to null=False would make Field.validate raise on that legitimate call
|
|
166
|
+
# BEFORE the row ever reaches the trigger. The column is still never NULL.
|
|
161
167
|
organization_id = UUIDField()
|
|
162
168
|
user_id = UUIDField()
|
|
163
169
|
actor_id = UUIDField()
|
|
@@ -160,7 +160,17 @@ async def record_secret_audit(
|
|
|
160
160
|
|
|
161
161
|
Audit is a trail, not a transaction: a failed audit write is logged loudly
|
|
162
162
|
but never propagates, because losing the trail must not also lose the
|
|
163
|
-
operation the user asked for.
|
|
163
|
+
operation the user asked for.
|
|
164
|
+
|
|
165
|
+
``organization_id`` is OPTIONAL here and stays that way on purpose: this
|
|
166
|
+
package has no tenancy model and must not grow one (see the module
|
|
167
|
+
docstring). Pass it when the caller already holds it; when it is ``None``
|
|
168
|
+
the DATABASE resolves it — ``users._stamp_secret_audit_org`` (BEFORE INSERT,
|
|
169
|
+
aidream/db/migrations/0444_org_null_ban_user_secret_audit.sql) walks the
|
|
170
|
+
audited secret, then the subject user, then the actor, then the session, and
|
|
171
|
+
lands on the system org for a genuinely system-context event. The column is
|
|
172
|
+
``NOT NULL``: NO NULL ORG (db-rules §2, owner ruling 2026-08-21). Do not
|
|
173
|
+
reintroduce a ``None`` org as a "system"/"unknown" marker."""
|
|
164
174
|
try:
|
|
165
175
|
await UserSecretAudit.create(
|
|
166
176
|
user_secret_id=user_secret_id,
|
|
@@ -107,6 +107,43 @@ def _safe_uuid(value: Any) -> str | None:
|
|
|
107
107
|
return None
|
|
108
108
|
|
|
109
109
|
|
|
110
|
+
# ── NO NULL ORG — the capture lane (db-rules §2, owner ruling 2026-08-21) ────
|
|
111
|
+
# "If something belongs to the system, that CANNOT EVER be represented by a
|
|
112
|
+
# NULL org!" A system-context failure — a boot step, a cron sweep, an orphan
|
|
113
|
+
# task, an idle-txn stall — has no acting user BY DEFINITION, so NULL is not
|
|
114
|
+
# merely untidy here, it is the wrong answer: those rows belong to the SYSTEM
|
|
115
|
+
# org. The constant lives in this package on purpose. matrx-orm may never
|
|
116
|
+
# import aidream (CLAUDE.md, the package paradox), and the system org's id is
|
|
117
|
+
# part of OUR database structure — enforcing exactly that structure is what
|
|
118
|
+
# this package exists to do, not a coupling to the host.
|
|
119
|
+
SYSTEM_ORGANIZATION_ID = "39c38960-d30c-4840-b0c1-c9960de95582"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _capture_org(organization_id: str | None, user_id: str | None) -> str | None:
|
|
123
|
+
"""The organization one capture row belongs to. Never a NULL that survives.
|
|
124
|
+
|
|
125
|
+
Three rungs, in the order db-rules §2 lays them out:
|
|
126
|
+
|
|
127
|
+
1. an org the caller resolved — always wins;
|
|
128
|
+
2. an acting user with no org — returns ``None`` DELIBERATELY, handing the
|
|
129
|
+
row to ``public._stamp_org_default``, the canonical backstop that
|
|
130
|
+
resolves that user's personal org. Re-resolving it here would mean a
|
|
131
|
+
second authority (and an extra round-trip on an error path);
|
|
132
|
+
3. no org and no user — the SYSTEM org.
|
|
133
|
+
|
|
134
|
+
Rung 3 is the whole point. ``organization_id`` on both capture tables is
|
|
135
|
+
NOT NULL, so without it an org-less capture would raise ``23502`` and the
|
|
136
|
+
error queue would fail to record errors — the worst possible place for a
|
|
137
|
+
write to start failing silently.
|
|
138
|
+
"""
|
|
139
|
+
explicit = _safe_uuid(organization_id)
|
|
140
|
+
if explicit is not None:
|
|
141
|
+
return explicit
|
|
142
|
+
if _safe_uuid(user_id) is not None:
|
|
143
|
+
return None
|
|
144
|
+
return SYSTEM_ORGANIZATION_ID
|
|
145
|
+
|
|
146
|
+
|
|
110
147
|
def _op_user_id(op: SessionOp, safe_user_id: str | None) -> str | None:
|
|
111
148
|
"""Best-effort actor for a dropped op: the request user if known, else the
|
|
112
149
|
op's own owner column. Keeps the forensic row attributed (the DB's
|
|
@@ -127,6 +164,7 @@ def _op_failure_row(
|
|
|
127
164
|
session_id: str | None,
|
|
128
165
|
safe_user_id: str | None,
|
|
129
166
|
safe_conversation_id: str | None,
|
|
167
|
+
organization_id: str | None,
|
|
130
168
|
error_text: str,
|
|
131
169
|
tb_text: str,
|
|
132
170
|
failed_at: datetime,
|
|
@@ -134,11 +172,13 @@ def _op_failure_row(
|
|
|
134
172
|
"""The single source of truth for one system_write_failure row's column
|
|
135
173
|
values. Used by BOTH the DB insert and the disk spill, so a spilled file is
|
|
136
174
|
byte-identical in shape to a table row (drain re-inserts it verbatim)."""
|
|
175
|
+
row_user_id = _op_user_id(op, safe_user_id)
|
|
137
176
|
return {
|
|
138
177
|
"op_id": op.op_id,
|
|
139
178
|
"request_id": request_id or session_id,
|
|
140
|
-
"user_id":
|
|
179
|
+
"user_id": row_user_id,
|
|
141
180
|
"conversation_id": safe_conversation_id,
|
|
181
|
+
"organization_id": _capture_org(organization_id, row_user_id),
|
|
142
182
|
"table_target": op.table,
|
|
143
183
|
"op_type": op.op_type,
|
|
144
184
|
"primary_key": _serialize_primary_key(op.pk_field, op.pk_value),
|
|
@@ -246,11 +286,12 @@ async def drain_spilled_ops(database: str | None = None) -> int:
|
|
|
246
286
|
"""
|
|
247
287
|
INSERT INTO ops.system_write_failure (
|
|
248
288
|
op_id, request_id, user_id, conversation_id,
|
|
289
|
+
organization_id,
|
|
249
290
|
table_target, op_type, primary_key, payload,
|
|
250
291
|
depends_on, error_text, traceback, failed_at, retry_count
|
|
251
292
|
) VALUES (
|
|
252
|
-
$1, $2, $3, $4, $5, $6, $7::jsonb, $
|
|
253
|
-
$
|
|
293
|
+
$1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9::jsonb,
|
|
294
|
+
$10::jsonb, $11, $12, $13, 0
|
|
254
295
|
)
|
|
255
296
|
ON CONFLICT (op_id) DO NOTHING
|
|
256
297
|
""",
|
|
@@ -258,6 +299,10 @@ async def drain_spilled_ops(database: str | None = None) -> int:
|
|
|
258
299
|
row.get("request_id"),
|
|
259
300
|
_safe_uuid(row.get("user_id")),
|
|
260
301
|
_safe_uuid(row.get("conversation_id")),
|
|
302
|
+
# A file spilled before the org column existed has no
|
|
303
|
+
# "organization_id" key — the resolver then re-derives it
|
|
304
|
+
# from the row's user, so an OLD spill file still drains.
|
|
305
|
+
_capture_org(row.get("organization_id"), row.get("user_id")),
|
|
261
306
|
row.get("table_target"),
|
|
262
307
|
row.get("op_type"),
|
|
263
308
|
row.get("primary_key"),
|
|
@@ -308,6 +353,7 @@ async def record_failures(
|
|
|
308
353
|
request_id: str | None = None,
|
|
309
354
|
user_id: str | None = None,
|
|
310
355
|
conversation_id: str | None = None,
|
|
356
|
+
organization_id: str | None = None,
|
|
311
357
|
database: str | None = None,
|
|
312
358
|
error_prefix: str | None = None,
|
|
313
359
|
) -> list[str]:
|
|
@@ -316,6 +362,11 @@ async def record_failures(
|
|
|
316
362
|
Never raises. If the fresh-connection write itself fails, dumps every
|
|
317
363
|
op to stdout in red and to the structured logger.
|
|
318
364
|
|
|
365
|
+
``organization_id`` is the org the captured rows belong to. Omit it and
|
|
366
|
+
the row still lands org-stamped, never NULL: the acting user's personal org
|
|
367
|
+
when the op has an owner, else the SYSTEM org (:func:`_capture_org`,
|
|
368
|
+
db-rules §2 NO NULL ORG).
|
|
369
|
+
|
|
319
370
|
``error_prefix`` stamps a recoverability marker onto ``error_text`` (the
|
|
320
371
|
same mechanism ``drain_spilled_ops`` uses for ``DISK_SPILL_RECOVERED_MARKER``)
|
|
321
372
|
so the auto-replay loop can classify this capture without pattern-matching
|
|
@@ -350,6 +401,7 @@ async def record_failures(
|
|
|
350
401
|
session_id=session_id,
|
|
351
402
|
safe_user_id=safe_user_id,
|
|
352
403
|
safe_conversation_id=safe_conversation_id,
|
|
404
|
+
organization_id=organization_id,
|
|
353
405
|
error_text=error_text,
|
|
354
406
|
tb_text=tb_text,
|
|
355
407
|
failed_at=failed_at,
|
|
@@ -427,14 +479,15 @@ async def _bulk_insert_failures(
|
|
|
427
479
|
"""
|
|
428
480
|
INSERT INTO ops.system_write_failure (
|
|
429
481
|
op_id, request_id, user_id, conversation_id,
|
|
482
|
+
organization_id,
|
|
430
483
|
table_target, op_type, primary_key, payload,
|
|
431
484
|
depends_on, error_text, traceback, failed_at, retry_count
|
|
432
485
|
) VALUES (
|
|
433
|
-
$1, $2, $3, $4, $5, $6, $7::jsonb, $
|
|
434
|
-
$
|
|
486
|
+
$1, $2, $3, $4, $5, $6, $7, $8::jsonb, $9::jsonb,
|
|
487
|
+
$10::jsonb, $11, $12, $13, 0
|
|
435
488
|
)
|
|
436
489
|
ON CONFLICT (op_id) DO UPDATE SET
|
|
437
|
-
retry_count =
|
|
490
|
+
retry_count = ops.system_write_failure.retry_count + 1,
|
|
438
491
|
error_text = EXCLUDED.error_text,
|
|
439
492
|
traceback = EXCLUDED.traceback,
|
|
440
493
|
failed_at = EXCLUDED.failed_at
|
|
@@ -443,6 +496,7 @@ async def _bulk_insert_failures(
|
|
|
443
496
|
row["request_id"],
|
|
444
497
|
row["user_id"],
|
|
445
498
|
row["conversation_id"],
|
|
499
|
+
row["organization_id"],
|
|
446
500
|
row["table_target"],
|
|
447
501
|
row["op_type"],
|
|
448
502
|
row["primary_key"],
|
|
@@ -471,6 +525,7 @@ async def record_error(
|
|
|
471
525
|
user_id: str | None = None,
|
|
472
526
|
conversation_id: str | None = None,
|
|
473
527
|
agent_id: str | None = None,
|
|
528
|
+
organization_id: str | None = None,
|
|
474
529
|
source_app: str | None = None,
|
|
475
530
|
route: str | None = None,
|
|
476
531
|
error_type: str | None = None,
|
|
@@ -510,6 +565,10 @@ async def record_error(
|
|
|
510
565
|
sampling the loop thread, or any external sampler) and ``exc`` is a
|
|
511
566
|
synthetic, never-raised marker with no ``__traceback__`` of its own.
|
|
512
567
|
Defaults to the formatted traceback of ``exc``.
|
|
568
|
+
organization_id: the org this failure belongs to, when the caller
|
|
569
|
+
knows it. Omitted, the row is STILL org-stamped rather than NULL:
|
|
570
|
+
the acting user's personal org when ``user_id`` is present, else
|
|
571
|
+
the SYSTEM org (:func:`_capture_org`, db-rules §2 NO NULL ORG).
|
|
513
572
|
payload: request args/body to capture (jsonb). Serialized defensively.
|
|
514
573
|
context: free-form context (debug_label, task_name, partial cost, …).
|
|
515
574
|
"""
|
|
@@ -534,6 +593,7 @@ async def record_error(
|
|
|
534
593
|
user_id=user_id,
|
|
535
594
|
conversation_id=conversation_id,
|
|
536
595
|
agent_id=agent_id,
|
|
596
|
+
organization_id=organization_id,
|
|
537
597
|
source_app=source_app,
|
|
538
598
|
route=route,
|
|
539
599
|
error_type=resolved_error_type,
|
|
@@ -581,6 +641,7 @@ async def _insert_error(
|
|
|
581
641
|
user_id: str | None,
|
|
582
642
|
conversation_id: str | None,
|
|
583
643
|
agent_id: str | None,
|
|
644
|
+
organization_id: str | None,
|
|
584
645
|
source_app: str | None,
|
|
585
646
|
route: str | None,
|
|
586
647
|
error_type: str | None,
|
|
@@ -623,11 +684,12 @@ async def _insert_error(
|
|
|
623
684
|
"""
|
|
624
685
|
INSERT INTO ops.system_error (
|
|
625
686
|
kind, request_id, user_id, conversation_id, agent_id,
|
|
687
|
+
organization_id,
|
|
626
688
|
source_app, route, error_type, error_text, traceback,
|
|
627
689
|
payload, context, occurred_at
|
|
628
690
|
) VALUES (
|
|
629
|
-
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10,
|
|
630
|
-
$
|
|
691
|
+
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11,
|
|
692
|
+
$12::jsonb, $13::jsonb, $14
|
|
631
693
|
)
|
|
632
694
|
""",
|
|
633
695
|
kind,
|
|
@@ -635,6 +697,7 @@ async def _insert_error(
|
|
|
635
697
|
safe_user_id,
|
|
636
698
|
safe_conversation_id,
|
|
637
699
|
safe_agent_id,
|
|
700
|
+
_capture_org(organization_id, safe_user_id),
|
|
638
701
|
source_app,
|
|
639
702
|
route,
|
|
640
703
|
error_type,
|
|
@@ -747,6 +810,7 @@ async def create_or_capture(
|
|
|
747
810
|
request_id: str | None = None,
|
|
748
811
|
user_id: str | None = None,
|
|
749
812
|
conversation_id: str | None = None,
|
|
813
|
+
organization_id: str | None = None,
|
|
750
814
|
database: str | None = None,
|
|
751
815
|
) -> Any:
|
|
752
816
|
"""Create ONE row, and never lose its payload if the write fails.
|
|
@@ -817,6 +881,7 @@ async def create_or_capture(
|
|
|
817
881
|
request_id=request_id,
|
|
818
882
|
user_id=user_id,
|
|
819
883
|
conversation_id=conversation_id,
|
|
884
|
+
organization_id=organization_id or payload.get("organization_id"),
|
|
820
885
|
database=database,
|
|
821
886
|
error_prefix=DIRECT_WRITE_PRESERVED_MARKER,
|
|
822
887
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "matrx-orm"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.99"
|
|
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" }
|
|
@@ -193,7 +193,7 @@ async def test_drain_relands_marks_recoverable_and_deletes(spill_dir, fake_db):
|
|
|
193
193
|
# auto-replay loop picks it up.
|
|
194
194
|
assert len(fake_db) == 1
|
|
195
195
|
args = fake_db[0]
|
|
196
|
-
error_text = args[
|
|
196
|
+
error_text = args[10] # 11th positional ($11) = error_text
|
|
197
197
|
assert DISK_SPILL_RECOVERED_MARKER in error_text
|
|
198
198
|
# File deleted after successful re-land.
|
|
199
199
|
assert not list(spill_dir.glob("*.json"))
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Matrx ORM runtime contracts
|
|
2
|
-
|
|
3
|
-
## Exception diagnostics stay event-loop safe
|
|
4
|
-
|
|
5
|
-
- **Caller capture is metadata-only.** `_capture_caller_frames()` walks live Python frames and reads only code filename, function name, and line number.
|
|
6
|
-
- **Source-file reads are forbidden during exception construction.** Never use `traceback.extract_stack()` here: it enters `linecache.checkcache()` and synchronously stats source files, which can freeze every request in an async server.
|
|
7
|
-
- **Diagnostic value is preserved.** `ORMException._caller_frames` retains up to three external application frames in oldest-to-newest order while excluding ORM, site-package, frozen-import, and runpy frames.
|
|
8
|
-
- **The regression guard is direct.** `tests/level1/test_exceptions.py::TestORMExceptionBase::test_caller_capture_never_reads_source_files` makes traceback extraction fail and proves exception construction still captures the application call site.
|
|
9
|
-
|
|
10
|
-
## Entry points
|
|
11
|
-
|
|
12
|
-
- Runtime hierarchy and formatting: `exceptions.py`
|
|
13
|
-
- Focused unit coverage: `tests/level1/test_exceptions.py`
|
|
14
|
-
|
|
15
|
-
## Change Log
|
|
16
|
-
|
|
17
|
-
- 2026-08-21 — Repointed the poison-proof error capture primitive to the live
|
|
18
|
-
`ops.system_error` table after the schema reorganization.
|
|
19
|
-
- 2026-08-18 — Replaced traceback extraction with live-frame metadata walking so ordinary ORM exceptions cannot synchronously stat source files on the event loop.
|
|
20
|
-
|
|
21
|
-
Verified against `exceptions.py` and `tests/level1/test_exceptions.py` on 2026-08-18.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|