matrx-orm 3.1.170__tar.gz → 3.1.172__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 (399) hide show
  1. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/PKG-INFO +1 -1
  2. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/rls_session.py +22 -6
  3. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/FEATURE.md +3 -1
  4. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/items.py +105 -11
  5. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/pyproject.toml +1 -1
  6. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_vault_aggregate_recovery_stateful.py +120 -3
  7. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/.gitignore +0 -0
  8. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/AGENTS.md +0 -0
  9. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/BASE_CLASS_METHODS.md +0 -0
  10. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/CLAUDE.md +0 -0
  11. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/MODEL_API.md +0 -0
  12. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/README.md +0 -0
  13. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/database/orm/extended/managers/ai_model_base.py +0 -0
  14. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/docs/migrations.md +0 -0
  15. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/FEATURE.md +0 -0
  16. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/MODULE_README.md +0 -0
  17. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/__init__.py +0 -0
  18. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/adapters/MODULE_README.md +0 -0
  19. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/adapters/__init__.py +0 -0
  20. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/adapters/async_postgresql.py +0 -0
  21. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/adapters/base_adapter.py +0 -0
  22. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/adapters/postgrest_client_adapter.py +0 -0
  23. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/adapters/supabase_adapter.py +0 -0
  24. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/admin/FEATURE.md +0 -0
  25. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/admin/__init__.py +0 -0
  26. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/admin/router.py +0 -0
  27. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/api/__init__.py +0 -0
  28. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/api/auth.py +0 -0
  29. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/api/config.py +0 -0
  30. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/api/handlers.py +0 -0
  31. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/api/protocol.py +0 -0
  32. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/api/server.py +0 -0
  33. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/associations.py +0 -0
  34. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/cache_debug.py +0 -0
  35. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/catalog.py +0 -0
  36. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/catalog_sql.py +0 -0
  37. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/MODULE_README.md +0 -0
  38. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/__init__.py +0 -0
  39. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/postgres_connection.py +0 -0
  40. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/postgrest.py +0 -0
  41. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/supabase_auth.py +0 -0
  42. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/supabase_config.py +0 -0
  43. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/client/supabase_manager.py +0 -0
  44. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/EXTENDED-TASK.md +0 -0
  45. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/FEATURE.md +0 -0
  46. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/MODULE_README.md +0 -0
  47. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/RELATIONS-TASKS.md +0 -0
  48. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/TASKS.md +0 -0
  49. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/__init__.py +0 -0
  50. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/async_db_manager.py +0 -0
  51. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/base.py +0 -0
  52. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/config.py +0 -0
  53. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/connections.py +0 -0
  54. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/db_function.py +0 -0
  55. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/diagnostics.py +0 -0
  56. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/expressions.py +0 -0
  57. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/extended.py +0 -0
  58. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/fields.py +0 -0
  59. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/introspection.py +0 -0
  60. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/listen.py +0 -0
  61. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/loop_filters.py +0 -0
  62. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/model_dto.py +0 -0
  63. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/model_view.py +0 -0
  64. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/one_database.py +0 -0
  65. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/paginator.py +0 -0
  66. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/pool_maintenance.py +0 -0
  67. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/pool_watch.py +0 -0
  68. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/pooler_role.py +0 -0
  69. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/pydantic_bridge.py +0 -0
  70. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/registry.py +0 -0
  71. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/relations.py +0 -0
  72. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/resilience.py +0 -0
  73. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/session_context.py +0 -0
  74. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/signals.py +0 -0
  75. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/tls.py +0 -0
  76. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/transaction.py +0 -0
  77. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/types.py +0 -0
  78. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/write_queue.py +0 -0
  79. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/core/write_retry.py +0 -0
  80. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/entity.py +0 -0
  81. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/error_handling.py +0 -0
  82. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/exceptions.py +0 -0
  83. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/extended/__init__.py +0 -0
  84. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/extended/app_error_handler.py +0 -0
  85. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/identity_rule.py +0 -0
  86. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/local_sqlite.py +0 -0
  87. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/middleware/__init__.py +0 -0
  88. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/middleware/base.py +0 -0
  89. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/MODULE_README.md +0 -0
  90. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/__init__.py +0 -0
  91. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/cli.py +0 -0
  92. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/ddl.py +0 -0
  93. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/diff.py +0 -0
  94. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/executor.py +0 -0
  95. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/integration.py +0 -0
  96. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/loader.py +0 -0
  97. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/operations.py +0 -0
  98. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/state.py +0 -0
  99. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/migrations/table_filter.py +0 -0
  100. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/no_org_assignment.py +0 -0
  101. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/FEATURE.md +0 -0
  102. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/MODULE_README.md +0 -0
  103. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/__init__.py +0 -0
  104. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/bulk_update_values.py +0 -0
  105. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/catalog_select.py +0 -0
  106. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/conflict.py +0 -0
  107. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/conflict_writes.py +0 -0
  108. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/create.py +0 -0
  109. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/db_functions.py +0 -0
  110. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/delete.py +0 -0
  111. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/dynamic_admin.py +0 -0
  112. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/dynamic_crud.py +0 -0
  113. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/graph_walk.py +0 -0
  114. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/latest_rows.py +0 -0
  115. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/queue_claim.py +0 -0
  116. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/read.py +0 -0
  117. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/relational_backfill.py +0 -0
  118. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/staging_load.py +0 -0
  119. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/operations/update.py +0 -0
  120. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/platform_access.py +0 -0
  121. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/platform_db.py +0 -0
  122. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/py.typed +0 -0
  123. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/pytest_lock_guard.py +0 -0
  124. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/pytest_plugin.py +0 -0
  125. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/python_sql/MODULE_README.md +0 -0
  126. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/python_sql/__init__.py +0 -0
  127. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/python_sql/db_objects.py +0 -0
  128. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/python_sql/table_detailed_relationships.py +0 -0
  129. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/python_sql/table_typescript_relationship.py +0 -0
  130. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/query/FEATURE.md +0 -0
  131. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/query/MODULE_README.md +0 -0
  132. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/query/__init__.py +0 -0
  133. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/query/builder.py +0 -0
  134. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/query/executor.py +0 -0
  135. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/resources/__init__.py +0 -0
  136. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/resources/additional-assigners-2026-09-12.json +0 -0
  137. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/resources/org_assignment_trigger_baseline.json +0 -0
  138. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/FEATURE.md +0 -0
  139. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/MODULE_README.md +0 -0
  140. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/__init__.py +0 -0
  141. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/code_handler.py +0 -0
  142. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/codegen_writer.py +0 -0
  143. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/columns.py +0 -0
  144. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/common.py +0 -0
  145. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/diff_preview.py +0 -0
  146. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/entity_capabilities.py +0 -0
  147. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/generator.py +0 -0
  148. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/helpers/__init__.py +0 -0
  149. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/helpers/base_generators.py +0 -0
  150. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/helpers/entity_generators.py +0 -0
  151. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/helpers/git_checker.py +0 -0
  152. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/package_wiring.py +0 -0
  153. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/relationships.py +0 -0
  154. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/runner.py +0 -0
  155. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/schema.py +0 -0
  156. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/schema_manager.py +0 -0
  157. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/tables.py +0 -0
  158. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/schema_builder/views.py +0 -0
  159. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/__init__.py +0 -0
  160. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/attachments.py +0 -0
  161. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/crypto.py +0 -0
  162. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/host_authorization.py +0 -0
  163. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/model.py +0 -0
  164. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/mutation_receipts.py +0 -0
  165. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/native_enable.py +0 -0
  166. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/native_lifecycle.py +0 -0
  167. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/native_passkeys.py +0 -0
  168. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/native_source.py +0 -0
  169. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/org_service.py +0 -0
  170. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/secrets_battery/service.py +0 -0
  171. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/README.md +0 -0
  172. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/__init__.py +0 -0
  173. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/coalesce.py +0 -0
  174. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/dag.py +0 -0
  175. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/errors.py +0 -0
  176. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/fallback.py +0 -0
  177. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/flush.py +0 -0
  178. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/lifecycle.py +0 -0
  179. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/managed.py +0 -0
  180. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/op.py +0 -0
  181. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/reads.py +0 -0
  182. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/session.py +0 -0
  183. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/session/telemetry.py +0 -0
  184. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/MODULE_README.md +0 -0
  185. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/__init__.py +0 -0
  186. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/executor.py +0 -0
  187. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/queries.py +0 -0
  188. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/registry.py +0 -0
  189. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/types.py +0 -0
  190. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/sql_executor/utils.py +0 -0
  191. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/state.py +0 -0
  192. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/utils/__init__.py +0 -0
  193. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/utils/sql_utils.py +0 -0
  194. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/utils/type_converters.py +0 -0
  195. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/matrx_orm/write_actor.py +0 -0
  196. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/scripts/git-branches.sh +0 -0
  197. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/scripts/publish.sh +0 -0
  198. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/scripts/release.sh +0 -0
  199. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/MODULE_README.md +0 -0
  200. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/__init__.py +0 -0
  201. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/conftest.py +0 -0
  202. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/MODULE_README.md +0 -0
  203. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/__init__.py +0 -0
  204. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_adapter_registry.py +0 -0
  205. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_admin_db_columns.py +0 -0
  206. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_admin_response_rendering.py +0 -0
  207. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_admin_search_negation.py +0 -0
  208. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_admin_search_sentinels.py +0 -0
  209. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_advisory_lock.py +0 -0
  210. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_agent_message.py +0 -0
  211. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_api_auth.py +0 -0
  212. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_api_config.py +0 -0
  213. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_api_handlers.py +0 -0
  214. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_api_protocol.py +0 -0
  215. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_array_agg_order_by.py +0 -0
  216. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_associations.py +0 -0
  217. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_associations_wiring.py +0 -0
  218. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_bulk_hydration_offload.py +0 -0
  219. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_bulk_update_by_pk.py +0 -0
  220. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_bulk_upsert_increment_set_fields.py +0 -0
  221. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_cache_debug.py +0 -0
  222. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_call_function.py +0 -0
  223. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_case_when.py +0 -0
  224. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_catalog.py +0 -0
  225. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_committed_row_guard.py +0 -0
  226. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_composite_pk_filter.py +0 -0
  227. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_composite_pk_write_paths.py +0 -0
  228. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_config.py +0 -0
  229. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_conflict_target.py +0 -0
  230. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_conflict_writes.py +0 -0
  231. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_connection_codecs.py +0 -0
  232. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_connection_poison_guard.py +0 -0
  233. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_connection_primitives.py +0 -0
  234. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_count_composite_distinct.py +0 -0
  235. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_count_limit_param_leak.py +0 -0
  236. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_db_function_field.py +0 -0
  237. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_ddl_generator.py +0 -0
  238. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_deadlock_retry.py +0 -0
  239. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_derived_table.py +0 -0
  240. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_dirty_tracking.py +0 -0
  241. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_dynamic_crud.py +0 -0
  242. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_exceptions.py +0 -0
  243. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_execute_query_integrity_mapping.py +0 -0
  244. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_expression_primitives.py +0 -0
  245. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_fields.py +0 -0
  246. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_filter_jsonb_agg_array_index.py +0 -0
  247. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_from_alias.py +0 -0
  248. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_fts.py +0 -0
  249. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_func_expression_args.py +0 -0
  250. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_graph_walk.py +0 -0
  251. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_having_annotate_alias.py +0 -0
  252. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_insert_ignore_and_admin_primitives.py +0 -0
  253. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_introspect_rls_policies.py +0 -0
  254. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_join_and_aggregate.py +0 -0
  255. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_latest_rows.py +0 -0
  256. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_listen_notify.py +0 -0
  257. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_local_sqlite.py +0 -0
  258. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_lock_contention_retry.py +0 -0
  259. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_managed_write_guard.py +0 -0
  260. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_matrx_entity.py +0 -0
  261. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_migration_diff_types.py +0 -0
  262. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_migration_loader.py +0 -0
  263. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_model_instance.py +0 -0
  264. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_model_meta.py +0 -0
  265. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_optimistic_concurrency.py +0 -0
  266. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_order_by_expression.py +0 -0
  267. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_org_assignment_inventory.py +0 -0
  268. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_orm_banners_are_client_safe.py +0 -0
  269. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_parameter_name_hydration.py +0 -0
  270. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_patch_jsonb_path.py +0 -0
  271. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_persisted_count.py +0 -0
  272. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_pool_holder_census.py +0 -0
  273. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_pool_loop_recreation.py +0 -0
  274. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_pool_maintenance.py +0 -0
  275. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_postgrest_filters.py +0 -0
  276. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_pydantic_bridge.py +0 -0
  277. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_query_builder.py +0 -0
  278. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_query_error_detail.py +0 -0
  279. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_query_executor_sql.py +0 -0
  280. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_query_timeout.py +0 -0
  281. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_querybuilder_clone_semantics.py +0 -0
  282. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_queue_claim.py +0 -0
  283. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_read_connection_retry.py +0 -0
  284. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_registry.py +0 -0
  285. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_registry_multi_database.py +0 -0
  286. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_registry_multi_schema.py +0 -0
  287. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_relational_backfill.py +0 -0
  288. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_relations.py +0 -0
  289. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_resilience.py +0 -0
  290. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_rls_session_scope.py +0 -0
  291. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_schema_exists.py +0 -0
  292. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_session_advisory_lock.py +0 -0
  293. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_standalone_write_session_context.py +0 -0
  294. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_state_cache.py +0 -0
  295. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_subquery_filter_raw.py +0 -0
  296. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_subquery_in_filter.py +0 -0
  297. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_subquery_nested_expressions.py +0 -0
  298. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_supabase_auth.py +0 -0
  299. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_supabase_config.py +0 -0
  300. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_tls.py +0 -0
  301. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_transaction_database_identity.py +0 -0
  302. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_typed_join_projection.py +0 -0
  303. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_typed_predicates.py +0 -0
  304. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_update_case_expression.py +0 -0
  305. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_update_subquery.py +0 -0
  306. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_update_with_rebase.py +0 -0
  307. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_upsert_default_leak.py +0 -0
  308. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_upsert_with_conflict.py +0 -0
  309. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_values_jsonb_decode.py +0 -0
  310. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_watched_lifecycle.py +0 -0
  311. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_write_queue_deadline.py +0 -0
  312. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level1/test_write_retry_semantics.py +0 -0
  313. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/MODULE_README.md +0 -0
  314. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/__init__.py +0 -0
  315. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/conftest.py +0 -0
  316. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_bulk_ops.py +0 -0
  317. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_cache_integration.py +0 -0
  318. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_crud.py +0 -0
  319. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_foreign_keys.py +0 -0
  320. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_m2m.py +0 -0
  321. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_manager.py +0 -0
  322. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_migrations_live.py +0 -0
  323. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_query_execution.py +0 -0
  324. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/test_schema_diff.py +0 -0
  325. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/level2/verify_committed_row_guard_pg17.py +0 -0
  326. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/live_pooler_role.py +0 -0
  327. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/native_source_cases.py +0 -0
  328. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/native_source_oracle.rs +0 -0
  329. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/.env.example +0 -0
  330. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/README.md +0 -0
  331. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/__init__.py +0 -0
  332. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/generate.py +0 -0
  333. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/generated/.gitkeep +0 -0
  334. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/matrx_orm.yaml +0 -0
  335. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project/test_schema_generation.py +0 -0
  336. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/.env.example +0 -0
  337. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/README.md +0 -0
  338. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/__init__.py +0 -0
  339. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/client_example.py +0 -0
  340. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/client_example.ts +0 -0
  341. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/client_supabase_example.py +0 -0
  342. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/sample_project_desktop/server.py +0 -0
  343. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/entity_tests.py +0 -0
  344. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_base_generation.py +0 -0
  345. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_composite_pk_fk_generation.py +0 -0
  346. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_composite_unique_generation.py +0 -0
  347. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_dto_identity_generation.py +0 -0
  348. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_entity_capability_generation.py +0 -0
  349. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_enum_ordering.py +0 -0
  350. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_generate_schema.py +0 -0
  351. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_junction_analysis.py +0 -0
  352. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_multi_schema_output.py +0 -0
  353. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_schema_analysis.py +0 -0
  354. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_sql_expression_defaults.py +0 -0
  355. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_table_relationships_query.py +0 -0
  356. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema/test_view_generation.py +0 -0
  357. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema_builder/test_array_default_parsing.py +0 -0
  358. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema_builder/test_focused_generation_plan.py +0 -0
  359. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/schema_builder/test_host_models_aggregator.py +0 -0
  360. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/__init__.py +0 -0
  361. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/conftest.py +0 -0
  362. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_cache_no_downgrade.py +0 -0
  363. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_capture_poison_proof.py +0 -0
  364. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_coalesce.py +0 -0
  365. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_dag.py +0 -0
  366. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_disk_spill_fallback.py +0 -0
  367. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_flush_individual_fallback.py +0 -0
  368. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_governed_write.py +0 -0
  369. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_managed.py +0 -0
  370. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_op_enqueue_site.py +0 -0
  371. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_reads.py +0 -0
  372. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_record_error_bounded_insert.py +0 -0
  373. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_record_error_storm.py +0 -0
  374. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_session.py +0 -0
  375. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/session/test_spill_guard_plugin.py +0 -0
  376. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_array_arg_element_type.py +0 -0
  377. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_attachment_mutation_serialization.py +0 -0
  378. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_database_name_alias.py +0 -0
  379. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_db_functions.py +0 -0
  380. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_dynamic_select_unregistered.py +0 -0
  381. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_immutable_insert_or_exact_verify.py +0 -0
  382. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_keyed_digest.py +0 -0
  383. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_model_cls_refactor.py +0 -0
  384. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_native_enable.py +0 -0
  385. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_native_lifecycle.py +0 -0
  386. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_native_lifecycle_fences.py +0 -0
  387. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_native_passkey_receipts.py +0 -0
  388. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_native_source.py +0 -0
  389. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_no_blocking_asyncpg_tls.py +0 -0
  390. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_one_database.py +0 -0
  391. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_order_by_desc_nulls_last.py +0 -0
  392. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_pooler_role_guard.py +0 -0
  393. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_secret_audit_names_its_organization.py +0 -0
  394. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_secrets_battery.py +0 -0
  395. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_secrets_minting_keys.py +0 -0
  396. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_shared_lock_guard.py +0 -0
  397. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_sql_param_casts.py +0 -0
  398. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_sync_twins_guard.py +0 -0
  399. {matrx_orm-3.1.170 → matrx_orm-3.1.172}/tests/test_user_visible_lookup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matrx-orm
