matrx-orm 3.1.203__tar.gz → 3.1.205__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 (436) hide show
  1. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/BASE_CLASS_METHODS.md +1 -1
  2. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/CLAUDE.md +1 -1
  3. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/PKG-INFO +2 -2
  4. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/__init__.py +4 -0
  5. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/db_function.py +26 -0
  6. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/introspection.py +1 -1
  7. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/session_context.py +32 -11
  8. matrx_orm-3.1.205/matrx_orm/matrx_orm_production_door.pth +3 -0
  9. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/db_functions.py +8 -1
  10. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/pytest_production_door.py +108 -33
  11. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/excluded_targets.py +2 -2
  12. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/schema_manager.py +1 -1
  13. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/dag.py +1 -1
  14. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/write_actor.py +4 -4
  15. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/pyproject.toml +5 -2
  16. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_association_trigger_actor_naming.py +7 -6
  17. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_catalog.py +4 -4
  18. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_rls_session_scope.py +1 -1
  19. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_standalone_write_session_context.py +4 -4
  20. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_transaction_database_identity.py +1 -1
  21. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_transaction_gucs_one_round_trip.py +2 -2
  22. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/verify_committed_row_guard_pg17.py +3 -3
  23. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_excluded_fk_targets.py +4 -4
  24. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_dag.py +2 -2
  25. matrx_orm-3.1.205/tests/test_a_list_of_uuids_binds_as_uuid_array.py +42 -0
  26. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/.gitignore +0 -0
  27. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/AGENTS.md +0 -0
  28. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/CHANGELOG.md +0 -0
  29. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/MODEL_API.md +0 -0
  30. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/README.md +0 -0
  31. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/database/orm/extended/managers/ai_model_base.py +0 -0
  32. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/docs/migrations.md +0 -0
  33. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/FEATURE.md +0 -0
  34. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/MODULE_README.md +0 -0
  35. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/adapters/MODULE_README.md +0 -0
  36. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/adapters/__init__.py +0 -0
  37. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/adapters/async_postgresql.py +0 -0
  38. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/adapters/base_adapter.py +0 -0
  39. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  40. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/adapters/supabase_adapter.py +0 -0
  41. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/admin/FEATURE.md +0 -0
  42. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/admin/__init__.py +0 -0
  43. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/admin/router.py +0 -0
  44. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/api/__init__.py +0 -0
  45. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/api/auth.py +0 -0
  46. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/api/config.py +0 -0
  47. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/api/handlers.py +0 -0
  48. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/api/protocol.py +0 -0
  49. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/api/server.py +0 -0
  50. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/associations.py +0 -0
  51. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/cache_debug.py +0 -0
  52. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/catalog.py +0 -0
  53. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/catalog_sql.py +0 -0
  54. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/MODULE_README.md +0 -0
  55. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/__init__.py +0 -0
  56. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/postgres_connection.py +0 -0
  57. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/postgrest.py +0 -0
  58. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/supabase_auth.py +0 -0
  59. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/supabase_config.py +0 -0
  60. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/client/supabase_manager.py +0 -0
  61. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  62. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/FEATURE.md +0 -0
  63. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/MODULE_README.md +0 -0
  64. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  65. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/TASKS.md +0 -0
  66. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/__init__.py +0 -0
  67. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/admin_lane.py +0 -0
  68. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/async_db_manager.py +0 -0
  69. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/base.py +0 -0
  70. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/config.py +0 -0
  71. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/connections.py +0 -0
  72. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/diagnostics.py +0 -0
  73. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/expressions.py +0 -0
  74. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/extended.py +0 -0
  75. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/fields.py +0 -0
  76. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/listen.py +0 -0
  77. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/loop_filters.py +0 -0
  78. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/model_dto.py +0 -0
  79. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/model_view.py +0 -0
  80. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/one_database.py +0 -0
  81. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/paginator.py +0 -0
  82. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/pool_maintenance.py +0 -0
  83. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/pool_watch.py +0 -0
  84. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/pooler_role.py +0 -0
  85. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/pydantic_bridge.py +0 -0
  86. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/read_write.py +0 -0
  87. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/registry.py +0 -0
  88. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/relations.py +0 -0
  89. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/resilience.py +0 -0
  90. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/rls_session.py +0 -0
  91. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/signals.py +0 -0
  92. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/statement_ceiling.py +0 -0
  93. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/tls.py +0 -0
  94. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/transaction.py +0 -0
  95. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/types.py +0 -0
  96. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/write_queue.py +0 -0
  97. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/core/write_retry.py +0 -0
  98. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/entity.py +0 -0
  99. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/error_handling.py +0 -0
  100. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/exceptions.py +0 -0
  101. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/extended/__init__.py +0 -0
  102. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/extended/app_error_handler.py +0 -0
  103. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/identity_rule.py +0 -0
  104. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/local_sqlite.py +0 -0
  105. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/middleware/__init__.py +0 -0
  106. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/middleware/base.py +0 -0
  107. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/MODULE_README.md +0 -0
  108. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/__init__.py +0 -0
  109. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/cli.py +0 -0
  110. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/ddl.py +0 -0
  111. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/diff.py +0 -0
  112. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/executor.py +0 -0
  113. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/integration.py +0 -0
  114. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/loader.py +0 -0
  115. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/operations.py +0 -0
  116. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/state.py +0 -0
  117. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/migrations/table_filter.py +0 -0
  118. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/no_org_assignment.py +0 -0
  119. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/FEATURE.md +0 -0
  120. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/MODULE_README.md +0 -0
  121. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/__init__.py +0 -0
  122. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/bulk_update_values.py +0 -0
  123. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/catalog_select.py +0 -0
  124. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/conflict.py +0 -0
  125. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/conflict_writes.py +0 -0
  126. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/create.py +0 -0
  127. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/delete.py +0 -0
  128. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/dynamic_admin.py +0 -0
  129. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/dynamic_crud.py +0 -0
  130. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/graph_walk.py +0 -0
  131. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/latest_rows.py +0 -0
  132. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/queue_claim.py +0 -0
  133. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/read.py +0 -0
  134. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/relational_backfill.py +0 -0
  135. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/staging_load.py +0 -0
  136. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/operations/update.py +0 -0
  137. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/platform_access.py +0 -0
  138. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/platform_db.py +0 -0
  139. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/py.typed +0 -0
  140. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/pytest_live_db_guard.py +0 -0
  141. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/pytest_lock_guard.py +0 -0
  142. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/pytest_plugin.py +0 -0
  143. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/python_sql/MODULE_README.md +0 -0
  144. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/python_sql/__init__.py +0 -0
  145. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/python_sql/db_objects.py +0 -0
  146. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  147. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  148. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/query/FEATURE.md +0 -0
  149. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/query/MODULE_README.md +0 -0
  150. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/query/__init__.py +0 -0
  151. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/query/builder.py +0 -0
  152. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/query/executor.py +0 -0
  153. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/resources/__init__.py +0 -0
  154. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  155. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  156. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/FEATURE.md +0 -0
  157. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  158. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/__init__.py +0 -0
  159. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/code_handler.py +0 -0
  160. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  161. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/columns.py +0 -0
  162. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/common.py +0 -0
  163. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/diff_preview.py +0 -0
  164. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  165. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/generator.py +0 -0
  166. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  167. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  168. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  169. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  170. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/package_wiring.py +0 -0
  171. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/relationships.py +0 -0
  172. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/runner.py +0 -0
  173. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/schema.py +0 -0
  174. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/tables.py +0 -0
  175. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/schema_builder/views.py +0 -0
  176. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/FEATURE.md +0 -0
  177. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/__init__.py +0 -0
  178. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/attachments.py +0 -0
  179. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/backup_restore.py +0 -0
  180. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/crypto.py +0 -0
  181. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  182. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/items.py +0 -0
  183. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/model.py +0 -0
  184. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  185. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/native_enable.py +0 -0
  186. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  187. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  188. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/native_source.py +0 -0
  189. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/org_service.py +0 -0
  190. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/org_vault_gate.py +0 -0
  191. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/service.py +0 -0
  192. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/secrets_battery/vault_history.py +0 -0
  193. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/README.md +0 -0
  194. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/__init__.py +0 -0
  195. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/coalesce.py +0 -0
  196. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/errors.py +0 -0
  197. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/fallback.py +0 -0
  198. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/flush.py +0 -0
  199. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/lifecycle.py +0 -0
  200. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/managed.py +0 -0
  201. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/op.py +0 -0
  202. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/reads.py +0 -0
  203. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/session.py +0 -0
  204. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/session/telemetry.py +0 -0
  205. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  206. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/__init__.py +0 -0
  207. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/executor.py +0 -0
  208. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/queries.py +0 -0
  209. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/registry.py +0 -0
  210. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/types.py +0 -0
  211. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/sql_executor/utils.py +0 -0
  212. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/state.py +0 -0
  213. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/utils/__init__.py +0 -0
  214. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/utils/sql_utils.py +0 -0
  215. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/matrx_orm/utils/type_converters.py +0 -0
  216. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/scripts/git-branches.sh +0 -0
  217. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/scripts/publish.sh +0 -0
  218. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/scripts/release.sh +0 -0
  219. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/MODULE_README.md +0 -0
  220. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/__init__.py +0 -0
  221. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/conftest.py +0 -0
  222. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/MODULE_README.md +0 -0
  223. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/__init__.py +0 -0
  224. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_adapter_registry.py +0 -0
  225. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_admin_db_columns.py +0 -0
  226. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_admin_response_rendering.py +0 -0
  227. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_admin_search_negation.py +0 -0
  228. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_admin_search_sentinels.py +0 -0
  229. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_advisory_lock.py +0 -0
  230. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_agent_message.py +0 -0
  231. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_api_auth.py +0 -0
  232. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_api_config.py +0 -0
  233. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_api_handlers.py +0 -0
  234. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_api_protocol.py +0 -0
  235. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_array_agg_order_by.py +0 -0
  236. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_associations.py +0 -0
  237. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_associations_wiring.py +0 -0
  238. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_bulk_hydration_offload.py +0 -0
  239. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_bulk_update_by_pk.py +0 -0
  240. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  241. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_cache_debug.py +0 -0
  242. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_call_function.py +0 -0
  243. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_case_when.py +0 -0
  244. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_column_scoped_writes.py +0 -0
  245. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_committed_row_guard.py +0 -0
  246. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_composite_pk_filter.py +0 -0
  247. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_composite_pk_write_paths.py +0 -0
  248. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_config.py +0 -0
  249. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_conflict_target.py +0 -0
  250. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_conflict_writes.py +0 -0
  251. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_connection_codecs.py +0 -0
  252. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_connection_poison_guard.py +0 -0
  253. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_connection_primitives.py +0 -0
  254. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_count_composite_distinct.py +0 -0
  255. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_count_limit_param_leak.py +0 -0
  256. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_db_function_field.py +0 -0
  257. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_ddl_generator.py +0 -0
  258. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_deadlock_retry.py +0 -0
  259. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_derived_table.py +0 -0
  260. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_dirty_tracking.py +0 -0
  261. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_dynamic_crud.py +0 -0
  262. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_exceptions.py +0 -0
  263. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  264. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_expression_primitives.py +0 -0
  265. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_fields.py +0 -0
  266. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  267. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_fk_cycle_resolution.py +0 -0
  268. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_from_alias.py +0 -0
  269. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_fts.py +0 -0
  270. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_func_expression_args.py +0 -0
  271. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_graph_walk.py +0 -0
  272. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_having_annotate_alias.py +0 -0
  273. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  274. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_introspect_rls_policies.py +0 -0
  275. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_join_and_aggregate.py +0 -0
  276. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_latest_rows.py +0 -0
  277. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_listen_notify.py +0 -0
  278. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_local_sqlite.py +0 -0
  279. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_lock_contention_retry.py +0 -0
  280. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_managed_write_guard.py +0 -0
  281. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_matrx_entity.py +0 -0
  282. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_migration_diff_types.py +0 -0
  283. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_migration_loader.py +0 -0
  284. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_model_instance.py +0 -0
  285. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_model_meta.py +0 -0
  286. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_optimistic_concurrency.py +0 -0
  287. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_order_by_expression.py +0 -0
  288. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_org_assignment_inventory.py +0 -0
  289. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  290. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_parameter_name_hydration.py +0 -0
  291. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_patch_jsonb_path.py +0 -0
  292. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_percentile_cont.py +0 -0
  293. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_persisted_count.py +0 -0
  294. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_person_scoped_session_bypasses_shared_cache.py +0 -0
  295. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_pool_create_never_wedges.py +0 -0
  296. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_pool_holder_census.py +0 -0
  297. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_pool_loop_recreation.py +0 -0
  298. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_pool_maintenance.py +0 -0
  299. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_postgrest_filters.py +0 -0
  300. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_pydantic_bridge.py +0 -0
  301. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_query_builder.py +0 -0
  302. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_query_error_detail.py +0 -0
  303. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_query_executor_sql.py +0 -0
  304. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_query_timeout.py +0 -0
  305. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  306. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_queue_claim.py +0 -0
  307. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_read_connection_retry.py +0 -0
  308. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_read_write_declared.py +0 -0
  309. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_registry.py +0 -0
  310. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_registry_multi_database.py +0 -0
  311. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_registry_multi_schema.py +0 -0
  312. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_relational_backfill.py +0 -0
  313. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_relations.py +0 -0
  314. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_resilience.py +0 -0
  315. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_schema_exists.py +0 -0
  316. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_session_advisory_lock.py +0 -0
  317. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_state_cache.py +0 -0
  318. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_subquery_filter_raw.py +0 -0
  319. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_subquery_in_filter.py +0 -0
  320. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_subquery_nested_expressions.py +0 -0
  321. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_supabase_auth.py +0 -0
  322. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_supabase_config.py +0 -0
  323. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_tls.py +0 -0
  324. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_transaction_pool_release_sends_nothing.py +0 -0
  325. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_typed_join_projection.py +0 -0
  326. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_typed_predicates.py +0 -0
  327. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_update_case_expression.py +0 -0
  328. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_update_subquery.py +0 -0
  329. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_update_with_rebase.py +0 -0
  330. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_upsert_default_leak.py +0 -0
  331. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_upsert_with_conflict.py +0 -0
  332. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_values_jsonb_decode.py +0 -0
  333. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_watched_lifecycle.py +0 -0
  334. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_write_queue_deadline.py +0 -0
  335. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level1/test_write_retry_semantics.py +0 -0
  336. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/MODULE_README.md +0 -0
  337. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/__init__.py +0 -0
  338. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/conftest.py +0 -0
  339. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_bulk_ops.py +0 -0
  340. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_cache_integration.py +0 -0
  341. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_crud.py +0 -0
  342. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_foreign_keys.py +0 -0
  343. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_m2m.py +0 -0
  344. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_manager.py +0 -0
  345. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_migrations_live.py +0 -0
  346. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_query_execution.py +0 -0
  347. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/level2/test_schema_diff.py +0 -0
  348. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/live_pooler_role.py +0 -0
  349. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/native_source_cases.py +0 -0
  350. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/native_source_oracle.rs +0 -0
  351. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/.env.example +0 -0
  352. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/README.md +0 -0
  353. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/__init__.py +0 -0
  354. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/generate.py +0 -0
  355. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/generated/.gitkeep +0 -0
  356. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/matrx_orm.yaml +0 -0
  357. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project/test_schema_generation.py +0 -0
  358. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/.env.example +0 -0
  359. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/README.md +0 -0
  360. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/__init__.py +0 -0
  361. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/client_example.py +0 -0
  362. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/client_example.ts +0 -0
  363. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  364. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/sample_project_desktop/server.py +0 -0
  365. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/entity_tests.py +0 -0
  366. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_base_generation.py +0 -0
  367. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  368. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_composite_unique_generation.py +0 -0
  369. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_dto_identity_generation.py +0 -0
  370. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_entity_capability_generation.py +0 -0
  371. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_enum_ordering.py +0 -0
  372. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_generate_schema.py +0 -0
  373. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_junction_analysis.py +0 -0
  374. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_multi_schema_output.py +0 -0
  375. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_schema_analysis.py +0 -0
  376. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_sql_expression_defaults.py +0 -0
  377. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_table_relationships_query.py +0 -0
  378. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema/test_view_generation.py +0 -0
  379. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema_builder/test_array_default_parsing.py +0 -0
  380. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  381. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  382. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/schema_builder/test_never_filter_columns.py +0 -0
  383. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/__init__.py +0 -0
  384. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/conftest.py +0 -0
  385. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_a_failed_capture_still_names_the_failure.py +0 -0
  386. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_cache_no_downgrade.py +0 -0
  387. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_capture_poison_proof.py +0 -0
  388. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_coalesce.py +0 -0
  389. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_disk_spill_fallback.py +0 -0
  390. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_flush_individual_fallback.py +0 -0
  391. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_governed_write.py +0 -0
  392. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_live_db_guard_plugin.py +0 -0
  393. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_managed.py +0 -0
  394. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_op_enqueue_site.py +0 -0
  395. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_reads.py +0 -0
  396. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_record_error_bounded_insert.py +0 -0
  397. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_record_error_storm.py +0 -0
  398. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_session.py +0 -0
  399. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/session/test_spill_guard_plugin.py +0 -0
  400. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_a_backend_handed_over_mid_transaction_never_takes_our_writes.py +0 -0
  401. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_a_read_only_backend_never_refuses_our_writes.py +0 -0
  402. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_array_arg_element_type.py +0 -0
  403. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_attachment_mutation_serialization.py +0 -0
  404. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_backup_alias_conflict.py +0 -0
  405. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_backup_history_restore.py +0 -0
  406. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_backup_restore_live.py +0 -0
  407. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_call_function_as.py +0 -0
  408. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_call_function_none_mode.py +0 -0
  409. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_composite_fk_is_not_a_column_fk.py +0 -0
  410. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_database_name_alias.py +0 -0
  411. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_db_functions.py +0 -0
  412. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_dsn_password_masking.py +0 -0
  413. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_dynamic_select_unregistered.py +0 -0
  414. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  415. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_keyed_digest.py +0 -0
  416. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_model_cls_refactor.py +0 -0
  417. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_native_enable.py +0 -0
  418. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_native_lifecycle.py +0 -0
  419. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_native_lifecycle_fences.py +0 -0
  420. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_native_passkey_receipts.py +0 -0
  421. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_native_source.py +0 -0
  422. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  423. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_one_database.py +0 -0
  424. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_order_by_desc_nulls_last.py +0 -0
  425. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_org_vault_gate.py +0 -0
  426. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_pooler_role_guard.py +0 -0
  427. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_secret_audit_names_its_organization.py +0 -0
  428. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_secrets_battery.py +0 -0
  429. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_secrets_minting_keys.py +0 -0
  430. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_shared_lock_guard.py +0 -0
  431. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_sql_param_casts.py +0 -0
  432. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_statement_ceiling_warning.py +0 -0
  433. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_sync_twins_guard.py +0 -0
  434. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_update_result_truthiness.py +0 -0
  435. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_user_visible_lookup.py +0 -0
  436. {matrx_orm-3.1.203 → matrx_orm-3.1.205}/tests/test_vault_aggregate_recovery_stateful.py +0 -0
