loom-kernel 2.18.0__tar.gz → 2.19.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.19.0}/CHANGELOG.md +187 -11
  2. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/PKG-INFO +1 -1
  3. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/_fingerprint.py +3 -13
  4. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/_plan.py +18 -10
  5. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/config.py +18 -2
  6. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_limits.py +1 -1
  7. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/errors.py +18 -0
  8. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/_batch.py +35 -13
  9. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/_columns.py +44 -15
  10. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/_frames.py +9 -9
  11. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/_ledger.py +0 -12
  12. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/_runner.py +8 -4
  13. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/_validation.py +27 -10
  14. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/pricing.py +3 -2
  15. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/errors/errors.py +9 -7
  16. loom_kernel-2.19.0/src/loom/etl/_uri.py +20 -0
  17. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_write_policy.py +44 -16
  18. loom_kernel-2.19.0/src/loom/etl/backends/polars/_frame.py +15 -0
  19. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_historify.py +4 -5
  20. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_reader.py +4 -23
  21. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_schema.py +43 -1
  22. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_writer.py +3 -3
  23. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/_writer.py +44 -3
  24. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_backends/_polars.py +2 -2
  25. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_cleaners.py +0 -11
  26. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_errors.py +11 -0
  27. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_filter.py +4 -4
  28. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_validators_agents.py +4 -14
  29. loom_kernel-2.19.0/src/loom/etl/declarative/_with_agent.py +109 -0
  30. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_errors.py +2 -2
  31. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_into.py +4 -2
  32. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_table.py +4 -5
  33. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/executor/_dispatcher.py +15 -20
  34. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/_builder.py +4 -2
  35. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/_ops.py +5 -3
  36. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/_wiring.py +2 -2
  37. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/config_loader.py +2 -2
  38. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/storage/_config.py +7 -5
  39. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/deploy/_discovery.py +51 -15
  40. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/notify/__init__.py +4 -2
  41. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/notify/_factory.py +13 -0
  42. loom_kernel-2.19.0/src/loom/prefect/notify/_format.py +40 -0
  43. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/notify/_slack.py +8 -32
  44. loom_kernel-2.19.0/src/loom/prefect/notify/_sns.py +78 -0
  45. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/observer/_logging_bridge.py +9 -6
  46. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/auto.py +8 -9
  47. loom_kernel-2.18.0/src/loom/etl/declarative/_with_agent.py +0 -70
  48. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/.gitignore +0 -0
  49. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/LICENSE +0 -0
  50. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/README.md +0 -0
  51. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/pyproject.toml +0 -0
  52. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/__init__.py +0 -0
  53. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/__init__.py +0 -0
  54. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_concurrency.py +0 -0
  55. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_filters.py +0 -0
  56. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_paths.py +0 -0
  57. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_roles.py +0 -0
  58. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_startup.py +0 -0
  59. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_transport.py +0 -0
  60. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/_usecase.py +0 -0
  61. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/__init__.py +0 -0
  62. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/_binding.py +0 -0
  63. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/_handlers.py +0 -0
  64. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/_rpc.py +0 -0
  65. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/card.py +0 -0
  66. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/events.py +0 -0
  67. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/a2a/server.py +0 -0
  68. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/abc.py +0 -0
  69. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/bootstrap.py +0 -0
  70. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/__init__.py +0 -0
  71. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/_compiler.py +0 -0
  72. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
  73. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
  74. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
  75. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
  76. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
  77. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
  78. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
  79. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
  80. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_output.py +0 -0
  81. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/compiler/phases/_state.py +0 -0
  82. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/declarative/__init__.py +0 -0
  83. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/declarative/_envelope.py +0 -0
  84. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/declarative/_schema.py +0 -0
  85. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/declarative/_v1.py +0 -0
  86. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
  87. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/describe.py +0 -0
  88. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/__init__.py +0 -0
  89. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
  90. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
  91. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +0 -0
  92. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
  93. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
  94. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
  95. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
  96. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
  97. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
  98. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
  99. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +0 -0
  100. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
  101. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
  102. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
  103. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
  104. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +0 -0
  105. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
  106. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
  107. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
  108. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
  109. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
  110. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
  111. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
  112. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
  113. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +0 -0
  114. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
  115. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
  116. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
  117. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
  118. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
  119. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/etl/__init__.py +0 -0
  120. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/fastapi/__init__.py +0 -0
  121. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/fastapi/endpoints.py +0 -0
  122. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/fastapi/response.py +0 -0
  123. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/fastapi/streaming.py +0 -0
  124. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/inference.py +0 -0
  125. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/registry.py +0 -0
  126. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/remote_auth.py +0 -0
  127. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/__init__.py +0 -0
  128. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_bounded.py +0 -0
  129. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_chain.py +0 -0
  130. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_conversation.py +0 -0
  131. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_grants.py +0 -0
  132. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_handle.py +0 -0
  133. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_health.py +0 -0
  134. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_hooks.py +0 -0
  135. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_lifecycle.py +0 -0
  136. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_limits.py +0 -0
  137. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/runtime/_mcp.py +0 -0
  138. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/validate/__init__.py +0 -0
  139. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/ai/validate/__main__.py +0 -0
  140. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/__init__.py +0 -0
  141. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/auto.py +0 -0
  142. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/bootstrap.py +0 -0
  143. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/config.py +0 -0
  144. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/constants.py +0 -0
  145. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/runner.py +0 -0
  146. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/celery/service.py +0 -0
  147. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/cli/__init__.py +0 -0
  148. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/cli/app.py +0 -0
  149. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/cli/schema.py +0 -0
  150. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/async_bridge.py +0 -0
  151. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/__init__.py +0 -0
  152. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/_decide.py +0 -0
  153. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/_grants.py +0 -0
  154. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/_roles.py +0 -0
  155. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/_scope.py +0 -0
  156. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/elevation.py +0 -0
  157. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/authz/product.py +0 -0
  158. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/backend/__init__.py +0 -0
  159. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/backend/core_model.py +0 -0
  160. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/backend/protocol.py +0 -0
  161. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/backend/scoped_ddl.py +0 -0
  162. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/backend/sqlalchemy.py +0 -0
  163. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/bootstrap/__init__.py +0 -0
  164. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
  165. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/bootstrap/kernel.py +0 -0
  166. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/__init__.py +0 -0
  167. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/_batching.py +0 -0
  168. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/_single_flight.py +0 -0
  169. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/abc/__init__.py +0 -0
  170. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/abc/backend.py +0 -0
  171. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/abc/config.py +0 -0
  172. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/abc/dependency.py +0 -0
  173. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/calls.py +0 -0
  174. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/codec.py +0 -0
  175. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/decorators.py +0 -0
  176. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/dependency.py +0 -0
  177. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/errors.py +0 -0
  178. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/gateway.py +0 -0
  179. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/keys.py +0 -0
  180. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/memory.py +0 -0
  181. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/repository.py +0 -0
  182. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/result_codec.py +0 -0
  183. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/serializer.py +0 -0
  184. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/cache/wiring.py +0 -0
  185. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/command/__init__.py +0 -0
  186. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/command/adapter.py +0 -0
  187. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/command/base.py +0 -0
  188. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/command/field.py +0 -0
  189. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/command/introspection.py +0 -0
  190. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/compiler.py +0 -0
  191. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/__init__.py +0 -0
  192. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/_boto3.py +0 -0
  193. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/_includes.py +0 -0
  194. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/_resolver_utils.py +0 -0
  195. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/binder.py +0 -0
  196. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/configurable.py +0 -0
  197. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/context.py +0 -0
  198. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/errors.py +0 -0
  199. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/keys.py +0 -0
  200. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/loader.py +0 -0
  201. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/model.py +0 -0
  202. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/observability.py +0 -0
  203. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/resolver.py +0 -0
  204. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/secrets.py +0 -0
  205. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/config/ssm.py +0 -0
  206. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/contracts/__init__.py +0 -0
  207. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/contracts/manifest.py +0 -0
  208. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/di/__init__.py +0 -0
  209. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/di/container.py +0 -0
  210. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/di/scope.py +0 -0
  211. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/discovery/__init__.py +0 -0
  212. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/discovery/_utils.py +0 -0
  213. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/discovery/base.py +0 -0
  214. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/discovery/interfaces.py +0 -0
  215. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/discovery/manifest.py +0 -0
  216. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/discovery/modules.py +0 -0
  217. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/__init__.py +0 -0
  218. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/compilable.py +0 -0
  219. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/compiler.py +0 -0
  220. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/events.py +0 -0
  221. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/executor.py +0 -0
  222. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/metrics.py +0 -0
  223. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/plan.py +0 -0
  224. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/engine/post_commit.py +0 -0
  225. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/errors/__init__.py +0 -0
  226. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/errors/codes.py +0 -0
  227. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/expr/__init__.py +0 -0
  228. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/expr/eval.py +0 -0
  229. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/expr/nodes.py +0 -0
  230. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/expr/refs.py +0 -0
  231. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/identity/__init__.py +0 -0
  232. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/identity/context.py +0 -0
  233. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/identity/identity.py +0 -0
  234. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/identity/issuer.py +0 -0
  235. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/identity/wire.py +0 -0
  236. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/introspection/__init__.py +0 -0
  237. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/introspection/base.py +0 -0
  238. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/introspection/describe.py +0 -0
  239. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/job/__init__.py +0 -0
  240. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/job/callback.py +0 -0
  241. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/job/context.py +0 -0
  242. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/job/handle.py +0 -0
  243. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/job/job.py +0 -0
  244. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/job/service.py +0 -0
  245. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/locator.py +0 -0
  246. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/logger/__init__.py +0 -0
  247. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/logger/abc.py +0 -0
  248. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/logger/config.py +0 -0
  249. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/logger/registry.py +0 -0
  250. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/logger/structlogger.py +0 -0
  251. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/__init__.py +0 -0
  252. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/_loom_type.py +0 -0
  253. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/base.py +0 -0
  254. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/convert.py +0 -0
  255. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/enums.py +0 -0
  256. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/field.py +0 -0
  257. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/introspection.py +0 -0
  258. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/partition.py +0 -0
  259. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/privilege.py +0 -0
  260. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/projection.py +0 -0
  261. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/relation.py +0 -0
  262. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/scoped.py +0 -0
  263. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/struct.py +0 -0
  264. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/timestamped.py +0 -0
  265. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/types.py +0 -0
  266. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/model/types_postgres.py +0 -0
  267. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/__init__.py +0 -0
  268. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/config.py +0 -0
  269. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/event.py +0 -0
  270. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/observer/__init__.py +0 -0
  271. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/observer/noop.py +0 -0
  272. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/observer/otel.py +0 -0
  273. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/observer/structlog.py +0 -0
  274. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/otel_ids.py +0 -0
  275. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/protocol.py +0 -0
  276. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/runtime.py +0 -0
  277. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/span.py +0 -0
  278. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/observability/topology.py +0 -0
  279. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/persistence/__init__.py +0 -0
  280. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/persistence/abc.py +0 -0
  281. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/persistence/none.py +0 -0
  282. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/persistence/registry.py +0 -0
  283. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/plugins/__init__.py +0 -0
  284. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/plugins/entrypoints.py +0 -0
  285. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/plugins/optional.py +0 -0
  286. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/projection/__init__.py +0 -0
  287. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/projection/loaders.py +0 -0
  288. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/projection/runtime.py +0 -0
  289. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/__init__.py +0 -0
  290. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/__init__.py +0 -0
  291. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/cursor.py +0 -0
  292. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/errors.py +0 -0
  293. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/query.py +0 -0
  294. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
  295. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/repo_for.py +0 -0
  296. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/repository.py +0 -0
  297. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/abc/session_scope.py +0 -0
  298. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
  299. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
  300. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
  301. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/dynamodb/repository.py +0 -0
  302. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
  303. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/__init__.py +0 -0
  304. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/backend.py +0 -0
  305. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/ids.py +0 -0
  306. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
  307. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/registry.py +0 -0
  308. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/repository.py +0 -0
  309. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/uow.py +0 -0
  310. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mongo/values.py +0 -0
  311. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/mutation.py +0 -0
  312. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/registration.py +0 -0
  313. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/registry.py +0 -0
  314. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
  315. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/backend.py +0 -0
  316. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
  317. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
  318. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/migrations/__init__.py +0 -0
  319. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/migrations/env_template.py +0 -0
  320. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/migrations/hook.py +0 -0
  321. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/migrations/operations.py +0 -0
  322. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/migrations/runners.py +0 -0
  323. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
  324. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
  325. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
  326. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
  327. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
  328. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
  329. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
  330. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
  331. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
  332. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
  333. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
  334. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
  335. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
  336. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
  337. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/__init__.py +0 -0
  338. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/bootstrap.py +0 -0
  339. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/config.py +0 -0
  340. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/elevate.py +0 -0
  341. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/guard/0001.sql +0 -0
  342. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/guard/0002.sql +0 -0
  343. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/guard/preflight.sql +0 -0
  344. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/guard_manifest.py +0 -0
  345. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/integrity.py +0 -0
  346. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/partitions.py +0 -0
  347. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/provider.py +0 -0
  348. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/schema.py +0 -0
  349. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/sources.py +0 -0
  350. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/rls/verify.py +0 -0
  351. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
  352. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/session_settings.py +0 -0
  353. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
  354. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
  355. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/response/__init__.py +0 -0
  356. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/response/base.py +0 -0
  357. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/routing/__init__.py +0 -0
  358. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/routing/ref.py +0 -0
  359. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/routing/resolver.py +0 -0
  360. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/runner.py +0 -0
  361. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/schema/__init__.py +0 -0
  362. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/schema/schema_mode.py +0 -0
  363. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/schema_names.py +0 -0
  364. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/__init__.py +0 -0
  365. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/abc/__init__.py +0 -0
  366. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/abc/contracts.py +0 -0
  367. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/abc/errors.py +0 -0
  368. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/caller_bound.py +0 -0
  369. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
  370. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
  371. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
  372. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
  373. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/config.py +0 -0
  374. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/roles.py +0 -0
  375. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/sql/service.py +0 -0
  376. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/symbols.py +0 -0
  377. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/tracing/__init__.py +0 -0
  378. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/tracing/context.py +0 -0
  379. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/transaction.py +0 -0
  380. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/transport/__init__.py +0 -0
  381. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/transport/adapter.py +0 -0
  382. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/uow/__init__.py +0 -0
  383. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/uow/abc.py +0 -0
  384. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/uow/context.py +0 -0
  385. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/__init__.py +0 -0
  386. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/_predicates.py +0 -0
  387. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/agent_markers.py +0 -0
  388. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/compute.py +0 -0
  389. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/constants.py +0 -0
  390. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/factory.py +0 -0
  391. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/field_ref.py +0 -0
  392. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/invoker.py +0 -0
  393. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/keys.py +0 -0
  394. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/markers.py +0 -0
  395. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/mcp_markers.py +0 -0
  396. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/registry.py +0 -0
  397. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/rule.py +0 -0
  398. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/core/use_case/use_case.py +0 -0
  399. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/__init__.py +0 -0
  400. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/__init__.py +0 -0
  401. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_format_registry.py +0 -0
  402. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
  403. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_historify/_common.py +0 -0
  404. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_historify/_log.py +0 -0
  405. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
  406. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
  407. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
  408. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_merge.py +0 -0
  409. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_path_template.py +0 -0
  410. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_predicate.py +0 -0
  411. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
  412. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
  413. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
  414. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/__init__.py +0 -0
  415. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
  416. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
  417. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
  418. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
  419. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
  420. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/polars/provider.py +0 -0
  421. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/__init__.py +0 -0
  422. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
  423. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/_historify.py +0 -0
  424. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/_reader.py +0 -0
  425. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/_schema.py +0 -0
  426. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
  427. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/backends/spark/provider.py +0 -0
  428. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/__init__.py +0 -0
  429. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
  430. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_options.py +0 -0
  431. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_paths.py +0 -0
  432. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_scope.py +0 -0
  433. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/checkpoint/_store.py +0 -0
  434. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/__init__.py +0 -0
  435. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_binding.py +0 -0
  436. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_compiler.py +0 -0
  437. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_plan.py +0 -0
  438. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_validators.py +0 -0
  439. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_validators_config.py +0 -0
  440. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
  441. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/compiler/_validators_step.py +0 -0
  442. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/__init__.py +0 -0
  443. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/_format.py +0 -0
  444. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/_read_options.py +0 -0
  445. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/_utils.py +0 -0
  446. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/_write_options.py +0 -0
  447. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
  448. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/expr/_params.py +0 -0
  449. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
  450. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
  451. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
  452. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/__init__.py +0 -0
  453. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/_from.py +0 -0
  454. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
  455. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
  456. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
  457. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
  458. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/source/_specs.py +0 -0
  459. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/__init__.py +0 -0
  460. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_client.py +0 -0
  461. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_file.py +0 -0
  462. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
  463. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_history/_builder.py +0 -0
  464. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
  465. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
  466. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
  467. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_history/_spec.py +0 -0
  468. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
  469. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/declarative/target/_temp.py +0 -0
  470. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/executor/__init__.py +0 -0
  471. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/executor/_agents.py +0 -0
  472. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/executor/_executor.py +0 -0
  473. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/__init__.py +0 -0
  474. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/_registry.py +0 -0
  475. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/__init__.py +0 -0
  476. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
  477. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
  478. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
  479. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
  480. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_mongo.py +0 -0
  481. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
  482. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
  483. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
  484. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/sources/_serialization.py +0 -0
  485. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/targets/__init__.py +0 -0
  486. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
  487. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/__init__.py +0 -0
  488. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/_config.py +0 -0
  489. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/_observer.py +0 -0
  490. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/_records.py +0 -0
  491. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
  492. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
  493. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
  494. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
  495. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/__init__.py +0 -0
  496. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/_protocol.py +0 -0
  497. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/_runner.py +0 -0
  498. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/_step.py +0 -0
  499. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
  500. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
  501. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/__init__.py +0 -0
  502. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_generics.py +0 -0
  503. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_params.py +0 -0
  504. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
  505. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_process.py +0 -0
  506. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_sql.py +0 -0
  507. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_step.py +0 -0
  508. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_step_client.py +0 -0
  509. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
  510. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/__init__.py +0 -0
  511. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/_agents.py +0 -0
  512. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/_providers.py +0 -0
  513. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/core.py +0 -0
  514. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/errors.py +0 -0
  515. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runner/filtering.py +0 -0
  516. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runtime/__init__.py +0 -0
  517. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runtime/_config_values.py +0 -0
  518. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/runtime/contracts.py +0 -0
  519. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/schema/__init__.py +0 -0
  520. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/schema/_contract.py +0 -0
  521. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/schema/_schema.py +0 -0
  522. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/storage/__init__.py +0 -0
  523. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/storage/_file_locator.py +0 -0
  524. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/storage/_locator.py +0 -0
  525. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/storage/routing.py +0 -0
  526. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/testing/__init__.py +0 -0
  527. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/testing/_result.py +0 -0
  528. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/testing/_runners.py +0 -0
  529. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/testing/_scenario.py +0 -0
  530. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/testing/_stubs.py +0 -0
  531. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/etl/testing/spark.py +0 -0
  532. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/__init__.py +0 -0
  533. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_async.py +0 -0
  534. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_config.py +0 -0
  535. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_ctx.py +0 -0
  536. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_flow_yaml.py +0 -0
  537. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_meta.py +0 -0
  538. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_placeholders.py +0 -0
  539. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/_summary.py +0 -0
  540. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/deploy/__init__.py +0 -0
  541. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/deploy/_schedule.py +0 -0
  542. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
  543. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
  544. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/__init__.py +0 -0
  545. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_assemble.py +0 -0
  546. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_backfill.py +0 -0
  547. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
  548. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_body.py +0 -0
  549. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_common.py +0 -0
  550. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_factory.py +0 -0
  551. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_hooks.py +0 -0
  552. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_maintenance.py +0 -0
  553. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_params.py +0 -0
  554. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_run_name.py +0 -0
  555. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_runtime.py +0 -0
  556. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_signature.py +0 -0
  557. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/flow/_stages.py +0 -0
  558. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/manifest/__init__.py +0 -0
  559. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/manifest/_model.py +0 -0
  560. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/manifest/_s3.py +0 -0
  561. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/manifest/_store.py +0 -0
  562. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/notify/_event.py +0 -0
  563. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/notify/_port.py +0 -0
  564. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/observer/__init__.py +0 -0
  565. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/observer/_flow.py +0 -0
  566. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/observer/_manifest.py +0 -0
  567. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prefect/observer/_task_run.py +0 -0
  568. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prometheus/__init__.py +0 -0
  569. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prometheus/_instruments.py +0 -0
  570. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prometheus/adapter.py +0 -0
  571. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prometheus/kafka.py +0 -0
  572. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prometheus/lifecycle.py +0 -0
  573. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/prometheus/middleware.py +0 -0
  574. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/py.typed +0 -0
  575. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/__init__.py +0 -0
  576. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/_body.py +0 -0
  577. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/adapter.py +0 -0
  578. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/auth/__init__.py +0 -0
  579. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/auth/abc.py +0 -0
  580. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/auth/config.py +0 -0
  581. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/auth/jwt.py +0 -0
  582. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/auth/middleware.py +0 -0
  583. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/autocrud.py +0 -0
  584. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/compiler.py +0 -0
  585. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/config.py +0 -0
  586. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/constants.py +0 -0
  587. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/cors.py +0 -0
  588. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/errors.py +0 -0
  589. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/__init__.py +0 -0
  590. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/_errors.py +0 -0
  591. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
  592. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/app.py +0 -0
  593. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/health.py +0 -0
  594. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/openapi.py +0 -0
  595. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/response.py +0 -0
  596. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
  597. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/fastapi/sql.py +0 -0
  598. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/middleware.py +0 -0
  599. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/model.py +0 -0
  600. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/rest/rest_adapter.py +0 -0
  601. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/__init__.py +0 -0
  602. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/__init__.py +0 -0
  603. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
  604. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
  605. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
  606. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_dlq.py +0 -0
  607. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
  608. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_errors.py +0 -0
  609. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_operators.py +0 -0
  610. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
  611. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
  612. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
  613. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
  614. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
  615. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
  616. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
  617. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
  618. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
  619. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
  620. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
  621. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
  622. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/bytewax/runner.py +0 -0
  623. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/__init__.py +0 -0
  624. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/_bindings.py +0 -0
  625. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/_compiler.py +0 -0
  626. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/_errors.py +0 -0
  627. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/_plan.py +0 -0
  628. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
  629. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
  630. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/core/__init__.py +0 -0
  631. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/core/_errors.py +0 -0
  632. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/core/_exceptions.py +0 -0
  633. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/core/_message.py +0 -0
  634. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/core/_tracing.py +0 -0
  635. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/core/_typing.py +0 -0
  636. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/graph/__init__.py +0 -0
  637. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/graph/_flow.py +0 -0
  638. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/__init__.py +0 -0
  639. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_codec.py +0 -0
  640. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_config.py +0 -0
  641. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_errors.py +0 -0
  642. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
  643. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_message.py +0 -0
  644. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_record.py +0 -0
  645. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/_wire.py +0 -0
  646. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
  647. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
  648. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
  649. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
  650. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
  651. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
  652. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
  653. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
  654. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
  655. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/mongo/__init__.py +0 -0
  656. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
  657. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/mongo/_config.py +0 -0
  658. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/mongo/_event.py +0 -0
  659. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/mongo/_normalize.py +0 -0
  660. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/__init__.py +0 -0
  661. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_boundary.py +0 -0
  662. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_branches.py +0 -0
  663. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
  664. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
  665. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_decompose.py +0 -0
  666. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
  667. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
  668. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_fork.py +0 -0
  669. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_helpers.py +0 -0
  670. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_mongo.py +0 -0
  671. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_protocols.py +0 -0
  672. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_router.py +0 -0
  673. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_shape.py +0 -0
  674. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_sink.py +0 -0
  675. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_step.py +0 -0
  676. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
  677. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_table/common.py +0 -0
  678. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_table/config.py +0 -0
  679. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/_with.py +0 -0
  680. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/nodes/refs.py +0 -0
  681. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/streaming/testing.py +0 -0
  682. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/testing/__init__.py +0 -0
  683. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/testing/agents.py +0 -0
  684. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/testing/golden.py +0 -0
  685. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/testing/http_harness.py +0 -0
  686. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/testing/in_memory.py +0 -0
  687. {loom_kernel-2.18.0 → loom_kernel-2.19.0}/src/loom/testing/repository_harness.py +0 -0
  688. {loom_kernel-2.18.0 → loom_kernel-2.19.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
@@ -370,6 +386,51 @@
370
386
 
371
387
  ### ai
372
388
 
389
+ - **ai:** `AgentPlan.fingerprint`, and so the ETL `agent_version` column,
390
+ changes once for every existing agent. It no longer covers any policy, so
391
+ changing `retries`, a timeout, `max_iterations`, `max_tool_calls`,
392
+ `max_requests`, a token cap, `max_usd`, `on_unpriced_spend` or
393
+ `max_history_bytes` keeps it; and it now covers the `include`/`exclude`
394
+ filters of `mcp` and `a2a` capabilities, so changing a filter changes it.
395
+ A step that keeps `agent_version` in its upsert keys and its anti-join
396
+ re-runs, and pays for, every row of the anti-join window on its next
397
+ execution after the upgrade.
398
+ - **ai:** in `PolarsAgentRunner.map`, a field of a pydantic output whose type
399
+ is another pydantic model is now a `Struct` column of that model's fields,
400
+ named by alias, instead of a `String` holding its JSON. Writing it into a
401
+ Delta table created before fails with `SchemaError` naming the column (see
402
+ the `etl` entry on casts between text and nested types). To keep writing to
403
+ that table, rewrite it once with the column decoded through the model,
404
+ `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>)`,
405
+ and `schema=SchemaMode.OVERWRITE` (delta-rs `schema_mode="overwrite"`).
406
+ `pl.col(name).str.json_decode(<the Struct type>)` fails with
407
+ `ComputeError` when the model has a `date` field (Polars 1.39.3).
408
+ - **ai:** in `PolarsAgentRunner.map`, a `String` column holding a value's JSON
409
+ now holds the JSON of a string too: `"5"` is written `"\"5\""` and `5` is
410
+ written `5`, where both were `5`. This covers a field typed as a union of
411
+ several types, `Any` or a `Literal` mixing value types whose answer is a
412
+ string. A `UUID`, `time`, `timedelta` or `bytes` field keeps its plain text
413
+ (`P1D` is written `P1D`). Rows written before hold the raw string and rows
414
+ written after hold its JSON encoding. A cell alone does not always tell
415
+ them apart (an old `5` may have been the string `"5"`), but `agent_version`
416
+ does: every agent's fingerprint changes with this release, so the old rows
417
+ carry the old version. Re-run the old rows of such a field, or rewrite each
418
+ old cell whose answer was a string as the JSON encoding of its text.
419
+ - **ai:** the `agent_cost_usd` column `PolarsAgentRunner.map` writes is
420
+ `Decimal(38, 12)` instead of `Float64`, carrying `AgentUsage.cost` without a
421
+ float conversion, rounded half to even to 12 decimal places. Writing into a
422
+ Delta table created before does not fail: an append, upsert or replace with
423
+ `SchemaMode.STRICT` or `EVOLVE` casts the column back to the table's
424
+ `Float64`. To keep the decimal, rewrite the table once with the column cast
425
+ to `pl.Decimal(38, 12)` and `schema=SchemaMode.OVERWRITE` (delta-rs
426
+ `schema_mode="overwrite"`); the costs already stored keep the precision of
427
+ the float they were written as.
428
+ - **ai:** an `ai:` section with `max_concurrent_runs` below 1 fails to load
429
+ with `MAX_CONCURRENT_RUNS_INVALID`, naming the key and the minimum. Before,
430
+ it loaded; with `0` the runtime refused every run with `TOO_MANY_RUNS` and
431
+ `PolarsAgentRunner.map` on a frame with a prompt waited on a semaphore of
432
+ zero slots and did not return, and a negative value failed when the runtime
433
+ was built.
373
434
  - **ai:** `load_specs`, and so `ai.specs`, refuses a glob that leaves the
374
435
  root it resolves against — a `..` segment, an absolute pattern or a match
375
436
  that resolves outside the root through a symlink — with
@@ -446,14 +507,41 @@
446
507
  - **prefect:** the private `_deploy_single(flow, meta, work_pool, env)` of
447
508
  `loom.prefect.deploy._discovery` now takes `(flow, meta, plan)`; callers
448
509
  migrate to the public `deploy_flow(flow, env=..., work_pool=...)`.
510
+ - **prefect:** `discover_and_deploy_etls(flows_package=...)` checks every
511
+ flow of the package, its work pool and that its module exposes it under its
512
+ attribute name as `deploy_flow` does, before it registers the first
513
+ deployment. A flow without a work pool for the environment, one its module
514
+ exposes under another attribute name, or one whose source file cannot be
515
+ imported raises `ValueError` and no deployment of the package is
516
+ registered. Flows used to be registered one by one: a flow without a work
517
+ pool raised after the flows before it were registered, and a flow exposed
518
+ under another name or not importable from its source file was registered
519
+ with an entrypoint the worker cannot import.
449
520
 
450
521
  ### etl
451
522
 
523
+ - **etl:** a `WithAgent` compiled by a runner whose config has no `ai:`
524
+ section fails with the new code `AGENT_RUNNER_NOT_CONFIGURED` instead of
525
+ `AGENT_NOT_FOUND`, which now means only that no artifact declares the name.
452
526
  - **etl:** the names of `loom.etl.runner.filtering` (`_filter_plan`,
453
527
  `_filter_process`, `_collect_all_names`, `_map_pipeline_nodes`,
454
528
  `_map_process_nodes`) are deprecated and removed in loom 3.0; each emits a
455
529
  `DeprecationWarning` naming its replacement, `loom.etl.compiler.filter_plan`
456
530
  or, for `_collect_all_names`, `iter_processes` and `iter_all_steps`.
531
+ - **etl:** the Polars writer refuses, under `SchemaMode.STRICT` and
532
+ `EVOLVE`, a frame column that is a `Struct` or `List` where the Delta table
533
+ has `String`, or `String` where the table has a `Struct` or `List`, at any
534
+ depth of a `Struct` or `List`, with `SchemaError` naming the column and
535
+ both types; nothing is written. The check is by dtype, so an all-null
536
+ `String` column written into a `List` column is refused too. Before, a
537
+ `Struct` was cast to its Polars display text (`{1.0}` for a `Float64`
538
+ field) and a `String` to a `List` wrapped or nulled each value, both
539
+ written without an error; a `List` to `String` and a `String` to `Struct`
540
+ failed inside Polars. The Spark writer does not refuse these casts: it
541
+ writes a `Struct` or `List` into a `String` column as text (`{1.0}`,
542
+ `[1]`). To change the column's type,
543
+ rewrite the table once with the column converted and
544
+ `schema=SchemaMode.OVERWRITE` (delta-rs `schema_mode="overwrite"`).
457
545
  - **etl:** `InvalidStageError` names what it reports: its message reads
458
546
  `Unknown step or process names: [...]` instead of `No steps or processes
459
547
  match include=[...]`, the constructor's parameter is `unknown`, and the
@@ -461,6 +549,22 @@
461
549
  unchanged; `InvalidStageError(include=...)` still works, emits a
462
550
  `DeprecationWarning` and is removed in loom 3.0. The error survives pickle
463
551
  with its `unknown` names, so it crosses process boundaries intact.
552
+ - **etl:** `ThreadDispatcher` runs each task in a copy of the caller's
553
+ context, as `asyncio.to_thread` does, so a step of a parallel group sees
554
+ the `ContextVar` values of the run that dispatched it (the Prefect flow run
555
+ among them) and its OpenTelemetry context. A parallel group's step spans
556
+ therefore nest under their process span instead of starting a trace of
557
+ their own. `ParallelDispatcher` lists running each task in a copy of the
558
+ caller's context among the requirements on an implementation.
559
+ - **etl:** `WithAgent(max_usd=...)` keeps the budget as a `Decimal`. An
560
+ `int`, or another `numbers.Integral` such as `numpy.int64`, is converted
561
+ exactly. A `float` emits a `DeprecationWarning`, is converted through its
562
+ `str()` (`0.1` becomes `Decimal("0.1")`) and is removed in loom 3.0. A
563
+ `bool`, accepted before, and any other type, such as `str`, raise
564
+ `TypeError`. `NaN`, `sNaN` and `Infinity`, as a `Decimal` or a `float`,
565
+ raise `ValueError`, like zero and a negative amount; a `Decimal` `NaN` or
566
+ `sNaN` used to raise `decimal.InvalidOperation`, and a `Decimal`
567
+ `Infinity`, a `float` `inf` and a `float` `nan` were accepted.
464
568
 
465
569
  ## 🐛 Fixes
466
570
 
@@ -491,6 +595,42 @@
491
595
 
492
596
  ### etl
493
597
 
598
+ - **etl:** `replace(allow_empty=False)` on Spark writes the rows it checked.
599
+ The writer ran `DataFrame.isEmpty()` and then let the write compute the
600
+ frame again, so a source that changed in between, or a nondeterministic
601
+ plan, could still replace the table with no rows. The frame is now
602
+ computed once with `localCheckpoint(eager=True)`, and the check and the
603
+ write both read that result. Those rows are kept in executor storage, not
604
+ in reliable storage: losing an executor before the write ends fails the
605
+ write instead of recomputing the frame. Once the write ends, whether it
606
+ succeeded or failed, and when the check refuses the frame, the writer
607
+ unpersists the checkpointed RDD, so its blocks do not stay on the executors
608
+ for the rest of the session. A Spark Connect DataFrame has no
609
+ `localCheckpoint()` in pyspark 3.5: it is persisted with `MEMORY_AND_DISK`,
610
+ counted, written and unpersisted. That is weaker: Spark recomputes a cached
611
+ block it loses, so the write may read rows other than the ones counted.
612
+ Persisting and unpersisting go through Spark's shared cache manager, which
613
+ matches cached data by plan, so a frame with a plan equivalent to the
614
+ written frame's, cached before the write, is unpersisted too. Freeing the
615
+ rows is best effort: a failure is logged as a warning and never replaces
616
+ the outcome of the write, its error or `EmptyReplaceError`. The write
617
+ policy's `_is_empty` hook becomes `_pin_rows`, which returns the frame to
618
+ write along with whether it is empty, and gains `_release_pinned`, which
619
+ frees what `_pin_rows` kept and must not raise.
620
+ - **etl:** the Polars checkpoint store memory-maps only a local checkpoint.
621
+ It recognised cloud URIs by a lower-case prefix list without `r2://`, so a
622
+ checkpoint under `r2://` or an upper-case scheme such as `S3://` was read
623
+ with `memory_map=True`; it now uses the scheme set of
624
+ `loom.etl._uri`, compared case-insensitively.
625
+ - **etl:** documentation states what the writers do. `replace(streaming=...)`
626
+ and `ReplaceSpec.streaming` claimed a streaming Arrow write on Polars; no
627
+ backend reads the flag for a full replace, and the collect engine follows
628
+ the step's `streaming` attribute. `vacuum(full=True)` warns, in the guide
629
+ and in `VacuumSpec`, `MaintainTable.vacuum` and `MaintenanceVacuumConfig`,
630
+ that it deletes every unreferenced file under the table directory older
631
+ than the retention, whoever wrote it. The pipelines page states that
632
+ `replace_where` with an empty frame deletes the rows matching its
633
+ predicate.
494
634
  - **etl:** `upsert` and `update` on the Polars backend write with the route's
495
635
  `writer` and `commit` settings. The delta-rs MERGE received neither, so the
496
636
  Parquet files it rewrote came out with delta-rs defaults (SNAPPY, row groups
@@ -534,6 +674,20 @@
534
674
 
535
675
  ### ai
536
676
 
677
+ - **ai:** `PolarsAgentRunner.map` runs at most `ai.max_concurrent_runs`
678
+ worker tasks, which take the rows in order, instead of creating one task
679
+ per row up front; the order of the output rows is unchanged. A run
680
+ cancelled while the batch was not raises a `RuntimeError` naming how many
681
+ rows were left without an outcome and the first of them, where the run's
682
+ `asyncio.CancelledError` reached the caller.
683
+ - **ai:** `PolarsAgentRunner.validate` reports an output with a field no
684
+ column can hold (a union of two models, for instance) as
685
+ `OUTPUT_MISMATCH` instead of raising its `TypeError`, and checks the output
686
+ columns before asking whether the model is priced.
687
+ - **ai:** an agent output type that contains itself, directly
688
+ (`children: list[Node]`) or through another type, no longer makes
689
+ `PolarsAgentRunner.validate` and `map` fail with `RecursionError`: the
690
+ repeated struct or pydantic model is a `String` column holding its JSON.
537
691
  - **ai:** a configured `ai.prices` rate prices runs again with pydantic-ai
538
692
  2.54. That release records a response's usage before the
539
693
  `after_model_request` hook loom priced it in, so every run reported
@@ -573,6 +727,22 @@
573
727
  `SERVICE_UNAVAILABLE`, which `HttpErrorMapper` maps to `503`. Any other
574
728
  exception from the authenticator, and the `401` refusal, are unchanged.
575
729
 
730
+ ### prefect
731
+
732
+ - **prefect:** every log line the bridge sends carries the run's
733
+ `flow_run_id`, and a step's line its `task_run_id` as well. A step's lines
734
+ went out with `task_run_id` only, so a reader scoping a run's logs by flow
735
+ run, such as Prefect's flow run view, missed every step line; a step of a
736
+ parallel group now keeps the flow run too, through `ThreadDispatcher`'s
737
+ context copy. A line emitted inside a step with no flow run bound omits
738
+ `flow_run_id` instead of sending `null`.
739
+ - **prefect:** `deploy_flow` refuses a flow built from a YAML declaration
740
+ with a `TypeError` naming `discover_and_deploy_etls(config=...)`, which
741
+ deploys it, instead of the entrypoint module's `ConfigError`. When the flow
742
+ module's `__getattr__` raises anything but `AttributeError` while the flow
743
+ is looked up, `deploy_flow` raises its documented `ValueError`, chained to
744
+ that exception.
745
+
576
746
  ## ♻️ Refactor
577
747
 
578
748
  ### etl
@@ -591,6 +761,12 @@
591
761
  spec type than the protocol it is dispatched through; it now accepts the
592
762
  protocol's type and refuses a spec of another kind with a `TypeError`,
593
763
  which the registry's dispatch by kind already made unreachable.
764
+ - **etl:** `PolarsSourceReader` decodes JSON columns through
765
+ `decode_json_columns`; the private `_apply_json_decode` staticmethod and
766
+ module function of `loom.etl.backends.polars._reader` are removed.
767
+ - **etl:** the private `_is_cloud_path` of `loom.etl.checkpoint._cleaners`
768
+ moves, with the same scheme set, to `loom.etl._uri.is_cloud_path`,
769
+ and the Polars backend defines its frame type variable once.
594
770
 
595
771
  # 🚀 Release 2.1.2 ([#238](https://github.com/the-reacher-data/loom-py/pull/238))
596
772
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: loom-kernel
3
- Version: 2.18.0
3
+ Version: 2.19.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
@@ -13,7 +13,7 @@ import msgspec
13
13
  import msgspec.inspect as mi
14
14
  import polars as pl
15
15
 
16
- from loom.core.model import loom_type
16
+ from loom.core.model import is_pydantic_model, loom_type
17
17
 
18
18
  DECIMAL_DTYPE: Final = pl.Decimal(38, 9)
19
19
 
@@ -42,9 +42,14 @@ def output_columns(output_type: type[Any]) -> dict[str, Column]:
42
42
  and integer choices ``Int64``; ``float`` ``Float64``; ``bool``
43
43
  ``Boolean``; ``date`` ``Date``; ``datetime`` a UTC ``Datetime`` (naive when
44
44
  the field requires naive values, a naive value otherwise read as UTC);
45
- ``Decimal`` ``Decimal(38, 9)``; lists and sets ``List``; nested structs
46
- ``Struct``; an optional field the type of its value. Any other shape is
47
- ``String`` holding the JSON of the value.
45
+ ``Decimal`` ``Decimal(38, 9)``; ``UUID``, ``time``, ``timedelta`` and
46
+ ``bytes`` ``String`` holding the text the output type serialises them to;
47
+ lists and sets ``List``; nested structs and pydantic models ``Struct``;
48
+ an optional field the type of its value. A struct or model nested in
49
+ itself, directly or through other types, is ``String`` holding the JSON
50
+ of the value from that repetition down. Any other shape (a union of
51
+ several types, ``Any``, ``dict``, a fixed-length tuple, a ``Literal``
52
+ mixing value types) is ``String`` holding the JSON of the value.
48
53
 
49
54
  Args:
50
55
  output_type: A strict ``msgspec.Struct`` or ``pydantic.BaseModel``.
@@ -52,39 +57,58 @@ def output_columns(output_type: type[Any]) -> dict[str, Column]:
52
57
  Returns:
53
58
  The columns, in field order.
54
59
  """
55
- return {name: _column(mi.type_info(annotation)) for name, annotation in _fields(output_type)}
60
+ path = frozenset({output_type})
61
+ return {
62
+ name: _column(mi.type_info(annotation), path) for name, annotation in _fields(output_type)
63
+ }
56
64
 
57
65
 
58
66
  def _fields(output_type: type[Any]) -> Iterable[tuple[str, Any]]:
59
67
  if loom_type(output_type).library == "msgspec":
60
68
  return [(f.encode_name, f.type) for f in msgspec.structs.fields(output_type)]
69
+ return _model_fields(output_type)
70
+
71
+
72
+ def _model_fields(model: type[Any]) -> list[tuple[str, Any]]:
61
73
  return [
62
74
  (info.serialization_alias or info.alias or name, info.annotation)
63
- for name, info in output_type.model_fields.items()
75
+ for name, info in model.model_fields.items()
64
76
  ]
65
77
 
66
78
 
67
- def _column(info: mi.Type) -> Column:
79
+ def _column(info: mi.Type, path: frozenset[type[Any]]) -> Column:
68
80
  if isinstance(info, mi.Metadata):
69
- return _column(info.type)
81
+ return _column(info.type, path)
70
82
  if isinstance(info, mi.UnionType):
71
- return _optional(info)
83
+ return _optional(info, path)
72
84
  if isinstance(info, mi.LiteralType):
73
85
  return _choice(info.values)
74
86
  if isinstance(info, mi.EnumType):
75
87
  return _choice(tuple(member.value for member in info.cls))
76
88
  if isinstance(info, mi.CollectionType):
77
- return _list(_column(info.item_type))
89
+ return _list(_column(info.item_type, path))
78
90
  if isinstance(info, mi.StructType | mi.DataclassType | mi.TypedDictType):
79
- return _struct({f.encode_name: _column(f.type) for f in info.fields})
91
+ return _nested(info.cls, [(f.encode_name, f.type) for f in info.fields], path)
92
+ if isinstance(info, mi.CustomType) and is_pydantic_model(info.cls):
93
+ fields = [(name, mi.type_info(a)) for name, a in _model_fields(info.cls)]
94
+ return _nested(info.cls, fields, path)
80
95
  if isinstance(info, mi.DateTimeType):
81
96
  return Column(pl.Datetime("us", None if info.tz is False else "UTC"), _datetime)
82
97
  return _SCALARS.get(type(info), _JSON)
83
98
 
84
99
 
85
- def _optional(info: mi.UnionType) -> Column:
100
+ def _nested(
101
+ cls: type[Any], fields: Iterable[tuple[str, mi.Type]], path: frozenset[type[Any]]
102
+ ) -> Column:
103
+ if cls in path:
104
+ return _JSON
105
+ inner = path | {cls}
106
+ return _struct({name: _column(info, inner) for name, info in fields})
107
+
108
+
109
+ def _optional(info: mi.UnionType, path: frozenset[type[Any]]) -> Column:
86
110
  values = [member for member in info.types if not isinstance(member, mi.NoneType)]
87
- return _column(values[0]) if len(values) == 1 else _JSON
111
+ return _column(values[0], path) if len(values) == 1 else _JSON
88
112
 
89
113
 
90
114
  def _choice(values: tuple[Any, ...]) -> Column:
@@ -122,18 +146,23 @@ def _decimal(value: str | float | int) -> Decimal:
122
146
 
123
147
 
124
148
  def _json(value: Any) -> str:
125
- return value if isinstance(value, str) else msgspec.json.encode(value).decode()
149
+ return msgspec.json.encode(value).decode()
126
150
 
127
151
 
128
152
  _JSON: Final = Column(pl.String(), _json)
153
+ _TEXT: Final = Column(pl.String(), _same)
129
154
 
130
155
  _SCALARS: Final[Mapping[type[mi.Type], Column]] = MappingProxyType(
131
156
  {
132
- mi.StrType: Column(pl.String(), _same),
157
+ mi.StrType: _TEXT,
133
158
  mi.IntType: Column(pl.Int64(), _same),
134
159
  mi.FloatType: Column(pl.Float64(), float),
135
160
  mi.BoolType: Column(pl.Boolean(), _same),
136
161
  mi.DateType: Column(pl.Date(), date.fromisoformat),
137
162
  mi.DecimalType: Column(DECIMAL_DTYPE, _decimal),
163
+ mi.UUIDType: _TEXT,
164
+ mi.TimeType: _TEXT,
165
+ mi.TimeDeltaType: _TEXT,
166
+ mi.BytesType: _TEXT,
138
167
  }
139
168
  )