matrx-orm 3.1.244__tar.gz → 3.1.246__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/PKG-INFO +2 -2
  2. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/associations.py +6 -1
  3. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/transaction.py +26 -2
  4. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/entity.py +2 -1
  5. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/platform_access.py +1 -1
  6. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/items.py +3 -1
  7. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/org_service.py +3 -5
  8. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/service.py +3 -2
  9. matrx_orm-3.1.246/matrx_orm/secrets_battery/use_stamp.py +27 -0
  10. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/fallback.py +72 -2
  11. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/pyproject.toml +2 -2
  12. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_call_function.py +4 -4
  13. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_db_function_field.py +2 -2
  14. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_deadlock_retry.py +2 -2
  15. matrx_orm-3.1.246/tests/level1/test_registry_reads_outside_the_person_session.py +49 -0
  16. matrx_orm-3.1.246/tests/session/test_record_error_group_open.py +152 -0
  17. matrx_orm-3.1.246/tests/test_a_failed_use_stamp_never_fails_the_read.py +48 -0
  18. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/.gitignore +0 -0
  19. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/AGENTS.md +0 -0
  20. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/BASE_CLASS_METHODS.md +0 -0
  21. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/CHANGELOG.md +0 -0
  22. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/CLAUDE.md +0 -0
  23. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/MODEL_API.md +0 -0
  24. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/README.md +0 -0
  25. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/database/orm/extended/managers/ai_model_base.py +0 -0
  26. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/docs/migrations.md +0 -0
  27. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/FEATURE.md +0 -0
  28. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/MODULE_README.md +0 -0
  29. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/__init__.py +0 -0
  30. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/adapters/MODULE_README.md +0 -0
  31. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/adapters/__init__.py +0 -0
  32. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/adapters/async_postgresql.py +0 -0
  33. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/adapters/base_adapter.py +0 -0
  34. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  35. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/adapters/supabase_adapter.py +0 -0
  36. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/admin/FEATURE.md +0 -0
  37. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/admin/__init__.py +0 -0
  38. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/admin/router.py +0 -0
  39. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/api/__init__.py +0 -0
  40. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/api/auth.py +0 -0
  41. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/api/config.py +0 -0
  42. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/api/handlers.py +0 -0
  43. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/api/protocol.py +0 -0
  44. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/api/server.py +0 -0
  45. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/cache_debug.py +0 -0
  46. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/catalog.py +0 -0
  47. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/catalog_sql.py +0 -0
  48. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/MODULE_README.md +0 -0
  49. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/__init__.py +0 -0
  50. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/postgres_connection.py +0 -0
  51. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/postgrest.py +0 -0
  52. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/supabase_auth.py +0 -0
  53. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/supabase_config.py +0 -0
  54. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/client/supabase_manager.py +0 -0
  55. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  56. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/FEATURE.md +0 -0
  57. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/MODULE_README.md +0 -0
  58. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  59. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/TASKS.md +0 -0
  60. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/__init__.py +0 -0
  61. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/admin_lane.py +0 -0
  62. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/async_db_manager.py +0 -0
  63. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/base.py +0 -0
  64. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/config.py +0 -0
  65. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/connections.py +0 -0
  66. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/db_function.py +0 -0
  67. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/diagnostics.py +0 -0
  68. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/expressions.py +0 -0
  69. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/extended.py +0 -0
  70. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/fields.py +0 -0
  71. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/foreign_session_state.py +0 -0
  72. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/introspection.py +0 -0
  73. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/listen.py +0 -0
  74. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/loop_filters.py +0 -0
  75. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/model_dto.py +0 -0
  76. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/model_view.py +0 -0
  77. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/one_database.py +0 -0
  78. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/paginator.py +0 -0
  79. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/pool_maintenance.py +0 -0
  80. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/pool_watch.py +0 -0
  81. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/pooler_role.py +0 -0
  82. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/pydantic_bridge.py +0 -0
  83. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/read_write.py +0 -0
  84. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/registry.py +0 -0
  85. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/relations.py +0 -0
  86. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/resilience.py +0 -0
  87. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/rls_session.py +0 -0
  88. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/session_context.py +0 -0
  89. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/signals.py +0 -0
  90. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/statement_ceiling.py +0 -0
  91. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/tls.py +0 -0
  92. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/types.py +0 -0
  93. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/write_queue.py +0 -0
  94. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/core/write_retry.py +0 -0
  95. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/error_handling.py +0 -0
  96. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/exceptions.py +0 -0
  97. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/extended/__init__.py +0 -0
  98. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/extended/app_error_handler.py +0 -0
  99. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/identity_rule.py +0 -0
  100. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/local_sqlite.py +0 -0
  101. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/middleware/__init__.py +0 -0
  102. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/middleware/base.py +0 -0
  103. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/MODULE_README.md +0 -0
  104. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/__init__.py +0 -0
  105. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/cli.py +0 -0
  106. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/ddl.py +0 -0
  107. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/diff.py +0 -0
  108. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/executor.py +0 -0
  109. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/integration.py +0 -0
  110. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/loader.py +0 -0
  111. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/operations.py +0 -0
  112. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/state.py +0 -0
  113. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/migrations/table_filter.py +0 -0
  114. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/no_org_assignment.py +0 -0
  115. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/FEATURE.md +0 -0
  116. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/MODULE_README.md +0 -0
  117. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/__init__.py +0 -0
  118. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/bulk_update_values.py +0 -0
  119. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/catalog_select.py +0 -0
  120. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/conflict.py +0 -0
  121. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/conflict_writes.py +0 -0
  122. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/create.py +0 -0
  123. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/db_functions.py +0 -0
  124. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/delete.py +0 -0
  125. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/dynamic_admin.py +0 -0
  126. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/dynamic_crud.py +0 -0
  127. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/graph_walk.py +0 -0
  128. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/latest_rows.py +0 -0
  129. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/queue_claim.py +0 -0
  130. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/read.py +0 -0
  131. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/relational_backfill.py +0 -0
  132. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/staging_load.py +0 -0
  133. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/operations/update.py +0 -0
  134. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/platform_db.py +0 -0
  135. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/py.typed +0 -0
  136. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/pytest_lock_guard.py +0 -0
  137. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/pytest_plugin.py +0 -0
  138. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/python_sql/MODULE_README.md +0 -0
  139. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/python_sql/__init__.py +0 -0
  140. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/python_sql/db_objects.py +0 -0
  141. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  142. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  143. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/query/FEATURE.md +0 -0
  144. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/query/MODULE_README.md +0 -0
  145. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/query/__init__.py +0 -0
  146. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/query/builder.py +0 -0
  147. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/query/executor.py +0 -0
  148. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/resources/__init__.py +0 -0
  149. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  150. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  151. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/FEATURE.md +0 -0
  152. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  153. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/__init__.py +0 -0
  154. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/code_handler.py +0 -0
  155. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  156. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/columns.py +0 -0
  157. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/common.py +0 -0
  158. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/diff_preview.py +0 -0
  159. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  160. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/excluded_targets.py +0 -0
  161. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/generator.py +0 -0
  162. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  163. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  164. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  165. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  166. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/package_wiring.py +0 -0
  167. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/relationships.py +0 -0
  168. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/runner.py +0 -0
  169. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/schema.py +0 -0
  170. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/schema_manager.py +0 -0
  171. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/tables.py +0 -0
  172. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/schema_builder/views.py +0 -0
  173. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  174. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/__init__.py +0 -0
  175. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/attachments.py +0 -0
  176. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/backup_restore.py +0 -0
  177. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/crypto.py +0 -0
  178. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  179. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/model.py +0 -0
  180. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  181. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_enable.py +0 -0
  182. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  183. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  184. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_source.py +0 -0
  185. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
  186. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/vault_history.py +0 -0
  187. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/README.md +0 -0
  188. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/__init__.py +0 -0
  189. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/coalesce.py +0 -0
  190. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/dag.py +0 -0
  191. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/errors.py +0 -0
  192. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/flush.py +0 -0
  193. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/lifecycle.py +0 -0
  194. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/managed.py +0 -0
  195. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/op.py +0 -0
  196. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/reads.py +0 -0
  197. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/session.py +0 -0
  198. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/session/telemetry.py +0 -0
  199. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  200. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/__init__.py +0 -0
  201. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/executor.py +0 -0
  202. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/queries.py +0 -0
  203. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/registry.py +0 -0
  204. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/types.py +0 -0
  205. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/sql_executor/utils.py +0 -0
  206. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/state.py +0 -0
  207. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/utils/__init__.py +0 -0
  208. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/utils/sql_utils.py +0 -0
  209. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/utils/type_converters.py +0 -0
  210. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/matrx_orm/write_actor.py +0 -0
  211. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/scripts/git-branches.sh +0 -0
  212. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/scripts/publish.sh +0 -0
  213. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/scripts/release.sh +0 -0
  214. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/MODULE_README.md +0 -0
  215. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/__init__.py +0 -0
  216. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/conftest.py +0 -0
  217. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/MODULE_README.md +0 -0
  218. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/__init__.py +0 -0
  219. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_adapter_registry.py +0 -0
  220. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_admin_db_columns.py +0 -0
  221. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_admin_response_rendering.py +0 -0
  222. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_admin_search_negation.py +0 -0
  223. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_admin_search_sentinels.py +0 -0
  224. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_advisory_lock.py +0 -0
  225. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_agent_message.py +0 -0
  226. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_api_auth.py +0 -0
  227. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_api_config.py +0 -0
  228. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_api_handlers.py +0 -0
  229. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_api_protocol.py +0 -0
  230. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_array_agg_order_by.py +0 -0
  231. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_association_trigger_actor_naming.py +0 -0
  232. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_associations.py +0 -0
  233. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_associations_wiring.py +0 -0
  234. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_borrowed_role_never_reaches_server_calls.py +0 -0
  235. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_bulk_hydration_offload.py +0 -0
  236. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_bulk_update_by_pk.py +0 -0
  237. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  238. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_cache_debug.py +0 -0
  239. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_case_when.py +0 -0
  240. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_catalog.py +0 -0
  241. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_column_scoped_writes.py +0 -0
  242. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_committed_row_guard.py +0 -0
  243. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_composite_pk_filter.py +0 -0
  244. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_composite_pk_write_paths.py +0 -0
  245. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_config.py +0 -0
  246. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_conflict_target.py +0 -0
  247. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_conflict_writes.py +0 -0
  248. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_connection_codecs.py +0 -0
  249. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_connection_poison_guard.py +0 -0
  250. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_connection_primitives.py +0 -0
  251. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_count_composite_distinct.py +0 -0
  252. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_count_limit_param_leak.py +0 -0
  253. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_ddl_generator.py +0 -0
  254. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_derived_table.py +0 -0
  255. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_dirty_tracking.py +0 -0
  256. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_dynamic_crud.py +0 -0
  257. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_exceptions.py +0 -0
  258. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  259. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_expression_primitives.py +0 -0
  260. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_fetch_on_init_holds_whole_table.py +0 -0
  261. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_fields.py +0 -0
  262. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  263. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_fk_cycle_resolution.py +0 -0
  264. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_from_alias.py +0 -0
  265. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_fts.py +0 -0
  266. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_func_expression_args.py +0 -0
  267. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_graph_walk.py +0 -0
  268. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_guarded_read_never_reruns_empty.py +0 -0
  269. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_having_annotate_alias.py +0 -0
  270. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  271. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_introspect_rls_policies.py +0 -0
  272. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_join_and_aggregate.py +0 -0
  273. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_latest_rows.py +0 -0
  274. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_listen_notify.py +0 -0
  275. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_local_sqlite.py +0 -0
  276. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_lock_contention_retry.py +0 -0
  277. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_managed_write_guard.py +0 -0
  278. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_matrx_entity.py +0 -0
  279. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_migration_diff_types.py +0 -0
  280. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_migration_loader.py +0 -0
  281. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_model_instance.py +0 -0
  282. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_model_meta.py +0 -0
  283. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_optimistic_concurrency.py +0 -0
  284. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_order_by_expression.py +0 -0
  285. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_org_assignment_inventory.py +0 -0
  286. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  287. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_parameter_name_hydration.py +0 -0
  288. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_patch_jsonb_path.py +0 -0
  289. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_percentile_cont.py +0 -0
  290. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_persisted_count.py +0 -0
  291. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
  292. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_pool_create_never_wedges.py +0 -0
  293. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_pool_holder_census.py +0 -0
  294. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_pool_loop_recreation.py +0 -0
  295. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_pool_maintenance.py +0 -0
  296. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_postgrest_filters.py +0 -0
  297. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_pydantic_bridge.py +0 -0
  298. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_query_builder.py +0 -0
  299. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_query_error_detail.py +0 -0
  300. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_query_executor_sql.py +0 -0
  301. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_query_timeout.py +0 -0
  302. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  303. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_queue_claim.py +0 -0
  304. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_read_connection_retry.py +0 -0
  305. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_read_write_declared.py +0 -0
  306. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_registry.py +0 -0
  307. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_registry_multi_database.py +0 -0
  308. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_registry_multi_schema.py +0 -0
  309. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_relational_backfill.py +0 -0
  310. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_relations.py +0 -0
  311. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_resilience.py +0 -0
  312. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_rls_session_scope.py +0 -0
  313. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_schema_exists.py +0 -0
  314. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_session_advisory_lock.py +0 -0
  315. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_standalone_write_session_context.py +0 -0
  316. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_state_cache.py +0 -0
  317. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_subquery_filter_raw.py +0 -0
  318. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_subquery_in_filter.py +0 -0
  319. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_subquery_nested_expressions.py +0 -0
  320. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_supabase_auth.py +0 -0
  321. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_supabase_config.py +0 -0
  322. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_sync_pool_declares_read_write.py +0 -0
  323. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_tls.py +0 -0
  324. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_transaction_database_identity.py +0 -0
  325. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
  326. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
  327. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_typed_join_projection.py +0 -0
  328. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_typed_predicates.py +0 -0
  329. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_update_case_expression.py +0 -0
  330. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_update_subquery.py +0 -0
  331. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_update_with_rebase.py +0 -0
  332. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_upsert_default_leak.py +0 -0
  333. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_upsert_with_conflict.py +0 -0
  334. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_values_jsonb_decode.py +0 -0
  335. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_watched_lifecycle.py +0 -0
  336. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_write_queue_deadline.py +0 -0
  337. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level1/test_write_retry_semantics.py +0 -0
  338. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/MODULE_README.md +0 -0
  339. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/__init__.py +0 -0
  340. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/conftest.py +0 -0
  341. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_bulk_ops.py +0 -0
  342. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_cache_integration.py +0 -0
  343. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_crud.py +0 -0
  344. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_foreign_keys.py +0 -0
  345. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_m2m.py +0 -0
  346. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_manager.py +0 -0
  347. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_migrations_live.py +0 -0
  348. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_query_execution.py +0 -0
  349. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/test_schema_diff.py +0 -0
  350. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
  351. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/live_pooler_role.py +0 -0
  352. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/native_source_cases.py +0 -0
  353. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/native_source_oracle.rs +0 -0
  354. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/.env.example +0 -0
  355. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/README.md +0 -0
  356. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/__init__.py +0 -0
  357. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/generate.py +0 -0
  358. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/generated/.gitkeep +0 -0
  359. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/matrx_orm.yaml +0 -0
  360. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project/test_schema_generation.py +0 -0
  361. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/.env.example +0 -0
  362. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/README.md +0 -0
  363. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/__init__.py +0 -0
  364. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_example.py +0 -0
  365. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_example.ts +0 -0
  366. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  367. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/sample_project_desktop/server.py +0 -0
  368. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/entity_tests.py +0 -0
  369. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_base_generation.py +0 -0
  370. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  371. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_composite_unique_generation.py +0 -0
  372. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_dto_identity_generation.py +0 -0
  373. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_entity_capability_generation.py +0 -0
  374. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_enum_ordering.py +0 -0
  375. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_excluded_fk_targets.py +0 -0
  376. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_generate_schema.py +0 -0
  377. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_junction_analysis.py +0 -0
  378. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_multi_schema_output.py +0 -0
  379. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_schema_analysis.py +0 -0
  380. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_sql_expression_defaults.py +0 -0
  381. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_table_relationships_query.py +0 -0
  382. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema/test_view_generation.py +0 -0
  383. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema_builder/test_array_default_parsing.py +0 -0
  384. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema_builder/test_enum_array_column.py +0 -0
  385. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  386. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  387. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/schema_builder/test_never_filter_columns.py +0 -0
  388. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/__init__.py +0 -0
  389. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/conftest.py +0 -0
  390. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
  391. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_a_grouped_update_writes_only_each_rows_own_fields.py +0 -0
  392. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_cache_no_downgrade.py +0 -0
  393. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_capture_poison_proof.py +0 -0
  394. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_coalesce.py +0 -0
  395. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_dag.py +0 -0
  396. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_disk_spill_fallback.py +0 -0
  397. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_flush_individual_fallback.py +0 -0
  398. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_governed_write.py +0 -0
  399. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_managed.py +0 -0
  400. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_op_enqueue_site.py +0 -0
  401. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_pending_insert_honors_operator_filters.py +0 -0
  402. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_reads.py +0 -0
  403. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_record_error_bounded_insert.py +0 -0
  404. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_record_error_storm.py +0 -0
  405. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_session.py +0 -0
  406. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_spill_guard_plugin.py +0 -0
  407. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/session/test_tests_never_write_live_system_error.py +0 -0
  408. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
  409. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_a_bulk_cache_never_stalls_the_loop.py +0 -0
  410. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_a_keyword_column_refuses_generation.py +0 -0
  411. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_a_list_of_uuids_binds_as_uuid_array.py +0 -0
  412. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
  413. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_a_sealed_field_shows_no_character_of_its_value.py +0 -0
  414. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_array_arg_element_type.py +0 -0
  415. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_attachment_mutation_serialization.py +0 -0
  416. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_backup_alias_conflict.py +0 -0
  417. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_backup_history_restore.py +0 -0
  418. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_backup_restore_live.py +0 -0
  419. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_call_function_as.py +0 -0
  420. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_call_function_none_mode.py +0 -0
  421. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
  422. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_database_name_alias.py +0 -0
  423. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_db_functions.py +0 -0
  424. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_dsn_password_masking.py +0 -0
  425. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_dynamic_select_unregistered.py +0 -0
  426. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_first_asks_the_database_for_one_row.py +0 -0
  427. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_foreign_session_state.py +0 -0
  428. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  429. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_instance_update_runs_expressions.py +0 -0
  430. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_keyed_digest.py +0 -0
  431. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_model_cls_refactor.py +0 -0
  432. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_native_enable.py +0 -0
  433. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_native_lifecycle.py +0 -0
  434. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_native_lifecycle_fences.py +0 -0
  435. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_native_passkey_receipts.py +0 -0
  436. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_native_source.py +0 -0
  437. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  438. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_one_database.py +0 -0
  439. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_order_by_desc_nulls_last.py +0 -0
  440. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_org_vault_gate.py +0 -0
  441. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_package_wiring_views.py +0 -0
  442. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_pooler_role_guard.py +0 -0
  443. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_secret_audit_names_its_organization.py +0 -0
  444. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_secrets_battery.py +0 -0
  445. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_secrets_minting_keys.py +0 -0
  446. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_shared_lock_guard.py +0 -0
  447. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_sql_param_casts.py +0 -0
  448. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_state_cache_sweeps_stale.py +0 -0
  449. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_statement_ceiling_warning.py +0 -0
  450. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_sync_twins_guard.py +0 -0
  451. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_update_result_truthiness.py +0 -0
  452. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_user_visible_lookup.py +0 -0
  453. {matrx_orm-3.1.244 → matrx_orm-3.1.246}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.244
