matrx-orm 3.1.253__tar.gz → 3.1.255__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (458) hide show
  1. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/PKG-INFO +2 -2
  2. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/FEATURE.md +22 -0
  3. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/async_db_manager.py +26 -9
  4. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/pooler_role.py +2 -2
  5. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/transaction.py +140 -26
  6. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/pyproject.toml +2 -2
  7. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_connection_poison_guard.py +77 -2
  8. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_guarded_read_never_reruns_empty.py +2 -1
  9. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_read_connection_retry.py +4 -2
  10. matrx_orm-3.1.255/tests/level1/test_transaction_isolation.py +213 -0
  11. matrx_orm-3.1.255/tests/level1/test_transaction_top_level_cleanup.py +471 -0
  12. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_sealed_field_shows_no_character_of_its_value.py +1 -1
  13. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_pooler_role_guard.py +29 -4
  14. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/.gitignore +0 -0
  15. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/AGENTS.md +0 -0
  16. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/BASE_CLASS_METHODS.md +0 -0
  17. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/CHANGELOG.md +0 -0
  18. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/CLAUDE.md +0 -0
  19. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/MODEL_API.md +0 -0
  20. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/README.md +0 -0
  21. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/database/orm/extended/managers/ai_model_base.py +0 -0
  22. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/docs/migrations.md +0 -0
  23. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/FEATURE.md +0 -0
  24. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/MODULE_README.md +0 -0
  25. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/__init__.py +0 -0
  26. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/adapters/MODULE_README.md +0 -0
  27. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/adapters/__init__.py +0 -0
  28. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/adapters/async_postgresql.py +0 -0
  29. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/adapters/base_adapter.py +0 -0
  30. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  31. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/adapters/supabase_adapter.py +0 -0
  32. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/admin/FEATURE.md +0 -0
  33. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/admin/__init__.py +0 -0
  34. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/admin/router.py +0 -0
  35. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/api/__init__.py +0 -0
  36. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/api/auth.py +0 -0
  37. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/api/config.py +0 -0
  38. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/api/handlers.py +0 -0
  39. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/api/protocol.py +0 -0
  40. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/api/server.py +0 -0
  41. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/associations.py +0 -0
  42. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/cache_debug.py +0 -0
  43. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/catalog.py +0 -0
  44. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/catalog_sql.py +0 -0
  45. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/MODULE_README.md +0 -0
  46. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/__init__.py +0 -0
  47. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/postgres_connection.py +0 -0
  48. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/postgrest.py +0 -0
  49. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/supabase_auth.py +0 -0
  50. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/supabase_config.py +0 -0
  51. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/client/supabase_manager.py +0 -0
  52. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  53. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/MODULE_README.md +0 -0
  54. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  55. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/TASKS.md +0 -0
  56. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/__init__.py +0 -0
  57. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/admin_lane.py +0 -0
  58. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/base.py +0 -0
  59. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/config.py +0 -0
  60. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/connections.py +0 -0
  61. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/db_function.py +0 -0
  62. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/diagnostics.py +0 -0
  63. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/expressions.py +0 -0
  64. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/extended.py +0 -0
  65. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/fields.py +0 -0
  66. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/foreign_session_state.py +0 -0
  67. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/introspection.py +0 -0
  68. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/listen.py +0 -0
  69. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/loop_filters.py +0 -0
  70. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/model_dto.py +0 -0
  71. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/model_view.py +0 -0
  72. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/one_database.py +0 -0
  73. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/paginator.py +0 -0
  74. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/pool_maintenance.py +0 -0
  75. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/pool_watch.py +0 -0
  76. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/pydantic_bridge.py +0 -0
  77. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/read_write.py +0 -0
  78. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/registry.py +0 -0
  79. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/relations.py +0 -0
  80. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/resilience.py +0 -0
  81. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/rls_session.py +0 -0
  82. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/session_context.py +0 -0
  83. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/signals.py +0 -0
  84. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/statement_ceiling.py +0 -0
  85. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/tls.py +0 -0
  86. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/types.py +0 -0
  87. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/write_queue.py +0 -0
  88. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/core/write_retry.py +0 -0
  89. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/entity.py +0 -0
  90. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/error_handling.py +0 -0
  91. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/exceptions.py +0 -0
  92. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/extended/__init__.py +0 -0
  93. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/extended/app_error_handler.py +0 -0
  94. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/identity_rule.py +0 -0
  95. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/local_sqlite.py +0 -0
  96. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/middleware/__init__.py +0 -0
  97. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/middleware/base.py +0 -0
  98. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/MODULE_README.md +0 -0
  99. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/__init__.py +0 -0
  100. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/cli.py +0 -0
  101. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/ddl.py +0 -0
  102. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/diff.py +0 -0
  103. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/executor.py +0 -0
  104. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/integration.py +0 -0
  105. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/loader.py +0 -0
  106. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/operations.py +0 -0
  107. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/state.py +0 -0
  108. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/migrations/table_filter.py +0 -0
  109. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/no_org_assignment.py +0 -0
  110. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/FEATURE.md +0 -0
  111. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/MODULE_README.md +0 -0
  112. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/__init__.py +0 -0
  113. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/bulk_update_values.py +0 -0
  114. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/catalog_select.py +0 -0
  115. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/conflict.py +0 -0
  116. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/conflict_writes.py +0 -0
  117. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/create.py +0 -0
  118. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/db_functions.py +0 -0
  119. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/delete.py +0 -0
  120. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/dynamic_admin.py +0 -0
  121. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/dynamic_crud.py +0 -0
  122. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/graph_walk.py +0 -0
  123. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/latest_rows.py +0 -0
  124. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/queue_claim.py +0 -0
  125. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/read.py +0 -0
  126. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/relational_backfill.py +0 -0
  127. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/staging_load.py +0 -0
  128. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/operations/update.py +0 -0
  129. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/platform_access.py +0 -0
  130. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/platform_db.py +0 -0
  131. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/py.typed +0 -0
  132. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/pytest_lock_guard.py +0 -0
  133. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/pytest_plugin.py +0 -0
  134. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/python_sql/MODULE_README.md +0 -0
  135. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/python_sql/__init__.py +0 -0
  136. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/python_sql/db_objects.py +0 -0
  137. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  138. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  139. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/query/FEATURE.md +0 -0
  140. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/query/MODULE_README.md +0 -0
  141. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/query/__init__.py +0 -0
  142. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/query/builder.py +0 -0
  143. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/query/executor.py +0 -0
  144. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/resources/__init__.py +0 -0
  145. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  146. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  147. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/FEATURE.md +0 -0
  148. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  149. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/__init__.py +0 -0
  150. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/code_handler.py +0 -0
  151. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  152. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/columns.py +0 -0
  153. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/common.py +0 -0
  154. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/diff_preview.py +0 -0
  155. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  156. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/excluded_targets.py +0 -0
  157. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/generator.py +0 -0
  158. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  159. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  160. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  161. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  162. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/package_wiring.py +0 -0
  163. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/relationships.py +0 -0
  164. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/runner.py +0 -0
  165. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/schema.py +0 -0
  166. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/schema_manager.py +0 -0
  167. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/tables.py +0 -0
  168. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/schema_builder/views.py +0 -0
  169. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  170. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/__init__.py +0 -0
  171. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/attachments.py +0 -0
  172. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/backup_restore.py +0 -0
  173. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/crypto.py +0 -0
  174. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  175. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/items.py +0 -0
  176. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/model.py +0 -0
  177. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  178. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_enable.py +0 -0
  179. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  180. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  181. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/native_source.py +0 -0
  182. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/org_service.py +0 -0
  183. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
  184. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/service.py +0 -0
  185. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/use_stamp.py +0 -0
  186. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/secrets_battery/vault_history.py +0 -0
  187. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/README.md +0 -0
  188. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/__init__.py +0 -0
  189. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/coalesce.py +0 -0
  190. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/dag.py +0 -0
  191. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/errors.py +0 -0
  192. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/fallback.py +0 -0
  193. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/flush.py +0 -0
  194. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/lifecycle.py +0 -0
  195. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/managed.py +0 -0
  196. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/op.py +0 -0
  197. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/reads.py +0 -0
  198. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/session.py +0 -0
  199. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/session/telemetry.py +0 -0
  200. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  201. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/__init__.py +0 -0
  202. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/executor.py +0 -0
  203. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/queries.py +0 -0
  204. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/registry.py +0 -0
  205. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/types.py +0 -0
  206. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/sql_executor/utils.py +0 -0
  207. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/state.py +0 -0
  208. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/utils/__init__.py +0 -0
  209. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/utils/sql_utils.py +0 -0
  210. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/utils/type_converters.py +0 -0
  211. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/matrx_orm/write_actor.py +0 -0
  212. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/scripts/git-branches.sh +0 -0
  213. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/scripts/publish.sh +0 -0
  214. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/scripts/release.sh +0 -0
  215. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/scripts/verify_wheel.py +0 -0
  216. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/MODULE_README.md +0 -0
  217. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/__init__.py +0 -0
  218. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/conftest.py +0 -0
  219. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/MODULE_README.md +0 -0
  220. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/__init__.py +0 -0
  221. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_adapter_registry.py +0 -0
  222. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_admin_db_columns.py +0 -0
  223. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_admin_response_rendering.py +0 -0
  224. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_admin_search_negation.py +0 -0
  225. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_admin_search_sentinels.py +0 -0
  226. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_advisory_lock.py +0 -0
  227. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_agent_message.py +0 -0
  228. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_api_auth.py +0 -0
  229. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_api_config.py +0 -0
  230. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_api_handlers.py +0 -0
  231. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_api_protocol.py +0 -0
  232. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_array_agg_order_by.py +0 -0
  233. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_association_trigger_actor_naming.py +0 -0
  234. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_associations.py +0 -0
  235. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_associations_wiring.py +0 -0
  236. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_borrowed_role_never_reaches_server_calls.py +0 -0
  237. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_bulk_hydration_offload.py +0 -0
  238. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_bulk_update_by_pk.py +0 -0
  239. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  240. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_cache_debug.py +0 -0
  241. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_call_function.py +0 -0
  242. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_case_when.py +0 -0
  243. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_catalog.py +0 -0
  244. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_column_scoped_writes.py +0 -0
  245. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_committed_row_guard.py +0 -0
  246. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_composite_pk_filter.py +0 -0
  247. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_composite_pk_write_paths.py +0 -0
  248. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_config.py +0 -0
  249. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_conflict_target.py +0 -0
  250. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_conflict_writes.py +0 -0
  251. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_connection_codecs.py +0 -0
  252. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_connection_primitives.py +0 -0
  253. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_count_composite_distinct.py +0 -0
  254. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_count_limit_param_leak.py +0 -0
  255. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_db_function_field.py +0 -0
  256. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_ddl_generator.py +0 -0
  257. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_deadlock_retry.py +0 -0
  258. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_derived_table.py +0 -0
  259. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_dirty_tracking.py +0 -0
  260. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_dynamic_crud.py +0 -0
  261. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_exceptions.py +0 -0
  262. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  263. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_expression_primitives.py +0 -0
  264. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_fetch_on_init_holds_whole_table.py +0 -0
  265. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_fields.py +0 -0
  266. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  267. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_fk_cycle_resolution.py +0 -0
  268. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_from_alias.py +0 -0
  269. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_fts.py +0 -0
  270. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_func_expression_args.py +0 -0
  271. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_graph_walk.py +0 -0
  272. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_having_annotate_alias.py +0 -0
  273. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  274. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_introspect_rls_policies.py +0 -0
  275. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_join_and_aggregate.py +0 -0
  276. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_latest_rows.py +0 -0
  277. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_listen_notify.py +0 -0
  278. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_local_sqlite.py +0 -0
  279. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_lock_contention_retry.py +0 -0
  280. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_managed_write_guard.py +0 -0
  281. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_matrx_entity.py +0 -0
  282. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_migration_diff_types.py +0 -0
  283. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_migration_loader.py +0 -0
  284. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_model_instance.py +0 -0
  285. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_model_meta.py +0 -0
  286. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_optimistic_concurrency.py +0 -0
  287. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_order_by_expression.py +0 -0
  288. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_org_assignment_inventory.py +0 -0
  289. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  290. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_parameter_name_hydration.py +0 -0
  291. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_patch_jsonb_path.py +0 -0
  292. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_percentile_cont.py +0 -0
  293. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_persisted_count.py +0 -0
  294. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
  295. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_pool_create_never_wedges.py +0 -0
  296. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_pool_holder_census.py +0 -0
  297. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_pool_loop_recreation.py +0 -0
  298. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_pool_maintenance.py +0 -0
  299. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_postgrest_filters.py +0 -0
  300. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_pydantic_bridge.py +0 -0
  301. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_query_builder.py +0 -0
  302. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_query_error_detail.py +0 -0
  303. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_query_executor_sql.py +0 -0
  304. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_query_timeout.py +0 -0
  305. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  306. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_queue_claim.py +0 -0
  307. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_read_write_declared.py +0 -0
  308. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_registry.py +0 -0
  309. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_registry_multi_database.py +0 -0
  310. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_registry_multi_schema.py +0 -0
  311. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_registry_reads_outside_the_person_session.py +0 -0
  312. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_relational_backfill.py +0 -0
  313. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_relations.py +0 -0
  314. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_resilience.py +0 -0
  315. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_rls_session_scope.py +0 -0
  316. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_schema_exists.py +0 -0
  317. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_session_advisory_lock.py +0 -0
  318. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_standalone_write_session_context.py +0 -0
  319. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_state_cache.py +0 -0
  320. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_subquery_filter_raw.py +0 -0
  321. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_subquery_in_filter.py +0 -0
  322. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_subquery_nested_expressions.py +0 -0
  323. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_supabase_auth.py +0 -0
  324. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_supabase_config.py +0 -0
  325. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_sync_pool_declares_read_write.py +0 -0
  326. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_tls.py +0 -0
  327. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_transaction_database_identity.py +0 -0
  328. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
  329. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
  330. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_typed_join_projection.py +0 -0
  331. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_typed_predicates.py +0 -0
  332. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_update_case_expression.py +0 -0
  333. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_update_subquery.py +0 -0
  334. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_update_with_rebase.py +0 -0
  335. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_upsert_default_leak.py +0 -0
  336. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_upsert_with_conflict.py +0 -0
  337. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_values_jsonb_decode.py +0 -0
  338. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_watched_lifecycle.py +0 -0
  339. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_wheel_contents.py +0 -0
  340. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_write_queue_deadline.py +0 -0
  341. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level1/test_write_retry_semantics.py +0 -0
  342. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/MODULE_README.md +0 -0
  343. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/__init__.py +0 -0
  344. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/conftest.py +0 -0
  345. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_bulk_ops.py +0 -0
  346. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_cache_integration.py +0 -0
  347. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_crud.py +0 -0
  348. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_foreign_keys.py +0 -0
  349. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_m2m.py +0 -0
  350. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_manager.py +0 -0
  351. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_migrations_live.py +0 -0
  352. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_query_execution.py +0 -0
  353. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/test_schema_diff.py +0 -0
  354. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
  355. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/live_pooler_role.py +0 -0
  356. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/native_source_cases.py +0 -0
  357. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/native_source_oracle.rs +0 -0
  358. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/.env.example +0 -0
  359. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/README.md +0 -0
  360. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/__init__.py +0 -0
  361. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/generate.py +0 -0
  362. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/generated/.gitkeep +0 -0
  363. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/matrx_orm.yaml +0 -0
  364. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project/test_schema_generation.py +0 -0
  365. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/.env.example +0 -0
  366. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/README.md +0 -0
  367. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/__init__.py +0 -0
  368. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/client_example.py +0 -0
  369. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/client_example.ts +0 -0
  370. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  371. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/sample_project_desktop/server.py +0 -0
  372. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/entity_tests.py +0 -0
  373. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_base_generation.py +0 -0
  374. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  375. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_composite_unique_generation.py +0 -0
  376. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_dto_identity_generation.py +0 -0
  377. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_entity_capability_generation.py +0 -0
  378. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_enum_ordering.py +0 -0
  379. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_excluded_fk_targets.py +0 -0
  380. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_generate_schema.py +0 -0
  381. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_junction_analysis.py +0 -0
  382. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_multi_schema_output.py +0 -0
  383. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_schema_analysis.py +0 -0
  384. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_sql_expression_defaults.py +0 -0
  385. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_table_relationships_query.py +0 -0
  386. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema/test_view_generation.py +0 -0
  387. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema_builder/test_array_default_parsing.py +0 -0
  388. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema_builder/test_enum_array_column.py +0 -0
  389. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  390. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  391. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/schema_builder/test_never_filter_columns.py +0 -0
  392. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/__init__.py +0 -0
  393. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/conftest.py +0 -0
  394. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
  395. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_a_grouped_update_writes_only_each_rows_own_fields.py +0 -0
  396. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_cache_no_downgrade.py +0 -0
  397. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_capture_poison_proof.py +0 -0
  398. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_coalesce.py +0 -0
  399. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_dag.py +0 -0
  400. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_disk_spill_fallback.py +0 -0
  401. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_flush_individual_fallback.py +0 -0
  402. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_governed_write.py +0 -0
  403. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_managed.py +0 -0
  404. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_op_enqueue_site.py +0 -0
  405. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_pending_insert_honors_operator_filters.py +0 -0
  406. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_reads.py +0 -0
  407. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_record_error_bounded_insert.py +0 -0
  408. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_record_error_group_open.py +0 -0
  409. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_record_error_storm.py +0 -0
  410. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_session.py +0 -0
  411. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_spill_guard_plugin.py +0 -0
  412. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/session/test_tests_never_write_live_system_error.py +0 -0
  413. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
  414. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_bulk_cache_never_stalls_the_loop.py +0 -0
  415. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_failed_use_stamp_never_fails_the_read.py +0 -0
  416. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_keyword_column_refuses_generation.py +0 -0
  417. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_list_of_uuids_binds_as_uuid_array.py +0 -0
  418. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
  419. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_array_arg_element_type.py +0 -0
  420. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_attachment_mutation_serialization.py +0 -0
  421. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_backup_alias_conflict.py +0 -0
  422. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_backup_history_restore.py +0 -0
  423. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_backup_restore_live.py +0 -0
  424. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_call_function_as.py +0 -0
  425. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_call_function_none_mode.py +0 -0
  426. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
  427. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_database_name_alias.py +0 -0
  428. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_db_functions.py +0 -0
  429. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_dsn_password_masking.py +0 -0
  430. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_dynamic_select_unregistered.py +0 -0
  431. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_first_asks_the_database_for_one_row.py +0 -0
  432. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_foreign_session_state.py +0 -0
  433. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  434. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_instance_update_runs_expressions.py +0 -0
  435. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_jsonb_postgres_illegal_text.py +0 -0
  436. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_keyed_digest.py +0 -0
  437. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_model_cls_refactor.py +0 -0
  438. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_native_enable.py +0 -0
  439. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_native_lifecycle.py +0 -0
  440. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_native_lifecycle_fences.py +0 -0
  441. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_native_passkey_receipts.py +0 -0
  442. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_native_source.py +0 -0
  443. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  444. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_one_database.py +0 -0
  445. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_order_by_desc_nulls_last.py +0 -0
  446. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_org_vault_gate.py +0 -0
  447. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_package_wiring_views.py +0 -0
  448. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_secret_audit_names_its_organization.py +0 -0
  449. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_secrets_battery.py +0 -0
  450. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_secrets_minting_keys.py +0 -0
  451. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_shared_lock_guard.py +0 -0
  452. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_sql_param_casts.py +0 -0
  453. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_state_cache_sweeps_stale.py +0 -0
  454. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_statement_ceiling_warning.py +0 -0
  455. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_sync_twins_guard.py +0 -0
  456. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_update_result_truthiness.py +0 -0
  457. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/tests/test_user_visible_lookup.py +0 -0
  458. {matrx_orm-3.1.253 → matrx_orm-3.1.255}/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.253
