loom-kernel 2.21.0__tar.gz → 2.22.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.
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/PKG-INFO +1 -1
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/__init__.py +2 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_historify/_common.py +11 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_historify/_log.py +26 -1
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_historify/_ops.py +22 -1
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_historify/_transform.py +22 -3
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_write_policy.py +52 -42
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_historify.py +37 -12
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_writer.py +3 -36
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/_historify.py +38 -11
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/_writer.py +3 -37
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_validators_step.py +40 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/__init__.py +2 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/__init__.py +3 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_history/__init__.py +2 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_history/_builder.py +75 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_history/_errors.py +38 -8
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_history/_spec.py +6 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/.gitignore +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/CHANGELOG.md +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/LICENSE +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/README.md +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/pyproject.toml +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_concurrency.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_filters.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_paths.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_roles.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_startup.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_transport.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/_usecase.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/_binding.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/_handlers.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/_rpc.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/card.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/events.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/a2a/server.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/abc.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/bootstrap.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/_compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/_fingerprint.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/_plan.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_capabilities.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_conversation.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_feedable.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_hook.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_instructions.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_limits.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_model_role.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_output.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/compiler/phases/_state.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/declarative/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/declarative/_envelope.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/declarative/_schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/declarative/_v1.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/declarative/schemas/agent-spec-v1.schema.json +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/describe.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_a2a.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_capabilities.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_engine.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_escape.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_events.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_guards.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_history.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_instructions.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_limits.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_mcp.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_models.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_native.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_output.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_returns.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_schemas.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/_spec.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/extras/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/extras/a2a.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/extras/handlebars.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/extras/mcp.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/extras/skills.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/provider.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/_shared.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/anthropic.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/bedrock.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/gateway.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/openai.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/engines/pydantic_ai/providers/typesafe.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/_batch.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/_columns.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/_frames.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/_ledger.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/_runner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/etl/_validation.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/fastapi/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/fastapi/endpoints.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/fastapi/response.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/fastapi/streaming.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/inference.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/pricing.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/remote_auth.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_bounded.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_chain.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_conversation.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_grants.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_handle.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_health.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_hooks.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_lifecycle.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_limits.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/runtime/_mcp.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/validate/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/ai/validate/__main__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/auto.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/bootstrap.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/constants.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/runner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/celery/service.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/cli/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/cli/app.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/cli/schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/async_bridge.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/_decide.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/_grants.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/_roles.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/_scope.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/elevation.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/authz/product.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/backend/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/backend/core_model.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/backend/protocol.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/backend/scoped_ddl.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/backend/sqlalchemy.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/bootstrap/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/bootstrap/bootstrap.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/bootstrap/kernel.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/_batching.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/_single_flight.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/abc/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/abc/backend.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/abc/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/abc/dependency.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/calls.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/codec.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/decorators.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/dependency.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/gateway.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/keys.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/memory.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/repository.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/result_codec.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/serializer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/cache/wiring.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/command/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/command/adapter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/command/base.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/command/field.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/command/introspection.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/_boto3.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/_includes.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/_resolver_utils.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/binder.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/configurable.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/context.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/keys.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/loader.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/model.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/observability.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/resolver.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/secrets.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/config/ssm.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/contracts/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/contracts/manifest.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/di/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/di/container.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/di/scope.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/discovery/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/discovery/_utils.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/discovery/base.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/discovery/interfaces.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/discovery/manifest.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/discovery/modules.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/compilable.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/events.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/executor.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/metrics.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/plan.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/engine/post_commit.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/errors/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/errors/codes.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/errors/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/expr/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/expr/eval.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/expr/nodes.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/expr/refs.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/identity/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/identity/context.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/identity/identity.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/identity/issuer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/identity/wire.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/introspection/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/introspection/base.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/introspection/describe.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/job/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/job/callback.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/job/context.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/job/handle.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/job/job.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/job/service.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/locator.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/logger/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/logger/abc.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/logger/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/logger/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/logger/structlogger.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/_json_schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/_loom_type.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/base.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/convert.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/enums.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/field.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/introspection.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/partition.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/privilege.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/projection.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/relation.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/scoped.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/struct.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/timestamped.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/types.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/model/types_postgres.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/event.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/observer/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/observer/noop.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/observer/otel.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/observer/structlog.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/otel_ids.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/protocol.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/runtime.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/span.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/observability/topology.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/persistence/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/persistence/abc.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/persistence/none.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/persistence/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/plugins/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/plugins/entrypoints.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/plugins/optional.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/projection/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/projection/loaders.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/projection/runtime.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/cursor.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/query.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/query_compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/repo_for.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/repository.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/abc/session_scope.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/dynamodb/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/dynamodb/backend.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/dynamodb/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/dynamodb/repository.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/dynamodb/uow.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/backend.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/ids.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/query_compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/repository.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/uow.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mongo/values.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/mutation.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/registration.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/backend.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/integrity.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/loaders.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/migrations/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/migrations/env_template.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/migrations/hook.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/migrations/operations.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/migrations/runners.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/mixins.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/model.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/profile_loader.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/projection.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/cursor.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/filters.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/ordering.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/paths.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/query_compiler/subquery.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/repository.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/bootstrap.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/elevate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/guard/0001.sql +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/guard/0002.sql +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/guard/preflight.sql +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/guard_manifest.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/integrity.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/partitions.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/provider.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/sources.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/rls/verify.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/session_manager.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/session_settings.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/transactional.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/repository/sqlalchemy/uow.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/response/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/response/base.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/routing/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/routing/ref.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/routing/resolver.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/runner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/schema/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/schema/schema_mode.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/schema_names.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/abc/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/abc/contracts.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/abc/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/caller_bound.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/clickhouse/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/clickhouse/_client.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/clickhouse/executor.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/clickhouse/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/roles.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/sql/service.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/symbols.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/tracing/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/tracing/context.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/transaction.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/transport/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/transport/adapter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/uow/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/uow/abc.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/uow/context.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/_predicates.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/agent_markers.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/compute.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/constants.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/factory.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/field_ref.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/invoker.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/keys.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/markers.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/mcp_markers.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/outcome.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/rule.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/core/use_case/use_case.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/_uri.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_format_registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_historify/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_historify/_snapshot.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_merge.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_path_template.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_predicate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_schema_aligner/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_schema_aligner/_aligner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/_schema_aligner/_policy.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_dtype.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_file_writer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_frame.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_predicate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_reader.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_schema_aligner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/_streaming.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/polars/provider.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/_dtype.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/_reader.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/_schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/_schema_aligner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/backends/spark/provider.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_backends/_polars.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_backends/_spark.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_cleaners.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_options.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_paths.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_scope.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/checkpoint/_store.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_binding.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_filter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_plan.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_validators.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_validators_agents.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_validators_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/compiler/_validators_plan.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/_format.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/_read_options.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/_utils.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/_with_agent.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/_write_options.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/expr/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/expr/_params.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/expr/_predicate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/expr/_predicate_dialect.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/expr/_refs.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/_from.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/_from_clickhouse.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/_from_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/_from_dynamodb.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/_from_mongo.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/source/_specs.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_client.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_file.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_history/_enums.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_history/_report.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_into.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_schema_mode.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_table.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/declarative/target/_temp.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/executor/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/executor/_agents.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/executor/_dispatcher.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/executor/_executor.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/_registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_clickhouse.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_dynamodb.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_dynamodb_items.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_dynamodb_predicate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_mongo.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_mongo_batch.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_mongo_bson.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_mongo_predicate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/sources/_serialization.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/targets/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/io/targets/_clickhouse.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/_observer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/_records.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/sinks/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/sinks/_protocol.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/sinks/_table.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/lineage/sinks/_writer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/_builder.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/_ops.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/_protocol.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/_runner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/_step.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/backends/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/maintenance/backends/_delta_rs.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_generics.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_params.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_pipeline.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_process.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_sql.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_step.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_step_client.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/pipeline/_step_sql.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/_agents.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/_providers.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/_wiring.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/config_loader.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/core.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runner/filtering.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runtime/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runtime/_config_values.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/runtime/contracts.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/schema/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/schema/_contract.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/schema/_schema.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/storage/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/storage/_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/storage/_file_locator.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/storage/_locator.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/storage/routing.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/testing/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/testing/_result.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/testing/_runners.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/testing/_scenario.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/testing/_stubs.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/etl/testing/spark.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_async.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_ctx.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_flow_yaml.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_meta.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_placeholders.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/_summary.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/deploy/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/deploy/_discovery.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/deploy/_schedule.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/deploy/_yaml_etls.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/deploy/entrypoint.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_assemble.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_backfill.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_backfill_body.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_body.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_common.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_factory.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_hooks.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_maintenance.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_params.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_run_name.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_runtime.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_signature.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/flow/_stages.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/manifest/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/manifest/_model.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/manifest/_s3.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/manifest/_store.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/_event.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/_factory.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/_format.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/_port.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/_slack.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/notify/_sns.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/observer/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/observer/_flow.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/observer/_logging_bridge.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/observer/_manifest.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prefect/observer/_task_run.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prometheus/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prometheus/_instruments.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prometheus/adapter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prometheus/kafka.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prometheus/lifecycle.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/prometheus/middleware.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/py.typed +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/_body.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/adapter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/auth/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/auth/abc.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/auth/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/auth/jwt.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/auth/middleware.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/autocrud.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/constants.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/cors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/_exclusions.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/app.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/auto.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/health.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/openapi.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/response.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/router_runtime.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/fastapi/sql.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/middleware.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/model.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/rest/rest_adapter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_adapter.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_batch_spans.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_commit_tracker.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_dlq.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_error_boundary.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_operators.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_resource_manager.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_runtime_io.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/_sink_registry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/_shared.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/boundary.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/dispatcher.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/routing.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/scopes.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/shapes.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/steps.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/handlers/storage.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/bytewax/runner.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/_bindings.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/_compiler.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/_plan.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/phases/build_plan.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/compiler/phases/validate.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/core/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/core/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/core/_exceptions.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/core/_message.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/core/_tracing.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/core/_typing.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/graph/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/graph/_flow.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_codec.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_errors.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_key_resolver.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_message.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_record.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/_wire.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/client/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/client/_consumer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/client/_producer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/client/_protocol.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/client/_retry.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/message/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/message/_consumer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/message/_producer.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/kafka/message/_protocol.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/mongo/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/mongo/_bytewax_source.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/mongo/_config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/mongo/_event.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/mongo/_normalize.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_boundary.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_branches.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_broadcast.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_capabilities.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_decompose.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_expand_routes.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_expr_eval.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_fork.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_helpers.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_mongo.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_protocols.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_router.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_shape.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_sink.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_step.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_table/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_table/common.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_table/config.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/_with.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/nodes/refs.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/streaming/testing.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/__init__.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/agents.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/golden.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/http_harness.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/in_memory.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/repository_harness.py +0 -0
- {loom_kernel-2.21.0 → loom_kernel-2.22.0}/src/loom/testing/runner.py +0 -0
|
@@ -63,6 +63,7 @@ from loom.etl.declarative import (
|
|
|
63
63
|
FromTable,
|
|
64
64
|
FromTemp,
|
|
65
65
|
HistorifyDateCollisionError,
|
|
66
|
+
HistorifyDeleteMarkerError,
|
|
66
67
|
HistorifyInputMode,
|
|
67
68
|
HistorifyKeyConflictError,
|
|
68
69
|
HistorifyRepairReport,
|
|
@@ -203,6 +204,7 @@ __all__ = [
|
|
|
203
204
|
# SCD2 errors
|
|
204
205
|
"HistorifyKeyConflictError",
|
|
205
206
|
"HistorifyDateCollisionError",
|
|
207
|
+
"HistorifyDeleteMarkerError",
|
|
206
208
|
"HistorifyTemporalConflictError",
|
|
207
209
|
"EmptyReplaceError",
|
|
208
210
|
# intermediates
|
|
@@ -42,9 +42,20 @@ def resolve_track_cols(spec: HistorifySpec, frame_cols: list[str]) -> tuple[str,
|
|
|
42
42
|
if spec.track is not None:
|
|
43
43
|
return spec.track
|
|
44
44
|
excluded = set(spec.keys) | {spec.valid_from, spec.valid_to}
|
|
45
|
+
if spec.delete_marker is not None:
|
|
46
|
+
excluded.add(spec.delete_marker)
|
|
45
47
|
return tuple(c for c in frame_cols if c not in excluded)
|
|
46
48
|
|
|
47
49
|
|
|
50
|
+
def log_run_cols(spec: HistorifySpec) -> list[str]:
|
|
51
|
+
"""Return the columns whose change starts a new LOG run: ``track`` plus the delete marker.
|
|
52
|
+
|
|
53
|
+
Including the marker keeps a tombstone from collapsing into the run it closes.
|
|
54
|
+
"""
|
|
55
|
+
marker = [spec.delete_marker] if spec.delete_marker is not None else []
|
|
56
|
+
return [*(spec.track or ()), *marker]
|
|
57
|
+
|
|
58
|
+
|
|
48
59
|
def prev_period_value(eff_date: Any, spec: HistorifySpec) -> Any:
|
|
49
60
|
"""Return one unit before eff_date (one day or one microsecond)."""
|
|
50
61
|
delta = _DATE_DELTA if spec.date_type is HistoryDateType.DATE else _TS_DELTA
|
|
@@ -24,6 +24,9 @@ def apply_log(
|
|
|
24
24
|
history is rebuilt from the union of existing events and incoming events.
|
|
25
25
|
Incoming events win on same ``(entity key, effective date)`` conflicts, so
|
|
26
26
|
a correction with different tracked values replaces the stored event.
|
|
27
|
+
With ``delete_marker`` set, every stored closure without a successor is
|
|
28
|
+
replayed as a tombstone so the rebuild keeps it closed. Removing the marker
|
|
29
|
+
later would merge those closures back into open history.
|
|
27
30
|
"""
|
|
28
31
|
eff_col = str(spec.effective_date)
|
|
29
32
|
entity_keys = list(spec.keys)
|
|
@@ -36,6 +39,12 @@ def apply_log(
|
|
|
36
39
|
c for c in [spec.valid_to, spec.deleted_at] if c in ops.columns(existing_events)
|
|
37
40
|
]
|
|
38
41
|
existing_events = ops.drop(existing_events, boundary_cols)
|
|
42
|
+
marker = spec.delete_marker
|
|
43
|
+
if marker is not None:
|
|
44
|
+
stored_tombstones = ops.stamp_col(
|
|
45
|
+
ops.closure_events(affected_keys, spec), marker, True, None
|
|
46
|
+
)
|
|
47
|
+
existing_events = ops.union([existing_events, stored_tombstones])
|
|
39
48
|
|
|
40
49
|
all_events = ops.union(
|
|
41
50
|
[
|
|
@@ -46,5 +55,21 @@ def apply_log(
|
|
|
46
55
|
deduped = ops.dedup_priority(all_events, entity_keys + [eff_col], _ORIGIN_COL)
|
|
47
56
|
deduped = ops.drop(deduped, [_ORIGIN_COL])
|
|
48
57
|
|
|
49
|
-
rebuilt = ops
|
|
58
|
+
rebuilt = build_log_history(ops, deduped, spec)
|
|
50
59
|
return ops.union([untouched, rebuilt])
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def build_log_history(ops: HistorifyBackend[F], events: F, spec: HistorifySpec) -> F:
|
|
63
|
+
"""Build LOG history vectors from an event frame, resolving tombstones.
|
|
64
|
+
|
|
65
|
+
Tombstones take part in boundary computation as events of their own, so the
|
|
66
|
+
vector before each one closes a period earlier; the tombstone rows and the
|
|
67
|
+
``delete_marker`` column are then dropped, leaving the entity without an
|
|
68
|
+
open vector until its next regular event.
|
|
69
|
+
"""
|
|
70
|
+
marker = spec.delete_marker
|
|
71
|
+
if marker is None:
|
|
72
|
+
return ops.build_log_boundaries(events, spec)
|
|
73
|
+
flagged = ops.fill_null(events, marker, False)
|
|
74
|
+
history = ops.build_log_boundaries(flagged, spec)
|
|
75
|
+
return ops.drop(ops.filter_eq(history, marker, False, None), [marker])
|
|
@@ -14,6 +14,10 @@ class HistorifyBackend(Protocol[F]):
|
|
|
14
14
|
|
|
15
15
|
def columns(self, frame: F) -> list[str]: ...
|
|
16
16
|
|
|
17
|
+
def non_boolean_dtype(self, frame: F, col: str) -> str | None:
|
|
18
|
+
"""Return the dtype name of ``col`` when it is not boolean, else ``None``."""
|
|
19
|
+
...
|
|
20
|
+
|
|
17
21
|
def history_dtype(self, spec: HistorifySpec) -> Any:
|
|
18
22
|
"""Return the native dtype for valid_from / valid_to columns."""
|
|
19
23
|
...
|
|
@@ -40,6 +44,10 @@ class HistorifyBackend(Protocol[F]):
|
|
|
40
44
|
"""Add null column with given dtype."""
|
|
41
45
|
...
|
|
42
46
|
|
|
47
|
+
def fill_null(self, frame: F, col: str, value: Any) -> F:
|
|
48
|
+
"""Replace nulls in ``col`` with a literal value."""
|
|
49
|
+
...
|
|
50
|
+
|
|
43
51
|
def rename(self, frame: F, rename_map: dict[str, str]) -> F:
|
|
44
52
|
"""Rename columns according to mapping."""
|
|
45
53
|
...
|
|
@@ -77,11 +85,24 @@ class HistorifyBackend(Protocol[F]):
|
|
|
77
85
|
"""Compute valid_from / valid_to from sorted event frame (LOG mode)."""
|
|
78
86
|
...
|
|
79
87
|
|
|
88
|
+
def closure_events(self, history: F, spec: HistorifySpec) -> F:
|
|
89
|
+
"""Return one tombstone instant per stored vector closed without a successor.
|
|
90
|
+
|
|
91
|
+
LOG history has no gaps except those left by tombstones, so every gap is
|
|
92
|
+
read as a deletion: a vector has no successor when no later vector of its
|
|
93
|
+
entity starts within one period after its ``valid_to``. Each row carries
|
|
94
|
+
``keys`` and the effective-date column at that next period (the
|
|
95
|
+
tombstone's instant); the caller flags it with ``delete_marker``.
|
|
96
|
+
"""
|
|
97
|
+
...
|
|
98
|
+
|
|
80
99
|
def apply_delete_policy(self, deleted: F, spec: HistorifySpec, eff_date: Any) -> F: ...
|
|
81
100
|
|
|
82
101
|
def ensure_soft_delete_col(self, result: F, spec: HistorifySpec) -> F: ...
|
|
83
102
|
|
|
84
|
-
def
|
|
103
|
+
def duplicate_keys(self, frame: F, keys: list[str]) -> str | None:
|
|
104
|
+
"""Describe up to five ``keys`` combinations repeated in ``frame``, or ``None``."""
|
|
105
|
+
...
|
|
85
106
|
|
|
86
107
|
def assert_no_date_collisions(
|
|
87
108
|
self, frame: F, keys: list[str], eff_col: str, spec: HistorifySpec
|
|
@@ -9,11 +9,13 @@ from loom.etl.backends._historify._common import (
|
|
|
9
9
|
resolve_effective_date,
|
|
10
10
|
resolve_track_cols,
|
|
11
11
|
)
|
|
12
|
-
from loom.etl.backends._historify._log import apply_log
|
|
12
|
+
from loom.etl.backends._historify._log import apply_log, build_log_history
|
|
13
13
|
from loom.etl.backends._historify._ops import HistorifyBackend
|
|
14
14
|
from loom.etl.backends._historify._snapshot import apply_snapshot
|
|
15
15
|
from loom.etl.declarative.target._history import (
|
|
16
|
+
HistorifyDeleteMarkerError,
|
|
16
17
|
HistorifyInputMode,
|
|
18
|
+
HistorifyKeyConflictError,
|
|
17
19
|
HistorifyRepairReport,
|
|
18
20
|
HistorifySpec,
|
|
19
21
|
HistorifyTemporalConflictError,
|
|
@@ -44,6 +46,7 @@ def scd2_transform(
|
|
|
44
46
|
(SNAPSHOT mode with ``allow_temporal_rerun``), otherwise ``None``.
|
|
45
47
|
|
|
46
48
|
Raises:
|
|
49
|
+
HistorifyDeleteMarkerError: ``delete_marker`` column missing or not boolean.
|
|
47
50
|
HistorifyKeyConflictError: Duplicate entity state vectors.
|
|
48
51
|
HistorifyDateCollisionError: Same-date collisions in LOG mode.
|
|
49
52
|
HistorifyTemporalConflictError: Future-open records, re-weave off.
|
|
@@ -52,8 +55,13 @@ def scd2_transform(
|
|
|
52
55
|
join_key = list(spec.keys) + list(track_cols)
|
|
53
56
|
eff_date = resolve_effective_date(spec, params_instance)
|
|
54
57
|
|
|
58
|
+
if spec.delete_marker is not None:
|
|
59
|
+
_assert_delete_marker(ops, frame, spec.delete_marker)
|
|
55
60
|
is_log = spec.mode is HistorifyInputMode.LOG
|
|
56
|
-
|
|
61
|
+
unique_key = [*spec.keys, str(spec.effective_date)] if is_log else join_key
|
|
62
|
+
duplicates = ops.duplicate_keys(frame, unique_key)
|
|
63
|
+
if duplicates is not None:
|
|
64
|
+
raise HistorifyKeyConflictError(duplicates, mode=spec.mode)
|
|
57
65
|
if is_log:
|
|
58
66
|
ops.assert_no_date_collisions(frame, join_key, str(spec.effective_date), spec)
|
|
59
67
|
|
|
@@ -68,6 +76,17 @@ def scd2_transform(
|
|
|
68
76
|
return apply_log(ops, frame, existing, spec), None
|
|
69
77
|
|
|
70
78
|
|
|
79
|
+
def _assert_delete_marker(ops: HistorifyBackend[F], frame: F, marker: str) -> None:
|
|
80
|
+
"""Raise unless the incoming frame carries ``marker`` as a boolean column."""
|
|
81
|
+
if marker not in ops.columns(frame):
|
|
82
|
+
raise HistorifyDeleteMarkerError(marker, "is missing from the incoming frame")
|
|
83
|
+
dtype = ops.non_boolean_dtype(frame, marker)
|
|
84
|
+
if dtype is not None:
|
|
85
|
+
raise HistorifyDeleteMarkerError(
|
|
86
|
+
marker, f"has dtype {dtype}, not boolean; cast it to Boolean (null = regular event)"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
71
90
|
def _first_run(
|
|
72
91
|
ops: HistorifyBackend[F],
|
|
73
92
|
frame: F,
|
|
@@ -84,7 +103,7 @@ def _first_run(
|
|
|
84
103
|
dtype,
|
|
85
104
|
)
|
|
86
105
|
return ops.ensure_soft_delete_col(result, spec)
|
|
87
|
-
return ops
|
|
106
|
+
return build_log_history(ops, frame, spec)
|
|
88
107
|
|
|
89
108
|
|
|
90
109
|
def _rewind_report_if_enabled(
|
|
@@ -12,6 +12,7 @@ from dataclasses import dataclass
|
|
|
12
12
|
from typing import TYPE_CHECKING, Any, Generic, TypeVar
|
|
13
13
|
|
|
14
14
|
from loom.core.logger import get_logger
|
|
15
|
+
from loom.etl.backends._historify import HistorifyBackend, scd2_transform
|
|
15
16
|
from loom.etl.declarative.target import (
|
|
16
17
|
AppendSpec,
|
|
17
18
|
ClientSpec,
|
|
@@ -421,9 +422,11 @@ class _WritePolicy(TargetWriter, Generic[InputFrameT, WriteFrameT, PhysicalSchem
|
|
|
421
422
|
) -> HistorifyRepairReport | None:
|
|
422
423
|
"""SCD Type 2 historify policy: read existing, validate, transform, write.
|
|
423
424
|
|
|
424
|
-
Reads existing target data, validates creation rights when absent,
|
|
425
|
-
|
|
426
|
-
|
|
425
|
+
Reads existing target data, validates creation rights when absent, runs
|
|
426
|
+
:func:`~loom.etl.backends._historify.scd2_transform` with the engine's
|
|
427
|
+
:meth:`_historify_backend`, then writes the rebuilt history. The existing
|
|
428
|
+
frame is dropped before the write, so eager backends release the table
|
|
429
|
+
snapshot instead of holding it alongside the rebuilt history.
|
|
427
430
|
|
|
428
431
|
Args:
|
|
429
432
|
frame: Incoming input frame.
|
|
@@ -435,18 +438,59 @@ class _WritePolicy(TargetWriter, Generic[InputFrameT, WriteFrameT, PhysicalSchem
|
|
|
435
438
|
Returns:
|
|
436
439
|
A :class:`~loom.etl.HistorifyRepairReport` when a re-weave was
|
|
437
440
|
performed, or ``None`` for a normal forward-only run.
|
|
441
|
+
|
|
442
|
+
Raises:
|
|
443
|
+
HistorifyDeleteMarkerError: ``delete_marker`` missing or not boolean.
|
|
444
|
+
HistorifyKeyConflictError: Duplicate entity state vectors.
|
|
445
|
+
HistorifyDateCollisionError: Same-date ties in LOG mode.
|
|
446
|
+
HistorifyTemporalConflictError: Future-open records detected.
|
|
438
447
|
"""
|
|
439
448
|
existing = self._read_existing_data(target, frame, spec)
|
|
440
|
-
|
|
449
|
+
create = existing is None
|
|
450
|
+
if create:
|
|
441
451
|
_ensure_can_create_missing_table(
|
|
442
452
|
target=target,
|
|
443
453
|
schema_mode=spec.schema_mode,
|
|
444
454
|
missing_table_policy=self._missing_table_policy,
|
|
445
455
|
)
|
|
446
456
|
materialized = self._materialize_checked(frame, target, streaming=False)
|
|
447
|
-
|
|
448
|
-
materialized, existing,
|
|
457
|
+
result, report = scd2_transform(
|
|
458
|
+
self._historify_backend(), materialized, existing, spec, params_instance
|
|
449
459
|
)
|
|
460
|
+
del existing
|
|
461
|
+
if report is not None:
|
|
462
|
+
_log.warning(
|
|
463
|
+
"historify_temporal_rerun",
|
|
464
|
+
target=target.logical_ref.ref,
|
|
465
|
+
affected_key_count=len(report.affected_keys),
|
|
466
|
+
dates_requiring_rerun=[str(d) for d in report.dates_requiring_rerun],
|
|
467
|
+
warnings=list(report.warnings),
|
|
468
|
+
)
|
|
469
|
+
self._write_history(result, target, spec=spec, create=create)
|
|
470
|
+
return report
|
|
471
|
+
|
|
472
|
+
def _write_history(
|
|
473
|
+
self,
|
|
474
|
+
result: WriteFrameT,
|
|
475
|
+
target: ResolvedTarget,
|
|
476
|
+
*,
|
|
477
|
+
spec: HistorifySpec,
|
|
478
|
+
create: bool,
|
|
479
|
+
) -> None:
|
|
480
|
+
"""Write rebuilt history: create the table, or replace its scoped content."""
|
|
481
|
+
if create:
|
|
482
|
+
self._create(
|
|
483
|
+
result,
|
|
484
|
+
target,
|
|
485
|
+
schema_mode=spec.schema_mode,
|
|
486
|
+
partition_cols=spec.partition_scope or (),
|
|
487
|
+
)
|
|
488
|
+
elif spec.partition_scope:
|
|
489
|
+
self._replace_partitions(
|
|
490
|
+
result, target, partition_cols=spec.partition_scope, schema_mode=spec.schema_mode
|
|
491
|
+
)
|
|
492
|
+
else:
|
|
493
|
+
self._replace(result, target, schema_mode=spec.schema_mode)
|
|
450
494
|
|
|
451
495
|
# ========================================================================
|
|
452
496
|
# Audit Hook (overrideable — default is a no-op)
|
|
@@ -664,42 +708,8 @@ class _WritePolicy(TargetWriter, Generic[InputFrameT, WriteFrameT, PhysicalSchem
|
|
|
664
708
|
"""Matched-only merge into existing table — never inserts."""
|
|
665
709
|
|
|
666
710
|
@abstractmethod
|
|
667
|
-
def
|
|
668
|
-
|
|
669
|
-
frame: WriteFrameT,
|
|
670
|
-
existing: WriteFrameT | None,
|
|
671
|
-
target: ResolvedTarget,
|
|
672
|
-
*,
|
|
673
|
-
spec: HistorifySpec,
|
|
674
|
-
params_instance: Any,
|
|
675
|
-
) -> HistorifyRepairReport | None:
|
|
676
|
-
"""Apply SCD Type 2 transform and write result to target.
|
|
677
|
-
|
|
678
|
-
Called after :meth:`_read_existing_data` has already fetched the current
|
|
679
|
-
target state. The implementation must:
|
|
680
|
-
|
|
681
|
-
* Run the SCD2 algorithm (via :func:`~loom.etl.backends._historify.scd2_transform`).
|
|
682
|
-
* Write the result using the existing write hooks (``_create``,
|
|
683
|
-
``_replace``, or ``_replace_partitions``).
|
|
684
|
-
|
|
685
|
-
Args:
|
|
686
|
-
frame: Materialised incoming frame (write-ready).
|
|
687
|
-
existing: Current target frame, or ``None`` for first run.
|
|
688
|
-
target: Resolved Delta target.
|
|
689
|
-
spec: Compiled historify spec.
|
|
690
|
-
params_instance: Runtime params; used to resolve
|
|
691
|
-
``spec.effective_date`` when it is a
|
|
692
|
-
:class:`~loom.etl.ParamExpr`.
|
|
693
|
-
|
|
694
|
-
Returns:
|
|
695
|
-
A :class:`~loom.etl.HistorifyRepairReport` when re-weave was
|
|
696
|
-
triggered, or ``None`` for a normal forward-only run.
|
|
697
|
-
|
|
698
|
-
Raises:
|
|
699
|
-
HistorifyKeyConflictError: Duplicate entity state vectors.
|
|
700
|
-
HistorifyDateCollisionError: Same-date ties in LOG mode.
|
|
701
|
-
HistorifyTemporalConflictError: Future-open records detected.
|
|
702
|
-
"""
|
|
711
|
+
def _historify_backend(self) -> HistorifyBackend[WriteFrameT]:
|
|
712
|
+
"""Return the SCD2 primitives of this engine."""
|
|
703
713
|
|
|
704
714
|
@abstractmethod
|
|
705
715
|
def _write_file(
|
|
@@ -6,12 +6,11 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
import polars as pl
|
|
8
8
|
|
|
9
|
-
from loom.etl.backends._historify._common import prev_period_value
|
|
9
|
+
from loom.etl.backends._historify._common import log_run_cols, prev_period_value
|
|
10
10
|
from loom.etl.backends.polars._frame import FrameT
|
|
11
11
|
from loom.etl.declarative.target._history import (
|
|
12
12
|
DeletePolicy,
|
|
13
13
|
HistorifyDateCollisionError,
|
|
14
|
-
HistorifyKeyConflictError,
|
|
15
14
|
HistorifySpec,
|
|
16
15
|
HistoryDateType,
|
|
17
16
|
)
|
|
@@ -21,12 +20,22 @@ def _history_boundary_dtype(spec: HistorifySpec) -> type[pl.Date] | pl.Datetime:
|
|
|
21
20
|
return pl.Date if spec.date_type is HistoryDateType.DATE else pl.Datetime("us", "UTC")
|
|
22
21
|
|
|
23
22
|
|
|
23
|
+
def _period_offset(spec: HistorifySpec) -> pl.Expr:
|
|
24
|
+
if spec.date_type is HistoryDateType.DATE:
|
|
25
|
+
return pl.duration(days=1)
|
|
26
|
+
return pl.duration(microseconds=1)
|
|
27
|
+
|
|
28
|
+
|
|
24
29
|
class PolarsHistorifyBackend:
|
|
25
30
|
"""Polars implementation of HistorifyBackend."""
|
|
26
31
|
|
|
27
32
|
def columns(self, frame: pl.DataFrame) -> list[str]:
|
|
28
33
|
return list(frame.columns)
|
|
29
34
|
|
|
35
|
+
def non_boolean_dtype(self, frame: pl.DataFrame, col: str) -> str | None:
|
|
36
|
+
dtype = frame.collect_schema()[col]
|
|
37
|
+
return None if dtype == pl.Boolean else str(dtype)
|
|
38
|
+
|
|
30
39
|
def history_dtype(self, spec: HistorifySpec) -> type[pl.Date] | pl.Datetime:
|
|
31
40
|
return _history_boundary_dtype(spec)
|
|
32
41
|
|
|
@@ -74,6 +83,9 @@ class PolarsHistorifyBackend:
|
|
|
74
83
|
def null_col(self, frame: pl.DataFrame, name: str, dtype: Any) -> pl.DataFrame:
|
|
75
84
|
return frame.with_columns(pl.lit(None, dtype=dtype).alias(name))
|
|
76
85
|
|
|
86
|
+
def fill_null(self, frame: pl.DataFrame, col: str, value: Any) -> pl.DataFrame:
|
|
87
|
+
return frame.with_columns(pl.col(col).fill_null(value))
|
|
88
|
+
|
|
77
89
|
def rename(self, frame: pl.DataFrame, rename_map: dict[str, str]) -> pl.DataFrame:
|
|
78
90
|
return frame.rename(rename_map)
|
|
79
91
|
|
|
@@ -143,11 +155,7 @@ class PolarsHistorifyBackend:
|
|
|
143
155
|
eff_col = str(spec.effective_date)
|
|
144
156
|
entity_key = list(spec.keys)
|
|
145
157
|
boundary_dtype = _history_boundary_dtype(spec)
|
|
146
|
-
offset = (
|
|
147
|
-
pl.duration(days=1)
|
|
148
|
-
if spec.date_type is HistoryDateType.DATE
|
|
149
|
-
else pl.duration(microseconds=1)
|
|
150
|
-
)
|
|
158
|
+
offset = _period_offset(spec)
|
|
151
159
|
|
|
152
160
|
collapsed = self._collapse_same_track_runs(frame, spec, entity_key, eff_col)
|
|
153
161
|
sorted_events = collapsed.sort(entity_key + [eff_col])
|
|
@@ -171,6 +179,24 @@ class PolarsHistorifyBackend:
|
|
|
171
179
|
clamped_valid_to.cast(boundary_dtype).alias(spec.valid_to),
|
|
172
180
|
).drop(eff_col)
|
|
173
181
|
|
|
182
|
+
def closure_events(self, history: pl.DataFrame, spec: HistorifySpec) -> pl.DataFrame:
|
|
183
|
+
entity_key = list(spec.keys)
|
|
184
|
+
closed_at = pl.col(spec.valid_to) + _period_offset(spec)
|
|
185
|
+
next_from = pl.col("__next_from__")
|
|
186
|
+
# Nulls last: a zero-width vector sorts before the vector sharing its valid_from.
|
|
187
|
+
return (
|
|
188
|
+
history.sort([*entity_key, spec.valid_from, spec.valid_to], nulls_last=True)
|
|
189
|
+
.with_columns(pl.col(spec.valid_from).shift(-1).over(entity_key).alias("__next_from__"))
|
|
190
|
+
.filter(
|
|
191
|
+
pl.col(spec.valid_to).is_not_null()
|
|
192
|
+
& (next_from.is_null() | (next_from > closed_at))
|
|
193
|
+
)
|
|
194
|
+
.select(
|
|
195
|
+
*entity_key,
|
|
196
|
+
closed_at.cast(_history_boundary_dtype(spec)).alias(str(spec.effective_date)),
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
|
|
174
200
|
@staticmethod
|
|
175
201
|
def _collapse_same_track_runs(
|
|
176
202
|
frame: FrameT,
|
|
@@ -187,9 +213,8 @@ class PolarsHistorifyBackend:
|
|
|
187
213
|
if spec.track is None:
|
|
188
214
|
return frame
|
|
189
215
|
|
|
190
|
-
track = list(spec.track)
|
|
191
216
|
overwrite: list[str] = list(spec.overwrite or ())
|
|
192
|
-
track_struct = pl.struct(
|
|
217
|
+
track_struct = pl.struct(log_run_cols(spec))
|
|
193
218
|
|
|
194
219
|
runs = (
|
|
195
220
|
frame.sort(entity_key + [eff_col])
|
|
@@ -242,11 +267,11 @@ class PolarsHistorifyBackend:
|
|
|
242
267
|
boundary_dtype = _history_boundary_dtype(spec)
|
|
243
268
|
return result.with_columns(pl.lit(None, dtype=boundary_dtype).alias(spec.deleted_at))
|
|
244
269
|
|
|
245
|
-
def
|
|
270
|
+
def duplicate_keys(self, frame: pl.DataFrame, keys: list[str]) -> str | None:
|
|
246
271
|
if len(frame) == frame.select(keys).n_unique():
|
|
247
|
-
return
|
|
272
|
+
return None
|
|
248
273
|
dupes = frame.filter(frame.select(keys).is_duplicated()).select(keys).head(5)
|
|
249
|
-
|
|
274
|
+
return str(dupes.to_dicts())
|
|
250
275
|
|
|
251
276
|
def assert_no_date_collisions(
|
|
252
277
|
self,
|
|
@@ -10,7 +10,6 @@ from deltalake import CommitProperties, DeltaTable, WriterProperties, write_delt
|
|
|
10
10
|
from deltalake.table import TableMerger
|
|
11
11
|
|
|
12
12
|
from loom.core.logger import get_logger
|
|
13
|
-
from loom.etl.backends._historify._transform import scd2_transform
|
|
14
13
|
from loom.etl.backends._merge import (
|
|
15
14
|
SOURCE_ALIAS,
|
|
16
15
|
TARGET_ALIAS,
|
|
@@ -31,7 +30,7 @@ from loom.etl.backends.polars._schema import (
|
|
|
31
30
|
)
|
|
32
31
|
from loom.etl.declarative.target import SchemaMode
|
|
33
32
|
from loom.etl.declarative.target._file import FileSpec
|
|
34
|
-
from loom.etl.declarative.target._history import
|
|
33
|
+
from loom.etl.declarative.target._history import HistorifySpec
|
|
35
34
|
from loom.etl.declarative.target._table import (
|
|
36
35
|
AppendSpec,
|
|
37
36
|
ReplacePartitionsSpec,
|
|
@@ -620,40 +619,8 @@ class PolarsTargetWriter(_WritePolicy[pl.LazyFrame, pl.DataFrame, PolarsPhysical
|
|
|
620
619
|
except (TableNotFoundError, FileNotFoundError):
|
|
621
620
|
return None
|
|
622
621
|
|
|
623
|
-
def
|
|
624
|
-
|
|
625
|
-
frame: pl.DataFrame,
|
|
626
|
-
existing: pl.DataFrame | None,
|
|
627
|
-
target: ResolvedTarget,
|
|
628
|
-
*,
|
|
629
|
-
spec: HistorifySpec,
|
|
630
|
-
params_instance: Any,
|
|
631
|
-
) -> HistorifyRepairReport | None:
|
|
632
|
-
"""Run SCD Type 2 transform and write result via existing write hooks."""
|
|
633
|
-
result, report = scd2_transform(
|
|
634
|
-
PolarsHistorifyBackend(), frame, existing, spec, params_instance
|
|
635
|
-
)
|
|
636
|
-
if report is not None:
|
|
637
|
-
_log.warning(
|
|
638
|
-
"historify temporal rerun rewound future history",
|
|
639
|
-
affected_key_count=len(report.affected_keys),
|
|
640
|
-
dates_requiring_rerun=[str(d) for d in report.dates_requiring_rerun],
|
|
641
|
-
warnings=list(report.warnings),
|
|
642
|
-
)
|
|
643
|
-
if existing is None:
|
|
644
|
-
self._create(
|
|
645
|
-
result,
|
|
646
|
-
target,
|
|
647
|
-
schema_mode=spec.schema_mode,
|
|
648
|
-
partition_cols=spec.partition_scope or (),
|
|
649
|
-
)
|
|
650
|
-
elif spec.partition_scope:
|
|
651
|
-
self._replace_partitions(
|
|
652
|
-
result, target, partition_cols=spec.partition_scope, schema_mode=spec.schema_mode
|
|
653
|
-
)
|
|
654
|
-
else:
|
|
655
|
-
self._replace(result, target, schema_mode=spec.schema_mode)
|
|
656
|
-
return report
|
|
622
|
+
def _historify_backend(self) -> PolarsHistorifyBackend:
|
|
623
|
+
return PolarsHistorifyBackend()
|
|
657
624
|
|
|
658
625
|
def _write_file(
|
|
659
626
|
self,
|
|
@@ -4,15 +4,15 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
-
from pyspark.sql import DataFrame
|
|
7
|
+
from pyspark.sql import Column, DataFrame
|
|
8
8
|
from pyspark.sql import functions as F
|
|
9
|
+
from pyspark.sql.types import BooleanType
|
|
9
10
|
from pyspark.sql.window import Window
|
|
10
11
|
|
|
11
|
-
from loom.etl.backends._historify._common import prev_period_value
|
|
12
|
+
from loom.etl.backends._historify._common import log_run_cols, prev_period_value
|
|
12
13
|
from loom.etl.declarative.target._history import (
|
|
13
14
|
DeletePolicy,
|
|
14
15
|
HistorifyDateCollisionError,
|
|
15
|
-
HistorifyKeyConflictError,
|
|
16
16
|
HistorifySpec,
|
|
17
17
|
HistoryDateType,
|
|
18
18
|
)
|
|
@@ -22,12 +22,22 @@ def _history_boundary_dtype_sql(spec: HistorifySpec) -> str:
|
|
|
22
22
|
return "date" if spec.date_type is HistoryDateType.DATE else "timestamp"
|
|
23
23
|
|
|
24
24
|
|
|
25
|
+
def _next_period(col: Column, spec: HistorifySpec) -> Column:
|
|
26
|
+
if spec.date_type is HistoryDateType.DATE:
|
|
27
|
+
return F.date_add(col, 1)
|
|
28
|
+
return col + F.expr("INTERVAL 1 MICROSECOND")
|
|
29
|
+
|
|
30
|
+
|
|
25
31
|
class SparkHistorifyBackend:
|
|
26
32
|
"""Spark implementation of HistorifyBackend."""
|
|
27
33
|
|
|
28
34
|
def columns(self, frame: DataFrame) -> list[str]:
|
|
29
35
|
return list(frame.columns)
|
|
30
36
|
|
|
37
|
+
def non_boolean_dtype(self, frame: DataFrame, col: str) -> str | None:
|
|
38
|
+
dtype = frame.schema[col].dataType
|
|
39
|
+
return None if isinstance(dtype, BooleanType) else dtype.simpleString()
|
|
40
|
+
|
|
31
41
|
def history_dtype(self, spec: HistorifySpec) -> str:
|
|
32
42
|
return _history_boundary_dtype_sql(spec)
|
|
33
43
|
|
|
@@ -77,6 +87,9 @@ class SparkHistorifyBackend:
|
|
|
77
87
|
def null_col(self, frame: DataFrame, name: str, dtype: Any) -> DataFrame:
|
|
78
88
|
return frame.withColumn(name, F.lit(None).cast(dtype))
|
|
79
89
|
|
|
90
|
+
def fill_null(self, frame: DataFrame, col: str, value: Any) -> DataFrame:
|
|
91
|
+
return frame.withColumn(col, F.coalesce(F.col(col), F.lit(value)))
|
|
92
|
+
|
|
80
93
|
def rename(self, frame: DataFrame, rename_map: dict[str, str]) -> DataFrame:
|
|
81
94
|
result = frame
|
|
82
95
|
for old, new in rename_map.items():
|
|
@@ -199,6 +212,25 @@ class SparkHistorifyBackend:
|
|
|
199
212
|
.drop(eff_col)
|
|
200
213
|
)
|
|
201
214
|
|
|
215
|
+
def closure_events(self, history: DataFrame, spec: HistorifySpec) -> DataFrame:
|
|
216
|
+
entity_key = list(spec.keys)
|
|
217
|
+
# Nulls last: a zero-width vector sorts before the vector sharing its valid_from.
|
|
218
|
+
window = Window.partitionBy(entity_key).orderBy(
|
|
219
|
+
F.col(spec.valid_from), F.col(spec.valid_to).asc_nulls_last()
|
|
220
|
+
)
|
|
221
|
+
closed_at = _next_period(F.col(spec.valid_to), spec)
|
|
222
|
+
next_from = F.col("__next_from__")
|
|
223
|
+
return (
|
|
224
|
+
history.withColumn("__next_from__", F.lead(spec.valid_from).over(window))
|
|
225
|
+
.filter(
|
|
226
|
+
F.col(spec.valid_to).isNotNull() & (next_from.isNull() | (next_from > closed_at))
|
|
227
|
+
)
|
|
228
|
+
.select(
|
|
229
|
+
*entity_key,
|
|
230
|
+
closed_at.cast(_history_boundary_dtype_sql(spec)).alias(str(spec.effective_date)),
|
|
231
|
+
)
|
|
232
|
+
)
|
|
233
|
+
|
|
202
234
|
@staticmethod
|
|
203
235
|
def _collapse_same_track_runs(
|
|
204
236
|
frame: DataFrame,
|
|
@@ -215,9 +247,8 @@ class SparkHistorifyBackend:
|
|
|
215
247
|
if spec.track is None:
|
|
216
248
|
return frame
|
|
217
249
|
|
|
218
|
-
track = list(spec.track)
|
|
219
250
|
overwrite = list(spec.overwrite or ())
|
|
220
|
-
track_struct = F.struct(*[F.col(c) for c in
|
|
251
|
+
track_struct = F.struct(*[F.col(c) for c in log_run_cols(spec)])
|
|
221
252
|
|
|
222
253
|
order_w = Window.partitionBy(entity_key).orderBy(eff_col)
|
|
223
254
|
prev_struct = F.lag(track_struct).over(order_w)
|
|
@@ -264,15 +295,11 @@ class SparkHistorifyBackend:
|
|
|
264
295
|
boundary_dtype = _history_boundary_dtype_sql(spec)
|
|
265
296
|
return result.withColumn(spec.deleted_at, F.lit(None).cast(boundary_dtype))
|
|
266
297
|
|
|
267
|
-
def
|
|
268
|
-
n_rows = frame.count()
|
|
269
|
-
n_unique = frame.select(keys).distinct().count()
|
|
270
|
-
if n_rows == n_unique:
|
|
271
|
-
return
|
|
298
|
+
def duplicate_keys(self, frame: DataFrame, keys: list[str]) -> str | None:
|
|
272
299
|
dupes = (
|
|
273
300
|
frame.groupBy(keys).count().filter(F.col("count") > 1).drop("count").limit(5).collect()
|
|
274
301
|
)
|
|
275
|
-
|
|
302
|
+
return str([row.asDict() for row in dupes]) if dupes else None
|
|
276
303
|
|
|
277
304
|
def assert_no_date_collisions(
|
|
278
305
|
self,
|
|
@@ -15,7 +15,6 @@ from pyspark.sql.column import Column
|
|
|
15
15
|
from pyspark.storagelevel import StorageLevel
|
|
16
16
|
|
|
17
17
|
from loom.etl.backends._format_registry import resolve_format_handler, write_options_or_default
|
|
18
|
-
from loom.etl.backends._historify._transform import scd2_transform
|
|
19
18
|
from loom.etl.backends._merge import (
|
|
20
19
|
SOURCE_ALIAS,
|
|
21
20
|
TARGET_ALIAS,
|
|
@@ -38,7 +37,7 @@ from loom.etl.declarative._write_options import (
|
|
|
38
37
|
)
|
|
39
38
|
from loom.etl.declarative.target import SchemaMode
|
|
40
39
|
from loom.etl.declarative.target._file import FileSpec
|
|
41
|
-
from loom.etl.declarative.target._history import
|
|
40
|
+
from loom.etl.declarative.target._history import HistorifySpec
|
|
42
41
|
from loom.etl.declarative.target._table import AppendSpec, UpdateSpec, UpsertSpec
|
|
43
42
|
from loom.etl.lineage._records import LineageRecord, get_lineage_schema
|
|
44
43
|
from loom.etl.storage._config import MissingTablePolicy
|
|
@@ -404,41 +403,8 @@ class SparkTargetWriter(_WritePolicy[DataFrame, DataFrame, SparkPhysicalSchema])
|
|
|
404
403
|
return self._spark.read.format("delta").load(target.location.uri)
|
|
405
404
|
return None
|
|
406
405
|
|
|
407
|
-
def
|
|
408
|
-
|
|
409
|
-
frame: DataFrame,
|
|
410
|
-
existing: DataFrame | None,
|
|
411
|
-
target: ResolvedTarget,
|
|
412
|
-
*,
|
|
413
|
-
spec: HistorifySpec,
|
|
414
|
-
params_instance: Any,
|
|
415
|
-
) -> HistorifyRepairReport | None:
|
|
416
|
-
"""Run SCD Type 2 transform and write result via existing write hooks."""
|
|
417
|
-
result, report = scd2_transform(
|
|
418
|
-
SparkHistorifyBackend(), frame, existing, spec, params_instance
|
|
419
|
-
)
|
|
420
|
-
if report is not None:
|
|
421
|
-
_log.warning(
|
|
422
|
-
"historify temporal rerun rewound future history: "
|
|
423
|
-
"affected_key_count=%d dates_requiring_rerun=%s warnings=%s",
|
|
424
|
-
len(report.affected_keys),
|
|
425
|
-
[str(d) for d in report.dates_requiring_rerun],
|
|
426
|
-
list(report.warnings),
|
|
427
|
-
)
|
|
428
|
-
if existing is None:
|
|
429
|
-
self._create(
|
|
430
|
-
result,
|
|
431
|
-
target,
|
|
432
|
-
schema_mode=spec.schema_mode,
|
|
433
|
-
partition_cols=spec.partition_scope or (),
|
|
434
|
-
)
|
|
435
|
-
elif spec.partition_scope:
|
|
436
|
-
self._replace_partitions(
|
|
437
|
-
result, target, partition_cols=spec.partition_scope, schema_mode=spec.schema_mode
|
|
438
|
-
)
|
|
439
|
-
else:
|
|
440
|
-
self._replace(result, target, schema_mode=spec.schema_mode)
|
|
441
|
-
return report
|
|
406
|
+
def _historify_backend(self) -> SparkHistorifyBackend:
|
|
407
|
+
return SparkHistorifyBackend()
|
|
442
408
|
|
|
443
409
|
def _write_file(
|
|
444
410
|
self,
|