matrx-orm 3.1.176__tar.gz → 3.1.178__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 (405) hide show
  1. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/PKG-INFO +2 -2
  2. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/__init__.py +9 -1
  3. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/catalog_sql.py +40 -0
  4. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/introspection.py +76 -2
  5. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/fallback.py +39 -1
  6. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/pyproject.toml +2 -2
  7. matrx_orm-3.1.178/tests/session/test_a_failed_capture_still_names_the_failure.py +144 -0
  8. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_record_error_bounded_insert.py +14 -2
  9. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/.gitignore +0 -0
  10. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/AGENTS.md +0 -0
  11. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/BASE_CLASS_METHODS.md +0 -0
  12. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/CLAUDE.md +0 -0
  13. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/MODEL_API.md +0 -0
  14. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/README.md +0 -0
  15. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/database/orm/extended/managers/ai_model_base.py +0 -0
  16. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/docs/migrations.md +0 -0
  17. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/FEATURE.md +0 -0
  18. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/MODULE_README.md +0 -0
  19. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/adapters/MODULE_README.md +0 -0
  20. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/adapters/__init__.py +0 -0
  21. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/adapters/async_postgresql.py +0 -0
  22. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/adapters/base_adapter.py +0 -0
  23. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  24. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/adapters/supabase_adapter.py +0 -0
  25. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/admin/FEATURE.md +0 -0
  26. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/admin/__init__.py +0 -0
  27. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/admin/router.py +0 -0
  28. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/api/__init__.py +0 -0
  29. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/api/auth.py +0 -0
  30. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/api/config.py +0 -0
  31. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/api/handlers.py +0 -0
  32. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/api/protocol.py +0 -0
  33. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/api/server.py +0 -0
  34. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/associations.py +0 -0
  35. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/cache_debug.py +0 -0
  36. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/catalog.py +0 -0
  37. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/MODULE_README.md +0 -0
  38. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/__init__.py +0 -0
  39. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/postgres_connection.py +0 -0
  40. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/postgrest.py +0 -0
  41. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/supabase_auth.py +0 -0
  42. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/supabase_config.py +0 -0
  43. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/client/supabase_manager.py +0 -0
  44. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  45. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/FEATURE.md +0 -0
  46. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/MODULE_README.md +0 -0
  47. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  48. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/TASKS.md +0 -0
  49. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/__init__.py +0 -0
  50. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/async_db_manager.py +0 -0
  51. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/base.py +0 -0
  52. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/config.py +0 -0
  53. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/connections.py +0 -0
  54. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/db_function.py +0 -0
  55. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/diagnostics.py +0 -0
  56. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/expressions.py +0 -0
  57. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/extended.py +0 -0
  58. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/fields.py +0 -0
  59. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/listen.py +0 -0
  60. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/loop_filters.py +0 -0
  61. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/model_dto.py +0 -0
  62. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/model_view.py +0 -0
  63. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/one_database.py +0 -0
  64. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/paginator.py +0 -0
  65. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/pool_maintenance.py +0 -0
  66. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/pool_watch.py +0 -0
  67. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/pooler_role.py +0 -0
  68. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/pydantic_bridge.py +0 -0
  69. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/registry.py +0 -0
  70. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/relations.py +0 -0
  71. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/resilience.py +0 -0
  72. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/rls_session.py +0 -0
  73. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/session_context.py +0 -0
  74. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/signals.py +0 -0
  75. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/tls.py +0 -0
  76. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/transaction.py +0 -0
  77. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/types.py +0 -0
  78. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/write_queue.py +0 -0
  79. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/core/write_retry.py +0 -0
  80. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/entity.py +0 -0
  81. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/error_handling.py +0 -0
  82. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/exceptions.py +0 -0
  83. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/extended/__init__.py +0 -0
  84. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/extended/app_error_handler.py +0 -0
  85. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/identity_rule.py +0 -0
  86. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/local_sqlite.py +0 -0
  87. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/middleware/__init__.py +0 -0
  88. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/middleware/base.py +0 -0
  89. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/MODULE_README.md +0 -0
  90. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/__init__.py +0 -0
  91. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/cli.py +0 -0
  92. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/ddl.py +0 -0
  93. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/diff.py +0 -0
  94. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/executor.py +0 -0
  95. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/integration.py +0 -0
  96. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/loader.py +0 -0
  97. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/operations.py +0 -0
  98. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/state.py +0 -0
  99. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/migrations/table_filter.py +0 -0
  100. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/no_org_assignment.py +0 -0
  101. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/FEATURE.md +0 -0
  102. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/MODULE_README.md +0 -0
  103. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/__init__.py +0 -0
  104. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/bulk_update_values.py +0 -0
  105. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/catalog_select.py +0 -0
  106. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/conflict.py +0 -0
  107. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/conflict_writes.py +0 -0
  108. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/create.py +0 -0
  109. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/db_functions.py +0 -0
  110. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/delete.py +0 -0
  111. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/dynamic_admin.py +0 -0
  112. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/dynamic_crud.py +0 -0
  113. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/graph_walk.py +0 -0
  114. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/latest_rows.py +0 -0
  115. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/queue_claim.py +0 -0
  116. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/read.py +0 -0
  117. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/relational_backfill.py +0 -0
  118. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/staging_load.py +0 -0
  119. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/operations/update.py +0 -0
  120. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/platform_access.py +0 -0
  121. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/platform_db.py +0 -0
  122. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/py.typed +0 -0
  123. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/pytest_lock_guard.py +0 -0
  124. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/pytest_plugin.py +0 -0
  125. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/python_sql/MODULE_README.md +0 -0
  126. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/python_sql/__init__.py +0 -0
  127. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/python_sql/db_objects.py +0 -0
  128. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  129. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  130. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/query/FEATURE.md +0 -0
  131. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/query/MODULE_README.md +0 -0
  132. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/query/__init__.py +0 -0
  133. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/query/builder.py +0 -0
  134. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/query/executor.py +0 -0
  135. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/resources/__init__.py +0 -0
  136. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  137. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  138. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/FEATURE.md +0 -0
  139. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  140. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/__init__.py +0 -0
  141. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/code_handler.py +0 -0
  142. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  143. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/columns.py +0 -0
  144. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/common.py +0 -0
  145. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/diff_preview.py +0 -0
  146. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  147. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/generator.py +0 -0
  148. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  149. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  150. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  151. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  152. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/package_wiring.py +0 -0
  153. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/relationships.py +0 -0
  154. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/runner.py +0 -0
  155. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/schema.py +0 -0
  156. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/schema_manager.py +0 -0
  157. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/tables.py +0 -0
  158. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/schema_builder/views.py +0 -0
  159. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  160. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/__init__.py +0 -0
  161. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/attachments.py +0 -0
  162. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/backup_restore.py +0 -0
  163. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/crypto.py +0 -0
  164. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  165. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/items.py +0 -0
  166. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/model.py +0 -0
  167. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  168. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/native_enable.py +0 -0
  169. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  170. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  171. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/native_source.py +0 -0
  172. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/org_service.py +0 -0
  173. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/secrets_battery/service.py +0 -0
  174. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/README.md +0 -0
  175. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/__init__.py +0 -0
  176. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/coalesce.py +0 -0
  177. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/dag.py +0 -0
  178. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/errors.py +0 -0
  179. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/flush.py +0 -0
  180. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/lifecycle.py +0 -0
  181. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/managed.py +0 -0
  182. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/op.py +0 -0
  183. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/reads.py +0 -0
  184. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/session.py +0 -0
  185. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/session/telemetry.py +0 -0
  186. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  187. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/__init__.py +0 -0
  188. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/executor.py +0 -0
  189. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/queries.py +0 -0
  190. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/registry.py +0 -0
  191. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/types.py +0 -0
  192. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/sql_executor/utils.py +0 -0
  193. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/state.py +0 -0
  194. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/utils/__init__.py +0 -0
  195. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/utils/sql_utils.py +0 -0
  196. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/utils/type_converters.py +0 -0
  197. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/matrx_orm/write_actor.py +0 -0
  198. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/scripts/git-branches.sh +0 -0
  199. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/scripts/publish.sh +0 -0
  200. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/scripts/release.sh +0 -0
  201. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/MODULE_README.md +0 -0
  202. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/__init__.py +0 -0
  203. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/conftest.py +0 -0
  204. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/MODULE_README.md +0 -0
  205. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/__init__.py +0 -0
  206. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_adapter_registry.py +0 -0
  207. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_admin_db_columns.py +0 -0
  208. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_admin_response_rendering.py +0 -0
  209. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_admin_search_negation.py +0 -0
  210. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_admin_search_sentinels.py +0 -0
  211. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_advisory_lock.py +0 -0
  212. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_agent_message.py +0 -0
  213. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_api_auth.py +0 -0
  214. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_api_config.py +0 -0
  215. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_api_handlers.py +0 -0
  216. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_api_protocol.py +0 -0
  217. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_array_agg_order_by.py +0 -0
  218. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_association_trigger_actor_naming.py +0 -0
  219. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_associations.py +0 -0
  220. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_associations_wiring.py +0 -0
  221. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_bulk_hydration_offload.py +0 -0
  222. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_bulk_update_by_pk.py +0 -0
  223. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  224. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_cache_debug.py +0 -0
  225. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_call_function.py +0 -0
  226. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_case_when.py +0 -0
  227. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_catalog.py +0 -0
  228. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_committed_row_guard.py +0 -0
  229. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_composite_pk_filter.py +0 -0
  230. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_composite_pk_write_paths.py +0 -0
  231. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_config.py +0 -0
  232. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_conflict_target.py +0 -0
  233. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_conflict_writes.py +0 -0
  234. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_connection_codecs.py +0 -0
  235. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_connection_poison_guard.py +0 -0
  236. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_connection_primitives.py +0 -0
  237. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_count_composite_distinct.py +0 -0
  238. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_count_limit_param_leak.py +0 -0
  239. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_db_function_field.py +0 -0
  240. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_ddl_generator.py +0 -0
  241. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_deadlock_retry.py +0 -0
  242. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_derived_table.py +0 -0
  243. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_dirty_tracking.py +0 -0
  244. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_dynamic_crud.py +0 -0
  245. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_exceptions.py +0 -0
  246. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  247. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_expression_primitives.py +0 -0
  248. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_fields.py +0 -0
  249. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  250. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_from_alias.py +0 -0
  251. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_fts.py +0 -0
  252. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_func_expression_args.py +0 -0
  253. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_graph_walk.py +0 -0
  254. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_having_annotate_alias.py +0 -0
  255. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  256. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_introspect_rls_policies.py +0 -0
  257. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_join_and_aggregate.py +0 -0
  258. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_latest_rows.py +0 -0
  259. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_listen_notify.py +0 -0
  260. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_local_sqlite.py +0 -0
  261. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_lock_contention_retry.py +0 -0
  262. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_managed_write_guard.py +0 -0
  263. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_matrx_entity.py +0 -0
  264. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_migration_diff_types.py +0 -0
  265. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_migration_loader.py +0 -0
  266. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_model_instance.py +0 -0
  267. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_model_meta.py +0 -0
  268. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_optimistic_concurrency.py +0 -0
  269. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_order_by_expression.py +0 -0
  270. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_org_assignment_inventory.py +0 -0
  271. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  272. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_parameter_name_hydration.py +0 -0
  273. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_patch_jsonb_path.py +0 -0
  274. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_percentile_cont.py +0 -0
  275. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_persisted_count.py +0 -0
  276. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_pool_holder_census.py +0 -0
  277. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_pool_loop_recreation.py +0 -0
  278. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_pool_maintenance.py +0 -0
  279. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_postgrest_filters.py +0 -0
  280. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_pydantic_bridge.py +0 -0
  281. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_query_builder.py +0 -0
  282. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_query_error_detail.py +0 -0
  283. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_query_executor_sql.py +0 -0
  284. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_query_timeout.py +0 -0
  285. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  286. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_queue_claim.py +0 -0
  287. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_read_connection_retry.py +0 -0
  288. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_registry.py +0 -0
  289. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_registry_multi_database.py +0 -0
  290. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_registry_multi_schema.py +0 -0
  291. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_relational_backfill.py +0 -0
  292. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_relations.py +0 -0
  293. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_resilience.py +0 -0
  294. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_rls_session_scope.py +0 -0
  295. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_schema_exists.py +0 -0
  296. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_session_advisory_lock.py +0 -0
  297. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_standalone_write_session_context.py +0 -0
  298. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_state_cache.py +0 -0
  299. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_subquery_filter_raw.py +0 -0
  300. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_subquery_in_filter.py +0 -0
  301. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_subquery_nested_expressions.py +0 -0
  302. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_supabase_auth.py +0 -0
  303. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_supabase_config.py +0 -0
  304. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_tls.py +0 -0
  305. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_transaction_database_identity.py +0 -0
  306. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_typed_join_projection.py +0 -0
  307. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_typed_predicates.py +0 -0
  308. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_update_case_expression.py +0 -0
  309. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_update_subquery.py +0 -0
  310. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_update_with_rebase.py +0 -0
  311. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_upsert_default_leak.py +0 -0
  312. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_upsert_with_conflict.py +0 -0
  313. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_values_jsonb_decode.py +0 -0
  314. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_watched_lifecycle.py +0 -0
  315. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_write_queue_deadline.py +0 -0
  316. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level1/test_write_retry_semantics.py +0 -0
  317. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/MODULE_README.md +0 -0
  318. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/__init__.py +0 -0
  319. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/conftest.py +0 -0
  320. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_bulk_ops.py +0 -0
  321. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_cache_integration.py +0 -0
  322. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_crud.py +0 -0
  323. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_foreign_keys.py +0 -0
  324. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_m2m.py +0 -0
  325. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_manager.py +0 -0
  326. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_migrations_live.py +0 -0
  327. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_query_execution.py +0 -0
  328. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/test_schema_diff.py +0 -0
  329. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
  330. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/live_pooler_role.py +0 -0
  331. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/native_source_cases.py +0 -0
  332. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/native_source_oracle.rs +0 -0
  333. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/.env.example +0 -0
  334. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/README.md +0 -0
  335. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/__init__.py +0 -0
  336. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/generate.py +0 -0
  337. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/generated/.gitkeep +0 -0
  338. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/matrx_orm.yaml +0 -0
  339. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project/test_schema_generation.py +0 -0
  340. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/.env.example +0 -0
  341. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/README.md +0 -0
  342. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/__init__.py +0 -0
  343. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/client_example.py +0 -0
  344. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/client_example.ts +0 -0
  345. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  346. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/sample_project_desktop/server.py +0 -0
  347. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/entity_tests.py +0 -0
  348. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_base_generation.py +0 -0
  349. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  350. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_composite_unique_generation.py +0 -0
  351. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_dto_identity_generation.py +0 -0
  352. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_entity_capability_generation.py +0 -0
  353. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_enum_ordering.py +0 -0
  354. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_generate_schema.py +0 -0
  355. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_junction_analysis.py +0 -0
  356. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_multi_schema_output.py +0 -0
  357. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_schema_analysis.py +0 -0
  358. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_sql_expression_defaults.py +0 -0
  359. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_table_relationships_query.py +0 -0
  360. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema/test_view_generation.py +0 -0
  361. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema_builder/test_array_default_parsing.py +0 -0
  362. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  363. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  364. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/__init__.py +0 -0
  365. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/conftest.py +0 -0
  366. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_cache_no_downgrade.py +0 -0
  367. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_capture_poison_proof.py +0 -0
  368. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_coalesce.py +0 -0
  369. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_dag.py +0 -0
  370. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_disk_spill_fallback.py +0 -0
  371. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_flush_individual_fallback.py +0 -0
  372. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_governed_write.py +0 -0
  373. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_managed.py +0 -0
  374. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_op_enqueue_site.py +0 -0
  375. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_reads.py +0 -0
  376. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_record_error_storm.py +0 -0
  377. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_session.py +0 -0
  378. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/session/test_spill_guard_plugin.py +0 -0
  379. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_array_arg_element_type.py +0 -0
  380. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_attachment_mutation_serialization.py +0 -0
  381. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_backup_alias_conflict.py +0 -0
  382. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_backup_restore_live.py +0 -0
  383. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_database_name_alias.py +0 -0
  384. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_db_functions.py +0 -0
  385. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_dynamic_select_unregistered.py +0 -0
  386. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  387. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_keyed_digest.py +0 -0
  388. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_model_cls_refactor.py +0 -0
  389. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_native_enable.py +0 -0
  390. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_native_lifecycle.py +0 -0
  391. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_native_lifecycle_fences.py +0 -0
  392. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_native_passkey_receipts.py +0 -0
  393. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_native_source.py +0 -0
  394. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  395. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_one_database.py +0 -0
  396. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_order_by_desc_nulls_last.py +0 -0
  397. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_pooler_role_guard.py +0 -0
  398. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_secret_audit_names_its_organization.py +0 -0
  399. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_secrets_battery.py +0 -0
  400. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_secrets_minting_keys.py +0 -0
  401. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_shared_lock_guard.py +0 -0
  402. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_sql_param_casts.py +0 -0
  403. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_sync_twins_guard.py +0 -0
  404. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/tests/test_user_visible_lookup.py +0 -0
  405. {matrx_orm-3.1.176 → matrx_orm-3.1.178}/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.176
