v2.0 Release

NAVALΒ·SEM v2.0 Documentation

πŸ”

v2.0.0 / v2.0.1 β€” Reproducibility & Provenance release. Every result-producing endpoint now carries a SHA-256 fingerprint, with an opt-in free Bitcoin timestamp (via OpenTimestamps) for results you intend to cite. This release also contains one intentional, narrowly-scoped breaking change to POST /nomological β€” see below.

v2.0 doesn't change any analysis math. Every fit index, coefficient, and p-value your v1.x integration already gets is byte-for-byte identical in v2.0. What's new is provenance: a reproducibility fingerprint (and, if you opt in, independent third-party timestamping) attached to every analysis result and every exported artifact, so a result cited in a paper can be independently verified later.

VersionDateSummary
v2.0.122 Aug 2026Fixed Bitcoin timestamping failing to initialize in packaged (PyInstaller) builds
v2.0.022 Aug 2026Fingerprint + provenance extended to all ~23 result-producing endpoints; breaking change to /nomological response shape
New in v2.0

Fingerprint & Provenance, Everywhere

Previously, only the main SEM fit (POST /run) and its exports carried a reproducibility fingerprint. v2.0 extends this to all other result-producing analysis endpoints β€” MGA, HOC, moderation, IPMA, NCA, NCA-ESSE, fsQCA, robustness checks, FIMIX, PLS-POS, LCA, moderated mediation, nomological validity, measurement invariance, CTA, multi-group CB-SEM, EFA, CVI, Bayesian SEM, bootstrap, HTMT, predictive relevance, CMB, and indirect effects.

What the fingerprint covers: model syntax, a hash of the input data, the algorithm used, environment details, and key fit results β€” computed locally via SHA-256, entirely offline. Nothing about your data or model ever leaves your machine unless you separately opt in to timestamping (below).

Every affected endpoint gained two new optional parameters, matching the pattern /run already used:

ParameterTypeRequiredDescription
run_idstringoptionalGroups this result with others from the same session for /fingerprint/{run_id}, /proof, and /upgrade
anchorbooleanoptionalDefault false everywhere. If true, submits the fingerprint hash to OpenTimestamps for Bitcoin timestamping (see below)

Every affected response schema gained two new optional fields:

fingerprint NEW field
string | null β€” the SHA-256 provenance hash for this result
anchor_status NEW field
string | null β€” null Β· "pending" Β· "confirmed" Β· "timeout" Β· "failed"
These are additive optional fields on already-frozen schemas (ModelResult, BootstrapResult, MGAResult, etc.) β€” allowed under the v1.0 schema-freeze policy, which permits new optional fields in patch/minor releases. No existing integration reading these schemas needs to change.
New in v2.0

Bitcoin Timestamping (OpenTimestamps, Free)

An opt-in mechanism for independently proving when a fingerprint was produced, intended for results you plan to cite in a paper or journal β€” corroboration alongside the project's existing Zenodo DOI.

