Skip to content

Complete ground truth and evaluation metadata

Data contract

Ground truth remains opt-in and never enters X, feature computation or obs implicitly. The native AnnData orientation remains snapshots × features. Version 0.3.0 adds an independent, lossless evaluation archive and explicit per-waveform annotations to the existing snapshot view.

Location Meaning
obsm['ground_truth'] Snapshot labels in the exact obs_names order, when a snapshot table exists
obsm['waveform_ground_truth'] One records_json cell per snapshot; zero or more waveform records with channel bindings
uns['vibframe_evaluation'] Original sidecar byte buffers and a source/path/SHA-256 manifest
uns['vibframe_anndata']['ground_truth'] Snapshot alignment diagnostics and provenance
uns['vibframe_anndata']['waveform_ground_truth'] Waveform alignment diagnostics and provenance
obsm['raw_waveforms_capture_t'] / raw_spectra_capture_t Actual capture t in integer microseconds UTC
Corresponding *_capture_t_known matrices True for explicitly supplied t; false for legacy fallback/missing captures

The original archive uses vibframe-evaluation-bytes/1; aligned waveform records use snapshot-aligned-json-records/1. Numeric capture times use the same channel columns as raw_*_lengths. An absent capture has length zero and a false known flag. Do not interpret its integer sentinel as a date. A present legacy capture without t falls back to snap_t, with known == False.

What is preserved

