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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (453) hide show
  1. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/PKG-INFO +2 -2
  2. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/associations.py +6 -1
  3. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/transaction.py +26 -2
  4. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/entity.py +2 -1
  5. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/platform_access.py +1 -1
  6. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/items.py +3 -1
  7. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/org_service.py +3 -5
  8. {matrx_orm-3.1.245 → 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.245 → matrx_orm-3.1.246}/matrx_orm/session/fallback.py +55 -1
  11. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/pyproject.toml +2 -2
  12. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_call_function.py +4 -4
  13. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_db_function_field.py +2 -2
  14. {matrx_orm-3.1.245 → 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.245 → matrx_orm-3.1.246}/.gitignore +0 -0
  19. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/AGENTS.md +0 -0
  20. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/BASE_CLASS_METHODS.md +0 -0
  21. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/CHANGELOG.md +0 -0
  22. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/CLAUDE.md +0 -0
  23. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/MODEL_API.md +0 -0
  24. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/README.md +0 -0
  25. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/database/orm/extended/managers/ai_model_base.py +0 -0
  26. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/docs/migrations.md +0 -0
  27. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/FEATURE.md +0 -0
  28. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/MODULE_README.md +0 -0
  29. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/__init__.py +0 -0
  30. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/MODULE_README.md +0 -0
  31. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/__init__.py +0 -0
  32. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/async_postgresql.py +0 -0
  33. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/base_adapter.py +0 -0
  34. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  35. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/adapters/supabase_adapter.py +0 -0
  36. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/admin/FEATURE.md +0 -0
  37. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/admin/__init__.py +0 -0
  38. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/admin/router.py +0 -0
  39. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/__init__.py +0 -0
  40. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/auth.py +0 -0
  41. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/config.py +0 -0
  42. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/handlers.py +0 -0
  43. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/protocol.py +0 -0
  44. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/api/server.py +0 -0
  45. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/cache_debug.py +0 -0
  46. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/catalog.py +0 -0
  47. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/catalog_sql.py +0 -0
  48. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/MODULE_README.md +0 -0
  49. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/__init__.py +0 -0
  50. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/postgres_connection.py +0 -0
  51. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/postgrest.py +0 -0
  52. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/supabase_auth.py +0 -0
  53. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/supabase_config.py +0 -0
  54. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/client/supabase_manager.py +0 -0
  55. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  56. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/FEATURE.md +0 -0
  57. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/MODULE_README.md +0 -0
  58. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  59. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/TASKS.md +0 -0
  60. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/__init__.py +0 -0
  61. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/admin_lane.py +0 -0
  62. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/async_db_manager.py +0 -0
  63. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/base.py +0 -0
  64. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/config.py +0 -0
  65. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/connections.py +0 -0
  66. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/db_function.py +0 -0
  67. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/diagnostics.py +0 -0
  68. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/expressions.py +0 -0
  69. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/extended.py +0 -0
  70. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/fields.py +0 -0
  71. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/foreign_session_state.py +0 -0
  72. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/introspection.py +0 -0
  73. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/listen.py +0 -0
  74. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/loop_filters.py +0 -0
  75. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/model_dto.py +0 -0
  76. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/model_view.py +0 -0
  77. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/one_database.py +0 -0
  78. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/paginator.py +0 -0
  79. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pool_maintenance.py +0 -0
  80. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pool_watch.py +0 -0
  81. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pooler_role.py +0 -0
  82. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/pydantic_bridge.py +0 -0
  83. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/read_write.py +0 -0
  84. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/registry.py +0 -0
  85. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/relations.py +0 -0
  86. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/resilience.py +0 -0
  87. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/rls_session.py +0 -0
  88. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/session_context.py +0 -0
  89. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/signals.py +0 -0
  90. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/statement_ceiling.py +0 -0
  91. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/tls.py +0 -0
  92. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/types.py +0 -0
  93. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/write_queue.py +0 -0
  94. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/core/write_retry.py +0 -0
  95. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/error_handling.py +0 -0
  96. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/exceptions.py +0 -0
  97. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/extended/__init__.py +0 -0
  98. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/extended/app_error_handler.py +0 -0
  99. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/identity_rule.py +0 -0
  100. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/local_sqlite.py +0 -0
  101. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/middleware/__init__.py +0 -0
  102. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/middleware/base.py +0 -0
  103. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/MODULE_README.md +0 -0
  104. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/__init__.py +0 -0
  105. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/cli.py +0 -0
  106. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/ddl.py +0 -0
  107. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/diff.py +0 -0
  108. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/executor.py +0 -0
  109. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/integration.py +0 -0
  110. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/loader.py +0 -0
  111. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/operations.py +0 -0
  112. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/state.py +0 -0
  113. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/migrations/table_filter.py +0 -0
  114. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/no_org_assignment.py +0 -0
  115. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/FEATURE.md +0 -0
  116. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/MODULE_README.md +0 -0
  117. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/__init__.py +0 -0
  118. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/bulk_update_values.py +0 -0
  119. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/catalog_select.py +0 -0
  120. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/conflict.py +0 -0
  121. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/conflict_writes.py +0 -0
  122. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/create.py +0 -0
  123. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/db_functions.py +0 -0
  124. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/delete.py +0 -0
  125. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/dynamic_admin.py +0 -0
  126. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/dynamic_crud.py +0 -0
  127. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/graph_walk.py +0 -0
  128. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/latest_rows.py +0 -0
  129. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/queue_claim.py +0 -0
  130. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/read.py +0 -0
  131. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/relational_backfill.py +0 -0
  132. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/staging_load.py +0 -0
  133. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/operations/update.py +0 -0
  134. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/platform_db.py +0 -0
  135. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/py.typed +0 -0
  136. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/pytest_lock_guard.py +0 -0
  137. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/pytest_plugin.py +0 -0
  138. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/MODULE_README.md +0 -0
  139. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/__init__.py +0 -0
  140. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/db_objects.py +0 -0
  141. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  142. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  143. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/FEATURE.md +0 -0
  144. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/MODULE_README.md +0 -0
  145. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/__init__.py +0 -0
  146. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/builder.py +0 -0
  147. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/query/executor.py +0 -0
  148. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/resources/__init__.py +0 -0
  149. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  150. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  151. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/FEATURE.md +0 -0
  152. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  153. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/__init__.py +0 -0
  154. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/code_handler.py +0 -0
  155. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  156. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/columns.py +0 -0
  157. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/common.py +0 -0
  158. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/diff_preview.py +0 -0
  159. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  160. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/excluded_targets.py +0 -0
  161. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/generator.py +0 -0
  162. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  163. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  164. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  165. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  166. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/package_wiring.py +0 -0
  167. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/relationships.py +0 -0
  168. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/runner.py +0 -0
  169. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/schema.py +0 -0
  170. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/schema_manager.py +0 -0
  171. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/tables.py +0 -0
  172. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/schema_builder/views.py +0 -0
  173. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  174. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/__init__.py +0 -0
  175. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/attachments.py +0 -0
  176. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/backup_restore.py +0 -0
  177. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/crypto.py +0 -0
  178. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  179. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/model.py +0 -0
  180. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  181. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_enable.py +0 -0
  182. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  183. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  184. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/native_source.py +0 -0
  185. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
  186. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/secrets_battery/vault_history.py +0 -0
  187. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/README.md +0 -0
  188. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/__init__.py +0 -0
  189. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/coalesce.py +0 -0
  190. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/dag.py +0 -0
  191. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/errors.py +0 -0
  192. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/flush.py +0 -0
  193. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/lifecycle.py +0 -0
  194. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/managed.py +0 -0
  195. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/op.py +0 -0
  196. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/reads.py +0 -0
  197. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/session.py +0 -0
  198. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/session/telemetry.py +0 -0
  199. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  200. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/__init__.py +0 -0
  201. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/executor.py +0 -0
  202. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/queries.py +0 -0
  203. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/registry.py +0 -0
  204. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/types.py +0 -0
  205. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/sql_executor/utils.py +0 -0
  206. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/state.py +0 -0
  207. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/utils/__init__.py +0 -0
  208. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/utils/sql_utils.py +0 -0
  209. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/utils/type_converters.py +0 -0
  210. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/matrx_orm/write_actor.py +0 -0
  211. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/scripts/git-branches.sh +0 -0
  212. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/scripts/publish.sh +0 -0
  213. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/scripts/release.sh +0 -0
  214. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/MODULE_README.md +0 -0
  215. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/__init__.py +0 -0
  216. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/conftest.py +0 -0
  217. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/MODULE_README.md +0 -0
  218. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/__init__.py +0 -0
  219. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_adapter_registry.py +0 -0
  220. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_db_columns.py +0 -0
  221. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_response_rendering.py +0 -0
  222. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_search_negation.py +0 -0
  223. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_admin_search_sentinels.py +0 -0
  224. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_advisory_lock.py +0 -0
  225. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_agent_message.py +0 -0
  226. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_auth.py +0 -0
  227. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_config.py +0 -0
  228. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_handlers.py +0 -0
  229. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_api_protocol.py +0 -0
  230. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_array_agg_order_by.py +0 -0
  231. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_association_trigger_actor_naming.py +0 -0
  232. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_associations.py +0 -0
  233. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_associations_wiring.py +0 -0
  234. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_borrowed_role_never_reaches_server_calls.py +0 -0
  235. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_bulk_hydration_offload.py +0 -0
  236. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_bulk_update_by_pk.py +0 -0
  237. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  238. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_cache_debug.py +0 -0
  239. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_case_when.py +0 -0
  240. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_catalog.py +0 -0
  241. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_column_scoped_writes.py +0 -0
  242. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_committed_row_guard.py +0 -0
  243. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_composite_pk_filter.py +0 -0
  244. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_composite_pk_write_paths.py +0 -0
  245. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_config.py +0 -0
  246. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_conflict_target.py +0 -0
  247. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_conflict_writes.py +0 -0
  248. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_connection_codecs.py +0 -0
  249. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_connection_poison_guard.py +0 -0
  250. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_connection_primitives.py +0 -0
  251. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_count_composite_distinct.py +0 -0
  252. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_count_limit_param_leak.py +0 -0
  253. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_ddl_generator.py +0 -0
  254. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_derived_table.py +0 -0
  255. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_dirty_tracking.py +0 -0
  256. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_dynamic_crud.py +0 -0
  257. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_exceptions.py +0 -0
  258. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  259. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_expression_primitives.py +0 -0
  260. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fetch_on_init_holds_whole_table.py +0 -0
  261. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fields.py +0 -0
  262. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  263. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fk_cycle_resolution.py +0 -0
  264. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_from_alias.py +0 -0
  265. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_fts.py +0 -0
  266. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_func_expression_args.py +0 -0
  267. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_graph_walk.py +0 -0
  268. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_guarded_read_never_reruns_empty.py +0 -0
  269. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_having_annotate_alias.py +0 -0
  270. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  271. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_introspect_rls_policies.py +0 -0
  272. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_join_and_aggregate.py +0 -0
  273. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_latest_rows.py +0 -0
  274. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_listen_notify.py +0 -0
  275. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_local_sqlite.py +0 -0
  276. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_lock_contention_retry.py +0 -0
  277. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_managed_write_guard.py +0 -0
  278. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_matrx_entity.py +0 -0
  279. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_migration_diff_types.py +0 -0
  280. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_migration_loader.py +0 -0
  281. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_model_instance.py +0 -0
  282. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_model_meta.py +0 -0
  283. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_optimistic_concurrency.py +0 -0
  284. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_order_by_expression.py +0 -0
  285. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_org_assignment_inventory.py +0 -0
  286. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  287. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_parameter_name_hydration.py +0 -0
  288. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_patch_jsonb_path.py +0 -0
  289. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_percentile_cont.py +0 -0
  290. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_persisted_count.py +0 -0
  291. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
  292. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_create_never_wedges.py +0 -0
  293. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_holder_census.py +0 -0
  294. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_loop_recreation.py +0 -0
  295. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pool_maintenance.py +0 -0
  296. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_postgrest_filters.py +0 -0
  297. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_pydantic_bridge.py +0 -0
  298. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_builder.py +0 -0
  299. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_error_detail.py +0 -0
  300. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_executor_sql.py +0 -0
  301. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_query_timeout.py +0 -0
  302. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  303. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_queue_claim.py +0 -0
  304. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_read_connection_retry.py +0 -0
  305. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_read_write_declared.py +0 -0
  306. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_registry.py +0 -0
  307. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_registry_multi_database.py +0 -0
  308. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_registry_multi_schema.py +0 -0
  309. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_relational_backfill.py +0 -0
  310. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_relations.py +0 -0
  311. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_resilience.py +0 -0
  312. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_rls_session_scope.py +0 -0
  313. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_schema_exists.py +0 -0
  314. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_session_advisory_lock.py +0 -0
  315. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_standalone_write_session_context.py +0 -0
  316. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_state_cache.py +0 -0
  317. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_subquery_filter_raw.py +0 -0
  318. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_subquery_in_filter.py +0 -0
  319. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_subquery_nested_expressions.py +0 -0
  320. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_supabase_auth.py +0 -0
  321. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_supabase_config.py +0 -0
  322. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_sync_pool_declares_read_write.py +0 -0
  323. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_tls.py +0 -0
  324. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_transaction_database_identity.py +0 -0
  325. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_transaction_gucs_one_round_trip.py +0 -0
  326. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
  327. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_typed_join_projection.py +0 -0
  328. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_typed_predicates.py +0 -0
  329. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_update_case_expression.py +0 -0
  330. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_update_subquery.py +0 -0
  331. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_update_with_rebase.py +0 -0
  332. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_upsert_default_leak.py +0 -0
  333. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_upsert_with_conflict.py +0 -0
  334. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_values_jsonb_decode.py +0 -0
  335. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_watched_lifecycle.py +0 -0
  336. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_write_queue_deadline.py +0 -0
  337. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level1/test_write_retry_semantics.py +0 -0
  338. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/MODULE_README.md +0 -0
  339. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/__init__.py +0 -0
  340. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/conftest.py +0 -0
  341. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_bulk_ops.py +0 -0
  342. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_cache_integration.py +0 -0
  343. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_crud.py +0 -0
  344. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_foreign_keys.py +0 -0
  345. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_m2m.py +0 -0
  346. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_manager.py +0 -0
  347. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_migrations_live.py +0 -0
  348. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_query_execution.py +0 -0
  349. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/test_schema_diff.py +0 -0
  350. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
  351. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/live_pooler_role.py +0 -0
  352. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/native_source_cases.py +0 -0
  353. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/native_source_oracle.rs +0 -0
  354. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/.env.example +0 -0
  355. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/README.md +0 -0
  356. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/__init__.py +0 -0
  357. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/generate.py +0 -0
  358. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/generated/.gitkeep +0 -0
  359. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/matrx_orm.yaml +0 -0
  360. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project/test_schema_generation.py +0 -0
  361. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/.env.example +0 -0
  362. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/README.md +0 -0
  363. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/__init__.py +0 -0
  364. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_example.py +0 -0
  365. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_example.ts +0 -0
  366. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  367. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/sample_project_desktop/server.py +0 -0
  368. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/entity_tests.py +0 -0
  369. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_base_generation.py +0 -0
  370. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  371. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_composite_unique_generation.py +0 -0
  372. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_dto_identity_generation.py +0 -0
  373. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_entity_capability_generation.py +0 -0
  374. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_enum_ordering.py +0 -0
  375. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_excluded_fk_targets.py +0 -0
  376. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_generate_schema.py +0 -0
  377. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_junction_analysis.py +0 -0
  378. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_multi_schema_output.py +0 -0
  379. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_schema_analysis.py +0 -0
  380. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_sql_expression_defaults.py +0 -0
  381. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_table_relationships_query.py +0 -0
  382. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema/test_view_generation.py +0 -0
  383. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_array_default_parsing.py +0 -0
  384. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_enum_array_column.py +0 -0
  385. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  386. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  387. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/schema_builder/test_never_filter_columns.py +0 -0
  388. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/__init__.py +0 -0
  389. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/conftest.py +0 -0
  390. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
  391. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_a_grouped_update_writes_only_each_rows_own_fields.py +0 -0
  392. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_cache_no_downgrade.py +0 -0
  393. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_capture_poison_proof.py +0 -0
  394. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_coalesce.py +0 -0
  395. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_dag.py +0 -0
  396. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_disk_spill_fallback.py +0 -0
  397. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_flush_individual_fallback.py +0 -0
  398. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_governed_write.py +0 -0
  399. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_managed.py +0 -0
  400. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_op_enqueue_site.py +0 -0
  401. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_pending_insert_honors_operator_filters.py +0 -0
  402. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_reads.py +0 -0
  403. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_record_error_bounded_insert.py +0 -0
  404. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_record_error_storm.py +0 -0
  405. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_session.py +0 -0
  406. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_spill_guard_plugin.py +0 -0
  407. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/session/test_tests_never_write_live_system_error.py +0 -0
  408. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
  409. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_bulk_cache_never_stalls_the_loop.py +0 -0
  410. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_keyword_column_refuses_generation.py +0 -0
  411. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_list_of_uuids_binds_as_uuid_array.py +0 -0
  412. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
  413. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_a_sealed_field_shows_no_character_of_its_value.py +0 -0
  414. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_array_arg_element_type.py +0 -0
  415. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_attachment_mutation_serialization.py +0 -0
  416. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_backup_alias_conflict.py +0 -0
  417. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_backup_history_restore.py +0 -0
  418. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_backup_restore_live.py +0 -0
  419. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_call_function_as.py +0 -0
  420. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_call_function_none_mode.py +0 -0
  421. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
  422. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_database_name_alias.py +0 -0
  423. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_db_functions.py +0 -0
  424. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_dsn_password_masking.py +0 -0
  425. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_dynamic_select_unregistered.py +0 -0
  426. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_first_asks_the_database_for_one_row.py +0 -0
  427. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_foreign_session_state.py +0 -0
  428. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  429. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_instance_update_runs_expressions.py +0 -0
  430. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_keyed_digest.py +0 -0
  431. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_model_cls_refactor.py +0 -0
  432. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_enable.py +0 -0
  433. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_lifecycle.py +0 -0
  434. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_lifecycle_fences.py +0 -0
  435. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_passkey_receipts.py +0 -0
  436. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_native_source.py +0 -0
  437. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  438. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_one_database.py +0 -0
  439. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_order_by_desc_nulls_last.py +0 -0
  440. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_org_vault_gate.py +0 -0
  441. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_package_wiring_views.py +0 -0
  442. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_pooler_role_guard.py +0 -0
  443. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_secret_audit_names_its_organization.py +0 -0
  444. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_secrets_battery.py +0 -0
  445. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_secrets_minting_keys.py +0 -0
  446. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_shared_lock_guard.py +0 -0
  447. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_sql_param_casts.py +0 -0
  448. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_state_cache_sweeps_stale.py +0 -0
  449. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_statement_ceiling_warning.py +0 -0
  450. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_sync_twins_guard.py +0 -0
  451. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_update_result_truthiness.py +0 -0
  452. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_user_visible_lookup.py +0 -0
  453. {matrx_orm-3.1.245 → matrx_orm-3.1.246}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.245
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
@@ -693,6 +693,7 @@ async def record_error(
693
693
  payload: Any | None = None,
694
694
  context: dict[str, Any] | None = None,
695
695
  database: str | None = None,
696
+ group_open: bool = False,
696
697
  ) -> None:
