jevassert
Regression tests for Jev question packs: assert accuracy, calibration and cost in CI, with recordings so runs are deterministic, free and rate-limit free.
Independent community tool. Not affiliated with TypeSafe AI.
Jev returns typed decisions with probabilities, which means two things your
normal test suite cannot check: does the decision match the labels, and
does the stated probability mean what it says. jevassert checks both — and
never calls the model during check, because CI should run on a recording.
record → predictions.jsonl → check (offline, deterministic) → exit 0/1/2
Quickstart
uvx jevassert record examples/demo-triage -o triage.jsonl # needs TYPESAFE_API_KEY
uvx jevassert check examples/demo-triage -p triage.jsonl --failures
record calls Jev once per case (concurrently, with retries) and writes one
JSONL line per case — model version, usage, latency, answers. check replays
that file: no API key, no network, same result every time.
Re-record when the pack questions, the gates or the model version change, then compare:
uvx jevassert record examples/demo-triage -o triage-next.jsonl
uvx jevassert compare examples/demo-triage --a triage.jsonl --b triage-next.jsonl
Packs
A pack follows spec v0 (canonical: jev-packs/SPEC.md):
examples/demo-triage/
pack.yaml # state contract, questions, optional threshold floors
cases.jsonl # {"id", "state", "expect"} per line
gates.yaml # optional — jevassert quality gates
Questions are the SPEC shapes — noul, choice (options), score
(levels) — and every closed set must include the label unknown (Jev cannot
abstain). Score levels may carry level_descriptions so the API gets
situational text instead of bare keys:
questions:
queue:
type: choice
instructions: Which team should handle this message?
options: {billing: ..., technical: ..., unknown: Cannot tell.}
urgency:
type: score
instructions: How soon does this need a human response?
levels: [low, normal, high, unknown]
level_descriptions:
low: No stated impact or time pressure; can wait.
high: Stated impact or time pressure; needs a response today.
thresholds in the pack are the author's recommended operating point
(per-label probability floors; labels without a floor always go to review).
Gates live in gates.yaml, so the quality contract is explicit:
min_accuracy: 0.85
max_ece: 0.15
max_cost_per_case_usd: 0.001
max_p95_latency_ms: 800
min_coverage_at_precision: {precision: 0.9, min_coverage: 0.6}
min_accuracy_ci_lower: 0.8 # bootstrap CI lower bound (n small-safe gate)
per_question:
queue: {min_accuracy: 0.9, max_ece: 0.1}
What check reports
- accuracy per question and overall, with a bootstrap 95% CI
(
--bootstrap N, default 1000;0disables) - ECE — expected calibration error of the decision probability, equal-mass bins (meaningful with a few hundred items; small packs get a warning)
- Brier — for Noul questions
- coverage — accept when
p >= threshold: how much you automate, at what precision - author thresholds — auto-accept coverage under the pack's own floors
- threshold suggestion —
--target-precision 0.95finds the highest-coverage cut that still reaches that precision - cost and latency — dollars per case and p50/p95, from the recording
--failures— every mismatch with expected/got/probability and the state
check warns when the recording's model version differs from pack.tested,
when cases are missing or extra, and when tested is still null.
Exit codes: 0 all gates pass, 1 a gate failed, 2 usage/IO error.
--junit FILE writes JUnit XML; --report FILE writes a markdown report
(the spec's evidence.md); --json prints machine-readable metrics.
GitHub Action
- uses: dtduc-git/jevassert@v0
with:
pack: examples/demo-triage
predictions: triage.jsonl
report: jevassert-report.md
Record outside CI (or as a scheduled job), commit the predictions file, and the Action enforces the gates on every pull request.
Commands
| command | what it does |
|---|---|
jevassert record PACK -o FILE [--model M] [--resume] [--rpm N] [--dry-run] [--shuffle-options SEED] [--repeat N] |
call Jev for every case, write predictions JSONL |
jevassert check PACK -p FILE [--failures] [--bootstrap N] [--target-precision P] [--partition dev|test] |
compute metrics, evaluate gates, exit 0/1/2 |
jevassert compare PACK --a A --b B |
paired accuracy deltas + exact McNemar p-value |
record extras: --dry-run estimates tokens/cost from the pack without sending
anything; --resume retries only cases that errored; --rpm paces requests;
--shuffle-options records a robustness pass with permuted Choice option order
(Score levels stay ordinal) — compare it against the base recording; --repeat N
records N independent rounds (FILE-r2.jsonl, ...) and prints the discordant
decision count across rounds.
check --partition dev|test evaluates only one deterministic hash-split half
(--partition-seed, --partition-ratio) — tune thresholds on dev, then verify
on test without fooling yourself.
Environment: TYPESAFE_API_KEY (record only), TYPESAFE_BASE_URL (override
the endpoint, e.g. a local Jev-compatible replica).
Reading the numbers
- Accuracy on <30 items per question is noisy (±19pp at n=10). Prefer packs
with 100+ items per question before gating on tight thresholds, and let
--bootstrapshow the CI — gate onmin_accuracy_ci_lowerwhen n is small. - ECE needs a few hundred items to be meaningful; with small n the bins collapse to per-item gaps. Treat it as a smoke signal, not a measurement.
- Stability: record twice and
compare— the flip rate is your run-to-run noise floor. Question wording, option order and model version all move it;--shuffle-optionsisolates the option-order effect and--repeat Nprints the flip rate automatically. - Threshold tuning: suggest on one half, verify on the other —
check --target-precision 0.95 --partition dev, then--partition test. (CIs are percentile bootstrap; with heavily tied probabilities the ECE CI can be slightly skewed.)
Scope
- Backend-neutral: anything that speaks the System One request/response shape.
- File-based and offline-first: no server, no database, no telemetry.
- Not a labeling tool, not a dashboard, not an observability product.
jevassert.packs is the reference loader/validator for SPEC v0 and is meant
to be imported by other tools (jev-table, packs CI).
Release files for jevassert 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| jevassert-0.1.0.tar.gz | 57.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jevassert-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 90.3 kB
Release files / jevassert-0.1.0.tar.gz
| Download URL | jevassert-0.1.0.tar.gz |
|---|---|
| Size | 57.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
949b2f2d450949549ccab6089743352f1fb9dfae588e1a6806994d3b096f744a
|
|
BLAKE2b-256 checksum How to use checksums |
e6cd8604e3a837badd8ee503e3aa72cd71519376c4190d1f792e1a3ac238a52e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency logRelease files / jevassert-0.1.0-py3-none-any.whl
| Download URL | jevassert-0.1.0-py3-none-any.whl |
|---|---|
| Size | 32.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb2c6eec31d2b60b0be7c3ad09571cb666adebfaa57345db8b0b41d7df0e7614
|
|
BLAKE2b-256 checksum How to use checksums |
7540387621a2b4712cc17d9f1dfca8f29cf7e95b593b72a35063b227028792dd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency log