matrx-orm 3.1.200__tar.gz → 3.1.201__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 (431) hide show
  1. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/CHANGELOG.md +5 -0
  2. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/PKG-INFO +1 -1
  3. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/FEATURE.md +30 -0
  4. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/async_db_manager.py +10 -0
  5. matrx_orm-3.1.201/matrx_orm/core/read_write.py +221 -0
  6. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/pytest_lock_guard.py +12 -4
  7. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/pyproject.toml +1 -1
  8. matrx_orm-3.1.201/tests/level1/test_read_write_declared.py +108 -0
  9. matrx_orm-3.1.201/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +311 -0
  10. matrx_orm-3.1.201/tests/test_a_read_only_backend_never_refuses_our_writes.py +187 -0
  11. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/.gitignore +0 -0
  12. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/AGENTS.md +0 -0
  13. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/BASE_CLASS_METHODS.md +0 -0
  14. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/CLAUDE.md +0 -0
  15. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/MODEL_API.md +0 -0
  16. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/README.md +0 -0
  17. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/database/orm/extended/managers/ai_model_base.py +0 -0
  18. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/docs/migrations.md +0 -0
  19. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/FEATURE.md +0 -0
  20. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/MODULE_README.md +0 -0
  21. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/__init__.py +0 -0
  22. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/adapters/MODULE_README.md +0 -0
  23. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/adapters/__init__.py +0 -0
  24. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/adapters/async_postgresql.py +0 -0
  25. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/adapters/base_adapter.py +0 -0
  26. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  27. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/adapters/supabase_adapter.py +0 -0
  28. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/admin/FEATURE.md +0 -0
  29. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/admin/__init__.py +0 -0
  30. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/admin/router.py +0 -0
  31. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/api/__init__.py +0 -0
  32. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/api/auth.py +0 -0
  33. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/api/config.py +0 -0
  34. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/api/handlers.py +0 -0
  35. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/api/protocol.py +0 -0
  36. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/api/server.py +0 -0
  37. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/associations.py +0 -0
  38. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/cache_debug.py +0 -0
  39. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/catalog.py +0 -0
  40. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/catalog_sql.py +0 -0
  41. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/MODULE_README.md +0 -0
  42. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/__init__.py +0 -0
  43. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/postgres_connection.py +0 -0
  44. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/postgrest.py +0 -0
  45. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/supabase_auth.py +0 -0
  46. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/supabase_config.py +0 -0
  47. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/client/supabase_manager.py +0 -0
  48. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  49. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/MODULE_README.md +0 -0
  50. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  51. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/TASKS.md +0 -0
  52. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/__init__.py +0 -0
  53. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/admin_lane.py +0 -0
  54. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/base.py +0 -0
  55. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/config.py +0 -0
  56. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/connections.py +0 -0
  57. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/db_function.py +0 -0
  58. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/diagnostics.py +0 -0
  59. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/expressions.py +0 -0
  60. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/extended.py +0 -0
  61. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/fields.py +0 -0
  62. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/introspection.py +0 -0
  63. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/listen.py +0 -0
  64. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/loop_filters.py +0 -0
  65. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/model_dto.py +0 -0
  66. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/model_view.py +0 -0
  67. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/one_database.py +0 -0
  68. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/paginator.py +0 -0
  69. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/pool_maintenance.py +0 -0
  70. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/pool_watch.py +0 -0
  71. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/pooler_role.py +0 -0
  72. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/pydantic_bridge.py +0 -0
  73. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/registry.py +0 -0
  74. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/relations.py +0 -0
  75. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/resilience.py +0 -0
  76. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/rls_session.py +0 -0
  77. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/session_context.py +0 -0
  78. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/signals.py +0 -0
  79. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/statement_ceiling.py +0 -0
  80. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/tls.py +0 -0
  81. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/transaction.py +0 -0
  82. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/types.py +0 -0
  83. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/write_queue.py +0 -0
  84. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/core/write_retry.py +0 -0
  85. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/entity.py +0 -0
  86. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/error_handling.py +0 -0
  87. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/exceptions.py +0 -0
  88. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/extended/__init__.py +0 -0
  89. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/extended/app_error_handler.py +0 -0
  90. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/identity_rule.py +0 -0
  91. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/local_sqlite.py +0 -0
  92. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/middleware/__init__.py +0 -0
  93. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/middleware/base.py +0 -0
  94. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/MODULE_README.md +0 -0
  95. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/__init__.py +0 -0
  96. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/cli.py +0 -0
  97. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/ddl.py +0 -0
  98. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/diff.py +0 -0
  99. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/executor.py +0 -0
  100. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/integration.py +0 -0
  101. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/loader.py +0 -0
  102. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/operations.py +0 -0
  103. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/state.py +0 -0
  104. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/migrations/table_filter.py +0 -0
  105. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/no_org_assignment.py +0 -0
  106. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/FEATURE.md +0 -0
  107. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/MODULE_README.md +0 -0
  108. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/__init__.py +0 -0
  109. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/bulk_update_values.py +0 -0
  110. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/catalog_select.py +0 -0
  111. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/conflict.py +0 -0
  112. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/conflict_writes.py +0 -0
  113. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/create.py +0 -0
  114. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/db_functions.py +0 -0
  115. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/delete.py +0 -0
  116. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/dynamic_admin.py +0 -0
  117. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/dynamic_crud.py +0 -0
  118. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/graph_walk.py +0 -0
  119. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/latest_rows.py +0 -0
  120. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/queue_claim.py +0 -0
  121. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/read.py +0 -0
  122. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/relational_backfill.py +0 -0
  123. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/staging_load.py +0 -0
  124. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/operations/update.py +0 -0
  125. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/platform_access.py +0 -0
  126. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/platform_db.py +0 -0
  127. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/py.typed +0 -0
  128. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/pytest_live_db_guard.py +0 -0
  129. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/pytest_plugin.py +0 -0
  130. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/python_sql/MODULE_README.md +0 -0
  131. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/python_sql/__init__.py +0 -0
  132. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/python_sql/db_objects.py +0 -0
  133. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  134. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  135. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/query/FEATURE.md +0 -0
  136. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/query/MODULE_README.md +0 -0
  137. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/query/__init__.py +0 -0
  138. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/query/builder.py +0 -0
  139. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/query/executor.py +0 -0
  140. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/resources/__init__.py +0 -0
  141. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  142. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  143. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/FEATURE.md +0 -0
  144. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  145. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/__init__.py +0 -0
  146. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/code_handler.py +0 -0
  147. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  148. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/columns.py +0 -0
  149. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/common.py +0 -0
  150. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/diff_preview.py +0 -0
  151. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  152. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/generator.py +0 -0
  153. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  154. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  155. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  156. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  157. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/package_wiring.py +0 -0
  158. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/relationships.py +0 -0
  159. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/runner.py +0 -0
  160. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/schema.py +0 -0
  161. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/schema_manager.py +0 -0
  162. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/tables.py +0 -0
  163. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/schema_builder/views.py +0 -0
  164. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  165. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/__init__.py +0 -0
  166. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/attachments.py +0 -0
  167. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/backup_restore.py +0 -0
  168. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/crypto.py +0 -0
  169. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  170. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/items.py +0 -0
  171. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/model.py +0 -0
  172. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  173. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/native_enable.py +0 -0
  174. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  175. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  176. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/native_source.py +0 -0
  177. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/org_service.py +0 -0
  178. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
  179. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/service.py +0 -0
  180. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/secrets_battery/vault_history.py +0 -0
  181. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/README.md +0 -0
  182. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/__init__.py +0 -0
  183. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/coalesce.py +0 -0
  184. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/dag.py +0 -0
  185. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/errors.py +0 -0
  186. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/fallback.py +0 -0
  187. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/flush.py +0 -0
  188. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/lifecycle.py +0 -0
  189. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/managed.py +0 -0
  190. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/op.py +0 -0
  191. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/reads.py +0 -0
  192. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/session.py +0 -0
  193. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/session/telemetry.py +0 -0
  194. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  195. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/__init__.py +0 -0
  196. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/executor.py +0 -0
  197. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/queries.py +0 -0
  198. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/registry.py +0 -0
  199. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/types.py +0 -0
  200. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/sql_executor/utils.py +0 -0
  201. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/state.py +0 -0
  202. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/utils/__init__.py +0 -0
  203. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/utils/sql_utils.py +0 -0
  204. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/utils/type_converters.py +0 -0
  205. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/matrx_orm/write_actor.py +0 -0
  206. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/scripts/git-branches.sh +0 -0
  207. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/scripts/publish.sh +0 -0
  208. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/scripts/release.sh +0 -0
  209. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/MODULE_README.md +0 -0
  210. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/__init__.py +0 -0
  211. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/conftest.py +0 -0
  212. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/MODULE_README.md +0 -0
  213. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/__init__.py +0 -0
  214. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_adapter_registry.py +0 -0
  215. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_admin_db_columns.py +0 -0
  216. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_admin_response_rendering.py +0 -0
  217. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_admin_search_negation.py +0 -0
  218. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_admin_search_sentinels.py +0 -0
  219. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_advisory_lock.py +0 -0
  220. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_agent_message.py +0 -0
  221. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_api_auth.py +0 -0
  222. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_api_config.py +0 -0
  223. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_api_handlers.py +0 -0
  224. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_api_protocol.py +0 -0
  225. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_array_agg_order_by.py +0 -0
  226. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_association_trigger_actor_naming.py +0 -0
  227. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_associations.py +0 -0
  228. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_associations_wiring.py +0 -0
  229. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_bulk_hydration_offload.py +0 -0
  230. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_bulk_update_by_pk.py +0 -0
  231. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  232. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_cache_debug.py +0 -0
  233. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_call_function.py +0 -0
  234. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_case_when.py +0 -0
  235. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_catalog.py +0 -0
  236. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_column_scoped_writes.py +0 -0
  237. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_committed_row_guard.py +0 -0
  238. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_composite_pk_filter.py +0 -0
  239. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_composite_pk_write_paths.py +0 -0
  240. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_config.py +0 -0
  241. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_conflict_target.py +0 -0
  242. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_conflict_writes.py +0 -0
  243. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_connection_codecs.py +0 -0
  244. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_connection_poison_guard.py +0 -0
  245. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_connection_primitives.py +0 -0
  246. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_count_composite_distinct.py +0 -0
  247. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_count_limit_param_leak.py +0 -0
  248. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_db_function_field.py +0 -0
  249. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_ddl_generator.py +0 -0
  250. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_deadlock_retry.py +0 -0
  251. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_derived_table.py +0 -0
  252. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_dirty_tracking.py +0 -0
  253. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_dynamic_crud.py +0 -0
  254. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_exceptions.py +0 -0
  255. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  256. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_expression_primitives.py +0 -0
  257. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_fields.py +0 -0
  258. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  259. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_fk_cycle_resolution.py +0 -0
  260. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_from_alias.py +0 -0
  261. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_fts.py +0 -0
  262. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_func_expression_args.py +0 -0
  263. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_graph_walk.py +0 -0
  264. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_having_annotate_alias.py +0 -0
  265. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  266. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_introspect_rls_policies.py +0 -0
  267. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_join_and_aggregate.py +0 -0
  268. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_latest_rows.py +0 -0
  269. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_listen_notify.py +0 -0
  270. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_local_sqlite.py +0 -0
  271. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_lock_contention_retry.py +0 -0
  272. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_managed_write_guard.py +0 -0
  273. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_matrx_entity.py +0 -0
  274. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_migration_diff_types.py +0 -0
  275. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_migration_loader.py +0 -0
  276. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_model_instance.py +0 -0
  277. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_model_meta.py +0 -0
  278. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_optimistic_concurrency.py +0 -0
  279. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_order_by_expression.py +0 -0
  280. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_org_assignment_inventory.py +0 -0
  281. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  282. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_parameter_name_hydration.py +0 -0
  283. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_patch_jsonb_path.py +0 -0
  284. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_percentile_cont.py +0 -0
  285. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_persisted_count.py +0 -0
  286. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
  287. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_pool_create_never_wedges.py +0 -0
  288. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_pool_holder_census.py +0 -0
  289. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_pool_loop_recreation.py +0 -0
  290. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_pool_maintenance.py +0 -0
  291. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_postgrest_filters.py +0 -0
  292. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_pydantic_bridge.py +0 -0
  293. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_query_builder.py +0 -0
  294. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_query_error_detail.py +0 -0
  295. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_query_executor_sql.py +0 -0
  296. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_query_timeout.py +0 -0
  297. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  298. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_queue_claim.py +0 -0
  299. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_read_connection_retry.py +0 -0
  300. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_registry.py +0 -0
  301. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_registry_multi_database.py +0 -0
  302. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_registry_multi_schema.py +0 -0
  303. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_relational_backfill.py +0 -0
  304. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_relations.py +0 -0
  305. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_resilience.py +0 -0
  306. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_rls_session_scope.py +0 -0
  307. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_schema_exists.py +0 -0
  308. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_session_advisory_lock.py +0 -0
  309. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_standalone_write_session_context.py +0 -0
  310. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_state_cache.py +0 -0
  311. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_subquery_filter_raw.py +0 -0
  312. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_subquery_in_filter.py +0 -0
  313. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_subquery_nested_expressions.py +0 -0
  314. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_supabase_auth.py +0 -0
  315. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_supabase_config.py +0 -0
  316. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_tls.py +0 -0
  317. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_transaction_database_identity.py +0 -0
  318. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
  319. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
  320. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_typed_join_projection.py +0 -0
  321. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_typed_predicates.py +0 -0
  322. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_update_case_expression.py +0 -0
  323. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_update_subquery.py +0 -0
  324. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_update_with_rebase.py +0 -0
  325. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_upsert_default_leak.py +0 -0
  326. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_upsert_with_conflict.py +0 -0
  327. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_values_jsonb_decode.py +0 -0
  328. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_watched_lifecycle.py +0 -0
  329. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_write_queue_deadline.py +0 -0
  330. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level1/test_write_retry_semantics.py +0 -0
  331. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/MODULE_README.md +0 -0
  332. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/__init__.py +0 -0
  333. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/conftest.py +0 -0
  334. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_bulk_ops.py +0 -0
  335. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_cache_integration.py +0 -0
  336. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_crud.py +0 -0
  337. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_foreign_keys.py +0 -0
  338. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_m2m.py +0 -0
  339. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_manager.py +0 -0
  340. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_migrations_live.py +0 -0
  341. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_query_execution.py +0 -0
  342. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/test_schema_diff.py +0 -0
  343. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
  344. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/live_pooler_role.py +0 -0
  345. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/native_source_cases.py +0 -0
  346. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/native_source_oracle.rs +0 -0
  347. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/.env.example +0 -0
  348. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/README.md +0 -0
  349. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/__init__.py +0 -0
  350. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/generate.py +0 -0
  351. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/generated/.gitkeep +0 -0
  352. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/matrx_orm.yaml +0 -0
  353. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project/test_schema_generation.py +0 -0
  354. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/.env.example +0 -0
  355. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/README.md +0 -0
  356. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/__init__.py +0 -0
  357. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/client_example.py +0 -0
  358. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/client_example.ts +0 -0
  359. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  360. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/sample_project_desktop/server.py +0 -0
  361. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/entity_tests.py +0 -0
  362. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_base_generation.py +0 -0
  363. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  364. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_composite_unique_generation.py +0 -0
  365. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_dto_identity_generation.py +0 -0
  366. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_entity_capability_generation.py +0 -0
  367. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_enum_ordering.py +0 -0
  368. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_generate_schema.py +0 -0
  369. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_junction_analysis.py +0 -0
  370. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_multi_schema_output.py +0 -0
  371. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_schema_analysis.py +0 -0
  372. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_sql_expression_defaults.py +0 -0
  373. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_table_relationships_query.py +0 -0
  374. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema/test_view_generation.py +0 -0
  375. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema_builder/test_array_default_parsing.py +0 -0
  376. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  377. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  378. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/schema_builder/test_never_filter_columns.py +0 -0
  379. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/__init__.py +0 -0
  380. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/conftest.py +0 -0
  381. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
  382. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_cache_no_downgrade.py +0 -0
  383. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_capture_poison_proof.py +0 -0
  384. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_coalesce.py +0 -0
  385. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_dag.py +0 -0
  386. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_disk_spill_fallback.py +0 -0
  387. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_flush_individual_fallback.py +0 -0
  388. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_governed_write.py +0 -0
  389. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_live_db_guard_plugin.py +0 -0
  390. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_managed.py +0 -0
  391. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_op_enqueue_site.py +0 -0
  392. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_reads.py +0 -0
  393. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_record_error_bounded_insert.py +0 -0
  394. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_record_error_storm.py +0 -0
  395. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_session.py +0 -0
  396. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/session/test_spill_guard_plugin.py +0 -0
  397. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_array_arg_element_type.py +0 -0
  398. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_attachment_mutation_serialization.py +0 -0
  399. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_backup_alias_conflict.py +0 -0
  400. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_backup_history_restore.py +0 -0
  401. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_backup_restore_live.py +0 -0
  402. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_call_function_as.py +0 -0
  403. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_call_function_none_mode.py +0 -0
  404. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
  405. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_database_name_alias.py +0 -0
  406. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_db_functions.py +0 -0
  407. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_dsn_password_masking.py +0 -0
  408. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_dynamic_select_unregistered.py +0 -0
  409. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  410. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_keyed_digest.py +0 -0
  411. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_model_cls_refactor.py +0 -0
  412. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_native_enable.py +0 -0
  413. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_native_lifecycle.py +0 -0
  414. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_native_lifecycle_fences.py +0 -0
  415. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_native_passkey_receipts.py +0 -0
  416. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_native_source.py +0 -0
  417. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  418. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_one_database.py +0 -0
  419. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_order_by_desc_nulls_last.py +0 -0
  420. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_org_vault_gate.py +0 -0
  421. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_pooler_role_guard.py +0 -0
  422. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_secret_audit_names_its_organization.py +0 -0
  423. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_secrets_battery.py +0 -0
  424. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_secrets_minting_keys.py +0 -0
  425. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_shared_lock_guard.py +0 -0
  426. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_sql_param_casts.py +0 -0
  427. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_statement_ceiling_warning.py +0 -0
  428. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_sync_twins_guard.py +0 -0
  429. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_update_result_truthiness.py +0 -0
  430. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_user_visible_lookup.py +0 -0
  431. {matrx_orm-3.1.200 → matrx_orm-3.1.201}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - **Fix: the shared-lock sampler no longer leaves its timeouts on a pooled backend.**
