22# Contract Stage Executor
33# =============================================================================
44
5+ import polars as pl
56from data_pipeline .shared .run_context import RunContext
67from data_pipeline .shared .loader_exporter import load_single_delta , export_file
8+ from data_pipeline .assembly .assembly_executor import force_gc
79from data_pipeline .shared .table_configs import TABLE_CONFIG
810from data_pipeline .contract .registry import ROLE_STEPS
9- from data_pipeline .contract .id_registrar import id_mapping , ID_COLUMNS_TO_MAP
10- from pathlib import Path
11+ from data_pipeline .contract .id_registrar import ID_ENTITY_MAP
1112
1213
1314def apply_contract (
1415 run_context : RunContext ,
1516 table_name : str ,
17+ master_mappings : dict [str , pl .LazyFrame ],
1618 invalid_order_ids : set | None = None ,
1719 valid_order_ids : set | None = None ,
1820) -> tuple [dict , set , set ]:
1921 """
20- Main entry point for the Raw-to-Contracted Stage .
22+ Orchestrates the Raw-to-Contracted transformation for a specific logical table .
2123
2224 Workflow:
2325 1. Resolve: Identifies table metadata (role, schema, keys) from the central registry.
2426 2. Hydrate: Fetches the raw snapshot from the lake's snapshot zone.
2527 3. Delegate: Iteratively applies atomic logic rules (Deduplication, Chronology, Null-checks).
2628 4. Validate: Executes 'enforce_schema' as the terminal structural gate.
27- 5. Promote: Persists the contract-compliant dataset to the Silver (contracted) zone.
29+ 5. Map: Joins against pre-calculated Discovery mappings to enrich UUIDs with UInt32 integer IDs.
30+ 6. Promote: Persists the contract-compliant dataset to the Silver (contracted) zone.
2831
2932 Operational Guarantees:
3033 - Subtractive Only: Exclusively filters rows or casts types; never mutates business values.
3134 - Referential Safety: Propagates invalidated keys across table boundaries to ensure consistent pruning.
32- - Structural Finality: Guarantees output parity with the ASSEMBLE_SCHEMA specification.
35+ - Structural Finality: Guarantees output parity with the Silver layer specification, including required integer IDs .
3336
3437 Side Effects:
3538 - Persists a Parquet artifact to the contracted directory.
36- - Updates newly invalidated 'order_id' sets for downstream cross-table pruning.
39+ - Updates invalidated 'order_id' sets for downstream cross-table pruning.
3740
3841 Failure Behavior:
3942 - Traps logic-step exceptions; logs errors to the report and halts the current table's processing.
40-
41- Returns:
42- tuple: (Stage Report Dict, Newly Invalidated IDs Set, Validated Order IDs Set)
43+ - Crashes if ID mapping joins fail to prevent downstream schema corruption.
4344 """
4445
4546 report = {
@@ -69,7 +70,6 @@ def apply_contract(
6970 if table_name not in TABLE_CONFIG :
7071 report ["status" ] = "failed"
7172 report ["errors" ].append (f"Unknown table: { table_name } " )
72-
7373 return report , invalid_ids , valid_ids
7474
7575 base_path = run_context .raw_snapshot_path
@@ -89,32 +89,26 @@ def apply_contract(
8989 role = config ["role" ]
9090
9191 for step in ROLE_STEPS [role ]:
92-
9392 contract = step ["contract" ]
94- args = []
95-
96- if "non_nullable" in step ["args" ]:
97- args .append (non_nullable )
9893
99- if "invalid_order_ids" in step ["args" ]:
100- args .append (invalid_order_ids )
94+ args = [
95+ non_nullable if "non_nullable" in step ["args" ] else None ,
96+ invalid_order_ids if "invalid_order_ids" in step ["args" ] else None ,
97+ valid_order_ids if "valid_order_ids" in step ["args" ] else None ,
98+ ]
10199
102- if "valid_order_ids" in step [ " args" ]:
103- args . append ( valid_order_ids )
100+ # Remove args not needed for the current registry loop
101+ args = [ arg for arg in args if arg is not None ]
104102
105103 if "required_column" in step ["args" ]:
106- args .append (required_column )
107- args .append (dtypes )
104+ args .extend ([required_column , dtypes ])
108105
109106 try :
110-
111107 if step ["return_invalid_ids" ]:
112108 df , removed , new_invalid = contract (df , * args )
113109 invalid_ids |= new_invalid
114-
115110 else :
116111 df , removed = contract (df , * args )
117-
118112 report [step ["metric" ]] += removed
119113
120114 except Exception as e :
@@ -129,33 +123,31 @@ def apply_contract(
129123 if table_name == "df_orders" :
130124 valid_ids = set (df .get_column ("order_id" ))
131125
132- temp_path = run_context .contracted_path / "id_mapping"
133- storage_mapping_str = run_context .storage_mapping_path
134-
135- # Switch between local and gcp path
136- storage_mapping = (
137- storage_mapping_str
138- if storage_mapping_str .startswith ("gs://" )
139- else Path (storage_mapping_str )
140- )
141-
142- df = id_mapping (
143- df = df ,
144- table_name = table_name ,
145- mapping_dict = ID_COLUMNS_TO_MAP ,
146- runtime_dir = temp_path ,
147- destination = storage_mapping ,
148- run_id = run_context .run_id ,
149- )
126+ df_lf = df .lazy ()
150127
151- output_path = run_context .contracted_path / f"{ filename } .parquet"
128+ try :
129+ # Attach mapped integer in dataframe
130+ for entity_col , tables in ID_ENTITY_MAP .items ():
131+ if table_name in tables and entity_col in master_mappings :
132+ df_lf = df_lf .join (
133+ master_mappings [entity_col ], on = entity_col , how = "left"
134+ )
135+
136+ # Force to fail before corrupting downstream
137+ except Exception as e :
138+ raise RuntimeError (f"Mapping Uint32 to UUIDs Failed: { e } " ) from e
152139
153- if not export_file (df , output_path ):
140+ output_path = run_context .contracted_path / f"{ filename } .parquet"
141+ if not export_file (df_lf .collect (), output_path ):
154142 report ["status" ] = "failed"
155143 report ["errors" ].append ("Export failed" )
156-
157144 return report , invalid_ids , valid_ids
158145
159- report ["status" ] = "success"
146+ if "df" in locals ():
147+ del df
148+ if "df_lf" in locals ():
149+ del df_lf
150+ force_gc ()
160151
152+ report ["status" ] = "success"
161153 return report , invalid_ids , valid_ids
0 commit comments