@@ -92,7 +92,7 @@ returned count. Omit the parameter → exact legacy last-write-wins.
92
92
  `MatrxEntity.update_with_rebase(id, expected_version=N, **fields)` additionally
93
93
  auto-rebases past conflicts whose intervening writes were DISJOINT from the
94
94
  written fields (proven from `history.row_versions` snapshots). Cross-repo
95
- contract: `common-docs/systems/platform/optimistic-concurrency/FEATURE.md`.
95
+ contract: `common-docs/systems/architecture/optimistic-concurrency/FEATURE.md`.
96
96
 
97
97
  ### Atomic queue claims
98
98
 
@@ -25,7 +25,7 @@ Every table that becomes a Model needs row identity: a single-column primary key
25
25
  - 🚨 **ONE CONNECTION, REQUIRED** (`matrx_orm.platform_db`): `register_platform_db(name, ...)` + `platform_connection_url()` — the ONLY sanctioned way any Matrx service or package turns env vars into a pool. One set of variables (`SUPABASE_MATRIX_*`), owned here; TLS is a deployment input (`SUPABASE_MATRIX_SSL`), never hardcoded; **RAISES** if it isn't given a database — no degraded mode. Every package's `bootstrap_db()` is one call to it. A package may absolutely run on its OWN Postgres — that is a change of VALUES, never a new variable name; what it may never have is a *second candidate* or a fallback chain. `register_database_from_env` is the low-level primitive underneath — **application and package code must not call it directly** (guard: `scripts/check_one_database.py`, blocking in release).