3
+ Version: 3.1.178
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.51
29
+ Requires-Dist: matrx-utils>=2.0.53
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
@@ -72,7 +72,13 @@ from .core.diagnostics import (
72
72
  long_transactions,
73
73
  long_transactions_sql,
74
74
  )
75
- from .core.introspection import introspect_columns, introspect_rls_policies, schema_exists
75
+ from .core.introspection import (
76
+ introspect_column_shapes,
77
+ introspect_columns,
78
+ introspect_function_privileges,
79
+ introspect_rls_policies,
80
+ schema_exists,
81
+ )
76
82
  from .core.one_database import OneDatabaseReport, PoolIdentity, audit_one_database
77
83
  from .core.listen import notify, ping
78
84
  from .core.tls import resolve_asyncpg_ssl, resolve_asyncpg_ssl_from_dsn
@@ -472,7 +478,9 @@ __all__ = [
472
478
  "audit_one_database",
473
479
  "OneDatabaseReport",
474
480
  "PoolIdentity",
481
+ "introspect_column_shapes",
475
482
  "introspect_columns",
483
+ "introspect_function_privileges",
476
484
  "introspect_lock_waits",
477
485
  "introspect_rls_policies",
478
486
  "schema_exists",
@@ -113,3 +113,43 @@ SELECT c.relname AS table_name, a.attname AS column_name
113
113
  AND NOT a.attisdropped
114
114
  AND c.relkind = ANY ('{r,p,v,m,f}')
115
115
  """
116
+
117
+ # The same catalog read, plus the two facts a drift guard actually argues about:
118
+ # whether a column may be empty, and what Postgres puts there when a writer says
119
+ # nothing. A NOT NULL column with a DEFAULT manufactures a value that reads,
120
+ # downstream, exactly like something a person chose — so "is there a default"
121
+ # is a question the ORM must be able to answer without a host hand-rolling SQL.
122
+ COLUMN_SHAPES_FOR_TABLE_SQL = """
123
+ SELECT a.attname AS column_name,
124
+ NOT a.attnotnull AS is_nullable,
125
+ pg_get_expr(d.adbin, d.adrelid) AS column_default
126
+ FROM pg_attribute a
127
+ JOIN pg_class c ON c.oid = a.attrelid
128
+ JOIN pg_namespace n ON n.oid = c.relnamespace
129
+ LEFT JOIN pg_attrdef d ON d.adrelid = a.attrelid AND d.adnum = a.attnum
130
+ WHERE n.nspname = $1
131
+ AND c.relname = $2
132
+ AND a.attnum > 0
133
+ AND NOT a.attisdropped
134
+ AND c.relkind = ANY ('{r,p,v,m,f}')
135
+ """
136
+
137
+
138
+ # "Who may CALL this function?" is the other half of the definer question. A
139
+ # SECURITY DEFINER function runs as the owner with BYPASSRLS, so the set of
140
+ # roles holding EXECUTE on it IS its access control — and a grant that quietly
141
+ # includes `anon` or `authenticated` hands a browser the owner's privileges.
142
+ # Like COLUMN_SHAPES_FOR_TABLE_SQL, this is a catalog question with no Model to
143
+ # bind it to, so the ORM answers it rather than every guard hand-rolling SQL.
144
+ FUNCTION_PRIVILEGES_SQL = """
145
+ SELECT p.oid::regprocedure::text AS signature,
146
+ p.prosecdef AS is_security_definer,
147
+ role_name AS role,
148
+ has_function_privilege(role_name, p.oid, 'EXECUTE') AS can_execute
149
+ FROM pg_proc p
150
+ JOIN pg_namespace n ON n.oid = p.pronamespace
151
+ CROSS JOIN unnest($3::text[]) AS role_name
152
+ WHERE n.nspname = $1
153
+ AND p.proname = $2
154
+ AND EXISTS (SELECT 1 FROM pg_roles r WHERE r.rolname = role_name)
155
+ """
@@ -17,11 +17,21 @@ from __future__ import annotations
17
17
 
18
18
  from typing import Any
19
19
 
20
- from matrx_orm.catalog_sql import COLUMNS_FOR_TABLES_SQL, SCHEMA_EXISTS_SQL
20
+ from matrx_orm.catalog_sql import (
21
+ COLUMN_SHAPES_FOR_TABLE_SQL,
22
+ COLUMNS_FOR_TABLES_SQL,
23
+ FUNCTION_PRIVILEGES_SQL,
24
+ SCHEMA_EXISTS_SQL,
25
+ )
21
26
  from matrx_orm.core.async_db_manager import AsyncDatabaseManager
22
27
  from matrx_orm.core.transaction import get_active_connection
23
28
 
24
- __all__ = ["introspect_rls_policies", "introspect_columns", "schema_exists"]
29
+ __all__ = [
30
+ "introspect_function_privileges",
31
+ "introspect_rls_policies",
32
+ "introspect_columns",
33
+ "schema_exists",
34
+ ]
25
35
 
26
36
  _RLS_AUDIT_SQL = """
27
37
  select
@@ -77,6 +87,7 @@ async def introspect_rls_policies(
77
87
  # we assume, present columns read as absent and the drift guard reports the code
78
88
  # as wrong about the schema. See matrx_orm/catalog_sql.py.
79
89
  _COLUMNS_SQL = COLUMNS_FOR_TABLES_SQL
90
+ _COLUMN_SHAPES_SQL = COLUMN_SHAPES_FOR_TABLE_SQL
80
91
 
81
92
 
82
93
  async def introspect_columns(database: str, schema: str, tables: list[str]) -> dict[str, list[str]]:
@@ -120,3 +131,66 @@ async def schema_exists(database: str, schema: str) -> bool:
120
131
 
121
132
  async with AsyncDatabaseManager.get_connection(database) as conn:
122
133
  return bool(await conn.fetchval(sql, schema))
134
+
135
+
136
+ async def introspect_column_shapes(
137
+ database: str, schema: str, table: str
138
+ ) -> dict[str, dict[str, object]]:
139
+ """Live nullability and default per column — ``{column: {...}}``.
140
+
141
+ ``introspect_columns`` answers "does this column exist"; this answers "what
142
+ will Postgres do when a writer says nothing about it". A NOT NULL column
143
+ with a DEFAULT does not leave a hole — it FILLS one, and every reader
144
+ downstream sees a value indistinguishable from a deliberate choice. On
145
+ 2026-09-22 that shape on one column
146
+ (``communication.sms_notification_preferences.timezone``) made an entire
147
+ feature a no-op in production. A guard must be able to see it without
148
+ hand-rolling SQL.
149
+
150
+ Each value is ``{"is_nullable": bool, "column_default": str | None}``.
151
+ ``schema``/``table`` are bound as parameters, never interpolated.
152
+ """
153
+ rows = await AsyncDatabaseManager.execute_query(database, _COLUMN_SHAPES_SQL, schema, table)
154
+ return {
155
+ str(r["column_name"]): {
156
+ "is_nullable": bool(r["is_nullable"]),
157
+ "column_default": (
158
+ str(r["column_default"]) if r["column_default"] is not None else None
159
+ ),
160
+ }
161
+ for r in rows
162
+ }
163
+
164
+
165
+ async def introspect_function_privileges(
166
+ database: str, schema: str, name: str, roles: list[str]
167
+ ) -> list[dict[str, Any]]:
168
+ """Which of ``roles`` can EXECUTE ``schema.name`` — one row per overload/role.
169
+
170
+ ``introspect_column_shapes`` answers "what will Postgres do when a writer
171
+ says nothing"; this answers "who can call this door". A SECURITY DEFINER
172
+ function runs as its owner with BYPASSRLS, so the roles holding EXECUTE on
173
+ it ARE its access control: if ``anon`` or ``authenticated`` is among them,
174
+ a browser holds the owner's privileges. A guard has to be able to see that
175
+ without hand-rolling a catalog query, which is why this lives here.
176
+
177
+ Each row is ``{"signature": str, "is_security_definer": bool, "role": str,
178
+ "can_execute": bool}``. An overload that exists yields one row per role in
179
+ ``roles``; a function that does not exist yields no rows at all, which is
180
+ how a caller tells "missing" from "locked". A name in ``roles`` that is not
181
+ a role on this server is skipped rather than raising — a server without a
182
+ ``supabase_auth_admin`` is a different deployment, not a violation.
183
+ ``schema``, ``name`` and ``roles`` are bound parameters, never interpolated.
184
+ """
185
+ rows = await AsyncDatabaseManager.execute_query(
186
+ database, FUNCTION_PRIVILEGES_SQL, schema, name, list(roles)
187
+ )
188
+ return [
189
+ {
190
+ "signature": str(r["signature"]),
191
+ "is_security_definer": bool(r["is_security_definer"]),
192
+ "role": str(r["role"]),
193
+ "can_execute": bool(r["can_execute"]),
194
+ }
195
+ for r in rows
196
+ ]
@@ -18,6 +18,7 @@ import json
18
18
  import logging
19
19
  import os
20
20
  import re
21
+ import sys
21
22
  import tempfile
22
23
  import traceback as _tb
23
24
  import uuid as _uuid
@@ -778,13 +779,50 @@ async def record_error(
778
779
  color="yellow",
779
780
  )
780
781
  except Exception as capture_exc:
782
+ # 🚨 THE ANNOUNCEMENT MUST SURVIVE THE OUTAGE IT DESCRIBES (2026-09-21).
783
+ #
784
+ # Every field below used to ride ONLY in ``extra``, and the log MESSAGE
785
+ # was the bare token ``matrx_orm_system_error_capture_failed``. ``extra``
786
+ # is read by exactly one consumer — the app_log handler, which inserts
787
+ # into the SAME Postgres this capture just failed against. So the one
788
+ # class of failure that kills the capture (a lock wave, a stalled
789
+ # trigger, a pool starve) killed its own announcement too, and stdout
790
+ # got a token with no route, no request id and no exception.
791
+ #
792
+ # Verified in production: 2026-09-21 18:48–18:51 UTC, a 48 s
793
+ # ``platform.provision_restricted(...)`` held a relation lock; SIX
794
+ # ``POST /browser-manager/profiles`` requests answered 500
795
+ # LockContentionError; exactly ONE reached ``ops.system_error``
796
+ # (request_id 5c4f84d9f19a4503ba127f3d8228d420, 18:50:45). The other
797
+ # five left 27 bare ``matrx_orm_system_error_capture_failed`` tokens in
798
+ # CloudWatch beside ``[app_log] drain insert failed, dropped 200 row(s):
799
+ # <LockContentionError>`` — both durable lanes died together and the
800
+ # surviving line named nothing.
801
+ #
802
+ # So the message itself is now SELF-CONTAINED: whoever reads the plain
803
+ # log stream gets the kind, the route, the request id, the real
804
+ # exception and why the capture failed, with no DB and no structured
805
+ # sink required. ``extra`` is unchanged for the queryable lane.
806
+ summary = (
807
+ "matrx_orm_system_error_capture_failed "
808
+ f"kind={kind} error_type={resolved_error_type} "
809
+ f"route={route or '-'} request_id={request_id or '-'} "
810
+ f"user_id={user_id or '-'} "
811
+ f"capture_failed_with={type(capture_exc).__name__}: "
812
+ f"{_capture_failure_diagnostic(capture_exc)} | "
813
+ f"UNRECORDED FAILURE: {_capture_failure_diagnostic(resolved_error_text)}"
814
+ )
815
+ # stdout FIRST and unconditionally: the logging tree can be
816
+ # misconfigured, filtered, or draining into the dead database, and this
817
+ # is the last place the failure can still be seen.
818
+ print(f"[matrx_orm.session.fallback] {summary}", file=sys.stdout, flush=True)
781
819
  # ``vcprint(..., color="red")`` is itself a logger call. Emitting it
782
820
  # beside this structured event made ONE failed capture appear as TWO
783
821
  # unrelated ERROR families in ``app_log``. Keep one ERROR so the
784
822
  # durable log has an exact, queryable incident without concealing the
785
823
  # original failure or the bounded-capture refusal.
786
824
  logger.error(
787
- "matrx_orm_system_error_capture_failed",
825
+ summary,
788
826
  extra={
789
827
  "matrx_system_error": {
790
828
  "kind": kind,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.176"
3
+ version = "3.1.178"
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.51",
44
+ "matrx-utils>=2.0.53",
45
45
  "pyyaml>=6.0.3",
46
46
  "python-dotenv>=1.0",
47
47
  "cryptography>=43.0",
@@ -0,0 +1,144 @@
1
+ """A capture that cannot reach the database still SAYS what it lost.
2
+
3
+ SUT: the failure branch of :func:`matrx_orm.session.fallback.record_error`.
4
+
5
+ 🚨 THE INCIDENT THIS GUARDS (production, 2026-09-21 18:48–18:51 UTC). A single
6
+ 48-second ``platform.provision_restricted(...)`` held a relation lock. SIX
7
+ ``POST /browser-manager/profiles`` requests answered
8
+ ``500 Internal server error: LockContentionError``. Exactly ONE of them reached
9
+ ``ops.system_error`` (request_id 5c4f84d9f19a4503ba127f3d8228d420, 18:50:45) —
10
+ the one that happened to fall in a gap between lock waves. The other five were
11
+ silent, because:
12
+
13
+ 1. ``record_error``'s INSERT goes to the SAME Postgres that is stalled, so it
14
+ fails exactly when the failure most needs recording; and
15
+ 2. its fallback announcement was ``logger.error("matrx_orm_system_error_...")``
16
+ with EVERY field — route, request id, the real exception — riding in
17
+ ``extra``, which only the app_log handler reads, and that handler inserts
18
+ into the same dead database (``[app_log] drain insert failed, dropped 200
19
+ row(s): <LockContentionError>``).
20
+
21
+ Both durable lanes died together and the only line that survived named nothing.
22
+
23
+ Breaks this test: moving any of kind / route / request id / the original error
24
+ text back out of the log MESSAGE and into ``extra`` alone; dropping the direct
25
+ stdout write; or making the announcement depend on the logging tree being
26
+ alive.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import logging
32
+
33
+ import pytest
34
+ from matrx_orm.session import fallback
35
+
36
+
37
+ class _StalledDatabase(Exception):
38
+ """Stands in for the lock-timeout the capture INSERT hit in production."""
39
+
40
+
41
+ # Two real jobs on the platform, so no single hard-coded announcement can
42
+ # satisfy both (forcing-function-tests §3).
43
+ _INCIDENTS = [
44
+ pytest.param(
45
+ # All Green Recycling: an operator starting a cloud browser to file a
46
+ # pickup manifest with the county portal.
47
+ {
48
+ "kind": "request_crash",
49
+ "route": "POST /browser-manager/profiles",
50
+ "request_id": "5c4f84d9f19a4503ba127f3d8228d420",
51
+ "user_id": "9f1c7b64-2b3a-4d51-8d9c-1e2f3a4b5c6d",
52
+ "error_type": "LockContentionError",
53
+ "error_text": "LockContentionError: canceling statement due to lock timeout",
54
+ "capture_failure": "canceling statement due to lock timeout on ops.system_error",
55
+ },
56
+ id="all_green_recycling_browser_profile",
57
+ ),
58
+ pytest.param(
59
+ # Harbor Dental: a front-desk save on the new-patient intake form.
60
+ {
61
+ "kind": "request_crash",
62
+ "route": "POST /forms/new-patient-intake/submissions",
63
+ "request_id": "a71e0d3c88f2427b93cc10b4d6e5f207",
64
+ "user_id": "3c8d2e17-90ab-4f66-b2e1-77d0c4a95b38",
65
+ "error_type": "DeadlockDetectedError",
66
+ "error_text": "DeadlockDetectedError: deadlock detected on intake_submission",
67
+ "capture_failure": "pool acquire timed out after 2.0s",
68
+ },
69
+ id="harbor_dental_intake_submission",
70
+ ),
71
+ ]
72
+
73
+
74
+ def _fail_the_capture(monkeypatch: pytest.MonkeyPatch, reason: str) -> None:
75
+ async def _boom(**_kwargs):
76
+ raise _StalledDatabase(reason)
77
+
78
+ monkeypatch.setattr(fallback, "_insert_error", _boom)
79
+
80
+
81
+ @pytest.mark.parametrize("incident", _INCIDENTS)
82
+ @pytest.mark.asyncio
83
+ async def test_a_failed_capture_names_route_request_id_and_the_real_exception(
84
+ incident: dict[str, str],
85
+ monkeypatch: pytest.MonkeyPatch,
86
+ capsys: pytest.CaptureFixture[str],
87
+ ) -> None:
88
+ fallback.reset_capture_storm_state()
89
+ _fail_the_capture(monkeypatch, incident["capture_failure"])
90
+
91
+ await fallback.record_error(
92
+ _StalledDatabase(incident["error_text"]),
93
+ kind=incident["kind"],
94
+ error_type=incident["error_type"],
95
+ error_text=incident["error_text"],
96
+ request_id=incident["request_id"],
97
+ user_id=incident["user_id"],
98
+ route=incident["route"],
99
+ )
100
+
101
+ announced = capsys.readouterr().out
102
+ # Everything an operator needs to act, in ONE line, with no database and no
103
+ # structured sink required to read it.
104
+ assert incident["route"] in announced
105
+ assert incident["request_id"] in announced
106
+ assert incident["error_type"] in announced
107
+ assert incident["error_text"] in announced
108
+ assert incident["capture_failure"] in announced
109
+ assert "_StalledDatabase" in announced, "the capture's own failure must be named"
110
+
111
+
112
+ @pytest.mark.parametrize("incident", _INCIDENTS)
113
+ @pytest.mark.asyncio
114
+ async def test_the_announcement_survives_a_dead_logging_tree(
115
+ incident: dict[str, str],
116
+ monkeypatch: pytest.MonkeyPatch,
117
+ capsys: pytest.CaptureFixture[str],
118
+ ) -> None:
119
+ """The one lane that outlives the outage must not go through logging.
120
+
121
+ In the incident the logging tree WAS the dead lane: its only durable
122
+ consumer inserted into the stalled database. An announcement that exists
123
+ only as a ``logger`` call is therefore no announcement at all.
124
+ """
125
+ fallback.reset_capture_storm_state()
126
+ _fail_the_capture(monkeypatch, incident["capture_failure"])
127
+
128
+ logging.disable(logging.CRITICAL)
129
+ try:
130
+ await fallback.record_error(
131
+ _StalledDatabase(incident["error_text"]),
132
+ kind=incident["kind"],
133
+ error_type=incident["error_type"],
134
+ error_text=incident["error_text"],
135
+ request_id=incident["request_id"],
136
+ route=incident["route"],
137
+ )
138
+ finally:
139
+ logging.disable(logging.NOTSET)
140
+
141
+ announced = capsys.readouterr().out
142
+ assert incident["request_id"] in announced
143
+ assert incident["route"] in announced
144
+ assert incident["error_text"] in announced
@@ -93,7 +93,7 @@ async def test_capture_insert_is_bounded_before_it_touches_the_table(monkeypatch
93
93
  def test_error_capture_with_user_but_no_org_stamps_system_org() -> None:
94
94
  # A fresh capture connection has no request actor GUC. The user id alone
95
95
  # cannot trigger a personal-org stamp and used to cause NOT NULL failure.
96
- user_id = "4cf62e4e-2679-484f-b652-034e697418df"
96
+ user_id = "22222222-3333-4444-8555-666666666666"
97
97
  assert fallback._capture_org(None, user_id) == fallback.SYSTEM_ORGANIZATION_ID
98
98
  org_id = "bfe0205b-24c6-4ae9-9262-2fe2169fe10d"
99
99
  assert fallback._capture_org(org_id, user_id) == org_id
@@ -129,13 +129,25 @@ async def test_failed_capture_emits_one_structured_error_not_a_banner_twin(
129
129
  context={"credential": capture_secret},
130
130
  )
131
131
 
132
+ # 2026-09-21: the message is now SELF-CONTAINED (kind / route / request id /
133
+ # the real exception ride IN it, not only in ``extra``) because the app_log
134
+ # handler that reads ``extra`` inserts into the very database a failed
135
+ # capture means is unreachable. The invariant this guard was written for is
136
+ # unchanged and still asserted: ONE ERROR record, never a vcprint banner
137
+ # twin — so it matches the incident PREFIX instead of the whole line.
132
138
  records = [
133
139
  record
134
140
  for record in caplog.records
135
141
  if record.name == "matrx_orm.session.fallback"
136
- and record.getMessage() == "matrx_orm_system_error_capture_failed"
142
+ and record.getMessage().startswith("matrx_orm_system_error_capture_failed")
137
143
  ]
138
144
  assert len(records) == 1
145
+ # The self-contained half: readable with no database and no structured sink.
146
+ message = records[0].getMessage()
147
+ assert "route=/api/cloud-files/changes" in message
148
+ assert "request_id=request-1" in message
149
+ assert "ValueError: shed" in message
150
+ assert capture_secret not in message
139
151
  captured = records[0].matrx_system_error
140
152
  assert captured == {
141
153
  "kind": "cloud_file_change_feed_shed",
File without changes
File without changes
File without changes
File without changes
File without changes