6
+ `pytest_lock_guard` sent session-level `set lock_timeout` / `set statement_timeout`
7
+ through the transaction pooler, where they stay on the backend for the next client
8
+ (both found leaked on the clone's pool, 2026-10-01). It now uses `SET LOCAL` inside
9
+ each sample's own transaction.
5
10
  - **Fix: a driver timeout longer than the server's statement ceiling screams.**
6
11
  `call_function` / `call_function_as` / `execute_query` read the connection's
7
12
  effective `statement_timeout` and log one WARNING per call site when the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.200
3
+ Version: 3.1.201
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
@@ -282,6 +282,34 @@ trip from a laptop): 435 → ~200 round trips. Pinned by
282
282
  `tests/level1/test_transaction_pool_release_sends_nothing.py` and
283
283
  `tests/level1/test_rls_session_scope.py`.
284
284
 
285
+ **A backend another client left read-only never refuses our writes.** A transaction
286
+ pooler shares server connections with every client of the same login and never resets
287
+ one between clients, so a session-level `SET default_transaction_read_only = on` (or
288
+ `SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY`) sent outside a transaction — the
289
+ shape of an ad-hoc "read-only production" helper — leaves that backend read-only for
290
+ everyone (2026-10-01 incident: dispatchers, workflow claims, request audit, chat writes;
291
+ recurring since 2026-09-12). A transaction-mode pool's connections are
292
+ `ReadWriteConnection` (`read_write.py`): every top-level BEGIN naming no access mode is
293
+ sent as `... READ WRITE` (zero extra round trips), and an autocommit statement refused as
294
+ read-only re-runs once inside `BEGIN READ WRITE` with a WARNING naming the cause. An
295
+ explicit `READ ONLY` is kept; the session is never rewritten. Read-only work through the
296
+ pooler belongs in `BEGIN READ ONLY`, never a session SET. Pinned by
297
+ `tests/test_a_read_only_backend_never_refuses_our_writes.py` (loopback `ISOLATED_PG17_DSN`)
298
+ and `tests/level1/test_read_write_declared.py`.
299
+
300
+ **A backend handed over inside another client's transaction never takes our writes.** The
301
+ second shape of the same incident: a probe sent `begin read only; …; rollback;` through the
302
+ pooler, an error or timeout skipped the `rollback`, and the pooler handed the open READ ONLY
303
+ transaction to the server. The pooler answers our handshake "idle", so asyncpg learns of it
304
+ only from the reply. A statement that comes back inside a transaction this connection never
305
+ opened is the stranger's: rolled back, logged at ERROR with the remedy, re-run once in our own
306
+ `BEGIN READ WRITE … COMMIT` (the rollback undid it, so exactly once). A top-level BEGIN answered
307
+ with 25001 is the same: rolled back and begun again; a second stranger raises
308
+ `InheritedTransactionError` by name. Pinned by
309
+ `tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py`, which runs an
310
+ in-process transaction pooler that never resets its one server connection (loopback
311
+ `ISOLATED_PG17_DSN`; 4 of 5 fail on the code before it).
312
+
285
313
  **The destructive live proof is loopback-only.**
