loom-kernel 2.18.0__tar.gz → 2.20.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 (688) hide show
  1. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/CHANGELOG.md +240 -11
  2. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/PKG-INFO +1 -1
  3. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/_fingerprint.py +3 -13
  4. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/_plan.py +18 -10
  5. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/config.py +18 -2
  6. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_limits.py +1 -1
  7. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/errors.py +18 -0
  8. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/_batch.py +35 -13
  9. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/_columns.py +44 -15
  10. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/_frames.py +9 -9
  11. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/_ledger.py +0 -12
  12. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/_runner.py +8 -4
  13. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/_validation.py +27 -10
  14. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/pricing.py +3 -2
  15. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/backend/core_model.py +2 -1
  16. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/backend/sqlalchemy.py +43 -8
  17. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/repository.py +64 -36
  18. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/errors/errors.py +9 -7
  19. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/__init__.py +2 -0
  20. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/introspection.py +14 -5
  21. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/cursor.py +32 -8
  22. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/dynamodb/repository.py +17 -2
  23. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/repository.py +17 -4
  24. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/mixins.py +82 -36
  25. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +21 -9
  26. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +22 -11
  27. loom_kernel-2.20.0/src/loom/etl/_uri.py +20 -0
  28. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_write_policy.py +44 -16
  29. loom_kernel-2.20.0/src/loom/etl/backends/polars/_frame.py +15 -0
  30. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_historify.py +4 -5
  31. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_reader.py +4 -23
  32. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_schema.py +43 -1
  33. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_writer.py +3 -3
  34. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/_writer.py +44 -3
  35. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_backends/_polars.py +2 -2
  36. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_cleaners.py +0 -11
  37. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_errors.py +11 -0
  38. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_filter.py +4 -4
  39. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_validators_agents.py +4 -14
  40. loom_kernel-2.20.0/src/loom/etl/declarative/_with_agent.py +109 -0
  41. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_errors.py +2 -2
  42. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_into.py +4 -2
  43. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_table.py +4 -5
  44. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/executor/_dispatcher.py +15 -20
  45. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/_builder.py +4 -2
  46. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/_ops.py +5 -3
  47. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/_wiring.py +2 -2
  48. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/config_loader.py +2 -2
  49. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/storage/_config.py +7 -5
  50. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/deploy/_discovery.py +51 -15
  51. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/notify/__init__.py +4 -2
  52. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/notify/_factory.py +13 -0
  53. loom_kernel-2.20.0/src/loom/prefect/notify/_format.py +40 -0
  54. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/notify/_slack.py +8 -32
  55. loom_kernel-2.20.0/src/loom/prefect/notify/_sns.py +78 -0
  56. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/observer/_logging_bridge.py +9 -6
  57. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/autocrud.py +30 -6
  58. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/auto.py +8 -9
  59. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/in_memory.py +22 -1
  60. loom_kernel-2.18.0/src/loom/etl/declarative/_with_agent.py +0 -70
  61. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/.gitignore +0 -0
  62. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/LICENSE +0 -0
  63. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/README.md +0 -0
  64. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/pyproject.toml +0 -0
  65. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/__init__.py +0 -0
  66. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/__init__.py +0 -0
  67. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_concurrency.py +0 -0
  68. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_filters.py +0 -0
  69. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_paths.py +0 -0
  70. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_roles.py +0 -0
  71. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_startup.py +0 -0
  72. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_transport.py +0 -0
  73. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/_usecase.py +0 -0
  74. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/__init__.py +0 -0
  75. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/_binding.py +0 -0
  76. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/_handlers.py +0 -0
  77. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/_rpc.py +0 -0
  78. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/card.py +0 -0
  79. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/events.py +0 -0
  80. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/a2a/server.py +0 -0
  81. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/abc.py +0 -0
  82. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/bootstrap.py +0 -0
  83. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/__init__.py +0 -0
  84. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/_compiler.py +0 -0
  85. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
  86. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
  87. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
  88. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
  89. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
  90. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
  91. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
  92. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
  93. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_output.py +0 -0
  94. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/compiler/phases/_state.py +0 -0
  95. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/declarative/__init__.py +0 -0
  96. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/declarative/_envelope.py +0 -0
  97. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/declarative/_schema.py +0 -0
  98. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/declarative/_v1.py +0 -0
  99. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
  100. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/describe.py +0 -0
  101. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/__init__.py +0 -0
  102. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
  103. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
  104. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +0 -0
  105. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
  106. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
  107. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
  108. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
  109. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
  110. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
  111. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
  112. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +0 -0
  113. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
  114. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
  115. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
  116. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
  117. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +0 -0
  118. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
  119. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
  120. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
  121. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
  122. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
  123. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
  124. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
  125. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
  126. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +0 -0
  127. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
  128. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
  129. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
  130. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
  131. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
  132. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/etl/__init__.py +0 -0
  133. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/fastapi/__init__.py +0 -0
  134. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/fastapi/endpoints.py +0 -0
  135. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/fastapi/response.py +0 -0
  136. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/fastapi/streaming.py +0 -0
  137. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/inference.py +0 -0
  138. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/registry.py +0 -0
  139. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/remote_auth.py +0 -0
  140. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/__init__.py +0 -0
  141. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_bounded.py +0 -0
  142. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_chain.py +0 -0
  143. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_conversation.py +0 -0
  144. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_grants.py +0 -0
  145. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_handle.py +0 -0
  146. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_health.py +0 -0
  147. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_hooks.py +0 -0
  148. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_lifecycle.py +0 -0
  149. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_limits.py +0 -0
  150. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/runtime/_mcp.py +0 -0
  151. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/validate/__init__.py +0 -0
  152. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/ai/validate/__main__.py +0 -0
  153. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/__init__.py +0 -0
  154. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/auto.py +0 -0
  155. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/bootstrap.py +0 -0
  156. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/config.py +0 -0
  157. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/constants.py +0 -0
  158. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/runner.py +0 -0
  159. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/celery/service.py +0 -0
  160. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/cli/__init__.py +0 -0
  161. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/cli/app.py +0 -0
  162. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/cli/schema.py +0 -0
  163. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/async_bridge.py +0 -0
  164. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/__init__.py +0 -0
  165. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/_decide.py +0 -0
  166. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/_grants.py +0 -0
  167. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/_roles.py +0 -0
  168. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/_scope.py +0 -0
  169. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/elevation.py +0 -0
  170. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/authz/product.py +0 -0
  171. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/backend/__init__.py +0 -0
  172. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/backend/protocol.py +0 -0
  173. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/backend/scoped_ddl.py +0 -0
  174. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/bootstrap/__init__.py +0 -0
  175. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
  176. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/bootstrap/kernel.py +0 -0
  177. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/__init__.py +0 -0
  178. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/_batching.py +0 -0
  179. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/_single_flight.py +0 -0
  180. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/abc/__init__.py +0 -0
  181. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/abc/backend.py +0 -0
  182. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/abc/config.py +0 -0
  183. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/abc/dependency.py +0 -0
  184. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/calls.py +0 -0
  185. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/codec.py +0 -0
  186. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/decorators.py +0 -0
  187. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/dependency.py +0 -0
  188. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/errors.py +0 -0
  189. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/gateway.py +0 -0
  190. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/keys.py +0 -0
  191. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/memory.py +0 -0
  192. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/result_codec.py +0 -0
  193. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/serializer.py +0 -0
  194. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/cache/wiring.py +0 -0
  195. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/command/__init__.py +0 -0
  196. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/command/adapter.py +0 -0
  197. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/command/base.py +0 -0
  198. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/command/field.py +0 -0
  199. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/command/introspection.py +0 -0
  200. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/compiler.py +0 -0
  201. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/__init__.py +0 -0
  202. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/_boto3.py +0 -0
  203. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/_includes.py +0 -0
  204. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/_resolver_utils.py +0 -0
  205. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/binder.py +0 -0
  206. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/configurable.py +0 -0
  207. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/context.py +0 -0
  208. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/errors.py +0 -0
  209. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/keys.py +0 -0
  210. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/loader.py +0 -0
  211. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/model.py +0 -0
  212. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/observability.py +0 -0
  213. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/resolver.py +0 -0
  214. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/secrets.py +0 -0
  215. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/config/ssm.py +0 -0
  216. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/contracts/__init__.py +0 -0
  217. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/contracts/manifest.py +0 -0
  218. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/di/__init__.py +0 -0
  219. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/di/container.py +0 -0
  220. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/di/scope.py +0 -0
  221. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/discovery/__init__.py +0 -0
  222. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/discovery/_utils.py +0 -0
  223. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/discovery/base.py +0 -0
  224. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/discovery/interfaces.py +0 -0
  225. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/discovery/manifest.py +0 -0
  226. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/discovery/modules.py +0 -0
  227. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/__init__.py +0 -0
  228. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/compilable.py +0 -0
  229. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/compiler.py +0 -0
  230. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/events.py +0 -0
  231. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/executor.py +0 -0
  232. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/metrics.py +0 -0
  233. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/plan.py +0 -0
  234. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/engine/post_commit.py +0 -0
  235. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/errors/__init__.py +0 -0
  236. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/errors/codes.py +0 -0
  237. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/expr/__init__.py +0 -0
  238. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/expr/eval.py +0 -0
  239. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/expr/nodes.py +0 -0
  240. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/expr/refs.py +0 -0
  241. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/identity/__init__.py +0 -0
  242. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/identity/context.py +0 -0
  243. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/identity/identity.py +0 -0
  244. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/identity/issuer.py +0 -0
  245. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/identity/wire.py +0 -0
  246. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/introspection/__init__.py +0 -0
  247. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/introspection/base.py +0 -0
  248. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/introspection/describe.py +0 -0
  249. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/job/__init__.py +0 -0
  250. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/job/callback.py +0 -0
  251. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/job/context.py +0 -0
  252. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/job/handle.py +0 -0
  253. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/job/job.py +0 -0
  254. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/job/service.py +0 -0
  255. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/locator.py +0 -0
  256. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/logger/__init__.py +0 -0
  257. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/logger/abc.py +0 -0
  258. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/logger/config.py +0 -0
  259. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/logger/registry.py +0 -0
  260. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/logger/structlogger.py +0 -0
  261. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/_loom_type.py +0 -0
  262. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/base.py +0 -0
  263. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/convert.py +0 -0
  264. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/enums.py +0 -0
  265. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/field.py +0 -0
  266. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/partition.py +0 -0
  267. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/privilege.py +0 -0
  268. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/projection.py +0 -0
  269. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/relation.py +0 -0
  270. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/scoped.py +0 -0
  271. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/struct.py +0 -0
  272. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/timestamped.py +0 -0
  273. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/types.py +0 -0
  274. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/model/types_postgres.py +0 -0
  275. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/__init__.py +0 -0
  276. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/config.py +0 -0
  277. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/event.py +0 -0
  278. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/observer/__init__.py +0 -0
  279. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/observer/noop.py +0 -0
  280. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/observer/otel.py +0 -0
  281. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/observer/structlog.py +0 -0
  282. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/otel_ids.py +0 -0
  283. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/protocol.py +0 -0
  284. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/runtime.py +0 -0
  285. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/span.py +0 -0
  286. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/observability/topology.py +0 -0
  287. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/persistence/__init__.py +0 -0
  288. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/persistence/abc.py +0 -0
  289. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/persistence/none.py +0 -0
  290. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/persistence/registry.py +0 -0
  291. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/plugins/__init__.py +0 -0
  292. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/plugins/entrypoints.py +0 -0
  293. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/plugins/optional.py +0 -0
  294. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/projection/__init__.py +0 -0
  295. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/projection/loaders.py +0 -0
  296. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/projection/runtime.py +0 -0
  297. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/__init__.py +0 -0
  298. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/__init__.py +0 -0
  299. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/errors.py +0 -0
  300. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/query.py +0 -0
  301. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
  302. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/repo_for.py +0 -0
  303. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/repository.py +0 -0
  304. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/abc/session_scope.py +0 -0
  305. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
  306. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
  307. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
  308. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
  309. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/__init__.py +0 -0
  310. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/backend.py +0 -0
  311. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/ids.py +0 -0
  312. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
  313. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/registry.py +0 -0
  314. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/uow.py +0 -0
  315. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mongo/values.py +0 -0
  316. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/mutation.py +0 -0
  317. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/registration.py +0 -0
  318. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/registry.py +0 -0
  319. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
  320. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/backend.py +0 -0
  321. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
  322. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
  323. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/migrations/__init__.py +0 -0
  324. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/migrations/env_template.py +0 -0
  325. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/migrations/hook.py +0 -0
  326. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/migrations/operations.py +0 -0
  327. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/migrations/runners.py +0 -0
  328. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
  329. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
  330. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
  331. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
  332. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
  333. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
  334. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
  335. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
  336. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
  337. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
  338. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
  339. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/__init__.py +0 -0
  340. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/bootstrap.py +0 -0
  341. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/config.py +0 -0
  342. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/elevate.py +0 -0
  343. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/guard/0001.sql +0 -0
  344. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/guard/0002.sql +0 -0
  345. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/guard/preflight.sql +0 -0
  346. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/guard_manifest.py +0 -0
  347. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/integrity.py +0 -0
  348. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/partitions.py +0 -0
  349. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/provider.py +0 -0
  350. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/schema.py +0 -0
  351. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/sources.py +0 -0
  352. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/rls/verify.py +0 -0
  353. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
  354. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/session_settings.py +0 -0
  355. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
  356. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
  357. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/response/__init__.py +0 -0
  358. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/response/base.py +0 -0
  359. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/routing/__init__.py +0 -0
  360. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/routing/ref.py +0 -0
  361. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/routing/resolver.py +0 -0
  362. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/runner.py +0 -0
  363. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/schema/__init__.py +0 -0
  364. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/schema/schema_mode.py +0 -0
  365. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/schema_names.py +0 -0
  366. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/__init__.py +0 -0
  367. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/abc/__init__.py +0 -0
  368. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/abc/contracts.py +0 -0
  369. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/abc/errors.py +0 -0
  370. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/caller_bound.py +0 -0
  371. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
  372. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
  373. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
  374. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
  375. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/config.py +0 -0
  376. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/roles.py +0 -0
  377. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/sql/service.py +0 -0
  378. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/symbols.py +0 -0
  379. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/tracing/__init__.py +0 -0
  380. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/tracing/context.py +0 -0
  381. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/transaction.py +0 -0
  382. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/transport/__init__.py +0 -0
  383. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/transport/adapter.py +0 -0
  384. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/uow/__init__.py +0 -0
  385. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/uow/abc.py +0 -0
  386. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/uow/context.py +0 -0
  387. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/__init__.py +0 -0
  388. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/_predicates.py +0 -0
  389. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/agent_markers.py +0 -0
  390. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/compute.py +0 -0
  391. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/constants.py +0 -0
  392. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/factory.py +0 -0
  393. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/field_ref.py +0 -0
  394. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/invoker.py +0 -0
  395. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/keys.py +0 -0
  396. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/markers.py +0 -0
  397. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/mcp_markers.py +0 -0
  398. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/registry.py +0 -0
  399. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/rule.py +0 -0
  400. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/core/use_case/use_case.py +0 -0
  401. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/__init__.py +0 -0
  402. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/__init__.py +0 -0
  403. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_format_registry.py +0 -0
  404. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
  405. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_historify/_common.py +0 -0
  406. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_historify/_log.py +0 -0
  407. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
  408. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
  409. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
  410. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_merge.py +0 -0
  411. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_path_template.py +0 -0
  412. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_predicate.py +0 -0
  413. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
  414. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
  415. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
  416. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/__init__.py +0 -0
  417. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
  418. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
  419. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
  420. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
  421. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
  422. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/polars/provider.py +0 -0
  423. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/__init__.py +0 -0
  424. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
  425. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/_historify.py +0 -0
  426. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/_reader.py +0 -0
  427. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/_schema.py +0 -0
  428. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
  429. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/backends/spark/provider.py +0 -0
  430. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/__init__.py +0 -0
  431. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
  432. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_options.py +0 -0
  433. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_paths.py +0 -0
  434. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_scope.py +0 -0
  435. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/checkpoint/_store.py +0 -0
  436. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/__init__.py +0 -0
  437. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_binding.py +0 -0
  438. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_compiler.py +0 -0
  439. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_plan.py +0 -0
  440. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_validators.py +0 -0
  441. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_validators_config.py +0 -0
  442. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
  443. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/compiler/_validators_step.py +0 -0
  444. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/__init__.py +0 -0
  445. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/_format.py +0 -0
  446. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/_read_options.py +0 -0
  447. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/_utils.py +0 -0
  448. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/_write_options.py +0 -0
  449. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
  450. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/expr/_params.py +0 -0
  451. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
  452. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
  453. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
  454. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/__init__.py +0 -0
  455. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/_from.py +0 -0
  456. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
  457. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
  458. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
  459. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
  460. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/source/_specs.py +0 -0
  461. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/__init__.py +0 -0
  462. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_client.py +0 -0
  463. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_file.py +0 -0
  464. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
  465. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
  466. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
  467. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
  468. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
  469. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
  470. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
  471. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/declarative/target/_temp.py +0 -0
  472. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/executor/__init__.py +0 -0
  473. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/executor/_agents.py +0 -0
  474. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/executor/_executor.py +0 -0
  475. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/__init__.py +0 -0
  476. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/_registry.py +0 -0
  477. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/__init__.py +0 -0
  478. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
  479. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
  480. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
  481. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
  482. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_mongo.py +0 -0
  483. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
  484. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
  485. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
  486. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/sources/_serialization.py +0 -0
  487. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/targets/__init__.py +0 -0
  488. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
  489. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/__init__.py +0 -0
  490. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/_config.py +0 -0
  491. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/_observer.py +0 -0
  492. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/_records.py +0 -0
  493. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
  494. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
  495. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
  496. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
  497. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/__init__.py +0 -0
  498. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/_protocol.py +0 -0
  499. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/_runner.py +0 -0
  500. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/_step.py +0 -0
  501. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
  502. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
  503. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/__init__.py +0 -0
  504. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_generics.py +0 -0
  505. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_params.py +0 -0
  506. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
  507. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_process.py +0 -0
  508. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_sql.py +0 -0
  509. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_step.py +0 -0
  510. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_step_client.py +0 -0
  511. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
  512. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/__init__.py +0 -0
  513. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/_agents.py +0 -0
  514. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/_providers.py +0 -0
  515. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/core.py +0 -0
  516. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/errors.py +0 -0
  517. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runner/filtering.py +0 -0
  518. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runtime/__init__.py +0 -0
  519. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runtime/_config_values.py +0 -0
  520. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/runtime/contracts.py +0 -0
  521. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/schema/__init__.py +0 -0
  522. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/schema/_contract.py +0 -0
  523. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/schema/_schema.py +0 -0
  524. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/storage/__init__.py +0 -0
  525. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/storage/_file_locator.py +0 -0
  526. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/storage/_locator.py +0 -0
  527. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/storage/routing.py +0 -0
  528. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/testing/__init__.py +0 -0
  529. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/testing/_result.py +0 -0
  530. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/testing/_runners.py +0 -0
  531. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/testing/_scenario.py +0 -0
  532. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/testing/_stubs.py +0 -0
  533. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/etl/testing/spark.py +0 -0
  534. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/__init__.py +0 -0
  535. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_async.py +0 -0
  536. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_config.py +0 -0
  537. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_ctx.py +0 -0
  538. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_flow_yaml.py +0 -0
  539. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_meta.py +0 -0
  540. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_placeholders.py +0 -0
  541. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/_summary.py +0 -0
  542. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/deploy/__init__.py +0 -0
  543. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/deploy/_schedule.py +0 -0
  544. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
  545. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
  546. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/__init__.py +0 -0
  547. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_assemble.py +0 -0
  548. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_backfill.py +0 -0
  549. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
  550. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_body.py +0 -0
  551. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_common.py +0 -0
  552. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_factory.py +0 -0
  553. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_hooks.py +0 -0
  554. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_maintenance.py +0 -0
  555. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_params.py +0 -0
  556. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_run_name.py +0 -0
  557. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_runtime.py +0 -0
  558. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_signature.py +0 -0
  559. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/flow/_stages.py +0 -0
  560. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/manifest/__init__.py +0 -0
  561. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/manifest/_model.py +0 -0
  562. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/manifest/_s3.py +0 -0
  563. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/manifest/_store.py +0 -0
  564. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/notify/_event.py +0 -0
  565. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/notify/_port.py +0 -0
  566. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/observer/__init__.py +0 -0
  567. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/observer/_flow.py +0 -0
  568. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/observer/_manifest.py +0 -0
  569. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prefect/observer/_task_run.py +0 -0
  570. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prometheus/__init__.py +0 -0
  571. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prometheus/_instruments.py +0 -0
  572. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prometheus/adapter.py +0 -0
  573. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prometheus/kafka.py +0 -0
  574. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prometheus/lifecycle.py +0 -0
  575. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/prometheus/middleware.py +0 -0
  576. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/py.typed +0 -0
  577. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/__init__.py +0 -0
  578. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/_body.py +0 -0
  579. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/adapter.py +0 -0
  580. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/auth/__init__.py +0 -0
  581. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/auth/abc.py +0 -0
  582. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/auth/config.py +0 -0
  583. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/auth/jwt.py +0 -0
  584. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/auth/middleware.py +0 -0
  585. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/compiler.py +0 -0
  586. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/config.py +0 -0
  587. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/constants.py +0 -0
  588. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/cors.py +0 -0
  589. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/errors.py +0 -0
  590. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/__init__.py +0 -0
  591. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/_errors.py +0 -0
  592. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
  593. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/app.py +0 -0
  594. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/health.py +0 -0
  595. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/openapi.py +0 -0
  596. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/response.py +0 -0
  597. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
  598. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/fastapi/sql.py +0 -0
  599. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/middleware.py +0 -0
  600. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/model.py +0 -0
  601. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/rest/rest_adapter.py +0 -0
  602. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/__init__.py +0 -0
  603. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/__init__.py +0 -0
  604. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
  605. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
  606. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
  607. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_dlq.py +0 -0
  608. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
  609. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_errors.py +0 -0
  610. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_operators.py +0 -0
  611. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
  612. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
  613. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
  614. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
  615. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
  616. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
  617. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
  618. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
  619. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
  620. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
  621. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
  622. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
  623. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/bytewax/runner.py +0 -0
  624. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/__init__.py +0 -0
  625. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/_bindings.py +0 -0
  626. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/_compiler.py +0 -0
  627. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/_errors.py +0 -0
  628. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/_plan.py +0 -0
  629. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
  630. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
  631. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/core/__init__.py +0 -0
  632. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/core/_errors.py +0 -0
  633. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/core/_exceptions.py +0 -0
  634. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/core/_message.py +0 -0
  635. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/core/_tracing.py +0 -0
  636. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/core/_typing.py +0 -0
  637. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/graph/__init__.py +0 -0
  638. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/graph/_flow.py +0 -0
  639. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/__init__.py +0 -0
  640. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_codec.py +0 -0
  641. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_config.py +0 -0
  642. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_errors.py +0 -0
  643. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
  644. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_message.py +0 -0
  645. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_record.py +0 -0
  646. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/_wire.py +0 -0
  647. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
  648. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
  649. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
  650. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
  651. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
  652. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
  653. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
  654. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
  655. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
  656. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/mongo/__init__.py +0 -0
  657. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
  658. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/mongo/_config.py +0 -0
  659. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/mongo/_event.py +0 -0
  660. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/mongo/_normalize.py +0 -0
  661. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/__init__.py +0 -0
  662. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_boundary.py +0 -0
  663. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_branches.py +0 -0
  664. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
  665. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
  666. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_decompose.py +0 -0
  667. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
  668. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
  669. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_fork.py +0 -0
  670. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_helpers.py +0 -0
  671. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_mongo.py +0 -0
  672. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_protocols.py +0 -0
  673. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_router.py +0 -0
  674. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_shape.py +0 -0
  675. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_sink.py +0 -0
  676. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_step.py +0 -0
  677. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
  678. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_table/common.py +0 -0
  679. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_table/config.py +0 -0
  680. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/_with.py +0 -0
  681. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/nodes/refs.py +0 -0
  682. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/streaming/testing.py +0 -0
  683. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/__init__.py +0 -0
  684. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/agents.py +0 -0
  685. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/golden.py +0 -0
  686. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/http_harness.py +0 -0
  687. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/repository_harness.py +0 -0
  688. {loom_kernel-2.18.0 → loom_kernel-2.20.0}/src/loom/testing/runner.py +0 -0