3
- Version: 3.1.170
3
+ Version: 3.1.172
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
@@ -98,12 +98,28 @@ async def rls_session(
98
98
  details={"role": role},
99
99
  )
100
100
  # Set the verified claims FIRST (while still the privileged role), then drop to
101
- # the restricted role. Order mirrors PostgREST; both are transaction-local and
102
- # survive the role switch within the same transaction.
103
- await conn.execute("select set_config('request.jwt.claims', $1, true)", claims_json)
101
+ # the restricted role. Order mirrors PostgREST; all of them are transaction-local
102
+ # (`set_config(..., true)` IS `SET LOCAL`) and survive the role switch within the
103
+ # same transaction.
104
+ #
105
+ # ONE ROUND TRIP, NOT FOUR. These were four sequential `execute` calls, and a
106
+ # round trip to a hosted pooler is not free: measured 2026-09-19 against the main
107
+ # database, the three that always run cost 0.247 + 0.085 + 0.105 = 0.437 s
108
+ # separately and 0.192 s as one statement — so every RLS session on the platform
109
+ # paid a quarter of a second to say three things it could say at once. They are
110
+ # emitted in the SAME ORDER inside one target list, which is the order that
111
+ # matters: the claims land before the role drops. `SET LOCAL ROLE x` and
112
+ # `set_config('role', 'x', true)` are the same GUC write, so the role still
113
+ # changes here and nowhere else, and `role` stays LAST.
114
+ settings: list[str] = ["set_config('request.jwt.claims', $1, true)"]
115
+ bound: list[str] = [claims_json]
104
116
  if statement_timeout_ms is not None:
