medallantic 0.27.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.
- medallantic-0.27.0/.gitignore +35 -0
- medallantic-0.27.0/PKG-INFO +133 -0
- medallantic-0.27.0/README.md +110 -0
- medallantic-0.27.0/ROADMAP.md +372 -0
- medallantic-0.27.0/docs/README.md +44 -0
- medallantic-0.27.0/docs/architecture.md +82 -0
- medallantic-0.27.0/docs/compatibility.md +71 -0
- medallantic-0.27.0/docs/concepts.md +77 -0
- medallantic-0.27.0/docs/development.md +61 -0
- medallantic-0.27.0/docs/getting-started.md +131 -0
- medallantic-0.27.0/docs/runtime-and-reports.md +114 -0
- medallantic-0.27.0/docs/sparkforge-migration.md +108 -0
- medallantic-0.27.0/pyproject.toml +47 -0
- medallantic-0.27.0/src/medallantic/__init__.py +61 -0
- medallantic-0.27.0/src/medallantic/adapt.py +572 -0
- medallantic-0.27.0/src/medallantic/compat.py +155 -0
- medallantic-0.27.0/src/medallantic/ir.py +197 -0
- medallantic-0.27.0/src/medallantic/py.typed +0 -0
- medallantic-0.27.0/src/medallantic/reports.py +341 -0
- medallantic-0.27.0/src/medallantic/runtime_map.py +104 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.eggs/
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
site/
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
.env
|
|
13
|
+
|
|
14
|
+
# Tools
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.ruff_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
htmlcov/
|
|
20
|
+
# macOS
|
|
21
|
+
.DS_Store
|
|
22
|
+
**/.DS_Store
|
|
23
|
+
._*
|
|
24
|
+
**/._*
|
|
25
|
+
|
|
26
|
+
examples/_file_storage_out/
|
|
27
|
+
examples/_generated_*.py
|
|
28
|
+
tmp_cli_contracts/
|
|
29
|
+
tmp_/
|
|
30
|
+
|
|
31
|
+
# Local durable workspace (reports, artifacts, schema history)
|
|
32
|
+
.etlantic/
|
|
33
|
+
|
|
34
|
+
# Local authoring artifacts (not part of the repo)
|
|
35
|
+
pipeline.definition.json
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: medallantic
|
|
3
|
+
Version: 0.27.0
|
|
4
|
+
Summary: Engine-agnostic medallion pipelines built on ETLantic.
|
|
5
|
+
Project-URL: Homepage, https://github.com/eddiethedean/etlantic
|
|
6
|
+
Project-URL: Documentation, https://github.com/eddiethedean/etlantic/tree/main/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/eddiethedean/etlantic
|
|
8
|
+
Project-URL: Issues, https://github.com/eddiethedean/etlantic/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/eddiethedean/etlantic/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Odo Matthews <odosmatthews@gmail.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: etlantic<0.28,>=0.27.0
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Medallantic
|
|
25
|
+
|
|
26
|
+
Engine-agnostic medallion pipelines built on ETLantic.
|
|
27
|
+
|
|
28
|
+
Medallantic owns bronze/silver/gold authoring and conventions. ETLantic owns
|
|
29
|
+
the portable contracts, graph, validation, planning, execution lifecycle, and
|
|
30
|
+
plugin coordination underneath it. **ETLantic core never gains medallion
|
|
31
|
+
types.**
|
|
32
|
+
|
|
33
|
+
The current release is the renamed SparkForge migration adapter. It maps
|
|
34
|
+
SparkForge IR onto ordinary ETLantic `Extract` / `Step` / `Load`, `Profile`,
|
|
35
|
+
`RunSelection` / `RunIntent`, and `PipelineRunReport` surfaces. A native
|
|
36
|
+
engine-agnostic builder and live Spark/SQL parity are planned; see the
|
|
37
|
+
[roadmap](ROADMAP.md).
|
|
38
|
+
|
|
39
|
+
Documentation:
|
|
40
|
+
|
|
41
|
+
- [Documentation index](docs/README.md)
|
|
42
|
+
- [Getting started](docs/getting-started.md)
|
|
43
|
+
- [SparkForge migration](docs/sparkforge-migration.md)
|
|
44
|
+
- [Compatibility](docs/compatibility.md)
|
|
45
|
+
- [Architecture](docs/architecture.md)
|
|
46
|
+
|
|
47
|
+
## Install
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install 'etlantic==0.27.0' 'medallantic==0.27.0'
|
|
51
|
+
# or
|
|
52
|
+
pip install 'etlantic[medallantic]'
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The shipped adapter is **IR-only**: feed `SparkForgePipelineSpec` (JSON/YAML
|
|
56
|
+
fixtures or hand-built dataclasses). There is **no** live
|
|
57
|
+
`pipeline_builder` / SparkForge Python API bridge in this release.
|
|
58
|
+
|
|
59
|
+
The adapter is registered explicitly by importing `medallantic` and
|
|
60
|
+
calling its conversion helpers. The adapted result supplies an ordinary
|
|
61
|
+
ETLantic pipeline and profile; select execution plugins such as
|
|
62
|
+
`Profile.spark_engine="pyspark"` separately. Production profiles must
|
|
63
|
+
allowlist every trusted execution plugin.
|
|
64
|
+
|
|
65
|
+
## Quick start (IR → Pipeline)
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from medallantic import (
|
|
69
|
+
SparkForgePipelineSpec,
|
|
70
|
+
SparkForgeStepSpec,
|
|
71
|
+
StepKind,
|
|
72
|
+
LayerKind,
|
|
73
|
+
adapt_pipeline,
|
|
74
|
+
debug_request_from_sparkforge,
|
|
75
|
+
enrich_plan,
|
|
76
|
+
)
|
|
77
|
+
from etlantic.plan import plan_pipeline
|
|
78
|
+
|
|
79
|
+
spec = SparkForgePipelineSpec(
|
|
80
|
+
name="ecommerce",
|
|
81
|
+
schema="demo",
|
|
82
|
+
steps=(
|
|
83
|
+
SparkForgeStepSpec(
|
|
84
|
+
name="orders",
|
|
85
|
+
kind=StepKind.BRONZE_RULES,
|
|
86
|
+
layer=LayerKind.BRONZE,
|
|
87
|
+
table_name="bronze_orders",
|
|
88
|
+
),
|
|
89
|
+
SparkForgeStepSpec(
|
|
90
|
+
name="clean_orders",
|
|
91
|
+
kind=StepKind.SILVER_TRANSFORM,
|
|
92
|
+
layer=LayerKind.SILVER,
|
|
93
|
+
source="orders",
|
|
94
|
+
table_name="silver_orders",
|
|
95
|
+
write_mode="overwrite",
|
|
96
|
+
),
|
|
97
|
+
),
|
|
98
|
+
)
|
|
99
|
+
adapted = adapt_pipeline(spec)
|
|
100
|
+
adapted.pipeline_cls.validate(profile=adapted.profile)
|
|
101
|
+
plan = enrich_plan(
|
|
102
|
+
plan_pipeline(adapted.pipeline_cls, profile=adapted.profile),
|
|
103
|
+
adapted,
|
|
104
|
+
)
|
|
105
|
+
request = debug_request_from_sparkforge(mode="incremental", skip_writes=True)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Delivery direction
|
|
109
|
+
|
|
110
|
+
1. **Plan-only** — generate/inspect ETLantic plans from SparkForge IR
|
|
111
|
+
(`strict_delta=False` to warn instead of fail when Delta caps are unknown)
|
|
112
|
+
2. **Dual reporting** — `adapt_run_result` → `PipelineRunReport`
|
|
113
|
+
3. **ETLantic planning** — selections/intents via `debug_request_from_sparkforge`
|
|
114
|
+
4. **Plugin execution** — `Profile.spark_engine="pyspark"` / SQL plugins
|
|
115
|
+
5. **Native facade** — Medallantic owns medallion authoring and retires the
|
|
116
|
+
duplicated legacy engine-specific builders
|
|
117
|
+
|
|
118
|
+
`transform_ref` / bronze `rules` emit `PMSF411` warnings: the adapter builds
|
|
119
|
+
passthrough transforms for planning parity; it does not execute SparkForge
|
|
120
|
+
callables. Write intents (including MERGE) are attached via `enrich_plan` for
|
|
121
|
+
orchestration; the local runtime still gates materialization with
|
|
122
|
+
`RunRequest.no_write`.
|
|
123
|
+
|
|
124
|
+
See `docs/11_DEVELOPMENT/MIGRATION_0_9_TO_0_10.md`.
|
|
125
|
+
|
|
126
|
+
## Boundary
|
|
127
|
+
|
|
128
|
+
| Concern | Owner |
|
|
129
|
+
|---|---|
|
|
130
|
+
| bronze / silver / gold APIs | Medallantic |
|
|
131
|
+
| portable graph, plan, reports | ETLantic |
|
|
132
|
+
| legacy mapping + parity fixtures | Medallantic migration layer |
|
|
133
|
+
| physical execution | ETLantic engine and storage plugins |
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Medallantic
|
|
2
|
+
|
|
3
|
+
Engine-agnostic medallion pipelines built on ETLantic.
|
|
4
|
+
|
|
5
|
+
Medallantic owns bronze/silver/gold authoring and conventions. ETLantic owns
|
|
6
|
+
the portable contracts, graph, validation, planning, execution lifecycle, and
|
|
7
|
+
plugin coordination underneath it. **ETLantic core never gains medallion
|
|
8
|
+
types.**
|
|
9
|
+
|
|
10
|
+
The current release is the renamed SparkForge migration adapter. It maps
|
|
11
|
+
SparkForge IR onto ordinary ETLantic `Extract` / `Step` / `Load`, `Profile`,
|
|
12
|
+
`RunSelection` / `RunIntent`, and `PipelineRunReport` surfaces. A native
|
|
13
|
+
engine-agnostic builder and live Spark/SQL parity are planned; see the
|
|
14
|
+
[roadmap](ROADMAP.md).
|
|
15
|
+
|
|
16
|
+
Documentation:
|
|
17
|
+
|
|
18
|
+
- [Documentation index](docs/README.md)
|
|
19
|
+
- [Getting started](docs/getting-started.md)
|
|
20
|
+
- [SparkForge migration](docs/sparkforge-migration.md)
|
|
21
|
+
- [Compatibility](docs/compatibility.md)
|
|
22
|
+
- [Architecture](docs/architecture.md)
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install 'etlantic==0.27.0' 'medallantic==0.27.0'
|
|
28
|
+
# or
|
|
29
|
+
pip install 'etlantic[medallantic]'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The shipped adapter is **IR-only**: feed `SparkForgePipelineSpec` (JSON/YAML
|
|
33
|
+
fixtures or hand-built dataclasses). There is **no** live
|
|
34
|
+
`pipeline_builder` / SparkForge Python API bridge in this release.
|
|
35
|
+
|
|
36
|
+
The adapter is registered explicitly by importing `medallantic` and
|
|
37
|
+
calling its conversion helpers. The adapted result supplies an ordinary
|
|
38
|
+
ETLantic pipeline and profile; select execution plugins such as
|
|
39
|
+
`Profile.spark_engine="pyspark"` separately. Production profiles must
|
|
40
|
+
allowlist every trusted execution plugin.
|
|
41
|
+
|
|
42
|
+
## Quick start (IR → Pipeline)
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from medallantic import (
|
|
46
|
+
SparkForgePipelineSpec,
|
|
47
|
+
SparkForgeStepSpec,
|
|
48
|
+
StepKind,
|
|
49
|
+
LayerKind,
|
|
50
|
+
adapt_pipeline,
|
|
51
|
+
debug_request_from_sparkforge,
|
|
52
|
+
enrich_plan,
|
|
53
|
+
)
|
|
54
|
+
from etlantic.plan import plan_pipeline
|
|
55
|
+
|
|
56
|
+
spec = SparkForgePipelineSpec(
|
|
57
|
+
name="ecommerce",
|
|
58
|
+
schema="demo",
|
|
59
|
+
steps=(
|
|
60
|
+
SparkForgeStepSpec(
|
|
61
|
+
name="orders",
|
|
62
|
+
kind=StepKind.BRONZE_RULES,
|
|
63
|
+
layer=LayerKind.BRONZE,
|
|
64
|
+
table_name="bronze_orders",
|
|
65
|
+
),
|
|
66
|
+
SparkForgeStepSpec(
|
|
67
|
+
name="clean_orders",
|
|
68
|
+
kind=StepKind.SILVER_TRANSFORM,
|
|
69
|
+
layer=LayerKind.SILVER,
|
|
70
|
+
source="orders",
|
|
71
|
+
table_name="silver_orders",
|
|
72
|
+
write_mode="overwrite",
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
adapted = adapt_pipeline(spec)
|
|
77
|
+
adapted.pipeline_cls.validate(profile=adapted.profile)
|
|
78
|
+
plan = enrich_plan(
|
|
79
|
+
plan_pipeline(adapted.pipeline_cls, profile=adapted.profile),
|
|
80
|
+
adapted,
|
|
81
|
+
)
|
|
82
|
+
request = debug_request_from_sparkforge(mode="incremental", skip_writes=True)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Delivery direction
|
|
86
|
+
|
|
87
|
+
1. **Plan-only** — generate/inspect ETLantic plans from SparkForge IR
|
|
88
|
+
(`strict_delta=False` to warn instead of fail when Delta caps are unknown)
|
|
89
|
+
2. **Dual reporting** — `adapt_run_result` → `PipelineRunReport`
|
|
90
|
+
3. **ETLantic planning** — selections/intents via `debug_request_from_sparkforge`
|
|
91
|
+
4. **Plugin execution** — `Profile.spark_engine="pyspark"` / SQL plugins
|
|
92
|
+
5. **Native facade** — Medallantic owns medallion authoring and retires the
|
|
93
|
+
duplicated legacy engine-specific builders
|
|
94
|
+
|
|
95
|
+
`transform_ref` / bronze `rules` emit `PMSF411` warnings: the adapter builds
|
|
96
|
+
passthrough transforms for planning parity; it does not execute SparkForge
|
|
97
|
+
callables. Write intents (including MERGE) are attached via `enrich_plan` for
|
|
98
|
+
orchestration; the local runtime still gates materialization with
|
|
99
|
+
`RunRequest.no_write`.
|
|
100
|
+
|
|
101
|
+
See `docs/11_DEVELOPMENT/MIGRATION_0_9_TO_0_10.md`.
|
|
102
|
+
|
|
103
|
+
## Boundary
|
|
104
|
+
|
|
105
|
+
| Concern | Owner |
|
|
106
|
+
|---|---|
|
|
107
|
+
| bronze / silver / gold APIs | Medallantic |
|
|
108
|
+
| portable graph, plan, reports | ETLantic |
|
|
109
|
+
| legacy mapping + parity fixtures | Medallantic migration layer |
|
|
110
|
+
| physical execution | ETLantic engine and storage plugins |
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# Medallantic Roadmap
|
|
2
|
+
|
|
3
|
+
Medallantic is the engine-agnostic medallion pipeline facade built on
|
|
4
|
+
[ETLantic](https://github.com/eddiethedean/etlantic). It will provide one
|
|
5
|
+
bronze/silver/gold authoring model across local Python, Polars, Pandas, SQL,
|
|
6
|
+
and PySpark while delegating contracts, graph validation, deterministic
|
|
7
|
+
planning, execution coordination, reports, and plugin trust to ETLantic.
|
|
8
|
+
|
|
9
|
+
This roadmap defines “full parity” against both legacy SparkForge surfaces:
|
|
10
|
+
|
|
11
|
+
- `pipeline_builder` (PySpark/Sparkless)
|
|
12
|
+
- `sql_pipeline_builder` (SQLAlchemy/Moltres)
|
|
13
|
+
|
|
14
|
+
Parity means preserving supported user outcomes and semantics, not copying
|
|
15
|
+
the two legacy implementations or exposing backend objects in the portable
|
|
16
|
+
model.
|
|
17
|
+
|
|
18
|
+
## Product boundary
|
|
19
|
+
|
|
20
|
+
Medallantic owns:
|
|
21
|
+
|
|
22
|
+
- bronze, silver, and gold vocabulary and conventions
|
|
23
|
+
- the fluent medallion builder and declarative configuration
|
|
24
|
+
- layer-aware dependency defaults and quality policies
|
|
25
|
+
- migration from both SparkForge builders
|
|
26
|
+
- medallion-oriented run results, explanations, and documentation
|
|
27
|
+
|
|
28
|
+
ETLantic owns:
|
|
29
|
+
|
|
30
|
+
- typed pipeline contracts and the logical graph
|
|
31
|
+
- validation, diagnostics, plans, run requests, and normalized reports
|
|
32
|
+
- artifact, state, lineage, security, and plugin coordination
|
|
33
|
+
- backend-neutral execution and compilation contracts
|
|
34
|
+
|
|
35
|
+
Execution plugins own:
|
|
36
|
+
|
|
37
|
+
- dataframe and relational execution
|
|
38
|
+
- SQL dialect and database transaction behavior
|
|
39
|
+
- Spark session and cluster behavior
|
|
40
|
+
- Delta Lake and other storage-specific operations
|
|
41
|
+
- engine-native expression compilation and optimization
|
|
42
|
+
|
|
43
|
+
Medallantic will not recreate separate Spark and SQL builder hierarchies.
|
|
44
|
+
Unsupported behavior must fail with a capability diagnostic; it must never
|
|
45
|
+
silently change semantics or select another engine.
|
|
46
|
+
|
|
47
|
+
### Promoting capabilities into ETLantic
|
|
48
|
+
|
|
49
|
+
ETLantic may be extended whenever Medallantic reveals a capability that is
|
|
50
|
+
useful beyond medallion architecture. Promotion is expected for portable
|
|
51
|
+
concepts such as typed multi-output steps, state transitions, materialization
|
|
52
|
+
policies, transaction boundaries, plan diagnostics, or plugin capability
|
|
53
|
+
negotiation.
|
|
54
|
+
|
|
55
|
+
A capability belongs in ETLantic when it:
|
|
56
|
+
|
|
57
|
+
- has the same semantics outside bronze/silver/gold pipelines,
|
|
58
|
+
- must be shared by more than one facade or execution plugin,
|
|
59
|
+
- affects portable validation, planning, execution, reports, or security, and
|
|
60
|
+
- can be named without medallion or engine-specific terminology.
|
|
61
|
+
|
|
62
|
+
Layer names, layer defaults, medallion dependency conventions, and migration
|
|
63
|
+
compatibility remain in Medallantic. Each milestone may therefore include
|
|
64
|
+
prerequisite Etlantic work; those prerequisites should land with their own
|
|
65
|
+
core tests before Medallantic consumes them.
|
|
66
|
+
|
|
67
|
+
## Current baseline
|
|
68
|
+
|
|
69
|
+
The renamed package starts with the former `etlantic-sparkforge` IR adapter.
|
|
70
|
+
It currently provides:
|
|
71
|
+
|
|
72
|
+
- SparkForge medallion IR parsing
|
|
73
|
+
- bronze/silver/gold-to-ETLantic graph adaptation
|
|
74
|
+
- dependency validation and cycle rejection
|
|
75
|
+
- layer quality-threshold mapping
|
|
76
|
+
- write-intent and retry-policy mapping
|
|
77
|
+
- run-intent and run-selection mapping
|
|
78
|
+
- plan enrichment
|
|
79
|
+
- SparkForge result normalization with secret redaction
|
|
80
|
+
- Delta capability checks
|
|
81
|
+
- IR fixture parity tests without SparkForge or PySpark installed
|
|
82
|
+
|
|
83
|
+
The baseline does **not** yet provide a native `MedallionPipeline` builder,
|
|
84
|
+
execute legacy transformation callables, or reach live Spark/SQL behavioral
|
|
85
|
+
parity.
|
|
86
|
+
|
|
87
|
+
## Joint pre-1.0 sequence
|
|
88
|
+
|
|
89
|
+
Medallantic milestones are release-gated with ETLantic's pre-1.0 roadmap:
|
|
90
|
+
|
|
91
|
+
| ETLantic release | Medallantic phase | Joint focus |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| 0.27 | M0 (partial) | Rename, workspace/CI, first `medallantic` PyPI publish |
|
|
94
|
+
| 0.28 | M0 closeout | Quadruple-minor burn-in, Plugin `/1` freeze, facade boundary |
|
|
95
|
+
| 0.29 | M1 | Native medallion authoring and facade conformance |
|
|
96
|
+
| 0.30 | M2 | Portable quality/rule semantics |
|
|
97
|
+
| 0.31 | M3 | Execution, state, writes, and materialization |
|
|
98
|
+
| 0.32 | M4 | PySpark/SparkForge differential parity |
|
|
99
|
+
| 0.33 | M5 | SQLAlchemy/relational differential parity |
|
|
100
|
+
| 0.34 | M6 | Operations, evidence, and production readiness |
|
|
101
|
+
| 0.35 | M7 | Migration completion and joint freeze |
|
|
102
|
+
| 0.36–0.98 | — | Joint compatibility burn-in |
|
|
103
|
+
| 0.99 | — | Shared release-candidate rehearsal |
|
|
104
|
+
|
|
105
|
+
The [ETLantic roadmap](../../ROADMAP.md) is authoritative for the core
|
|
106
|
+
capability promoted at each phase and the joint exit gate. This document is
|
|
107
|
+
authoritative for Medallantic feature parity and migration scope.
|
|
108
|
+
|
|
109
|
+
## Definition of full parity
|
|
110
|
+
|
|
111
|
+
Full parity is reached only when all required rows below have:
|
|
112
|
+
|
|
113
|
+
1. a public Medallantic API,
|
|
114
|
+
2. an explicit ETLantic mapping,
|
|
115
|
+
3. conformance tests shared by all applicable engines,
|
|
116
|
+
4. live PySpark and SQL integration tests where backend behavior matters,
|
|
117
|
+
5. migration documentation and a declared compatibility result.
|
|
118
|
+
|
|
119
|
+
“Equivalent” permits an intentional API improvement. “Plugin” means the
|
|
120
|
+
portable intent is in Medallantic/ETLantic and the physical behavior is
|
|
121
|
+
implemented by a capability-bearing plugin. “Do not carry forward” records
|
|
122
|
+
legacy behavior that would be unsafe or architecturally incorrect.
|
|
123
|
+
|
|
124
|
+
## Parity matrix
|
|
125
|
+
|
|
126
|
+
| Capability | Spark builder | SQL builder | Target | Priority |
|
|
127
|
+
|---|---:|---:|---|---|
|
|
128
|
+
| Fluent bronze/silver/gold builder | Yes | Yes | Native `MedallionPipeline`/builder | P0 |
|
|
129
|
+
| Partial pipelines (any layer subset) | Yes | Yes | Equivalent | P0 |
|
|
130
|
+
| Unique step names and construction-time validation | Yes | Yes | Equivalent diagnostics | P0 |
|
|
131
|
+
| Automatic dependency ordering | Yes | Yes | ETLantic deterministic planner | P0 |
|
|
132
|
+
| Cycle and missing-dependency detection | Yes | Yes | Fail closed with stable codes | P0 |
|
|
133
|
+
| Bronze source to silver wiring | Yes | Yes | Typed output references | P0 |
|
|
134
|
+
| Multiple silver inputs for gold | Yes | Yes | Named typed input ports | P0 |
|
|
135
|
+
| Prior silver result access | Yes | Yes | Run-scoped artifact context | P0 |
|
|
136
|
+
| Cross-schema reads and writes | Yes | Yes | Dataset bindings plus profiles | P0 |
|
|
137
|
+
| Layer descriptions and metadata | Yes | Partial | Portable metadata | P1 |
|
|
138
|
+
| Per-layer validation thresholds | Yes | Yes | Named medallion quality policy | P0 |
|
|
139
|
+
| Multiple rules per column | Yes | Yes | Contract-backed quality gates | P0 |
|
|
140
|
+
| Valid/invalid row separation | Yes | Yes | Typed accepted/rejected outputs | P0 |
|
|
141
|
+
| Validation-only steps and runs | Yes | Yes | `RunIntent.VALIDATE`, no writes | P0 |
|
|
142
|
+
| PySpark expression rules | Yes | No | PySpark compiler/plugin | P0 |
|
|
143
|
+
| String rule shorthand | Yes | No | Medallantic rule DSL | P1 |
|
|
144
|
+
| Moltres expression rules | No | Yes | SQL compiler compatibility | P0 |
|
|
145
|
+
| SQLAlchemy expression compatibility | No | Yes | SQL migration adapter | P0 |
|
|
146
|
+
| Callable transforms | Yes | Yes | Backend implementation refs | P0 |
|
|
147
|
+
| Initial load | Yes | Yes | Initialize intent | P0 |
|
|
148
|
+
| Incremental load | Yes | Yes | Incremental strategy plus state | P0 |
|
|
149
|
+
| Full refresh | Yes | Equivalent | Refresh intent | P0 |
|
|
150
|
+
| Bronze incremental column | Yes | Yes | Watermark strategy | P0 |
|
|
151
|
+
| Silver watermark column | Yes | Yes | State strategy | P0 |
|
|
152
|
+
| Append writes | Yes | Yes | Portable write intent | P0 |
|
|
153
|
+
| Overwrite writes | Yes | Yes | Portable write intent | P0 |
|
|
154
|
+
| Partition overwrite | Yes | Backend-specific | Plugin capability | P1 |
|
|
155
|
+
| Merge/upsert | Delta | Database-specific | Keyed merge capability | P0 |
|
|
156
|
+
| Ignore/skip-if-exists | Yes | Partial | Portable write intent | P1 |
|
|
157
|
+
| Schema compatibility checks | Yes | ORM model | Contracts plus sink checks | P0 |
|
|
158
|
+
| Schema override/evolution policy | Yes | ORM model | Explicit mutation policy | P1 |
|
|
159
|
+
| Table create/drop/refresh | Yes | Yes | Storage plugin | P0 |
|
|
160
|
+
| Silver initial recreate | N/A/overwrite | Yes | Refresh policy | P0 |
|
|
161
|
+
| Gold replace on every run | Yes | Yes | Layer default, overridable | P0 |
|
|
162
|
+
| SQLAlchemy ORM model table creation | No | Yes | SQL plugin compatibility | P0 |
|
|
163
|
+
| Primary-key validation | No | Yes | Merge/publication validation | P0 |
|
|
164
|
+
| Moltres lazy DataFrame transforms | No | Yes | SQL compiler | P0 |
|
|
165
|
+
| SQLAlchemy `Select`/compound selects | No | Yes | SQL compiler | P0 |
|
|
166
|
+
| Sync SQLAlchemy sessions | No | Yes | SQL runtime | P0 |
|
|
167
|
+
| Async SQLAlchemy sessions | No | Yes | SQL runtime | P1 |
|
|
168
|
+
| Multi-database SQLAlchemy support | No | Yes | Dialect conformance matrix | P1 |
|
|
169
|
+
| Spark and Sparkless execution | Yes | No | PySpark plus local test backend | P0 |
|
|
170
|
+
| JDBC sources and targets | Yes | No | SQL/PySpark I/O plugins | P1 |
|
|
171
|
+
| SQLAlchemy sources and targets from Spark | Yes | No | Explicit bridge capability | P2 |
|
|
172
|
+
| Delta merge | Yes | No | Delta plugin | P0 |
|
|
173
|
+
| Delta optimize, vacuum, history | Yes | No | Delta plugin | P1 |
|
|
174
|
+
| Delta time travel | Yes | No | Delta source capability | P1 |
|
|
175
|
+
| Run one / run until | Yes | No | ETLantic run selection | P0 |
|
|
176
|
+
| Stateful debug session | Yes | No | Medallantic convenience facade | P1 |
|
|
177
|
+
| Runtime parameter overrides | Yes | No | ETLantic run request | P1 |
|
|
178
|
+
| Transform/rule overrides for debug | Yes | No | Scoped implementation overrides | P1 |
|
|
179
|
+
| Downstream invalidation and rerun | Yes | No | Artifact provenance/invalidation | P1 |
|
|
180
|
+
| Skip writes during debugging | Yes | No | No-write materialization policy | P0 |
|
|
181
|
+
| Retry attempts and delays | Yes | Shared base | ETLantic retry policy | P0 |
|
|
182
|
+
| Contextual pipeline/step logging | Yes | Yes | Structured lifecycle events | P0 |
|
|
183
|
+
| Normalized run and step reports | Yes | Yes | Medallantic result facade | P0 |
|
|
184
|
+
| Counts, duration, validation and table metrics | Yes | Yes | Normalized report fields | P0 |
|
|
185
|
+
| Persisted execution-log writer | Yes | Shared base | Observability provider | P1 |
|
|
186
|
+
| Log table create/append/read | Yes | Shared base | Provider conformance | P1 |
|
|
187
|
+
| Trend and quality analytics | Yes | No | Event consumer/reference provider | P2 |
|
|
188
|
+
| Anomaly detection queries | Yes | No | Observability integration | P2 |
|
|
189
|
+
| Parallel candidates/execution groups | Analysis | Async SQL claim | Planner explain plus executor | P1 |
|
|
190
|
+
| Dependency recommendations | Yes | Shared base | Structured lint findings | P2 |
|
|
191
|
+
| Development/testing/production presets | Yes | Shared base | Profile templates | P1 |
|
|
192
|
+
| Serialization of configuration/results | Yes | Yes | Stable versioned schemas | P0 |
|
|
193
|
+
| Detailed errors with suggestions | Yes | Yes | Stable diagnostics/remediation | P0 |
|
|
194
|
+
| Engine-explicit configuration | Partial | Partial | Required profile selection | P0 |
|
|
195
|
+
| Silent runtime/mock auto-detection | Yes | N/A | Do not carry forward | Never |
|
|
196
|
+
| Automatic cycle breaking | Legacy analyzer | Legacy analyzer | Do not carry forward | Never |
|
|
197
|
+
| Separate public builders per engine | Yes | Yes | Do not carry forward | Never |
|
|
198
|
+
|
|
199
|
+
## Delivery milestones
|
|
200
|
+
|
|
201
|
+
### M0 / ETLantic 0.27–0.28 — Rename, release hygiene, and M0 closeout
|
|
202
|
+
|
|
203
|
+
**Shipped in 0.27.0**
|
|
204
|
+
|
|
205
|
+
- [x] Rename distribution to `medallantic`.
|
|
206
|
+
- [x] Rename import package to `medallantic`.
|
|
207
|
+
- [x] Rename workspace paths, tests, documentation, extras, and release checks.
|
|
208
|
+
- [x] Preserve SparkForge-specific conversion helper names where they describe
|
|
209
|
+
the legacy input format.
|
|
210
|
+
- [x] Publish the first `medallantic` distribution (`medallantic==0.27.0`).
|
|
211
|
+
|
|
212
|
+
**Owned by 0.28 (M0 closeout)**
|
|
213
|
+
|
|
214
|
+
- [ ] Decide whether to publish a final `etlantic-sparkforge` compatibility
|
|
215
|
+
release that depends on Medallantic and emits a deprecation warning.
|
|
216
|
+
- [ ] Document facade-package release category and ongoing trusted-publishing
|
|
217
|
+
evidence for `medallantic`.
|
|
218
|
+
|
|
219
|
+
Exit criteria: clean build, install, import, docs, lockfile, and adapter suite on
|
|
220
|
+
every release; core remains importable without Medallantic; no medallion
|
|
221
|
+
identifier in ETLantic wire schemas.
|
|
222
|
+
|
|
223
|
+
### M1 / ETLantic 0.29 — Native medallion authoring
|
|
224
|
+
|
|
225
|
+
- [ ] Add `MedallionPipeline`, `MedallionBuilder`, `Bronze`, `Silver`, and
|
|
226
|
+
`Gold` public surfaces.
|
|
227
|
+
- [ ] Support fluent and declarative/serialized authoring.
|
|
228
|
+
- [ ] Map every layer definition to ordinary ETLantic nodes, typed ports,
|
|
229
|
+
quality gates, sinks, and policies.
|
|
230
|
+
- [ ] Support partial pipelines, multiple branches, prior-result references,
|
|
231
|
+
cross-schema bindings, descriptions, tags, and deterministic names.
|
|
232
|
+
- [ ] Add stable `MDL1xx` construction and graph diagnostics.
|
|
233
|
+
- [ ] Keep the current IR adapter as `medallantic.migrate.sparkforge`.
|
|
234
|
+
|
|
235
|
+
Exit criteria: representative SparkForge pipelines can be authored natively,
|
|
236
|
+
validated, planned, serialized, and explained without SparkForge installed.
|
|
237
|
+
|
|
238
|
+
### M2 / ETLantic 0.30 — Quality and rules parity
|
|
239
|
+
|
|
240
|
+
- [ ] Define an engine-neutral rule AST/DSL for common shorthand:
|
|
241
|
+
`not_null`, comparisons, membership, ranges, regex, length, uniqueness,
|
|
242
|
+
and custom contract rules.
|
|
243
|
+
- [ ] Compile rules to ETLantic/ContractModel quality gates.
|
|
244
|
+
- [ ] Add PySpark, SQL/Moltres, Polars, and Pandas rule compilers.
|
|
245
|
+
- [ ] Return accepted and rejected typed artifacts with counts and reasons.
|
|
246
|
+
- [ ] Implement named per-layer defaults and per-step overrides.
|
|
247
|
+
- [ ] Make validation cost and unsupported-rule fallback visible in plans.
|
|
248
|
+
|
|
249
|
+
Exit criteria: shared fixtures produce equivalent pass/fail decisions,
|
|
250
|
+
accepted/rejected counts, and diagnostics across supported engines.
|
|
251
|
+
|
|
252
|
+
### M3 / ETLantic 0.31 — Execution and materialization parity
|
|
253
|
+
|
|
254
|
+
- [ ] Execute native callable transforms through ETLantic implementation
|
|
255
|
+
references.
|
|
256
|
+
- [ ] Implement initial, incremental, refresh, standard, and validation-only
|
|
257
|
+
behavior.
|
|
258
|
+
- [ ] Map incremental columns and watermarks to atomic ETLantic state
|
|
259
|
+
transitions.
|
|
260
|
+
- [ ] Implement append, replace, keyed merge, skip-if-exists, and partition
|
|
261
|
+
replacement with capability checks.
|
|
262
|
+
- [ ] Implement layer defaults for bronze preservation, silver refresh, and
|
|
263
|
+
gold publication without hard-coding them into ETLantic core.
|
|
264
|
+
- [ ] Support retries only when the planned operation is safely retryable.
|
|
265
|
+
- [ ] Normalize run, step, validation, artifact, write, and state results.
|
|
266
|
+
|
|
267
|
+
Exit criteria: engine-neutral conformance fixtures pass for local, Polars,
|
|
268
|
+
Pandas, SQL, and PySpark where each engine advertises support.
|
|
269
|
+
|
|
270
|
+
### M4 / ETLantic 0.32 — PySpark/SparkForge parity
|
|
271
|
+
|
|
272
|
+
- [ ] Add a live migration bridge for `PipelineBuilder` definitions.
|
|
273
|
+
- [ ] Support PySpark Column validation expressions and transform callables.
|
|
274
|
+
- [ ] Support real PySpark and Sparkless test modes explicitly.
|
|
275
|
+
- [ ] Cover schema/catalog management, cross-schema access, caches, JDBC I/O,
|
|
276
|
+
and Spark-native metrics through plugins.
|
|
277
|
+
- [ ] Add Delta capabilities for merge, optimize, vacuum, history, schema
|
|
278
|
+
evolution, and time travel.
|
|
279
|
+
- [ ] Reproduce run-one, run-until, no-write, parameter override, transform
|
|
280
|
+
override, rerun, and downstream invalidation workflows.
|
|
281
|
+
- [ ] Compare logical order, writes, validation outcomes, and normalized
|
|
282
|
+
reports against frozen SparkForge fixtures.
|
|
283
|
+
|
|
284
|
+
Exit criteria: every supported `pipeline_builder` fixture has a documented
|
|
285
|
+
`equivalent`, `plugin-dependent`, or `intentionally rejected` result.
|
|
286
|
+
|
|
287
|
+
### M5 / ETLantic 0.33 — SQL pipeline-builder parity
|
|
288
|
+
|
|
289
|
+
- [ ] Add a live migration bridge for `SqlPipelineBuilder` definitions.
|
|
290
|
+
- [ ] Accept Moltres DataFrames/expressions and SQLAlchemy ORM, `Select`, and
|
|
291
|
+
compound-select sources during migration.
|
|
292
|
+
- [ ] Preserve lazy relational execution and avoid unnecessary table
|
|
293
|
+
round-trips between steps.
|
|
294
|
+
- [ ] Support model-driven table creation and primary-key validation.
|
|
295
|
+
- [ ] Match initial/incremental silver behavior and gold replacement defaults.
|
|
296
|
+
- [ ] Support sync and async SQLAlchemy execution with transaction rollback.
|
|
297
|
+
- [ ] Validate missing sources, ambiguous/duplicate columns, invalid transform
|
|
298
|
+
results, conversion failures, and write failures consistently.
|
|
299
|
+
- [ ] Establish dialect tiers and live CI for SQLite and PostgreSQL, followed
|
|
300
|
+
by additional SQLAlchemy dialects.
|
|
301
|
+
|
|
302
|
+
Exit criteria: the SQL parity matrix passes on SQLite and PostgreSQL, with
|
|
303
|
+
other dialect support accurately capability-gated.
|
|
304
|
+
|
|
305
|
+
### M6 / ETLantic 0.34 — Operations, observability, and production readiness
|
|
306
|
+
|
|
307
|
+
- [ ] Provide medallion-oriented structured explain output.
|
|
308
|
+
- [ ] Emit normalized lifecycle events with pipeline, layer, step, attempt,
|
|
309
|
+
plan, run, and backend context.
|
|
310
|
+
- [ ] Add durable run-history provider conformance for create/append/read.
|
|
311
|
+
- [ ] Port trend, quality, performance, and anomaly analytics as optional
|
|
312
|
+
event consumers rather than core storage logic.
|
|
313
|
+
- [ ] Add development, testing, and production profile templates.
|
|
314
|
+
- [ ] Complete redaction, plugin allowlist, schema-mutation, concurrency,
|
|
315
|
+
cancellation, timeout, and recovery tests.
|
|
316
|
+
- [ ] Publish compatibility, security, performance, and production-readiness
|
|
317
|
+
documentation with explicit support tiers.
|
|
318
|
+
|
|
319
|
+
Exit criteria: Medallantic meets ETLantic’s production profile requirements
|
|
320
|
+
and has no undocumented fallback or mutation behavior.
|
|
321
|
+
|
|
322
|
+
### M7 / ETLantic 0.35 — Migration completion
|
|
323
|
+
|
|
324
|
+
- [ ] Ship an automated scanner that inventories a SparkForge project and
|
|
325
|
+
emits a migration report.
|
|
326
|
+
- [ ] Generate native Medallantic definitions where conversion is safe.
|
|
327
|
+
- [ ] Produce stable diagnostics for manual conversion points.
|
|
328
|
+
- [ ] Maintain golden before/after plans and run reports.
|
|
329
|
+
- [ ] Publish versioned deprecation timelines for legacy imports.
|
|
330
|
+
- [ ] Remove transitional adapters only in a major release.
|
|
331
|
+
|
|
332
|
+
Exit criteria: both legacy builders have documented, tested migration paths
|
|
333
|
+
and all claimed parity rows are backed by conformance evidence.
|
|
334
|
+
|
|
335
|
+
## Test strategy
|
|
336
|
+
|
|
337
|
+
The parity suite will have four layers:
|
|
338
|
+
|
|
339
|
+
1. **IR tests** — no SparkForge, SQLAlchemy, or PySpark dependency.
|
|
340
|
+
2. **Semantic conformance** — one logical fixture and normalized assertions
|
|
341
|
+
across local, Polars, Pandas, SQL, and PySpark.
|
|
342
|
+
3. **Legacy differential tests** — run frozen SparkForge and Medallantic
|
|
343
|
+
fixtures and compare graph order, validation, writes, and reports.
|
|
344
|
+
4. **Backend integration tests** — real SQLite/PostgreSQL, PySpark, and Delta
|
|
345
|
+
environments for physical semantics.
|
|
346
|
+
|
|
347
|
+
Every parity claim must identify its fixture, engines, capability requirements,
|
|
348
|
+
and normalized assertions. Unit-test coverage alone cannot establish backend
|
|
349
|
+
parity.
|
|
350
|
+
|
|
351
|
+
## Compatibility policy
|
|
352
|
+
|
|
353
|
+
- SparkForge names may remain in migration-only APIs and serialized legacy IR.
|
|
354
|
+
- New authoring APIs use Medallantic names exclusively.
|
|
355
|
+
- Diagnostic codes and serialized fields already consumed externally remain
|
|
356
|
+
stable until a documented major-version migration.
|
|
357
|
+
- Backend-specific expressions are accepted only as implementation details;
|
|
358
|
+
portable definitions use contracts, rule AST nodes, and typed references.
|
|
359
|
+
- A capability gap is an explicit diagnostic, never an implicit fallback.
|
|
360
|
+
|
|
361
|
+
## Release gates
|
|
362
|
+
|
|
363
|
+
A release may claim full parity only when:
|
|
364
|
+
|
|
365
|
+
- every P0 matrix row is complete,
|
|
366
|
+
- all P1 rows are complete or explicitly deferred with a documented support
|
|
367
|
+
limitation,
|
|
368
|
+
- both legacy differential suites pass,
|
|
369
|
+
- SQLite, PostgreSQL, PySpark, and Delta integration suites pass,
|
|
370
|
+
- package build/install/import and documentation checks pass,
|
|
371
|
+
- security/redaction and schema-mutation gates pass,
|
|
372
|
+
- the compatibility table is generated from test evidence.
|