What's New · 22 August 2026

NAVAL·SEM v2.0.0 — Fingerprint & Provenance

Reproducibility Bitcoin Timestamping 23 Endpoints Updated ⚠ Breaking: /nomological
Released 22 August 2026 · Semantic version 2.0.0 · CC BY-NC-ND 4.0
🔐

Every result is now independently verifiable

Previously only POST /run carried a reproducibility fingerprint. v2.0 extends a local SHA-256 fingerprint — and an optional, free Bitcoin timestamp — to every result-producing endpoint, and threads that provenance through every export format. No analysis math changed anywhere.

⚠

One breaking change: POST /nomological

A bare JSON array can't carry a top-level fingerprint field, so /nomological's response is now a wrapped object instead of a bare array. The per-item numbers are byte-for-byte unchanged — see the Migration section below.

◆
Reproducibility fingerprint extended to ~23 analysis endpoints
app/main.py · _compute_fingerprint_generic() · _attach_provenance() · schemas.py

Every result-producing analysis endpoint — 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 — now attaches a fingerprint and anchor status to its result, not just the main SEM fit.

  • New _compute_fingerprint_generic() — a reusable fingerprinting function not tied to SEM-specific fields, so it works across fundamentally different result shapes (fsQCA solutions, LCA class assignments, CTA tetrad tests, etc). The original SEM-specific fingerprint function is now a thin wrapper around it.
  • New _attach_provenance() helper shared by every endpoint — computes the fingerprint, optionally submits it for Bitcoin timestamping, and registers it so /fingerprint/{run_id}, /proof, and /upgrade work uniformly everywhere.
  • fingerprint and anchor_status fields added to all 22 corresponding response schemas — additive, optional fields on already-frozen result models.
  • Every affected endpoint gained a run_id and an anchor parameter (default false), matching /run's existing pattern.
  • Degrades gracefully exactly like /run: anchor=true with no internet access still returns the full result, with anchor_status reporting timeout/failed instead of the request failing.
⏱
Optional, free, independent proof of when a fingerprint was produced
app/anchor.py · GET /fingerprint/{run_id}/proof · POST /fingerprint/{run_id}/upgrade

Set anchor: true on any supported endpoint to submit the fingerprint hash to free public OpenTimestamps calendar servers, which batch many users' hashes into one Bitcoin transaction someone else pays the fee for — a decentralized analogue of RFC 3161 trusted timestamping.

  • No wallet, no funds, no mining — NAVAL-SEM never constructs or signs an on-chain transaction, and no blockchain node runs locally.
  • Off by default everywhere — the app stays fully offline-capable unless you explicitly opt in per-request.
  • Proof lives in memory only — the .ots proof is never written to disk; download it promptly after a run or before restarting the server, or it's lost.
  • Relabeled the in-app checkbox and tooltip to "Timestamp on Bitcoin (via OpenTimestamps, free)", spelling out the actual mechanism for the research audience this targets.
⬇
Fingerprint now travels with every exported artifact
CSV · JSON · R/Python/lavaan code · APA .docx · PDF

Previously the fingerprint only existed inside the running app session — nothing that actually left the system carried it, which defeated the point of timestamping a result meant to be cited in a paper.

  • CSV exports get a trailing "Provenance" section with fingerprint and Bitcoin timestamp status.
  • JSON export gets a provenance object plus a one-line verification note.
  • R / Python / lavaan code exports get a #-comment provenance header.
  • APA .docx report gets a new "Reproducibility & Provenance" section right after the title, spelling out exactly what the hash covers and that only the hash — never data, syntax, or results — ever left the machine.
  • PDF report gets the equivalent section via _build_provenance_section in app/export_pdf.py.
  • Older exports (no fingerprint) simply omit the provenance section rather than showing a broken block.
⚠
Response shape changed from bare array to wrapped object
app/schemas.py · NomologicalBatchResult replaces List[NomologicalResult]

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

// v1.x response — bare array [ { "construct": "Y", "r_squared": 0.42, "benchmark": 0.10, "passed": true, "interpretation": "..." } ] // v2.0 response — wrapped NomologicalBatchResult { "entries": [ { "construct": "Y", "r_squared": 0.42, "benchmark": 0.10, "passed": true, "interpretation": "..." } ], "warnings": [], "fingerprint": "a3f9e1...", "anchor_status": null }

The analysis output itself did not change. compute_nomological_validity() and every per-item field are byte-for-byte identical to v1.x. What breaks is purely mechanical: the top-level JSON is now an object instead of an array.

Everything except /nomological is additive

If you don't call /nomological directly, no code changes are required. All other endpoints only gained optional run_id/anchor parameters and optional fingerprint/anchor_status response fields.

If you call POST /nomological directly

Change response[0].r_squared / response.map(...) to response.entries[0].r_squared / response.entries.map(...). The in-app frontend already handled both shapes defensively before this shipped, so no in-app behavior changed — this only affects external scripts calling the endpoint directly. Full guide: docs/v2.0 → Migration Guide.

New files introduced in this release:

app/anchor.py

Updated files:

app/main.py app/schemas.py app/export_pdf.py static/index.html pyproject.toml GET /fingerprint/{run_id} GET /fingerprint/{run_id}/proof POST /fingerprint/{run_id}/upgrade