3
+ Version: 3.1.246
4
4
  Summary: Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching
5
5
  Project-URL: Homepage, https://github.com/AI-Matrix-Engine/aidream-current
6
6
  Project-URL: Repository, https://github.com/AI-Matrix-Engine/aidream-current
@@ -26,7 +26,7 @@ Requires-Dist: asyncpg>=0.31.0
26
26
  Requires-Dist: cbor2<7,>=6.1.3
27
27
  Requires-Dist: cryptography>=43.0
28
28
  Requires-Dist: gitpython>=3.1.40
29
- Requires-Dist: matrx-utils>=2.0.83
29
+ Requires-Dist: matrx-utils>=2.0.84
30
30
  Requires-Dist: psycopg-pool>=3.2.5
31
31
  Requires-Dist: psycopg[binary]>=3.2.5
32
32
  Requires-Dist: python-dotenv>=1.0
@@ -71,6 +71,8 @@ from collections.abc import Awaitable, Callable
71
71
 
72
72
  from matrx_utils import vcprint
73
73
 
74
+ from matrx_orm.core.transaction import outside_transaction
75
+
74
76
  if TYPE_CHECKING:
75
77
  from matrx_orm.core.base import Model
76
78
 
@@ -209,7 +211,10 @@ class EntityRegistry:
209
211
  return self._cache[token]