286
314
  `tests/live_pooler_role.py::assert_isolated_pooler_target` runs before DSN
287
315
  construction or connection and refuses every shared or remote database. The proof
@@ -360,6 +388,8 @@ can never disagree about who the blocker was.
360
388
  Verified against the live database: 2026-08-21.
361
389
 
362
390
  ## Change log
391
+ - 2026-10-01: `ReadWriteConnection` rolls back a stranger's open transaction it was handed (statement reply or 25001 on BEGIN), re-runs our statement in its own transaction, and names a repeat `InheritedTransactionError`.
392
+ - 2026-10-01: `ReadWriteConnection` for transaction-mode pools — every BEGIN declares READ WRITE and a read-only-refused autocommit statement re-runs once in one; a pooled backend another client left read-only at session level no longer fails the platform's writes.
363
393
  - 2026-09-30: Fewer round trips per request (agent-launch latency, lane deep): one-statement proof of a clean empty read; ceilings + declared context + `rls_session` settings in ONE BEGIN-time `set_config` statement (`transaction(opening_gucs=)`, `set_local_gucs`, `emit_local_gucs`); transaction-mode pools release with no reset statement. 435 → ~200 round trips on a flashcard launch.
364
394
  - 2026-09-30: `statement_ceiling.py` — a driver timeout above the server's statement ceiling is logged once per call site; `SERVER_CEILING` sentinel. ~19 callers passed 60-600 s under the 30 s `postgres` ceiling (the nightly keyword classifier was cancelled at 30 s for eight days).