26
26
  - **Core model layer**: `Model`, `BaseManager`, `BaseDTO`, `ModelView`, `model_registry`, plus 50+ field types (`CharField`, `IntegerField`, `ForeignKey`, `ManyToManyField`, `JSONField`, …).
27
27
  - **`MatrxEntity`** (`matrx_orm/entity.py`) — **the platform entity contract as an ORM primitive.** A table registered in `platform.entity_types` generates as a `MatrxEntity` (everything else stays a plain `Model`) and gets the behavior instead of every consumer hand-wiring it: `await page.versions()` (not a query on `history.row_versions`), `await page.restore(3)` (not a `version_restore` RPC + a cache bust — `restore()` busts the cache itself), `Note.alive()` / `.dead()` / `.soft_delete()` / `.undelete()`, and `Page.capabilities()`. Capability flags (`_entity_token`, `_is_versioned`, `_has_soft_delete`, `_is_org_scoped`, `_rls_variant`) are **stamped by the generator from the LIVE DATABASE** (does the table really carry the `_version_capture` trigger? a `deleted_at` column?) — never from `entity_types`' own flags, which are wrong on 61 of its 242 rows. **The database is truth; a flag is a claim.** Using a capability an entity does not declare RAISES (`EntityCapabilityError`) and names the fix — it never returns silently-wrong data, and `is_deleted` refuses to answer from a column a partial fetch never loaded. Drift guard: `scripts/check_entity_drift.py` (loud, non-blocking, in `release.sh`).