210
212
  model: type[Model] | None = None
211
213
  if self._etype_model is not None:
212
- row = await self._etype_model.get_or_none(**{self._token_field: token})
214
+ # Vocabulary, never person data: read off the caller's session, or a person's RLS
215
+ # hides the row and the miss below is cached for every later caller.
216
+ etype_model = self._etype_model
217
+ row = await outside_transaction(lambda: etype_model.get_or_none(**{self._token_field: token}))
213
218
  active = self._active_field is None or getattr(row, self._active_field, True)
214
219
  if row is not None and active:
215
220
  schema = getattr(row, self._schema_field, None)
@@ -36,16 +36,19 @@ reuses the connection when present — this behavior is unchanged.
36
36
  from __future__ import annotations
37
37
 
38
38
  import asyncio
39
+ import contextvars
39
40
  import os
40
41
  import re
41
42
  import uuid
42
- from collections.abc import AsyncIterator
43
+ from collections.abc import AsyncIterator, Awaitable, Callable
43
44
  from contextlib import asynccontextmanager
44
45
  from contextvars import ContextVar, Token
45
- from typing import Any
46
+ from typing import Any, TypeVar
46
47
 
47
48
  from matrx_orm.exceptions import DatabaseError
48
49
 
50
+ _T = TypeVar("_T")
51
+
49
52
  # ContextVar holding the active connection (if any) for the current task tree.