@@ -90,6 +90,9 @@
90
90
 
91
91
  ### ai
92
92
 
93
+ - **ai:** `AiConfig` logs a warning for every key of `ai.prices` that no
94
+ binding of `ai.models` names, a price no run is priced with (a misspelt
95
+ model id, for instance).
93
96
  - **ai:** `provider: typesafe` binds TypeSafe's Jev, a decision model that
94
97
  fills a typed output from the state it is given and never writes text, so a
95
98
  role whose answer is a choice or a verdict can run on it. Extra
@@ -153,12 +156,14 @@
153
156
  assembles an unentered `AgentRuntime` from an `ai:` section: engine,
154
157
  artifacts under `root`, compilation. `create_app` now builds its runtime
155
158
  through it. `AgentRuntime.plans` exposes the compiled plans.
156
- - **ai:** `AgentPlan.fingerprint`, a stable sha256 of what decides an
157
- agent's answers: compiled instructions, output schema, output check (by
158
- import path), policies, `spec_version`, the kind and name of every
159
- capability and the bound provider, model, `output_mode` and `options`; not
160
- the name, metadata, price, where a capability is served from, region,
161
- endpoint, credentials or `streaming`.
159
+ - **ai:** `AgentPlan.fingerprint`, a stable sha256 of the declared facts
160
+ that decide an agent's answers: `spec_version`, compiled instructions,
161
+ output schema, output check (by import path), the kind and declared facts
162
+ of every capability (including the `include`/`exclude` filters of `mcp`
163
+ and `a2a`) and the bound provider, model, `output_mode` and `options`; not
164
+ the policies, the content of the skills, tools or use cases a capability
165
+ names, the name, metadata, price, where a capability is served from,
166
+ region, endpoint, credentials or `streaming`.
162
167
  - **ai:** `loom.ai.etl.PolarsAgentRunner` runs an agent over a Polars frame