365
395
  - 2026-09-12 (later): ONE retry mechanism. Two independent lock-retry
@@ -25,6 +25,7 @@ from matrx_orm.core.pooler_role import (
25
25
  reprove_empty_read,
26
26
  )
27
27
  from matrx_orm.core.statement_ceiling import resolve_driver_timeout
28
+ from matrx_orm.core.read_write import ReadWriteConnection
28
29
  from matrx_orm.core.tls import resolve_asyncpg_ssl
29
30
  from matrx_orm.exceptions import (
30
31
  AdapterError,
@@ -693,6 +694,15 @@ class AsyncDatabaseManager:
693
694
  if effective_mode == "transaction"
694
695
  else None
695
696
  ),
697
+ # A transaction pooler hands us server connections other
698
+ # clients may have left read-only at SESSION level; every
699
+ # BEGIN declares READ WRITE and a refused autocommit
700
+ # statement re-runs once in one (core/read_write.py).
701
+ connection_class=(
702
+ ReadWriteConnection
703
+ if effective_mode == "transaction"
704
+ else asyncpg.Connection
705
+ ),
696
706
  )
697
707
  try:
698
708
  async with asyncio.timeout(create_timeout):
@@ -0,0 +1,221 @@
1
+ """A pooled backend another client left read-only never refuses our writes.
2
+
3
+ A transaction-mode pooler (Supavisor / PgBouncer, port 6543) shares its server
4
+ connections between EVERY client that logs in as the same user, and never resets
5
+ one between clients. A client that runs a session-level read-only setting outside a
6
+ transaction — ``SET default_transaction_read_only = on``,
7
+ ``SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY`` (the shape of an ad-hoc
8
+ "read-only production" helper) — leaves it on whichever server connection the pooler
9
+ handed it. Every later transaction routed there starts read-only, and every write
10
+ fails with ``cannot execute ... in a read-only transaction`` while the database is
11
+ writable. (2026-10-01: SMS and notification dispatchers, workflow claims, the request
12
+ audit and chat writes; recurring since at least 2026-09-12. Proven live: one of 21
13
+ pooled backends carried ``default_transaction_read_only = on``, ``source = session``.)
14
+
15
+ ``ReadWriteConnection`` is the connection class of every transaction-mode pool:
16
+
17
+ * every top-level ``BEGIN`` that names no access mode is sent as ``BEGIN ... READ
18
+ WRITE`` — the ORM's own ``transaction()`` and any raw ``conn.transaction()``
19
+ alike, at no extra round trip. An explicit ``READ ONLY`` is kept.
20
+ * an AUTOCOMMIT statement the backend refuses as read-only (SQLSTATE 25006) is re-run
21
+ once inside one explicit ``BEGIN READ WRITE`` transaction, and the event is logged
22
+ with its remedy. The refusal proves the statement never ran: Postgres checks the
23
+ access mode before a statement modifies anything, and an implicit transaction
24
+ rolls back whole.
25
+
26
+ THE SECOND SHAPE — a server connection handed over INSIDE another client's transaction
27
+ (2026-10-01: live probes sent ``begin read only; …; rollback;`` as one string through the
28
+ pooler; an error or timeout skipped the ``rollback`` and the open READ ONLY transaction went to
29
+ the platform server). A transaction pooler answers our handshake with "idle" itself, so asyncpg
30
+ only learns of the stranger's transaction from the reply to our next statement:
31
+
32
+ * a statement that comes back inside a transaction this connection never opened (asyncpg's
33
+ ``_top_xact`` unset, no BEGIN of ours open) ran inside a STRANGER's transaction: that
34
+ transaction is rolled back, logged at ERROR with its remedy, and the statement re-runs once in
35
+ our own ``BEGIN READ WRITE … COMMIT``. The rollback undid whatever the statement did, so the
36
+ re-run is exactly once.
37
+ * a top-level ``BEGIN`` the server answers with SQLSTATE 25001 ("there is already a transaction
38
+ in progress" / "read-write mode must be set before any query") is the same stranger: rolled
39
+ back, begun again once; a second stranger raises ``InheritedTransactionError`` by name —
40
+ never a bare 25006 three statements later.
41
+
42
+ It never touches the session it was handed — the poison stays visible to whoever
43
+ investigates (``SHOW default_transaction_read_only``) and the guard stays per
44
+ transaction. Session-mode pools keep the plain asyncpg connection: their server
45
+ connection is ours alone and asyncpg's release reset clears it.
46
+ """
47
+
48
+ from __future__ import annotations
49
+
50
+ import logging
51
+ import re
52
+ from collections.abc import Awaitable, Callable
53
+ from typing import Any
54
+
55
+ import asyncpg
56
+
57
+ logger = logging.getLogger(__name__)
58
+
59
+ # One statement that opens a top-level transaction: BEGIN / BEGIN WORK / BEGIN
60
+ # TRANSACTION / START TRANSACTION, optionally with modes and one trailing ';'.
61
+ _BEGIN_STATEMENT = re.compile(
62
+ r"^\s*(?:BEGIN|START\s+TRANSACTION)\b(?P<modes>[^;]*?)\s*;?\s*$",
63
+ re.IGNORECASE | re.DOTALL,
64
+ )
65
+ _ACCESS_MODE = re.compile(r"\bREAD\s+(?:ONLY|WRITE)\b", re.IGNORECASE)
66
+ # A statement that ends the top-level transaction (not ROLLBACK TO / RELEASE a savepoint).
67
+ _END_STATEMENT = re.compile(
68
+ r"^\s*(?:COMMIT|END|ABORT|ROLLBACK)\b(?!\s+(?:TO|PREPARED)\b)(?!\s+(?:WORK|TRANSACTION)\s+TO\b)",
69
+ re.IGNORECASE,
70
+ )
71
+ _ACTIVE_SQL_TRANSACTION = "25001"
72
+
73
+
74
+ def declare_read_write(query: str) -> str:
75
+ """``query`` with ``READ WRITE`` declared when it is a BEGIN naming no access mode.
76
+
77
+ Anything else — a savepoint, a multi-statement script, a BEGIN that already says
78
+ ``READ ONLY`` or ``READ WRITE`` — is returned unchanged.
79
+ """
80
+ match = _BEGIN_STATEMENT.match(query)
81
+ if match is None or _ACCESS_MODE.search(match.group("modes")):
82
+ return query
83
+ return query.strip().rstrip(";").rstrip() + " READ WRITE"
84
+
85
+
86
+ _REFUSED_REMEDY = (
87
+ "[matrx_orm] A pooled server connection refused an autocommit statement as "
88
+ "read-only: another client of the transaction pooler left a SESSION-level "
89
+ "read-only default on it (SET default_transaction_read_only / SET SESSION "
90
+ "CHARACTERISTICS AS TRANSACTION READ ONLY sent outside a transaction). The "
91
+ "statement never ran and was re-run inside BEGIN READ WRITE. Remedy: find the "
92
+ "client sending that SET through the pooler — read-only work belongs in "
93
+ "BEGIN READ ONLY, one transaction at a time. Statement: %s"
94
+ )
95
+
96
+
97
+ _STRANGER_REMEDY = (
98
+ "[matrx_orm] The pooler handed this connection a server connection still inside "
99
+ "another client's open transaction (a client of the transaction pooler left without "
100
+ "COMMIT/ROLLBACK, e.g. a 'begin read only; ...; rollback;' probe that errored or timed "
101
+ "out). That transaction was rolled back and our statement re-runs in its own "
102
+ "transaction. Remedy: find the client — probes belong on a DIRECT connection (:5432) "
103
+ "with ROLLBACK in a finally. Statement: %s"
104
+ )
105
+
106
+
107
+ class InheritedTransactionError(RuntimeError):
108
+ """Every server connection the pooler offered was inside another client's transaction."""
109
+
110
+
111
+ class ReadWriteConnection(asyncpg.Connection): # type: ignore[misc]
112
+ """The connection class of a transaction-mode pool (see module docstring)."""
113
+
114
+ _matrx_own_xact = False # a top-level BEGIN of ours is open
115
+ _matrx_saw_25001 = False # the server warned "already a transaction in progress"
116
+
117
+ def _process_log_message(self, fields: Any, last_query: Any) -> None:
118
+ if fields.get("C") == _ACTIVE_SQL_TRANSACTION:
119
+ self._matrx_saw_25001 = True
120
+ super()._process_log_message(fields, last_query)
121
+
122
+ async def _reset(self) -> None:
123
+ self._matrx_own_xact = False
124
+ await super()._reset()
125
+
126
+ def _in_strangers_transaction(self) -> bool:
127
+ return self.is_in_transaction() and self._top_xact is None and not self._matrx_own_xact
128
+
129
+ async def _drop_strangers_transaction(self, query: str) -> None:
130
+ logger.error(_STRANGER_REMEDY, " ".join(str(query).split())[:160])
131
+ self._matrx_own_xact = False
132
+ await asyncpg.Connection.execute(self, "ROLLBACK")
133
+
134
+ async def _begin(self, query: str) -> str:
135
+ """A top-level BEGIN that never silently joins a stranger's transaction."""
136
+ if self._in_strangers_transaction():
137
+ await self._drop_strangers_transaction(query)
138
+ for _ in range(2):
139
+ self._matrx_saw_25001 = False
140
+ try:
141
+ result = await asyncpg.Connection.execute(self, query)
142
+ except asyncpg.exceptions.ActiveSQLTransactionError:
143
+ pass
144
+ else:
145
+ if not self._matrx_saw_25001:
146
+ self._matrx_own_xact = True
147
+ return result
148
+ await self._drop_strangers_transaction(query)
149
+ raise InheritedTransactionError(
150
+ "Two server connections in a row were inside another client's open transaction; "
151
+ "nothing was written. A client of the transaction pooler is leaving transactions "
152
+ "open (see matrx_orm/core/read_write.py)."
153
+ )
154
+
155
+ async def _in_own_transaction(
156
+ self, call: Callable[..., Awaitable[Any]], query: str, args: tuple[Any, ...], kwargs: dict[str, Any]
157
+ ) -> Any:
158
+ await self._begin("BEGIN READ WRITE")
159
+ try:
160
+ result = await call(query, *args, **kwargs)
161
+ except BaseException:
162
+ self._matrx_own_xact = False
163
+ try:
164
+ await asyncpg.Connection.execute(self, "ROLLBACK")
165
+ except Exception: # noqa: BLE001 — the pool's release rolls back what this cannot
166
+ pass
167
+ raise
168
+ self._matrx_own_xact = False
169
+ await asyncpg.Connection.execute(self, "COMMIT")
170
+ return result
171
+
172
+ async def _healed(
173
+ self, call: Callable[..., Awaitable[Any]], query: str, args: tuple[Any, ...], kwargs: dict[str, Any]
174
+ ) -> Any:
175
+ if self._in_strangers_transaction():
176
+ await self._drop_strangers_transaction(query)
177
+ if self.is_in_transaction():
178
+ result = await call(query, *args, **kwargs)
179
+ if self._top_xact is None and _END_STATEMENT.match(str(query)):
180
+ self._matrx_own_xact = False
181
+ return result
182
+ try:
183
+ result = await call(query, *args, **kwargs)
184
+ except asyncpg.exceptions.ReadOnlySQLTransactionError:
185
+ if self.is_in_transaction():
186
+ await self._drop_strangers_transaction(query)
187
+ else:
188
+ logger.warning(_REFUSED_REMEDY, " ".join(str(query).split())[:160])
189
+ except Exception:
190
+ if not self._in_strangers_transaction():
191
+ raise
192
+ await self._drop_strangers_transaction(query)
193
+ else:
194
+ if not self._in_strangers_transaction():
195
+ return result
196
+ # The reply came from inside a stranger's transaction; rolling it back undid it.
197
+ await self._drop_strangers_transaction(query)
198
+ return await self._in_own_transaction(call, query, args, kwargs)
199
+
200
+ async def execute(self, query: str, *args: Any, **kwargs: Any) -> str:
201
+ if not args:
202
+ declared = declare_read_write(query)
203
+ if _BEGIN_STATEMENT.match(declared) and not (self.is_in_transaction() and not self._in_strangers_transaction()):
204
+ return await self._begin(declared)
205
+ query = declared
206
+ return await self._healed(super().execute, query, args, kwargs)
207
+
208
+ async def fetch(self, query: str, *args: Any, **kwargs: Any) -> list[Any]:
209
+ return await self._healed(super().fetch, query, args, kwargs)
210
+
211
+ async def fetchrow(self, query: str, *args: Any, **kwargs: Any) -> Any:
212
+ return await self._healed(super().fetchrow, query, args, kwargs)
213
+
214
+ async def fetchval(self, query: str, *args: Any, **kwargs: Any) -> Any:
215
+ return await self._healed(super().fetchval, query, args, kwargs)
216
+
217
+ async def executemany(self, command: str, args: Any, **kwargs: Any) -> None:
218
+ return await self._healed(super().executemany, command, (args,), kwargs)
219
+
220
+
221
+ __all__ = ["InheritedTransactionError", "ReadWriteConnection", "declare_read_write"]
@@ -413,13 +413,21 @@ def _run_sampler() -> None: # pragma: no cover — exercised by the guard's own
413
413
  with psycopg.connect(
414
414
  _STATE.dsn, autocommit=True, prepare_threshold=None
415
415
  ) as conn, conn.cursor() as cur:
