Skip to content

Commit deab594

Browse files
committed
docs: refactor pipeline documentation to design-contract architecture
- Decoupled stage Executor and Logic into distinct contracts - Map component-level failure surfaces and severity models - Align Global Orchestrator docstrings with the Promote-Purge-Restore Cloud-Sync pattern
1 parent d0f89c1 commit deab594

23 files changed

Lines changed: 488 additions & 1792 deletions

data_extract/run_extract.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
MIME_TYPE = "application/vnd.google-apps.folder"
2121

2222

23+
# TODO: wrap steps into functions
2324
def run_extraction(target_child_folder):
2425

2526
service = get_drive_service()

data_pipeline/assembly/assembly_executor.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ def orchestrate_event_assembly(run_context: RunContext, report: Dict) -> bool:
4343
Coordinates the linear transformation pipeline for order-grain events.
4444
4545
Execution Flow:
46-
1. Load: Fetch 'orders', 'items', and 'payments'.
47-
2. Merge: Join into a single row-per-order grain.
48-
3. Derive: Calculate analytical time-deltas and lineage.
49-
4. Freeze: Enforce semantic schema and dtypes.
50-
5. Export: Persist to the assembly zone.
46+
1. Load: Fetch 'orders', 'items', and 'payments'.
47+
2. Merge: Join into a single row-per-order grain.
48+
3. Derive: Calculate analytical time-deltas and lineage.
49+
4. Freeze: Enforce semantic schema and dtypes.
50+
5. Export: Persist to the assembly zone.
5151
5252
Memory Management:
5353
- Explicitly deletes intermediate DataFrames and triggers gc.collect()
@@ -152,16 +152,16 @@ def assemble_events(run_context: RunContext) -> dict:
152152
tables into contract-compliant analytical datasets.
153153
154154
Workflow I: Event Assembly (Order Grain)
155-
1. Load: Fetches core event tables (Orders, Items, Payments).
156-
2. Merge: Join datasets with strict 1:1 order_id cardinality enforcement.
157-
3. Derive: Calculate temporal metrics (lead times) and lineage attributes.
158-
4. Freeze: Project final schema and enforce strictly defined dtypes.
159-
5. Export: Persist the unified event table to the Gold zone.
155+
1. Load: Fetches core event tables (Orders, Items, Payments).
156+
2. Merge: Join datasets with strict 1:1 order_id cardinality enforcement.
157+
3. Derive: Calculate temporal metrics (lead times) and lineage attributes.
158+
4. Freeze: Project final schema and enforce strictly defined dtypes.
159+
5. Export: Persist the unified event table to the Gold zone.
160160
161161
Workflow II: Dimension Reference Extraction
162-
1. Iterate: Process Customer and Product registries.
163-
2. Extract: Select required columns and deduplicate by primary key.
164-
3. Export: Persist independent reference tables to the Gold zone.
162+
1. Iterate: Process Customer and Product registries.
163+
2. Extract: Select required columns and deduplicate by primary key.
164+
3. Export: Persist independent reference tables to the Gold zone.
165165
166166
Operational Guarantees:
167167
- Grain: Strictly one row per 'order_id' for the event dataset.