697
698
  """Universal failure capture for NON-write errors → ``system_error``.
698
699
 
@@ -737,6 +738,16 @@ async def record_error(
737
738
  indistinguishable from a Codex one.
738
739
  payload: request args/body to capture (jsonb). Serialized defensively.
739
740
  context: free-form context (debug_label, task_name, partial cost, …).
741
+ group_open: ONE OPEN ROW PER SIGNATURE (error-capture rule "a count is a
742
+ number on an existing row, never a new row"). When True, a capture whose
743
+ ``(kind, route, error_type)`` already has an UNRESOLVED row bumps that row's
744
+ ``context.occurrences`` (exact, atomic, across every process and deploy) and
745
+ ``context.last_seen_at`` instead of filing a new row; with none open it files
746
+ the row with ``occurrences=1``. Resolving the row zeroes the count — the next
747
+ occurrence reopens as one new row. For announcements that are a COUNT of a
748
+ known condition per site (legacy lanes, runtime bypasses), never for a crash
749
+ whose every instance carries its own inputs. The storm budget does not apply
750
+ (the grouping is the budget).
740
751
  """
741
752
  # Both attribution halves ride the carried request context; a capture site
742
753
  # that declared neither still files a fully categorized row.
@@ -755,7 +766,7 @@ async def record_error(
755
766
  else:
756
767
  tb_text = "".join(_tb.format_exception(type(exc), exc, exc.__traceback__))
757
768
 
758
- admitted, folded = _storm_admit(kind, resolved_error_type, route)
769
+ admitted, folded = (True, 0) if group_open else _storm_admit(kind, resolved_error_type, route)
759
770
  if not admitted:
760
771
  # Counted, never silent: the next admitted row for this signature
761
772
  # carries the total. ONE stdout line per window (the first fold) — a line per
@@ -803,12 +814,14 @@ async def record_error(
803
814
  "route": route,
804
815
  "context": context,
805
816
  "payload": payload,
817
+ **({"group_open": True} if group_open else {}),
806
818
  }
807
819
  )