105
- await conn.execute(f"SET LOCAL statement_timeout = {int(statement_timeout_ms)}")
117
+ bound.append(str(int(statement_timeout_ms)))
118
+ settings.append(f"set_config('statement_timeout', ${len(bound)}, true)")
106
119
  if lock_timeout_ms is not None:
107
- await conn.execute(f"SET LOCAL lock_timeout = {int(lock_timeout_ms)}")
108
- await conn.execute(f"SET LOCAL ROLE {role}")
120
+ bound.append(str(int(lock_timeout_ms)))
121
+ settings.append(f"set_config('lock_timeout', ${len(bound)}, true)")
122
+ bound.append(role)
123
+ settings.append(f"set_config('role', ${len(bound)}, true)")
124
+ await conn.execute("select " + ", ".join(settings), *bound)
109
125
  yield
@@ -66,7 +66,7 @@ remains atomic.
66
66
 
67
67
  **Native source admission (`native_source.py`).** `validate_native_source` is the server reader of the provider's exact source-v1 byte format; Rust remains the encoder and authenticator. It requires an explicit positive source-size limit, preserves nullable names and bytes, rejects duplicate/noncanonical JSON and COSE, and derives public metadata only after maintained P-256 key-pair validation. The result is provider-custody data, never a response model or generic field. `repr` and fixed failures omit material. `scripts/check_native_source_parity.py --rust-core <native-vault-provider/core>` compares the real compiled Rust reader against the server corpus; no mocked oracle. This prerequisite adds no creator, materializer, database row or native readiness. Verified September19 against132 focused tests and525 cross-language cases.
