matrx-orm 3.1.142__tar.gz → 3.1.144__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 (379) hide show
  1. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/PKG-INFO +1 -1
  2. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/FEATURE.md +4 -1
  3. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/__init__.py +10 -0
  4. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/async_db_manager.py +2 -0
  5. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/transaction.py +35 -3
  6. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/update.py +13 -11
  7. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/query/FEATURE.md +10 -0
  8. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/query/builder.py +22 -0
  9. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/README.md +15 -0
  10. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/__init__.py +10 -0
  11. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/errors.py +11 -0
  12. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/fallback.py +140 -8
  13. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/session.py +91 -1
  14. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/pyproject.toml +1 -1
  15. matrx_orm-3.1.144/tests/level1/test_committed_row_guard.py +144 -0
  16. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_optimistic_concurrency.py +5 -3
  17. matrx_orm-3.1.144/tests/level1/test_transaction_database_identity.py +114 -0
  18. matrx_orm-3.1.144/tests/level2/verify_committed_row_guard_pg17.py +588 -0
  19. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_disk_spill_fallback.py +11 -0
  20. matrx_orm-3.1.144/tests/test_immutable_insert_or_exact_verify.py +159 -0
  21. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/.gitignore +0 -0
  22. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/AGENTS.md +0 -0
  23. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/BASE_CLASS_METHODS.md +0 -0
  24. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/CLAUDE.md +0 -0
  25. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/MODEL_API.md +0 -0
  26. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/README.md +0 -0
  27. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/database/orm/extended/managers/ai_model_base.py +0 -0
  28. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/docs/migrations.md +0 -0
  29. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/MODULE_README.md +0 -0
  30. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/MODULE_README.md +0 -0
  31. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/__init__.py +0 -0
  32. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/async_postgresql.py +0 -0
  33. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/base_adapter.py +0 -0
  34. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/postgresql.py +0 -0
  35. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  36. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/adapters/supabase_adapter.py +0 -0
  37. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/admin/FEATURE.md +0 -0
  38. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/admin/__init__.py +0 -0
  39. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/admin/router.py +0 -0
  40. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/api/__init__.py +0 -0
  41. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/api/auth.py +0 -0
  42. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/api/config.py +0 -0
  43. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/api/handlers.py +0 -0
  44. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/api/protocol.py +0 -0
  45. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/api/server.py +0 -0
  46. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/associations.py +0 -0
  47. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/cache_debug.py +0 -0
  48. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/catalog.py +0 -0
  49. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/catalog_sql.py +0 -0
  50. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/MODULE_README.md +0 -0
  51. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/__init__.py +0 -0
  52. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/postgres_connection.py +0 -0
  53. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/postgrest.py +0 -0
  54. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/supabase_auth.py +0 -0
  55. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/supabase_config.py +0 -0
  56. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/client/supabase_manager.py +0 -0
  57. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  58. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/FEATURE.md +0 -0
  59. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/MODULE_README.md +0 -0
  60. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  61. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/TASKS.md +0 -0
  62. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/__init__.py +0 -0
  63. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/base.py +0 -0
  64. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/config.py +0 -0
  65. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/connections.py +0 -0
  66. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/db_function.py +0 -0
  67. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/diagnostics.py +0 -0
  68. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/expressions.py +0 -0
  69. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/extended.py +0 -0
  70. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/fields.py +0 -0
  71. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/introspection.py +0 -0
  72. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/listen.py +0 -0
  73. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/loop_filters.py +0 -0
  74. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/model_dto.py +0 -0
  75. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/model_view.py +0 -0
  76. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/one_database.py +0 -0
  77. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/paginator.py +0 -0
  78. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/pool_maintenance.py +0 -0
  79. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/pool_watch.py +0 -0
  80. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/pooler_role.py +0 -0
  81. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/pydantic_bridge.py +0 -0
  82. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/registry.py +0 -0
  83. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/relations.py +0 -0
  84. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/resilience.py +0 -0
  85. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/rls_session.py +0 -0
  86. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/session_context.py +0 -0
  87. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/signals.py +0 -0
  88. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/tls.py +0 -0
  89. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/types.py +0 -0
  90. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/core/write_queue.py +0 -0
  91. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/entity.py +0 -0
  92. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/error_handling.py +0 -0
  93. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/exceptions.py +0 -0
  94. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/extended/__init__.py +0 -0
  95. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/extended/app_error_handler.py +0 -0
  96. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/identity_rule.py +0 -0
  97. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/local_sqlite.py +0 -0
  98. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/middleware/__init__.py +0 -0
  99. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/middleware/base.py +0 -0
  100. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/MODULE_README.md +0 -0
  101. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/__init__.py +0 -0
  102. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/cli.py +0 -0
  103. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/ddl.py +0 -0
  104. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/diff.py +0 -0
  105. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/executor.py +0 -0
  106. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/integration.py +0 -0
  107. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/loader.py +0 -0
  108. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/operations.py +0 -0
  109. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/state.py +0 -0
  110. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/migrations/table_filter.py +0 -0
  111. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/no_org_assignment.py +0 -0
  112. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/FEATURE.md +0 -0
  113. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/MODULE_README.md +0 -0
  114. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/__init__.py +0 -0
  115. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/bulk_update_values.py +0 -0
  116. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/catalog_select.py +0 -0
  117. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/conflict.py +0 -0
  118. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/conflict_writes.py +0 -0
  119. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/create.py +0 -0
  120. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/db_functions.py +0 -0
  121. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/delete.py +0 -0
  122. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/dynamic_admin.py +0 -0
  123. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/dynamic_crud.py +0 -0
  124. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/graph_walk.py +0 -0
  125. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/latest_rows.py +0 -0
  126. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/queue_claim.py +0 -0
  127. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/read.py +0 -0
  128. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/relational_backfill.py +0 -0
  129. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/operations/staging_load.py +0 -0
  130. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/platform_access.py +0 -0
  131. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/platform_db.py +0 -0
  132. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/py.typed +0 -0
  133. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/pytest_plugin.py +0 -0
  134. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/python_sql/MODULE_README.md +0 -0
  135. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/python_sql/__init__.py +0 -0
  136. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/python_sql/db_objects.py +0 -0
  137. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  138. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  139. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/query/MODULE_README.md +0 -0
  140. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/query/__init__.py +0 -0
  141. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/query/executor.py +0 -0
  142. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/resources/__init__.py +0 -0
  143. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  144. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  145. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/FEATURE.md +0 -0
  146. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  147. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/__init__.py +0 -0
  148. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/code_handler.py +0 -0
  149. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  150. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/columns.py +0 -0
  151. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/common.py +0 -0
  152. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/diff_preview.py +0 -0
  153. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  154. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/generator.py +0 -0
  155. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  156. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  157. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  158. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  159. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/package_wiring.py +0 -0
  160. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/relationships.py +0 -0
  161. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/runner.py +0 -0
  162. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/schema.py +0 -0
  163. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/schema_manager.py +0 -0
  164. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/tables.py +0 -0
  165. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/schema_builder/views.py +0 -0
  166. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  167. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/__init__.py +0 -0
  168. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/attachments.py +0 -0
  169. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/crypto.py +0 -0
  170. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  171. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/items.py +0 -0
  172. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/model.py +0 -0
  173. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  174. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/org_service.py +0 -0
  175. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/secrets_battery/service.py +0 -0
  176. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/coalesce.py +0 -0
  177. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/dag.py +0 -0
  178. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/flush.py +0 -0
  179. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/lifecycle.py +0 -0
  180. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/managed.py +0 -0
  181. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/op.py +0 -0
  182. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/reads.py +0 -0
  183. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/session/telemetry.py +0 -0
  184. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  185. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/__init__.py +0 -0
  186. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/executor.py +0 -0
  187. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/queries.py +0 -0
  188. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/registry.py +0 -0
  189. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/types.py +0 -0
  190. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/sql_executor/utils.py +0 -0
  191. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/state.py +0 -0
  192. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/utils/__init__.py +0 -0
  193. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/utils/sql_utils.py +0 -0
  194. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/matrx_orm/utils/type_converters.py +0 -0
  195. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/scripts/git-branches.sh +0 -0
  196. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/scripts/publish.sh +0 -0
  197. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/scripts/release.sh +0 -0
  198. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/MODULE_README.md +0 -0
  199. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/__init__.py +0 -0
  200. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/conftest.py +0 -0
  201. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/MODULE_README.md +0 -0
  202. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/__init__.py +0 -0
  203. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_adapter_registry.py +0 -0
  204. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_admin_db_columns.py +0 -0
  205. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_admin_response_rendering.py +0 -0
  206. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_admin_search_negation.py +0 -0
  207. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_admin_search_sentinels.py +0 -0
  208. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_advisory_lock.py +0 -0
  209. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_agent_message.py +0 -0
  210. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_api_auth.py +0 -0
  211. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_api_config.py +0 -0
  212. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_api_handlers.py +0 -0
  213. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_api_protocol.py +0 -0
  214. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_array_agg_order_by.py +0 -0
  215. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_associations.py +0 -0
  216. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_associations_wiring.py +0 -0
  217. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_bulk_hydration_offload.py +0 -0
  218. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_bulk_update_by_pk.py +0 -0
  219. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  220. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_cache_debug.py +0 -0
  221. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_call_function.py +0 -0
  222. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_case_when.py +0 -0
  223. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_catalog.py +0 -0
  224. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_composite_pk_filter.py +0 -0
  225. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_composite_pk_write_paths.py +0 -0
  226. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_config.py +0 -0
  227. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_conflict_target.py +0 -0
  228. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_conflict_writes.py +0 -0
  229. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_connection_codecs.py +0 -0
  230. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_connection_poison_guard.py +0 -0
  231. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_connection_primitives.py +0 -0
  232. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_count_composite_distinct.py +0 -0
  233. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_count_limit_param_leak.py +0 -0
  234. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_db_function_field.py +0 -0
  235. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_ddl_generator.py +0 -0
  236. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_derived_table.py +0 -0
  237. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_dirty_tracking.py +0 -0
  238. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_dynamic_crud.py +0 -0
  239. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_exceptions.py +0 -0
  240. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  241. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_expression_primitives.py +0 -0
  242. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_fields.py +0 -0
  243. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  244. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_from_alias.py +0 -0
  245. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_fts.py +0 -0
  246. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_func_expression_args.py +0 -0
  247. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_graph_walk.py +0 -0
  248. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_having_annotate_alias.py +0 -0
  249. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  250. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_introspect_rls_policies.py +0 -0
  251. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_join_and_aggregate.py +0 -0
  252. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_latest_rows.py +0 -0
  253. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_listen_notify.py +0 -0
  254. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_local_sqlite.py +0 -0
  255. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_lock_contention_retry.py +0 -0
  256. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_managed_write_guard.py +0 -0
  257. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_matrx_entity.py +0 -0
  258. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_migration_diff_types.py +0 -0
  259. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_migration_loader.py +0 -0
  260. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_model_instance.py +0 -0
  261. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_model_meta.py +0 -0
  262. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_order_by_expression.py +0 -0
  263. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_org_assignment_inventory.py +0 -0
  264. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_parameter_name_hydration.py +0 -0
  265. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_patch_jsonb_path.py +0 -0
  266. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_persisted_count.py +0 -0
  267. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_pool_holder_census.py +0 -0
  268. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_pool_loop_recreation.py +0 -0
  269. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_pool_maintenance.py +0 -0
  270. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_postgrest_filters.py +0 -0
  271. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_pydantic_bridge.py +0 -0
  272. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_query_builder.py +0 -0
  273. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_query_error_detail.py +0 -0
  274. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_query_executor_sql.py +0 -0
  275. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_query_timeout.py +0 -0
  276. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  277. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_queue_claim.py +0 -0
  278. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_read_connection_retry.py +0 -0
  279. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_registry.py +0 -0
  280. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_registry_multi_database.py +0 -0
  281. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_registry_multi_schema.py +0 -0
  282. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_relational_backfill.py +0 -0
  283. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_relations.py +0 -0
  284. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_resilience.py +0 -0
  285. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_rls_session_scope.py +0 -0
  286. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_schema_exists.py +0 -0
  287. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_session_advisory_lock.py +0 -0
  288. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_standalone_write_session_context.py +0 -0
  289. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_state_cache.py +0 -0
  290. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_subquery_filter_raw.py +0 -0
  291. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_subquery_in_filter.py +0 -0
  292. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_subquery_nested_expressions.py +0 -0
  293. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_supabase_auth.py +0 -0
  294. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_supabase_config.py +0 -0
  295. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_tls.py +0 -0
  296. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_typed_join_projection.py +0 -0
  297. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_typed_predicates.py +0 -0
  298. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_update_case_expression.py +0 -0
  299. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_update_subquery.py +0 -0
  300. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_update_with_rebase.py +0 -0
  301. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_upsert_default_leak.py +0 -0
  302. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_upsert_with_conflict.py +0 -0
  303. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_values_jsonb_decode.py +0 -0
  304. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_watched_lifecycle.py +0 -0
  305. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_write_queue_deadline.py +0 -0
  306. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level1/test_write_retry_semantics.py +0 -0
  307. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/MODULE_README.md +0 -0
  308. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/__init__.py +0 -0
  309. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/conftest.py +0 -0
  310. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_bulk_ops.py +0 -0
  311. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_cache_integration.py +0 -0
  312. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_crud.py +0 -0
  313. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_foreign_keys.py +0 -0
  314. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_m2m.py +0 -0
  315. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_manager.py +0 -0
  316. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_migrations_live.py +0 -0
  317. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_query_execution.py +0 -0
  318. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/level2/test_schema_diff.py +0 -0
  319. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/live_pooler_role.py +0 -0
  320. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/.env.example +0 -0
  321. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/README.md +0 -0
  322. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/__init__.py +0 -0
  323. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/generate.py +0 -0
  324. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/generated/.gitkeep +0 -0
  325. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/matrx_orm.yaml +0 -0
  326. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project/test_schema_generation.py +0 -0
  327. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/.env.example +0 -0
  328. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/README.md +0 -0
  329. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/__init__.py +0 -0
  330. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/client_example.py +0 -0
  331. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/client_example.ts +0 -0
  332. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  333. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/sample_project_desktop/server.py +0 -0
  334. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/entity_tests.py +0 -0
  335. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_base_generation.py +0 -0
  336. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  337. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_composite_unique_generation.py +0 -0
  338. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_dto_identity_generation.py +0 -0
  339. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_entity_capability_generation.py +0 -0
  340. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_enum_ordering.py +0 -0
  341. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_generate_schema.py +0 -0
  342. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_junction_analysis.py +0 -0
  343. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_multi_schema_output.py +0 -0
  344. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_schema_analysis.py +0 -0
  345. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_sql_expression_defaults.py +0 -0
  346. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_table_relationships_query.py +0 -0
  347. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema/test_view_generation.py +0 -0
  348. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema_builder/test_array_default_parsing.py +0 -0
  349. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  350. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  351. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/__init__.py +0 -0
  352. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/conftest.py +0 -0
  353. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_cache_no_downgrade.py +0 -0
  354. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_capture_poison_proof.py +0 -0
  355. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_coalesce.py +0 -0
  356. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_dag.py +0 -0
  357. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_flush_individual_fallback.py +0 -0
  358. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_governed_write.py +0 -0
  359. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_managed.py +0 -0
  360. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_op_enqueue_site.py +0 -0
  361. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_reads.py +0 -0
  362. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_record_error_bounded_insert.py +0 -0
  363. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_record_error_storm.py +0 -0
  364. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_session.py +0 -0
  365. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/session/test_spill_guard_plugin.py +0 -0
  366. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_array_arg_element_type.py +0 -0
  367. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_database_name_alias.py +0 -0
  368. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_db_functions.py +0 -0
  369. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_dynamic_select_unregistered.py +0 -0
  370. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_keyed_digest.py +0 -0
  371. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_model_cls_refactor.py +0 -0
  372. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  373. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_one_database.py +0 -0
  374. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_order_by_desc_nulls_last.py +0 -0
  375. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_pooler_role_guard.py +0 -0
  376. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_secrets_battery.py +0 -0
  377. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_secrets_minting_keys.py +0 -0
  378. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_sql_param_casts.py +0 -0
  379. {matrx_orm-3.1.142 → matrx_orm-3.1.144}/tests/test_sync_twins_guard.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.142