808
820
  return
809
821
 
810
822
  try:
811
823
  await _insert_error(
824
+ **({"group_open": True} if group_open else {}),
812
825
  kind=kind,
813
826
  request_id=request_id,
814
827
  user_id=user_id,
@@ -912,6 +925,7 @@ async def _insert_error(
912
925
  payload: Any | None,
913
926
  context: dict[str, Any] | None,
914
927
  database: str | None,
928
+ group_open: bool = False,
915
929
  ) -> None:
916
930
  from matrx_orm.adapters import AdapterRegistry
917
931
  from matrx_orm.core.config import get_all_database_project_names
@@ -947,6 +961,13 @@ async def _insert_error(
947
961
  # capture fast instead of parking a pool slot behind it.
948
962
  await conn.execute(f"SET LOCAL lock_timeout = '{CAPTURE_LOCK_TIMEOUT_MS}ms'")
949
963
  await conn.execute(f"SET LOCAL statement_timeout = '{CAPTURE_STATEMENT_TIMEOUT_MS}ms'")
964
+ if group_open:
965
+ if await _bump_open_error(conn, kind=kind, route=route, error_type=error_type):
966
+ return
967
+ context_json = json.dumps(
968
+ {**(context or {}), "occurrences": 1, "grouped": GROUPED_NOTE},
969
+ default=_json_default,
970
+ )
950
971
  await _execute_error_insert(
951
972
  conn,
952
973
  kind=kind,
@@ -967,6 +988,39 @@ async def _insert_error(
967
988
 
968
989
 
969
990
 
991
+ #: Stamped on a grouped row (``record_error(group_open=True)``) so a reader knows what the count means.
992
+ GROUPED_NOTE = (
993
+ "one open row per kind+route+error_type; context.occurrences counts every capture since the row "
994
+ "was last resolved (all processes), context.last_seen_at the latest"
995
+ )
996
+
997
+ # The bump is ONE statement under a transaction-scoped advisory lock on the signature, so two
998
+ # processes seeing the same site at once neither lose a count nor both file a row.
999
+ _GROUP_LOCK_SQL = "SELECT pg_advisory_xact_lock(hashtextextended($1::text, 0))"
1000
+ _GROUP_BUMP_SQL = """
1001
+ UPDATE ops.system_error
1002
+ SET context = coalesce(context, '{}'::jsonb) || jsonb_build_object(
1003
+ 'occurrences', coalesce((context->>'occurrences')::bigint, 1) + 1,
1004
+ 'last_seen_at', now())
1005
+ WHERE id = (
1006
+ SELECT id FROM ops.system_error
1007
+ WHERE kind = $1::text
1008
+ AND route IS NOT DISTINCT FROM $2::text
1009
+ AND error_type IS NOT DISTINCT FROM $3::text
1010
+ AND resolved_at IS NULL
1011
+ ORDER BY occurred_at
1012
+ LIMIT 1)
1013
+ RETURNING id
1014
+ """
1015
+
1016
+
1017
+ async def _bump_open_error(conn: Any, *, kind: str, route: str | None, error_type: str | None) -> bool:
1018
+ """Count this capture on the signature's open row; False when none is open (file one)."""
1019
+ await conn.fetch(_GROUP_LOCK_SQL, f"system_error:{kind}|{route or ''}|{error_type or ''}")
1020
+ rows = await conn.fetch(_GROUP_BUMP_SQL, kind, route, error_type)
1021
+ return bool(rows)
1022
+
1023
+
970
1024
  _LIVE_INSERT_ERROR = _insert_error
971
1025
 
972
1026
  async def _execute_error_insert(
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.245"
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"
@@ -0,0 +1,48 @@
1
+ """A ``last_used_at`` stamp is telemetry: its failure never ends the read (or the run) that used the secret.
2
+
3
+ 2026-10-22: a timed-out ``UPDATE users.user_secrets SET last_used_at`` stopped a whole Notion import.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import asyncio
9
+ import pathlib
10
+ import re
11
+
12
+ from matrx_orm.secrets_battery.use_stamp import stamp_last_used
13
+
14
+ ROOT = pathlib.Path(__file__).resolve().parents[3]
15
+
16
+
17
+ class _TimesOut:
18
+ calls = 0
19
+
20
+ @classmethod
21
+ async def update_where(cls, filters, **kw):
22
+ cls.calls += 1
23
+ raise TimeoutError("statement timeout")
24
+
25
+
26
+ def test_a_timed_out_stamp_is_dropped_not_raised():
27
+ assert asyncio.run(stamp_last_used(_TimesOut, {"id": "x"})) is False
28
+ assert _TimesOut.calls == 1
29
+
30
+
31
+ # Inside a held transaction a swallowed error would poison it, so those two stamps stay raw.
32
+ _TRANSACTIONAL = {"packages/matrx-orm/matrx_orm/secrets_battery/attachments.py"}
33
+
34
+
35
+ def test_no_bare_user_secret_stamp_outside_the_helper():
36
+ """Every non-transactional ``last_used_at`` stamp on a vault row goes through ``stamp_last_used``."""
37
+ offenders = []
38
+ for base in ("packages/matrx-orm/matrx_orm/secrets_battery", "aidream/services/user_secrets"):
39
+ for path in (ROOT / base).rglob("*.py"):
40
+ rel = path.relative_to(ROOT).as_posix()
41
+ if rel in _TRANSACTIONAL or path.name == "use_stamp.py" or "/tests/" in rel:
42
+ continue
43
+ text = path.read_text()
44
+ for m in re.finditer(r"UserSecret\.update_where\((?:[^()]|\([^()]*\))*?last_used_at\s*=", text, re.S):
45
+ if "_stamp_used_secrets" in text[max(0, m.start() - 1500): m.start()]:
46
+ continue # retries lock collisions itself and swallows every other failure
47
+ offenders.append(f"{rel}:{text[: m.start()].count(chr(10)) + 1}")
48
+ assert not offenders, f"raw last_used_at stamps that can fail a run: {offenders}"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes