Architecture

September 17, 2026 ยท View on GitHub

jev-benchmarks separates experiment definition, data selection, inference, validation, and analysis so a model call can never silently rewrite the evaluation contract.

Modules

ModuleResponsibility
config.pyLoad and validate the YAML experiment contract; resolve artifact paths.
data.pyLoad a pinned BTZSC revision, reject targetless rows, sample deterministically, write the manifest.
adapters/Translate a common Example into backend-specific calls and return Prediction.
runner.pyResume append-only runs, validate probability vectors, retain failures and usage.
metrics.pyCompute discrimination, calibration, selective-risk, latency, controls, and paired intervals.
report.pyVerify manifest/prediction identity and produce hashed JSON and Markdown summaries.
io.pyAtomic JSONL writes, durable appends, artifact hashing, and runtime metadata.

Artifact flow

Manifest

prepare writes one JSON object per selected example:

{
  "dataset": "agnews",
  "task": "topic",
  "example_id": "agnews:9",
  "text": "...",
  "text_sha256": "...",
  "labels": ["..."],
  "target_index": 0
}

The ordered labels tuple is part of the evaluation contract. If an existing manifest differs from the deterministic regeneration, preparation fails and requires a new experiment directory.

Predictions

Each backend writes an append-only JSONL record containing requested and resolved model identities, the complete probability vector, target and predicted indices, latency, optional token usage, the raw probability sum, and any error. Successful example IDs are skipped on resume. Failed calls remain in the log and are retried; reporting selects the most recent record for each example.

Report

Before scoring, report generation checks that every backend covers exactly the manifest IDs and that each target and ordered label tuple matches the manifest. The JSON report includes:

  • schema and package versions;
  • the complete experiment config and protocol revision;
  • config, manifest, and prediction-log SHA-256 hashes;
  • resolved model identities;
  • runtime metadata;
  • per-model/per-dataset metrics;
  • paired confidence intervals.

Probability validation

Vectors must have one finite value in [0, 1] for every label. Sums within 0.02 of one are treated as serialization rounding and normalized; the pre-normalization sum is retained. Larger deviations are failures.

The tolerance addresses APIs that expose rounded probabilities. It is not a general repair for unnormalized scores, logits, or independent one-vs-rest probabilities.

Selective coverage

Coverage at an error budget is computed only at thresholds realizable from reported confidence values. Every example tied at a threshold is accepted together. This avoids optimistic coverage that could only be achieved by splitting identical scores.

The pilot chooses and evaluates the threshold on one slice. A confirmatory experiment should select the threshold on validation data and report risk once on a disjoint test set.

Extension points

Backends implement the Backend protocol in adapters/base.py. Dataset loaders emit the common Example type. The current CLI lists supported backend names explicitly so adding a provider is a reviewed API change rather than dynamic code loading.

Heavy dependencies are optional:

  • data: Hugging Face datasets;
  • gliner: GLiNER2, PyTorch, Transformers, tokenizer dependencies;
  • jev: the TypeSafe SDK;
  • benchmark: the complete stack.

Imports occur only when the corresponding command/backend is selected, so metrics and report tooling remain lightweight.