3
+ Version: 3.1.144
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
@@ -11,7 +11,7 @@
11
11
 
12
12
  `session/fallback.py` owns both failure-capture tables — `ops.system_error`
13
13
  (`record_error`) and `ops.system_write_failure` (`record_failures`,
14
- `drain_spilled_ops`, `create_or_capture`). Both carry `organization_id NOT NULL`.
14
+ `drain_spilled_ops`, `immutable_insert_or_exact_verify`). Both carry `organization_id NOT NULL`.
15
15
 
16
16
  - **Every capture row is org-stamped by `_capture_org()`.** Three rungs: an org
17
17
  the caller passed, else `None` — handing the row to the DB's
@@ -115,6 +115,9 @@
115
115
 
116
116
  ## Change Log
117
117
 
118
+ - 2026-09-12 — Added `immutable_insert_or_exact_verify`: immutable direct writes
119
+ normalize timestamps/JSON, verify the full row after ambiguous acknowledgements,
120
+ preserve absent intent under a distinct replay marker, and refuse conflicts.
118
121
  - 2026-09-12 — Made organization-assignment retirement output an explicit,
119
122
  non-overwriting review proposal; a checked-in resource update is required
120
123
  before the next standalone wheel carries a retirement.
@@ -356,6 +356,7 @@ from matrx_orm.session import (
356
356
  FlushError,
357
357
  FlushReport,
358
358
  ManagedWriteViolation,
359
+ PendingRowOperationError,
359
360
  Session,
360
361
  SessionClosedError,
361
362
  SessionError,
@@ -367,11 +368,15 @@ from matrx_orm.session import (
367
368
  allow_direct_coordinator_write,
368
369
  coordinator_policy_tables,
369
370
  create_or_capture,
371
+ immutable_insert_or_exact_verify,
372
+ immutable_row_differences,
370
373
  current_session,
374
+ assert_no_pending_row,
371
375
  declare_managed,
372
376
  drain_spilled_ops,
373
377
  is_in_session,
374
378
  WritePreservedError,
379
+ ImmutableWriteConflictError,
375
380
  record_error,
376
381
  record_failures,
377
382
  register_coordinator_owned_model,
@@ -675,6 +680,7 @@ __all__ = [
675
680
  "FlushError",
676
681
  "FlushReport",
677
682
  "ManagedWriteViolation",
683
+ "PendingRowOperationError",
678
684
  "Session",
679
685
  "SessionClosedError",
680
686
  "SessionError",
@@ -683,13 +689,17 @@ __all__ = [
683
689
  "WatchedLifecycleConfig",
684
690
  "WatchedLifecycleRegistry",
685
691
  "current_session",
692
+ "assert_no_pending_row",
686
693
  "declare_managed",
687
694
  "is_in_session",
688
695
  "record_error",
689
696
  "record_failures",
690
697
  "drain_spilled_ops",
691
698
  "create_or_capture",
699
+ "immutable_insert_or_exact_verify",
700
+ "immutable_row_differences",
692
701
  "WritePreservedError",
702
+ "ImmutableWriteConflictError",
693
703
  "run_lifecycle_sweeper",
694
704
  "sweep_lifecycle_once",
695
705
  # ── Adapter layer ──────────────────────────────────────────────────────────
@@ -157,6 +157,8 @@ READ_TIMEOUT_RETRY_BACKOFF = 0.25 # seconds before the read retry
157
157
  # "listConversations: deadlock detected" on /chat, and ops.app_log shows the same
158
158
  # class crashing POST /coding-sessions/bridge with a 500. Bounded and LOUD: real
159
159
  # contention still surfaces, it just costs two extra attempts first.
160
+ # KNOB MIRROR of platform.feature_knob "orm.write_retry" "contention_retries" — the database
161
+ # manager cannot read the database to configure itself; change the row, then re-mirror here.
160
162
  CONTENTION_RETRIES = 2 # extra attempts for a cancelled statement; total = 1 + this
161
163
  CONTENTION_BACKOFF = 0.06 # seconds before the first re-issue; doubled each time
162
164
 
@@ -48,6 +48,10 @@ from matrx_orm.exceptions import DatabaseError
48
48
 
49
49
  # ContextVar holding the active connection (if any) for the current task tree.
50
50
  _active_connection: ContextVar[Any | None] = ContextVar("_active_connection", default=None)
51
+ # The canonical registered database that owns ``_active_connection``. A raw
52
+ # connection has no portable database identity, so callers that need routing
53
+ # truth must use this ContextVar rather than infer it from connection details.
54
+ _active_database: ContextVar[str | None] = ContextVar("_active_database", default=None)
51
55
  # ContextVar tracking savepoint depth (0 = top-level transaction)
52
56
  _savepoint_depth: ContextVar[int] = ContextVar("_savepoint_depth", default=0)
53
57
 
@@ -57,6 +61,11 @@ def get_active_connection() -> Any | None:
57
61
  return _active_connection.get()
58
62
 
59
63
 
64
+ def get_active_database_name() -> str | None:
65
+ """Return the canonical database identity of the active transaction."""
66
+ return _active_database.get()
67
+
68
+
60
69
  async def advisory_xact_lock(key: str | int, *, connection: Any = None) -> None:
61
70
  """Acquire a transaction-scoped Postgres advisory lock
62
71
  (``pg_advisory_xact_lock``) keyed on ``key``. Auto-released at
@@ -213,6 +222,7 @@ class TransactionContext:
213
222
  def __init__(self, database: str) -> None:
214
223
  self.database = database
215
224
  self._conn_token: Token[Any | None] | None = None
225
+ self._database_token: Token[str | None] | None = None
216
226
  self._depth_token: Token[int] | None = None
217
227
  self._is_savepoint: bool = False
218
228
  self._savepoint_name: str = ""
@@ -227,7 +237,16 @@ class TransactionContext:
227
237
  self._savepoint_name = f"sp_{uuid.uuid4().hex[:12]}"
228
238
  depth = _savepoint_depth.get()
229
239
  self._depth_token = _savepoint_depth.set(depth + 1)
230
- await existing.execute(f"SAVEPOINT {self._savepoint_name}")
240
+ try:
241
+ await existing.execute(f"SAVEPOINT {self._savepoint_name}")
242
+ except BaseException:
243
+ # Entry never completed, so __aexit__ will not run. Restore
244
+ # only this attempted savepoint's depth; the outer transaction
245
+ # owns its connection, database identity and eventual cleanup.
246
+ _savepoint_depth.reset(self._depth_token)
247
+ self._depth_token = None
248
+ self._is_savepoint = False
249
+ raise
231
250
  else:
232
251
  # Top-level → BEGIN
233
252
  self._is_savepoint = False
@@ -239,15 +258,24 @@ class TransactionContext:
239
258
  self._raw_conn = conn
240
259
  try:
241
260
  await conn.execute("BEGIN")
242
- except Exception as e:
261
+ except BaseException as e:
243
262
  await self._adapter_cm.__aexit__(type(e), e, e.__traceback__)
244
263
  self._raw_conn = None
245
264
  self._adapter_cm = None
265
+ if not isinstance(e, Exception):
266
+ raise
246
267
  raise DatabaseError(
247
268
  message=f"Failed to begin transaction: {e}",
248
269
  details={"database": self.database},
249
270
  ) from e
271
+ # Keep the connection and its canonical database identity bound as
272
+ # one top-level transaction fact. Nested transactions are
273
+ # savepoints and deliberately retain the outer identity.
274
+ from matrx_orm.core.config import resolve_database_name
275
+
276
+ canonical_database = resolve_database_name(self.database)
250
277
  self._conn_token = _active_connection.set(conn)
278
+ self._database_token = _active_database.set(canonical_database)
251
279
  self._depth_token = _savepoint_depth.set(0)
252
280
  # THE HOST'S DECLARED SESSION CONTEXT (provenance and friends). A
253
281
  # transaction-local GUC only has meaning inside a transaction, so
@@ -260,8 +288,10 @@ class TransactionContext:
260
288
 
261
289
  try:
262
290
  await apply_session_context(conn)
263
- except Exception as e:
291
+ except BaseException as e:
264
292
  await self.__aexit__(type(e), e, e.__traceback__)
293
+ if not isinstance(e, Exception):
294
+ raise
265
295
  raise DatabaseError(
266
296
  message=f"Failed to apply the declared session context: {e}",
267
297
  details={"database": self.database},
@@ -290,6 +320,8 @@ class TransactionContext:
290
320
  # Top-level: restore ContextVars before touching the connection
291
321
  if self._conn_token is not None:
292
322
  _active_connection.reset(self._conn_token)
323
+ if self._database_token is not None:
324
+ _active_database.reset(self._database_token)
293
325
  if self._depth_token is not None:
294
326
  _savepoint_depth.reset(self._depth_token)
295
327
 
@@ -91,7 +91,7 @@ async def _conflict_actor(
91
91
  )
92
92
  .order_by("-id")
93
93
  .limit(1)
94
- .all()
94
+ .get_committed()
95
95
  )
96
96
  except Exception as exc:
97
97
  vcprint(
@@ -102,10 +102,9 @@ async def _conflict_actor(
102
102
  log_level="WARNING",
103
103
  )
104
104
  return (None, None)
105
- if not snapshots:
105
+ if snapshots is None:
106
106
  return (None, None)
107
- snapshot = snapshots[0]
108
- return (getattr(snapshot, "actor_id", None), getattr(snapshot, "occurred_at", None))
107
+ return (getattr(snapshots, "actor_id", None), getattr(snapshots, "occurred_at", None))
109
108
 
110
109
 
111
110
  async def _build_conflict(
@@ -149,10 +148,7 @@ async def _raise_stale_write(
149
148
  """
150
149
  from matrx_orm.exceptions import DoesNotExist
151
150
 
152
- # Note: inside an open Session the re-read merges PENDING (uncommitted)
153
- # writes for this row — a CAS should run on the direct write paths, not
154
- # Coordinator-adjacent code (see the contract's session-plane exclusion).
155
- current = await QueryBuilder(model_cls).filter(**pk_filter).get_or_none()
151
+ current = await QueryBuilder(model_cls).filter(**pk_filter).get_committed_or_none()
156
152
  if current is None or getattr(current, "deleted_at", None) is not None:
157
153
  # Hard-gone or soft-deleted: for conflict classification a soft-deleted
158
154
  # row IS gone — reporting it as "changed by someone else, refresh and
@@ -190,12 +186,15 @@ async def guarded_update(
190
186
  narrowing filter that stopped matching still classifies as a conflict.
191
187
  """
192
188
  _require_version_column(model_cls, version_column)
189
+ from matrx_orm.session import assert_no_pending_row
190
+
191
+ pk_filter = {pk: filters[pk] for pk in model_cls._meta.primary_keys}
192
+ assert_no_pending_row(model_cls, pk_filter)
193
193
  data = dict(update_data)
194
194
  attempted_fields = list(data)
195
195
  data.setdefault(version_column, expected_version + 1)
196
196
  result = await update(model_cls, {**filters, version_column: expected_version}, **data)
197
197
  if result.rows_affected == 0:
198
- pk_filter = {pk: filters[pk] for pk in model_cls._meta.primary_keys}
199
198
  await _raise_stale_write(
200
199
  model_cls, pk_filter, version_column, expected_version, attempted_fields
201
200
  )
@@ -373,14 +372,17 @@ async def guarded_delete(
373
372
  delete; deleting it anyway would discard their work unseen).
374
373
  """
375
374
  _require_version_column(model_cls, version_column)
375
+ from matrx_orm.session import assert_no_pending_row
376
+
377
+ pk_filter = {pk: filters[pk] for pk in model_cls._meta.primary_keys}
378
+ assert_no_pending_row(model_cls, pk_filter)
376
379
  deleted = (
377
380
  await QueryBuilder(model_cls)
378
381
  .filter(**{**filters, version_column: expected_version})
379
382
  .delete()
380
383
  )
381
384
  if deleted == 0:
382
- pk_filter = {pk: filters[pk] for pk in model_cls._meta.primary_keys}
383
- current = await QueryBuilder(model_cls).filter(**pk_filter).get_or_none()
385
+ current = await QueryBuilder(model_cls).filter(**pk_filter).get_committed_or_none()
384
386
  # Soft-deleted counts as already gone — idempotent 0, not a conflict.
385
387
  if current is not None and getattr(current, "deleted_at", None) is None:
386
388
  # A delete contests no individual field (it contests the whole row),
@@ -70,6 +70,16 @@ want persisted database state call `count(include_pending=False)`. That opt-out
70
70
  always uses the database aggregate and never hydrates or serializes every
71
71
  matching model merely because a request Coordinator has queued a write.
72
72
 
73
+ ## Committed-row evidence
74
+
75
+ `get_committed()` and `get_committed_or_none()` execute the current query through
76
+ the normal executor and current transaction/RLS identity, then hydrate returned
77
+ columns through the canonical model path. They never consult or update
78
+ `StateManager`, and never merge the Session stack. They retain the builder's
79
+ filters, projection, ordering, and ordinary zero/one/many semantics. Use them
80
+ only where database evidence is required, such as stale CAS diagnostics and
81
+ resource authorization; ordinary `get()` remains read-your-own-writes.
82
+
73
83
  ## A rebuilt statement binds only the params it references
74
84
 
75
85
  `count()`, `update()` and `delete()` rebuild SQL from the WHERE tail that
@@ -909,6 +909,28 @@ class QueryBuilder(Generic[ModelT]):
909
909
  except DoesNotExist:
910
910
  return None
911
911
 
912
+ async def get_committed(self) -> ModelT:
913
+ """Retrieve exactly one database row, ignoring Session and identity-cache state."""
914
+ filters = self._merge_filters_excludes()
915
+ try:
916
+ executor = await self._get_executor_async()
917
+ results = await executor.all()
918
+ if not results:
919
+ raise DoesNotExist(model=self.model, filters=filters)
920
+ if len(results) > 1:
921
+ raise MultipleObjectsReturned(model=self.model, count=len(results), filters=filters)
922
+ return results[0]
923
+ except ORMException as e:
924
+ e.enrich(model=self.model, operation="get_committed", filters=filters)
925
+ raise
926
+
927
+ async def get_committed_or_none(self) -> ModelT | None:
928
+ """Return a committed database row or ``None`` without Session merging."""
929
+ try:
930
+ return await self.get_committed()
931
+ except DoesNotExist:
932
+ return None
933
+
912
934
  async def update(self, **kwargs: Any) -> UpdateResult:
913
935
  """Update matching records.
914
936
 
@@ -154,6 +154,21 @@ Complex predicates (operator suffixes, JSON paths, joins) only match
154
154
  DB rows — the pending state is assumed safe (the DB still applies the
155
155
  predicate on its side).
156
156
 
157
+ ## Guarded committed operations beside a Session
158
+
159
+ `assert_no_pending_row(model, primary_key)` is the narrow door used by
160
+ synchronous guarded writes and committed-resource authorization. It refuses
161
+ only an exact schema/table and complete ordered primary-key collision; it
162
+ never flushes, drops, reorders, or otherwise changes a Session. The comparison
163
+ uses canonical database aliases and checks both places a queued operation can
164
+ land: the current transaction's database when one is active, and the owning
165
+ Session's explicit database (or normal transaction default) when it later
166
+ flushes standalone. A raw active connection without the ORM's canonical
167
+ database identity refuses action rather than guessing. A malformed queued
168
+ identity refuses only after its database destination matches; other databases,
169
+ rows and tables remain valid. This is not a blanket Session exclusion or a
170
+ SessionOp CAS.
171
+
157
172
  ## 🚨 Flush stubs are PARTIAL — they never enter the identity cache
158
173
 
159
174
  `flush._execute_group` turns each queued UPDATE into a lightweight
@@ -53,10 +53,14 @@ from matrx_orm.session.errors import (
53
53
  CoordinatorWriteViolation,
54
54
  FlushError,
55
55
  ManagedWriteViolation,
56
+ PendingRowOperationError,
56
57
  SessionClosedError,
57
58
  SessionError,
58
59
  )
59
60
  from matrx_orm.session.fallback import (
61
+ ImmutableWriteConflictError,
62
+ immutable_insert_or_exact_verify,
63
+ immutable_row_differences,
60
64
  WritePreservedError,
61
65
  create_or_capture,
62
66
  drain_spilled_ops,
@@ -92,6 +96,7 @@ from matrx_orm.session.reads import (
92
96
  merge_pending_with_db_one,
93
97
  )
94
98
  from matrx_orm.session.session import (
99
+ assert_no_pending_row,
95
100
  FlushReport,
96
101
  Session,
97
102
  SessionPhase,
@@ -108,6 +113,7 @@ __all__ = [
108
113
  "FlushError",
109
114
  "FlushReport",
110
115
  "ManagedWriteViolation",
116
+ "PendingRowOperationError",
111
117
  "OpType",
112
118
  "SWEEP_INTERVAL_SECS_DEFAULT",
113
119
  "SWEEP_LIMIT_DEFAULT",
@@ -121,6 +127,7 @@ __all__ = [
121
127
  "coalesce_ops",
122
128
  "config_from_meta",
123
129
  "current_session",
130
+ "assert_no_pending_row",
124
131
  "COORDINATOR_BYPASS_ACKNOWLEDGEMENT",
125
132
  "allow_direct_coordinator_write",
126
133
  "coordinator_policy_tables",
@@ -139,6 +146,9 @@ __all__ = [
139
146
  "drain_spilled_ops",
140
147
  "create_or_capture",
141
148
  "WritePreservedError",
149
+ "ImmutableWriteConflictError",
150
+ "immutable_insert_or_exact_verify",
151
+ "immutable_row_differences",
142
152
  "merge_pending_with_db_one",
143
153
  "run_sweeper",
144
154
  "session_stack",
@@ -11,6 +11,17 @@ class SessionError(Exception):
11
11
  """Base class for all Session exceptions."""
12
12
 
13
13
 
14
+ class PendingRowOperationError(SessionError):
15
+ """An authoritative operation targets a row with queued Session work."""
16
+
17
+ def __init__(self, table: str) -> None:
18
+ super().__init__(
19
+ f"{table} has a pending Session operation for this exact row. "
20
+ "Finish the current operation before authorizing or mutating this resource."
21
+ )
22
+ self.table = table
23
+
24
+
14
25
  class LifecycleWatchdogAlarm(SessionError):
15
26
  """A watched lifecycle crossed its SLA and requires operator attention."""
16
27
 
@@ -17,6 +17,7 @@ from __future__ import annotations
17
17
  import json
18
18
  import logging
19
19
  import os
20
+ import re
20
21
  import tempfile
21
22
  import traceback as _tb
22
23
  import uuid as _uuid
@@ -116,6 +117,7 @@ DISK_SPILL_RECOVERED_MARKER = "DiskSpillRecovered"
116
117
  # matrx-ai's replay loop adds this to its RECOVERABLE_RETRY_ERRORS set — keep
117
118
  # the string in lockstep.
118
119
  DIRECT_WRITE_PRESERVED_MARKER = "DirectWritePreserved"
120
+ IMMUTABLE_WRITE_PRESERVED_MARKER = "ImmutableWritePreserved"
119
121
  # Resolved-writable spill dir, cached after first success so we don't re-probe
120
122
  # the cascade on every failure. None until first resolution.
121
123
  _spill_dir_cache: Path | None = None
@@ -535,10 +537,13 @@ async def record_failures(
535
537
  spilled=spilled,
536
538
  total=len(failed_rows),
537
539
  )
538
- # A spilled op is still preserved (drain_spilled_ops re-lands it), so it
539
- # counts as captured. Only ops that reached neither the table nor the disk
540
- # are lost, and those already screamed above.
541
- return [op.op_id for op in ops]
540
+ # A spill is durable only when every failed row reached disk. Never return
541
+ # a handle for the DB+disk-loss case: callers use the receipt to tell a
542
+ # human whether the final utterance is actually recoverable.
543
+ if spilled == len(failed_rows):
544
+ return [op.op_id for op in ops]
545
+ failed_ids = {str(row["op_id"]) for row in failed_rows}
546
+ return [op.op_id for op in ops if op.op_id not in failed_ids]
542
547
 
543
548
 
544
549
  async def _bulk_insert_failures(
@@ -901,6 +906,67 @@ def _scream_to_stdout(
901
906
  # ── Keep-the-work tier: DIRECT writes that must never lose their payload ─────
902
907
 
903
908
 
909
+ class ImmutableWriteConflictError(RuntimeError):
910
+ """An immutable row id exists, but its stored value differs from the intent."""
911
+
912
+
913
+ def _canonical_immutable_value(value: Any, *, parse_iso_timestamp: bool = False) -> Any:
914
+ """Normalize JSON and timestamps before comparing immutable write intent."""
915
+ if isinstance(value, datetime):
916
+ if value.tzinfo is None:
917
+ value = value.replace(tzinfo=UTC)
918
+ return value.astimezone(UTC).isoformat().replace("+00:00", "Z")
919
+ if isinstance(value, _uuid.UUID):
920
+ return str(value)
921
+ if parse_iso_timestamp and isinstance(value, str) and re.fullmatch(
922
+ r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})", value
923
+ ):
924
+ try:
925
+ parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
926
+ except ValueError:
927
+ pass
928
+ else:
929
+ return _canonical_immutable_value(parsed)
930
+ if hasattr(value, "model_dump"):
931
+ value = value.model_dump()
932
+ if isinstance(value, dict):
933
+ return {str(key): _canonical_immutable_value(item) for key, item in value.items()}
934
+ if isinstance(value, (list, tuple)):
935
+ return [_canonical_immutable_value(item) for item in value]
936
+ return value
937
+
938
+
939
+ def _row_value(row: Any, field: str) -> Any:
940
+ if isinstance(row, dict):
941
+ return row.get(field)
942
+ return getattr(row, field, None)
943
+
944
+
945
+ async def _load_immutable_row(model_cls: type, pk_field: str, pk_value: Any) -> Any | None:
946
+ rows = await model_cls.filter(**{pk_field: pk_value}).limit(1).all()
947
+ return rows[0] if rows else None
948
+
949
+
950
+ def _immutable_differences(row: Any, payload: dict[str, Any]) -> dict[str, dict[str, Any]]:
951
+ differences: dict[str, dict[str, Any]] = {}
952
+ for field, expected in payload.items():
953
+ actual = _row_value(row, field)
954
+ # ISO parsing is field-aware: transcript content may legitimately be a
955
+ # date-looking literal, while *_at columns are actual instants.
956
+ parse_iso_timestamp = field.endswith("_at") or field.endswith("_timestamp")
957
+ if _canonical_immutable_value(actual, parse_iso_timestamp=parse_iso_timestamp) != _canonical_immutable_value(expected, parse_iso_timestamp=parse_iso_timestamp):
958
+ differences[field] = {
959
+ "expected": _canonical_immutable_value(expected, parse_iso_timestamp=parse_iso_timestamp),
960
+ "actual": _canonical_immutable_value(actual, parse_iso_timestamp=parse_iso_timestamp),
961
+ }
962
+ return differences
963
+
964
+
965
+ def immutable_row_differences(row: Any, payload: dict[str, Any]) -> dict[str, dict[str, Any]]:
966
+ """Public exact-comparison contract for immutable insert/replay consumers."""
967
+ return _immutable_differences(row, payload)
968
+
969
+
904
970
  class WritePreservedError(RuntimeError):
905
971
  """A direct write failed, but its payload was PRESERVED for replay.
906
972
 
@@ -1004,11 +1070,9 @@ async def create_or_capture(
1004
1070
  row[pk_field] = str(_uuid.uuid4())
1005
1071
  pk_value = row[pk_field]
1006
1072
  table = f"{getattr(model_cls._meta, 'schema', 'public')}.{model_cls._meta.table_name}"
1007
-
1008
1073
  try:
1009
1074
  return await model_cls.create_item(**row)
1010
1075
  except Exception as exc:
1011
- # (3) The attempt failing is NOT proof the row is missing.
1012
1076
  try:
1013
1077
  landed = await model_cls.filter(**{pk_field: pk_value}).limit(1).all()
1014
1078
  except Exception:
@@ -1018,11 +1082,79 @@ async def create_or_capture(
1018
1082
  f"[matrx_orm.create_or_capture] {table} {pk_value} raised "
1019
1083
  f"{type(exc).__name__} but the row IS committed — the write "
1020
1084
  f"succeeded and the error was the acknowledgement, not the write. "
1021
- f"Investigate: this means a client gave up on a landed write.",
1085
+ "Investigate: this means a client gave up on a landed write.",
1022
1086
  color="yellow",
1023
1087
  )
1024
1088
  logger.warning("create_or_capture_landed_despite_error", exc_info=exc)
1025
1089
  return landed[0]
1090
+ op = make_insert(model_cls, row, pk_value=pk_value)
1091
+ op_ids = await record_failures(
1092
+ [op], exc, request_id=request_id, user_id=user_id,
1093
+ conversation_id=conversation_id,
1094
+ organization_id=organization_id or payload.get("organization_id"), database=database,
1095
+ error_prefix=DIRECT_WRITE_PRESERVED_MARKER,
1096
+ )
1097
+ op_id = op_ids[0] if op_ids else None
1098
+ vcprint(
1099
+ f"[matrx_orm.create_or_capture] {table} {pk_value} FAILED "
1100
+ f"({type(exc).__name__}) — payload preserved as system_write_failure "
1101
+ f"op {op_id}; the auto-replay loop will re-apply it.",
1102
+ color="yellow",
1103
+ )
1104
+ raise WritePreservedError(
1105
+ f"{table} write failed ({type(exc).__name__}: {exc}); the payload was preserved for automatic replay",
1106
+ table=table, pk_value=pk_value, op_id=op_id, captured=op_id is not None, cause=exc,
1107
+ ) from exc
1108
+
1109
+
1110
+ async def immutable_insert_or_exact_verify(
1111
+ model_cls: type,
1112
+ payload: dict[str, Any],
1113
+ *,
1114
+ pk_field: str = "id",
1115
+ request_id: str | None = None,
1116
+ user_id: str | None = None,
1117
+ conversation_id: str | None = None,
1118
+ organization_id: str | None = None,
1119
+ database: str | None = None,
1120
+ ) -> Any:
1121
+ """Insert an immutable row, or verify the complete intended row exactly.
1122
+
1123
+ A failed acknowledgement is ambiguous: a fresh read either proves the exact
1124
+ row landed, proves a conflict, or preserves the complete insert for replay.
1125
+ """
1126
+ from matrx_orm.session.op import make_insert
1127
+
1128
+ row = dict(payload)
1129
+ if not row.get(pk_field):
1130
+ row[pk_field] = str(_uuid.uuid4())
1131
+ pk_value = row[pk_field]
1132
+ table = f"{getattr(model_cls._meta, 'schema', 'public')}.{model_cls._meta.table_name}"
1133
+
1134
+ try:
1135
+ # Deliberately no Session: this primitive owns one direct write boundary.
1136
+ return await model_cls.create_item(**row)
1137
+ except Exception as exc:
1138
+ # (3) The attempt failing is NOT proof the row is missing.
1139
+ try:
1140
+ landed = await _load_immutable_row(model_cls, pk_field, pk_value)
1141
+ except Exception:
1142
+ landed = None
1143
+ if landed:
1144
+ differences = _immutable_differences(landed, row)
1145
+ if differences:
1146
+ raise ImmutableWriteConflictError(
1147
+ f"immutable write conflict for {table} {pk_value}: {sorted(differences)}"
1148
+ ) from exc
1149
+ vcprint(
1150
+ f"[matrx_orm.create_or_capture] {table} {pk_value} raised "
1151
+ f"{type(exc).__name__} but the row IS committed — the write "
1152
+ f"succeeded and the error was the acknowledgement, not the write. "
1153
+ f"Investigate: this means a client gave up on a landed write.",
1154
+ color="yellow",
1155
+ )
1156
+ logger.warning("create_or_capture_landed_despite_error", exc_info=exc)
1157
+ return landed
1026
1158
 
1027
1159
  # (4) Preserve the payload where the replay loop will find it.
1028
1160
  op = make_insert(model_cls, row, pk_value=pk_value)
@@ -1034,7 +1166,7 @@ async def create_or_capture(
1034
1166
  conversation_id=conversation_id,
1035
1167
  organization_id=organization_id or payload.get("organization_id"),
1036
1168
  database=database,
1037
- error_prefix=DIRECT_WRITE_PRESERVED_MARKER,
1169
+ error_prefix=IMMUTABLE_WRITE_PRESERVED_MARKER,
1038
1170
  )
1039
1171
  op_id = op_ids[0] if op_ids else None
1040
1172
  vcprint(