68
68
 
69
- **Native lifecycle component (`native_lifecycle.py`).** The shared coordinator must supply locked parent/child projections from the exported field constants, current host management authority and its active transaction. Inspection locks the exact native metadata child; component delete/restore mutate only that child's tombstone and lifecycle. Deletion accepts active and restored-quarantined sources; recovery compares aware ISO manifest timestamps to database timestamps. Personal metadata provenance is enforced by the database guard, never inferred from the request scope. Coordinator/preview integration and actual aggregate database acceptance remain pending; these helpers alone do not enable protected recovery. Contract: [native lifecycle](../../../../../common-docs/projects/credential-sharing-browser-login/NATIVE-LIFECYCLE.md).
69
+ **Native lifecycle component (`native_lifecycle.py`).** The shared coordinator must supply locked parent/child projections from the exported field constants, current host management authority and its active transaction. Inspection locks the exact native metadata child; component delete/restore mutate only that child's tombstone and lifecycle. Deletion accepts active and restored-quarantined sources; recovery compares aware ISO manifest timestamps to database timestamps, then parses the already-validated manifest instant only at the typed native restore mutation boundary. Personal metadata provenance is enforced by the database guard, never inferred from the request scope. Coordinator/preview integration and actual aggregate database acceptance remain pending; these helpers alone do not enable protected recovery. Contract: [native lifecycle](../../../../../common-docs/projects/credential-sharing-browser-login/NATIVE-LIFECYCLE.md).
70
70
 
71
71
  **`inject_into_sandbox=true` REQUIRES an env alias — refused otherwise.** A
72
72
  container environment is a NAME→value map, so a field with `key IS NULL` has
@@ -365,6 +365,8 @@ delete).
365
365
 
366
366
  ## Change Log
367
367
 
368
+ - **2026-09-19** — Restored native lifecycle metadata with the parsed, timezone-aware manifest instant at the typed mutation boundary, preserving the manifest string for aggregate integrity checks.
369
+
368
370
  - **2026-09-19** — Added transaction-owned native lifecycle component operations, quarantine deletion and aware timestamp validation; aggregate coordinator integration remains open.
369
371
 
370
372
  - **2026-09-19** — Added `native_enable.py`, a transaction-required, value-free