3
+ Version: 3.1.255
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.87
29
+ Requires-Dist: matrx-utils>=2.0.89
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
@@ -289,6 +289,28 @@ trip from a laptop): 435 → ~200 round trips. Pinned by
289
289
  `tests/level1/test_transaction_pool_release_sends_nothing.py` and
290
290
  `tests/level1/test_rls_session_scope.py`.
291
291
 
292
+ **Snapshot isolation is selected only at the canonical transaction boundary.**
293
+ `transaction(isolation=…)` accepts `read_committed`, `repeatable_read`, or
294
+ `serializable` and emits the corresponding fixed `BEGIN ISOLATION LEVEL` clause;
295
+ omitting it preserves plain `BEGIN`. Unknown values fail before connection
296
+ acquisition. An explicit mode inside an existing transaction refuses before any
297
+ savepoint or depth mutation because a savepoint cannot change the outer isolation;
298
+ an ordinary nested transaction remains a savepoint. Opening GUCs still follow the
299
+ BEGIN in their one ordered round trip. Pinned by
300
+ `tests/level1/test_transaction_isolation.py`.
301
+
302
+ **A top-level transaction does not outlive its physical cleanup.** COMMIT or
303
+ ROLLBACK and adapter release run in one retained task; caller cancellation is
304
+ remembered while repeated cancellation is consumed and the task is shielded and
305
+ joined. Precedence is caller cancellation, then the original body error, then a
306
+ cleanup error. Command and release faults are observed separately using only a
307
+ fixed code, phase, exception type, and database alias; an unknown release fault
308
+ terminates only an asyncpg proxy that still owns its backend. A successful COMMIT
309
+ whose bounded pool reset times out remains successful because asyncpg has already
310
+ discarded that backend; its diagnostic is metadata-only. Pinned by
311
+ `tests/level1/test_transaction_top_level_cleanup.py` and
312
+ `tests/level1/test_connection_poison_guard.py`.
313
+
292
314
  **A backend another client left read-only never refuses our writes.** A transaction