416
- cur.execute("set lock_timeout = '2s'")
417
- cur.execute("set statement_timeout = '10s'")
418
- _STATE.baseline_oids = _baseline_oids(cur)
416
+ # The limits are SET LOCAL inside each statement's own transaction, never a session SET:
417
+ # through Supavisor's transaction pooler a session SET stays on the backend and the next
418
+ # client inherits it (lock_timeout=2s / statement_timeout=10s were found leaked on the
419
+ # clone's pool, 2026-10-01 — common-docs v5/PROGRESS-POOLER-LEAK-GUARD.md).
420
+ def limited(fn):
421
+ with conn.transaction():
422
+ cur.execute("set local lock_timeout = '2s'")
423
+ cur.execute("set local statement_timeout = '10s'")
424
+ return fn()
425
+
426
+ _STATE.baseline_oids = limited(lambda: _baseline_oids(cur))
419
427
  _STATE.active = True
420
428
  while not _STATE.stop.wait(SAMPLE_INTERVAL_SECONDS):
421
429
  try:
422
- found = _sample_once(cur, time.monotonic())
430
+ found = limited(lambda: _sample_once(cur, time.monotonic()))
423
431
  except Exception as exc: # noqa: BLE001 — never kill the run over a sample
424
432
  log.warning("[%s] sample failed: %s", _PLUGIN_NAME, exc)