@@ -896,17 +896,26 @@ async def delete_credential_item(
896
896
  raw = await _lock_item_raw(item_id)
897
897
  from .attachments import soft_delete_item_attachments
898
898
 
899
+ # Keep the native lifecycle's complete locked projection here. The
900
+ # classifier deliberately owns the metadata lock, while the aggregate
901
+ # coordinator remains the only author of parent/source changes.
902
+ from .native_lifecycle import (
903
+ NATIVE_LIFECYCLE_ATTACHMENT_FIELDS,
904
+ NATIVE_LIFECYCLE_FIELD_FIELDS,
905
+ delete_native_component,
906
+ inspect_native_lifecycle,
907
+ )
908
+
899
909
  fields = await (
900
910
  UserSecret.filter(credential_item_id=item_id, deleted_at__isnull=True)
901
- .select_for_update().order_by("id")
902
- .values("id", "is_active", "user_id", "organization_id")
911
+ .select_for_update().order_by("id").values(*NATIVE_LIFECYCLE_FIELD_FIELDS)
903
912
  )
904
913
  for child in fields:
905
914
  if child.get("user_id") != raw.get("user_id") or child.get("organization_id") != raw.get("organization_id"):
906
915
  raise CredentialRestoreConflictError("credential field ownership does not match parent")
907
916
  attachments = await (
908
917
  CredentialAttachment.filter(credential_item_id=item_id, deleted_at__isnull=True)
909
- .select_for_update().order_by("id").values("id")
918
+ .select_for_update().order_by("id").values(*NATIVE_LIFECYCLE_ATTACHMENT_FIELDS)
910
919
  )
911
920
  # A legacy field grant can otherwise survive a parent delete and become
912
921
  # usable if a future path reactivates the field.
@@ -916,6 +925,15 @@ async def delete_credential_item(
916
925
  ).values("id")]
917
926
  if bound_field_ids:
918
927
  await UserSecretGrant.delete_where(user_secret_id__in=bound_field_ids)
928
+ native_component = await inspect_native_lifecycle(
929
+ {**raw, "deleted_at": None}, fields, attachments, actor_id=actor_id,
930
+ audit_organization_id=audit_organization_id, state="live", deletion_timestamp=None,
931
+ )
932
+ if native_component is not None:
933
+ await delete_native_component(
934
+ native_component, parent_id=item_id, actor_id=actor_id,
935
+ audit_organization_id=audit_organization_id, deleted_at=now,
936
+ )
919
937
  await soft_delete_item_attachments(item_id, actor_id=actor_id, deleted_at=now)
