loom-kernel 8.0.0__tar.gz → 9.0.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 (699) hide show
  1. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/CHANGELOG.md +434 -26
  2. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/PKG-INFO +5 -1
  3. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/README.md +4 -0
  4. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +6 -4
  5. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +7 -12
  6. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +11 -6
  7. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +3 -2
  8. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/errors.py +48 -10
  9. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_lifecycle.py +5 -6
  10. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/bootstrap.py +15 -3
  11. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/cli/check.py +1 -0
  12. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/backend/sqlalchemy.py +32 -4
  13. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/decorators.py +4 -5
  14. loom_kernel-9.0.0/src/loom/core/cache/keys.py +186 -0
  15. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/repository.py +263 -148
  16. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/result_codec.py +5 -29
  17. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/checks.py +14 -4
  18. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/keys.py +2 -0
  19. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/overrides.py +15 -7
  20. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/executor.py +1 -2
  21. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/environment.py +21 -4
  22. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/__init__.py +2 -0
  23. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/convert.py +31 -1
  24. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/field.py +9 -4
  25. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/introspection.py +60 -12
  26. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/timestamped.py +0 -2
  27. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/types.py +11 -2
  28. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/types_postgres.py +1 -0
  29. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/plugins/entrypoints.py +5 -13
  30. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/abc/__init__.py +21 -4
  31. loom_kernel-9.0.0/src/loom/core/repository/abc/checks.py +60 -0
  32. loom_kernel-9.0.0/src/loom/core/repository/abc/cursor.py +682 -0
  33. loom_kernel-9.0.0/src/loom/core/repository/abc/session_scope.py +60 -0
  34. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/dynamodb/repository.py +7 -3
  35. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/backend.py +11 -5
  36. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/ids.py +6 -2
  37. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/registry.py +19 -2
  38. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/repository.py +57 -27
  39. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/backend.py +10 -5
  40. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/mixins.py +37 -5
  41. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +55 -14
  42. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +34 -12
  43. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/registry.py +25 -8
  44. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/repository.py +17 -2
  45. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/session_manager.py +8 -2
  46. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/values.py +47 -31
  47. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/__init__.py +1 -3
  48. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/compute.py +2 -2
  49. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/invoker.py +1 -1
  50. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/rule.py +6 -11
  51. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/__init__.py +4 -3
  52. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_schema_aligner/_policy.py +2 -2
  53. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_write_policy.py +13 -4
  54. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_reader.py +0 -6
  55. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_schema.py +1 -2
  56. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_writer.py +1 -1
  57. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/_schema.py +1 -2
  58. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/_writer.py +1 -1
  59. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/__init__.py +0 -2
  60. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_cleaners.py +3 -7
  61. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_store.py +2 -2
  62. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_filter.py +2 -30
  63. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/_with_agent.py +5 -16
  64. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -4
  65. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/_specs.py +0 -5
  66. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/__init__.py +1 -1
  67. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_history/_builder.py +1 -1
  68. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_history/_spec.py +1 -1
  69. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_into.py +5 -3
  70. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_table.py +1 -1
  71. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_clickhouse.py +2 -3
  72. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runner/__init__.py +1 -2
  73. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runner/core.py +1 -2
  74. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/schema/_schema.py +11 -5
  75. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/deploy/_discovery.py +4 -2
  76. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/compiler.py +161 -50
  77. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/app.py +15 -49
  78. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/auto.py +2 -1
  79. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/openapi.py +8 -18
  80. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/router_runtime.py +10 -6
  81. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/model.py +8 -5
  82. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_adapter.py +35 -9
  83. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_runtime_io.py +3 -7
  84. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/runner.py +6 -5
  85. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/_errors.py +6 -17
  86. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/_plan.py +18 -19
  87. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/phases/build_plan.py +14 -10
  88. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/phases/validate.py +93 -110
  89. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_config.py +20 -28
  90. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_boundary.py +0 -7
  91. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_mongo.py +0 -3
  92. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_shape.py +3 -4
  93. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_step.py +4 -0
  94. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_table/common.py +206 -159
  95. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_table/config.py +21 -0
  96. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/repository_harness.py +7 -1
  97. loom_kernel-8.0.0/src/loom/core/cache/keys.py +0 -96
  98. loom_kernel-8.0.0/src/loom/core/repository/abc/cursor.py +0 -157
  99. loom_kernel-8.0.0/src/loom/core/repository/abc/session_scope.py +0 -37
  100. loom_kernel-8.0.0/src/loom/etl/declarative/target/_schema_mode.py +0 -5
  101. loom_kernel-8.0.0/src/loom/etl/runner/errors.py +0 -7
  102. loom_kernel-8.0.0/src/loom/etl/runner/filtering.py +0 -41
  103. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/.gitignore +0 -0
  104. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/LICENSE +0 -0
  105. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/pyproject.toml +0 -0
  106. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/__init__.py +0 -0
  107. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/__init__.py +0 -0
  108. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_concurrency.py +0 -0
  109. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_filters.py +0 -0
  110. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_paths.py +0 -0
  111. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_roles.py +0 -0
  112. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_startup.py +0 -0
  113. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_transport.py +0 -0
  114. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/_usecase.py +0 -0
  115. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/__init__.py +0 -0
  116. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/_binding.py +0 -0
  117. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/_handlers.py +0 -0
  118. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/_rpc.py +0 -0
  119. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/card.py +0 -0
  120. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/events.py +0 -0
  121. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/a2a/server.py +0 -0
  122. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/abc.py +0 -0
  123. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/bootstrap.py +0 -0
  124. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/__init__.py +0 -0
  125. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/_compiler.py +0 -0
  126. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/_fingerprint.py +0 -0
  127. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/_plan.py +0 -0
  128. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
  129. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
  130. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
  131. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
  132. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
  133. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
  134. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
  135. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
  136. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_output.py +0 -0
  137. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/compiler/phases/_state.py +0 -0
  138. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/config.py +0 -0
  139. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/declarative/__init__.py +0 -0
  140. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/declarative/_envelope.py +0 -0
  141. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/declarative/_schema.py +0 -0
  142. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/declarative/_v1.py +0 -0
  143. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
  144. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/describe.py +0 -0
  145. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/__init__.py +0 -0
  146. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
  147. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
  148. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
  149. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
  150. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
  151. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
  152. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
  153. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
  154. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
  155. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_limits.py +0 -0
  156. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
  157. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
  158. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
  159. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
  160. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
  161. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
  162. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
  163. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
  164. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
  165. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
  166. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
  167. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
  168. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
  169. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
  170. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
  171. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
  172. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
  173. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/__init__.py +0 -0
  174. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/_batch.py +0 -0
  175. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/_columns.py +0 -0
  176. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/_frames.py +0 -0
  177. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/_ledger.py +0 -0
  178. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/_runner.py +0 -0
  179. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/etl/_validation.py +0 -0
  180. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/fastapi/__init__.py +0 -0
  181. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/fastapi/endpoints.py +0 -0
  182. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/fastapi/response.py +0 -0
  183. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/fastapi/streaming.py +0 -0
  184. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/inference.py +0 -0
  185. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/pricing.py +0 -0
  186. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/registry.py +0 -0
  187. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/remote_auth.py +0 -0
  188. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/__init__.py +0 -0
  189. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_bounded.py +0 -0
  190. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_chain.py +0 -0
  191. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_conversation.py +0 -0
  192. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_grants.py +0 -0
  193. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_handle.py +0 -0
  194. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_health.py +0 -0
  195. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_hooks.py +0 -0
  196. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_limits.py +0 -0
  197. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/runtime/_mcp.py +0 -0
  198. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/validate/__init__.py +0 -0
  199. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/ai/validate/__main__.py +0 -0
  200. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/__init__.py +0 -0
  201. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/auto.py +0 -0
  202. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/config.py +0 -0
  203. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/constants.py +0 -0
  204. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/runner.py +0 -0
  205. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/celery/service.py +0 -0
  206. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/cli/__init__.py +0 -0
  207. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/cli/app.py +0 -0
  208. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/cli/schema.py +0 -0
  209. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/async_bridge.py +0 -0
  210. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/__init__.py +0 -0
  211. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/_decide.py +0 -0
  212. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/_grants.py +0 -0
  213. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/_roles.py +0 -0
  214. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/_scope.py +0 -0
  215. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/elevation.py +0 -0
  216. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/authz/product.py +0 -0
  217. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/backend/__init__.py +0 -0
  218. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/backend/core_model.py +0 -0
  219. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/backend/protocol.py +0 -0
  220. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/backend/scoped_ddl.py +0 -0
  221. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/bootstrap/__init__.py +0 -0
  222. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
  223. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/bootstrap/kernel.py +0 -0
  224. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/__init__.py +0 -0
  225. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/_batching.py +0 -0
  226. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/_single_flight.py +0 -0
  227. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/abc/__init__.py +0 -0
  228. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/abc/backend.py +0 -0
  229. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/abc/config.py +0 -0
  230. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/abc/dependency.py +0 -0
  231. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/calls.py +0 -0
  232. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/codec.py +0 -0
  233. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/dependency.py +0 -0
  234. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/errors.py +0 -0
  235. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/gateway.py +0 -0
  236. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/memory.py +0 -0
  237. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/serializer.py +0 -0
  238. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/cache/wiring.py +0 -0
  239. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/command/__init__.py +0 -0
  240. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/command/adapter.py +0 -0
  241. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/command/base.py +0 -0
  242. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/command/field.py +0 -0
  243. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/command/introspection.py +0 -0
  244. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/compiler.py +0 -0
  245. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/__init__.py +0 -0
  246. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/_boto3.py +0 -0
  247. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/_includes.py +0 -0
  248. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/_resolver_utils.py +0 -0
  249. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/binder.py +0 -0
  250. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/configurable.py +0 -0
  251. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/context.py +0 -0
  252. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/errors.py +0 -0
  253. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/loader.py +0 -0
  254. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/model.py +0 -0
  255. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/observability.py +0 -0
  256. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/resolver.py +0 -0
  257. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/secrets.py +0 -0
  258. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/config/ssm.py +0 -0
  259. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/contracts/__init__.py +0 -0
  260. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/contracts/manifest.py +0 -0
  261. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/di/__init__.py +0 -0
  262. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/di/container.py +0 -0
  263. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/di/scope.py +0 -0
  264. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/discovery/__init__.py +0 -0
  265. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/discovery/_utils.py +0 -0
  266. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/discovery/base.py +0 -0
  267. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/discovery/interfaces.py +0 -0
  268. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/discovery/manifest.py +0 -0
  269. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/discovery/modules.py +0 -0
  270. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/__init__.py +0 -0
  271. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/compilable.py +0 -0
  272. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/compiler.py +0 -0
  273. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/events.py +0 -0
  274. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/metrics.py +0 -0
  275. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/plan.py +0 -0
  276. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/engine/post_commit.py +0 -0
  277. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/errors/__init__.py +0 -0
  278. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/errors/codes.py +0 -0
  279. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/errors/errors.py +0 -0
  280. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/expr/__init__.py +0 -0
  281. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/expr/eval.py +0 -0
  282. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/expr/nodes.py +0 -0
  283. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/expr/refs.py +0 -0
  284. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/identity/__init__.py +0 -0
  285. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/identity/context.py +0 -0
  286. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/identity/identity.py +0 -0
  287. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/identity/issuer.py +0 -0
  288. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/identity/wire.py +0 -0
  289. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/introspection/__init__.py +0 -0
  290. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/introspection/base.py +0 -0
  291. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/introspection/describe.py +0 -0
  292. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/job/__init__.py +0 -0
  293. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/job/callback.py +0 -0
  294. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/job/context.py +0 -0
  295. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/job/handle.py +0 -0
  296. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/job/job.py +0 -0
  297. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/job/service.py +0 -0
  298. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/locator.py +0 -0
  299. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/logger/__init__.py +0 -0
  300. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/logger/abc.py +0 -0
  301. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/logger/checks.py +0 -0
  302. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/logger/config.py +0 -0
  303. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/logger/registry.py +0 -0
  304. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/logger/structlogger.py +0 -0
  305. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/_json_schema.py +0 -0
  306. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/_loom_type.py +0 -0
  307. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/base.py +0 -0
  308. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/enums.py +0 -0
  309. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/partition.py +0 -0
  310. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/privilege.py +0 -0
  311. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/projection.py +0 -0
  312. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/relation.py +0 -0
  313. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/scoped.py +0 -0
  314. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/model/struct.py +0 -0
  315. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/__init__.py +0 -0
  316. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/config.py +0 -0
  317. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/event.py +0 -0
  318. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/observer/__init__.py +0 -0
  319. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/observer/noop.py +0 -0
  320. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/observer/otel.py +0 -0
  321. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/observer/structlog.py +0 -0
  322. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/otel_ids.py +0 -0
  323. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/protocol.py +0 -0
  324. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/runtime.py +0 -0
  325. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/span.py +0 -0
  326. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/observability/topology.py +0 -0
  327. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/persistence/__init__.py +0 -0
  328. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/persistence/abc.py +0 -0
  329. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/persistence/none.py +0 -0
  330. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/persistence/registry.py +0 -0
  331. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/plugins/__init__.py +0 -0
  332. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/plugins/optional.py +0 -0
  333. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/projection/__init__.py +0 -0
  334. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/projection/loaders.py +0 -0
  335. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/projection/runtime.py +0 -0
  336. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/__init__.py +0 -0
  337. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/abc/errors.py +0 -0
  338. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/abc/query.py +0 -0
  339. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
  340. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/abc/repo_for.py +0 -0
  341. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/abc/repository.py +0 -0
  342. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
  343. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
  344. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
  345. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
  346. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/__init__.py +0 -0
  347. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
  348. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/uow.py +0 -0
  349. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mongo/values.py +0 -0
  350. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/mutation.py +0 -0
  351. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/registration.py +0 -0
  352. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/registry.py +0 -0
  353. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
  354. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
  355. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
  356. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/migrations/__init__.py +0 -0
  357. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/migrations/env_template.py +0 -0
  358. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/migrations/hook.py +0 -0
  359. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/migrations/operations.py +0 -0
  360. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/migrations/runners.py +0 -0
  361. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
  362. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
  363. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
  364. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
  365. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
  366. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
  367. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
  368. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
  369. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
  370. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/__init__.py +0 -0
  371. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/bootstrap.py +0 -0
  372. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/config.py +0 -0
  373. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/elevate.py +0 -0
  374. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/guard/0001.sql +0 -0
  375. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/guard/0002.sql +0 -0
  376. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/guard/preflight.sql +0 -0
  377. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/guard_manifest.py +0 -0
  378. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/integrity.py +0 -0
  379. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/partitions.py +0 -0
  380. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/provider.py +0 -0
  381. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/schema.py +0 -0
  382. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/sources.py +0 -0
  383. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/rls/verify.py +0 -0
  384. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/session_settings.py +0 -0
  385. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
  386. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
  387. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/response/__init__.py +0 -0
  388. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/response/base.py +0 -0
  389. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/routing/__init__.py +0 -0
  390. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/routing/ref.py +0 -0
  391. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/routing/resolver.py +0 -0
  392. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/runner.py +0 -0
  393. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/schema/__init__.py +0 -0
  394. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/schema/schema_mode.py +0 -0
  395. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/schema_names.py +0 -0
  396. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/__init__.py +0 -0
  397. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/abc/__init__.py +0 -0
  398. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/abc/contracts.py +0 -0
  399. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/abc/errors.py +0 -0
  400. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/caller_bound.py +0 -0
  401. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
  402. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
  403. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
  404. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
  405. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/config.py +0 -0
  406. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/roles.py +0 -0
  407. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/sql/service.py +0 -0
  408. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/symbols.py +0 -0
  409. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/tracing/__init__.py +0 -0
  410. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/tracing/context.py +0 -0
  411. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/transaction.py +0 -0
  412. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/transport/__init__.py +0 -0
  413. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/transport/adapter.py +0 -0
  414. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/uow/__init__.py +0 -0
  415. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/uow/abc.py +0 -0
  416. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/uow/context.py +0 -0
  417. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/_predicates.py +0 -0
  418. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/agent_markers.py +0 -0
  419. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/constants.py +0 -0
  420. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/factory.py +0 -0
  421. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/field_ref.py +0 -0
  422. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/keys.py +0 -0
  423. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/markers.py +0 -0
  424. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/mcp_markers.py +0 -0
  425. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/outcome.py +0 -0
  426. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/registry.py +0 -0
  427. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/core/use_case/use_case.py +0 -0
  428. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/_uri.py +0 -0
  429. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/__init__.py +0 -0
  430. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_format_registry.py +0 -0
  431. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
  432. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_historify/_common.py +0 -0
  433. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_historify/_log.py +0 -0
  434. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_historify/_ops.py +0 -0
  435. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
  436. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_historify/_transform.py +0 -0
  437. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_merge.py +0 -0
  438. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_path_template.py +0 -0
  439. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_predicate.py +0 -0
  440. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
  441. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
  442. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/__init__.py +0 -0
  443. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
  444. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
  445. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_frame.py +0 -0
  446. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_historify.py +0 -0
  447. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
  448. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
  449. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
  450. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/polars/provider.py +0 -0
  451. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/__init__.py +0 -0
  452. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
  453. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/_historify.py +0 -0
  454. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/_reader.py +0 -0
  455. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
  456. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/backends/spark/provider.py +0 -0
  457. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
  458. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
  459. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_options.py +0 -0
  460. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_paths.py +0 -0
  461. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/checkpoint/_scope.py +0 -0
  462. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/__init__.py +0 -0
  463. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_binding.py +0 -0
  464. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_compiler.py +0 -0
  465. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_errors.py +0 -0
  466. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_plan.py +0 -0
  467. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_validators.py +0 -0
  468. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_validators_agents.py +0 -0
  469. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_validators_config.py +0 -0
  470. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
  471. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/compiler/_validators_step.py +0 -0
  472. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/__init__.py +0 -0
  473. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/_format.py +0 -0
  474. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/_read_options.py +0 -0
  475. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/_utils.py +0 -0
  476. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/_write_options.py +0 -0
  477. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
  478. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/expr/_params.py +0 -0
  479. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
  480. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
  481. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
  482. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/__init__.py +0 -0
  483. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/_from.py +0 -0
  484. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
  485. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
  486. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
  487. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_client.py +0 -0
  488. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_errors.py +0 -0
  489. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_file.py +0 -0
  490. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_history/__init__.py +0 -0
  491. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
  492. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_history/_errors.py +0 -0
  493. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
  494. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/declarative/target/_temp.py +0 -0
  495. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/executor/__init__.py +0 -0
  496. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/executor/_agents.py +0 -0
  497. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/executor/_dispatcher.py +0 -0
  498. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/executor/_executor.py +0 -0
  499. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/__init__.py +0 -0
  500. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/_registry.py +0 -0
  501. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/__init__.py +0 -0
  502. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
  503. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
  504. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
  505. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_mongo.py +0 -0
  506. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
  507. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
  508. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
  509. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/sources/_serialization.py +0 -0
  510. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/targets/__init__.py +0 -0
  511. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
  512. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/__init__.py +0 -0
  513. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/_config.py +0 -0
  514. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/_observer.py +0 -0
  515. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/_records.py +0 -0
  516. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
  517. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
  518. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
  519. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
  520. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/__init__.py +0 -0
  521. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/_builder.py +0 -0
  522. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/_ops.py +0 -0
  523. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/_protocol.py +0 -0
  524. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/_runner.py +0 -0
  525. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/_step.py +0 -0
  526. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
  527. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
  528. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/__init__.py +0 -0
  529. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_generics.py +0 -0
  530. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_params.py +0 -0
  531. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
  532. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_process.py +0 -0
  533. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_sql.py +0 -0
  534. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_step.py +0 -0
  535. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_step_client.py +0 -0
  536. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
  537. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runner/_agents.py +0 -0
  538. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runner/_providers.py +0 -0
  539. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runner/_wiring.py +0 -0
  540. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runner/config_loader.py +0 -0
  541. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runtime/__init__.py +0 -0
  542. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runtime/_config_values.py +0 -0
  543. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/runtime/contracts.py +0 -0
  544. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/schema/__init__.py +0 -0
  545. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/schema/_contract.py +0 -0
  546. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/storage/__init__.py +0 -0
  547. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/storage/_config.py +0 -0
  548. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/storage/_file_locator.py +0 -0
  549. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/storage/_locator.py +0 -0
  550. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/storage/routing.py +0 -0
  551. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/testing/__init__.py +0 -0
  552. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/testing/_result.py +0 -0
  553. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/testing/_runners.py +0 -0
  554. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/testing/_scenario.py +0 -0
  555. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/testing/_stubs.py +0 -0
  556. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/etl/testing/spark.py +0 -0
  557. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/__init__.py +0 -0
  558. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_async.py +0 -0
  559. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_config.py +0 -0
  560. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_ctx.py +0 -0
  561. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_flow_yaml.py +0 -0
  562. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_meta.py +0 -0
  563. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_placeholders.py +0 -0
  564. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/_summary.py +0 -0
  565. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/deploy/__init__.py +0 -0
  566. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/deploy/_schedule.py +0 -0
  567. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
  568. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
  569. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/__init__.py +0 -0
  570. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_assemble.py +0 -0
  571. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_backfill.py +0 -0
  572. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
  573. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_body.py +0 -0
  574. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_common.py +0 -0
  575. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_factory.py +0 -0
  576. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_hooks.py +0 -0
  577. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_maintenance.py +0 -0
  578. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_params.py +0 -0
  579. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_run_name.py +0 -0
  580. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_runtime.py +0 -0
  581. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_signature.py +0 -0
  582. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/flow/_stages.py +0 -0
  583. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/manifest/__init__.py +0 -0
  584. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/manifest/_model.py +0 -0
  585. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/manifest/_s3.py +0 -0
  586. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/manifest/_store.py +0 -0
  587. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/__init__.py +0 -0
  588. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/_event.py +0 -0
  589. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/_factory.py +0 -0
  590. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/_format.py +0 -0
  591. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/_port.py +0 -0
  592. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/_slack.py +0 -0
  593. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/notify/_sns.py +0 -0
  594. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/observer/__init__.py +0 -0
  595. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/observer/_flow.py +0 -0
  596. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/observer/_logging_bridge.py +0 -0
  597. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/observer/_manifest.py +0 -0
  598. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prefect/observer/_task_run.py +0 -0
  599. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prometheus/__init__.py +0 -0
  600. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prometheus/_instruments.py +0 -0
  601. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prometheus/adapter.py +0 -0
  602. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prometheus/kafka.py +0 -0
  603. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prometheus/lifecycle.py +0 -0
  604. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/prometheus/middleware.py +0 -0
  605. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/py.typed +0 -0
  606. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/__init__.py +0 -0
  607. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/_body.py +0 -0
  608. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/adapter.py +0 -0
  609. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/auth/__init__.py +0 -0
  610. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/auth/abc.py +0 -0
  611. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/auth/config.py +0 -0
  612. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/auth/jwt.py +0 -0
  613. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/auth/middleware.py +0 -0
  614. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/autocrud.py +0 -0
  615. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/checks.py +0 -0
  616. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/config.py +0 -0
  617. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/constants.py +0 -0
  618. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/cors.py +0 -0
  619. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/errors.py +0 -0
  620. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/__init__.py +0 -0
  621. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/_errors.py +0 -0
  622. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
  623. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/health.py +0 -0
  624. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/response.py +0 -0
  625. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/fastapi/sql.py +0 -0
  626. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/middleware.py +0 -0
  627. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/rest/rest_adapter.py +0 -0
  628. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/__init__.py +0 -0
  629. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/__init__.py +0 -0
  630. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
  631. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
  632. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
  633. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_errors.py +0 -0
  634. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_operators.py +0 -0
  635. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
  636. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
  637. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
  638. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
  639. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
  640. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
  641. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
  642. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
  643. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
  644. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
  645. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
  646. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/__init__.py +0 -0
  647. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/_bindings.py +0 -0
  648. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/compiler/_compiler.py +0 -0
  649. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/core/__init__.py +0 -0
  650. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/core/_errors.py +0 -0
  651. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/core/_exceptions.py +0 -0
  652. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/core/_message.py +0 -0
  653. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/core/_tracing.py +0 -0
  654. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/core/_typing.py +0 -0
  655. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/graph/__init__.py +0 -0
  656. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/graph/_flow.py +0 -0
  657. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/__init__.py +0 -0
  658. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_codec.py +0 -0
  659. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_errors.py +0 -0
  660. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
  661. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_message.py +0 -0
  662. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_record.py +0 -0
  663. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/_wire.py +0 -0
  664. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
  665. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
  666. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
  667. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
  668. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
  669. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
  670. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
  671. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
  672. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
  673. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/mongo/__init__.py +0 -0
  674. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
  675. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/mongo/_config.py +0 -0
  676. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/mongo/_event.py +0 -0
  677. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/mongo/_normalize.py +0 -0
  678. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/__init__.py +0 -0
  679. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_branches.py +0 -0
  680. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
  681. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
  682. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_decompose.py +0 -0
  683. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
  684. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
  685. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_fork.py +0 -0
  686. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_helpers.py +0 -0
  687. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_protocols.py +0 -0
  688. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_router.py +0 -0
  689. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_sink.py +0 -0
  690. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
  691. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/_with.py +0 -0
  692. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/nodes/refs.py +0 -0
  693. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/streaming/testing.py +0 -0
  694. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/__init__.py +0 -0
  695. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/agents.py +0 -0
  696. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/golden.py +0 -0
  697. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/http_harness.py +0 -0
  698. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/in_memory.py +0 -0
  699. {loom_kernel-8.0.0 → loom_kernel-9.0.0}/src/loom/testing/runner.py +0 -0
@@ -412,7 +412,7 @@
412
412
  selection can be checked without running it. A bare string as `include`
413
413
  raises `TypeError`. The runner now filters through it. `InvalidStageError`
414
414
  is exported from `loom.etl.compiler` as well; it is the same class as
415
- `loom.etl.runner.InvalidStageError` and `loom.etl.InvalidStageError`.
415
+ `loom.etl.InvalidStageError`.
416
416
  - **etl:** `iter_processes`, `iter_steps_in_process` and `iter_all_steps` are
417
417
  exported from `loom.etl.compiler`. They flatten a compiled plan in
418
418
  execution order, parallel groups in declaration order, so code that walks
@@ -459,6 +459,78 @@
459
459
 
460
460
  ### core
461
461
 
462
+ - **core:** `RuleViolation` and `RuleViolations` are no longer exported by
463
+ `loom.core.use_case` or `loom.core.use_case.rule`. Import them from
464
+ `loom.core.errors`, their only public home.
465
+ - **core:** wrapping a repository in `CachedRepository` raises `RuntimeError`
466
+ when one of its `@cache_query` reads has a missing return annotation, one
467
+ the defining module cannot resolve, or one outside the supported grammar,
468
+ naming the repository and the method; a `@cached` repository therefore fails
469
+ when it is built. Before, wrapping emitted a `DeprecationWarning` and logged
470
+ `CacheQueryReturnTypeUnusable`, and the cached call returned the decoded
471
+ payload instead of the declared type. Annotate the read's return type with a
472
+ struct, a scalar, or a `list`, `tuple` or optional of those. A
473
+ `@cache_query` coroutine that is not defined on the repository class, such
474
+ as one set on the instance, raises `RuntimeError` when it is looked up on
475
+ the wrapper, since no codec was built for it; define it as a method of the
476
+ class.
477
+ - **core:** a field annotated `X | UnsetType` infers `X`'s column type.
478
+ `UNSET` means "not provided", not another type, so `str | UnsetType` now
479
+ compiles to `String` and `int | UnsetType` to `Integer` instead of `JSON`,
480
+ and `Annotated[str, String(20)] | UnsetType` reads its declared type. Such
481
+ a column is scalar: a REST route may declare it filterable, `like` and
482
+ `ilike` included for text, and sortable by offset; a cursor sort on it is
483
+ still refused, since a cursor key must be a bare type. Nullability is
484
+ unchanged: `str | None | UnsetType` admits `None` and is nullable,
485
+ `UnsetType` alone keeps the column `NOT NULL`. An undeclared
486
+ `Decimal | UnsetType`, plain `Enum | UnsetType` or `Literal[...] | UnsetType`
487
+ now needs a declared column type, as it does without `UnsetType`. On Mongo,
488
+ a `str | UnsetType` or `UUID | UnsetType` primary key is now accepted, and
489
+ a range filter or sort on a `Decimal | UnsetType` field is refused, as on a
490
+ `Decimal` field. Alembic autogenerate will show the type change from `JSON`
491
+ for existing tables with such columns.
492
+ - **core:** a column's nullability follows its field's annotation. A field
493
+ whose annotation admits `None` (`x: int | None = None`, also inside
494
+ `Annotated`) compiles to a nullable column; any other field compiles to
495
+ `NOT NULL`, and a primary key column is `NOT NULL` whatever its annotation.
496
+ Before, every column was `NOT NULL` unless declared otherwise, so the model
497
+ accepted `None` and the database refused it on insert. `nullable=` on
498
+ `ColumnField`, `ScopedField` or `Field` now defaults to `None` (follow the
499
+ annotation) and a declared `True` or `False` still wins. Alembic
500
+ autogenerate will propose `nullable` changes for existing tables whose
501
+ Optional fields were created `NOT NULL`; to keep such a column `NOT NULL`,
502
+ declare `nullable=False`. ETL schema contracts keep their own rule (a
503
+ column is nullable unless declared otherwise), which this change does not
504
+ touch.
505
+ - **core:** a `uuid.UUID` field without a declared column type is now a
506
+ `Uuid` column (`loom.core.model.Uuid`, SQLAlchemy `Uuid`) instead of
507
+ `JSON`: `UUID` on Postgres, `CHAR(32)` holding the hex form on dialects
508
+ without a native UUID type, such as SQLite. Such a field is now a scalar
509
+ column, so REST `filterable`, `sortable` and `ALL` accept it on every
510
+ backend, `mongo` included; on SQLite a cursor walk sorted by it pages in
511
+ UUID order and an equality filter on it matches. Streaming `IntoTable` with the
512
+ SQLAlchemy backend binds a `UUID` field the same way instead of failing to
513
+ serialise it as JSON. Migration: an existing table with such a column needs
514
+ a revision changing its type; Alembic autogenerate reports it as a type
515
+ change from `JSON` to `Uuid`. Postgres does not cast `json` to `uuid`, so
516
+ the revision needs `postgresql_using="(<column> #>> '{}')::uuid"`. On a
517
+ dialect without a native UUID type the old rows hold JSON text (the quoted
518
+ UUID with dashes), which the `Uuid` column cannot read, so after the type
519
+ change the revision rewrites each value to its 32-character hex. On
520
+ SQLite: `op.batch_alter_table` for the type change, then
521
+ `UPDATE <table> SET <column> = replace(json_extract(<column>, '$'), '-', '')`.
522
+ Rewriting before the type change loses values on SQLite: a hex form made
523
+ only of digits is stored as a number in the `JSON` column.
524
+ - **core:** a `Decimal` field, plain or optional, declares its column type: a
525
+ SQLAlchemy model with an undeclared one is refused when it is compiled,
526
+ naming the field. loom inferred `NUMERIC(10, 2)`, and Postgres silently
527
+ rounds a value to that scale (`1.2345` is stored as `1.23`) and refuses one
528
+ past that precision. Migration: declare it, e.g.
529
+ `Annotated[Decimal, Numeric(precision=20, scale=6)]` or
530
+ `ColumnField(Numeric(precision=20, scale=6))`; `Numeric()` with no
531
+ precision is now an unbounded `NUMERIC` instead of `NUMERIC(10, 2)`, and
532
+ `Numeric(scale=...)` without a precision raises `ValueError`, as SQLAlchemy
533
+ would drop the scale.
462
534
  - **core:** `sql_endpoint.auth` admits only `identity` and `external`;
463
535
  `auth: jwt` is refused when the config is loaded, and the alias and its
464
536
  `DeprecationWarning` are gone. Migration: replace `auth: jwt` with
@@ -550,6 +622,81 @@
550
622
  or `RuleViolation` it returns no longer fails the rule. Migrate
551
623
  `Rule.check(F(Order).total, via=lambda v: v <= 0, message="total must be > 0")`
552
624
  to `Rule.check(F(Order).total, via=lambda v: "total must be > 0" if v <= 0 else None)`.
625
+ - **core:** cursor signing keys are required (ADR 0004). An application whose
626
+ persistence backend serves repositories (`sqlalchemy`, `mongo`), and a
627
+ Celery worker that registers repositories, read `persistence.cursors` at
628
+ startup and fail with a `ConfigError` without a key:
629
+
630
+ ```yaml
631
+ persistence:
632
+ cursors:
633
+ current_key_id: "2026-10"
634
+ keys:
635
+ "2026-10": {env: CURSOR_KEY_2026_10} # or {path: /run/secrets/...}
636
+ ```
637
+
638
+ Keys are read from a file or an environment variable, never written in the
639
+ configuration, as standard base64 decoding to at least 32 random bytes
640
+ (`openssl rand -base64 32`); a passphrase is refused. Older key ids stay in
641
+ `keys` to verify the tokens they signed during a rotation.
642
+ The default is `signed` in every environment; `signing: ephemeral` (a
643
+ random per-process key, for `development.yaml`) and `signing: unsigned`
644
+ (for `test.yaml`) are explicit opt-outs, and both log a WARNING at
645
+ startup. In production and staging the deploy check `loom.cursors.E001`
646
+ fails startup, and `loom check --deploy` fails, when a `database` or
647
+ `persistence.mongo` section is set and `signing` is not `signed` or
648
+ `current_key_id` names no entry of `keys`. No `config.overridable` entry
649
+ may open a key under `persistence.cursors`. A key's `env` source must not
650
+ name a `LOOM_*` variable. Tokens issued before this release are refused:
651
+ clients restart from the first page.
652
+ - **core:** a cursor page orders only by non-null columns of a type a token
653
+ carries; a dotted path, a JSON, `bytes` or optional column answers
654
+ `400 unsupported_query` before the query runs (`require_cursor_sort`), and
655
+ a page whose last row holds a non-finite number or a value the token
656
+ cannot carry answers 400 instead of 500. An empty cursor is an invalid
657
+ token on SQLAlchemy as on Mongo. Tokens bind the model as
658
+ `module.qualname`; `UnsupportedQuery` and the client's 400 name it by its
659
+ qualified name alone. `CursorCodec.encode`/`decode`, `require_cursor_sort`
660
+ and `QuerySpecCompiler(model=...)` take the model class (or a name). Mongo
661
+ issues the next token in the model's types, so a page sorted by a date or
662
+ UUID column, or keyed by a UUID, reaches the next page.
663
+ - **core:** one `CursorCodec` per process: the registration modules register
664
+ it with `register_cursor_codec`, which raises `ConfigError` when a
665
+ different codec is already registered, and, in a deployed environment,
666
+ for an `ephemeral` or `unsigned` codec unless `CursorCodec.from_context`
667
+ built it from a configuration silencing `loom.cursors.E001`. Without a
668
+ registered `Environment` the process environment decides (`LOOM_ENV`, else
669
+ production).
670
+ - **core:** `loom.core.checks.silenced_checks(config)` returns the ids
671
+ `checks.silenced` lists, as the deploy-check runner reads them.
672
+ - **core:** the unsigned module functions `encode_cursor` and
673
+ `decode_cursor` are gone. `CursorCodec` (with `CursorConfig` and
674
+ `CursorKeySource`, exported from `loom.core.repository.abc`) issues and
675
+ verifies tokens: `encode(cursor, *, model, query, scope)` and
676
+ `decode(token, *, backend, model, query, scope, columns, primary_key)`,
677
+ where `scope` is required and `""` binds a token to no tenant, `columns`
678
+ maps each column name to its annotation and `primary_key` names the key
679
+ columns in order. A sort key or primary-key value whose type is not its
680
+ column's is refused (`400 unsupported_query`), as is a sort field missing
681
+ from `columns`. The backends
682
+ register the codec they build in DI, so a service paginating by hand
683
+ resolves it with `container.resolve(CursorCodec)`. A decoded datetime key
684
+ is always aware. A `time` sort key is carried too, with the offset it was
685
+ issued with; before, a page sorted by a column holding `time` values
686
+ raised `TypeError` when it issued the next cursor.
687
+ - **core:** `RepositorySQLAlchemy`, `RepositoryMongo`, `QuerySpecCompiler`
688
+ (with a required `scope` and `columns` too), `SQLAlchemyDefaultRepositoryBuilder`,
689
+ `MongoDefaultRepositoryBuilder`, `build_sqlalchemy_repository_registration_module`,
690
+ `build_mongo_repository_registration_module` and
691
+ `loom.testing.build_repository_harness` take a required keyword-only
692
+ `cursor_codec`. A custom repository `builder` passes
693
+ `context.container.resolve(CursorCodec)`. `extract_next_cursor` returns the
694
+ next `Cursor` position instead of a token, and `SessionManager` gains
695
+ `current_settings()`. SQLAlchemy repositories bind cursors to the caller's
696
+ `loom.scope.*` session values. `loom.core.environment` gains
697
+ `configured_variable(name)`, which reads a variable a configuration names
698
+ and refuses a `LOOM_*` name.
699
+
553
700
  - **core:** the `LoomType` protocol gains `from_query(params)`, which
554
701
  validates query-string values strictly. A number takes the JSON number
555
702
  grammar and must be finite, an integer its integer subset within
@@ -567,8 +714,7 @@
567
714
  takes the tuple as its first argument and raises `TypeError` for anything
568
715
  else. A cursor token issued for such a model before this release is refused with
569
716
  `UnsupportedQuery`, `400 unsupported_query`; clients restart from the first
570
- page. `decode_cursor` takes `id_count`, the number of key columns, and
571
- `get_id_attributes` returns every key column name.
717
+ page. `get_id_attributes` returns every key column name.
572
718
 
573
719
  - **core:** `compile_all` raises `ValueError` for a model with a composite
574
720
  primary key that declares a relation or a projection whose loader runs
@@ -663,6 +809,8 @@
663
809
  present convert those rows deliberately (for example to UTC with
664
810
  `(c::timetz AT TIME ZONE 'UTC')::time`) before changing the type. MongoDB is
665
811
  unaffected: it stores `date` and `time` values as ISO 8601 strings.
812
+ - **core:** `to_column_value` is imported from `loom.core.model.convert`; it is
813
+ no longer exported by `loom.core.repository.sqlalchemy.values`.
666
814
 
667
815
  ### ai
668
816
 
@@ -671,9 +819,15 @@
671
819
  example `spec_malformed`, `engine_not_found` and `mcp_server_unreachable`.
672
820
  Build an issue with `AgentErrorCode.X.issue(...)` and keyword arguments,
673
821
  such as `AgentErrorCode.ENGINE_NOT_FOUND.issue(component="openai-agents",
674
- available=["pydantic-ai"])`. `loom.ai.errors.from_message` is removed too:
675
- `AgentCompilationError` still turns a bare string into an `UNSPECIFIED`
676
- issue. Messages keep their text; a list that is empty renders `none`.
822
+ available=["pydantic-ai"])`. `loom.ai.errors.from_message` is removed too.
823
+ Messages keep their text; a list that is empty renders `none`.
824
+ - **ai:** `AgentCompilationError` takes `AgentCompilationIssue` values only;
825
+ bare strings and the `AgentErrorCode.UNSPECIFIED` code they became are
826
+ removed. Build an issue from an `AgentErrorCode` member with `.issue()`.
827
+ The five pydantic-ai engine failures that raised bare strings now carry
828
+ their own codes, with the same messages: `TOOL_NAME_COLLISION`,
829
+ `TOOL_NAME_TOO_LONG`, `USECASE_NOT_COMPILED`, `CAPABILITY_KIND_NO_BUILDER`
830
+ and `MCP_CONNECTION_NOT_OPENED`.
677
831
  - **ai:** `AgentCompilationIssue` is a type alias of
678
832
  `CompileIssue[AgentErrorCode]` from `loom.core.errors.codes`, not a class.
679
833
  It has the same fields, but `isinstance` against it raises `TypeError`
@@ -752,6 +906,9 @@
752
906
  declares both a pydantic `type_ref` output and `output_check` serialises
753
907
  an accepted answer twice per attempt — once for the check's own builtins
754
908
  projection, once for the wire — accepted rather than optimised away.
909
+ - **ai:** a provider's `credentials_ref` is read through
910
+ `loom.core.environment.configured_variable` and may not name a `LOOM_*`
911
+ variable.
755
912
 
756
913
  ### rest
757
914
 
@@ -814,6 +971,33 @@
814
971
  `msgspec.ValidationError`. The root `title` is dropped on pydantic
815
972
  OpenAPI schemas for request bodies and responses alike, matching the
816
973
  untitled document a Struct always produced.
974
+ - **rest:** a `sortable` column must be a field of the items the route
975
+ answers with (`PageResult[T]`, `CursorResult[T]` or `list[T]`); a column
976
+ the response does not show, or a result type that does not say, fails
977
+ compilation naming the route and the field, since ordering by it reveals
978
+ its values. `sortable=ALL` opens every scalar column, hidden ones included,
979
+ and its startup warning says so. `filterable` follows the same rule, with
980
+ `filterable=ALL` as its escape hatch. "Shown" is decided by field name; a
981
+ pydantic field declared `exclude=True` is not shown.
982
+ - **rest:** breaking: a `QuerySpec` route that can serve cursor pages (cursor
983
+ mode, or the default `allow_pagination_override=True`) must answer with
984
+ items that show its primary key, which every cursor token carries. A route
985
+ whose response hides the key, or whose result type is untyped (`str`,
986
+ `dict[str, Any]`, ...), now fails compilation naming the route and the key.
987
+ `sortable=ALL` opens it with a warning; a route that must hide its keys
988
+ serves offset pages only (`pagination_mode` offset and
989
+ `allow_pagination_override=False`). On such a route the key must also be of
990
+ a type a token carries, in a scalar column: a key declared in a JSON or
991
+ array column, which a SQL keyset cannot order, fails compilation instead
992
+ of on the first cursor request. A bare `UUID` key, a scalar `Uuid` column,
993
+ compiles and pages on SQLAlchemy and Mongo alike.
994
+ - **rest:** `create_fastapi_app(interfaces=...)` is removed and `routes` is
995
+ required; use `create_fastapi_app(result, RouteSources(python=[...]))`.
996
+ - **rest:** the `QUERY_PARAM_PAGE`, `QUERY_PARAM_LIMIT`,
997
+ `QUERY_PARAM_PAGINATION`, `QUERY_PARAM_AFTER`, `QUERY_PARAM_CURSOR`,
998
+ `QUERY_PARAM_SORT`, `QUERY_PARAM_DIRECTION` and `QUERY_PARAM_PROFILE`
999
+ re-exports of `loom.rest.fastapi.openapi` are removed; use the matching
1000
+ `loom.rest.constants.QueryParam` member (`QueryParam.PAGE`, ...).
817
1001
 
818
1002
  ### prefect
819
1003
 
@@ -904,11 +1088,8 @@
904
1088
  - **etl:** a `WithAgent` compiled by a runner whose config has no `ai:`
905
1089
  section fails with the new code `AGENT_RUNNER_NOT_CONFIGURED` instead of
906
1090
  `AGENT_NOT_FOUND`, which now means only that no artifact declares the name.
907
- - **etl:** the names of `loom.etl.runner.filtering` (`_filter_plan`,
908
- `_filter_process`, `_collect_all_names`, `_map_pipeline_nodes`,
909
- `_map_process_nodes`) are deprecated and removed in loom 3.0; each emits a
910
- `DeprecationWarning` naming its replacement, `loom.etl.compiler.filter_plan`
911
- or, for `_collect_all_names`, `iter_processes` and `iter_all_steps`.
1091
+ - **etl:** `loom.etl.runner.filtering` is removed; use
1092
+ `loom.etl.compiler.filter_plan`.
912
1093
  - **etl:** the Polars writer refuses, under `SchemaMode.STRICT` and
913
1094
  `EVOLVE`, a frame column that is a `Struct` or `List` where the Delta table
914
1095
  has `String`, or `String` where the table has a `Struct` or `List`, at any
@@ -927,8 +1108,7 @@
927
1108
  `Unknown step or process names: [...]` instead of `No steps or processes
