loom-kernel 2.9.0__tar.gz → 2.11.0__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 (637) hide show
  1. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/PKG-INFO +1 -1
  2. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/pyproject.toml +3 -0
  3. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/_decide.py +94 -24
  4. loom_kernel-2.11.0/src/loom/core/authz/_grants.py +135 -0
  5. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/_scope.py +17 -13
  6. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/__init__.py +2 -0
  7. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/session_manager.py +55 -1
  8. loom_kernel-2.11.0/src/loom/core/repository/sqlalchemy/session_settings.py +83 -0
  9. loom_kernel-2.9.0/src/loom/core/authz/_grants.py +0 -79
  10. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/.gitignore +0 -0
  11. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/CHANGELOG.md +0 -0
  12. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/LICENSE +0 -0
  13. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/README.md +0 -0
  14. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/__init__.py +0 -0
  15. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/__init__.py +0 -0
  16. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_concurrency.py +0 -0
  17. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_filters.py +0 -0
  18. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_roles.py +0 -0
  19. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_startup.py +0 -0
  20. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_transport.py +0 -0
  21. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/_usecase.py +0 -0
  22. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/__init__.py +0 -0
  23. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/_binding.py +0 -0
  24. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/_handlers.py +0 -0
  25. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/_rpc.py +0 -0
  26. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/card.py +0 -0
  27. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/events.py +0 -0
  28. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/a2a/server.py +0 -0
  29. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/abc.py +0 -0
  30. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/__init__.py +0 -0
  31. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/_compiler.py +0 -0
  32. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/_plan.py +0 -0
  33. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
  34. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
  35. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
  36. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
  37. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
  38. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
  39. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
  40. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
  41. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_output.py +0 -0
  42. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/compiler/phases/_state.py +0 -0
  43. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/config.py +0 -0
  44. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/__init__.py +0 -0
  45. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/_envelope.py +0 -0
  46. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/_schema.py +0 -0
  47. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/_v1.py +0 -0
  48. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
  49. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/describe.py +0 -0
  50. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/__init__.py +0 -0
  51. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
  52. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
  53. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +0 -0
  54. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
  55. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
  56. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
  57. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
  58. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
  59. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
  60. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
  61. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_limits.py +0 -0
  62. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +0 -0
  63. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
  64. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
  65. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
  66. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
  67. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +0 -0
  68. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
  69. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
  70. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
  71. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
  72. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
  73. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
  74. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
  75. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
  76. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +0 -0
  77. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
  78. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
  79. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
  80. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
  81. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
  82. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/errors.py +0 -0
  83. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/__init__.py +0 -0
  84. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/endpoints.py +0 -0
  85. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/response.py +0 -0
  86. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/fastapi/streaming.py +0 -0
  87. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/inference.py +0 -0
  88. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/registry.py +0 -0
  89. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/remote_auth.py +0 -0
  90. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/__init__.py +0 -0
  91. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_bounded.py +0 -0
  92. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_chain.py +0 -0
  93. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_conversation.py +0 -0
  94. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_grants.py +0 -0
  95. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_handle.py +0 -0
  96. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_health.py +0 -0
  97. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_hooks.py +0 -0
  98. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_lifecycle.py +0 -0
  99. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_limits.py +0 -0
  100. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/runtime/_mcp.py +0 -0
  101. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/validate/__init__.py +0 -0
  102. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/ai/validate/__main__.py +0 -0
  103. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/__init__.py +0 -0
  104. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/auto.py +0 -0
  105. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/bootstrap.py +0 -0
  106. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/config.py +0 -0
  107. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/constants.py +0 -0
  108. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/runner.py +0 -0
  109. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/celery/service.py +0 -0
  110. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/async_bridge.py +0 -0
  111. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/__init__.py +0 -0
  112. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/authz/_roles.py +0 -0
  113. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/__init__.py +0 -0
  114. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/core_model.py +0 -0
  115. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/protocol.py +0 -0
  116. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/backend/sqlalchemy.py +0 -0
  117. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/bootstrap/__init__.py +0 -0
  118. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
  119. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/bootstrap/kernel.py +0 -0
  120. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/__init__.py +0 -0
  121. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/_batching.py +0 -0
  122. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/_single_flight.py +0 -0
  123. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/__init__.py +0 -0
  124. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/backend.py +0 -0
  125. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/config.py +0 -0
  126. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/abc/dependency.py +0 -0
  127. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/calls.py +0 -0
  128. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/codec.py +0 -0
  129. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/decorators.py +0 -0
  130. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/dependency.py +0 -0
  131. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/errors.py +0 -0
  132. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/gateway.py +0 -0
  133. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/keys.py +0 -0
  134. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/memory.py +0 -0
  135. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/repository.py +0 -0
  136. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/result_codec.py +0 -0
  137. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/serializer.py +0 -0
  138. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/cache/wiring.py +0 -0
  139. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/__init__.py +0 -0
  140. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/adapter.py +0 -0
  141. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/base.py +0 -0
  142. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/field.py +0 -0
  143. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/command/introspection.py +0 -0
  144. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/compiler.py +0 -0
  145. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/__init__.py +0 -0
  146. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/_boto3.py +0 -0
  147. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/_includes.py +0 -0
  148. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/_resolver_utils.py +0 -0
  149. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/binder.py +0 -0
  150. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/configurable.py +0 -0
  151. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/context.py +0 -0
  152. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/errors.py +0 -0
  153. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/keys.py +0 -0
  154. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/loader.py +0 -0
  155. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/model.py +0 -0
  156. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/observability.py +0 -0
  157. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/resolver.py +0 -0
  158. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/secrets.py +0 -0
  159. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/config/ssm.py +0 -0
  160. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/contracts/__init__.py +0 -0
  161. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/contracts/manifest.py +0 -0
  162. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/di/__init__.py +0 -0
  163. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/di/container.py +0 -0
  164. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/di/scope.py +0 -0
  165. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/__init__.py +0 -0
  166. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/_utils.py +0 -0
  167. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/base.py +0 -0
  168. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/interfaces.py +0 -0
  169. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/manifest.py +0 -0
  170. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/discovery/modules.py +0 -0
  171. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/__init__.py +0 -0
  172. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/compilable.py +0 -0
  173. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/compiler.py +0 -0
  174. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/events.py +0 -0
  175. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/executor.py +0 -0
  176. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/metrics.py +0 -0
  177. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/plan.py +0 -0
  178. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/engine/post_commit.py +0 -0
  179. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/errors/__init__.py +0 -0
  180. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/errors/codes.py +0 -0
  181. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/errors/errors.py +0 -0
  182. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/__init__.py +0 -0
  183. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/eval.py +0 -0
  184. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/nodes.py +0 -0
  185. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/expr/refs.py +0 -0
  186. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/__init__.py +0 -0
  187. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/context.py +0 -0
  188. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/identity.py +0 -0
  189. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/issuer.py +0 -0
  190. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/identity/wire.py +0 -0
  191. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/introspection/__init__.py +0 -0
  192. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/introspection/base.py +0 -0
  193. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/introspection/describe.py +0 -0
  194. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/__init__.py +0 -0
  195. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/callback.py +0 -0
  196. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/context.py +0 -0
  197. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/handle.py +0 -0
  198. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/job.py +0 -0
  199. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/job/service.py +0 -0
  200. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/__init__.py +0 -0
  201. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/abc.py +0 -0
  202. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/config.py +0 -0
  203. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/registry.py +0 -0
  204. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/logger/structlogger.py +0 -0
  205. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/__init__.py +0 -0
  206. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/_loom_type.py +0 -0
  207. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/base.py +0 -0
  208. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/convert.py +0 -0
  209. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/enums.py +0 -0
  210. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/field.py +0 -0
  211. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/introspection.py +0 -0
  212. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/projection.py +0 -0
  213. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/relation.py +0 -0
  214. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/struct.py +0 -0
  215. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/timestamped.py +0 -0
  216. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/types.py +0 -0
  217. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/model/types_postgres.py +0 -0
  218. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/__init__.py +0 -0
  219. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/config.py +0 -0
  220. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/event.py +0 -0
  221. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/__init__.py +0 -0
  222. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/noop.py +0 -0
  223. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/otel.py +0 -0
  224. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/observer/structlog.py +0 -0
  225. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/otel_ids.py +0 -0
  226. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/protocol.py +0 -0
  227. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/runtime.py +0 -0
  228. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/span.py +0 -0
  229. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/observability/topology.py +0 -0
  230. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/__init__.py +0 -0
  231. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/abc.py +0 -0
  232. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/none.py +0 -0
  233. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/persistence/registry.py +0 -0
  234. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/plugins/__init__.py +0 -0
  235. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/plugins/entrypoints.py +0 -0
  236. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/plugins/optional.py +0 -0
  237. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/projection/__init__.py +0 -0
  238. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/projection/loaders.py +0 -0
  239. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/projection/runtime.py +0 -0
  240. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/__init__.py +0 -0
  241. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/__init__.py +0 -0
  242. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/cursor.py +0 -0
  243. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/errors.py +0 -0
  244. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/query.py +0 -0
  245. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
  246. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/repo_for.py +0 -0
  247. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/repository.py +0 -0
  248. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/abc/session_scope.py +0 -0
  249. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
  250. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
  251. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
  252. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/repository.py +0 -0
  253. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
  254. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/__init__.py +0 -0
  255. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/backend.py +0 -0
  256. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/ids.py +0 -0
  257. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
  258. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/registry.py +0 -0
  259. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/repository.py +0 -0
  260. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/uow.py +0 -0
  261. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mongo/values.py +0 -0
  262. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/mutation.py +0 -0
  263. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/registration.py +0 -0
  264. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/registry.py +0 -0
  265. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/backend.py +0 -0
  266. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
  267. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
  268. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
  269. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
  270. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
  271. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
  272. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
  273. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
  274. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
  275. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
  276. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
  277. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
  278. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
  279. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
  280. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
  281. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
  282. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
  283. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
  284. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/response/__init__.py +0 -0
  285. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/response/base.py +0 -0
  286. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/routing/__init__.py +0 -0
  287. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/routing/ref.py +0 -0
  288. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/routing/resolver.py +0 -0
  289. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/runner.py +0 -0
  290. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/schema/__init__.py +0 -0
  291. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/schema/schema_mode.py +0 -0
  292. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/__init__.py +0 -0
  293. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/abc/__init__.py +0 -0
  294. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/abc/contracts.py +0 -0
  295. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/abc/errors.py +0 -0
  296. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/caller_bound.py +0 -0
  297. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
  298. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
  299. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
  300. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
  301. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/config.py +0 -0
  302. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/roles.py +0 -0
  303. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/sql/service.py +0 -0
  304. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/symbols.py +0 -0
  305. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/tracing/__init__.py +0 -0
  306. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/tracing/context.py +0 -0
  307. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/transaction.py +0 -0
  308. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/transport/__init__.py +0 -0
  309. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/transport/adapter.py +0 -0
  310. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/uow/__init__.py +0 -0
  311. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/uow/abc.py +0 -0
  312. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/uow/context.py +0 -0
  313. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/__init__.py +0 -0
  314. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/_predicates.py +0 -0
  315. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/agent_markers.py +0 -0
  316. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/compute.py +0 -0
  317. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/constants.py +0 -0
  318. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/factory.py +0 -0
  319. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/field_ref.py +0 -0
  320. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/invoker.py +0 -0
  321. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/keys.py +0 -0
  322. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/markers.py +0 -0
  323. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/mcp_markers.py +0 -0
  324. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/registry.py +0 -0
  325. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/rule.py +0 -0
  326. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/core/use_case/use_case.py +0 -0
  327. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/__init__.py +0 -0
  328. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/__init__.py +0 -0
  329. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_format_registry.py +0 -0
  330. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
  331. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_common.py +0 -0
  332. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_log.py +0 -0
  333. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
  334. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
  335. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
  336. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_merge.py +0 -0
  337. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_path_template.py +0 -0
  338. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_predicate.py +0 -0
  339. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
  340. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
  341. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
  342. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/_write_policy.py +0 -0
  343. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/__init__.py +0 -0
  344. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
  345. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
  346. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_historify.py +0 -0
  347. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
  348. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_reader.py +0 -0
  349. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_schema.py +0 -0
  350. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
  351. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
  352. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/_writer.py +0 -0
  353. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/polars/provider.py +0 -0
  354. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/__init__.py +0 -0
  355. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
  356. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_historify.py +0 -0
  357. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_reader.py +0 -0
  358. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_schema.py +0 -0
  359. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
  360. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/_writer.py +0 -0
  361. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/backends/spark/provider.py +0 -0
  362. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/__init__.py +0 -0
  363. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
  364. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
  365. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_cleaners.py +0 -0
  366. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_options.py +0 -0
  367. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_paths.py +0 -0
  368. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_scope.py +0 -0
  369. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/checkpoint/_store.py +0 -0
  370. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/__init__.py +0 -0
  371. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_binding.py +0 -0
  372. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_compiler.py +0 -0
  373. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_errors.py +0 -0
  374. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_plan.py +0 -0
  375. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators.py +0 -0
  376. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators_config.py +0 -0
  377. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
  378. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/compiler/_validators_step.py +0 -0
  379. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/__init__.py +0 -0
  380. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_format.py +0 -0
  381. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_read_options.py +0 -0
  382. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_utils.py +0 -0
  383. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/_write_options.py +0 -0
  384. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
  385. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_params.py +0 -0
  386. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
  387. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
  388. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
  389. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/__init__.py +0 -0
  390. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from.py +0 -0
  391. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
  392. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
  393. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
  394. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
  395. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/source/_specs.py +0 -0
  396. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/__init__.py +0 -0
  397. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_client.py +0 -0
  398. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_file.py +0 -0
  399. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
  400. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
  401. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
  402. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
  403. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
  404. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
  405. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_into.py +0 -0
  406. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
  407. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_table.py +0 -0
  408. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/declarative/target/_temp.py +0 -0
  409. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/executor/__init__.py +0 -0
  410. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/executor/_dispatcher.py +0 -0
  411. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/executor/_executor.py +0 -0
  412. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/__init__.py +0 -0
  413. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/_registry.py +0 -0
  414. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/__init__.py +0 -0
  415. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
  416. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
  417. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
  418. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
  419. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo.py +0 -0
  420. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
  421. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
  422. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
  423. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/sources/_serialization.py +0 -0
  424. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/targets/__init__.py +0 -0
  425. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
  426. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/__init__.py +0 -0
  427. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/_config.py +0 -0
  428. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/_observer.py +0 -0
  429. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/_records.py +0 -0
  430. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
  431. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
  432. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
  433. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
  434. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/__init__.py +0 -0
  435. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_builder.py +0 -0
  436. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_ops.py +0 -0
  437. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_protocol.py +0 -0
  438. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_runner.py +0 -0
  439. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/_step.py +0 -0
  440. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
  441. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
  442. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/__init__.py +0 -0
  443. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_generics.py +0 -0
  444. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_params.py +0 -0
  445. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
  446. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_process.py +0 -0
  447. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_sql.py +0 -0
  448. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_step.py +0 -0
  449. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_step_client.py +0 -0
  450. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
  451. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/__init__.py +0 -0
  452. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/_providers.py +0 -0
  453. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/_wiring.py +0 -0
  454. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/config_loader.py +0 -0
  455. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/core.py +0 -0
  456. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/errors.py +0 -0
  457. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runner/filtering.py +0 -0
  458. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runtime/__init__.py +0 -0
  459. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runtime/_config_values.py +0 -0
  460. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/runtime/contracts.py +0 -0
  461. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/schema/__init__.py +0 -0
  462. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/schema/_contract.py +0 -0
  463. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/schema/_schema.py +0 -0
  464. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/__init__.py +0 -0
  465. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/_config.py +0 -0
  466. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/_file_locator.py +0 -0
  467. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/_locator.py +0 -0
  468. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/storage/routing.py +0 -0
  469. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/__init__.py +0 -0
  470. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_result.py +0 -0
  471. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_runners.py +0 -0
  472. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_scenario.py +0 -0
  473. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/_stubs.py +0 -0
  474. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/etl/testing/spark.py +0 -0
  475. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/__init__.py +0 -0
  476. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_async.py +0 -0
  477. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_config.py +0 -0
  478. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_ctx.py +0 -0
  479. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_flow_yaml.py +0 -0
  480. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_meta.py +0 -0
  481. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_placeholders.py +0 -0
  482. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/_summary.py +0 -0
  483. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/__init__.py +0 -0
  484. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/_discovery.py +0 -0
  485. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/_schedule.py +0 -0
  486. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
  487. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
  488. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/__init__.py +0 -0
  489. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_assemble.py +0 -0
  490. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_backfill.py +0 -0
  491. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
  492. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_body.py +0 -0
  493. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_common.py +0 -0
  494. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_factory.py +0 -0
  495. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_hooks.py +0 -0
  496. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_maintenance.py +0 -0
  497. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_params.py +0 -0
  498. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_run_name.py +0 -0
  499. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_runtime.py +0 -0
  500. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_signature.py +0 -0
  501. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/flow/_stages.py +0 -0
  502. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/__init__.py +0 -0
  503. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/_model.py +0 -0
  504. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/_s3.py +0 -0
  505. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/manifest/_store.py +0 -0
  506. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/__init__.py +0 -0
  507. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_event.py +0 -0
  508. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_factory.py +0 -0
  509. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_port.py +0 -0
  510. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/notify/_slack.py +0 -0
  511. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/__init__.py +0 -0
  512. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_flow.py +0 -0
  513. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_logging_bridge.py +0 -0
  514. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_manifest.py +0 -0
  515. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prefect/observer/_task_run.py +0 -0
  516. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/__init__.py +0 -0
  517. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/_instruments.py +0 -0
  518. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/adapter.py +0 -0
  519. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/kafka.py +0 -0
  520. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/lifecycle.py +0 -0
  521. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/prometheus/middleware.py +0 -0
  522. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/py.typed +0 -0
  523. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/__init__.py +0 -0
  524. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/_body.py +0 -0
  525. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/adapter.py +0 -0
  526. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/__init__.py +0 -0
  527. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/abc.py +0 -0
  528. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/config.py +0 -0
  529. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/jwt.py +0 -0
  530. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/auth/middleware.py +0 -0
  531. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/autocrud.py +0 -0
  532. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/compiler.py +0 -0
  533. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/config.py +0 -0
  534. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/constants.py +0 -0
  535. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/cors.py +0 -0
  536. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/errors.py +0 -0
  537. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/__init__.py +0 -0
  538. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/_errors.py +0 -0
  539. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
  540. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/app.py +0 -0
  541. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/auto.py +0 -0
  542. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/health.py +0 -0
  543. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/openapi.py +0 -0
  544. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/response.py +0 -0
  545. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
  546. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/fastapi/sql.py +0 -0
  547. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/middleware.py +0 -0
  548. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/model.py +0 -0
  549. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/rest/rest_adapter.py +0 -0
  550. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/__init__.py +0 -0
  551. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/__init__.py +0 -0
  552. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
  553. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
  554. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
  555. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_dlq.py +0 -0
  556. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
  557. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_errors.py +0 -0
  558. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_operators.py +0 -0
  559. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
  560. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
  561. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
  562. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
  563. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
  564. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
  565. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
  566. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
  567. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
  568. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
  569. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
  570. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
  571. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/bytewax/runner.py +0 -0
  572. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/__init__.py +0 -0
  573. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_bindings.py +0 -0
  574. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_compiler.py +0 -0
  575. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_errors.py +0 -0
  576. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/_plan.py +0 -0
  577. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
  578. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
  579. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/__init__.py +0 -0
  580. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_errors.py +0 -0
  581. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_exceptions.py +0 -0
  582. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_message.py +0 -0
  583. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_tracing.py +0 -0
  584. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/core/_typing.py +0 -0
  585. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/graph/__init__.py +0 -0
  586. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/graph/_flow.py +0 -0
  587. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/__init__.py +0 -0
  588. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_codec.py +0 -0
  589. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_config.py +0 -0
  590. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_errors.py +0 -0
  591. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
  592. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_message.py +0 -0
  593. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_record.py +0 -0
  594. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/_wire.py +0 -0
  595. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
  596. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
  597. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
  598. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
  599. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
  600. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
  601. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
  602. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
  603. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
  604. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/__init__.py +0 -0
  605. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
  606. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_config.py +0 -0
  607. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_event.py +0 -0
  608. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/mongo/_normalize.py +0 -0
  609. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/__init__.py +0 -0
  610. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_boundary.py +0 -0
  611. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_branches.py +0 -0
  612. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
  613. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
  614. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_decompose.py +0 -0
  615. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
  616. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
  617. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_fork.py +0 -0
  618. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_helpers.py +0 -0
  619. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_mongo.py +0 -0
  620. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_protocols.py +0 -0
  621. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_router.py +0 -0
  622. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_shape.py +0 -0
  623. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_sink.py +0 -0
  624. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_step.py +0 -0
  625. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
  626. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_table/common.py +0 -0
  627. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_table/config.py +0 -0
  628. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/_with.py +0 -0
  629. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/nodes/refs.py +0 -0
  630. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/streaming/testing.py +0 -0
  631. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/__init__.py +0 -0
  632. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/agents.py +0 -0
  633. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/golden.py +0 -0
  634. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/http_harness.py +0 -0
  635. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/in_memory.py +0 -0
  636. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/repository_harness.py +0 -0
  637. {loom_kernel-2.9.0 → loom_kernel-2.11.0}/src/loom/testing/runner.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: loom-kernel