920
938
  await UserSecret.update_where(
921
939
  {"credential_item_id": item_id, "deleted_at__isnull": True},
@@ -924,7 +942,7 @@ async def delete_credential_item(
924
942
  updated_at=now,
925
943
  )
926
944
  lifecycle = dict(raw.get("lifecycle") or {})
927
- lifecycle["vault_recovery"] = {
945
+ manifest: dict[str, Any] = {
928
946
  "schema_version": 1,
929
947
  "deletion_id": str(uuid.uuid4()),
930
948
  "deleted_at": now.isoformat(),
@@ -933,6 +951,13 @@ async def delete_credential_item(
933
951
  "attachments": [{"id": str(row["id"])} for row in attachments],
934
952
  "state": "deleted",
935
953
  }
954
+ if native_component is not None:
955
+ manifest["schema_version"] = 2
956
+ manifest["native_passkeys"] = [{
957
+ "id": native_component.passkey_id,
958
+ "source_field_id": native_component.source_field_id,
959
+ }]
960
+ lifecycle["vault_recovery"] = manifest
936
961
  await CredentialItem.update_where(
937
962
  {"id": item_id, "deleted_at__isnull": True},
938
963
  deleted_at=now,
@@ -956,12 +981,13 @@ async def delete_credential_item(
956
981
 
957
982
  def _recovery_manifest(raw: dict[str, Any], deletion_id: str) -> dict[str, Any]:
958
983
  recovery = dict(raw.get("lifecycle") or {}).get("vault_recovery")
959
- manifest_keys = {
984
+ manifest_v1_keys = {
960
985
  "schema_version", "deletion_id", "deleted_at", "prior_status",
961
986
  "fields", "attachments", "state",
962
987
  }
963
- if not isinstance(recovery, dict) or type(recovery.get("schema_version")) is not int or recovery.get("schema_version") != 1:
988
+ if not isinstance(recovery, dict) or type(recovery.get("schema_version")) is not int or recovery.get("schema_version") not in {1, 2}:
964
989
  raise CredentialRestoreConflictError("automatic recovery is unavailable for this deletion")
990
+ manifest_keys = manifest_v1_keys | ({"native_passkeys"} if recovery["schema_version"] == 2 else set())
965
991
  if set(recovery) != manifest_keys:
966
992
  raise CredentialRestoreConflictError("deletion record has unexpected or missing fields")
967
993
  if not isinstance(recovery.get("deletion_id"), str) or recovery.get("deletion_id") != deletion_id:
@@ -1009,6 +1035,23 @@ def _recovery_manifest(raw: dict[str, Any], deletion_id: str) -> dict[str, Any]:
1009
1035
  attachment_ids.append(entry["id"])
1010
1036
  if len(set(field_ids)) != len(field_ids) or len(set(attachment_ids)) != len(attachment_ids):
1011
1037
  raise CredentialRestoreConflictError("deletion record contains duplicate components")
1038
+ if recovery["schema_version"] == 2:
1039
+ native = recovery.get("native_passkeys")
1040
+ if not isinstance(native, list) or len(native) != 1:
1041
+ raise CredentialRestoreConflictError("native deletion record is invalid")
1042
+ entry = native[0]
1043
+ if not isinstance(entry, dict) or set(entry) != {"id", "source_field_id"}:
1044
+ raise CredentialRestoreConflictError("native deletion record is invalid")
1045
+ try:
1046
+ passkey_id, source_id = entry["id"], entry["source_field_id"]
1047
+ if not isinstance(passkey_id, str) or not isinstance(source_id, str):
1048
+ raise ValueError
1049
+ if str(uuid.UUID(passkey_id)) != passkey_id or str(uuid.UUID(source_id)) != source_id:
1050
+ raise ValueError
1051
+ except (KeyError, TypeError, ValueError) as exc:
1052
+ raise CredentialRestoreConflictError("native deletion record is invalid") from exc
1053
+ if source_id not in field_ids:
1054
+ raise CredentialRestoreConflictError("native source is absent from deletion fields")
1012
1055
  parent_deleted_at = raw.get("deleted_at")
1013
1056
  if recovery["state"] == "deleted":
1014
1057
  if parent_deleted_at is None or _iso(parent_deleted_at) != recovery["deleted_at"]:
@@ -1031,7 +1074,7 @@ async def restore_credential_item(
1031
1074
  async with transaction(PACKAGE_DB_NAME):
1032
1075
  raw = await _lock_restore_item_raw(item_id)
1033
1076
  manifest = _recovery_manifest(raw, deletion_id)
1034
- if manifest["state"] == "restored":
1077
+ if manifest["state"] == "restored" and manifest["schema_version"] == 1:
1035
1078
  item = await get_credential_item(item_id)
1036
1079
  if item is None: # pragma: no cover
1037
1080
  raise CredentialRestoreConflictError("restore state is inconsistent")
@@ -1043,19 +1086,49 @@ async def restore_credential_item(
1043
1086
  raise CredentialRestoreConflictError("deletion record is incomplete")
1044
1087
  field_ids = sorted(entry["id"] for entry in field_entries)
1045
1088
  attachment_ids = sorted(entry["id"] for entry in attachment_entries)
1089
+ from .native_lifecycle import (
1090
+ NATIVE_LIFECYCLE_ATTACHMENT_FIELDS,
1091
+ NATIVE_LIFECYCLE_FIELD_FIELDS,
1092
+ inspect_native_lifecycle,
1093
+ restore_native_component,
1094
+ )
1046
1095
  fields = await UserSecret.filter(id__in=field_ids).select_for_update().order_by("id").values(
1047
- "id", "credential_item_id", "user_id", "organization_id", "deleted_at", "execution_purpose", "field_key"
1096
+ *NATIVE_LIFECYCLE_FIELD_FIELDS
1048
1097
  ) if field_ids else []
1049
1098
  attachments = await CredentialAttachment.filter(id__in=attachment_ids).select_for_update().order_by("id").values(
1050
- "id", "credential_item_id", "deleted_at"
1099
+ *NATIVE_LIFECYCLE_ATTACHMENT_FIELDS
1051
1100
  ) if attachment_ids else []
1052
1101
  if {str(row["id"]) for row in fields} != set(field_ids) or {str(row["id"]) for row in attachments} != set(attachment_ids):
1053
1102
  raise CredentialRestoreConflictError("a deleted component is no longer retained")
1103
+ all_fields = await UserSecret.filter(credential_item_id=item_id).select_for_update().order_by("id").values(
1104
+ *NATIVE_LIFECYCLE_FIELD_FIELDS
1105
+ )
1106
+ unrecorded_protected = [
1107
+ field for field in all_fields
1108
+ if field.get("execution_purpose") != GENERAL_EXECUTION_PURPOSE and str(field.get("id")) not in set(field_ids)
1109
+ ]
1110
+ if unrecorded_protected:
1111
+ raise CredentialRestoreUnsupportedError("unrecorded protected component needs its owning recovery flow")
1112
+ if manifest["state"] == "restored":
1113
+ expected = manifest["native_passkeys"][0]
1114
+ native_component = await inspect_native_lifecycle(
1115
+ raw, all_fields, attachments, actor_id=actor_id,
1116
+ audit_organization_id=audit_organization_id, state="live", deletion_timestamp=None,
1117
+ )
1118
+ if native_component is None or (
1119
+ native_component.passkey_id != expected["id"]
1120
+ or native_component.source_field_id != expected["source_field_id"]
1121
+ ):
1122
+ raise CredentialRestoreConflictError("native component no longer matches this deletion")
1123
+ item = await get_credential_item(item_id)
1124
+ if item is None: # pragma: no cover
1125
+ raise CredentialRestoreConflictError("restore state is inconsistent")
1126
+ return item, 0, 0, True
1054
1127
  for field in fields:
1055
1128
  if (str(field.get("credential_item_id")) != item_id or field.get("user_id") != raw.get("user_id")
1056
1129
  or field.get("organization_id") != raw.get("organization_id") or _iso(field.get("deleted_at")) != deleted_at):
1057
1130
  raise CredentialRestoreConflictError("a field no longer matches this deletion")
1058
- if field.get("execution_purpose") != GENERAL_EXECUTION_PURPOSE or field.get("field_key") == PROTECTED_FIELD_KEY:
1131
+ if manifest["schema_version"] == 1 and (field.get("execution_purpose") != GENERAL_EXECUTION_PURPOSE or field.get("field_key") == PROTECTED_FIELD_KEY):
1059
1132
  raise CredentialRestoreUnsupportedError("passkey or protected field recovery needs its native recovery flow")
1060
1133
  if field.get("field_key") == "totp_seed":
1061
1134
  await require_host_authorization(
@@ -1065,6 +1138,27 @@ async def restore_credential_item(
1065
1138
  for attachment in attachments:
1066
1139
  if str(attachment.get("credential_item_id")) != item_id or _iso(attachment.get("deleted_at")) != deleted_at:
1067
1140
  raise CredentialRestoreConflictError("an attachment no longer matches this deletion")
1141
+ native_component = None
1142
+ if manifest["schema_version"] == 2:
1143
+ native_component = await inspect_native_lifecycle(
1144
+ raw, fields, attachments, actor_id=actor_id, audit_organization_id=audit_organization_id,
1145
+ state="deleted", deletion_timestamp=deleted_at,
1146
+ )
1147
+ if manifest["schema_version"] == 2:
1148
+ expected = manifest["native_passkeys"][0]
1149
+ if native_component is None or (
1150
+ native_component.passkey_id != expected["id"]
1151
+ or native_component.source_field_id != expected["source_field_id"]
1152
+ ):
1153
+ raise CredentialRestoreConflictError("native component no longer matches this deletion")
1154
+ if native_component is not None:
1155
+ # The manifest persists an exact ISO string for integrity comparison;
1156
+ # the typed native mutation owns a timestamptz equality predicate.
1157
+ native_deleted_at = datetime.fromisoformat(deleted_at)
1158
+ await restore_native_component(
1159
+ native_component, parent_id=item_id, actor_id=actor_id,
1160
+ audit_organization_id=audit_organization_id, deleted_at=native_deleted_at,
1161
+ )
1068
1162
  # Do not turn a hidden uniqueness violation into a generic DB error.
1069
1163
  # Field-key identity is local to its credential item; environment
1070
1164
  # aliases are separately unique in the item's owner namespace.
@@ -1107,7 +1201,7 @@ async def restore_credential_item(
1107
1201
  await record_secret_audit(action="item_restored_quarantined", actor_id=actor_id,
1108
1202
  organization_id=audit_organization(record_organization_id=raw.get("organization_id"), request_organization_id=audit_organization_id, what=f"restore_credential_item(item_id={item_id})"),
1109
1203
  user_id=str(raw["user_id"]) if raw.get("user_id") else None,
1110
- metadata={"credential_item_id": item_id, "deletion_id": deletion_id, "restored_fields": len(fields), "restored_attachments": len(attachments)})
1204
+ metadata={"credential_item_id": item_id, "deletion_id": deletion_id, "restored_fields": len(fields), "restored_attachments": len(attachments), "restored_native_passkeys": 1 if manifest["schema_version"] == 2 else 0})
1111
1205
  item = await get_credential_item(item_id)
1112
1206
  if item is None: # pragma: no cover
1113
1207
  raise CredentialRestoreConflictError("restored item is unavailable")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "matrx-orm"
3
- version = "3.1.170"
3
+ version = "3.1.172"
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" }
@@ -16,6 +16,7 @@ import pytest
16
16
 
17
17
  from matrx_orm.secrets_battery import attachments as attachments_mod
18
18
  from matrx_orm.secrets_battery import items as items_mod
19
+ from matrx_orm.secrets_battery import native_lifecycle
19
20
  from matrx_orm.secrets_battery import service as service_mod
20
21
 
21
22
 
@@ -26,6 +27,7 @@ INACTIVE_FIELD = "00000000-0000-0000-0000-000000000012"
26
27
  OLD_FIELD = "00000000-0000-0000-0000-000000000013"
27
28
  ATTACHMENT = "00000000-0000-0000-0000-000000000021"
28
29
  OLD_ATTACHMENT = "00000000-0000-0000-0000-000000000022"
30
+ PASSKEY = "00000000-0000-0000-0000-000000000031"
29
31
 
30
32
 
31
33
  class _Query:
@@ -57,6 +59,9 @@ class _Query:
57
59
  elif key.endswith("__in"):
58
60
  if row.get(key[:-4]) not in expected: # type: ignore[operator]
59
61
  return False
62
+ elif isinstance(row.get(key), datetime) and isinstance(expected, str):
63
+ if row[key].isoformat() != expected: # type: ignore[union-attr]
64
+ return False
60
65
  elif row.get(key) != expected:
61
66
  return False
62
67
  return True
@@ -119,10 +124,11 @@ class _Store:
119
124
  "value_hint": "c", "value_version": 1, "is_active": False, "description": None,
120
125
  "created_at": old, "updated_at": old, "deleted_at": old},
121
126
  ],
122
- "attachments": [
127
+ "attachments": [
123
128
  {"id": ATTACHMENT, "credential_item_id": ITEM, "deleted_at": None, "updated_at": now},
124
129
  {"id": OLD_ATTACHMENT, "credential_item_id": ITEM, "deleted_at": old, "updated_at": old},
125
130
  ],
131
+ "passkeys": [],
126
132
  "grants": [
127
133
  {"credential_item_id": ITEM, "user_secret_id": None, "user_id": "member"},
128
134
  {"credential_item_id": None, "user_secret_id": ACTIVE_FIELD, "user_id": "legacy-member"},
@@ -167,6 +173,12 @@ def vault(monkeypatch: pytest.MonkeyPatch) -> _Store:
167
173
  monkeypatch.setattr(items_mod, "record_secret_audit", audit)
168
174
  monkeypatch.setattr(attachments_mod, "record_secret_audit", audit)
169
175
  monkeypatch.setattr(items_mod, "audit_organization", lambda **_kwargs: "audit-org")
176
+ passkeys = type("Passkeys", (_Model,), {"table": "passkeys", "store": store})
177
+ monkeypatch.setattr(native_lifecycle, "CredentialItem", item)
178
+ monkeypatch.setattr(native_lifecycle, "UserSecret", field)
179
+ monkeypatch.setattr(native_lifecycle, "PasskeyCredential", passkeys)
180
+ monkeypatch.setattr(native_lifecycle, "get_active_connection", lambda: object())
181
+ monkeypatch.setattr(native_lifecycle, "require_host_authorization", _native_allow)
170
182
  return store
171
183
 
172
184
 
@@ -190,11 +202,9 @@ async def test_actual_delete_then_restore_quarantines_only_children_in_manifest(
190
202
  assert all(row["deleted_at"].isoformat() == deleted_at for row in vault.tables["fields"][:2]) # type: ignore[union-attr]
191
203
  assert vault.tables["attachments"][0]["deleted_at"].isoformat() == deleted_at # type: ignore[union-attr]
192
204
  assert vault.tables["grants"] == []
193
-
194
205
  restored, fields, attachments, already = await items_mod.restore_credential_item(
195
206
  ITEM, deletion_id=deletion_id, actor_id="owner", audit_organization_id="audit-org"
196
207
  )
197
-
198
208
  assert (fields, attachments, already) == (2, 1, False)
199
209
  assert restored.status == "disabled"
200
210
  assert parent["deleted_at"] is None and parent["access_mode"] == "restricted"
@@ -211,6 +221,113 @@ async def test_actual_delete_then_restore_quarantines_only_children_in_manifest(
211
221
  assert vault.tables["grants"] == []
212
222
 
213
223
 
224
+ @pytest.mark.asyncio
225
+ async def test_native_v2_coordinator_deletes_and_restores_exact_pair_with_auxiliaries(
226
+ vault: _Store, monkeypatch: pytest.MonkeyPatch
227
+ ) -> None:
228
+ """The aggregate coordinator, not a helper-only caller, owns v2 custody."""
229
+ vault.tables["items"][0].update(definition_key="native_passkey", access_mode="restricted")
230
+ source = vault.tables["fields"][0]
231
+ source.update(
232
+ field_key="passkey_private", execution_purpose="passkey_private", handling="sealed",
233
+ editable=False, inject_into_sandbox=False, key=None, value_hint=None,
234
+ )
235
+ vault.tables["passkeys"] = [{
236
+ "id": PASSKEY, "credential_item_id": ITEM, "source_field_id": ACTIVE_FIELD,
237
+ "organization_id": "owner-personal-org", "lifecycle": "saved_waiting_for_site",
238
+ "deleted_at": None,
239
+ }]
240
+ passkeys = type("Passkeys", (_Model,), {"table": "passkeys", "store": vault})
241
+ monkeypatch.setattr(native_lifecycle, "CredentialItem", items_mod.CredentialItem)
242
+ monkeypatch.setattr(native_lifecycle, "UserSecret", items_mod.UserSecret)
243
+ monkeypatch.setattr(native_lifecycle, "PasskeyCredential", passkeys)
244
+ monkeypatch.setattr(native_lifecycle, "get_active_connection", lambda: object())
245
+
246
+ async def authorize(*_args: object, **_kwargs: object) -> None:
247
+ return None
248
+
249
+ monkeypatch.setattr(native_lifecycle, "require_host_authorization", authorize)
250
+ deletion_id = await _delete(vault)
251
+ manifest = vault.tables["items"][0]["lifecycle"]["vault_recovery"] # type: ignore[index]
252
+ assert manifest["schema_version"] == 2 # type: ignore[index]
253
+ assert manifest["native_passkeys"] == [{"id": PASSKEY, "source_field_id": ACTIVE_FIELD}] # type: ignore[index]
254
+ assert vault.tables["passkeys"][0]["lifecycle"] == "retired"
255
+ assert vault.tables["passkeys"][0]["deleted_at"] == vault.tables["items"][0]["deleted_at"]
256
+ expected_native_deleted_at = datetime.fromisoformat(manifest["deleted_at"]) # type: ignore[arg-type]
257
+ native_restore_timestamps: list[datetime] = []
258
+ original_restore_native_component = native_lifecycle.restore_native_component
259
+
260
+ async def restore_with_typed_timestamp(*args: object, **kwargs: object) -> None:
261
+ deleted_at = kwargs["deleted_at"]
262
+ assert isinstance(deleted_at, datetime)
263
+ assert deleted_at.tzinfo is not None and deleted_at.utcoffset() is not None
264
+ native_restore_timestamps.append(deleted_at)
265
+ await original_restore_native_component(*args, **kwargs) # type: ignore[arg-type]
266
+
267
+ monkeypatch.setattr(native_lifecycle, "restore_native_component", restore_with_typed_timestamp)
268
+
269
+ _, fields, attachments, already = await items_mod.restore_credential_item(
270
+ ITEM, deletion_id=deletion_id, actor_id="owner", audit_organization_id="audit-org"
271
+ )
272
+ assert (fields, attachments, already) == (2, 1, False)
273
+ assert native_restore_timestamps == [expected_native_deleted_at]
274
+ assert vault.tables["passkeys"][0]["deleted_at"] is None
275
+ assert vault.tables["passkeys"][0]["lifecycle"] == "saved_waiting_for_site"
276
+ assert vault.tables["fields"][0]["is_active"] is False
277
+ assert vault.tables["items"][0]["status"] == "disabled"
278
+ _, fields, attachments, already = await items_mod.restore_credential_item(
279
+ ITEM, deletion_id=deletion_id, actor_id="owner", audit_organization_id="audit-org"
280
+ )
281
+ assert (fields, attachments, already) == (0, 0, True)
282
+ vault.tables["fields"].append({
283
+ **vault.tables["fields"][0], "id": SECOND_ITEM, "field_key": "other_protected",
284
+ "deleted_at": None, "is_active": False,
285
+ })
286
+ before = deepcopy(vault.tables)
287
+ with pytest.raises(items_mod.CredentialRestoreUnsupportedError):
288
+ await items_mod.restore_credential_item(
289
+ ITEM, deletion_id=deletion_id, actor_id="owner", audit_organization_id="audit-org"
290
+ )
291
+ assert vault.tables == before
292
+ restore_audits = [event for event in vault.audits if event.get("action") == "item_restored_quarantined"]
293
+ assert restore_audits[-1]["metadata"]["restored_native_passkeys"] == 1 # type: ignore[index]
294
+
295
+
296
+ @pytest.mark.asyncio
297
+ async def test_native_v2_forged_pair_refuses_before_resurrecting_any_component(
298
+ vault: _Store, monkeypatch: pytest.MonkeyPatch
299
+ ) -> None:
300
+ """A forged native manifest cannot restore a parent, source, or auxiliary."""
301
+ vault.tables["items"][0].update(definition_key="native_passkey", access_mode="restricted")
302
+ vault.tables["fields"][0].update(
303
+ field_key="passkey_private", execution_purpose="passkey_private", handling="sealed",
304
+ editable=False, inject_into_sandbox=False, key=None, value_hint=None,
305
+ )
306
+ vault.tables["passkeys"] = [{
307
+ "id": PASSKEY, "credential_item_id": ITEM, "source_field_id": ACTIVE_FIELD,
308
+ "organization_id": "owner-personal-org", "lifecycle": "saved_waiting_for_site",
309
+ "deleted_at": None,
310
+ }]
311
+ passkeys = type("Passkeys", (_Model,), {"table": "passkeys", "store": vault})
312
+ monkeypatch.setattr(native_lifecycle, "CredentialItem", items_mod.CredentialItem)
313
+ monkeypatch.setattr(native_lifecycle, "UserSecret", items_mod.UserSecret)
314
+ monkeypatch.setattr(native_lifecycle, "PasskeyCredential", passkeys)
315
+ monkeypatch.setattr(native_lifecycle, "get_active_connection", lambda: object())
316
+ monkeypatch.setattr(native_lifecycle, "require_host_authorization", _native_allow)
317
+ deletion_id = await _delete(vault)
318
+ vault.tables["items"][0]["lifecycle"]["vault_recovery"]["native_passkeys"][0]["id"] = SECOND_ITEM # type: ignore[index]
319
+ before = deepcopy(vault.tables)
320
+ with pytest.raises(items_mod.CredentialRestoreConflictError):
321
+ await items_mod.restore_credential_item(
322
+ ITEM, deletion_id=deletion_id, actor_id="owner", audit_organization_id="audit-org"
323
+ )
324
+ assert vault.tables == before
325
+
326
+
327
+ async def _native_allow(*_args: object, **_kwargs: object) -> None:
328
+ return None
329
+
330
+
214
331
  @pytest.mark.asyncio
215
332
  @pytest.mark.parametrize("breakage", ["purged", "ownership_mismatch"])
216
333
  async def test_actual_restore_refuses_changed_child_without_partial_resurrection(vault: _Store, breakage: str) -> None:
File without changes
File without changes
File without changes
File without changes
File without changes