28
- - **Optimistic concurrency (`expected_version=`)** — opt-in compare-and-swap on the canonical `version` int column: `update_where` / `update_item` / instance `update()` take `expected_version=N` (`WHERE version = N`, `SET version = N + 1`; 0 rows → `DoesNotExist` if gone, `OptimisticLockError` if changed — carrying the **decision package**: `current_version`, `current_row`, `contested_fields` (current values of ONLY the fields this write attempted), and `changed_by`/`changed_at` from `history.row_versions` where versioned); `bulk_update(..., check_version=True)` guards per row; `MatrxEntity.update_with_rebase` auto-rebases past DISJOINT concurrent writes using `history.row_versions` snapshots. **Never automatic** — an unguarded write stays last-write-wins (the `_touch_row` trigger bumps `version` on every update, so auto-guarding would raise spurious conflicts). Contract: `common-docs/systems/platform/optimistic-concurrency/FEATURE.md`.
28
+ - **Optimistic concurrency (`expected_version=`)** — opt-in compare-and-swap on the canonical `version` int column: `update_where` / `update_item` / instance `update()` take `expected_version=N` (`WHERE version = N`, `SET version = N + 1`; 0 rows → `DoesNotExist` if gone, `OptimisticLockError` if changed — carrying the **decision package**: `current_version`, `current_row`, `contested_fields` (current values of ONLY the fields this write attempted), and `changed_by`/`changed_at` from `history.row_versions` where versioned); `bulk_update(..., check_version=True)` guards per row; `MatrxEntity.update_with_rebase` auto-rebases past DISJOINT concurrent writes using `history.row_versions` snapshots. **Never automatic** — an unguarded write stays last-write-wins (the `_touch_row` trigger bumps `version` on every update, so auto-guarding would raise spurious conflicts). Contract: `common-docs/systems/architecture/optimistic-concurrency/FEATURE.md`.
29
29
  - **Change tracking** — every instance records which columns were **loaded** (a SELECTed row, or the caller's kwargs) and which were **changed**. `save()` writes only those, so `.only("id","email")` + `save()` can never NULL the columns it never fetched (it used to — silent data loss). Mutable containers (jsonb/arrays) are always rewritten when loaded, because `obj.metadata["k"]=1` cannot be seen by `__setattr__`; **reassigning** (`obj.metadata = {...}`) is tracked precisely and is the sanctioned way. `Model._hydrate()` is the ONE row→model entry point.
30
30
  - **Upsert writes only what the caller supplied.** `upsert` / `bulk_upsert` / `upsert_with_conflict` materialize every field's Python default so the **INSERT** half is complete — but `ON CONFLICT DO UPDATE SET` covers **only the columns present in the caller's `data`** (an explicit `update_fields` still wins). Letting defaults reach the UPDATE half silently RESET every defaulted column on each re-upsert of an existing row: it once reset scraped-and-analyzed `research.rs_source` rows to `scrape_status='pending', server_attempts=0` (a watchdog then finalized them `'failed'`) and undid users' manual `is_included=false`. A caller-supplied `None` is excluded too — it is dropped from the INSERT, and `EXCLUDED.<col>` on an omitted column resolves to that column's **DEFAULT**. An upsert of only conflict keys means "ensure this row exists" and reconciles to a no-op self-assignment, never a raise (a bare `DO NOTHING` would break `RETURNING *`). Pinned by `tests/level1/test_upsert_default_leak.py`.
31
31
  - **Read-only models** (`_read_only = True`): a model that can be queried but NEVER written through the ORM — every write path raises `ReadOnlyModelError` (enforced at `QueryExecutor.insert/bulk_insert/upsert/update/delete`, so it covers all of `create`/`save`/`update`/`delete`/`update_where`/`delete_where`/`upsert`/`bulk_*`). Used for DB-managed tables the app must not mutate. The canonical **`auth.users`** model is baked into the schema generator (`get_string_user_model`) as the full, curated Supabase auth schema (safe columns only — no password/token fields), `_read_only`, bound per-database. Read a user's profile/metadata there; mutate users only through Supabase Auth (GoTrue).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.203
3
+ Version: 3.1.205
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.59
29
+ Requires-Dist: matrx-utils>=2.0.60
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
@@ -263,10 +263,12 @@ from .core.session_context import (
263
263
  ACTOR_AGENT_GUC,
264
264
  ACTOR_SYSTEM_GUC,
265
265
  ACTOR_TIER_GUC,
266
+ RETIRED_TIER_WORDS,
266
267
  VALID_TIERS,
267
268
  ActorRef,
268
269
  ActorTier,
269
270
  SessionContextProvider,
271
+ canonical_actor_tier,
270
272
  configure_session_context,
271
273
  current_actor,
272
274
  current_tier,
@@ -703,9 +705,11 @@ __all__ = [
703
705
  "ACTOR_AGENT_GUC",
704
706
  "ACTOR_SYSTEM_GUC",
705
707
  "ACTOR_TIER_GUC",
708
+ "RETIRED_TIER_WORDS",
706
709
  "VALID_TIERS",
707
710
  "ActorRef",
708
711
  "ActorTier",
712
+ "canonical_actor_tier",
709
713
  "configure_session_context",
710
714
  "current_actor",
711
715
  "current_tier",
@@ -150,6 +150,29 @@ class TypedArg:
150
150
  return ".".join(f'"{seg}"' for seg in str(self.pg_type).split("."))
151
151
 
152
152
 
153
+ def uuid_list_kind(value: list[Any]) -> bool:
154
+ """``True`` when ``value`` is a non-empty list of ``uuid.UUID`` — a ``uuid[]`` argument.
155
+
156
+ A list holding ONLY ``uuid.UUID`` objects can never be a jsonb argument (``json.dumps``
157
+ cannot encode one), so it can only mean a native ``uuid[]`` parameter; it binds as one,
158
+ with the explicit cast :class:`ArrayArg` would give it. A list MIXING ``uuid.UUID`` with
159
+ other values is ambiguous and is refused by name (VISION-REACH W2, 2026-10-02: the
160
+ records tool's roll-up raised ``Object of type UUID is not JSON serializable`` on every
161
+ call because a list of UUIDs was taken for jsonb).
162
+ """
163
+ import uuid as _uuid
164
+
165
+ if not value or not any(isinstance(v, _uuid.UUID) for v in value):
166
+ return False
167
+ if all(isinstance(v, _uuid.UUID) for v in value):
168
+ return True
169
+ raise TypeError(
170
+ "call_function: a list mixes uuid.UUID objects with other values, so it is neither a "
171
+ "uuid[] nor a jsonb argument. Pass ArrayArg(values, \"uuid\") with every element a "
172
+ "UUID (or its text), or a list of plain JSON values for a jsonb parameter."
173
+ )
174
+
175
+
153
176
  def _bind_args(args: tuple[Any, ...]) -> tuple[str, list[Any]]:
154
177
  """Build the ``$1, $2, ...`` placeholder list + bound values.
155
178
 
@@ -175,6 +198,9 @@ def _bind_args(args: tuple[Any, ...]) -> tuple[str, list[Any]]:
175
198
  suffix = f"::{value.element_type}[]" if value.element_type else ""
176
199
  placeholders.append(f"${idx}{suffix}")
177
200
  bound.append(value.value)
201
+ elif isinstance(value, list) and uuid_list_kind(value):
202
+ placeholders.append(f"${idx}::uuid[]")
203
+ bound.append(value)
178
204
  elif isinstance(value, dict | list):
179
205
  placeholders.append(f"${idx}::jsonb")
180
206
  bound.append(json.dumps(value))
@@ -64,7 +64,7 @@ async def introspect_rls_policies(
64
64
  ``schemas``/``relnames`` are PARALLEL arrays (zipped server-side via
65
65
  ``unnest``) — e.g. ``schemas=["public","workspace"],
66
66
  relnames=["notes","tasks"]`` audits ``public.notes`` and
67
- ``workspace.tasks``. Both are bound array parameters, never
67
+ ``projects.tasks``. Both are bound array parameters, never
68
68
  string-interpolated. Returns one row per table that actually exists
69
69
  (callers should treat a missing pair as "table not found").
70
70
 
@@ -9,7 +9,7 @@ reliably apply them is the moment this package opens a transaction.
9
9
  The host declares a provider once at startup::
10
10
 
11
11
  from matrx_orm import configure_session_context
12
- configure_session_context(lambda: {"app.actor_tier": "ai", "app.actor_system": "x"})
12
+ configure_session_context(lambda: {"app.actor_tier": "agent", "app.actor_system": "x"})
13
13
 
14
14
  and from then on every TOP-LEVEL ``transaction()`` (which includes the one
15
15
  ``rls_session`` opens, before it drops to the restricted role) emits whatever
@@ -134,11 +134,11 @@ async def apply_session_context(connection: Any) -> None:
134
134
  # The host (aidream) re-exports these names and wires ``declared_actor_gucs``
135
135
  # into ``configure_session_context`` at startup.
136
136
  #
137
- # CONVERGE: actor tier literal code|ai|human; target vocabulary
138
- # system|agent|user - declared 2026-09-10, Data Doctrine 1.5/7.
137
+ # Tier words (DD-064): ``system`` (the platform's own machinery), ``agent`` (an
138
+ # agent's turn), ``user`` (a person's own action).
139
139
  # ---------------------------------------------------------------------------
140
140
 
141
- ActorTier = Literal["code", "ai", "human"]
141
+ ActorTier = Literal["system", "agent", "user"]
142
142
 
143
143
  ACTOR_TIER_GUC = "app.actor_tier"
144
144
  ACTOR_SYSTEM_GUC = "app.actor_system"
@@ -149,7 +149,24 @@ ACTOR_SYSTEM_GUC = "app.actor_system"
149
149
  # control that saves a value nothing honours.
150
150
  ACTOR_AGENT_GUC = "app.actor_agent"
151
151
 
152
- VALID_TIERS: frozenset[str] = frozenset({"code", "ai", "human"})
152
+ VALID_TIERS: frozenset[str] = frozenset({"system", "agent", "user"})
153
+
154
+ #: DD-064 transition: the retired spellings and the word each became. The
155
+ #: database accepts both on every channel and answers in the new words, but
156
+ #: ``history.row_versions.actor_tier`` keeps the old words on rows written
157
+ #: before the rename, so every reader of a stored tier normalizes through
158
+ #: :func:`canonical_actor_tier` (mirrors ``platform.canonical_actor_tier``).
159
+ RETIRED_TIER_WORDS: Mapping[str, str] = {"code": "system", "ai": "agent", "human": "user"}
160
+
161
+
162
+ def canonical_actor_tier(value: object) -> ActorTier | None:
163
+ """The tier in the current words: old -> new, new passes through, else None."""
164
+ if not isinstance(value, str):
165
+ return None
166
+ word = value.strip().lower()
167
+ if word in VALID_TIERS:
168
+ return word # type: ignore[return-value]
169
+ return RETIRED_TIER_WORDS.get(word) # type: ignore[return-value]
153
170
 
154
171
 
155
172
  @dataclass(frozen=True, slots=True)
@@ -160,7 +177,7 @@ class ActorRef:
160
177
  system: str | None = None
161
178
  #: The agent definition id, when the writer IS an agent (DD-211). A
162
179
  #: person's write never carries one -- the database refuses the pair
163
- #: ``tier="human"`` + an agent, because "a person did this" and "agent X
180
+ #: ``tier="user"`` + an agent, because "a person did this" and "agent X
164
181
  #: did this" are two different authors.
165
182
  agent: str | None = None
166
183
 
@@ -198,7 +215,7 @@ def declared_actor_gucs() -> dict[str, str]:
198
215
 
199
216
  This is the provider a host passes to :func:`configure_session_context`.
200
217
  Empty when nothing declared an actor: the DB resolver then applies its
201
- documented default (``human`` with an identity present, ``code`` without)
218
+ documented default (``user`` with an identity present, ``system`` without)
202
219
  and logs that it did.
203
220
 
204
221
  The WORKFLOW CHAIN rides the same provider (it is part of "who is writing":
@@ -278,20 +295,22 @@ def declaring_workflow_chain(chain: WorkflowChain | None) -> Iterator[WorkflowCh
278
295
 
279
296
 
280
297
  def _validated_actor(tier: str, system: str, agent: str | None, *, caller: str) -> ActorRef:
281
- if tier not in VALID_TIERS:
298
+ canonical = canonical_actor_tier(tier)
299
+ if canonical is None:
282
300
  raise ValueError(f"{caller} tier must be one of {sorted(VALID_TIERS)}; got {tier!r}")
301
+ tier = canonical
283
302
  if not system or not system.strip():
284
303
  raise ValueError(f"{caller} requires a non-empty system (who specifically)")
285
304
  cleaned = (agent or "").strip() or None
286
305
  if cleaned is not None:
287
- if tier == "human":
306
+ if tier == "user":
288
307
  # The database refuses this pair outright (23514). Refusing it here
289
308
  # too means the door that made the mistake learns at the call site
290
309
  # rather than on whichever write happens to land first.
291
310
  raise ValueError(
292
- f"{caller} was given tier='human' AND agent={cleaned!r}. A person's write carries "
311
+ f"{caller} was given tier='user' AND agent={cleaned!r}. A person's write carries "
293
312
  "no agent: either the person is the author (drop the agent) or the agent is "
294
- "(declare tier='ai' and the agent that is running)."
313
+ "(declare tier='agent' and the agent that is running)."
295
314
  )
296
315
  try:
297
316
  UUID(cleaned)
@@ -357,11 +376,13 @@ __all__ = [
357
376
  "ACTOR_AGENT_GUC",
358
377
  "ACTOR_SYSTEM_GUC",
359
378
  "ACTOR_TIER_GUC",
379
+ "RETIRED_TIER_WORDS",
360
380
  "VALID_TIERS",
361
381
  "ActorRef",
362
382
  "ActorTier",
363
383
  "SessionContextProvider",
364
384
  "apply_session_context",
385
+ "canonical_actor_tier",
365
386
  "emit_local_gucs",
366
387
  "local_gucs_statement",
367
388
  "configure_session_context",
@@ -0,0 +1,3 @@
1
+ # Installed by matrx-orm: in a process whose environment carries MATRX_PRODUCTION_DOOR=1 (exported by the
2
+ # pytest plugin matrx_orm.pytest_production_door), install the same production door before any user code.
3
+ import os; exec("import sys, importlib.util as u, importlib.machinery as m\ns = m.PathFinder.find_spec('matrx_orm')\nif s and s.submodule_search_locations and 'matrx_orm.pytest_production_door' not in sys.modules:\n sp = u.spec_from_file_location('matrx_orm.pytest_production_door', list(s.submodule_search_locations)[0] + '/pytest_production_door.py')\n mod = u.module_from_spec(sp); sys.modules[sp.name] = mod; sp.loader.exec_module(mod); mod.install()") if os.environ.get("MATRX_PRODUCTION_DOOR") == "1" else None
@@ -24,6 +24,8 @@ import json
24
24
  import re
25
25
  from typing import TYPE_CHECKING, Any
26
26
 
27
+ from matrx_orm.core.db_function import uuid_list_kind
28
+
27
29
  if TYPE_CHECKING: # pragma: no cover
28
30
  from matrx_orm.core.base import Model
29
31
 
@@ -38,7 +40,12 @@ def _render_call(function_name: str, args: tuple[Any, ...]) -> tuple[str, list[A
38
40
  placeholders: list[str] = []
39
41
  values: list[Any] = []
40
42
  for index, arg in enumerate(args, start=1):
41
- if isinstance(arg, dict | list):
43
+ if isinstance(arg, list) and uuid_list_kind(arg):
44
+ # A list of uuid.UUID is a uuid[] argument; `default=str` below would have
45
+ # turned it into a jsonb array of text and missed the uuid[] overload.
46
+ placeholders.append(f"${index}::uuid[]")
47
+ values.append(arg)
48
+ elif isinstance(arg, dict | list):
42
49
  placeholders.append(f"${index}::jsonb")
43
50
  values.append(json.dumps(arg, ensure_ascii=False, default=str))
44
51
  else:
@@ -21,9 +21,21 @@ and every ``psycopg_pool`` pool), ``psycopg2.connect``, ``asyncpg.connect`` / ``
21
21
  plugin loads is patched on import.
22
22
 
23
23
  THE ONE EXCEPTION: ``db.pooled_read.read_only("production")`` opens its connection inside
24
- :func:`production_read_only` and then runs ``begin read only`` before handing out a cursor, so a production
25
- read in a test is a transaction that cannot write. Nothing else — no flag, no environment variable — opens
26
- this door. Not covered: a libpq service file or ``~/.pgpass`` host that the environment does not name.
24
+ :func:`production_read_only`, and that connection is the least-privilege role ``matrx_reader`` (``pg_read_all_data``
25
+ only, no write grant) — the role is the door; the read-only transaction and statement check there are defence in
26
+ depth. Nothing else — no flag, no environment variable — opens this door. Designed doors the reader role leaves
27
+ open (accepted 2026-10-02): ``lo_create`` and the SECURITY DEFINER functions granted to PUBLIC, which write as
28
+ their owner once a session turns its read-only default off. Child Python processes carry it too: the plugin exports ``MATRX_PRODUCTION_DOOR=1`` and the
29
+ ``matrx_orm_production_door.pth`` this package installs puts the same door in any process started with it.
30
+ ``psql`` / ``pg_dump`` / ``pg_dumpall`` / ``pg_restore`` are matched anywhere in a command line (argv, ``bash -c`` /
31
+ ``sh -c`` strings, ``shell=True``, ``os.system``) after ``$VAR`` / ``${VAR}`` are resolved against the child's environment.
32
+
33
+ The door stops ACCIDENTAL production writes by tests, not a determined insider. Residual, deliberately not closed:
34
+ - the public exception helpers and module flag (``production_read_only``, ``_READ_ONLY_PRODUCTION``) are a deliberate bypass;
35
+ - ``-p no:matrx_production_door`` or ``PYTEST_DISABLE_PLUGIN_AUTOLOAD`` from a package root (no root conftest) skips it;
36
+ - private driver internals (``pgconn``, ``asyncpg.connect_utils``) and ``importlib.reload`` of a driver bypass the wrappers;
37
+ - a host given only as an IP address or ``hostaddr`` (no ref, no production name) is not recognized;
38
+ - raw sockets, and a libpq service file or ``~/.pgpass`` host the environment does not name.
27
39
 
28
40
  Guard: ``aidream/tests/test_tests_never_write_production.py`` (plants per bypass class).
29
41
  """
@@ -34,6 +46,7 @@ import contextvars
34
46
  import importlib.abc
35
47
  import importlib.util
36
48
  import os
49
+ import re
37
50
  import subprocess
38
51
  import sys
39
52
  from collections.abc import Iterator
@@ -55,7 +68,7 @@ class ProductionDoorRefusal(RuntimeError):
55
68
 
56
69
  @contextmanager
57
70
  def production_read_only() -> Iterator[None]:
58
- """Open ONE production connection that the caller turns into ``begin read only`` before any statement."""
71
+ """Admit ONE production connection: the read-only helper's, made as the least-privilege reader role."""
59
72
  token = _READ_ONLY_PRODUCTION.set(True)
60
73
  try:
61
74
  yield
@@ -252,40 +265,75 @@ def _patch_orm_registry(mod: Any) -> None:
252
265
  registry_cls.register = register
253
266
 
254
267
 
255
- def _psql_argv(args: Any, shell: bool) -> list[str] | None:
256
- """The command line as words when it runs ``psql`` (directly or inside a shell string), else None."""
257
- words = args.split() if isinstance(args, str | bytes) else [str(a) for a in args] if args else []
258
- words = [w.decode() if isinstance(w, bytes) else w for w in words]
259
- if any(os.path.basename(w) == "psql" for w in words):
260
- return words
261
- return None
268
+ #: The libpq command-line clients that open a database connection.
269
+ _PG_CLIENT = re.compile(r"(?:^|[\s/;&|(`'\"])(psql|pg_dump|pg_dumpall|pg_restore)(?=$|[\s;&|)`'\"])")
270
+ _VAR = re.compile(r"\$\{(\w+)\}|\$(\w+)")
271
+ _FLAGS = {"-h": "host", "--host": "host", "-U": "user", "--username": "user", "-d": "dbname", "--dbname": "dbname"}
272
+
273
+
274
+ def _command_text(args: Any) -> str:
275
+ """The whole command line as one string: a shell string as given, an argv joined (so ``bash -c "…"`` shows)."""
276
+ if isinstance(args, bytes):
277
+ return args.decode(errors="replace")
278
+ if isinstance(args, str):
279
+ return args
280
+ try:
281
+ return " ".join(a.decode(errors="replace") if isinstance(a, bytes) else str(a) for a in args)
282
+ except TypeError:
283
+ return str(args)
284
+
285
+
286
+ def check_command(what: str, args: Any, env: Any = None) -> None:
287
+ """Refuse a psql / pg_dump / pg_dumpall / pg_restore command line whose target names production.
288
+
289
+ ``$VAR`` and ``${VAR}`` are resolved against the environment the child will see, and the child's ``PG*``
290
+ variables count as libpq defaults, exactly as the client would read them.
291
+ """
292
+ text = _command_text(args)
293
+ match = _PG_CLIENT.search(text)
294
+ if match is None:
295
+ return
296
+ child_env = {str(k): str(v) for k, v in (env if env is not None else os.environ).items()}
297
+ expanded = _VAR.sub(lambda m: child_env.get(m.group(1) or m.group(2), m.group(0)), text)
298
+ words = expanded.split()
299
+ kwargs: dict[str, str] = {}
300
+ for i, w in enumerate(words):
301
+ key, sep, value = w.partition("=")
302
+ if key in _FLAGS and sep:
303
+ kwargs[_FLAGS[key]] = value
304
+ elif w in _FLAGS and i + 1 < len(words):
305
+ kwargs[_FLAGS[w]] = words[i + 1]
306
+ saved = dict(os.environ)
307
+ try:
308
+ if env is not None: # the client sees the child's environment, not ours
309
+ os.environ.clear()
310
+ os.environ.update(child_env)
311
+ check(f"{match.group(1)} ({what})", expanded, **kwargs)
312
+ finally:
313
+ if env is not None:
314
+ os.environ.clear()
315
+ os.environ.update(saved)
262
316
 
263
317
 
264
318
  def _patch_subprocess() -> None:
265
319
  original = subprocess.Popen.__init__
266
- if getattr(original, "_production_door", False):
267
- return
320
+ if not getattr(original, "_production_door", False):
268
321
 
269
- def __init__(self: Any, args: Any, *a: Any, **kw: Any) -> None:
270
- words = _psql_argv(args, bool(kw.get("shell")))
271
- if words is not None:
272
- env = kw.get("env")
273
- saved = dict(os.environ)
274
- try:
275
- if env is not None: # psql sees the child's environment, not ours
276
- os.environ.clear()
277
- os.environ.update({str(k): str(v) for k, v in env.items()})
278
- flags = {"-h": "host", "--host": "host", "-U": "user", "--username": "user", "-d": "dbname", "--dbname": "dbname"}
279
- kwargs = {flags[w]: words[i + 1] for i, w in enumerate(words[:-1]) if w in flags}
280
- check("psql (subprocess)", " ".join(words), **kwargs)
281
- finally:
282
- if env is not None:
283
- os.environ.clear()
284
- os.environ.update(saved)
285
- original(self, args, *a, **kw)
286
-
287
- __init__._production_door = True # type: ignore[attr-defined]
288
- subprocess.Popen.__init__ = __init__ # type: ignore[method-assign]
322
+ def __init__(self: Any, args: Any, *a: Any, **kw: Any) -> None:
323
+ check_command("subprocess", args, kw.get("env"))
324
+ original(self, args, *a, **kw)
325
+
326
+ __init__._production_door = True # type: ignore[attr-defined]
327
+ subprocess.Popen.__init__ = __init__ # type: ignore[method-assign]
328
+ original_system = os.system
329
+ if not getattr(original_system, "_production_door", False):
330
+
331
+ def system(command: Any) -> int:
332
+ check_command("os.system", command)
333
+ return original_system(command)
334
+
335
+ system._production_door = True # type: ignore[attr-defined]
336
+ os.system = system
289
337
 
290
338
 
291
339
  _PATCHERS = {
@@ -326,8 +374,33 @@ class _PatchOnImport(importlib.abc.MetaPathFinder, importlib.abc.Loader):
326
374
  return spec
327
375
 
328
376
 
377
+ #: Exported into the environment so every child Python process installs the same door (see the .pth below).
378
+ CHILD_MARKER = "MATRX_PRODUCTION_DOOR"
379
+ _PTH_NAME = "matrx_orm_production_door.pth"
380
+
381
+
382
+ def ensure_child_hook() -> None:
383
+ """Make sure the interpreter's site-packages carries the .pth that installs this door in a child process.
384
+
385
+ The matrx-orm wheel ships it (hatch force-include); an editable or stale install may not, so the plugin
386
+ writes the packaged copy beside the other .pth files on first use. Idempotent; a read-only site is left alone.
387
+ """
388
+ import sysconfig
389
+
390
+ source = os.path.join(os.path.dirname(__file__), _PTH_NAME)
391
+ target = os.path.join(sysconfig.get_paths()["purelib"], _PTH_NAME)
392
+ try:
393
+ wanted = open(source, encoding="utf-8").read()
394
+ if not os.path.exists(target) or open(target, encoding="utf-8").read() != wanted:
395
+ with open(target, "w", encoding="utf-8") as fh:
396
+ fh.write(wanted)
397
+ except OSError:
398
+ pass
399
+
400
+
329
401
  def install() -> None:
330
402
  """Wrap every driver already imported, and every one imported later. Idempotent."""
403
+ os.environ[CHILD_MARKER] = "1"
331
404
  _patch_subprocess()
332
405
  for name, patch in _PATCHERS.items():
333
406
  if name in sys.modules:
@@ -346,8 +419,10 @@ def install() -> None:
346
419
 
347
420
 
348
421
  def pytest_load_initial_conftests(early_config: Any, parser: Any, args: Any) -> None:
422
+ ensure_child_hook()
349
423
  install()
350
424
 
351
425
 
352
426
  def pytest_configure(config: Any) -> None:
427
+ ensure_child_hook()
353
428
  install() # idempotent: covers a registration through the root conftest's fallback
@@ -11,8 +11,8 @@ The excluded set is qualified (``schema.table``) and spans every ``generate[]``
11
11
  database, because the referencing table usually lives in another schema's run.
12
12
 
13
13
  The same holds for a table in a schema the host never models: a foreign key follows its table's
14
- oid, so once a retired table moves to ``graveyard`` every reference to it reads
15
- ``to_schema='graveyard'`` — a class the registry can never hold. A reference whose target schema
14
+ oid, so once a retired table moves to ``deprecated`` every reference to it reads
15
+ ``to_schema='deprecated'`` — a class the registry can never hold. A reference whose target schema
16
16
  is neither generated nor one of the database's ``additional_schemas`` is dropped the same way.
17
17
  """
18
18
 
@@ -98,7 +98,7 @@ class SchemaManager:
98
98
  #: ``schema.table`` names excluded from generation in ANY generate[] entry of this database:
99
99
  #: a reference to one is dropped at load (``excluded_targets.drop_references_to``).
100
100
  self._excluded_fk_targets: frozenset[str] = frozenset(excluded_fk_targets or ())
101
- #: Schemas the host models; a reference into any other (``graveyard``) is dropped the same way.
101
+ #: Schemas the host models; a reference into any other (``deprecated``) is dropped the same way.
102
102
  self._modeled_schemas: frozenset[str] | None = (
103
103
  frozenset(modeled_schemas) if modeled_schemas is not None else None
104
104
  )
@@ -136,7 +136,7 @@ def _resolve_fk_deps(
136
136
  continue
137
137
  # Resolving a bare-name FK reference can RAISE (ambiguous across
138
138
  # databases, or a target whose model set was never imported — e.g. the
139
- # `graveyard` schema). Neither is a reason to fail a WRITE: an
139
+ # `deprecated` schema). Neither is a reason to fail a WRITE: an
140
140
  # unresolvable target cannot be a parent row in THIS flush, so it
141
141
  # contributes no ordering constraint. Letting the raise escape is what
142
142
  # detonated the 2026-07-11 'Users' persistence outage — an ambiguous
@@ -1,7 +1,7 @@
1
1
  """ONE DOOR: a write to a table that refuses an unnamed actor names one here.
2
2
 
3
3
  🚨 THE CLASS THIS CLOSES (2026-09-17). ``platform.associations`` refuses a write
4
- that declares ``actor_tier=code`` and names no system — "an AI did it" with no
4
+ that declares ``actor_tier=system`` and names no system — "an AI did it" with no
5
5
  name is not provenance — and it reads that name from ``SET LOCAL`` GUCs, which
6
6
  exist only inside a transaction that declared them.
7
7
 
@@ -58,7 +58,7 @@ __all__ = [
58
58
  ]
59
59
 
60
60
  #: ``(schema, table)`` pairs whose database-side rule refuses a write that
61
- #: declares ``actor_tier=code`` and names no system. Membership is what makes
61
+ #: declares ``actor_tier=system`` and names no system. Membership is what makes
62
62
  #: the seam speak; every other table's writes are untouched (no extra
63
63
  #: transaction, no extra round trip).
64
64
  ACTOR_REQUIRED_TABLES: frozenset[tuple[str, str]] = frozenset(
@@ -180,7 +180,7 @@ def writing_system() -> str:
180
180
  "A write to an actor-required table could not name the code making it. "
181
181
  f"The outermost frame the seam could read was {where}, and every frame above "
182
182
  "it belongs to the ORM or to async plumbing. Declare the actor at the call "
183
- "site — `async with actor_session('code', '<your system>'):` — rather than "
183
+ "site — `async with actor_session('system', '<your system>'):` — rather than "
184
184
  "letting an unnamed write reach the database, which would be refused there "
185
185
  "anyway, at CASCADE time, nowhere near here."
186
186
  )
@@ -225,7 +225,7 @@ async def actor_named_for_write(database: str) -> AsyncIterator[None]:
225
225
  # the enclosing transaction — which is correct: the enclosing work had no
226
226
  # actor either.
227
227
  async with transaction(database=database):
228
- with declaring_actor("code", system) as actor:
228
+ with declaring_actor("system", system) as actor:
229
229
  await set_local_gucs(actor.as_gucs())
230
230
  yield
231
231
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.203"
3
+ version = "3.1.205"
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.59",
44
+ "matrx-utils>=2.0.60",
45
45
  "pyyaml>=6.0.3",
46
46
  "python-dotenv>=1.0",
47
47
  "cryptography>=43.0",
@@ -84,6 +84,9 @@ dev = [
84
84
  packages = ["matrx_orm"]
85
85
  include = ["matrx_orm/py.typed", "matrx_orm/resources/*.json"]
86
86
 
87
+ [tool.hatch.build.targets.wheel.force-include]
88
+ "matrx_orm/matrx_orm_production_door.pth" = "matrx_orm_production_door.pth"
89
+
87
90
  [tool.hatch.metadata]
88
91
  allow-direct-references = true
89
92
 
@@ -33,6 +33,7 @@ from contextlib import asynccontextmanager
33
33
 
34
34
  import pytest
35
35
  from matrx_orm.core.session_context import (
36
+ canonical_actor_tier,
36
37
  configure_session_context,
37
38
  current_actor,
38
39
  declared_actor_gucs,
@@ -44,11 +45,11 @@ from matrx_orm.write_actor import actor_named_for_write
44
45
  def _would_the_database_refuse(gucs: dict[str, str]) -> bool:
45
46
  """``platform._stamp_actor_tier()``'s refusal clause (``wf_051``): an
46
47
  unset or empty ``app.actor_system`` GUC is NULL to the database, and a
47
- ``code``/``ai`` tier with a NULL system is refused. A ``human`` write (or
48
+ ``system``/``agent`` tier with a NULL system is refused. A ``user`` write (or
48
49
  one with a real name) is not."""
49
- tier = gucs.get("app.actor_tier") or "code"
50
+ tier = canonical_actor_tier(gucs.get("app.actor_tier") or "") or "system"
50
51
  system = (gucs.get("app.actor_system") or "").strip() or None
51
- return tier in ("ai", "code") and system is None
52
+ return tier in ("agent", "system") and system is None
52
53
 
53
54
 
54
55
  @pytest.fixture(autouse=True)
@@ -121,7 +122,7 @@ async def test_actor_named_for_write_names_the_actor_the_trigger_needs(monkeypat
121
122
  seen_gucs = set_gucs
122
123
 
123
124
  assert not _would_the_database_refuse(seen_gucs), seen_gucs
124
- assert seen_gucs["app.actor_tier"] == "code"
125
+ assert seen_gucs["app.actor_tier"] == "system"
125
126
  # The calling frame (this test module), never a hand-typed constant.
126
127
  assert seen_gucs["app.actor_system"] == "level1.test_association_trigger_actor_naming"
127
128
  assert current_actor() is None, "the declaration must not outlive the block"
@@ -145,9 +146,9 @@ async def test_actor_named_for_write_passes_through_an_existing_declaration(monk
145
146
 
146
147
  monkeypatch.setattr(transaction_module, "transaction", fake_transaction)
147
148
 
148
- async with declared_actor("human", "user-42"):
149
+ async with declared_actor("user", "user-42"):
149
150
  async with actor_named_for_write("main"):
150
- assert current_actor().tier == "human"
151
+ assert current_actor().tier == "user"
151
152
  assert current_actor().system == "user-42"
152
153
 
153
154
  assert opened is False, "a caller that already declared an actor is trusted as-is"
@@ -22,7 +22,7 @@ async def test_list_relations_binds_all_filters(query_spy):
22
22
  "main",
23
23
  schemas=["public"],
24
24
  kinds=("BASE TABLE",),
25
- exclude_schemas=["graveyard"],
25
+ exclude_schemas=["deprecated"],
26
26
  ) == []
27
27
  database, sql, schemas, kinds, excluded = query_spy[0]
28
28
  assert database == "main"
@@ -32,21 +32,21 @@ async def test_list_relations_binds_all_filters(query_spy):
32
32
  assert "information_schema" not in sql
33
33
  assert schemas == ["public"]
34
34
  assert kinds == ["BASE TABLE"]
35
- assert excluded == ["graveyard"]
35
+ assert excluded == ["deprecated"]
36
36
 
37
37
 
38
38
  @pytest.mark.asyncio
39
39
  async def test_relation_discovery_and_description_bind_values(query_spy):
40
40
  await catalog.application_schemas("main", exclude_schemas=["pg_catalog"])
41
41
  await catalog.relation_schemas(
42
- "main", table="message", exclude_schemas=["graveyard"]
42
+ "main", table="message", exclude_schemas=["deprecated"]
43
43
  )
44
44
  await catalog.describe_relation_columns(
45
45
  "main", schema="chat", table="message"
46
46
  )
47
47
 
48
48
  assert query_spy[0][2:] == (["pg_catalog"],)
49
- assert query_spy[1][2:] == ("message", ["graveyard"])
49
+ assert query_spy[1][2:] == ("message", ["deprecated"])
50
50
  assert query_spy[2][2:] == ("chat", "message")
51
51
  # These decide EXISTENCE, so they must be privilege-independent.
52
52
  assert "pg_namespace" in query_spy[0][1]
@@ -164,7 +164,7 @@ async def test_declared_context_and_rls_settings_share_one_round_trip_role_last(
164
164
  monkeypatch: pytest.MonkeyPatch,
165
165
  ) -> None:
166
166
  """The host's declared context, the ceilings and the RLS settings: ONE statement."""
167
- monkeypatch.setattr(session_context, "_provider", lambda: {"app.actor_tier": "human"})
167
+ monkeypatch.setattr(session_context, "_provider", lambda: {"app.actor_tier": "user"})
168
168
  monkeypatch.setattr(transaction_module, "_TRANSACTION_CEILINGS", {"lock_timeout": "5000"})
169
169
  conn, _adapter = _install_adapter(monkeypatch)
170
170