50
53
  _active_connection: ContextVar[Any | None] = ContextVar("_active_connection", default=None)
51
54
  # The canonical registered database that owns ``_active_connection``. A raw
@@ -69,6 +72,27 @@ def in_person_scoped_session() -> bool:
69
72
  _savepoint_depth: ContextVar[int] = ContextVar("_savepoint_depth", default=0)
70
73
 
71
74
 
75
+ async def outside_transaction(fn: Callable[[], Awaitable[_T]]) -> _T:
76
+ """Await ``fn()`` on the process's own connection, outside the caller's transaction.
77
+
78
+ For process-wide VOCABULARY reads (the entity-type registry) whose answer must not
79
+ depend on who is acting: inside ``rls_session`` a person's RLS may hide the row, and a
80
+ cached answer outlives the person. The read runs as its own task with every transaction
81
+ ContextVar at its default, so it never touches (or ends) the caller's pinned connection,
82
+ and the caller's session is unchanged when it returns. Never use it for person data.
83
+ """
84
+ ctx = contextvars.copy_context()
85
+
86
+ def _clear() -> None:
87
+ _active_connection.set(None)
88
+ _active_database.set(None)
89
+ _person_scoped.set(False)
90
+ _savepoint_depth.set(0)
91
+
92
+ ctx.run(_clear)
93
+ return await asyncio.get_running_loop().create_task(fn(), context=ctx)
94
+
95
+
72
96
  def get_active_connection() -> Any | None:
73
97
  """Return the connection bound to the current transaction context, or None."""
74
98
  return _active_connection.get()
@@ -40,7 +40,8 @@ if TYPE_CHECKING:
40
40
  # The canonical version log + restore function. Identical in every Matrx database
41
41
  # (verified live on both the main and CMS projects):
42
42
  # history.row_versions(entity_type, row_id, version, operation, row_data, actor_id, occurred_at)
43
- # public.version_restore(token text, id uuid, version int) -> int (the new version)
43
+ # public.version_restore(token text, id uuid, version int) -> int (the new version) —
44
+ # a thin SQL wrapper over platform.version_restore; both exist live, the ORM calls the public door
44
45
  VERSION_LOG_SCHEMA = "history"
45
46
  VERSION_LOG_MODEL = "RowVersions"
46
47
  VERSION_RESTORE_SCHEMA = "public"
