# Shared Contracts This directory contains wire-contract artifacts shared with `dag-ml-data`, plus DAG-ML-specific publication schemas. `dag-ml` remains the consumer and semantic validator: it checks fingerprints, campaign fold membership, OOF boundaries and leakage policies before any controller receives a handle. ## Heterogeneous Multi-Source Vocabulary and Evolution The heterogeneous multi-source repetitions roadmap (`docs/HETEROGENEOUS_MULTISOURCE_REPETITIONS_ROADMAP.md`) extends several of the schemas below with optional unit-level fields. `docs/adr/ADR-19-multisource-unit-vocabulary.md` freezes the vocabulary (`physical_sample`, `source_sample`, `observation`, `combo`, `EntityUnitLevel`, `PredictionUnitId`, `ReductionPlan`, `RepresentationPlan`, `FitInfluencePolicy`) and records the mainline decision that combos are relation-backed derived observations rather than a public `PredictionLevel`. Each phase that touches a contract here follows the ADR-19 / ADR-02 checklist: optional fields first, defaults/dual-read, fixture and conformance-pack update, CHANGELOG entry, and an explicit C ABI decision. A first-class public `combo` / `source_sample` prediction level remains deferred and gated. ## Coordinator Data Plan Envelope v1 Schema: `coordinator_data_plan_envelope.schema.json` Canonical fixture: `examples/fixtures/data/coordinator_data_plan_envelope_nir.json` Conformance pack: `conformance_pack.v1.json` Parity oracle handoff: `parity_oracle.v1.json` Public C ABI snapshot: `abi_snapshot.v1.json` Runtime type consumed here: `ExternalDataPlanEnvelope` Producer type in `dag-ml-data`: `CoordinatorDataPlanEnvelope` The envelope binds a data plan to stable schema, plan and relation fingerprints. It may carry coordinator relation records for sample, target, group, origin, source and augmentation identity. The JSON Schema documents the portable shape of that envelope; Rust validation enforces the stronger semantic rules that depend on the active campaign. Short-term policy: both repositories keep a JSON-identical conformance fixture for this envelope plus a copy of the v1 schema, and test that the published artifact declares the Rust-supported version. `scripts/validate_contracts.py` compares the fixture and schema copies when `DAG_ML_DATA_REPO` points to a sibling checkout, validates the shared conformance-pack digests, and CI checks out that peer explicitly. When development moves into a monorepo, this file should become a single generated or shared contract artifact used by both crates. The D8 multisource audit extends the shared conformance pack with seven named scenarios: `multisource_a2_b3_c2.v1`, `sample_level_late_fusion.v1`, `cartesian_combo_to_sample_reducer.v1`, `missing_source_with_fallback.v1`, `stacking_oof_contract.v1`, `invalid_unit_join.v1` and `row_vs_sample_selection_mismatch.v1`. These scenarios bind the D1-D7 public surface changes to schema digests, canonical fixtures and concrete Rust/contract test references. They intentionally remain metadata: the core still validates relations, fingerprints, OOF safety and representation replay without owning feature buffers or host model objects. ## Parity Oracle v1 Manifest: `parity_oracle.v1.json` This is the producer-side handoff for the future `nirs4all` compatibility ledger. It does not wire `nirs4all`; instead it names the parity cases, fixtures, Python/WASM gates and invariants that the consumer ledger must bind to public API rows before bridge work starts. `scripts/validate_contracts.py` checks the manifest shape, verifies referenced `dag-ml`/`dag-ml-data` fixtures when the sibling checkout is present, pins its digest in `conformance_pack.v1.json`, and requires the manifest to stay byte-identical across both repositories. ## Public C ABI Snapshot v1 Snapshot: `abi_snapshot.v1.json` Header: `crates/dag-ml-capi/include/dag_ml.h` `scripts/validate_abi_snapshot.py` checks the header SHA-256 against the snapshot and runs in CI. Any C ABI header change must update this manifest in the same review so downstream hosts can see the ABI movement explicitly. The shared `dag-ml-data` conformance pack also requires the producer-side multi-target Arrow helper `dagmldata_coordinator_multi_target_arrow_json`, which is consumed as a data provider capability rather than as a `dag-ml` header symbol. ## Coordinator Branch View v1 Schema: `coordinator_branch_view.schema.json` Mirrors `dag-ml-data`'s `coordinator_branch_view.v1` byte-for-byte except for the `$id` (each repo declares its own domain). The normalized SHA-256 (with `$id` stripped) is pinned identically in both repos' `conformance_pack.v1.json` so the wire contract cannot drift. `BranchViewPlan` records in `dag-ml`/`crates/dag-ml-core/src/data.rs` accept the same shape and the in-memory `dag-ml-data` provider executes `by_source` natively. ## Fitted Adapter Ref v1 Schema: `fitted_adapter_ref.schema.json` Mirrors `dag-ml-data`'s `fitted_adapter_ref.v1` byte-for-byte except for the `$id`. Same normalized-SHA-256 enforcement in both `conformance_pack.v1.json` files. The producer type is `FittedAdapterRef` in `dag-ml-data`; `dag-ml` relies on this schema to validate fitted-adapter records that flow through the data layer at refit time. ## Feature Fusion Selector v1 Schema: `feature_fusion_selector.schema.json` Canonical fixture: `examples/fixtures/data/feature_fusion_selector_nir_chem.json` Runtime shape passed through data-provider `feature_arrow` when the provider supports `dag-ml-data` multi-source fusion: `{ schema_version, feature_set_id, sources, alignment, combination_plan?, representation_plan?, policy? }`, where each source maps a `source_id` to a provider-owned `feature_set_id` and optional column subset. The optional D6 plans describe host-owned representation work such as cartesian, sampled cartesian, fixed stack and padded/masked stack materialization; the core validates identity, unit, replay and provenance contracts without materializing feature buffers. This keeps `DagMlDataVTable` ABI-compatible while making feature fusion explicit. ## GraphSpec v1 Schema: `graph_spec.schema.json` Canonical fixture: `examples/branch_merge_oof_graph.json` Runtime type: `GraphSpec` C ABI: `DAG_ML_GRAPH_SPEC_SCHEMA_VERSION`, `dagml_graph_spec_contract_json`, `dagml_graph_validate_json` This is the portable graph object produced by the DSL compiler and consumed by the execution-plan builder. The schema documents node kinds, ports, edge contracts, OOF prediction edges and lineage propagation flags so host bindings can reject malformed graph JSON before controller resolution or scheduling. Rust validation remains the semantic authority for uniqueness, endpoint checks, port-kind alignment and cycle refusal. Prediction-stacking meta-nodes reserve the optional node metadata key `stacking_oof_refit_contract`. Its current shape is `{"policy": "require_full_coverage" | "cv_only" | "skip_refit_on_incomplete_oof"}`. The default is `require_full_coverage`: REFIT consumes validation OOF only when the producer covers the complete refit sample universe. `cv_only` always skips the stacking node during REFIT, while `skip_refit_on_incomplete_oof` skips only when otherwise well-formed validation OOF is incomplete. Invalid OOF still fails with a stable cause such as `partial_oof_without_policy` or `non_validation_partition`; Rust validates the metadata object and the OOF coverage semantics. ## Pipeline DSL v1 Schema: `pipeline_dsl.schema.json` Canonical compatibility fixture: `examples/pipeline_dsl_nirs4all_compat.json` Runtime parser: `parse_pipeline_dsl_json` C ABI: `DAG_ML_PIPELINE_DSL_SCHEMA_VERSION`, `dagml_pipeline_dsl_contract_json`, `dagml_pipeline_dsl_validate_json`, `dagml_pipeline_dsl_compile_json`, `dagml_pipeline_dsl_compile_artifact_json`, `dagml_pipeline_dsl_execution_plan_build_json` This is the public input contract for both canonical `PipelineDslSpec` JSON and serialized nirs4all-style list/dict JSON. The schema documents the accepted portable surface: canonical step kinds plus compatibility keys such as `pipeline`, `preprocessing`, `model`, `branch`, `merge`, `split`, `sources`, `_or_`, `_cartesian_`, `_chain_`, `_grid_`, `_range_`, `_log_range_`, `_zip_` and `_sample_`. The compatibility profile also accepts minimal nirs4all-style operator aliases: short strings such as `SNV`/`PLSRegression`, plain `{"class": ...}` / `{"function": ...}` / `{"ref": ...}` objects, and `{"name": ..., "step": ...}` wrappers. Rust classifies those aliases only far enough to build the safe plan: splitters become campaign `SplitInvocation` entries, obvious estimators become model nodes, obvious tuners such as `OptunaTuner` become tuner nodes, chart aliases become chart nodes, and everything else remains an external transform for host controller resolution. When the compiler is given controller manifests (`compile-pipeline-dsl --controllers` or `build-pipeline-dsl-plan`), selector-only aliases can refine this default before graph ports are frozen: a custom bare alias such as `ElasticSpectra` may become a model if exactly one operator kind claims it through `operator_selectors`. Cross-kind matches are rejected and must use explicit DSL syntax. Rust validation remains the semantic authority: it lowers compatibility JSON into canonical DSL, compiles the graph/campaign/generation artifact, rejects unsafe augmentation/shape contracts and enforces OOF graph edges. External tuner/finetune controllers are canonical operator steps. `kind: "tuner"` and its alias `kind: "finetune"` compile to `NodeKind::Tuner`, preserve public tuning metadata and produce fold-aligned OOF prediction outputs like model nodes; the actual search implementation remains in the host controller. Runtime data generators are canonical operator steps, separate from compile-time search-space generators. `kind: "data_generation"` and its alias `kind: "generation"` compile to `NodeKind::Generator` and require a public `shape` contract so synthetic samples/features can be scoped to fold-train data, audited through origin/group/target inheritance and executed by an external controller. ## CampaignSpec v1 Schema: `campaign_spec.schema.json` Canonical fixture: `examples/campaign_oof_generation.json` Runtime type: `CampaignSpec` C ABI: `DAG_ML_CAMPAIGN_SPEC_SCHEMA_VERSION`, `dagml_campaign_spec_contract_json`, `dagml_campaign_validate_json` This is the portable experimental-plan contract layered beside the graph. It keeps split invocation, concrete fold sets, leakage-unit policy, repeated-sample aggregation policy, generation/search dimensions, data/model shape plans and data bindings outside operator nodes. Selector-driven separation branches are recorded here as `branch_view_plans`, so source/metadata/tag/filter branch views can be materialized by data-provider bindings without turning splits or filters into graph operators. Rust validation remains the semantic authority for fold membership, leakage guards, generation consistency, shape-plan/key alignment, branch-view selector sanity and data-binding fingerprint requirements. ## ExecutionPlan v1 Schema: `execution_plan.schema.json` Canonical fixture: `examples/fixtures/runtime/execution_plan_branch_merge_executable.json` Runtime type: `ExecutionPlan` C ABI: `DAG_ML_EXECUTION_PLAN_SCHEMA_VERSION`, `dagml_execution_plan_contract_json`, `dagml_execution_plan_validate_json` This is the compiled, scheduler-ready DAG contract. It binds the validated graph, campaign, resolved controller manifests, per-node execution policies, generation variants, fold set and canonical fingerprints used later by bundles, replay and provenance exports. The schema documents the portable envelope and critical coordination fields; Rust validation remains the authority for DAG topology, controller-policy consistency, OOF capability checks, fold semantics, shape/data binding checks and fingerprint consistency. ## ModelInputSpec v1 Schema: `model_input_spec.schema.json` Canonical fixture: `examples/fixtures/data/model_input_spec_tabular_regressor.json` Runtime type: `ModelInputSpec` C ABI: `DAG_ML_MODEL_INPUT_SPEC_SCHEMA_VERSION`, `dagml_model_input_spec_contract_json`, `dagml_model_input_spec_validate_json` This neutral contract is the data/model compatibility request declared by a controller or binding. It lists required input ports, accepted representations/types, tensor rank expectations, multi-source support and the default fusion policy to ask from a data planner. For a multi-source `concatenate_features` request, the concrete `DataBinding.metadata.source_index` map is the required source-concat layout hint. It maps each source id to its feature-axis block index and is propagated into `DataProviderViewSpec.extra.source_index`; without it the planner refuses the binding with a structured `dagml.data_requirement.*` code instead of silently treating early fusion as ordinary flat features. `by_source` branches remain single-source per branch unless a future contract explicitly supports grouped source branches. ## DataPlan v1 Schema: `data_plan.schema.json` Canonical fixture: `examples/fixtures/data/data_plan_tabular_fusion.json` Runtime type: `DataPlan` C ABI: `DAG_ML_DATA_PLAN_SCHEMA_VERSION`, `dagml_data_plan_contract_json`, `dagml_data_plan_validate_json` This neutral contract is the data-planner answer to a `ModelInputSpec`: a deterministic sequence of materialize/adapt/align/join/collate steps plus the named outputs that feed model ports. DAG-ML validates ordering, output references and refusal metadata before such a plan can become part of an execution plan or bundle. ## ControllerManifest v1 Schema: `controller_manifest.schema.json` Canonical fixture: `examples/fixtures/runtime/controller_manifest_data_aware_model.json` Runtime type: `ControllerManifest` C ABI: `DAG_ML_CONTROLLER_MANIFEST_SCHEMA_VERSION`, `dagml_controller_manifest_contract_json`, `dagml_controller_manifest_validate_json`, `dagml_controller_manifest_list_validate_json` This is the binding-facing contract each external controller registry must publish. It declares the controller id/version, operator kind, phase support, ports, deterministic/replay capabilities, fit scope, RNG policy, artifact policy and optional `ModelInputSpec` data requirements. The schema is the portable shape; Rust validation remains the authority for registry uniqueness, phase/fit-scope consistency, capability/port consistency and typed `data_requirements` semantics. `operator_selectors` are the minimal-alias bridge used by bindings. A host can publish a `TransformerMixin` controller that matches aliases such as `SNV`, plain strings such as `StandardScaler`, a tuner controller that matches `OptunaTuner`, or class/function/ref/type descriptors; Rust keeps the operator payload opaque, uses selectors to classify bare aliases when manifests are available at compile time, and routes the node to the matching controller before execution. ## NodeTask / NodeResult v1 Schemas: `node_task.schema.json`, `node_result.schema.json` Canonical fixtures: `examples/fixtures/runtime/node_task_transform_scale.json`, `examples/fixtures/runtime/node_result_transform_scale.json` Runtime types: `NodeTask`, `NodeResult` C ABI: `DAG_ML_NODE_TASK_SCHEMA_VERSION`, `DAG_ML_NODE_RESULT_SCHEMA_VERSION`, `dagml_node_task_contract_json`, `dagml_node_result_contract_json`, `dagml_node_result_validate_for_task_json` These are the direct wire contracts between the Rust coordinator and external operator controllers. `NodeTask` carries the resolved node plan, phase, variant/fold context, handles, data views, OOF prediction inputs, refit artifact inputs and deterministic seed. `NodeResult` returns output handles, sample predictions, optional observation-level predictions, optional aggregated sample/target/group predictions, shape deltas, artifacts and lineage. Rust validates every result against the exact task before committing it, including node/run/phase/fold, variant, controller, seed, params fingerprint, shape fingerprints, output ownership and artifact handle consistency. ## SelectionPolicy / SelectionDecision v1 Schemas: `selection_policy.schema.json`, `selection_decision.schema.json` Canonical fixtures: `examples/fixtures/bundle/selection_policy_rmse.json`, `examples/fixtures/bundle/selection_decision_branch_b0.json` Runtime types: `SelectionPolicy`, `SelectionDecision` C ABI: `DAG_ML_SELECTION_POLICY_SCHEMA_VERSION`, `DAG_ML_SELECTION_DECISION_SCHEMA_VERSION`, `dagml_selection_policy_contract_json`, `dagml_selection_decision_contract_json`, `dagml_selection_policy_validate_json`, `dagml_selection_decision_validate_json` These contracts preserve the selection boundary used before refit/replay: metric name/objective, optional required prediction level (`observation`/`sample`/`target`/`group`), selected candidate, selected score and the deterministic ranked candidate list. Rust validation remains the semantic authority for rank continuity, selected-candidate consistency, duplicate candidates and finite selected scores. ## DAG-ML OpenLineage Facets v1 Schema: `openlineage_dagml_facets.schema.json` This is a DAG-ML-specific publication contract, not a shared `dag-ml-data` wire contract. `export-open-lineage` derives an OpenLineage `RunEvent` from an already validated research provenance package and uses these custom `dagml_*` facets to preserve DAG-ML fingerprints, OOF coverage counters, unsafe flags and bundle/plan identifiers that OpenLineage does not model natively. ## Prediction Cache Tensor Metadata v1 Schema: `prediction_cache_tensor_metadata.schema.json` This C ABI metadata contract accompanies `dagml_prediction_cache_payload_f64_tensor_json`. The tensor carries contiguous row-major F64 prediction values; the metadata carries the stable requirement key, cache id, prediction level, block offsets, fold ids, sample ids, unit ids and target names required to interpret rows without hiding traceability inside the value buffer. ## Prediction Cache Columnar Tensor Metadata v1 Schema: `prediction_cache_columnar_tensor_metadata.schema.json` This C ABI metadata contract accompanies `dagml_prediction_cache_payload_f64_columnar_tensor_json`. It keeps the same traceability fields as the row-major export and adds `layout: column_major_f64` plus `column_offsets` so host bindings can read each target column contiguously without guessing buffer order. ## Data Output Provenance v1 Schema: `data_output_provenance.schema.json` Canonical fixture: `examples/fixtures/runtime/data_output_provenance_augmented_view.json` Runtime type: `DataOutputProvenance` C ABI: `DAG_ML_DATA_OUTPUT_PROVENANCE_SCHEMA_VERSION`, `DAG_ML_DATA_OUTPUT_PROVENANCE_EXTRA_KEY`, `dagml_data_output_provenance_contract_json`, `dagml_data_output_provenance_validate_json` This DAG-ML runtime contract is embedded under the reserved `DataProviderViewSpec.extra["dag_ml_output"]` key when a data-producing DAG node emits a downstream data view. It records the producer node/port/phase, variant/fold scope, shape-plan and aggregation fingerprints, current feature schema fingerprint and emitted shape deltas. D6/D7 add optional representation plans, replay manifests, relation-delta fingerprints and train/predict compatibility reports so serve-time missing source or repetition differences are explicit, policy-bound and replayable. Controllers and host bindings can discover and validate this metadata without reverse-engineering free-form JSON or hardcoding Rust-only constants. ## Process Adapter Description v1 Schema: `process_adapter_description.schema.json` Canonical fixture: `examples/fixtures/runtime/process_adapter_description_python.json` Runtime shape returned by process adapters from `--describe`: `{ schema_version, protocol, adapter_id, supported_modes, capabilities }`. C ABI: `DAG_ML_PROCESS_ADAPTER_DESCRIPTION_SCHEMA_VERSION`, `dagml_process_adapter_description_contract_json` This CLI/runtime contract lets the coordinator reject unsupported process adapters before any `NodeTask` is sent. Version 1 requires protocol `dag-ml-process-adapter`, mode declarations for `one_shot`/`jsonl` support and explicit JSON task/result capabilities. Persistent worker and parallel scheduler features remain opt-in capabilities layered on the same description object. ## Process Adapter Frame v1 Schema: `process_adapter_frame.schema.json` Canonical fixtures: `examples/fixtures/runtime/process_adapter_frame_init.json`, `process_adapter_frame_task_transform_scale.json`, `process_adapter_frame_result_transform_scale.json`, `process_adapter_frame_ack_initialized.json`, `process_adapter_frame_error_retryable_timeout.json`, `process_adapter_frame_close.json` Runtime shape used by persistent JSONL process adapters: `init | task | close` coordinator request frames and `ack | result | error` adapter response frames. C ABI: `DAG_ML_PROCESS_ADAPTER_FRAME_SCHEMA_VERSION`, `dagml_process_adapter_frame_contract_json` This contract is enabled only when the adapter description declares `control_frames_v1`. It gives host adapters a stable lifecycle and error surface: `init` carries controller and worker identity, `task` wraps a published `NodeTask`, `result` wraps a published `NodeResult`, `error` carries typed retryability, and `close` gives the coordinator a bounded shutdown path. ## Aggregation Controller Task/Result v1 Schemas: `aggregation_controller_task.schema.json` and `aggregation_controller_result.schema.json` C ABI: `DAG_ML_AGGREGATION_CONTROLLER_TASK_SCHEMA_VERSION`, `DAG_ML_AGGREGATION_CONTROLLER_RESULT_SCHEMA_VERSION`, `dagml_aggregation_controller_task_contract_json`, `dagml_aggregation_controller_result_contract_json`, `dagml_aggregation_controller_task_validate_json`, `dagml_aggregation_controller_result_validate_for_task_json` These contracts define the leakage-sensitive payloads used when aggregation is delegated to an external controller through `AggregationMethod::CustomController`. The task carries the custom aggregation policy, controller id, repeated observation or sample-to-unit inputs, relation metadata and requested output order. The result is validated against the exact task so custom reducers cannot change sample/unit coverage, fold scope, target names or prediction level. ## Research Provenance Package Profile v1 Profile: `research_provenance_package_profile.v1.json` This publication profile declares the required files, optional files, checksum rules, PROV JSON-LD sections, RO-Crate file properties, OpenLineage facets and CLI tests for a DAG-ML research package. It is validated by `scripts/validate_contracts.py` so the human-facing publication contract stays aligned with the Rust/CLI validator. ## Data Provider C ABI v2 The shared provider surface is `DagMlDataVTable` guarded by `DAG_ML_DATA_VTABLE_DEFINED` and versioned by `DAG_ML_DATA_PROVIDER_VTABLE_ABI_VERSION == 2`. `scripts/validate_contracts.py` and the C ABI tests verify that `dag_ml.h` and `dag_ml_data.h` can be included together in either order when the sibling checkout is available.