Correctness & Compatibility
This page answers a practical question:
If I replace
ezc3dwithsqzc3dfor reading C3D into arrays, will I silently get different data?
sqzc3d is intentionally not an “object-graph clone” of ezc3d. Instead, it focuses on delivering:
predictable arrays (
points/analogs+ explicit*_validmasks),clear selector / index-space contracts,
and stable behavior across native + WASM environments.
Correctness is defined within that scope.
30-second summary
For beginners:
If you only want to answer “can I switch safely?”, start here:
Do my arrays change if I switch? → run
verify.py nativeor stressG0(a directsqzc3dvsezc3dcross-check).I select markers by label / only want some markers →
S03/S05/S06(selectors + index-space).I read only a frame window →
S04(window reads must equal slicing).I worry about units/scaling →
S07(reported clearly; use--strict-unitif you want a hard gate).I worry about gaps / missing samples →
S08(*_validmust be reliable).I want caching →
S11(bundle roundtrip).I read from bytes →
S12(open_memory).I worry about corrupted inputs →
S15(fail loudly; don’t produce bogus data).
Mini glossary
No need to memorize:
Term |
Plain meaning |
|---|---|
materialize |
read a C3D fully into memory and produce arrays (think “C3D → NumPy tables”). |
selector |
“picking” which markers/channels you want (labels / indices). |
index-space |
the numbering scheme (source-total indices vs chunk-local indices). |
window read |
reading only a slice of frames (like decoding only a segment of a video). |
|
a per-sample “is this sample usable?” flag. |
units / scaling |
length unit metadata ( |
|
the C3D parameter tree (think “settings/metadata dictionary”; matrix params include |
bundle |
a cache artifact ( |
stress |
a scenario-based contract “health report” (PASS/WARN/FAIL + optional JSON report). |
|
turn some “report-only differences” into hard gates (mismatch becomes FAIL). |
oracle |
the reference implementation used for comparison (here: |
Expected outcomes
Under the same interpretation policies (units, validity, etc.),
sqzc3dpoints/analogs should matchezc3d(used as the oracle), avoiding silent numeric drift.For human-discernible policy differences (units / validity gate), stress defaults to clear reporting rather than surprising failures; use
--strict-unit/--strict-validityto make them hard gates.Optional features (e.g.
meta_tree, bundles) should degrade explicitly (WARN/skip/guidance) when dependencies or build options are missing.
Scope
What we verify:
Covered (publicly documented contracts):
C3D → materialize to arrays (Python/C/C++; i.e., “read into NumPy / contiguous arrays”).
Open from file or from memory (
open_memory; i.e., “read from bytes”).Selectors (
None/[]/labels/indices; i.e., “pick which markers/channels”) and window reads (start_frame/frame_count; i.e., “read only a frame slice”).Validity masks (
*_valid; i.e., “which samples are usable”) and missing samples.Units metadata behavior (
POINT:UNITS) without surprising implicit scaling.Type-groups (marker-set semantics; i.e., “marker-set conventions”).
meta_tree(EZ parameter tree / metadata dictionary): readable from C3D when built withSQZC3D_WITH_EZC3D=ON, and preserved in bundles.Bundle persistence (
export_bundle/load_bundle; cache roundtrip, strict vs best-effort).
Not covered (by design):
Writing/editing C3D files.
Higher-level biomechanics semantics (force-plate post-processing, gait events, etc.).
Verification entry points
From source:
All public verification tools live in the source repository under samples/verify/:
python samples/verify/verify.py native— closest to daily workflows: read arrays and compare vsezc3d(points/analogs/labels/meta/meta_tree).python samples/verify/verify.py wasm— browser/WASM smoke (Playwright) foropen_file+open_memory.python samples/verify/verify.py stress— scenario-oriented “health report” checks (PASS/WARN/FAIL + optional JSON report).python samples/verify/verify.py cpp— C++ correctness matrix (best for bundle + index-space hard checks).
Quick reproduce:
python samples/verify/verify.py all --c3d path/to/c3d_dir --wasm-dir path/to/wasm_out --limit 5
python samples/verify/verify.py stress --c3d path/to/c3d_dir --sample 0 --report stress_report.json
How to read results
You can think of stress output as a simple “health report”: each Scenario is one check.
PASS: the scenario’s contract held for the tested inputs (or the file was skipped because the scenario is not applicable).
PASS + “skipped: …”: normal, means “this file doesn’t have that feature” (e.g. no analog channels).
WARN: comparison could not be performed (missing dependency), or a potentially surprising behavior was observed.
FAIL: contract violation or oracle mismatch.
Some differences (e.g. unit policies) are easy for humans to spot. For those, the default behavior is to report clearly
and let users make them strict via flags (--strict-unit, --strict-validity) rather than failing by default.
If you see FAIL, the fastest debugging loop is usually:
Add
--report stress_report.jsonand check which file + which contract triggered.Re-run only that scenario via
--scenarios <ID>(don’t run everything while iterating).If it’s a policy mismatch (units/validity), decide whether to enable
--strict-unit/--strict-validityas hard gates.If it’s about
meta_tree, make sure you built withSQZC3D_WITH_EZC3D=ON.
Stress scenarios: preset → contract → how to run → what it means
The full spec is in samples/verify/STRESS_PLAN.md. The runner is python samples/verify/verify.py stress.
G0 — Mixed-dataset regression
Preset: a folder of C3Ds from different sources (points-only + analog-heavy mixed).
Contract: core payload matches
ezc3d(points/analogs/labels + core meta + meta_tree).Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios G0Result: PASS means “no silent numeric drift” under the same interpretation rules.
Mental model: give the same trial to two “translators” (
sqzc3d/ezc3d) and diff the output tables; PASS = same translation.
S01 — Points-only materialize
Preset: a trial with no analog channels.
Contract: points arrays have stable shapes; analog arrays are empty (but well-formed).
Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S01Result: PASS is expected; files with analogs are skipped.
Mental model: you only have a “marker table”; the “sensor table” should be an empty table, not garbage.
S02 — Materialize with analogs
Preset: analog channels exist (e.g. EMG / force plate).
Contract: analog arrays are shaped and indexed consistently (
layout="CN"), with a matching*_validmask.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S02Result: PASS is expected; files without analogs are skipped.
Mental model: besides marker positions, you also deliver a time-series “sensor table”; shapes + indexing must line up.
S03 — Selector semantics
Preset: you request a small set of markers by label (including a reversed order).
Contract:
Nonemeans ALL,[]means empty, and label selection is order-preserving.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S03Result: PASS means “label selection is predictable” (see also
user_guide_selectors.md).Mental model: “ordering is what you asked for”;
Noneis “give me everything”,[]is “give me nothing”.
S04 — Window reads are equivalent to slicing
Preset: you load a window (
start_frame,frame_count) instead of the full trial.Contract: window read == full materialize then slice, including edge cases (
frame_count=0,-1).Contract:
metarecords the time-axis origin of the returned window (frame_start,analog_frame_start, and absolute variants).Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S04Result: PASS means “window reads are a safe optimization” (see also
user_guide_materialize_vs_streaming.md).Mental model: decoding only a segment of a video should not change the frames you did decode.
S05 — Indices vs labels
Preset: you select points by indices vs labels and expect the same data.
Contract: indices/labels paths agree on both values and the index-space mapping (
point_indices_total).Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S05Result: PASS means “no off-by-one / wrong index space” (see
user_guide_selectors.md).Mental model: two naming systems for the same thing (numbers vs names) should still land on the same marker.
S06 — Label normalization
Preset: labels with whitespace / case variations.
Contract:
label_normpolicies behave as documented and are stable.Contract: if normalization makes a label ambiguous,
sqzc3draises instead of picking an arbitrary match.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S06Result: PASS means “label matching rules are explicit and testable”.
Mental model: normalize “names” first (trim/case), then match, so users aren’t surprised by trivial formatting.
S07 — Units & scaling
Preset: C3Ds with
POINT:UNITSset tomm/cm/m(or missing/unknown).Contract: default point scale is explainable and does not surprise users; unit differences can be made strict.
Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S07 --unit-contract autoResult: PASS means “sqzc3d’s default matches ezc3d raw output for your files”; otherwise the report tells you how it differs.
Mental model: units are the ruler marks (mm/cm/m); default is “don’t secretly swap rulers”, but do report differences clearly.
For details, see user_guide_units.md.
S08 — Validity policies
Preset: real-world trials with gaps / missing markers.
Contract:
*_validmasks are consistent and values are compared under the agreed validity policy.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S08Result: PASS means “you can trust
*_validas the single source of truth”.Mental model: every sample comes with a “usable / not usable” sticker; compare only after checking the sticker.
See user_guide_valid.md.
S09 — Analog scaling
Preset: analog channels with calibration parameters.
Contract: scaled analog values match
ezc3dfor the same file.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S09Result: PASS is expected; files without analog values are skipped.
Mental model: analog readings need calibration (scale/offset); if calibration differs, everything shifts.
S10 — meta_tree
Preset: parameters that are matrices (corners/origin/etc).
Contract: structure is stable, value ordering is stable, and
dimensionsis present so callers can reshape reliably.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S10Result: PASS means “no subtle param-tree drift” (requires
SQZC3D_WITH_EZC3D=ON).Mental model: a settings menu can contain matrices; row/column ordering matters even if values “look similar”.
S11 — Bundles roundtrip
Preset: cache a chunk as a bundle (
.sqzc3d) and reload it.Contract: export → load roundtrip preserves meta + payload +
meta_tree; strict mode rejects incompatible bundles.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S11Result: PASS means “bundle is safe for caching”. If Python lacks
export_bundle, the scenario degrades to WARN.Mental model: bundle is a sealed cache box; strict mode is “verify the seal” before trusting the contents.
See user_guide_bundles.md.
S12 — open_memory
Preset: load from bytes (e.g. network / archive / WASM FS).
Contract:
open_memorybehaves like reading the same file path (includingmeta_tree).Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S12Result: PASS means “bytes-in == file-in”.
Mental model: reading the same content from disk vs from bytes should produce the same tables.
S13 — Streaming
Preset: you want true streaming.
Contract: Python does not expose a dedicated streaming API (yet); window reads (
S04) cover most sampling needs.Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S13Result: informational (PASS) with guidance (not a hard compatibility gate).
Mental model: true streaming is “read while playing”; Python currently focuses on “read by window” (
S04).
S14 — Feature gating
Preset: builds that disable optional components.
Contract: feature bits are queryable and match behavior.
Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S14Result: PASS means “switches match behavior”; missing features should be explicit, not silent.
Mental model: like optional add-ons—if you didn’t install it, the system should say so clearly.
S15 — Pathological inputs & diagnostics
Preset: truncated / corrupted C3D inputs.
Contract: fail loudly with actionable diagnostics (no silent success).
Stress:
python samples/verify/verify.py stress --c3d <dir> --scenarios S15Result: PASS means “bad inputs don’t produce bad data”.
Mental model: a torn/truncated book should trigger an error, not a made-up “successful” translation.
See user_guide_errors.md.
Snapshot
This is a point-in-time snapshot to give readers a concrete expectation (think: “the health report we ran on that date”). For up-to-date results, run the commands above.
Snapshot metadata:
Date: 2026-02-27
sqzc3d: v0.4.0 (Python bindings)ezc3d(Python oracle): 1.6.0Platform: Windows (native + WASM)
Entry points
Check |
Expected |
Snapshot |
|---|---|---|
|
PASS on sampled files |
PASS |
|
PASS for |
PASS |
|
PASS (with possible “skipped” notes) |
PASS |
Scenario snapshot
Scenario |
Expected |
Snapshot |
|---|---|---|
G0 |
PASS |
PASS |
S01 |
PASS (skips non-points-only files) |
PASS |
S02 |
PASS (skips files without analogs) |
PASS |
S03 |
PASS |
PASS |
S04 |
PASS |
PASS |
S05 |
PASS |
PASS |
S06 |
PASS |
PASS |
S07 |
PASS (or clear report; strict optional) |
PASS |
S08 |
PASS (or WARN if strict policy differs) |
PASS |
S09 |
PASS (skips files without analog values) |
PASS |
S10 |
PASS (requires |
PASS |
S11 |
PASS (or WARN if Python lacks |
PASS |
S12 |
PASS |
PASS |
S13 |
informational |
PASS |
S14 |
PASS |
PASS |
S15 |
PASS |
PASS |