What this is not: NAVAL-SEM does not run a Bitcoin node, hold a wallet, spend funds, or construct/sign any on-chain transaction. Setting anchor: true submits only the fingerprint hash to free public OpenTimestamps calendar servers, which batch many users' hashes into one Bitcoin transaction that someone else pays the fee for β€” a decentralized analogue of RFC 3161 trusted timestamping.
  • GET/fingerprint/{run_id}Retrieve the fingerprint and current anchor status for a run
  • GET/fingerprint/{run_id}/proofDownload the .ots proof file, verifiable by anyone once the Bitcoin transaction confirms (usually within hours)
  • POST/fingerprint/{run_id}/upgradeRe-check and finalize a pending proof
  • The proof does not persist server-side. The .ots proof only lives in server memory for the current session β€” it is never written to disk. Download it promptly after a run (or before restarting the server), or it is lost and the run needs to be repeated to get a new one.
    Degrades gracefully: anchor: true with no internet or calendar-server access still returns the full analysis result normally β€” anchor_status simply reports "timeout" or "failed" rather than the request failing. The app remains fully offline-capable by default.
    New in v2.0

    Provenance in Every Export

    The fingerprint (and Bitcoin timestamp status, if requested) now travels with every exported artifact, not just the in-app Downloads tab β€” so a reader of a published result has somewhere to find the hash to verify against.

    • βœ“   CSV exports get a trailing "Provenance" section with fingerprint and timestamp status
    • βœ“   The JSON export gets a provenance object plus a one-line verification note
    • βœ“   R / Python / lavaan code exports get a #-comment provenance header
    • βœ“   The APA .docx report gets a new "Reproducibility & Provenance" section after the title
    • βœ“   The PDF report gets the equivalent section
    Older clients degrade cleanly: exports with no fingerprint (an older client, or a payload predating this feature) simply omit the provenance section entirely rather than showing a broken block.
    ⚠ Breaking Change · v2.0.0

    POST /nomological Response Shape

    A bare JSON array cannot carry a top-level fingerprint field, so /nomological is the one endpoint in this release whose response shape had to change to accommodate provenance.

    // v1.x response β€” bare array [ { "construct": "Y", "r_squared": 0.42, "benchmark": 0.10, "passed": true, "interpretation": "..." }, { "construct": "Z", "r_squared": 0.31, "benchmark": 0.10, "passed": true, "interpretation": "..." } ] // v2.0 response β€” wrapped NomologicalBatchResult object { "entries": [ { "construct": "Y", "r_squared": 0.42, "benchmark": 0.10, "passed": true, "interpretation": "..." }, { "construct": "Z", "r_squared": 0.31, "benchmark": 0.10, "passed": true, "interpretation": "..." } ], "warnings": [], "fingerprint": "a3f9e1...", "anchor_status": null }
    The analysis output itself is unchanged. compute_nomological_validity() and every per-item field (construct, r_squared, benchmark, passed, interpretation) are byte-for-byte identical to v1.x β€” the numbers you get back have not changed. What breaks is purely mechanical: the top-level JSON is now an object instead of an array.
    Reference

    Migration from v1.x

    v2.0 is additive everywhere except one endpoint. If you don't call /nomological directly, no code changes are required.

    // Before (v1.x) const results = await response.json(); results[0].r_squared; results.map(r => r.construct); // After (v2.0+) const results = await response.json(); results.entries[0].r_squared; results.entries.map(r => r.construct); // results.fingerprint and results.anchor_status are also available now
    Not affected: the in-app frontend's own _renderNomologicalResults() already defensively handled both a bare array and a {entries: [...]} object before this change shipped, so no in-app behavior changed. This migration note is for anyone calling /nomological directly from their own scripts.
    v2.0.1 Patch

    Packaging Fix

    Bitcoin timestamping failed to initialize in packaged (PyInstaller) builds β€” opentimestamps and its dependencies (Cryptodome, bitcoin) weren't declared as PyInstaller hidden imports, and UPX compression could corrupt Cryptodome's compiled extensions on Windows.

    Fixed by adding explicit hidden imports and excluding Cryptodome from UPX compression in naval_sem.spec. If you build NAVAL-SEM from source with PyInstaller, make sure you're building from v2.0.1 or later if you plan to use the anchor flag in a packaged binary.
    Reference

    Schema Stability Note

    The v1.0 schema freeze covers a specific list of frozen result models (ModelResult, BootstrapResult, ModerationResult, IPMAResult, NCAResult, NCAESSEResult, FIMIXResult, PLSPOSResult, MGAResult, ModMediationResult, FsQCAResult, ScaleDevelopmentResult, CVIResult) β€” see the v1.0 Schema Stability reference for the full guarantee.

    Why the /nomological change doesn't violate the freeze: NomologicalResult was never in the frozen list above β€” its per-item fields are unchanged regardless, but the freeze's "no shape changes" guarantee was never made for its top-level response wrapper. Every other endpoint's response shape is untouched in v2.0; only new optional fields were added.