293
315
  pooler shares server connections with every client of the same login and never resets
294
316
  one between clients, so a session-level `SET default_transaction_read_only = on` (or
@@ -64,6 +64,24 @@ from matrx_orm.core.write_retry import (
64
64
  logger = logging.getLogger("matrx_orm.async_db_manager")
65
65
 
66
66
 
67
+ def _log_connection_release_failure(
68
+ *, config_name: str, code: str, error: BaseException
69
+ ) -> None:
70
+ error_type = type(error).__name__
71
+ logger.error(
72
+ "matrx_orm_connection_release_failed code=%s phase=release error_type=%s database=%s",
73
+ code,
74
+ error_type,
75
+ config_name,
76
+ extra={
77
+ "code": code,
78
+ "phase": "release",
79
+ "error_type": error_type,
80
+ "database": config_name,
81
+ },
82
+ )
83
+
84
+
67
85
  def _terminate_pool_after_loop_change(pool: Any, config_name: str) -> None:
68
86
  try:
69
87
  pool.terminate()
@@ -1271,10 +1289,10 @@ class AsyncDatabaseManager:
1271
1289
  return
1272
1290
  release_exc = task.exception()
1273
1291
  if release_exc is not None:
1274
- logger.error(
1275
- "[matrx_orm] Connection release failed for '%s': %s",
1276
- config_name,
1277
- release_exc,
1292
+ _log_connection_release_failure(
1293
+ config_name=config_name,
1294
+ code="connection_release_failed",
1295
+ error=release_exc,
1278
1296
  )
1279
1297
  return
1280
1298
  try:
@@ -1295,11 +1313,10 @@ class AsyncDatabaseManager:
1295
1313
  # release timeout. The query already completed successfully, so
1296
1314
  # this cleanup failure must not replace its result with a false
1297
1315
  # request crash. Keep the pool-health signal loud.
1298
- logger.error(
1299
- "[matrx_orm] Connection release timed out for '%s'; "
1300
- "asyncpg discarded the connection: %s",
1301
- config_name,
1302
- release_exc,
1316
+ _log_connection_release_failure(
1317
+ config_name=config_name,
1318
+ code="connection_release_timeout_discarded",
1319
+ error=release_exc,
1303
1320
  )
1304
1321
  else:
1305
1322
  try:
@@ -294,7 +294,7 @@ async def learn_login_role(conn: Any) -> str:
294
294
  both resets put a borrowed role back before ``session_user`` is read, so the
295
295
  answer is the role the backend authenticated as — never a borrowed one.
296
296
  """
297
- async with conn.transaction():
297
+ async with conn.transaction(readonly=True):
298
298
  await conn.execute("RESET SESSION AUTHORIZATION")
299
299
  await conn.execute("RESET ROLE")
300
300
  row = await conn.fetchrow("SELECT session_user AS login_, current_user AS current_")
@@ -463,7 +463,7 @@ async def _pinned_reread(
463
463
  """
464
464
  last_role: tuple[str, str] | None = None
465
465
  for _ in range(REPROVE_ATTEMPTS):
466
- async with conn.transaction():
466
+ async with conn.transaction(readonly=True):
467
467
  before = await conn.fetchrow("SELECT current_user, session_user")
468
468
  before_current = before["current_user"]
469
469
  before_session = before["session_user"]
@@ -21,11 +21,12 @@ automatically uses the same connection without any manual passing.
21
21
 
22
22
  Adapter decoupling
23
23
  ------------------
24
- The ``TransactionContext`` no longer imports asyncpg directly. Instead it
25
- obtains its connection through ``AdapterRegistry.get(database).get_connection()``,
26
- which returns a raw asyncpg pool connection for the default adapter but can
27
- return any connection object for custom adapters, as long as that object
28
- supports ``.execute(sql)`` and ``.fetch(sql, *args)``.
24
+ ``TransactionContext`` obtains its connection through
25
+ ``AdapterRegistry.get(database).get_connection()``, which returns an asyncpg
26
+ pool proxy for the default adapter but can return any connection object for
27
+ custom adapters, as long as that object supports ``.execute(sql)`` and
28
+ ``.fetch(sql, *args)``. The one driver-specific check is the failed-release
29
+ discard boundary: only an attached ``PoolConnectionProxy`` may be terminated.
29
30
 
30
31
  The ``_active_connection`` ContextVar is typed as ``Any`` so the rest of the
31
32
  ORM can hold a reference to the active connection without depending on asyncpg.
@@ -37,17 +38,71 @@ from __future__ import annotations
37
38
 
38
39
  import asyncio
39
40
  import contextvars
41
+ import logging
40
42
  import os
41
43
  import re
42
44
  import uuid
43
45
  from collections.abc import AsyncIterator, Awaitable, Callable
44
46
  from contextlib import asynccontextmanager
45
47
  from contextvars import ContextVar, Token
46
- from typing import Any, TypeVar
48
+ from typing import Any, Literal
49
+
50
+ from asyncpg.pool import PoolConnectionProxy
47
51
 
48
52
  from matrx_orm.exceptions import DatabaseError
49
53
 
50
- _T = TypeVar("_T")
54
+ logger = logging.getLogger("matrx_orm.transaction")
55
+
56
+ type TransactionIsolation = Literal[
57
+ "read_committed", "repeatable_read", "serializable"
58
+ ]
59
+
60
+ _ISOLATION_BEGIN_STATEMENTS: dict[TransactionIsolation, str] = {
61
+ "read_committed": "BEGIN ISOLATION LEVEL READ COMMITTED",
62
+ "repeatable_read": "BEGIN ISOLATION LEVEL REPEATABLE READ",
63
+ "serializable": "BEGIN ISOLATION LEVEL SERIALIZABLE",
64
+ }
65
+
66
+
67
+ def _begin_statement(isolation: TransactionIsolation | None) -> str:
68
+ if isolation is None:
69
+ return "BEGIN"
70
+ try:
71
+ return _ISOLATION_BEGIN_STATEMENTS[isolation]
72
+ except (KeyError, TypeError):
73
+ accepted = ", ".join(_ISOLATION_BEGIN_STATEMENTS)
74
+ raise ValueError(
75
+ f"Unsupported transaction isolation {isolation!r}; expected one of: {accepted}"
76
+ ) from None
77
+
78
+
79
+ def _log_cleanup_failure(*, database: str, phase: str, error: BaseException) -> None:
80
+ error_type = type(error).__name__
81
+ logger.error(
82
+ "matrx_orm_transaction_cleanup_failed code=%s phase=%s error_type=%s database=%s",
83
+ "transaction_cleanup_failed",
84
+ phase,
85
+ error_type,
86
+ database,
87
+ extra={
88
+ "code": "transaction_cleanup_failed",
89
+ "phase": phase,
90
+ "error_type": error_type,
91
+ "database": database,
92
+ },
93
+ )
94
+
95
+
96
+ def _discard_still_owned_asyncpg_proxy(connection: Any) -> None:
97
+ # asyncpg detaches a PoolConnectionProxy by clearing ``_con`` before that
98
+ # pool slot can be borrowed again. Only terminate while this exact proxy
99
+ # still owns its backend; never chase a holder or a later borrower.
100
+ if not isinstance(connection, PoolConnectionProxy) or connection._con is None:
101
+ return
102
+ try:
103
+ connection.terminate()
104
+ except Exception:
105
+ pass
51
106
 
52
107
  # ContextVar holding the active connection (if any) for the current task tree.
53
108
  _active_connection: ContextVar[Any | None] = ContextVar("_active_connection", default=None)
@@ -72,7 +127,7 @@ def in_person_scoped_session() -> bool:
72
127
  _savepoint_depth: ContextVar[int] = ContextVar("_savepoint_depth", default=0)
73
128
 
74
129
 
75
- async def outside_transaction(fn: Callable[[], Awaitable[_T]]) -> _T:
130
+ async def outside_transaction[T](fn: Callable[[], Awaitable[T]]) -> T:
76
131
  """Await ``fn()`` on the process's own connection, outside the caller's transaction.
77
132
 
78
133
  For process-wide VOCABULARY reads (the entity-type registry) whose answer must not
@@ -278,8 +333,16 @@ class TransactionContext:
278
333
  On nested entry (active connection exists): creates a SAVEPOINT instead.
279
334
  """
280
335
 
281
- def __init__(self, database: str, opening_gucs: dict[str, str] | None = None) -> None:
336
+ def __init__(
337
+ self,
338
+ database: str,
339
+ opening_gucs: dict[str, str] | None = None,
340
+ *,
341
+ isolation: TransactionIsolation | None = None,
342
+ ) -> None:
282
343
  self.database = database
344
+ self._isolation = isolation
345
+ self._begin_sql = _begin_statement(isolation)
283
346
  # Transaction-local GUCs the OPENER needs set at BEGIN (``rls_session``'s
284
347
  # claims + role), emitted in the same statement as the ceilings and the
285
348
  # declared session context — one round trip for all of them. Top-level only.
@@ -295,6 +358,14 @@ class TransactionContext:
295
358
  async def __aenter__(self) -> TransactionContext:
296
359
  existing = _active_connection.get()
297
360
  if existing is not None:
361
+ if self._isolation is not None:
362
+ raise DatabaseError(
363
+ message=(
364
+ "transaction(isolation=...) must open a TOP-LEVEL transaction: "
365
+ "a nested savepoint cannot change the outer transaction's isolation."
366
+ ),
367
+ details={"database": self.database, "isolation": self._isolation},
368
+ )
298
369
  if self._opening_gucs:
299
370
  raise DatabaseError(
300
371
  message=(
@@ -329,7 +400,7 @@ class TransactionContext:
329
400
  conn = await self._adapter_cm.__aenter__()
330
401
  self._raw_conn = conn
331
402
  try:
332
- await conn.execute("BEGIN")
403
+ await conn.execute(self._begin_sql)
333
404
  except BaseException as e:
334
405
  await self._adapter_cm.__aexit__(type(e), e, e.__traceback__)
335
406
  self._raw_conn = None
@@ -414,35 +485,72 @@ class TransactionContext:
414
485
  # pool poisoned (an in-transaction connection causes the next
415
486
  # consumer's first statement to fail with "transaction is
416
487
  # aborted" and lose that request's data).
488
+ command_error: BaseException | None = None
489
+ release_error: BaseException | None = None
417
490
  try:
418
491
  if exc_type is None:
419
492
  await conn_to_use.execute("COMMIT")
420
493
  else:
421
494
  await conn_to_use.execute("ROLLBACK")
422
- except BaseException:
495
+ except BaseException as error:
496
+ command_error = error
497
+ _log_cleanup_failure(database=self.database, phase="command", error=error)
423
498
  try:
424
499
  conn_to_use.terminate()
425
500
  except Exception:
426
501
  pass
427
- raise
428
- finally:
429
- if adapter_cm is not None:
502
+ if adapter_cm is not None:
503
+ try:
430
504
  await adapter_cm.__aexit__(exc_type, exc_val, exc_tb)
505
+ except BaseException as error:
506
+ release_error = error
507
+ _log_cleanup_failure(database=self.database, phase="release", error=error)
508
+ _discard_still_owned_asyncpg_proxy(conn_to_use)
509
+
510
+ if command_error is not None:
511
+ raise command_error
512
+ if release_error is not None:
513
+ raise release_error
514
+
515
+ # One retained task owns command + release. Caller cancellation is
516
+ # remembered and temporarily consumed while this task is shielded and
517
+ # joined; repeated cancellation cannot let the async-with frame escape
518
+ # with locks or a checkout still held. A child that cancels itself is
519
+ # distinguished by its completed/cancelled state, so it cannot spin.
520
+ teardown_task = asyncio.create_task(
521
+ _teardown(), name=f"matrx-orm-transaction-cleanup:{self.database}"
522
+ )
523
+ caller_cancelled = False
524
+ current_task = asyncio.current_task()
525
+ while not teardown_task.done():
526
+ try:
527
+ await asyncio.shield(teardown_task)
528
+ except asyncio.CancelledError:
529
+ if current_task is not None and current_task.cancelling():
530
+ caller_cancelled = True
531
+ current_task.uncancel()
532
+ continue
533
+ if teardown_task.done() and teardown_task.cancelled():
534
+ break
535
+ raise
536
+ except BaseException:
537
+ if teardown_task.done():
538
+ break
539
+ raise
431
540
 
432
- # SHIELD the teardown so an in-flight cancellation (hard-deadline,
433
- # client disconnect, shutdown) can never SKIP the ROLLBACK and leak a
434
- # poisoned (in-transaction) connection back to the pool. The shielded
435
- # teardown runs to completion even when the outer await is canceled.
541
+ cleanup_error: BaseException | None = None
436
542
  try:
437
- await asyncio.shield(_teardown())
438
- except Exception:
439
- # A teardown failure (e.g. COMMIT failed) must surface on the
440
- # success path; on the error path the original exception wins.
441
- if exc_type is None:
442
- raise
543
+ teardown_task.result()
544
+ except BaseException as error:
545
+ cleanup_error = error
546
+
547
+ if caller_cancelled:
548
+ raise asyncio.CancelledError
443
549
 
444
550
  if exc_type is not None:
445
551
  return False # re-raise the original exception
552
+ if cleanup_error is not None:
553
+ raise cleanup_error
446
554
 
447
555
  return False # never suppress exceptions
448
556
 
@@ -497,17 +605,23 @@ def _opening_statement_gucs(opening_gucs: dict[str, str]) -> dict[str, str]:
497
605
 
498
606
 
499
607
  def transaction(
500
- database: str | None = None, *, opening_gucs: dict[str, str] | None = None
608
+ database: str | None = None,
609
+ *,
610
+ opening_gucs: dict[str, str] | None = None,
611
+ isolation: TransactionIsolation | None = None,
501
612
  ) -> TransactionContext:
502
613
  """Return a ``TransactionContext`` async context manager.
503
614
 
504
615
  ``database`` defaults to the first configured database when omitted.
505
616
  ``opening_gucs`` are transaction-local settings the opener needs at BEGIN;
506
617
  they ride the one opening statement (top-level transactions only).
618
+ ``isolation`` selects one of the fixed PostgreSQL isolation clauses; an
619
+ explicit mode is top-level only.
507
620
  """
621
+ _begin_statement(isolation)
508
622
  if database is None:
509
623
  database = _get_default_database()
510
- return TransactionContext(database, opening_gucs)
624
+ return TransactionContext(database, opening_gucs, isolation=isolation)
511
625
 
512
626
 
513
627
  def _get_default_database() -> str:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.253"
3
+ version = "3.1.255"
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.87",
44
+ "matrx-utils>=2.0.89",
45
45
  "pyyaml>=6.0.3",
46
46
  "python-dotenv>=1.0",
47
47
  "cryptography>=43.0",
@@ -14,6 +14,8 @@ connection is terminated (never reused).
14
14
 
15
15
  from __future__ import annotations
16
16
 
17
+ import asyncio
18
+
17
19
  import pytest
18
20
  from matrx_orm.core.async_db_manager import AsyncDatabaseManager
19
21
  from matrx_orm.exceptions import StateError
@@ -84,13 +86,35 @@ class _FakePool:
84
86
 
85
87
 
86
88
  class _ReleaseTimeoutPool(_FakePool):
89
+ async def release(
90
+ self,
91
+ conn: _FakeConn,
92
+ timeout: float | None = None, # noqa: ASYNC109 - mirrors asyncpg
93
+ ) -> None:
94
+ del timeout
95
+ # Installed asyncpg discards the physical backend before surfacing a
96
+ # reset timeout from Pool.release(). This fake owns that network edge.
97
+ conn.terminate()
98
+ raise TimeoutError("private reset payload exceeded release budget")
99
+
100
+
101
+ class _GatedReleaseFailurePool(_FakePool):
102
+ def __init__(self, conn: _FakeConn) -> None:
103
+ super().__init__(conn)
104
+ self.release_started = asyncio.Event()
105
+ self.release_gate = asyncio.Event()
106
+ self.release_finished = asyncio.Event()
107
+
87
108
  async def release(
88
109
  self,
89
110
  conn: _FakeConn,
90
111
  timeout: float | None = None, # noqa: ASYNC109 - mirrors asyncpg
91
112
  ) -> None:
92
113
  del conn, timeout
93
- raise TimeoutError("reset exceeded release budget")
114
+ self.release_started.set()
115
+ await self.release_gate.wait()
116
+ self.release_finished.set()
117
+ raise RuntimeError("private delayed release payload")
94
118
 
95
119
 
96
120
  def _patch_pool(monkeypatch, pool: _FakePool) -> None:
@@ -146,4 +170,55 @@ async def test_release_timeout_does_not_replace_successful_query_result(monkeypa
146
170
  result = await AsyncDatabaseManager.execute_query("x", "SELECT 1 AS value")
147
171
 
148
172
  assert result == [{"value": 1}]
149
- assert "Connection release timed out for 'x'" in caplog.text
173
+ assert "TERMINATE" in conn.calls
174
+ records = [
175
+ record
176
+ for record in caplog.records
177
+ if record.name == "matrx_orm.async_db_manager"
178
+ and getattr(record, "code", None) == "connection_release_timeout_discarded"
179
+ ]
180
+ assert len(records) == 1
181
+ record = records[0]
182
+ assert record.phase == "release"
183
+ assert record.error_type == "TimeoutError"
184
+ assert record.database == "x"
185
+ assert record.exc_info is None and record.stack_info is None
186
+ assert not any(isinstance(arg, BaseException) for arg in record.args)
187
+ assert "private reset payload" not in record.getMessage()
188
+
189
+
190
+ async def test_cancelled_holder_observes_late_release_failure_without_private_text(
191
+ monkeypatch, caplog
192
+ ):
193
+ conn = _FakeConn(in_tx=False)
194
+ pool = _GatedReleaseFailurePool(conn)
195
+ _patch_pool(monkeypatch, pool)
196
+
197
+ async def use_connection() -> None:
198
+ async with AsyncDatabaseManager.get_connection("x"):
199
+ pass
200
+
201
+ with caplog.at_level("ERROR", logger="matrx_orm.async_db_manager"):
202
+ caller = asyncio.create_task(use_connection())
203
+ await pool.release_started.wait()
204
+ caller.cancel()
205
+ with pytest.raises(asyncio.CancelledError):
206
+ await caller
207
+ pool.release_gate.set()
208
+ await pool.release_finished.wait()
209
+ await asyncio.sleep(0)
210
+
211
+ records = [
212
+ record
213
+ for record in caplog.records
214
+ if record.name == "matrx_orm.async_db_manager"
215
+ and getattr(record, "code", None) == "connection_release_failed"
216
+ ]
217
+ assert len(records) == 1
218
+ record = records[0]
219
+ assert record.phase == "release"
220
+ assert record.error_type == "RuntimeError"
221
+ assert record.database == "x"
222
+ assert record.exc_info is None and record.stack_info is None
223
+ assert not any(isinstance(arg, BaseException) for arg in record.args)
224
+ assert "private delayed release payload" not in record.getMessage()
@@ -47,7 +47,8 @@ class _Conn:
47
47
  self.borrowed = borrowed
48
48
  self.log: list[str] = []
49
49
 
50
- def transaction(self) -> _Tx:
50
+ def transaction(self, *, readonly: bool = False) -> _Tx:
51
+ assert readonly is True
51
52
  return _Tx(self)
52
53
 
53
54
  async def execute(self, sql: str, *_a: object, **_k: object) -> None:
@@ -71,7 +71,8 @@ async def test_read_retries_disconnect_masked_by_reproof_transaction(monkeypatch
71
71
  "connection was closed in the middle of operation"
72
72
  )
73
73
 
74
- def transaction(self):
74
+ def transaction(self, *, readonly: bool = False):
75
+ assert readonly is True
75
76
  return MaskingTransaction()
76
77
 
77
78
  def is_closed(self) -> bool:
@@ -91,7 +92,8 @@ async def test_read_retries_disconnect_masked_by_reproof_transaction(monkeypatch
91
92
  async def fetchrow(self, *_args, **_kwargs):
92
93
  return {"login_": "postgres", "current_": "postgres"}
93
94
 
94
- def transaction(self):
95
+ def transaction(self, *, readonly: bool = False):
96
+ assert readonly is True
95
97
  class _Tx:
96
98
  async def __aenter__(self):
97
99
  return self