All regular files recursively below evaluation/, ground-truth/, ground_truth/ are preserved, not only a hard-coded subset of columns. Root .json, .yaml, .yml documents and machine=*/*.json context are preserved too. This covers construction truth, waveform duration, offset, quantization and hashes; machine parameters; paired controls; scenario/spectral configuration; normative *.diaggt.json; observations.parquet, observations_consolidated.parquet, findings.parquet; and materialization manifests.

Original bytes retain nulls, nested Arrow structures, large integer values, JSON number spelling, unknown future fields, schema metadata and file hashes. Convenience aligned views may stringify nested/object columns for H5AD compatibility. Use read_evaluation_table for the original Arrow schema or read_evaluation_file for exact bytes. Files are never executed. Symlinks, unsafe paths and unfinished .inprogress, .partial, .tmp files are rejected or excluded as documented.

This is not a second raw-signal archive. Raw waves.parquet, spectra.parquet and trends.parquet outside these annotation roots are not copied into it. Trend values remain a numerical-regression oracle, never a source of calculated features.

Import a complete dataset

from vibframe_anndata import import_raw_to_h5ad

base = import_raw_to_h5ad(
    "DRMHB-compact.vibframe.zip",
    "DRMHB-raw.h5ad",
    config={
        "version": 1,
        "raw_import": {"on_missing_signal": "nan"},
        "ground_truth": {
            "enabled": True,
            "scope": "all",
            "on_missing": "error",
            "max_sidecar_mib": 512,
        },
        "output": {"dtype": "float32"},
    },
    block_size_mib=8,
)

The same configuration works with import_raw() when signals and annotations fit comfortably in memory. scope: snapshot selects the previous snapshot-only footprint. With enabled: false (the default), no evaluation archive or aligned labels are imported.

all supports a source that has DiagGT but no construction snapshot table: its diagnostic files are preserved without fabricating obsm['ground_truth']. A mixture of sources may expose different truth families. If a source declares a snapshot/waveform table, strict mode checks its coverage; it does not require an unrelated source to provide a table it never declared.

Exact alignment rules

Snapshots are joined by (source, machine_id, snap_t), never by row order. Integer times are Unix-epoch microseconds UTC. Fractional numeric timestamps, ambiguous floating-point integers, null identities and conflicting timestamp/snap_t fields fail. Datetime-typed values are explicitly normalized to microseconds. No seconds/milliseconds heuristic is applied.

Waveforms additionally match point_id and any supplied proc_mode_id, mode_definition_id or config_id against the actual raw channels present at that snapshot. Omitted mode identifiers are accepted only when the match is unambiguous. Two annotations cannot bind the same raw capture. Capture t is not snap_t: a cropped waveform starts later than its parent snapshot.

on_missing: error rejects missing declared labels or unresolved/ambiguous waveform bindings. ignore retains an explicit unresolved status; it does not guess the channel. A spectra-only import may still retain waveform annotations as unbound because the waveforms were deliberately not imported. Extra annotation rows remain in the original archive and alignment diagnostics.

Same-named source datasets are disambiguated with hashes of resolved input paths. Record the source paths/set for reproducibility and for retrofitting. A repeated identical source path fails.

Read labels without loading multi-GiB waveforms

from vibframe_anndata import (
    get_snapshot_ground_truth, get_waveform_ground_truth,
    list_evaluation_files, read_evaluation_table, read_evaluation_json,
)

inventory = list_evaluation_files("DRMHB-raw.h5ad")
snapshot = get_snapshot_ground_truth("DRMHB-raw.h5ad")
waveform = get_waveform_ground_truth(
    "DRMHB-raw.h5ad", point_id="pump_DE_H", proc_mode_id="ACC_10K",
)
# Inspect the inventory: choose the exact source/path present in your dataset.
entry = inventory.loc[inventory["path"].str.endswith("observations.parquet")].iloc[0]
observations = read_evaluation_table(
    "DRMHB-raw.h5ad", entry["path"], source=entry["source"],
)

The accessors also accept an in-memory AnnData. Passing a file path opens only annotation and manifest groups, not raw waveform/spectrum arrays. get_waveform_ground_truth returns a convenient long DataFrame with vfta_snapshot_id, vfta_source, vfta_channel_id, vfta_proc_mode_id, vfta_alignment_status and vfta_path. Original fields are kept alongside these binding fields. If the source itself uses a reserved vfta_* name, the convenience view fails instead of silently overwriting it; use the original table accessor.

read_evaluation_file(data, path, source=...) returns byte-exact content and verifies SHA-256 by default. read_evaluation_json parses a selected JSON document. A path present in several sources requires an explicit source. export_evaluation_files(data, destination) writes the original files into source-hash subdirectories and refuses overwrites.

Upgrade an existing 0.2.x H5AD

from vibframe_anndata import add_ground_truth_to_h5ad

add_ground_truth_to_h5ad(
    "DRMHB-features.h5ad",
    "DRMHB-compact.vibframe.zip",
    output="DRMHB-features-complete.h5ad",
)

This operation reads source metadata/annotations, not source raw sample buffers. It copies the existing H5AD transactionally on disk, retains X, var and raw arrays, adds the evaluation archive/projections, validates, then promotes the output. output=None atomically replaces the input. Additional temporary disk space is approximately one H5AD copy. Keep obs.source, obs.machine and obs.snap_t: the operation fails if those identities were removed or if sources cannot be matched. It does not retrospectively recover capture-time companion matrices on legacy H5AD files; those are populated by new raw imports. Snapshot-only refresh preserves an existing complete archive and waveform projection.

Features, slicing and experimental controls

Adding, recalculating or removing features preserves ground truth. Out-of-core feature edits do not decode embedded sidecar buffers. Aligned obsm rows follow AnnData slicing, whereas the original archive is deliberately dataset-wide and remains unchanged after slicing. Exporting it exports the original campaign, not a fabricated per-subset DiagGT manifest.

Controls are not silently merged into the longitudinal benchmark. Keep separate source files or explicitly select their source/pair metadata. Operational-state oracle labels must be copied to a model input only under a declared experimental protocol. Severity, physical-state labels, fault identities, seeds, OOD flags and future labels are not automatic features.

Preservation versus interpretation

Complete retention does not assign arbitrary DiagGT diagnoses or time intervals to every snapshot. For example, consolidated diagnoses have their own validity/deduplication conventions. Researchers must use the original document, table and materialization.json semantics when deriving a target; the package does not substitute nearest-timestamp matching or assume a missing diagnosis means healthy. Snapshot/waveform construction tables have explicit supported alignment rules above.

The reader preserves existing annotations; it does not certify the generator's physical validity, validate all future DiagGT schemas, or infer missing labels. Invalid known alignment is reported; unknown sidecars remain accessible losslessly rather than being dropped.

Storage and memory

No VibFrame ZIP or raw-signal compression setting is modified. The H5AD grows by the sum of original sidecar byte sizes plus the manifest, aligned label views and capture-time matrices. list_evaluation_files reports exact archived sizes per source. The default 512 MiB limit covers encoded original sidecars and can be raised explicitly; it is not a total process-RAM limit. Decoded Parquet/JSON tables and aligned labels consume additional metadata memory. Raw streaming remains blockwise. A single accessor call materializes its selected sidecar/table; large annotation archives should be accessed one table at a time. In-memory AnnData naturally materializes its archive as well as its raw signals. No compression benchmark is repeated by this release.