Principles
These principles are mandatory. They define what may live in a step package, what belongs in the framework, and how framework modules may depend on each other.
Violations break CI (test_step_domain_boundaries, test_layer_import_boundaries) and make steps non-portable across backends and runtimes.
Two boundary planes
Section titled “Two boundary planes”| Plane | Question | Doc |
|---|---|---|
| Step ↔ framework | Who owns I/O, metrics, UI, orchestration? | Step and framework |
| Inside framework | Which package may import which? | Framework layers |
Axioms (memorize these)
Section titled “Axioms (memorize these)”- Step = transform. Receive data → process → return data. No storage, Prometheus, Airflow, Ray, or file I/O in domain code.
- DRTML = contract. Params, datasets, feed, metrics, UI, and orchestration are declarative. Steps do not parse YAML.
- Framework owns the run. Feed, write, flush, checkpoint, metrics emit, Streamlit forms, Airflow/Ray transport — framework only.
- One dataset — one backend. No dual-write. Dispatch via registries, not
if backend ==. - Layers have a one-way edge.
drtml → contracts / storage.plan → db | storage → processing → telemetry | integration
Reverse edges are forbidden. domain.*is step-only. Framework may pass params through; it must not interpret domain fields.- Algorithms = math. Policy (K, probe, early-stop) stays in the step; formulas live in
framework/algorithms. - Shared DTOs live in
contracts/. Never copy saturation / worker-delta types into storage or telemetry.
Package map
Section titled “Package map”framework package # platform runtime drtml / storage / db / processing / algorithms / telemetry / integration …
step packages # DRTML + pure domain processors (edge / ops / third-party)
platform stack # Docker, CLI, Grafana sync, Postgres bootstrapSteps and platform must not become dependencies of framework Python (except contract tests that load step manifests).
Before you change code
Section titled “Before you change code”Use the checklists on the detailed pages. Short version:
- Is this I/O / wire-format / metrics emit? → framework, not the step.
- New shared type across layers? →
contracts/. - New backend / mode / metric method? → register, do not grow an if-forest.
- Does the import reverse the layer edge? → redesign.
- Does framework Python mention a step id or
domain.*field? → move out.