@@ -379,7 +379,7 @@ async def platform_edge_requirement(
379
379
 
380
380
  rows = await call_function(
381
381
  host_db_config_name(who="matrx-orm edge policy"),
382
- "public",
382
+ "platform",
383
383
  "assoc_container_side",
384
384
  key[0],
385
385
  key[1],
@@ -1745,7 +1745,9 @@ async def resolve_field_by_id(field_id: str) -> str:
1745
1745
  f"credential field {field_id} exists but does not decrypt with the "
1746
1746
  "configured CREDENTIALS_ENCRYPTION_KEY (key drift)"
1747
1747
  ) from exc
1748
- await UserSecret.update_where({"id": field_id}, last_used_at=datetime.now(UTC))
1748
+ from .use_stamp import stamp_last_used
1749
+
1750
+ await stamp_last_used(UserSecret, {"id": field_id})
1749
1751
  return value
1750
1752
 
1751
1753
 
@@ -753,11 +753,9 @@ async def resolve_org_secrets(
753
753
  # the same row locks in opposite orders and Postgres kills one as a
754
754
  # deadlock victim (40P01) — four ``ai.agent.start`` invocations over 185
755
755
  # rows of one org killed a live workflow run on 2026-09-12.
756
- await UserSecret.update_where(
757
- {"id__in": sorted(used_ids)},
758
- lock_rows_in_pk_order=True,
759
- last_used_at=datetime.now(UTC),
760
- )
756
+ from .use_stamp import stamp_last_used
757
+
758
+ await stamp_last_used(UserSecret, {"id__in": sorted(used_ids)}, lock_rows_in_pk_order=True)
761
759
  return resolved
762
760
 
763
761
 
@@ -21,6 +21,7 @@ from typing import Any
21
21
 
22
22
  from .crypto import decrypt_value, encrypt_value, mask_value
23
23
  from .model import CredentialItem, UserSecret, UserSecretGrant
24
+ from .use_stamp import stamp_last_used
24
25
 
25
26
  logger = logging.getLogger(__name__)
26
27
 
@@ -243,7 +244,7 @@ async def get_user_secret(
243
244
  )
244
245
  plaintext = None
245
246
  if touch_last_used:
246
- await UserSecret.update_where({"id": row["id"]}, last_used_at=datetime.now(UTC))
247
+ await stamp_last_used(UserSecret, {"id": row["id"]})
247
248
  return _row_to_dataclass(row, decrypted_value=plaintext)
248
249
 
249
250
 
@@ -312,7 +313,7 @@ async def get_org_secret(
312
313
  )
313
314
  plaintext = None
314
315
  if touch_last_used:
315
- await UserSecret.update_where({"id": row["id"]}, last_used_at=datetime.now(UTC))
316
+ await stamp_last_used(UserSecret, {"id": row["id"]})
316
317
  return _row_to_dataclass(row, decrypted_value=plaintext)
317
318
 
318
319
 
@@ -0,0 +1,27 @@
1
+ """``last_used_at`` stamps are telemetry: a failed stamp never fails the read that used the secret."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from datetime import UTC, datetime
7
+ from typing import Any
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ async def stamp_last_used(model: Any, filters: dict[str, Any], **options: Any) -> bool:
13
+ """Stamp ``last_used_at`` on the rows ``filters`` names; announce and drop any failure.
14
+
15
+ A timeout or lock collision on this bookkeeping UPDATE once ended a whole Notion import
16
+ (2026-10-22). The caller already holds the value it read, so losing the stamp loses
17
+ nothing a person needs. Returns whether the stamp landed.
18
+ """
19
+ try:
20
+ await model.update_where(filters, last_used_at=datetime.now(UTC), **options)
21
+ return True
22
+ except Exception as exc:
23
+ logger.warning(
24
+ "[secrets] last_used_at stamp on %s skipped (%s: %s); the read continues",
25
+ getattr(model, "__name__", model), type(exc).__name__, exc,
26
+ )
27
+ return False
@@ -269,6 +269,16 @@ def _op_user_id(op: SessionOp, safe_user_id: str | None) -> str | None:
269
269
  return None
270
270
 
271
271
 
272
+ #: The refusal text of the database's confidential-content guard (chat.refuse_sealed_content).
273
+ CONFIDENTIAL_REFUSAL_MARK = "may not be stored on the server (chat.confidential)"
274
+ _CONFIDENTIAL_KEPT_KEYS = ("id", "conversation_id", "user_request_id", "message_id", "role", "position")
275
+
276
+
277
+ def _confidential_payload(payload: Any) -> Any:
278
+ kept = {k: payload.get(k) for k in _CONFIDENTIAL_KEPT_KEYS if isinstance(payload, dict) and k in payload}
279
+ return _serialize_payload({**kept, "redacted": "confidential conversation: content refused, not kept"})
280
+
281
+
272
282
  def _op_failure_row(
273
283
  op: SessionOp,
274
284
  *,
@@ -285,6 +295,12 @@ def _op_failure_row(
285
295
  values. Used by BOTH the DB insert and the disk spill, so a spilled file is
286
296
  byte-identical in shape to a table row (drain re-inserts it verbatim)."""
287
297
  row_user_id = _op_user_id(op, safe_user_id)
298
+ payload = _serialize_payload(op.payload)
299
+ if CONFIDENTIAL_REFUSAL_MARK in (error_text or ""):
300
+ # The database refused this row because its conversation is CONFIDENTIAL
301
+ # (trigger chat.refuse_sealed_content): its content must never land on our
302
+ # server, so the failure record keeps the row's identity, never its values.
303
+ payload = _confidential_payload(op.payload)
288
304
  return {
289
305
  "op_id": op.op_id,
290
306
  "request_id": request_id or session_id,
@@ -294,7 +310,7 @@ def _op_failure_row(
294
310
  "table_target": op.table,
295
311
  "op_type": op.op_type,
296
312
  "primary_key": _serialize_primary_key(op.pk_field, op.pk_value),
297
- "payload": _serialize_payload(op.payload),
313
+ "payload": payload,
298
314
  "depends_on": json.dumps([]), # FK-inferred deps aren't tracked on the op
299
315
  "error_text": error_text,
300
316
  "traceback": tb_text,
@@ -677,6 +693,7 @@ async def record_error(
677
693
  payload: Any | None = None,
678
694
  context: dict[str, Any] | None = None,
679
695
  database: str | None = None,
696
+ group_open: bool = False,
680
697
  ) -> None:
681
698
  """Universal failure capture for NON-write errors → ``system_error``.
682
699
 
@@ -721,6 +738,16 @@ async def record_error(
721
738
  indistinguishable from a Codex one.
722
739
  payload: request args/body to capture (jsonb). Serialized defensively.
723
740
  context: free-form context (debug_label, task_name, partial cost, …).
741
+ group_open: ONE OPEN ROW PER SIGNATURE (error-capture rule "a count is a
742
+ number on an existing row, never a new row"). When True, a capture whose
743
+ ``(kind, route, error_type)`` already has an UNRESOLVED row bumps that row's
744
+ ``context.occurrences`` (exact, atomic, across every process and deploy) and
745
+ ``context.last_seen_at`` instead of filing a new row; with none open it files
746
+ the row with ``occurrences=1``. Resolving the row zeroes the count — the next
747
+ occurrence reopens as one new row. For announcements that are a COUNT of a
748
+ known condition per site (legacy lanes, runtime bypasses), never for a crash
749
+ whose every instance carries its own inputs. The storm budget does not apply
750
+ (the grouping is the budget).
724
751
  """
725
752
  # Both attribution halves ride the carried request context; a capture site
726
753
  # that declared neither still files a fully categorized row.
@@ -739,7 +766,7 @@ async def record_error(
739
766
  else:
740
767
  tb_text = "".join(_tb.format_exception(type(exc), exc, exc.__traceback__))
741
768
 
742
- admitted, folded = _storm_admit(kind, resolved_error_type, route)
769
+ admitted, folded = (True, 0) if group_open else _storm_admit(kind, resolved_error_type, route)
743
770
  if not admitted:
744
771
  # Counted, never silent: the next admitted row for this signature
745
772
  # carries the total. ONE stdout line per window (the first fold) — a line per
@@ -787,12 +814,14 @@ async def record_error(
787
814
  "route": route,
788
815
  "context": context,
789
816
  "payload": payload,
817
+ **({"group_open": True} if group_open else {}),
790
818
  }
791
819
  )
792
820
  return
793
821
 
794
822
  try:
795
823
  await _insert_error(
824
+ **({"group_open": True} if group_open else {}),
796
825
  kind=kind,
797
826
  request_id=request_id,
798
827
  user_id=user_id,
@@ -896,6 +925,7 @@ async def _insert_error(
896
925
  payload: Any | None,
897
926
  context: dict[str, Any] | None,
898
927
  database: str | None,
928
+ group_open: bool = False,
899
929
  ) -> None:
900
930
  from matrx_orm.adapters import AdapterRegistry
901
931
  from matrx_orm.core.config import get_all_database_project_names
@@ -931,6 +961,13 @@ async def _insert_error(
931
961
  # capture fast instead of parking a pool slot behind it.
932
962
  await conn.execute(f"SET LOCAL lock_timeout = '{CAPTURE_LOCK_TIMEOUT_MS}ms'")
933
963
  await conn.execute(f"SET LOCAL statement_timeout = '{CAPTURE_STATEMENT_TIMEOUT_MS}ms'")
964
+ if group_open:
965
+ if await _bump_open_error(conn, kind=kind, route=route, error_type=error_type):
966
+ return
967
+ context_json = json.dumps(
968
+ {**(context or {}), "occurrences": 1, "grouped": GROUPED_NOTE},
969
+ default=_json_default,
970
+ )
934
971
  await _execute_error_insert(
935
972
  conn,
936
973
  kind=kind,
@@ -951,6 +988,39 @@ async def _insert_error(
951
988
 
952
989
 
953
990
 
991
+ #: Stamped on a grouped row (``record_error(group_open=True)``) so a reader knows what the count means.
992
+ GROUPED_NOTE = (
993
+ "one open row per kind+route+error_type; context.occurrences counts every capture since the row "
994
+ "was last resolved (all processes), context.last_seen_at the latest"
995
+ )
996
+
997
+ # The bump is ONE statement under a transaction-scoped advisory lock on the signature, so two
998
+ # processes seeing the same site at once neither lose a count nor both file a row.
999
+ _GROUP_LOCK_SQL = "SELECT pg_advisory_xact_lock(hashtextextended($1::text, 0))"
1000
+ _GROUP_BUMP_SQL = """
1001
+ UPDATE ops.system_error
1002
+ SET context = coalesce(context, '{}'::jsonb) || jsonb_build_object(
1003
+ 'occurrences', coalesce((context->>'occurrences')::bigint, 1) + 1,
1004
+ 'last_seen_at', now())
1005
+ WHERE id = (
1006
+ SELECT id FROM ops.system_error
1007
+ WHERE kind = $1::text
1008
+ AND route IS NOT DISTINCT FROM $2::text
1009
+ AND error_type IS NOT DISTINCT FROM $3::text
1010
+ AND resolved_at IS NULL
1011
+ ORDER BY occurred_at
1012
+ LIMIT 1)
1013
+ RETURNING id
1014
+ """
1015
+
1016
+
1017
+ async def _bump_open_error(conn: Any, *, kind: str, route: str | None, error_type: str | None) -> bool:
1018
+ """Count this capture on the signature's open row; False when none is open (file one)."""
1019
+ await conn.fetch(_GROUP_LOCK_SQL, f"system_error:{kind}|{route or ''}|{error_type or ''}")
1020
+ rows = await conn.fetch(_GROUP_BUMP_SQL, kind, route, error_type)
1021
+ return bool(rows)
1022
+
1023
+
954
1024
  _LIVE_INSERT_ERROR = _insert_error
955
1025
 
956
1026
  async def _execute_error_insert(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.244"
3
+ version = "3.1.246"
4
4
  description = "Async-first PostgreSQL ORM with bidirectional migrations, schema introspection, many-to-many relationships, and built-in state caching"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -41,7 +41,7 @@ dependencies = [
41
41
  "gitpython>=3.1.40",
42
42
  "psycopg[binary]>=3.2.5",
43
43
  "psycopg-pool>=3.2.5",
44
- "matrx-utils>=2.0.83",
44
+ "matrx-utils>=2.0.84",
45
45
  "pyyaml>=6.0.3",
46
46
  "python-dotenv>=1.0",
47
47
  "cryptography>=43.0",
@@ -159,11 +159,11 @@ class TestArrayArgBinding:
159
159
  lambda database: _FakeConnCtx(conn),
160
160
  )
161
161
  result = await call_function(
162
- "db", "public", "resolve_full_context", "user-id", ArrayArg(["scope-1", "scope-2"])
162
+ "db", "context", "resolve_full_context", "user-id", ArrayArg(["scope-1", "scope-2"])
163
163
  )
164
164
  assert result == "ok"
165
165
  conn.fetchval.assert_awaited_once_with(
166
- 'SELECT "public"."resolve_full_context"($1, $2)',
166
+ 'SELECT "context"."resolve_full_context"($1, $2)',
167
167
  "user-id",
168
168
  ["scope-1", "scope-2"], timeout=None
169
169
  )
@@ -174,9 +174,9 @@ class TestArrayArgBinding:
174
174
  "matrx_orm.core.db_function.AsyncDatabaseManager.get_connection",
175
175
  lambda database: _FakeConnCtx(conn),
176
176
  )
177
- await call_function("db", "public", "resolve_full_context", "user-id", ArrayArg(None))
177
+ await call_function("db", "context", "resolve_full_context", "user-id", ArrayArg(None))
178
178
  conn.fetchval.assert_awaited_once_with(
179
- 'SELECT "public"."resolve_full_context"($1, $2)', "user-id", None, timeout=None
179
+ 'SELECT "context"."resolve_full_context"($1, $2)', "user-id", None, timeout=None
180
180
  )
181
181
 
182
182
  async def test_array_arg_distinct_from_plain_list_jsonb_cast(self, monkeypatch) -> None:
@@ -110,11 +110,11 @@ class TestCallFunctionRows:
110
110
  )
111
111
 
112
112
  result = await call_function(
113
- "main", "public", "dict_list_entries_for", "user-1", "user", None, mode="rows"
113
+ "main", "dictionary", "dict_list_entries_for", "user-1", "user", None, mode="rows"
114
114
  )
115
115
  assert result == [{"id": "1", "term": "foo"}, {"id": "2", "term": "bar"}]
116
116
  assert conn.calls[0]["sql"] == (
117
- 'SELECT * FROM "public"."dict_list_entries_for"($1, $2, $3)'
117
+ 'SELECT * FROM "dictionary"."dict_list_entries_for"($1, $2, $3)'
118
118
  )
119
119
  assert conn.calls[0]["args"] == ("user-1", "user", None)
120
120
 
@@ -328,7 +328,7 @@ async def test_call_function_retries_a_rolled_back_rpc(monkeypatch):
328
328
  monkeypatch.setattr("matrx_orm.core.write_retry.resolve_policy", _fake_policy)
329
329
  clear_policy_cache()
330
330
 
331
- await db_function.call_function("test", "public", "library_revoke", "g1", mode="none")
331
+ await db_function.call_function("test", "rag", "library_revoke", "g1", mode="none")
332
332
 
333
333
  assert calls[0] == 2, (
334
334
  f"A deadlocked RPC must be retried on its own fresh connection. Got {calls[0]} attempts."
@@ -352,7 +352,7 @@ async def test_call_function_inside_a_transaction_does_not_retry(monkeypatch):
352
352
  clear_policy_cache()
353
353
 
354
354
  with pytest.raises(LockContentionError) as caught:
355
- await db_function.call_function("test", "public", "library_revoke", "g1", mode="none")
355
+ await db_function.call_function("test", "rag", "library_revoke", "g1", mode="none")
356
356
  assert calls[0] == 1, f"expected exactly one attempt inside a transaction, got {calls[0]}"
357
357
  assert caught.value.details["in_transaction"] is True
358
358
 
@@ -0,0 +1,49 @@
1
+ """Level 1: a noun lookup never depends on who is acting.
2
+
3
+ ``platform.entity_types`` is vocabulary, and a non-admin person's RLS hides it (a restrictive
4
+ ``platform_admin_only`` policy). ``EntityRegistry.resolve`` read it on whatever connection the
5
+ caller held, so inside ``acting_as_user`` it found no row, answered ``None`` and CACHED that
6
+ miss for the life of the process: every later ``sources_to(..., "fc_card")`` raised
7
+ ``UnknownEntityType('fc_card')`` — the Education Guide lost a study-media record's source (a
8
+ flashcard deck) on 2026-10-22. The registry now reads the noun outside the caller's session.
9
+ """
10
+
11
+ import pytest
12
+
13
+ from matrx_orm.associations import EntityRegistry
14
+ from matrx_orm.core import transaction as tx
15
+
16
+
17
+ class _Card:
18
+ pass
19
+
20
+
21
+ class _HiddenUnderRls:
22
+ """An entity_types stand-in that answers only off the person's session, like the live table."""
23
+
24
+ seen: list[tuple[bool, object]] = []
25
+
26
+ @classmethod
27
+ async def get_or_none(cls, **filters):
28
+ cls.seen.append((tx.in_person_scoped_session(), tx.get_active_connection()))
29
+ if tx.in_person_scoped_session() or tx.get_active_connection() is not None:
30
+ return None
31
+ row = type("Row", (), {})()
32
+ row.schema_name, row.table_name, row.is_active = "education", "fc_card", True
33
+ return row if filters.get("token") == "fc_card" else None
34
+
35
+
36
+ @pytest.mark.asyncio
37
+ async def test_a_person_session_never_hides_a_registered_noun() -> None:
38
+ reg = EntityRegistry(entity_type_model=_HiddenUnderRls,
39
+ model_lookup=lambda s, t: _Card if (s, t) == ("education", "fc_card") else None)
40
+ marks = (tx._active_connection.set(object()), tx._person_scoped.set(True))
41
+ try:
42
+ assert await reg.resolve("fc_card") is _Card
43
+ assert await reg.require("fc_card") is _Card
44
+ finally:
45
+ tx._person_scoped.reset(marks[1])
46
+ tx._active_connection.reset(marks[0])
47
+ assert _HiddenUnderRls.seen and all(scoped is False and conn is None for scoped, conn in _HiddenUnderRls.seen)
48
+ # the caller's session is untouched by the lookup
49
+ assert tx.in_person_scoped_session() is False and tx.get_active_connection() is None
@@ -0,0 +1,152 @@
1
+ """ONE OPEN ROW PER SIGNATURE: ``record_error(group_open=True)`` counts on the existing row.
2
+
3
+ SUT: :func:`matrx_orm.session.fallback.record_error` with ``group_open=True`` (and ``_insert_error``).
4
+
5
+ 2026-10-22: the mandate runner's legacy-lane announcements were "announced once per site" with a
6
+ per-PROCESS set, so every process and every 30-minute deploy re-filed the same site: 413
7
+ ``mandate_offer_eager_legacy`` rows for ~60 sites, 56 ``mandate_bypass_runtime`` rows for 2 lines, in
8
+ 12 hours. The error-capture rule: "a count is a number on an existing row, never a new row".
9
+
10
+ Breaks these tests name: a second capture of an open signature filing a new row, the count not being
11
+ exact across "processes" (fresh storm state, fresh per-process sets), a resolved row swallowing a
12
+ recurrence instead of reopening as one, or distinct sites collapsing into one row.
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import json
18
+ import uuid
19
+ from typing import Any
20
+
21
+ import pytest
22
+ from matrx_orm.session import fallback
23
+
24
+
25
+ class _Table:
26
+ """``ops.system_error`` as far as the grouped door touches it."""
27
+
28
+ def __init__(self) -> None:
29
+ self.rows: list[dict[str, Any]] = []
30
+
31
+ def open_row(self, kind: str, route: str | None, error_type: str | None) -> dict[str, Any] | None:
32
+ for row in self.rows:
33
+ if (row["kind"], row["route"], row["error_type"]) == (kind, route, error_type) and row["resolved_at"] is None:
34
+ return row
35
+ return None
36
+
37
+
38
+ class _Txn:
39
+ async def __aenter__(self):
40
+ return self
41
+
42
+ async def __aexit__(self, *exc):
43
+ return False
44
+
45
+
46
+ class _Conn:
47
+ def __init__(self, table: _Table) -> None:
48
+ self.table = table
49
+
50
+ def transaction(self):
51
+ return _Txn()
52
+
53
+ async def execute(self, sql: str, *args: Any) -> None:
54
+ if "ops.record_system_error" in sql:
55
+ self.table.rows.append(
56
+ {
57
+ "id": str(uuid.uuid4()),
58
+ "kind": args[0],
59
+ "route": args[8],
60
+ "error_type": args[9],
61
+ "context": json.loads(args[13]) if args[13] else {},
62
+ "resolved_at": None,
63
+ }
64
+ )
65
+
66
+ async def fetch(self, sql: str, *args: Any) -> list[dict[str, Any]]:
67
+ if "UPDATE ops.system_error" in sql:
68
+ row = self.table.open_row(*args)
69
+ if row is None:
70
+ return []
71
+ row["context"]["occurrences"] = int(row["context"].get("occurrences", 1)) + 1
72
+ row["context"]["last_seen_at"] = "now"
73
+ return [{"id": row["id"]}]
74
+ return []
75
+
76
+
77
+ class _Adapter:
78
+ def __init__(self, table: _Table) -> None:
79
+ self.table = table
80
+
81
+ def get_connection(self, timeout: float = 10.0):
82
+ conn = _Conn(self.table)
83
+
84
+ class _Ctx:
85
+ async def __aenter__(self_inner):
86
+ return conn
87
+
88
+ async def __aexit__(self_inner, *exc):
89
+ return False
90
+
91
+ return _Ctx()
92
+
93
+
94
+ @pytest.fixture
95
+ def table(monkeypatch) -> _Table:
96
+ table = _Table()
97
+ monkeypatch.setattr("matrx_orm.adapters.AdapterRegistry.get", lambda name: _Adapter(table))
98
+
99
+ async def live(**kwargs: Any) -> None: # the real insert path, against the fake table
100
+ await fallback._LIVE_INSERT_ERROR(**kwargs)
101
+
102
+ monkeypatch.setattr(fallback, "_insert_error", live)
103
+ fallback.reset_capture_storm_state()
104
+ yield table
105
+ fallback.reset_capture_storm_state()
106
+
107
+
108
+ async def _sighting(site: str, kind: str = "mandate_offer_eager_legacy") -> None:
109
+ fallback.reset_capture_storm_state() # every sighting may be a different process / deploy
110
+ await fallback.record_error(
111
+ RuntimeError(f"legacy at {site}"), kind=kind, route=site, context={"site": site},
112
+ database="t", group_open=True,
113
+ )
114
+
115
+
116
+ @pytest.mark.asyncio
117
+ async def test_one_open_row_per_site_with_an_exact_count(table: _Table) -> None:
118
+ for _ in range(7):
119
+ await _sighting("seo.job @ aidream/services/seo/run.py:12")
120
+ assert len(table.rows) == 1, "seven sightings of one site are ONE open row"
121
+ assert table.rows[0]["context"]["occurrences"] == 7, "and the row counts every one of them"
122
+ assert table.rows[0]["context"]["site"] == "seo.job @ aidream/services/seo/run.py:12"
123
+
124
+
125
+ @pytest.mark.asyncio
126
+ async def test_distinct_sites_and_kinds_stay_distinct_rows(table: _Table) -> None:
127
+ await _sighting("a.job @ x.py:1")
128
+ await _sighting("a.job @ x.py:2")
129
+ await _sighting("a.job @ x.py:1", kind="mandate_by_name_legacy")
130
+ await _sighting("a.job @ x.py:1")
131
+ assert len(table.rows) == 3, "never merge genuinely distinct signatures"
132
+ counts = sorted(r["context"]["occurrences"] for r in table.rows)
133
+ assert counts == [1, 1, 2]
134
+
135
+
136
+ @pytest.mark.asyncio
137
+ async def test_a_recurrence_after_resolve_reopens_as_one_new_row(table: _Table) -> None:
138
+ await _sighting("b.job @ y.py:9")
139
+ await _sighting("b.job @ y.py:9")
140
+ table.rows[0]["resolved_at"] = "2026-10-22T23:00:00Z"
141
+ await _sighting("b.job @ y.py:9")
142
+ await _sighting("b.job @ y.py:9")
143
+ assert len(table.rows) == 2
144
+ assert [r["context"]["occurrences"] for r in table.rows] == [2, 2], "resolve zeroes the count"
145
+
146
+
147
+ @pytest.mark.asyncio
148
+ async def test_without_group_open_every_capture_is_still_its_own_row(table: _Table) -> None:
149
+ for _ in range(2):
150
+ fallback.reset_capture_storm_state()
151
+ await fallback.record_error(RuntimeError("crash"), kind="request_crash", route="/r", database="t")
152
+ assert len(table.rows) == 2, "grouping is opt-in: a crash keeps its own inputs per row"