928
1109
  match include=[...]`, the constructor's parameter is `unknown`, and the
929
1110
  names are kept on the new `unknown` attribute. Positional construction is
930
- unchanged; `InvalidStageError(include=...)` still works, emits a
931
- `DeprecationWarning` and is removed in loom 3.0. The error survives pickle
1111
+ unchanged. The error survives pickle
932
1112
  with its `unknown` names, so it crosses process boundaries intact.
933
1113
  - **etl:** `ThreadDispatcher` runs each task in a copy of the caller's
934
1114
  context, as `asyncio.to_thread` does, so a step of a parallel group sees
@@ -939,16 +1119,91 @@
939
1119
  caller's context among the requirements on an implementation.
940
1120
  - **etl:** `WithAgent(max_usd=...)` keeps the budget as a `Decimal`. An
941
1121
  `int`, or another `numbers.Integral` such as `numpy.int64`, is converted
942
- exactly. A `float` emits a `DeprecationWarning`, is converted through its
943
- `str()` (`0.1` becomes `Decimal("0.1")`) and is removed in loom 3.0. A
944
- `bool`, accepted before, and any other type, such as `str`, raise
945
- `TypeError`. `NaN`, `sNaN` and `Infinity`, as a `Decimal` or a `float`,
946
- raise `ValueError`, like zero and a negative amount; a `Decimal` `NaN` or
947
- `sNaN` used to raise `decimal.InvalidOperation`, and a `Decimal`
948
- `Infinity`, a `float` `inf` and a `float` `nan` were accepted.
1122
+ exactly. A `bool`, accepted before, and any other type, such as `str`,
1123
+ raise `TypeError`. `NaN`, `sNaN` and `Infinity` raise `ValueError`, like
1124
+ zero and a negative amount; a `Decimal` `NaN` or `sNaN` used to raise
1125
+ `decimal.InvalidOperation`, and a `Decimal` `Infinity` was accepted.
1126
+ - **etl:** `InvalidStageError(include=...)` is removed; use
1127
+ `InvalidStageError(unknown=...)` or pass the names positionally.
1128
+ - **etl:** `WithAgent(max_usd=<float>)` is removed and raises `TypeError`;
1129
+ pass a `Decimal`, such as `Decimal("2.50")`, or an `int`.
1130
+ - **etl:** `loom.etl.CheckpointCleaner` and
1131
+ `loom.etl.checkpoint.CheckpointCleaner` are removed; use
1132
+ `FsspecTempCleaner`, now exported from `loom.etl` as well.
1133
+ - **etl:** the module `loom.etl.declarative.target._schema_mode` is removed;
1134
+ import `SchemaMode` from `loom.core.schema` (or `loom.etl`).
1135
+ - **etl:** `FromClickHouse.select(columns)` is removed; use
1136
+ `FromClickHouse.columns(*columns)`.
1137
+ - **etl:** `ClickHouseSourceSpec.table` is removed; use
1138
+ `ClickHouseSourceSpec.table_ref.ref`.
1139
+ - **etl:** `loom.etl.backends.polars._reader._apply_source_schema` is
1140
+ removed. It was a test helper and has no public replacement.
1141
+ - **etl:** the module `loom.etl.runner.errors` is removed, and neither
1142
+ `loom.etl.runner` nor `loom.etl.runner.core` exports `InvalidStageError`;
1143
+ import it from `loom.etl.compiler` (or `loom.etl`).
1144
+ - **etl:** `loom.etl.io.sources._clickhouse` no longer re-exports
1145
+ `FromClickHouse` and `ClickHouseSourceSpec`; import them from
1146
+ `loom.etl.declarative.source` (`FromClickHouse` also from `loom.etl`).
949
1147
 
950
1148
  ### streaming
951
1149
 
1150
+ - **streaming:** `ConsumerSettings.delivery` is required. A Kafka consumer
1151
+ config without `delivery` fails to decode, so compiling a flow that reads
1152
+ from Kafka raises `CompilationError` with `KAFKA_CONFIG_INVALID` naming the
1153
+ missing field. Before, a missing `delivery` resolved to `at_most_once`.
1154
+ Declare `delivery: at_most_once` to keep that behaviour, or
1155
+ `delivery: at_least_once`. `ConsumerSettings.effective_delivery()` is
1156
+ removed; read `ConsumerSettings.delivery`.
1157
+ - **streaming:** `ConsumerSettings.enable_auto_commit` is removed, together
1158
+ with the `DELIVERY_CONFLICT` compile code. The consumer settings forbid
1159
+ unknown fields, so a config that sets `enable_auto_commit` fails to decode
1160
+ (`KAFKA_CONFIG_INVALID`). Declare `delivery` instead: `enable_auto_commit:
1161
+ false` was `delivery: at_least_once`, and `true` was `delivery:
1162
+ at_most_once`.
1163
+ - **streaming:** `ConsumerSettings.poll_timeout_ms` is removed. The
1164
+ partitioned source ignored it and logged a deprecation warning; a config
1165
+ that sets it now fails to decode (`KAFKA_CONFIG_INVALID`). Remove the key;
1166
+ the partitioned source is tuned with `batch_size` and `poll_backoff_ms`.
1167
+ - **streaming:** `CompilationError` takes `CompilationIssue` values only;
1168
+ bare strings and the `StreamingErrorCode.UNSPECIFIED` code they became are
1169
+ removed. Build an issue from a `StreamingErrorCode` member with `.issue()`.
1170
+ - **streaming:** `CompilationError.errors` is removed. Read the messages from
1171
+ `CompilationError.issues` (`[issue.message for issue in error.issues]`).
1172
+ - **streaming:** an `IntoTable` sink section (`streaming.sinks.<name>`) with a
1173
+ key its backend does not read fails at compile with `SINK_CONFIG_INVALID`,
1174
+ naming every unknown key; on Delta this covers the keys under `staging`
1175
+ too, and a `staging` or `writer_properties` that is not a mapping is
1176
+ refused. Before, such a key was ignored. A SQLAlchemy sink that references a
1177
+ shared `database` reads no pool keys (`pool_size`, `echo`, ...) from its own
1178
+ section, so they are refused there; set them under `database.<name>`.
1179
+ A SQLAlchemy or ClickHouse sink section that sets both `url` and `database`
1180
+ is refused too, instead of one silently winning: a SQLAlchemy sink sets one
1181
+ or the other, and a ClickHouse sink takes its url from `database.<name>`, so
1182
+ it sets `database` only.
1183
+ Delta's `part_max_records` is removed and therefore refused: it was an alias
1184
+ of `writer_properties.max_row_group_size`, which is the key to set. Without
1185
+ `writer_properties` the row groups still hold at most 10 000 rows.
1186
+ `DeltaSinkConfig` has no `part_max_records` attribute.
1187
+ - **streaming:** `CompiledSingleSource` and `CompiledMultiSource` take a
1188
+ required `settings_key`, the config key their consumer settings were
1189
+ resolved from (`kafka.consumer` or `kafka.consumers.<ref>`);
1190
+ `KafkaSettings.consumer_key_for(ref)` names it.
1191
+ - **streaming:** `FromTopic`, `FromMultiTypeTopic`, `FromMongoCDC` and
1192
+ `IntoTopic` take no `shape`, `CompiledSingleSource`, `CompiledMultiSource`
1193
+ and `CompiledMongoCDCSource` have no `shape` field, and `StreamShape.MANY`
1194
+ is removed. The runtime never read a declared shape: every source emits one
1195
+ record per message, so a source declared `BATCH` was shape-checked as
1196
+ batches while its nodes received records, and an `IntoTopic` writes one
1197
+ record per message whatever it declared. Every flow now starts as a record
1198
+ stream, and an `IntoTopic` ends its path (shape `none`). Migration: drop
1199
+ `shape=`; to work on batches, use `CollectBatch` and, back to records,
1200
+ `ForEach`.
1201
+ - **streaming:** a batch reaching a `Drain` or a `Broadcast` fails compilation
1202
+ with `SHAPE_MISMATCH`, whatever the delivery. Under at-most-once delivery
1203
+ `CollectBatch → Drain` compiled and dropped the batch; under at-least-once
1204
+ the batch's offsets never completed. Under at-least-once a `Broadcast` with
1205
+ more than one route raised `TypeError` (`Expected Message, got list`) on a
1206
+ batch. Put a `ForEach` before the node.
952
1207
  - **streaming:** `BatchExpandStep.execute` returns one list of payloads per
953
1208
  message of its batch, in batch order, instead of one flat list. List `i`
954
1209
  holds what `messages[i]` expands into; each output takes that message's
@@ -975,9 +1230,11 @@
975
1230
  `CompileIssue` instead), `loom_message_type()` is gone, and
976
1231
  `CompilationIssue.prefixed()` is removed. Messages keep their text.
977
1232
  - **streaming:** a `Broadcast` followed by another node reports
978
- `BROADCAST_NOT_LAST` with component `broadcast`, at the top level, in a
979
- branch and in a Router branch. It used to report `TERMINAL_NOT_LAST` with
980
- component `Broadcast`.
1233
+ `BROADCAST_NOT_LAST` with component `broadcast`, at the top level and in a
1234
+ branch. It used to report `TERMINAL_NOT_LAST` with component `Broadcast`. In
1235
+ a Router branch a `Broadcast` reports `ROUTER_BRANCH_UNSAFE_NODE`, and one
1236
+ followed by another node also `TERMINAL_NOT_LAST` with component
1237
+ `router branch <label> > Broadcast`.
981
1238
  - **streaming:** a Router branch that ends in `IntoTopic`, `IntoTable` (any
982
1239
  `IntoSink`) or `Drain` hands the message to that terminal. The branch's
983
1240
  terminal was skipped: with a flow `output` the message went to the output
@@ -1060,11 +1317,71 @@
1060
1317
  - **streaming:** a sync `With(process=...)` hands on one message at a time, as
1061
1318
  `WithAsync` does. After a `CollectBatch` it handed on whole batches, so as
1062
1319
  the last node of a flow without `output` its messages never completed.
1320
+ - **streaming:** `IntoTable` with `Backend.SQLALCHEMY` binds each column with
1321
+ the type core compiles for the field instead of its own map:
1322
+ - a `StrEnum` or `IntEnum` field is written as its scalar (`String`,
1323
+ `Integer`) instead of as JSON;
1324
+ - a column type declared with `ColumnField` (on a `BaseModel`) or
1325
+ `Annotated[T, <ColumnType>]` is used;
1326
+ - a `Decimal`, plain `Enum` or `Literal` field without a declared column
1327
+ type is refused when the partition is built, with core's message, instead
1328
+ of being written as `Numeric()` (a `Decimal`) or as JSON. Declare it, e.g.
1329
+ `Annotated[Decimal, Numeric(precision=12, scale=2)]`, or
1330
+ `Annotated[Decimal, Numeric()]` for an unbounded `NUMERIC`.
1331
+ - **streaming:** `IntoTable` with `Backend.CLICKHOUSE` hands a `date` field to
1332
+ clickhouse-connect as a `date`, as core keeps it for a column, instead of as
1333
+ its ISO-8601 text. clickhouse-connect writes a `Date` column only from a
1334
+ `date` and refused the text ("unsupported operand type(s) for -: 'str' and
1335
+ 'datetime.date'"); a `String` column now refuses the `date` ("object of type
1336
+ 'datetime.date' has no len()"). A `dict` value is written as compact JSON
1337
+ text from `msgspec.json`, keys still sorted (`{"a":1}`, was `{"a": 1}`).
1063
1338
 
1064
1339
  ## 🐛 Fixes
1065
1340
 
1066
1341
  ### core
1067
1342
 
1343
+ - **core:** `RepositoryDynamoDB` reads, updates and deletes by a `UUID`
1344
+ primary key. `get_by_id`, `get_by`, `exists_by`, `update` and `delete`
1345
+ handed the raw key to boto3's `TypeSerializer`, which raised
1346
+ `TypeError: Unsupported type "<class 'uuid.UUID'>"`; `create` already stored
1347
+ the key as a string through `msgspec.to_builtins`. The key is now encoded
1348
+ with that same conversion, so it matches its stored form and round-trips.
1349
+ `update` keeps the key as stored instead of rewriting it from the argument.
1350
+ Attribute values are encoded as before.
1351
+ - **cache:** security: the repository cache keeps each caller's entries apart.
1352
+ The entity key (`get_by_id`, and the rows behind a cached page), the
1353
+ `list_paginated` index key, the `list_with_query` key and the key of a
1354
+ `@cache_query` read (`scope="entity"` and `scope="list"`) now carry the
1355
+ caller's cache scope, so a row, a page of ids, a first page with its next
1356
+ cursor or a custom read's result cached for one caller is no longer served
1357
+ to another that row-level security hides it from. The scope comes from the
1358
+ new, provisional `SupportsCacheScope.cache_scope()` (`""` for a repository
1359
+ without it): `RepositorySQLAlchemy` builds it from every setting the
1360
+ session-settings provider returns, so a policy reading a product setting
1361
+ such as `app.tenant_id` is kept apart too, while cursor tokens stay bound to
1362
+ the `loom.scope.*` settings only. Inside a caller-owned transaction (the
1363
+ unit of work a use case runs in, or a `@transactional` scope) every cached
1364
+ read goes straight to the repository, with no lookup and no store, and so
1365
+ does a call to a `@cache_query` method whose `session` parameter, passed by
1366
+ position or by name, is not `None`. This holds where the backend reports
1367
+ such a transaction, SQLAlchemy and Mongo with transactions; DynamoDB and
1368
+ Mongo with `transactions: false` keep caching, and a read-only use case run
1369
+ outside another unit of work opens none and keeps using the cache. Writes
1370
+ still evict every scope's entries: the scope is not part of the dependency
1371
+ tags, and a write bumps the same generation counters whatever its scope. The
1372
+ scope is read once per cache operation and read again before its writes,
1373
+ which are skipped if it changed. `CachedRepository` implements
1374
+ `cache_scope()` and `has_caller_scoped_session()` by forwarding the wrapped
1375
+ repository's, so a wrapper around it keys by the same scope and stays out of
1376
+ the same transactions, and refuses at construction, with a `RuntimeError`, a
1377
+ repository whose `session_manager` has session settings but which does not
1378
+ implement `cache_scope()`. The list filter, query and `@cache_query`
1379
+ arguments fingerprints in cache keys are now the full SHA-256 instead of its
1380
+ first 64 bits. `entity_key` and `list_index_key` take a required
1381
+ keyword-only `scope`, and the new `query_index_key` and `custom_query_key`
1382
+ build the `list_with_query` and `@cache_query` keys. Existing entity, list,
1383
+ query and `@cache_query` entries are no longer read after the upgrade and
1384
+ expire by their TTL.
1068
1385
  - **core:** one environment selector and deploy checks (ADR 0005). loom had
1069
1386
  two unconnected notions of environment (the logger's `dev`/`prod`, where an
1070
1387
  unknown value meant `dev`, and `FlowCtx.environment`) and nothing checked a
@@ -1115,10 +1432,25 @@
1115
1432
  startup. `parse_environment` validates a value naming an environment.
1116
1433
  - **core:** the SQLAlchemy query compiler converts a filter value, and each
1117
1434
  `in` item, as the repository converts a value it writes
1118
- (`loom.core.repository.sqlalchemy.values.to_column_value`, now shared by
1435
+ (`loom.core.model.convert.to_column_value`, now shared by
1119
1436
  both): an `Enum` member is bound as its value, a JSON column's value is
1120
1437
  reduced to builtins. A plain `Enum` member as the value of a filter on a
1121
1438
  string column failed to bind.
1439
+ - **core:** pagination cursors are signed and decoded strictly (ADR 0004).
1440
+ A cursor token was base64url JSON with no integrity, and a datetime key
1441
+ decoded without a time zone, so a client could forge a position and a
1442
+ consumer comparing it with aware datetimes raised `TypeError` (a 500). A
1443
+ token is now `base64url(payload).base64url(tag)`, the tag an HMAC-SHA256
1444
+ over a domain-separated input bound to the model, the normalised filters,
1445
+ the sort and the caller's scope, verified with `hmac.compare_digest` before
1446
+ the payload is parsed. A malformed, unsigned, forged or rebound token, a
1447
+ key signed by an unknown key id, a datetime key without a time zone, a key
1448
+ of an unknown type, the wrong number of keys or the wrong backend is
1449
+ `UnsupportedQuery` (`400 unsupported_query`), and the message never echoes
1450
+ the token. A naive datetime key, such as a `DateTime(tz=False)` column, is
1451
+ issued as UTC with an explicit offset and compared as naive UTC against
1452
+ that column, on SQLite and Postgres alike.
1453
+
1122
1454
  - **core:** a `BoundaryValidationError` no longer echoes the rejected value
1123
1455
  (#347). msgspec's `Invalid enum value 'x'` (an `Enum`, `IntEnum` or `Literal`
1124
1456
  field or dict key) and `Invalid value 'x'` (a tagged-union tag) become
@@ -1147,8 +1479,9 @@
1147
1479
  column only. The cursor now orders and compares on
1148
1480
  every key column after the sort keys and carries every key value in the
1149
1481
  token; offset pages and `list_paginated` order by every key column too.
1150
- Tokens of single-column keys are unchanged. A cached repository over such a
1151
- model keyed its entries by the first key column too, so a warm
1482
+ That fix leaves tokens of single-column keys as they were. A cached
1483
+ repository over such a model keyed its entries by the first key column
1484
+ too, so a warm
1152
1485
  `list_paginated` or first cursor page served the rows sharing a first key
1153
1486
  value as copies of one of them; it now caches and reloads every row by its
1154
1487
  full key, one `get_by_id` per missing row.
@@ -1184,6 +1517,12 @@
1184
1517
 
1185
1518
  ### etl
1186
1519
 
1520
+ - **etl:** the error for a missing destination table names only advice that
1521
+ works under the policy in force. Under `missing_table_policy='error'` it
1522
+ used to suggest `SchemaMode.OVERWRITE`, which that policy ignores; it now
1523
+ suggests `missing_table_policy='create'`, `'schema_mode'` with
1524
+ `SchemaMode.OVERWRITE`, or creating the table first.
1525
+
1187
1526
  - **etl:** `replace(allow_empty=False)` on Spark writes the rows it checked.
1188
1527
  The writer ran `DataFrame.isEmpty()` and then let the write compute the
1189
1528
  frame again, so a source that changed in between, or a nondeterministic
@@ -1364,6 +1703,32 @@
1364
1703
 
1365
1704
  ### streaming
1366
1705
 
1706
+ - **streaming:** `SINK_CANNOT_TRACK_COMMITS` and
1707
+ `INLINE_SINK_CANNOT_SKIP_COMMITS` point their `field` at the `delivery` of
1708
+ the consumer the source was bound through, `kafka.consumer.delivery` or
1709
+ `kafka.consumers.<ref>.delivery`, instead of `streaming.delivery`, which no
1710
+ config reads.
1711
+ - **streaming:** `ForEach` accepts the batch a `BatchStep` produces, so
1712
+ `CollectBatch → BatchStep → ForEach → IntoTopic` compiles; it failed with
1713
+ `shape mismatch: expected many but got batch before ForEach`. Under
1714
+ at-least-once delivery each offset completes once, after its write is
1715
+ flushed.
1716
+ - **streaming:** a batch reaching a node that takes records fails compilation
1717
+ with `SHAPE_MISMATCH`: `IntoTopic`, `IntoTable` (any `IntoSink`), `Fork`,
1718
+ `ExpandRoutes`, `CollectBatch` (it groups records), the flow `output`
1719
+ (component `flow.output`, field `output`)
1720
+ and a Broadcast route `output` (component `broadcast branch <n> > output`,
1721
+ field `output`). Such flows used to compile. `CollectBatch → BatchStep →
1722
+ IntoTopic` raised `'list' object has no attribute 'meta'` at runtime. Put a
1723
+ `ForEach` before the node. `Drain` and `Broadcast` are under Behaviour
1724
+ changes.
1725
+ - **streaming:** a `BatchExpandStep` subclass outputs records to the shape
1726
+ check. The compiler matched step output shapes by exact type, so every step
1727
+ subclass kept the incoming shape and a record step after a
1728
+ `BatchExpandStep` failed with `expected record but got batch`. The shape
1729
+ check reads a step's `input_shape` and `output_shape` from its class,
1730
+ except in a Router branch: there a `BatchStep` runs one record at a time,
1731
+ on a one-message batch, so it is record to record.
1367
1732
  - **streaming:** a `Broadcast` is validated as a `Broadcast`. The compiler
1368
1733
  treated it as a plain terminal, so the nodes of its branches were never
1369
1734
  shape-checked. A branch with a shape mismatch, such as a record step after
@@ -1433,6 +1798,49 @@
1433
1798
  offset at the step, also when the batch holds several messages of one
1434
1799
  offset that an earlier expanding node produced. The new return type is under
1435
1800
  Behaviour changes.
1801
+ - **streaming:** `IntoTable` with `Backend.SQLALCHEMY` binds a `bytes` field as
1802
+ `LargeBinary` (`bytea` on Postgres). It bound it as text, which Postgres
1803
+ refused for a `bytea` column ("column is of type bytea but expression is of
1804
+ type character varying"). IntoTable now takes each column's type from core's
1805
+ model introspection (`loom.core.backend.sqlalchemy.sa_table_for`), the type
1806
+ a compiled model declares, and builds each row with core's new
1807
+ `loom.core.repository.sqlalchemy.values.to_column_row`, which converts and
1808
+ checks values as the repository does when it writes them: a plain `Enum` as
1809
+ its value, a struct in a JSON column as a dict, an `UNSET` value left out so
1810
+ the column's database default applies, also when other rows of the batch
1811
+ set it, and a `time` whose UTC offset its column cannot take refused with
1812
+ `BoundaryValidationError` (`boundary_validation`) instead of being written
1813
+ without the offset. Relation and projection fields are no longer columns
1814
+ for any backend: the SQLAlchemy and Delta rows included them and failed on
1815
+ their `UNSET` value, and the ClickHouse insert named them. A `date` or
1816
+ `time` field is bound as `Date` or `Time`, as core infers it, so it is
1817
+ written into a Postgres `date` or `time` column; it was bound as `String`
1818
+ and Postgres refused it ("column is of type date but expression is of type
1819
+ character varying").
1820
+ - **streaming:** `IntoTable` with `Backend.DELTA` or `Backend.CLICKHOUSE`
1821
+ refuses an `UNSET` column value when the item is written, with
1822
+ `BoundaryValidationError` (`boundary_validation`) naming the field and the
1823
+ table. Delta failed later, at a mini-batch or flush, with pyarrow's
1824
+ `ArrowInvalid`, and ClickHouse passed the `UNSET` object to
1825
+ clickhouse-connect's `insert`. Neither can leave a column out for one row as
1826
+ `Backend.SQLALCHEMY` does.
1827
+ - **streaming:** `IntoTable` with `Backend.DELTA` or `Backend.CLICKHOUSE`
1828
+ converts each column value as `Backend.SQLALCHEMY` and core's repository
1829
+ do, with `loom.core.model.convert.to_column_value`: a plain `Enum` becomes
1830
+ its value and a nested `msgspec.Struct` or `LoomStruct` a dict, also inside a
1831
+ list or a dict, while `bytes`, `datetime`, `date`, `time`, `Decimal` and
1832
+ `UUID` are kept. Delta refused an `Enum` or a struct with pyarrow's
1833
+ `ArrowInvalid` ("did not recognize Python value type when inferring an
1834
+ Arrow data type"); a nested struct is now a Delta struct column, as a `dict`
1835
+ field already was, and keeps its `datetime` and `Decimal` types.
1836
+ clickhouse-connect refused an `Enum` or a struct ("object of type ... has no
1837
+ len()") and `json.dumps` a `dict` holding a `Decimal` or `datetime` ("Object
1838
+ of type Decimal is not JSON serializable"); an `Enum` is now inserted as its
1839
+ value and a struct or `dict` as JSON text from `msgspec.json`, a `datetime`
1840
+ inside it as ISO-8601 text and a `Decimal` as decimal text.
1841
+ `to_column_value` moved to `loom.core.model.convert` (under Behaviour
1842
+ changes), so the Delta and ClickHouse writers use it without SQLAlchemy
1843
+ installed.
1436
1844
 
1437
1845
  ### prefect
1438
1846
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: loom-kernel
3
- Version: 8.0.0
3
+ Version: 9.0.0
4
4
  Summary: Loom Python project
5
5
  License-File: LICENSE
6
6
  Classifier: Programming Language :: Python :: 3
@@ -457,6 +457,10 @@ app:
457
457
  title: My Store API
458
458
  version: 0.1.0
459
459
 
460
+ persistence:
461
+ cursors:
462
+ signing: ephemeral # development.yaml only; production.yaml configures keys
463
+
460
464
  database:
461
465
  url: ${oc.env:DATABASE_URL,sqlite+aiosqlite:///store.db}
462
466
 
@@ -333,6 +333,10 @@ app:
333
333
  title: My Store API
334
334
  version: 0.1.0
335
335
 
336
+ persistence:
337
+ cursors:
338
+ signing: ephemeral # development.yaml only; production.yaml configures keys
339
+
336
340
  database:
337
341
  url: ${oc.env:DATABASE_URL,sqlite+aiosqlite:///store.db}
338
342
 
@@ -115,9 +115,7 @@ class _UsecaseGrant:
115
115
  def _grant(key: str, use_case: type[Compilable]) -> _UsecaseGrant:
116
116
  execution = use_case.__execution_plan__
117
117
  if execution is None:
118
- raise AgentCompilationError(
119
- [f"use case '{key}' carries no compiled execution plan; it was never compiled"]
120
- )
118
+ raise AgentCompilationError([AgentErrorCode.USECASE_NOT_COMPILED.issue(key=key)])
121
119
  return _UsecaseGrant(
122
120
  tool_name=tool_name("usecase", key), key=key, use_case=use_case, execution=execution
123
121
  )
@@ -637,7 +635,11 @@ def _build(plan: AgentPlan, destination: _Destination, context: BuildContext) ->
637
635
  binding = _KINDS.get(type(capability))
638
636
  if binding is None:
639
637
  raise AgentCompilationError(
640
- [f"{context.agent}: capability kind '{capability.kind}' has no builder"]
638
+ [
639
+ AgentErrorCode.CAPABILITY_KIND_NO_BUILDER.issue(
640
+ component=context.agent, kind=capability.kind
641
+ )
642
+ ]
641
643
  )
642
644
  if binding.destination is destination:
643
645
  yield binding.builder(capability, context)