163
168
  for ETL steps (see `etl`): a runtime of its own per call that also sees the
164
169
  caller's context variables, concurrency that waits instead of refusing, one
@@ -250,6 +255,14 @@
250
255
  attribute name (the flow name with `-` replaced by `_`), as the worker
251
256
  imports it, and raises `ValueError` otherwise; a module not yet imported is
252
257
  imported from that file. Any other object raises `TypeError`.
258
+ - **prefect:** a flow can notify an AWS SNS topic. The `notifications` list
259
+ takes `kind: sns` with `topic_arn` and the same `on_failure` (default
260
+ `true`) and `on_completion` (default `false`) filters as `kind: slack`; an
261
+ empty `topic_arn` skips the entry. Matching terminal states are published
262
+ through boto3 (`prefect` extra) in the topic's region with subject
263
+ `[<state>] <flow>` and a plain-text message with the run details, the end of
264
+ the error message and the Prefect link. A failed publish is logged and does
265
+ not fail the run. `SnsNotifier` is exported from `loom.prefect.notify`.
253
266
 
254
267
  ### etl
255
268
 
@@ -333,11 +346,14 @@
333
346
  exported from `loom.etl`, carrying `table_ref`) before it creates or writes
334
347
  anything, so a dimension rebuilt from a read that came back empty keeps its