3
- Version: 2.9.0
3
+ Version: 2.11.0
4
4
  Summary: Loom Python project
5
5
  License-File: LICENSE
6
6
  Classifier: Programming Language :: Python :: 3
@@ -224,6 +224,7 @@ mcp-tests = [
224
224
  dev = [
225
225
  "aiocache>=0.12,<1.0",
226
226
  "aiosqlite>=0.20.0",
227
+ "asyncpg>=0.30",
227
228
  # Declared, not merely transitive: one cache test pins what the key renderer
228
229
  # cannot separate inside an object msgspec expands itself, and an attrs class
229
230
  # is the only such object the stdlib can build.
@@ -477,6 +478,7 @@ prerelease_ignore = [
477
478
  "ci/.*",
478
479
  "test/.*",
479
480
  "build/.*",
481
+ "dependabot/.*",
480
482
  ]
481
483
  release_ignore = [
482
484
  "wip/.*",
@@ -485,4 +487,5 @@ release_ignore = [
485
487
  "ci/.*",
486
488
  "test/.*",
487
489
  "build/.*",
490
+ "dependabot/.*",
488
491
  ]
@@ -4,8 +4,9 @@ from __future__ import annotations
4
4
 
5
5
  from collections.abc import Iterable
6
6
  from dataclasses import dataclass
7
+ from datetime import datetime
7
8
 
8
- from loom.core.authz._grants import Grant
9
+ from loom.core.authz._grants import Grant, require_aware
9
10
  from loom.core.authz._roles import Permission, RoleCatalog
10
11
  from loom.core.authz._scope import Scope
11
12
 
@@ -54,8 +55,41 @@ class GrantCheck:
54
55
  return self.allowed
55
56
 
56
57
 
57
- def _specificity(grant: Grant) -> tuple[int, str, str]:
58
- return (-len(grant.scope.path), grant.role, grant.subject)
58
+ _FOREVER = float("-inf")
59
+
60
+
61
+ def _rank(grant: Grant) -> tuple[int, str, str, float]:
62
+ lifetime = _FOREVER if grant.expires_at is None else -grant.expires_at.timestamp()
63
+ return (-len(grant.scope.path), grant.role, grant.subject, lifetime)
64
+
65
+
66
+ def _check_now(now: datetime | None) -> None:
67
+ if now is not None:
68
+ require_aware("now", now)
69
+
70
+
71
+ def _require_now_for_expiring(grants: tuple[Grant, ...], now: datetime | None) -> None:
72
+ expiry = next((grant.expires_at for grant in grants if grant.expires_at is not None), None)
73
+ if now is None and expiry is not None:
74
+ raise ValueError(
75
+ f"A grant expires at {expiry.isoformat()}; pass now= to decide whether it is alive."
76
+ )
77
+
78
+
79
+ def _alive(grant: Grant, now: datetime | None) -> bool:
80
+ return grant.expires_at is None or (now is not None and now < grant.expires_at)
81
+
82
+
83
+ def _covering_paths(scope: Scope) -> frozenset[tuple[str, ...]]:
84
+ return frozenset(scope.path[:depth] for depth in range(len(scope.path) + 1))
85
+
86
+
87
+ def _outermost(scopes: set[Scope]) -> frozenset[Scope]:
88
+ return frozenset(
89
+ scope
90
+ for scope in scopes
91
+ if not any(other != scope and other.covers(scope) for other in scopes)
92
+ )
59
93
 
60
94
 
61
95
  def evaluate(
@@ -63,6 +97,8 @@ def evaluate(
63
97
  grants: Iterable[Grant],
64
98
  permission: Permission,
65
99
  scope: Scope,
100
+ *,
101
+ now: datetime | None = None,
66
102
  ) -> Decision:
67
103
  """Decide whether a subject holds *permission* on *scope*.
68
104
 
@@ -70,30 +106,38 @@ def evaluate(
70
106
  scope covering *scope*. A grant whose role the catalog does not declare
71
107
  allows nothing. When several grants allow, the decision names the one on
72
108
  the deepest scope, then the first by role name and subject, regardless of
73
- the order of *grants*.
109
+ the order of *grants*; among grants that tie there, the one that lives
110
+ longest. A grant is alive while *now* is before its expiry; an expired
111
+ grant counts as absent.
74
112
 
75
113
  Args:
76
114
  catalog: The product's roles.
77
115
  grants: The grants of one subject.
78
116
  permission: The capability being exercised.
79
117
  scope: Where it is exercised.
118
+ now: The timezone-aware instant of the decision; needed only when
119
+ some grant carries an expiry.
80
120
 
81
121
  Returns:
82
122
  The decision, carrying the grant that allowed it.
83
123
 
84
124
  Raises:
85
125
  UnknownPermission: When *permission* is not declared in the catalog.
126
+ TypeError: When *now* is not a datetime.
127
+ ValueError: When *now* is naive, or is ``None`` while some grant
128
+ carries an expiry.
86
129
  """
130
+ _check_now(now)
131
+ held = tuple(grants)
132
+ _require_now_for_expiring(held, now)
87
133
  roles = catalog.roles_with(permission)
88
- covering = {scope.path[:depth] for depth in range(len(scope.path) + 1)}
89
- winner: Grant | None = None
90
- for grant in grants:
91
- if (
92
- grant.role in roles
93
- and grant.scope.path in covering
94
- and (winner is None or _specificity(grant) < _specificity(winner))
95
- ):
96
- winner = grant
134
+ covering = _covering_paths(scope)
135
+ allowing = [
136
+ grant
137
+ for grant in held
138
+ if grant.role in roles and grant.scope.path in covering and _alive(grant, now)
139
+ ]
140
+ winner = min(allowing, key=_rank, default=None)
97
141
  return Decision(winner is not None, winner)
98
142
 
99
143
 
@@ -101,28 +145,36 @@ def scopes_with(
101
145
  catalog: RoleCatalog,
102
146
  grants: Iterable[Grant],
103
147
  permission: Permission,
148
+ *,
149
+ now: datetime | None = None,
104
150
  ) -> frozenset[Scope]:
105
151
  """Return the outermost scopes on which a subject holds *permission*.
106
152
 
107
153
  A scope covered by another returned scope is left out, so a listing can
108
- be filtered with one :meth:`Scope.covers` test per returned scope.
154
+ be filtered with one :meth:`Scope.covers` test per returned scope. An
155
+ expired grant counts as absent.
109
156
 
110
157
  Args:
111
158
  catalog: The product's roles.
112
159
  grants: The grants of one subject.
113
160
  permission: The capability being listed.
161
+ now: The timezone-aware instant of the listing; needed only when
162
+ some grant carries an expiry.
114
163
 
115
164
  Returns:
116
165
  The minimal set of scopes covering everything the subject may reach.
117
166
 
118
167
  Raises:
119
168
  UnknownPermission: When *permission* is not declared in the catalog.
169
+ TypeError: When *now* is not a datetime.
170
+ ValueError: When *now* is naive, or is ``None`` while some grant
171
+ carries an expiry.
120
172
  """
173
+ _check_now(now)
174
+ held = tuple(grants)
175
+ _require_now_for_expiring(held, now)
121
176
  roles = catalog.roles_with(permission)
122
- held = {grant.scope for grant in grants if grant.role in roles}
123
- return frozenset(
124
- scope for scope in held if not any(other != scope and other.covers(scope) for other in held)
125
- )
177
+ return _outermost({grant.scope for grant in held if grant.role in roles and _alive(grant, now)})
126
178
 
127
179
 
128
180
  def _delegation_check(
@@ -130,10 +182,13 @@ def _delegation_check(
130
182
  granter_grants: Iterable[Grant],
131
183
  needed: Iterable[Permission],
132
184
  scope: Scope,
185
+ now: datetime | None,
133
186
  ) -> GrantCheck:
134
187
  held = tuple(granter_grants)
135
188
  missing = frozenset(
136
- permission for permission in needed if not evaluate(catalog, held, permission, scope)
189
+ permission
190
+ for permission in needed
191
+ if not evaluate(catalog, held, permission, scope, now=now)
137
192
  )
138
193
  return GrantCheck(not missing, missing)
139
194
 
@@ -145,11 +200,12 @@ def can_grant(
145
200
  scope: Scope,
146
201
  *,
147
202
  delegate: Permission,
203
+ now: datetime | None = None,
148
204
  ) -> GrantCheck:
149
205
  """Decide whether a granter may assign *role* on *scope*.
150
206
 
151
207
  The granter needs *delegate* and every permission of *role*, each held on
152
- a scope covering *scope*.
208
+ a scope covering *scope* by a grant that is alive at *now*.
153
209
 
154
210
  Args:
155
211
  catalog: The product's roles.
@@ -157,6 +213,8 @@ def can_grant(
157
213
  role: Name of the role to assign.
158
214
  scope: Where it would apply.
159
215
  delegate: The permission that allows assigning roles at all.
216
+ now: The timezone-aware instant of the check; needed only when some
217
+ of the granter's grants carry an expiry.
160
218
 
161
219
  Returns:
162
220
  The check, listing the permissions the granter lacks there.
@@ -164,9 +222,13 @@ def can_grant(
164
222
  Raises:
165
223
  UnknownRole: When *role* is not declared in the catalog.
166
224
  UnknownPermission: When *delegate* is not declared in the catalog.
225
+ TypeError: When *now* is not a datetime.
226
+ ValueError: When *now* is naive, or is ``None`` while some of the
227
+ granter's grants carry an expiry.
167
228
  """
229
+ _check_now(now)
168
230
  needed = {delegate, *catalog.role(role).permissions}
169
- return _delegation_check(catalog, granter_grants, needed, scope)
231
+ return _delegation_check(catalog, granter_grants, needed, scope, now)
170
232
 
171
233
 
172
234
  def can_revoke(
@@ -175,23 +237,31 @@ def can_revoke(
175
237
  grant: Grant,
176
238
  *,
177
239
  delegate: Permission,
240
+ now: datetime | None = None,
178
241
  ) -> GrantCheck:
179
242
  """Decide whether a granter may remove *grant*.
180
243
 
181
- Revoking needs what granting it would. A grant whose role the code does
182
- not declare allows nothing, so removing it needs *delegate* only.
244
+ Revoking needs what granting it would, whether or not *grant* has
245
+ expired. A grant whose role the code does not declare allows nothing, so
246
+ removing it needs *delegate* only.
183
247
 
184
248
  Args:
185
249
  catalog: The product's roles.
186
250
  granter_grants: The granter's grants.
187
251
  grant: The assignment to remove.
188
252
  delegate: The permission that allows assigning roles at all.
253
+ now: The timezone-aware instant of the check; needed only when some
254
+ of the granter's grants carry an expiry.
189
255
 
190
256
  Returns:
191
257
  The check, listing the permissions the granter lacks there.
192
258
 
193
259
  Raises:
194
260
  UnknownPermission: When *delegate* is not declared in the catalog.
261
+ TypeError: When *now* is not a datetime.
262
+ ValueError: When *now* is naive, or is ``None`` while some of the
263
+ granter's grants carry an expiry.
195
264
  """
265
+ _check_now(now)
196
266
  needed = {delegate, *(catalog.permissions_of(grant.role) or frozenset())}
197
- return _delegation_check(catalog, granter_grants, needed, grant.scope)
267
+ return _delegation_check(catalog, granter_grants, needed, grant.scope, now)
@@ -0,0 +1,135 @@
1
+ """Who holds which role where, and where those assignments come from."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import functools
6
+ from collections.abc import Collection, Iterable
7
+ from dataclasses import dataclass
8
+ from datetime import UTC, datetime
9
+ from typing import Protocol
10
+
11
+ from loom.core.authz._roles import require_name
12
+ from loom.core.authz._scope import Scope
13
+
14
+
15
+ def require_aware(name: str, moment: datetime) -> None:
16
+ """Reject a moment that does not name a single instant.
17
+
18
+ Args:
19
+ name: What the moment is, for the error message.
20
+ moment: The moment to check.
21
+
22
+ Raises:
23
+ TypeError: When *moment* is not a datetime.
24
+ ValueError: When *moment* is naive.
25
+ """
26
+ if not isinstance(moment, datetime):
27
+ raise TypeError(f"{name} must be a datetime, not {type(moment).__name__}.")
28
+ if moment.utcoffset() is None:
29
+ raise ValueError(f"{name} must be timezone-aware: {moment!r}.")
30
+
31
+
32
+ def _require_subject(subject: str) -> None:
33
+ if not subject:
34
+ raise ValueError("A grant needs a subject.")
35
+
36
+
37
+ def _require_scope(scope: object) -> None:
38
+ if not isinstance(scope, Scope):
39
+ raise TypeError(f"A grant scope must be a Scope, not {type(scope).__name__}.")
40
+
41
+
42
+ def _utc_or_none(name: str, moment: datetime | None) -> datetime | None:
43
+ if moment is None:
44
+ return None
45
+ require_aware(name, moment)
46
+ return moment.astimezone(UTC)
47
+
48
+
49
+ _NEVER = (0,)
50
+
51
+
52
+ @functools.total_ordering
53
+ @dataclass(frozen=True, slots=True)
54
+ class Grant:
55
+ """An assignment of a role to a subject on a scope, possibly until a moment.
56
+
57
+ Grants order by subject, role, scope and then expiry, with grants that
58
+ never expire before those that do, soonest first.
59
+
60
+ Attributes:
61
+ subject: Opaque identifier of the holder, such as an identity subject
62
+ or a service account id.
63
+ role: Name of the role; its permissions are looked up in the catalog
64
+ at decision time.
65
+ scope: Where the role applies, including everything below it.
66
+ expires_at: The timezone-aware instant from which the grant allows
67
+ nothing; ``None`` when it never expires.
68
+ """
69
+
70
+ subject: str
71
+ role: str
72
+ scope: Scope
73
+ expires_at: datetime | None = None
74
+
75
+ def __post_init__(self) -> None:
76
+ """Reject a grant with no holder, an unusable role name, no scope or a naive expiry."""
77
+ _require_subject(self.subject)
78
+ require_name("role", self.role)
79
+ _require_scope(self.scope)
80
+ object.__setattr__(self, "expires_at", _utc_or_none("A grant expiry", self.expires_at))
81
+
82
+ @property
83
+ def _sort_key(self) -> tuple[str, str, Scope, tuple[int] | tuple[int, datetime]]:
84
+ expiry = _NEVER if self.expires_at is None else (1, self.expires_at)
85
+ return (self.subject, self.role, self.scope, expiry)
86
+
87
+ def __lt__(self, other: object) -> bool:
88
+ """Order by subject, role, scope, then expiry."""
89
+ if not isinstance(other, Grant):
90
+ return NotImplemented
91
+ return self._sort_key < other._sort_key
92
+
93
+
94
+ class GrantSource(Protocol):
95
+ """Where the grants of a subject are loaded from.
96
+
97
+ Any class with this method satisfies the protocol structurally, with no
98
+ inheritance required.
99
+ """
100
+
101
+ async def grants_for(self, subject: str) -> Collection[Grant]:
102
+ """Return every grant held by *subject*.
103
+
104
+ Args:
105
+ subject: Identifier of the holder.
106
+
107
+ Returns:
108
+ The subject's grants; empty when it holds none.
109
+ """
110
+ ...
111
+
112
+
113
+ class InMemoryGrantSource:
114
+ """A :class:`GrantSource` over a fixed list, for tests and examples."""
115
+
116
+ __slots__ = ("_grants",)
117
+
118
+ def __init__(self, grants: Iterable[Grant]) -> None:
119
+ """Hold *grants*, deduplicated in their original order.
120
+
121
+ Args:
122
+ grants: Grants of any number of subjects.
123
+ """
124
+ self._grants = tuple(dict.fromkeys(grants))
125
+
126
+ async def grants_for(self, subject: str) -> Collection[Grant]: # NOSONAR S7503 - protocol
127
+ """Return the grants of *subject*, in the order they were given.
128
+
129
+ Args:
130
+ subject: Identifier of the holder.
131
+
132
+ Returns:
133
+ The subject's grants.
134
+ """
135
+ return tuple(grant for grant in self._grants if grant.subject == subject)
@@ -8,6 +8,22 @@ from dataclasses import dataclass
8
8
  _SEPARATOR = "/"
9
9
 
10
10
 
11
+ def _segments_of(path: Iterable[str]) -> tuple[str, ...]:
12
+ if isinstance(path, str):
13
+ raise TypeError("A scope path is a sequence of segments, not a string; use Scope.parse().")
14
+ return tuple(map(_segment, path))
15
+
16
+
17
+ def _segment(value: object) -> str:
18
+ if not isinstance(value, str):
19
+ raise TypeError(f"A scope segment must be a string: {value!r}.")
20
+ if not value or _SEPARATOR in value:
21
+ raise ValueError(
22
+ f"A scope segment must be non-empty and free of {_SEPARATOR!r}: {value!r}."
23
+ )
24
+ return value
25
+
26
+
11
27
  @dataclass(frozen=True, slots=True, order=True, init=False)
12
28
  class Scope:
13
29
  """A node in the product's resource hierarchy.
@@ -43,19 +59,7 @@ class Scope:
43
59
  TypeError: When *path* is a single string or holds a non-string.
44
60
  ValueError: When a segment is empty or contains ``/``.
45
61
  """
46
- if isinstance(path, str):
47
- raise TypeError(
48
- "A scope path is a sequence of segments, not a string; use Scope.parse()."
49
- )
50
- segments = tuple(path)
51
- for segment in segments:
52
- if not isinstance(segment, str):
53
- raise TypeError(f"A scope segment must be a string: {segment!r}.")
54
- if not segment or _SEPARATOR in segment:
55
- raise ValueError(
56
- f"A scope segment must be non-empty and free of {_SEPARATOR!r}: {segment!r}."
57
- )
58
- object.__setattr__(self, "path", segments)
62
+ object.__setattr__(self, "path", _segments_of(path))
59
63
 
60
64
  @classmethod
61
65
  def root(cls) -> Scope:
@@ -13,6 +13,7 @@ from loom.core.repository.sqlalchemy.registry import (
13
13
  )
14
14
  from loom.core.repository.sqlalchemy.repository import RepositorySQLAlchemy, with_session_scope
15
15
  from loom.core.repository.sqlalchemy.session_manager import SessionManager
16
+ from loom.core.repository.sqlalchemy.session_settings import SessionSettings
16
17
  from loom.core.repository.sqlalchemy.transactional import SupportsPostCommit, transactional
17
18
 
18
19
  __all__ = [
@@ -24,6 +25,7 @@ __all__ = [
24
25
  "Projection",
25
26
  "RepositorySQLAlchemy",
26
27
  "SessionManager",
28
+ "SessionSettings",
27
29
  "SupportsPostCommit",
28
30
  "TimestampMixin",
29
31
  "SQLAlchemyDefaultRepositoryBuilder",
@@ -5,14 +5,20 @@ from contextlib import asynccontextmanager
5
5
  from typing import Any
6
6
 
7
7
  from sqlalchemy import event
8
+ from sqlalchemy.engine import make_url
8
9
  from sqlalchemy.ext.asyncio import (
9
10
  AsyncEngine,
10
11
  AsyncSession,
11
12
  async_sessionmaker,
12
13
  create_async_engine,
13
14
  )
15
+ from sqlalchemy.orm import Session
14
16
 
15
17
  from loom.core.logger import get_logger
18
+ from loom.core.repository.sqlalchemy.session_settings import (
19
+ SessionSettings,
20
+ install_session_settings,
21
+ )
16
22
  from loom.core.tracing import get_trace_id
17
23
 
18
24
 
@@ -25,6 +31,7 @@ class SessionManager:
25
31
  config: Mapping[str, Any],
26
32
  *,
27
33
  inject_trace_id: bool = True,
34
+ session_settings: SessionSettings | None = None,
28
35
  **engine_kwargs: object,
29
36
  ) -> SessionManager:
30
37
  """Build a session manager from a resolved SQLAlchemy config mapping.
@@ -34,6 +41,8 @@ class SessionManager:
34
41
  optional pool tuning keys.
35
42
  inject_trace_id: When ``True``, prefixes SQL statements with the
36
43
  active trace id when available.
44
+ session_settings: Optional provider of transaction-local Postgres
45
+ settings; see :meth:`SessionManager.__init__` for the contract.
37
46
  **engine_kwargs: Additional keyword arguments forwarded to the
38
47
  async engine constructor.
39
48
 
@@ -41,7 +50,8 @@ class SessionManager:
41
50
  A configured :class:`SessionManager`.
42
51
 
43
52
  Raises:
44
- ValueError: If ``url`` is missing or empty.
53
+ ValueError: If ``url`` is missing or empty, or if ``session_settings``
54
+ is given and ``url`` is not a Postgres URL.
45
55
  """
46
56
  url = config.get("url")
47
57
  if not url:
@@ -56,6 +66,7 @@ class SessionManager:
56
66
  pool_recycle=_optional_int(config.get("pool_recycle"), 1800),
57
67
  connect_args=dict(config.get("connect_args") or {}),
58
68
  inject_trace_id=inject_trace_id,
69
+ session_settings=session_settings,
59
70
  **engine_kwargs,
60
71
  )
61
72
 
@@ -71,6 +82,7 @@ class SessionManager:
71
82
  pool_recycle: int | None = 1800,
72
83
  connect_args: dict[str, object] | None = None,
73
84
  inject_trace_id: bool = True,
85
+ session_settings: SessionSettings | None = None,
74
86
  **engine_kwargs: object,
75
87
  ) -> None:
76
88
  """Create a session manager backed by an async SQLAlchemy engine.
@@ -88,8 +100,32 @@ class SessionManager:
88
100
  ``/* trace_id=<id> */`` comment when a trace identifier is active
89
101
  in the current async context. Visible in database slow-query logs
90
102
  and ``pg_stat_activity``. Defaults to ``True``.
103
+ session_settings: When given, a callable that returns the settings for
104
+ the transaction about to start, or ``None`` to apply none. Each
105
+ outer transaction then begins with one ``SELECT`` that calls
106
+ ``set_config(key, value, true)`` once per entry, with keys and
107
+ values bound as parameters. The settings are local to the
108
+ transaction, so the connection returns to the pool clean. Postgres
109
+ only, and incompatible with ``isolation_level="AUTOCOMMIT"``, which
110
+ would discard the settings after each statement; when ``None``,
111
+ the manager behaves exactly as it does without this option.
91
112
  **engine_kwargs: Additional keyword arguments forwarded to ``create_async_engine``.
113
+
114
+ Raises:
115
+ ValueError: If ``session_settings`` is given and ``url`` is not a
116
+ Postgres URL, or the engine is configured with
117
+ ``isolation_level="AUTOCOMMIT"``.
92
118
  """
119
+ if session_settings is not None:
120
+ backend = make_url(url).get_backend_name()
121
+ if backend != "postgresql":
122
+ raise ValueError(
123
+ f"session_settings requires a postgresql URL, got backend {backend!r}"
124
+ )
125
+ if _autocommit(engine_kwargs):
126
+ raise ValueError(
127
+ "session_settings is incompatible with isolation_level='AUTOCOMMIT'"
128
+ )
93
129
  engine_config: dict[str, object] = {
94
130
  "echo": echo,
95
131
  "pool_pre_ping": pool_pre_ping,
@@ -108,10 +144,16 @@ class SessionManager:
108
144
 
109
145
  self._log = get_logger(__name__).bind(module="session_manager")
110
146
  self._engine = create_async_engine(url, **engine_config)
147
+ factory_kwargs: dict[str, Any] = {}
148
+ if session_settings is not None:
149
+ session_class = type("SettingsSession", (Session,), {})
150
+ install_session_settings(session_class, session_settings)
151
+ factory_kwargs["sync_session_class"] = session_class
111
152
  self._session_factory = async_sessionmaker(
112
153
  bind=self._engine,
113
154
  class_=AsyncSession,
114
155
  expire_on_commit=False,
156
+ **factory_kwargs,
115
157
  )
116
158
  if inject_trace_id:
117
159
  _register_trace_id_listener(self._engine)
@@ -120,6 +162,7 @@ class SessionManager:
120
162
  backend=self._engine.url.get_backend_name(),
121
163
  driver=self._engine.url.get_driver_name(),
122
164
  inject_trace_id=inject_trace_id,
165
+ session_settings=session_settings is not None,
123
166
  )
124
167
 
125
168
  @asynccontextmanager
@@ -181,6 +224,17 @@ def _register_trace_id_listener(async_engine: AsyncEngine) -> None:
181
224
  return statement, parameters
182
225
 
183
226
 
227
+ def _autocommit(engine_kwargs: Mapping[str, object]) -> bool:
228
+ execution_options = engine_kwargs.get("execution_options")
229
+ levels = (
230
+ engine_kwargs.get("isolation_level"),
231
+ execution_options.get("isolation_level")
232
+ if isinstance(execution_options, Mapping)
233
+ else None,
234
+ )
235
+ return any(isinstance(level, str) and level.upper() == "AUTOCOMMIT" for level in levels)
236
+
237
+
184
238
  def _optional_int(value: Any, default: int) -> int:
185
239
  if value is None:
186
240
  return default
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+
3
+ import re
4
+ from collections.abc import Callable, Mapping
5
+ from typing import Any
6
+
7
+ from sqlalchemy import TextClause, event, text
8
+ from sqlalchemy.orm import Session
9
+
10
+ SessionSettings = Callable[[], Mapping[str, str] | None]
11
+ """Returns the settings to apply to the transaction about to start, or ``None`` to apply none.
12
+
13
+ loom does not interpret the keys or values. A product returns, for example, the tenant
14
+ and the subject of the current request, and writes its Postgres policies against
15
+ ``current_setting(key, true)``.
16
+ """
17
+
18
+ _KEY = re.compile(r"[A-Za-z_]\w*\.[A-Za-z_]\w*")
19
+
20
+
21
+ def settings_statement(
22
+ values: Mapping[str, str] | None,
23
+ ) -> tuple[TextClause, dict[str, str]] | None:
24
+ """Build the one statement that sets *values* for the current transaction.
25
+
26
+ Every key and value is bound as a parameter: the compiled SQL carries only
27
+ placeholders. Keys must be application-prefixed identifiers, ``prefix.name``,
28
+ which is what Postgres requires of a custom setting.
29
+
30
+ Args:
31
+ values: The settings to apply, or ``None``.
32
+
33
+ Returns:
34
+ The ``SELECT set_config(...)`` clause with its parameters, or ``None``
35
+ when there is nothing to set.
36
+
37
+ Raises:
38
+ ValueError: If a key is not a string of the form ``prefix.name``.
39
+ TypeError: If a value is not a ``str``.
40
+ """
41
+ if not values:
42
+ return None
43
+ calls: list[str] = []
44
+ params: dict[str, str] = {}
45
+ for index, (key, value) in enumerate(values.items()):
46
+ if not isinstance(key, str) or _KEY.fullmatch(key) is None:
47
+ raise ValueError(
48
+ f"session setting key must be a str of the form 'prefix.name', got {key!r}"
49
+ )
50
+ if not isinstance(value, str):
51
+ raise TypeError(
52
+ f"session setting value for {key!r} must be str, got {type(value).__name__}"
53
+ )
54
+ calls.append(f"set_config(:k{index}, :v{index}, true)")
55
+ params[f"k{index}"] = key
56
+ params[f"v{index}"] = value
57
+ return text("SELECT " + ", ".join(calls)), params
58
+
59
+
60
+ def install_session_settings(session_class: type[Session], provider: SessionSettings) -> None:
61
+ """Apply *provider*'s settings at the start of every outer transaction of *session_class*.
62
+
63
+ The listener runs once per outer transaction and not for savepoints. A provider
64
+ that raises, an invalid key, or a non-``str`` value fails the transaction before
65
+ its first product statement reaches the database, and invalidates its connection,
66
+ so the session refuses further statements until it is rolled back.
67
+
68
+ Args:
69
+ session_class: The synchronous ``Session`` subclass the listener is bound to.
70
+ provider: The settings provider called at the start of each transaction.
71
+ """
72
+
73
+ @event.listens_for(session_class, "after_begin")
74
+ def _apply_session_settings(_session: Session, transaction: Any, connection: Any) -> None:
75
+ if transaction.nested:
76
+ return
77
+ try:
78
+ statement = settings_statement(provider())
79
+ if statement is not None:
80
+ connection.execute(*statement)
81
+ except BaseException:
82
+ connection.invalidate()
83
+ raise