Reproducible read fixtures¶
Fixture recipes freeze a target, source and selection policy. They do not infer allele/junction/protein support. Classification remains in the evidence-producing library; its versioned assignments become recipe inputs. Selection does not use the current predicted protein and is never a full-source abundance/VAF estimate.
Recipe v1¶
select_fixtures(recipe, sources) accepts a JSON-compatible dictionary with
schema_version: 1, a stable id, and targets, sources, members mappings.
Dataset.select_fixtures runs the identical implementation. sources maps source
IDs to explicit local BAM paths or acquired ReadSubset objects; remote BAMs
must first go through bounded extract_reads. Local archives can be pinned with
archive_sha256 in the recipe's source declaration.
A small-variant target declares kind: small_variant, assembly, pinned
reference identity, coordinates: one-based, contig, position, ref, alt.
An SV declares kind: sv, coordinates: zero-based-interbase, and at least two
breakends with contig, position, orientation (+, -, or null if unknown).
Retain inserted sequence and original source-call/annotation provenance in the
target. kind: unresolved requires a reason and does not acquire/select reads.
A source declares identity (original asset/snapshot/checksum metadata),
assembly, sample, library, and product. Unknown scope is explicitly null.
Different processing products remain separate sources even if they share a
library. CB/UMI labels never merge templates into inferred molecules.
Each member names a target and source, and a policy with version: 1:
| Kind | Selection |
|---|---|
regional |
Candidates overlapping explicit regions, optionally template-capped |
exact |
Required records mapping from record digest to positive multiplicity |
witnesses |
Original source/RG/QNAME/segment selectors with pinned reasons |
stratified |
Required witnesses plus deterministically sampled optional strata |
empty |
Deliberate empty fixture, distinct from unavailable acquisition |
omitted |
Explicit omission with reason |
regions and context_regions contain Region fields: contig, start, end,
assembly (zero-based, half-open). Context records are retained with the reason
assembly context, never promoted to junction support by overlap alone.
Each witness/stratum assignment contains a selector (rg, qname, optional
segment = original FLAG & 0xc0), a reason, and producer name/version.
required defaults true; absence fails. Optional assignments can specify
stratum. cap is an optional-template budget per stratum; strata maps
stratum names to overrides. Required witnesses bypass caps. All records of a
sampled template available in the input survive. seed defaults to the string
0. Hash ordering makes sampling independent of input order. Missing required
record occurrences fail instead of silently weakening a pinned regression.
Duplicate multiplicity is preserved by default. duplicate_policy:
identical-record-once explicitly requests the legacy deduplication behavior.
Shared fixture members reference a source record; their counts must not be
summed as independent evidence. Results distinguish selected, truncated, empty,
unresolved and omitted. Selection returns a manifest of per-record reasons and
multiplicities, along with in-memory original records for export.
Identity and fidelity¶
record_multiset(path) uses bam-record-v1: stored CIGAR, sequence, qualities,
flags and typed auxiliary bytes, with reference names replacing numeric IDs and
the derived bin omitted. Tag order is significant. Float payloads and integer
widths survive; compression and coordinate-order ties do not affect equality.
The encoding follows SAM/BAM ยง4.2.
An exact recipe may explicitly use encoding: sam-text-v1 for historical SAM
checksums. This cannot prove bitwise tag fidelity and rejects a text identity
that ambiguously maps to different binary records. It is not the default.
Named panels and CLI¶
load_panel("vaccine-loci-v1") supplies the pinned historical vaccine alleles;
consumers retain their own reference/correction policies. sv-regressions-v1
pins historical RNA events and the additional 2026-09-23 research panel, retaining
original VCF anchors beside explicitly converted interbase boundaries. A target name alone is never an acquisition selector.
osteosarc fixtures panel vaccine-loci-v1
osteosarc --offline fixtures select recipe.json --source rna=archive.bam
The CLI prints the same membership and reasons as the standalone and Dataset
APIs. Constructors in tests/conftest.py and tests/test_fixtures.py exercise
source/RG collisions, duplicates, required controls, contexts, empty selections,
missing witnesses, float precision and API/CLI conformance without network.
Bounded partner recovery¶
from osteosarc import RecoveryPolicy, extract_reads
subset = extract_reads(source, seed_and_context_regions, cache=cache,
recovery=RecoveryPolicy(max_rounds=4, max_intervals=128,
max_bases=1_000_000,
max_records=100_000))
The seed union preserves every available record. Distant mate/SA windows retain only matching source/RG/segment observations; SA requires matching position, strand, CIGAR and MAPQ, plus NM when present. Hard clipping, absent SEQ/QUAL, secondary/supplementary flags and tags are unchanged. Duplicate counts use the maximum occurrence count across indexed queries, never a set or a sum of repeated retrievals. No query synthesizes a missing partner or reverse-complement read.
The receipt records visited intervals, requested leads, missing/conflicting
partners, malformed SA, missing sequence, ambiguous placement, repeated/cyclic
leads, and acquisition limits. complete_template is always false. Even a fully
resolved SA graph may omit unreported alignments. Missing indexes fail without a
scan fallback. Interval/round limits produce an explicit truncated receipt;
record overflow fails instead of publishing a partial successful artifact.
Seed interval/base limits are checked against the resolved union before read
extraction. The record budget covers every acquired candidate, including records
that do not match a partner pointer; extraction stops on overflow. Previously
fetched candidates remain available when a later mate or SA link points into an
already visited window, without an additional query.
Changed sources/headers/indexes fail across steps. Interrupted runs reuse only
verified intermediate extractions.
A member can set retain_partners: true to retain recovered mates/split records
for its selected templates, carrying the recovery reasons. acquisition_status
is separate from selection status: zero retained records in bounded or truncated
input is not evidence of zero support in the source. CLI extraction also supports
reads --recover-linked. The existing fetch_pairs behavior remains unchanged;
choose a recovery policy instead of combining those options.
Portable bundles¶
generate_bundle(recipe, destination, sources=..., cache=...) acquires declared
inputs, selects, and publishes a self-contained directory. pack_bundle(selection,
destination) starts from an existing selection. Destinations must be new.
Dataset.generate_bundle also checks source identities against its snapshot.
A source may declare a small historical archive with url, sha256, and
size_bytes, or identity.url, index and bounded regions for live indexed
acquisition. Member regions are the fallback acquisition union. Source
acquisition holds explicit filters/recovery settings. Explicit local sources
are verified against any declared archive hash. Interrupted extraction can reuse
the existing verified Cache derivatives. Normal installation never acquires data.
Indexed acquisition preserves declared inventory size and modification metadata;
the Dataset API also accepts an identity containing only a snapshot key or ID.
The bundle stores a shared source record pool, indexed BAMs, full original headers,
recipe, acquisition receipts, source/sample/library/product identities, member
multiplicity and reasons, tool versions, parent lineage, and file hashes/sizes.
redistribution in the recipe carries source-license/citation information; absent
license information remains unresolved. Remote HTTP identity is preserved as HTTP
evidence, separate from archive or full-file SHA256. Historical receipt paths are
audit strings, never dependencies for offline verification or export.
header_policy="full" is the default. Compact mode keeps every SQ (including
assembly-identifying contigs), source comments, retained RG/SM/LB metadata, and
required PG ancestry. When producer lineage is unresolved it retains all PGs.
Neither mode invents missing source metadata. Sorting only updates HD sort fields;
the full original header remains archived. This avoids weakening assembly guards
for downstream offline use.
verify_bundle(directory, sha256=pinned_manifest_hash) checks all files, the
recipe digest, source/member record multisets and index enumeration. Pin the
manifest hash when consuming an external release; internal consistency checks
alone are not an authenticity signature. record_multiset separately supports
lossless equivalence comparisons across compression/tool versions. Exact BAM
byte reproducibility requires the same recorded pysam/HTSlib toolchain.
export_bundle(bundle, destination, members=[...]) adds named, coordinate-sorted,
indexed BAM exports, retaining the self-contained source pool and provenance.
format="sam"/"sam.gz" explicitly requests legacy SAM-text fidelity. Empty
members export valid empty indexed BAMs. Unresolved/omitted members stay declared
without fabricated data. The default size budget is 64 MiB including metadata;
set a smaller size_budget for a consumer's package. Publication is atomic only
after verification, and existing destinations are refused.
Exporting an exported bundle is supported: each request replaces the named export
set in the new destination, so changing format leaves no stale export files.
SAM exports use coordinate order, consistent with their headers. Verification
checks member counts/status and SAM field multisets as well as BAM identities.
osteosarc --offline fixtures generate recipe.json bundle --source rna=archive.bam
osteosarc fixtures verify bundle
osteosarc fixtures list bundle
osteosarc fixtures export bundle exported --member example
The constructors in tests/test_bundles.py demonstrate generation, packing,
export and verification in a fresh offline directory after deleting the input
BAM. Corrupt records, missing duplicates, nested members, recipe changes, swapped
indexes, unsafe paths and size-budget failures are separate regressions.