nirs4all.pipeline.dagml.envelope module
Data-plan envelope + fold-set builders for the nirs4all → dag-ml(-data) bridge.
dag-ml-data owns the contract types and the fingerprint algorithm; this module only
assembles the JSON inputs from a SpectroDataset + its IdentityMap and hands
them to the dag_ml_data wheel, which computes every fingerprint internally and derives
coordinator_relations from the SampleRelationTable. We never compute a fingerprint
or hand-build a coordinator relation — that keeps the materialize-time fingerprint gate
passing by construction.
Declares identity only, never X/y values:
the
DatasetSchema(one source, NIR spectrasignal_1d→tabular_numeric),the
DataPlan(materialize → adaptspectra.flatten→ join toport:X),the
SampleRelationTable(one row per observation; input field namesorigin_id/repetition_id/augmented/excluded).
Folds are a separate first-class contract (FoldSet), validated against the
CV-universe relations by validate_fold_set_against_sample_relations — never carried in
the envelope. That validator enforces a clean OOF partition (each sample validated
exactly once): KFold satisfies it; ShuffleSplit does not (a known OOF-semantics gap
flagged for the execution/mechanism phase).
dag_ml_data is a CORE dependency since the ADR-17 cutover; imports are still guarded so a
broken wheel missing the native backend surfaces a clear error rather than a raw ImportError.
Scope: single-source / no-repetition baseline.
- nirs4all.pipeline.dagml.envelope.build_envelope(dataset: SpectroDataset, identity: IdentityMap, *, source_id: str = 'src0', sample_ints: list[int] | None = None, excluded_sample_ints: set[int] | None = None, metadata_by_sample: dict[str, dict[int, Any]] | None = None, tags_by_sample: dict[int, list[str]] | None = None, augmentation_by_sample: dict[int, str] | None = None, group_by_sample: dict[int, str] | None = None, final_sample_ints: list[int] | None = None) dict[str, Any][source]
Build the validated
CoordinatorDataPlanEnvelope.Pass
sample_intsto scope the envelope to a sample universe — e.g. the CV training pool, so the schema +coordinator_relationsmatch the embeddedFoldSetand passvalidate_data_envelope_relations(every relation must live inside the fold set). Omit it for a whole-dataset envelope.Pass
excluded_sample_ints(a subset ofsample_ints) to mark those rowsexcluded: true— the opt-inkeep_in_oof=Trueexclude mode where Phase 1’s native bit drops them from fold TRAIN but keeps them in validation/OOF. Default (None) marks every row not-excluded.Pass
metadata_by_sample({column: {sample_int: value}}) to emit per-sample metadata onto each relation — the nativefan_out_data_aware_branchesreads aby_metadataseparation branch’s partition values from these relation metadata values.Pass
tags_by_sample({sample_int: [tag, ...]}) to emit per-sample tag labels onto the native relations. Untagged rows omit the field.Pass
augmentation_by_sample({sample_int: transform_id}) to attach the structuredaugmentationmetadata to augmented rows (theirorigin_idis always emitted from the identity grain).Pass
group_by_sample({sample_int: group_value}) to emitgroup_idon each relation for a repetition dataset — repetitions of one physical sample share a group value, and dag-ml-data refuses a fold that splits a group across train/validation. For a repetition dataset every relation is its ownsample_id(each stored row is scored individually at the repetition grain), so the schema’s sample axis is one entry per row.Pass
final_sample_intsto request the V2 terminal prediction authority. It must contain every CVsample_intsentry and may add held-out prediction identities. A core that has not negotiated the V2 capability is refused instead of receiving a weakened envelope.The wheel computes all fingerprints and derives
coordinator_relations; a successful return means the envelope is contract-valid (the materialize-time fingerprint gate will accept it).
- nirs4all.pipeline.dagml.envelope.num_targets(dataset: SpectroDataset) int[source]
The number of target columns (
ywidth). 1 for the single-target baseline.
- nirs4all.pipeline.dagml.envelope.sample_relations(identity: IdentityMap, *, source_id: str | None = 'src0', sample_ints: list[int] | None = None, excluded_sample_ints: set[int] | None = None, metadata_by_sample: dict[str, dict[int, Any]] | None = None, tags_by_sample: dict[int, list[str]] | None = None, augmentation_by_sample: dict[int, str] | None = None, group_by_sample: dict[int, str] | None = None) dict[str, Any][source]
The
SampleRelationTablerows, optionally scoped to a sample-int subset.Pass
sample_ints(e.g. the CV training pool) to scope the relations for fold validation; omit it for the full-dataset relations the envelope declares.Pass
excluded_sample_intsto emitexcluded: truefor those rows — the opt-in leakage-pure exclude mode (keep_in_oof=True): Phase 1’s nativeexcludedbit then drops them from each fold’s TRAIN view while keeping them in validation/OOF and predict. Omit it (the default) and every row isexcluded: false— the legacy mode removes excluded samples from the CV universe entirely (they are simply absent from the pool).Pass
metadata_by_sample({column: {sample_int: value}}) to emit per-sample metadata onto each relation (Slice 1metadatafield). The nativefan_out_data_aware_branchesdiscovers a separation branch’s partition values from these relation metadata values, so aby_metadatabranch criterion column must be present here. Omit it and every row carries emptymetadata.Pass
tags_by_sample({sample_int: [tag, ...]}) to emit per-sample tag labels onto each relation. Rows without tags omit thetagsfield so untagged fingerprints stay on the native contract’s skip-if-empty path.Pass
group_by_sample({sample_int: group_value}) to emitgroup_idfor a repetition dataset — several stored rows that share one physical sample carry the same group value (their repetition column). dag-ml-data’svalidate_fold_set_against_sample_relationsthen refuses any fold that splits a group across train/validation (native group-leakage validation), so all repetitions of a sample must stay on the same fold side. Omit it and every row keepsgroup_id = None.Augmented rows (
identityminted on a dataset that already holds the synthetic rows) emitorigin_id= the origin row’sobservation_id(to_wire(origin_int), distinct from the child’s ownobservation_id); theirsample_idstays the origin’s grouping key. Passaugmentation_by_sample({sample_int: transform_id}) to attach the structuredaugmentationmetadata ({transform_id, params_fingerprint}) for those rows. Base rows keeporigin_id = Noneand no augmentation metadata (the dag-ml-data contract rejects an origin or augmentation on a non-augmented row).
- nirs4all.pipeline.dagml.envelope.source_ids(dataset: SpectroDataset) list[str][source]
The per-source ids the schema/plan/binding agree on.
Single-source keeps the legacy
["src0"](BYTE-IDENTICAL); a multi-source dataset (features_sources() > 1) emits["src0", "src1", …]— one perFeatureSource.
- nirs4all.pipeline.dagml.envelope.source_order(dataset: SpectroDataset) list[str][source]
Legacy by_source branch keys in exact source-index order.
Mirrors
BranchController._get_source_nameswithout importing the controller: usedataset.source_name(i)when a dataset exposes it, else fall back tosource_i. These are the user-facing keys legacy by_source dict bodies resolve against, distinct from the native data-plan ids (src0/src1).