335
348
  rows and the step fails. Polars checks the row count of the frame the
336
- replace already collects, at no extra cost; Spark runs `isEmpty()`, one
337
- job that stops at the first row, before the write recomputes the frame. On
338
- Polars a `Null`-typed column still fails first, with `SchemaError`. On
339
- Spark a streaming DataFrame, whose rows cannot be counted before the
340
- write, raises `ValueError` and the table is left as it was.
349
+ replace already collects, at no extra cost. Spark computes the frame once
350
+ with `localCheckpoint(eager=True)`, checks that result with `isEmpty()`,
351
+ writes it and then frees its blocks, as described under Fixes; a Spark
352
+ Connect DataFrame, which has no `localCheckpoint()` in pyspark 3.5, is
353
+ persisted, counted, written and unpersisted instead. On Polars a
354
+ `Null`-typed column still fails first, with `SchemaError`. On Spark a
355
+ streaming DataFrame, whose rows cannot be counted before the write, raises
356
+ `ValueError` and the table is left as it was.
341
357
  The default, `allow_empty=True`, keeps today's behaviour, and `ReplaceSpec`
342
358
  gains the `allow_empty` field.
343
359
  - **etl:** `MaintenanceSpec`, `VacuumSpec`, `CompactSpec` and `ZOrderSpec` are
@@ -359,6 +375,34 @@
359
375
 
360
376
  ### core
361
377
 
378
+ - **core:** on a model with a composite primary key, the SQLAlchemy
379
+ repository's `get_by_id`, `exists`, `update` and `delete` take the key as a
380
+ tuple of every key value in declaration order (`repo.get_by_id((account_id,
381
+ entry_id))`) and raise `ValueError` for anything else, a scalar included,
382
+ instead of matching the first key column. A `Load` step and a cached
383
+ repository's `get_by_id`, `update` and `delete` pass the id unchanged, so a
384
+ scalar id raises there too; a cached `@cache_query(scope="entity")` read
385
+ takes the tuple as its first argument and raises `TypeError` for anything
386
+ else. A cursor token issued for such a model before this release is refused with
387
+ `UnsupportedQuery`, `400 unsupported_query`; clients restart from the first
388
+ page. `decode_cursor` takes `id_count`, the number of key columns, and
389
+ `get_id_attributes` returns every key column name.
390
+
391
+ - **core:** `compile_all` raises `ValueError` for a model with a composite
392
+ primary key that declares a relation or a projection whose loader runs
393
+ `load_many`, naming the model, its key and those fields. The backend loads
394
+ them by the first key column only, so a many-to-one relation attached
395
+ another owner's row and a one-to-many relation grouped children by that
396
+ column; load them by hand until they are matched by the full key.
397
+
398
+ - **core:** the `RepositoryMongo`, `RepositoryDynamoDB` and
399
+ `loom.testing.InMemoryRepository` constructors raise `ConfigError` for a
400
+ model with a composite primary key, naming the model and its key. Each
401
+ keys an item by one field (Mongo's `_id` and the DynamoDB partition key by
402
+ the first key column, the in-memory store by its `id_field`), so a second
403
+ row sharing that field's value raised `Conflict` on Mongo and DynamoDB and
404
+ replaced the first row in memory.
405
+
362
406
  - **core:** the miss path of a cached `@cache_query`/`@cache_call` read,