425
433
  continue
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.200"
3
+ version = "3.1.201"
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" }
@@ -0,0 +1,108 @@
1
+ """A transaction-mode pool declares READ WRITE on every BEGIN (no database needed).
2
+
3
+ The live half — a backend another client left read-only at session level, written
4
+ through anyway — is ``tests/test_a_read_only_backend_never_refuses_our_writes.py``.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ import asyncpg
12
+ import pytest
13
+
14
+ from matrx_orm.core import async_db_manager as adm
15
+ from matrx_orm.core.async_db_manager import AsyncDatabaseManager
16
+ from matrx_orm.core.config import DatabaseProjectConfig, register_database, registry
17
+ from matrx_orm.core.read_write import ReadWriteConnection, declare_read_write
18
+
19
+
20
+ @pytest.mark.parametrize(
21
+ ("sent", "expected"),
22
+ [
23
+ ("BEGIN", "BEGIN READ WRITE"),
24
+ ("BEGIN;", "BEGIN READ WRITE"),
25
+ ("begin", "begin READ WRITE"),
26
+ ("BEGIN ISOLATION LEVEL REPEATABLE READ;", "BEGIN ISOLATION LEVEL REPEATABLE READ READ WRITE"),
27
+ ("BEGIN ISOLATION LEVEL READ COMMITTED;", "BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE"),
28
+ ("START TRANSACTION", "START TRANSACTION READ WRITE"),
29
+ ("BEGIN WORK", "BEGIN WORK READ WRITE"),
30
+ ],
31
+ )
32
+ def test_a_begin_naming_no_access_mode_declares_read_write(sent: str, expected: str) -> None:
33
+ assert declare_read_write(sent) == expected
34
+
35
+
36
+ @pytest.mark.parametrize(
37
+ "sent",
38
+ [
39
+ "BEGIN READ ONLY;",
40
+ "BEGIN ISOLATION LEVEL SERIALIZABLE READ ONLY DEFERRABLE;",
41
+ "begin read only",
42
+ "BEGIN READ WRITE",
43
+ "SAVEPOINT sp_1;",
44
+ "BEGIN; SET LOCAL statement_timeout = 1000",
45
+ "COMMIT;",
46
+ "SELECT 'BEGIN'",
47
+ ],
48
+ )
49
+ def test_everything_else_is_sent_unchanged(sent: str) -> None:
50
+ assert declare_read_write(sent) == sent
51
+
52
+
53
+ class _FakePool:
54
+ def get_size(self) -> int:
55
+ return 1
56
+
57
+ def terminate(self) -> None:
58
+ pass
59
+
60
+
61
+ @pytest.mark.asyncio
62
+ @pytest.mark.parametrize(
63
+ ("port", "expected"), [(6543, ReadWriteConnection), (5432, asyncpg.Connection)]
64
+ )
65
+ async def test_only_a_transaction_mode_pool_uses_the_read_write_connection(
66
+ monkeypatch, port: int, expected: type
67
+ ) -> None:
68
+ seen: dict[str, Any] = {}
69
+
70
+ async def _make(pool: _FakePool) -> _FakePool:
71
+ return pool
72
+
73
+ def fake_create_pool(**kwargs: Any):
74
+ seen.update(kwargs)
75
+ return _make(_FakePool())
76
+
77
+ monkeypatch.setattr(adm.asyncpg, "create_pool", fake_create_pool)
78
+ monkeypatch.setattr(AsyncDatabaseManager, "_start_keepalive", classmethod(lambda *_a: None))
79
+ name = f"read_write_class_{port}"
80
+ registry._configs.pop(name, None)
81
+ register_database(
82
+ DatabaseProjectConfig(
83
+ name=name,
84
+ alias=f"{name}_alias",
85
+ host="127.0.0.1",
86
+ port=str(port),
87
+ database_name="postgres",
88
+ user="postgres",
89
+ password="unused",
90
+ pool_min=1,
91
+ pool_max=2,
92
+ ssl=False,
93
+ write_queue_enabled=False,
94
+ )
95
+ )
96
+ try:
97
+ await AsyncDatabaseManager.get_pool(name)
98
+ finally:
99
+ AsyncDatabaseManager._pools.pop(name, None)
100
+ AsyncDatabaseManager._pool_loops.pop(name, None)
101
+ AsyncDatabaseManager._locks.pop(name, None)
102
+ AsyncDatabaseManager._growth_locks.pop(name, None)
103
+ task = AsyncDatabaseManager._keepalive_tasks.pop(name, None)
104
+ if task is not None:
105
+ task.cancel()
106
+ registry._configs.pop(name, None)
107
+
108
+ assert seen.get("connection_class") is expected