data_pipeline/contract/contract_executor.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ def apply_contract(
2222
ensuring only compliant rows and columns reach the Silver (contracted) layer.
2323
2424
Workflow:
25-
1. Resolve: Determines table configuration and role (event_fact, entity_reference, etc.).
26-
2. Load: Fetches the raw snapshot from the lake's snapshot zone.
27-
3. Sequence: Iteratively applies atomic filtering rules (Deduplication, Null-checks, etc.).
28-
4. Track: Captures row-level telemetry and identifies compromised 'order_id's.
29-
5. Propagate: Returns validated/invalidated IDs to maintain referential integrity.
30-
6. Freeze: Executes 'enforce_schema' as the terminal step to project approved columns.
31-
7. Export: Persists the contract-compliant dataset to the Silver zone.
25+
1. Resolve: Determines table configuration and role (event_fact, entity_reference, etc.).
26+
2. Load: Fetches the raw snapshot from the lake's snapshot zone.
27+
3. Sequence: Iteratively applies atomic filtering rules (Deduplication, Null-checks, etc.).
28+
4. Track: Captures row-level telemetry and identifies compromised 'order_id's.
29+
5. Propagate: Returns validated/invalidated IDs to maintain referential integrity.
30+
6. Freeze: Executes 'enforce_schema' as the terminal step to project approved columns.
31+
7. Export: Persists the contract-compliant dataset to the Silver zone.
3232
3333
Operational Guarantees:
3434
- Subtractive Only: Filters rows first; never mutates row values (only column types).

data_pipeline/publish/publish_executor.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ def execute_publish_lifecycle(run_context: RunContext) -> Dict:
2020
the internal assembly zones to the production-facing BI environment.
2121
2222
Workflow:
23-
1. Integrity Gate: Verifies that the current run has produced all
24-
required semantic modules and tables defined in the registry.
25-
2. Promotion: Moves/copies artifacts into a permanent, read-only
26-
versioned directory (v{run_id}).
27-
3. Activation: Performs an atomic update of the 'latest' pointer
28-
to switch BI/Reporting traffic to the new version.
23+
1. Integrity Gate: Verifies that the current run has produced all
24+
required semantic modules and tables defined in the registry.
25+
2. Promotion: Moves/copies artifacts into a permanent, read-only
26+
versioned directory (v{run_id}).
27+
3. Activation: Performs an atomic update of the 'latest' pointer
28+
to switch BI/Reporting traffic to the new version.
2929
3030
Operational Guarantees:
3131
- Atomicity: The 'latest' pointer is updated ONLY if all prior

data_pipeline/run_pipeline.py

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -33,27 +33,39 @@
3333

3434
def persist_json(path: Path, payload: dict) -> None:
3535
"""
36-
Writes the stage report to a JSON file.
36+
Serializes state dictionaries to the local filesystem.
37+
38+
Contract:
39+
- Creates parent directories if they do not exist.
40+
- Performs standard JSON serialization with 2-space indentation.
3741
"""
3842
path.parent.mkdir(parents=True, exist_ok=True)
3943
with open(path, "w") as f:
4044
json.dump(payload, f, indent=2)
4145

4246

4347
def stage_logger(run_context: RunContext, stage: str, report: dict | list):
48+
"""
49+
Standardizes the persistence of stage-level telemetry.
50+
51+
Contract:
52+
- Maps 'stage' identifiers to deterministic filenames (e.g., stage_report.json).
53+
- Persists reports to the 'run_context.run_path'.
54+
"""
4455

4556
persist_json(
4657
path=run_context.logs_path / f"{stage}.json",
4758
payload={"run_id": run_context.run_id, "report": report},
4859
)
4960

5061

51-
def initiliaze_metadata(run_context: RunContext) -> None:
62+
def initialize_metadata(run_context: RunContext) -> None:
5263
"""
53-
Run metadata initializer.
64+
Registers the commencement of a pipeline run.
5465
55-
Creates the run-scoped metadata record at pipeline start to
56-
establish lifecycle tracking and publish eligibility state.
66+
Contract:
67+
- Generates a 'run_metadata.json' artifact.
68+
- Captures the initial 'run_id', 'start_time', and sets status to 'RUNNING'.
5769
"""
5870

5971
run_dt = dt.strptime(run_context.run_id[:15], "%Y%m%dT%H%M%S")
@@ -65,7 +77,7 @@ def initiliaze_metadata(run_context: RunContext) -> None:
6577
"started_at": dt.utcnow().isoformat(),
6678
"run_year": run_dt.year,
6779
"run_month": run_dt.month,
68-
"run_week_of_month": (run_dt.day - 1) // 7 + 1,
80+
"run_day": run_dt.day,
6981
"completed_at": None,
7082
"run_duration": None,
7183
"published": False,
@@ -76,10 +88,11 @@ def initiliaze_metadata(run_context: RunContext) -> None:
7688

7789
def finalize_metadata(run_context: RunContext, status: str) -> None:
7890
"""
79-
Run metadata finalizer.
91+
Updates the run metadata record with terminal status and completion timestamp.
8092
81-
Updates the run metadata record with terminal status and
82-
completion timestamp.
93+
Contract:
94+
- Updates 'run_metadata.json' with the 'end_time' and final 'status'.
95+
- Calculates the total run duration and display in '00m 00s' format.
8396
"""
8497

8598
if not run_context.metadata_path.exists():
@@ -88,18 +101,17 @@ def finalize_metadata(run_context: RunContext, status: str) -> None:
88101
with open(run_context.metadata_path, "r") as file:
89102
payload = json.load(file)
90103

104+
start_time = dt.fromisoformat(payload["started_at"])
91105
completion_time = dt.utcnow()
92106

93107
payload["status"] = status
94108
payload["completed_at"] = completion_time.isoformat()
95109

96-
start_time = dt.fromisoformat(payload["started_at"])
97110
duration = completion_time - start_time
98-
99111
mm, ss = divmod(int(duration.total_seconds()), 60)
100-
payload["run_duration"] = f"{mm:02d}m {ss:02d}s"
101112

102-
payload["published"] = True if status == "SUCCESS" else False
113+
payload["run_duration"] = f"{mm:02d}m {ss:02d}s"
114+
payload["published"] = status == "SUCCESS"
103115

104116
persist_json(run_context.metadata_path, payload)
105117

@@ -186,32 +198,29 @@ def run_prepublishing_validation_stage(run_context) -> None:
186198

187199
def main() -> None:
188200
"""
189-
Pipeline orchestrator.
190-
191-
Execution order:
192-
1. Snapshot raw data
193-
2. Initialize metadata (RUNNING)
194-
3. Validation
195-
4. Contract enforcement
196-
- Apply role-driven repair
197-
- Propagate invalid order_ids (parent → child)
198-
- Propogate valida order_ids (parent → child)
199-
5. Re-validation
200-
6. Assemble event table
201-
7. Build semantic layer
202-
8. Pre-publish integrity gate
203-
9. Promote version
204-
10. Finalize metadata (SUCCESS)
205-
11. Atomic activation
206-
207-
Guarantees:
208-
- Deterministic forward-only execution
209-
- Single run isolation
210-
- Only Contract stage mutates data
211-
- Activation occurs only after SUCCESS
212-
213-
Failure behavior:
214-
- Any stage failure → metadata FAILED → process exits
201+
Ultimate authority for the end-to-end data pipeline lifecycle.
202+
203+
Workflow:
204+
1. Initialization: Resolve RunContext and instantiate global run metadata.
205+
2. Ingestion: Synchronize the raw data snapshot from Cloud Storage to local workspace.
206+
3. Gate I (Validation): Assert raw data sanity; fail-fast on fatal structural errors.
207+
4. Processing (Contract): Execute subtractive filtering and Silver-layer schema freezing.
208+
5. Gate II (Revalidation): Defensive check to ensure 'contracted' data is valid.
209+
6. Persistence (Sync Upload): Promote local contracted artifacts to the Cloud Silver Storage.
210+
7. Resource Reclamation: Purge transient directories (raw/contracted) to optimize memory.
211+
8. Hydration (Sync Download): Restore local environment with the full accumulated Silver state.
212+
9. Integration (Assembly): Flatten relational data into a unified Gold event layer.
213+
10. Modeling (Semantic): Build entity-centric analytical modules (Fact/Dim).
214+
11. Gate III (Pre-Publish): Final verification of semantic artifact completeness.
215+
12. Activation (Publish): Atomic swap of the production 'latest' version pointer.
216+
13. Finalization: Persist all telemetry/logs to Cloud and purge the local workspace.
217+
218+
Operational Guarantees:
219+
- Defensive Integrity: No data moves to 'Assembly' without passing 'Revalidation'.
220+
- Silver Continuity: Uses a Cloud-Sync loop to ensure Assembly operates on the full delta state.
221+
- Resource Stewardship: Mandatory local cleanup via global 'finally' block to prevent disk leaks.
222+
- Traceability: Enforces atomic 'run_id' consistency across all 13 lifecycle steps.
223+
- Visibility: Guarantees cloud-upload of stage reports even in partial failure scenarios.
215224
"""
216225

217226
run_context = RunContext.create()
@@ -223,7 +232,7 @@ def main() -> None:
223232
try:
224233

225234
download_raw_snapshot(run_context)
226-
initiliaze_metadata(run_context)
235+
initialize_metadata(run_context)
227236

228237
run_initial_validation_stage(run_context)
229238
run_contract_application_stage(run_context)

data_pipeline/semantic/semantic_executor.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from data_pipeline.shared.run_context import RunContext
99
from data_pipeline.shared.loader_exporter import load_historical_table, export_file
1010
from data_pipeline.semantic.semantic_logic import init_report, log_error, log_info
11-
from data_pipeline.semantic.registy import SEMANTIC_MODULES
11+
from data_pipeline.semantic.registry import SEMANTIC_MODULES
1212

1313

1414
def task_wrapper(
@@ -111,11 +111,11 @@ def orchestrate_module(
111111
Coordinates the construction, validation, and export of a semantic module.
112112
113113
Workflow:
114-
1. Build: Executes the module-specific builder logic.
115-
2. Loop: Iterates through each returned table in the builder output.
116-
3. Validate: Enforces technical contracts (grain, schema, dtypes).
117-
4. Export: Persists validated artifacts to the semantic zone.
118-
5. Cleanup: Manages memory via explicit deletion and garbage collection.
114+
1. Build: Executes the module-specific builder logic.
115+
2. Loop: Iterates through each returned table in the builder output.
116+
3. Validate: Enforces technical contracts (grain, schema, dtypes).
117+
4. Export: Persists validated artifacts to the semantic zone.
118+
5. Cleanup: Manages memory via explicit deletion and garbage collection.
119119
120120
Invariants:
121121
- Fail-Fast: Any error in building or table-level processing halts the module.
@@ -188,10 +188,10 @@ def build_semantic_layer(run_context: RunContext) -> Dict:
188188
Main entry point for the Gold-to-Semantic stage.
189189
190190
Workflow:
191-
1. Source Verification: Loads 'assembled_events' and halts if empty/missing.
192-
2. Registry Execution: Iterates through 'SEMANTIC_MODULES'.
193-
3. Orchestration: Triggers builder logic followed by contract enforcement.
194-
4. Cleanup: Purges memory after each module export.
191+
1. Source Verification: Loads 'assembled_events' and halts if empty/missing.
192+
2. Registry Execution: Iterates through 'SEMANTIC_MODULES'.
193+
3. Orchestration: Triggers builder logic followed by contract enforcement.
194+
4. Cleanup: Purges memory after each module export.
195195
196196
Guarantees:
197197
- Atomicity: Module failures are trapped but mark the entire stage as 'failed'.

data_pipeline/validation/validation_executor.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ def apply_validation(run_context: RunContext, base_path: Path | None = None) ->
2828
subsequent Contract and Assembly stages.
2929
3030
Workflow:
31-
1. Loading: Iteratively fetches logical tables from the snapshot zone.
32-
2. Base Check: Enforces schema, uniqueness, and null constraints via 'run_base_validations'.
33-
3. Role Dispatch: Executes specialized logic (Event/Transaction) based on 'TABLE_CONFIG'.
34-
4. Referential Check: Evaluates inter-table integrity (orphans) via 'run_cross_table_validations'.
31+
1. Loading: Iteratively fetches logical tables from the snapshot zone.
32+
2. Base Check: Enforces schema, uniqueness, and null constraints via 'run_base_validations'.
33+
3. Role Dispatch: Executes specialized logic (Event/Transaction) based on 'TABLE_CONFIG'.
34+
4. Referential Check: Evaluates inter-table integrity (orphans) via 'run_cross_table_validations'.
3535
3636
Operational Guarantees:
3737
- Diagnostic Only: This function is read-only and will never mutate the source data.

docs/assembly_stage.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# **Assembly Stage**
2+
3+
**Files:**
4+
* **Executor:** [`assembly_executor.py`](../data_pipeline/assembly/assembly_executor.py)
5+
* **Logic:** [`assembly_logic.py`](../data_pipeline/assembly/assembly_logic.py)
6+
7+
**Role:** Data Integration and Analytical Flattening.
8+
9+
## **System Contract**
10+
11+
**Purpose**
12+
13+
Integrates multiple normalized relational tables into a unified, analytical "Event" dataset and extracts high-fidelity "Dimension" references. It transforms raw business facts into a ready-to-model state by enforcing cardinality rules and calculating temporal performance metrics.
14+
15+
**Invariants**
16+
* **Strict Order-ID Grain:** The primary event output is guaranteed to be exactly 1 row per `order_id`. Any operation causing cardinality explosion triggers a terminal failure.
17+
* **Inner-Join Priority:** To maintain analytical integrity, orders without corresponding items are purged.
18+
* **Temporal Determinism:** All lead times, lags, and delays are calculated as integer-day durations based on validated UTC timestamps.
19+
* **Reference Uniqueness:** Dimension reference tables (Customers, Products) are strictly deduplicated by their primary keys.
20+
21+
**Inputs**
22+
* `run_context`: `RunContext` (Path resolution for Silver/contracted and Gold/assembled zones).
23+
* **Source Tables:** `df_orders`, `df_order_items`, `df_payments` (from the contracted layer).
24+
25+
**Outputs**
26+
* **Assembly Report:** `dict` (Step-level status and informational logs).
27+
* **Assembled Events:** `parquet` (The unified analytical order-grain table).
28+
* **Dimension Refs:** `parquet` (Unique snapshots of customer and product attributes).
29+
30+
## **Execution Workflow**
31+
32+
The **Executor** coordinates two distinct sub-orchestrations:
33+
34+
### **Workflow I: Event Assembly**
35+
1. **Batch Load:** Fetches the required triplet (`orders`, `items`, `payments`) from the Silver zone.
36+
2. **Merge:** Joins datasets using `merge_data`. It performs an inner join on items and a left join on payments to preserve financial data without losing order context.
37+
3. **Derivation:** Executes `derive_fields` to calculate fulfillment lead times and extract ISO-calendar attributes.
38+
4. **Schema Freeze:** Projects the final `ASSEMBLE_SCHEMA` and casts all columns to `ASSEMBLE_DTYPES`.
39+
5. **Export & Clean:** Persists the table and triggers `gc.collect()` to free memory before dimension processing.
40+
41+
### **Workflow II: Dimension Reference Extraction**
42+
1. **Selection:** Iterates through the `DIMENSION_REFERENCES` registry.
43+
2. **Deduplication:** Extracts the required column subset and drops duplicate primary keys.
44+
3. **Export:** Persists each dimension (e.g., `df_customers`) as an independent artifact.
45+
46+
## **Boundaries**
47+
48+
| This component **DOES** | This component **DOES NOT** |
49+
| :--- | :--- |
50+
| Join multiple relational tables into a flat grain. | Perform data cleaning (handled in Contract stage). |
51+
| Calculate time-deltas (e.g., `lead_time_days`). | Perform complex multi-stage aggregations (delegated to Semantic stage). |
52+
| Enforce 1:1 cardinality for the final event grain. | Handle schema validation of raw data. |
53+
| Deduplicate dimension attributes. | Manage partitioning logic (managed by the loader/exporter). |
54+
| Manage peak memory via explicit `gc` triggers. | Change historical values or re-map IDs. |
55+
56+
## **Failure & Severity Model**
57+
58+
### **Operational Failures (System Level)**
59+
* **Loading Missing Table:** If a required table (e.g., `df_orders`) is missing from the Silver zone, the stage returns `failed` immediately.
60+
* **Export Failure:** Disk I/O errors or path resolution issues during the `export_file` call halt the lifecycle.
61+
62+
### **Functional Findings (Data Level)**
63+
64+
* **Cardinality Explosion:** If `merge_data` detects multiple rows for a single `order_id`, it raises a `RuntimeError`, treating it as a fatal violation of the analytical grain.
65+
* **Reference Duplication:** If a dimension table contains duplicate primary keys after extraction, it raises a `RuntimeError` to prevent downstream join corruption.
66+
* **Partial Payments:** Orders without payments are allowed (via Left Join); the system fills these with `None/NaN`, which is considered a valid business state rather than a failure.

0 commit comments

Comments
 (0)