363
407
  `McpHandle.call` and `CacheGateway.get_value`/`multi_get_values` now raise
364
408
  `BoundaryValidationError` — a `ValueError` — on a stale or malformed cached
@@ -370,6 +414,51 @@
370
414
 
371
415
  ### ai
372
416
 
417
+ - **ai:** `AgentPlan.fingerprint`, and so the ETL `agent_version` column,
418
+ changes once for every existing agent. It no longer covers any policy, so
419
+ changing `retries`, a timeout, `max_iterations`, `max_tool_calls`,
420
+ `max_requests`, a token cap, `max_usd`, `on_unpriced_spend` or
421
+ `max_history_bytes` keeps it; and it now covers the `include`/`exclude`
422
+ filters of `mcp` and `a2a` capabilities, so changing a filter changes it.
423
+ A step that keeps `agent_version` in its upsert keys and its anti-join
424
+ re-runs, and pays for, every row of the anti-join window on its next
425
+ execution after the upgrade.
426
+ - **ai:** in `PolarsAgentRunner.map`, a field of a pydantic output whose type
427
+ is another pydantic model is now a `Struct` column of that model's fields,
428
+ named by alias, instead of a `String` holding its JSON. Writing it into a
429
+ Delta table created before fails with `SchemaError` naming the column (see
430
+ the `etl` entry on casts between text and nested types). To keep writing to
431
+ that table, rewrite it once with the column decoded through the model,
432
+ `pl.Series(name, [None if c is None else Model.model_validate_json(c).model_dump(by_alias=True) for c in frame[name]], dtype=<the Struct type>)`,
433
+ and `schema=SchemaMode.OVERWRITE` (delta-rs `schema_mode="overwrite"`).
434
+ `pl.col(name).str.json_decode(<the Struct type>)` fails with
435
+ `ComputeError` when the model has a `date` field (Polars 1.39.3).
436
+ - **ai:** in `PolarsAgentRunner.map`, a `String` column holding a value's JSON
437
+ now holds the JSON of a string too: `"5"` is written `"\"5\""` and `5` is
438
+ written `5`, where both were `5`. This covers a field typed as a union of
439
+ several types, `Any` or a `Literal` mixing value types whose answer is a
440
+ string. A `UUID`, `time`, `timedelta` or `bytes` field keeps its plain text
441
+ (`P1D` is written `P1D`). Rows written before hold the raw string and rows
442
+ written after hold its JSON encoding. A cell alone does not always tell
443
+ them apart (an old `5` may have been the string `"5"`), but `agent_version`
444
+ does: every agent's fingerprint changes with this release, so the old rows
445
+ carry the old version. Re-run the old rows of such a field, or rewrite each
446
+ old cell whose answer was a string as the JSON encoding of its text.
447
+ - **ai:** the `agent_cost_usd` column `PolarsAgentRunner.map` writes is
448
+ `Decimal(38, 12)` instead of `Float64`, carrying `AgentUsage.cost` without a
449
+ float conversion, rounded half to even to 12 decimal places. Writing into a
450
+ Delta table created before does not fail: an append, upsert or replace with
451
+ `SchemaMode.STRICT` or `EVOLVE` casts the column back to the table's
452
+ `Float64`. To keep the decimal, rewrite the table once with the column cast
453
+ to `pl.Decimal(38, 12)` and `schema=SchemaMode.OVERWRITE` (delta-rs
454
+ `schema_mode="overwrite"`); the costs already stored keep the precision of
455
+ the float they were written as.
456
+ - **ai:** an `ai:` section with `max_concurrent_runs` below 1 fails to load
457
+ with `MAX_CONCURRENT_RUNS_INVALID`, naming the key and the minimum. Before,
458
+ it loaded; with `0` the runtime refused every run with `TOO_MANY_RUNS` and
459
+ `PolarsAgentRunner.map` on a frame with a prompt waited on a semaphore of
460
+ zero slots and did not return, and a negative value failed when the runtime
461
+ was built.
373
462
  - **ai:** `load_specs`, and so `ai.specs`, refuses a glob that leaves the
374
463
  root it resolves against — a `..` segment, an absolute pattern or a match
375
464
  that resolves outside the root through a symlink — with
@@ -396,6 +485,10 @@
396
485
 
397
486
  ### rest
398
487
 
488
+ - **rest:** auto-CRUD mounts no `/{id}` route (get, update, delete) for a
489
+ model with a composite primary key, since one path segment cannot carry the
490
+ key; naming one of them in `include` raises `ValueError` when the routes are
491
+ built. Those routes matched the first key column only.
399
492
  - **rest:** a JSON object body that fails `Command` validation now answers
400
493
  `422 boundary_validation` with a `violations` list (`{field, message}`
401
494
  pairs, `field` being the wire name the client sent, the same shape
@@ -446,14 +539,41 @@
446
539
  - **prefect:** the private `_deploy_single(flow, meta, work_pool, env)` of
447
540
  `loom.prefect.deploy._discovery` now takes `(flow, meta, plan)`; callers
448
541
  migrate to the public `deploy_flow(flow, env=..., work_pool=...)`.
542
+ - **prefect:** `discover_and_deploy_etls(flows_package=...)` checks every
543
+ flow of the package, its work pool and that its module exposes it under its
544
+ attribute name as `deploy_flow` does, before it registers the first
545
+ deployment. A flow without a work pool for the environment, one its module
546
+ exposes under another attribute name, or one whose source file cannot be
547
+ imported raises `ValueError` and no deployment of the package is
548
+ registered. Flows used to be registered one by one: a flow without a work
549
+ pool raised after the flows before it were registered, and a flow exposed
550
+ under another name or not importable from its source file was registered
551
+ with an entrypoint the worker cannot import.
449
552
 
450
553
  ### etl
451
554
 
555
+ - **etl:** a `WithAgent` compiled by a runner whose config has no `ai:`
556
+ section fails with the new code `AGENT_RUNNER_NOT_CONFIGURED` instead of
557
+ `AGENT_NOT_FOUND`, which now means only that no artifact declares the name.
452
558
  - **etl:** the names of `loom.etl.runner.filtering` (`_filter_plan`,
453
559
  `_filter_process`, `_collect_all_names`, `_map_pipeline_nodes`,
454
560
  `_map_process_nodes`) are deprecated and removed in loom 3.0; each emits a
455
561
  `DeprecationWarning` naming its replacement, `loom.etl.compiler.filter_plan`
456
562
  or, for `_collect_all_names`, `iter_processes` and `iter_all_steps`.
563
+ - **etl:** the Polars writer refuses, under `SchemaMode.STRICT` and
564
+ `EVOLVE`, a frame column that is a `Struct` or `List` where the Delta table
565
+ has `String`, or `String` where the table has a `Struct` or `List`, at any
566
+ depth of a `Struct` or `List`, with `SchemaError` naming the column and
567
+ both types; nothing is written. The check is by dtype, so an all-null
568
+ `String` column written into a `List` column is refused too. Before, a
569
+ `Struct` was cast to its Polars display text (`{1.0}` for a `Float64`
570
+ field) and a `String` to a `List` wrapped or nulled each value, both
571
+ written without an error; a `List` to `String` and a `String` to `Struct`
572
+ failed inside Polars. The Spark writer does not refuse these casts: it
573
+ writes a `Struct` or `List` into a `String` column as text (`{1.0}`,
574
+ `[1]`). To change the column's type,
575
+ rewrite the table once with the column converted and
576
+ `schema=SchemaMode.OVERWRITE` (delta-rs `schema_mode="overwrite"`).
457
577
  - **etl:** `InvalidStageError` names what it reports: its message reads
458
578
  `Unknown step or process names: [...]` instead of `No steps or processes
459
579
  match include=[...]`, the constructor's parameter is `unknown`, and the
@@ -461,11 +581,48 @@
461
581
  unchanged; `InvalidStageError(include=...)` still works, emits a
462
582
  `DeprecationWarning` and is removed in loom 3.0. The error survives pickle
463
583
  with its `unknown` names, so it crosses process boundaries intact.
584
+ - **etl:** `ThreadDispatcher` runs each task in a copy of the caller's
585
+ context, as `asyncio.to_thread` does, so a step of a parallel group sees
586
+ the `ContextVar` values of the run that dispatched it (the Prefect flow run
587
+ among them) and its OpenTelemetry context. A parallel group's step spans
588
+ therefore nest under their process span instead of starting a trace of
589
+ their own. `ParallelDispatcher` lists running each task in a copy of the
590
+ caller's context among the requirements on an implementation.
591
+ - **etl:** `WithAgent(max_usd=...)` keeps the budget as a `Decimal`. An
592
+ `int`, or another `numbers.Integral` such as `numpy.int64`, is converted
593
+ exactly. A `float` emits a `DeprecationWarning`, is converted through its
594
+ `str()` (`0.1` becomes `Decimal("0.1")`) and is removed in loom 3.0. A
595
+ `bool`, accepted before, and any other type, such as `str`, raise
596
+ `TypeError`. `NaN`, `sNaN` and `Infinity`, as a `Decimal` or a `float`,
597
+ raise `ValueError`, like zero and a negative amount; a `Decimal` `NaN` or
598
+ `sNaN` used to raise `decimal.InvalidOperation`, and a `Decimal`
599
+ `Infinity`, a `float` `inf` and a `float` `nan` were accepted.
464
600
 
465
601
  ## 🐛 Fixes
466
602
 
467
603
  ### core
468
604
 
605
+ - **core:** cursor pagination and the by-id operations of the SQLAlchemy
606
+ repository use the full primary key of a model whose key is composite, such
607
+ as a `RowScoped` model keyed by its boundary column and its own id. They
608
+ used only the first key column: a cursor walk ordered and compared on it
609
+ alone and skipped the rows sharing that column's value with the last row of
610
+ each page, and `get_by_id`, `exists`, `update` and `delete` matched that
611
+ column only. The cursor now orders and compares on
612
+ every key column after the sort keys and carries every key value in the
613
+ token; offset pages and `list_paginated` order by every key column too.
614
+ Tokens of single-column keys are unchanged. A cached repository over such a
615
+ model keyed its entries by the first key column too, so a warm
616
+ `list_paginated` or first cursor page served the rows sharing a first key
617
+ value as copies of one of them; it now caches and reloads every row by its
618
+ full key, one `get_by_id` per missing row.
619
+
620
+ - **core:** a `MANY_TO_MANY` relation joins the target table on the column
621
+ the secondary table's foreign key references. It joined on the target
622
+ model's first key column, so a target with a composite key, or whose link
623
+ references a unique non-key column, loaded the rows whose first key column
624
+ held the linked value instead of the linked rows.
625
+
469
626
  - **core:** the RLS guard refuses, in the same statement, a drop outside the
470
627
  hatch that breaks its invariants. `DROP POLICY` or `DROP TRIGGER
471
628
  loom_deny_owner_dml` on a scoped table used to commit, because drops are not
@@ -491,6 +648,42 @@
491
648
 
492
649
  ### etl
493
650
 
651
+ - **etl:** `replace(allow_empty=False)` on Spark writes the rows it checked.
652
+ The writer ran `DataFrame.isEmpty()` and then let the write compute the
653
+ frame again, so a source that changed in between, or a nondeterministic
654
+ plan, could still replace the table with no rows. The frame is now
655
+ computed once with `localCheckpoint(eager=True)`, and the check and the
656
+ write both read that result. Those rows are kept in executor storage, not
657
+ in reliable storage: losing an executor before the write ends fails the
658
+ write instead of recomputing the frame. Once the write ends, whether it
659
+ succeeded or failed, and when the check refuses the frame, the writer
660
+ unpersists the checkpointed RDD, so its blocks do not stay on the executors
661
+ for the rest of the session. A Spark Connect DataFrame has no
662
+ `localCheckpoint()` in pyspark 3.5: it is persisted with `MEMORY_AND_DISK`,
663
+ counted, written and unpersisted. That is weaker: Spark recomputes a cached
664
+ block it loses, so the write may read rows other than the ones counted.
665
+ Persisting and unpersisting go through Spark's shared cache manager, which
666
+ matches cached data by plan, so a frame with a plan equivalent to the
667
+ written frame's, cached before the write, is unpersisted too. Freeing the
668
+ rows is best effort: a failure is logged as a warning and never replaces
669
+ the outcome of the write, its error or `EmptyReplaceError`. The write
670
+ policy's `_is_empty` hook becomes `_pin_rows`, which returns the frame to
671
+ write along with whether it is empty, and gains `_release_pinned`, which
672
+ frees what `_pin_rows` kept and must not raise.
673
+ - **etl:** the Polars checkpoint store memory-maps only a local checkpoint.
674
+ It recognised cloud URIs by a lower-case prefix list without `r2://`, so a
675
+ checkpoint under `r2://` or an upper-case scheme such as `S3://` was read
676
+ with `memory_map=True`; it now uses the scheme set of
677
+ `loom.etl._uri`, compared case-insensitively.
678
+ - **etl:** documentation states what the writers do. `replace(streaming=...)`
679
+ and `ReplaceSpec.streaming` claimed a streaming Arrow write on Polars; no
680
+ backend reads the flag for a full replace, and the collect engine follows
681
+ the step's `streaming` attribute. `vacuum(full=True)` warns, in the guide
682
+ and in `VacuumSpec`, `MaintainTable.vacuum` and `MaintenanceVacuumConfig`,
683
+ that it deletes every unreferenced file under the table directory older
684
+ than the retention, whoever wrote it. The pipelines page states that
685
+ `replace_where` with an empty frame deletes the rows matching its
686
+ predicate.
494
687
  - **etl:** `upsert` and `update` on the Polars backend write with the route's
495
688
  `writer` and `commit` settings. The delta-rs MERGE received neither, so the
496
689
  Parquet files it rewrote came out with delta-rs defaults (SNAPPY, row groups
@@ -534,6 +727,20 @@
534
727
 
535
728
  ### ai
536
729
 
730
+ - **ai:** `PolarsAgentRunner.map` runs at most `ai.max_concurrent_runs`
731
+ worker tasks, which take the rows in order, instead of creating one task
732
+ per row up front; the order of the output rows is unchanged. A run
733
+ cancelled while the batch was not raises a `RuntimeError` naming how many
734
+ rows were left without an outcome and the first of them, where the run's
735
+ `asyncio.CancelledError` reached the caller.
736
+ - **ai:** `PolarsAgentRunner.validate` reports an output with a field no
737
+ column can hold (a union of two models, for instance) as
738
+ `OUTPUT_MISMATCH` instead of raising its `TypeError`, and checks the output
739
+ columns before asking whether the model is priced.
740
+ - **ai:** an agent output type that contains itself, directly
741
+ (`children: list[Node]`) or through another type, no longer makes
742
+ `PolarsAgentRunner.validate` and `map` fail with `RecursionError`: the
743
+ repeated struct or pydantic model is a `String` column holding its JSON.
537
744
  - **ai:** a configured `ai.prices` rate prices runs again with pydantic-ai
538
745
  2.54. That release records a response's usage before the
539
746
  `after_model_request` hook loom priced it in, so every run reported
@@ -573,6 +780,22 @@
573
780
  `SERVICE_UNAVAILABLE`, which `HttpErrorMapper` maps to `503`. Any other
574
781
  exception from the authenticator, and the `401` refusal, are unchanged.
575
782
 
783
+ ### prefect
784
+
785
+ - **prefect:** every log line the bridge sends carries the run's
786
+ `flow_run_id`, and a step's line its `task_run_id` as well. A step's lines
787
+ went out with `task_run_id` only, so a reader scoping a run's logs by flow
788
+ run, such as Prefect's flow run view, missed every step line; a step of a
789
+ parallel group now keeps the flow run too, through `ThreadDispatcher`'s
790
+ context copy. A line emitted inside a step with no flow run bound omits
791
+ `flow_run_id` instead of sending `null`.
792
+ - **prefect:** `deploy_flow` refuses a flow built from a YAML declaration
793
+ with a `TypeError` naming `discover_and_deploy_etls(config=...)`, which
794
+ deploys it, instead of the entrypoint module's `ConfigError`. When the flow
795
+ module's `__getattr__` raises anything but `AttributeError` while the flow
796
+ is looked up, `deploy_flow` raises its documented `ValueError`, chained to
797
+ that exception.
798
+
576
799
  ## ♻️ Refactor
577
800
 
578
801
  ### etl
@@ -591,6 +814,12 @@
591
814
  spec type than the protocol it is dispatched through; it now accepts the
592
815
  protocol's type and refuses a spec of another kind with a `TypeError`,
593
816
  which the registry's dispatch by kind already made unreachable.
817
+ - **etl:** `PolarsSourceReader` decodes JSON columns through
818
+ `decode_json_columns`; the private `_apply_json_decode` staticmethod and
819
+ module function of `loom.etl.backends.polars._reader` are removed.
820
+ - **etl:** the private `_is_cloud_path` of `loom.etl.checkpoint._cleaners`
821
+ moves, with the same scheme set, to `loom.etl._uri.is_cloud_path`,
822
+ and the Polars backend defines its frame type variable once.
594
823
 
595
824
  # 🚀 Release 2.1.2 ([#238](https://github.com/the-reacher-data/loom-py/pull/238))
596
825
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: loom-kernel
3
- Version: 2.18.0
3
+ Version: 2.20.0
4
4
  Summary: Loom Python project
5
5
  License-File: LICENSE
6
6
  Classifier: Programming Language :: Python :: 3
@@ -18,32 +18,22 @@ _CAPABILITY_NAMES: Final[Mapping[str, tuple[str, ...]]] = MappingProxyType(
18
18
  {
19
19
  "usecase": ("keys",),
20
20
  "sql": ("connection",),
21
- "mcp": ("server",),
21
+ "mcp": ("server", "include", "exclude"),
22
22
  "skills": ("library", "names"),
23
23
  "python": ("factory_ref",),
24
- "a2a": ("agent",),
24
+ "a2a": ("agent", "include", "exclude"),
25
25
  "native": ("tool",),
26
26
  }
27
27
  )
28
28
 
29
29
 
30
30
  def plan_fingerprint(plan: AgentPlan) -> str:
31
- """Return the sha256 of what decides *plan*'s answers.
32
-
33
- Args:
34
- plan: Compiled plan.
35
-
36
- Returns:
37
- Hex digest over the instructions, output schema and check, policies,
38
- format version, the kind and name of every capability and the model
39
- binding, without the deployment details.
40
- """
31
+ """Return the sha256 behind :attr:`AgentPlan.fingerprint`, which states what it covers."""
41
32
  facts = {
42
33
  "spec_version": plan.spec_version,
43
34
  "instructions": [[block.text, block.template] for block in plan.instructions],
44
35
  "output_schema": plan.output.schema,
45
36
  "output_check": _reference(plan.output_check),
46
- "policies": plan.policies,
47
37
  "capabilities": [_capability(capability) for capability in plan.capabilities],
48
38
  "provider": plan.inference.provider,
49
39
  "model": plan.inference.model,
@@ -408,16 +408,24 @@ class AgentPlan(LoomFrozenStruct, frozen=True, kw_only=True):
408
408
 
409
409
  @property
410
410
  def fingerprint(self) -> str:
411
- """Stable sha256 of everything that decides this agent's answers.
412
-
413
- Covers the instructions as compiled, the output schema, the output
414
- check, the policies, the format version, the kind and name of every
415
- capability and the bound provider, model, output mode and options.
416
- Leaves out the name, description, metadata, provenance, configured
417
- price, where a capability is served from (URL, directory,
418
- credentials, timeouts) and the binding's region, endpoint,
419
- credentials and streaming flag. The output check enters by its import
420
- path, so editing the check's body keeps the fingerprint.
411
+ """Stable sha256 of the declared facts that decide this agent's answers.
412
+
413
+ Covers the format version, the instructions as compiled, the output
414
+ schema, the output check, the kind and declared facts of every
415
+ capability (use case keys, SQL connection, MCP server, skill library
416
+ and names, Python factory reference, A2A agent, native tool, and the
417
+ ``include``/``exclude`` filters of MCP and A2A) and the bound
418
+ provider, model, output mode and options. It covers what the plan
419
+ declares, not the content of the skills, tools or use cases it names:
420
+ editing a skill's text or a tool's code keeps the fingerprint. Leaves
421
+ out the name, description, metadata, provenance, configured price,
422
+ every policy (each bounds a run and fails it past that bound;
423
+ ``max_history_bytes`` also withholds from the hook a history above
424
+ it; none decides the content of an accepted answer), where a
425
+ capability is served from (URL, directory, credentials, timeouts) and
426
+ the binding's region, endpoint, credentials and streaming flag. The
427
+ output check enters by its import path, so editing the check's body
428
+ keeps the fingerprint.
421
429
  """
422
430
  return plan_fingerprint(self)
423
431
 
@@ -28,6 +28,7 @@ from loom.ai.errors import (
28
28
  endpoint_auth_missing,
29
29
  inference_target_incomplete,
30
30
  max_agent_depth_invalid,
31
+ max_concurrent_runs_invalid,
31
32
  mcp_auth_conflict,
32
33
  mcp_auth_strategy_unknown,
33
34
  mcp_credentials_inline,
@@ -343,7 +344,8 @@ class AiConfig(LoomFrozenStruct, frozen=True, kw_only=True):
343
344
  prices: Prices keyed by vendor model id (``InferenceTarget.model``).
344
345
  A plan bound to a listed model is priced with these rates rather
345
346
  than the engine's own, which is what keeps ``policies.max_usd``
346
- enforceable for a model the engine cannot price.
347
+ enforceable for a model the engine cannot price. A key no
348
+ binding of ``models`` names is logged as a warning.
347
349
  skills_root: Filesystem root bare skill library names resolve against.
348
350
  mcp_servers: Named remote MCP servers artifacts refer to by name.
349
351
  a2a_agents: Named remote A2A agents artifacts refer to by name.
@@ -361,7 +363,8 @@ class AiConfig(LoomFrozenStruct, frozen=True, kw_only=True):
361
363
  that did open and whose tool listing times out still fails
362
364
  start-up, and no client becomes lazy — one that never opened is
363
365
  not reconnected later.
364
- max_concurrent_runs: Per-worker run limit (FR-033a).
366
+ max_concurrent_runs: Per-worker run limit (FR-033a); below 1 the
367
+ config fails with ``MAX_CONCURRENT_RUNS_INVALID``.
365
368
  max_prompt_bytes: Enforced while reading the request body, against
366
369
  the ``prompt`` field alone (FR-015).
367
370
  max_state_bytes: Enforced while reading the request body, against the
@@ -422,8 +425,21 @@ class AiConfig(LoomFrozenStruct, frozen=True, kw_only=True):
422
425
  issues.append(remote_clients_unknown(self.remote_clients, _REMOTE_CLIENTS_MODES))
423
426
  if self.max_agent_depth < 1:
424
427
  issues.append(max_agent_depth_invalid(self.max_agent_depth))
428
+ if self.max_concurrent_runs < 1:
429
+ issues.append(max_concurrent_runs_invalid(self.max_concurrent_runs))
425
430
  if issues:
426
431
  raise AgentCompilationError(issues)
432
+ _warn_unused_prices(self.prices, self.models)
433
+
434
+
435
+ def _warn_unused_prices(
436
+ prices: Mapping[str, ModelPrice], models: Mapping[str, InferenceTarget]
437
+ ) -> None:
438
+ bound = {target.model for target in models.values()}
439
+ for model in sorted(prices.keys() - bound):
440
+ _logger.warning(
441
+ "ai.prices[%r] names no model of ai.models; no run is priced with it", model
442
+ )
427
443
 
428
444
 
429
445
  _UrlIssue = Callable[[str, str, str], AgentCompilationIssue]
@@ -1,4 +1,4 @@
1
- """Spend caps projected onto the engine's own ``UsageLimits``.
1
+ """Spend caps projected onto the engine's own ``UsageLimits``, and the pricing of its responses.
2
2
 
3
3
  ``PolicySpec`` carries five caps (FR-040), four of them optional and one,
4
4
  ``max_requests``, always set to a default; :func:`usage_limits` projects all
@@ -155,6 +155,7 @@ class AgentErrorCode(StrEnum):
155
155
  AGENT_SPECS_ESCAPE_ROOT = "AGENT_SPECS_ESCAPE_ROOT"
156
156
  REMOTE_CLIENTS_UNKNOWN = "REMOTE_CLIENTS_UNKNOWN"
157
157
  MAX_AGENT_DEPTH_INVALID = "MAX_AGENT_DEPTH_INVALID"
158
+ MAX_CONCURRENT_RUNS_INVALID = "MAX_CONCURRENT_RUNS_INVALID"
158
159
 
159
160
  # Use-case agent markers (model-as-actor)
160
161
  AGENT_MARKER_UNKNOWN = "AGENT_MARKER_UNKNOWN"
@@ -1317,6 +1318,23 @@ def max_agent_depth_invalid(value: int) -> AgentCompilationIssue:
1317
1318
  )
1318
1319
 
1319
1320
 
1321
+ def max_concurrent_runs_invalid(value: int) -> AgentCompilationIssue:
1322
+ """The run limit admits no run.
1323
+
1324
+ Args:
1325
+ value: The rejected value of ``ai.max_concurrent_runs``.
1326
+ """
1327
+ return AgentCompilationIssue(
1328
+ code=AgentErrorCode.MAX_CONCURRENT_RUNS_INVALID,
1329
+ message=(
1330
+ f"ai.max_concurrent_runs: {value} is below the minimum of 1; a worker "
1331
+ "with no run slot refuses every run and an ETL batch answers no row"
1332
+ ),
1333
+ component="ai",
1334
+ field="ai.max_concurrent_runs",
1335
+ )
1336
+
1337
+
1320
1338
  # ---------------------------------------------------------------------------
1321
1339
  # Compatibility factories
1322
1340
  # ---------------------------------------------------------------------------
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import asyncio
6
6
  import logging
7
- from collections.abc import Callable, Mapping, Sequence
7
+ from collections.abc import Callable, Iterator, Mapping, Sequence
8
8
  from dataclasses import dataclass
9
9
  from decimal import Decimal
10
10
  from typing import Any, Final
@@ -58,21 +58,43 @@ class Batch:
58
58
  to_builtins: Callable[[Any], Mapping[str, Any]]
59
59
 
60
60
  async def answer_all(self, prompts: Sequence[str | None]) -> list[RowOutcome]:
61
- """Enter the runtime, answer every prompt in order, and close it in the same task."""
62
- slots = asyncio.Semaphore(self.limit)
63
- identity = Identity(subject=f"etl:{self.name}")
64
- async with self.runtime:
65
- return list(await asyncio.gather(*(self._answer(p, slots, identity) for p in prompts)))
61
+ """Enter the runtime, answer every prompt in order, and close it in the same task.
62
+
63
+ *limit* workers take the prompts in order from one shared iterator, so
64
+ the batch creates at most *limit* tasks whatever the number of rows.
66
65
 
67
- async def _answer(
68
- self, prompt: str | None, slots: asyncio.Semaphore, identity: Identity
69
- ) -> RowOutcome:
66
+ Raises:
67
+ RuntimeError: A run was cancelled while the batch was not, so its
68
+ worker stopped and left rows without an outcome.
69
+ """
70
+ identity = Identity(subject=f"etl:{self.name}")
71
+ outcomes: list[RowOutcome | None] = [None] * len(prompts)
72
+ pending = iter(enumerate(prompts))
73
+ async with self.runtime, asyncio.TaskGroup() as workers:
74
+ for _ in range(min(self.limit, len(prompts))):
75
+ workers.create_task(self._work(pending, outcomes, identity))
76
+ if None in outcomes:
77
+ raise RuntimeError(
78
+ f"agent {self.name!r} left {outcomes.count(None)} row(s) without an outcome, the "
79
+ f"first row {outcomes.index(None)}: a run was cancelled while the batch was not"
80
+ )
81
+ return [outcome for outcome in outcomes if outcome is not None]
82
+
83
+ async def _work(
84
+ self,
85
+ pending: Iterator[tuple[int, str | None]],
86
+ outcomes: list[RowOutcome | None],
87
+ identity: Identity,
88
+ ) -> None:
89
+ for row, prompt in pending:
90
+ outcomes[row] = await self._answer(prompt, identity)
91
+
92
+ async def _answer(self, prompt: str | None, identity: Identity) -> RowOutcome:
70
93
  if prompt is None:
71
94
  return RowOutcome(output=None, error=PROMPT_MISSING, usage=None)
72
- async with slots:
73
- if not self.ledger.reserve(self.reservation):
74
- return RowOutcome(output=None, error=BUDGET_EXHAUSTED, usage=None)
75
- return await self._run(prompt, identity)
95
+ if not self.ledger.reserve(self.reservation):
96
+ return RowOutcome(output=None, error=BUDGET_EXHAUSTED, usage=None)
97
+ return await self._run(prompt, identity)
76
98
 
77
99
  async def _run(self, prompt: str, identity: Identity) -> RowOutcome:
78
100
  usage: AgentUsage | None = None