Documentation

NAVAL-SEM v0.9

Open-source structural equation modelling desktop application. PLS-SEM and CB-SEM in a self-contained GUI — no R, no SPSS licence required.

v0.9.0 FastAPI · Python semopy · NumPy · pandas CC BY-NC-ND 4.0 Windows · macOS · Linux
▸ What's new in v0.9
  • Content Validity Index (CVI) — item-level I-CVI, S-CVI/Ave, S-CVI/UA, and modified kappa (κ*) for expert-panel scale validation (POST /cvi)
  • Exploratory Factor Analysis (EFA) — KMO, Bartlett's sphericity, Kaiser criterion, varimax/other rotations, cross-loading and weak-loading flags (POST /efa)
  • Nomological Validity — per-construct R² checked against Hair et al. (2019) benchmarks, Substantial / Moderate / Weak / Not-supported interpretation (POST /nomological)
  • Measurement Invariance — configural → metric → scalar sequence, ΔCFI criterion (Cheung & Rensvold 2002), partial-invariance release list (POST /invariance)
  • NCA-ESSE — NCA Effect Size Sensitivity Extension (Becker et al. 2026, JBR): ECDF threshold sweep 0–5%, joint-uniform benchmark, permutation tests, recommended threshold (POST /nca-esse) — unscheduled addition

Quick Start

1 · Launch the server

Shell
# From the extracted release folder
uvicorn app.main:app --reload --port 8000
# Or use the bundled launcher
python launcher.py

2 · POST your first model

All analysis endpoints accept multipart/form-data with a file upload (CSV / XLSX / SAV) and a model string in lavaan syntax.

cURL — minimal PLS-SEM run
curl -X POST http://localhost:8000/run \
  -F "file=@data.csv" \
  -F "model=Y =~ y1 + y2 + y3
X =~ x1 + x2 + x3
Y ~ X" \
  -F "algorithm=pls" \
  -F "bootstrap_n=500"

3 · Stream live logs (SSE)

JavaScript
const runId = crypto.randomUUID();
const es = new EventSource(`/logs/${runId}`);

es.onmessage = (e) => {
  const d = JSON.parse(e.data);
  if (d.done) { es.close(); return; }
  console.log(d.level, d.msg);
};

// Then POST /run with run_id in the form body
formData.append("run_id", runId);

Algorithms

All analysis endpoints that accept an algorithm parameter support three estimators:

pls
Partial Least Squares SEM
  • Default for all endpoints
  • Small-to-medium samples
  • Non-normal data
  • Exploratory research
  • Composite-based fit
cb
Covariance-Based SEM
  • Theory-confirming
  • Normal distribution assumed
  • Full CFI / TLI / RMSEA
  • n ≥ 200 recommended
  • ML estimator via semopy
wls
Weighted Least Squares
  • Ordinal / Likert data
  • Robust to non-normality
  • DWLS / WLSMV variant
  • Categorical indicators

lavaan Syntax

NAVAL-SEM parses a lavaan-compatible model string. Three operator types are supported:

OperatorMeaningExample
=~Measurement (reflective loading)EXO =~ x1 + x2 + x3
~Structural regression pathENO ~ EXO + MOD
~~Residual covariance / variancey2 ~~ y4

Interaction terms

Use the * operator inside a structural path to specify moderation. The engine auto-creates the mean-centred product column.

Moderation syntax
# Standard moderation: X*M on outcome Y
Y  ~  X + M + X*M
X  =~ x1 + x2 + x3
M  =~ m1 + m2 + m3
Y  =~ y1 + y2 + y3

Auto reverse scoring

Prefix any indicator name with r (e.g. rx3) when the column x3 exists in the dataset but rx3 does not. The server applies (max + min) − value automatically before fitting.

Reverse-scored indicator
SatisfactionLV =~ sat1 + sat2 + rsat3 + sat4
# rsat3 will be auto-reverse-scored from sat3
Multi-target residual covariance shorthand (y2 ~~ y4 + y6) is automatically expanded to individual pairs by the engine. However, write them individually for clarity in production models.
Core API

POST /run

Fit a full SEM model. Returns path coefficients, loadings, fit indices, validity metrics, and optionally bootstrap CIs. Generates a SHA-256 reproducibility fingerprint.

POST /run Fit model → ModelResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV, XLSX, or SAV dataset
modelrequiredstringlavaan syntax string
algorithmoptionalstringplspls | cb | wls
bootstrap_noptionalint0Bootstrap resamples (0 = no bootstrap, max 20 000)
missingoptionalstringlistwiselistwise | mean
run_idoptionalstringauto UUIDClient-supplied ID for SSE log streaming

Returns → ModelResult

Key fields in the response JSON:

FieldTypeNotes
algorithmstringEstimator used
n_obsintRows used after missing-data handling
convergedboolOptimisation converged
parametersPathParameter[]All =~, ~, ~~ rows with estimates, SE, z, p, CI
fitFitIndicesCFI, TLI, RMSEA, SRMR, χ², AIC, BIC, AVE, CR, α
vifVIFEntry[] | nullCollinearity — VIF < 5 acceptable, < 3.3 strict
f2F2Entry[] | nullCohen's f² for each predictor
indirectIndirectResult | nullPopulated when bootstrap_n > 0
outer_weightsOuterWeightEntry[] | nullBootstrap outer weights
fingerprintstring | nullSHA-256 reproducibility hash
summaryModelSummary | nullHigh-level digest for UI panels (v0.7)
warningsstring[]Non-fatal notices

POST /bootstrap

Run standalone bootstrap without re-fitting the full model. Useful for extending an existing /run result with CIs post-hoc.

POST /bootstrap Bootstrap → BootstrapResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV, XLSX, or SAV
modelrequiredstringlavaan syntax
bootstrap_noptionalint500Resamples (max 20 000)
algorithmoptionalstringplsEstimator
missingoptionalstringlistwiseMissing-data strategy

POST /indirect

Decompose indirect (mediation) effects for all variable pairs connected via paths of length ≥ 2. Returns bootstrap 95 % CIs and a total-effects matrix.

POST /indirect Indirect effects → IndirectResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset
modelrequiredstringlavaan syntax
bootstrap_noptionalint500Bootstrap resamples for CIs
missingoptionalstringlistwise

Returns → IndirectResult

FieldTypeNotes
effectsIndirectEffect[]One row per from→through→to chain with bootstrapped SE, CI, significance
total_effectsDict[str, Dict[str, float]]Matrix: total_effects[from_var][to_var]

POST /predict

Predictive relevance suite: Stone-Geisser Q² (blindfolding), PLSpredict k-fold vs linear baseline, and CVPAT.

POST /predict Q² · PLSpredict · CVPAT → PredictResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset
modelrequiredstringlavaan syntax
omission_distanceoptionalint7Blindfolding omission distance D
k_foldsoptionalint10Cross-validation folds for PLSpredict
missingoptionalstringlistwise

POST /cmb

Common Method Bias marker variable analysis (Lindell & Whitney 2001). Requires a marker variable theoretically unrelated to your constructs.

POST /cmb Common Method Bias → CMBMarkerResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset
modelrequiredstringlavaan syntax
marker_variablerequiredstringColumn name of the marker variable
missingoptionalstringlistwise

POST /mga

Multi-Group Analysis: per-group model fit, pairwise bootstrap path-difference CIs, and (for 2-group analyses) MICOM measurement invariance.

POST /mga Multi-Group Analysis → MGAResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset (must contain grouping column)
modelrequiredstringlavaan syntax
grouping_variablerequiredstringColumn name for group splits
algorithmoptionalstringpls
bootstrap_noptionalint500Resamples for path-difference CIs
missingoptionalstringlistwise
run_idoptionalstringauto UUIDSSE tracking ID
v0.7

POST /moderation

Moderation analysis via the product-of-composites approach. Detects X*M interaction terms in the lavaan structural syntax and tests each one by comparing R² with vs. without the interaction term (Δ R², Cohen's f²) and computing bootstrap simple slopes at moderator = −1 SD, mean (0), +1 SD.

Manifest-variable fallback: when the model contains no =~ measurement lines, NAVAL-SEM automatically switches to an OLS path for observed-variable moderation (no latent composites needed).
POST /moderation Moderation → ModerationResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset (CSV, XLSX, SAV)
modelrequiredstringlavaan syntax; must include at least one X*M term
algorithmoptionalstringplspls | cb | wls
bootstrap_noptionalint500Bootstrap resamples for β_interaction CIs and simple slopes
missingoptionalstringlistwise
run_idoptionalstringauto UUIDSSE tracking ID

Returns → ModerationResult

FieldTypeNotes
moderation_termsModerationTerm[]One entry per detected X×M interaction
parametersPathParameter[]Full model parameters including interaction term
fitFitIndicesFit of the full (interaction-included) model
n_obsintEffective sample size
bootstrap_nintActual resamples used
warningsstring[]

ModerationTerm fields

FieldTypeNotes
iv / moderator / outcomestringVariable names
interaction_colstringAuto-created product column name (e.g. X_x_M)
beta_iv / beta_moderator / beta_interactionfloatStandardised path coefficients
ci_lower_95 / ci_upper_95float | nullBootstrap percentile CI for β_interaction
significantboolTrue when CI excludes 0
r2_with / r2_without / delta_r2floatR² comparison
f2_interactionfloatCohen's f² = Δ R² / (1 − R²_with)
simple_slopesSimpleSlope[]At W = −1 SD, 0, +1 SD
Example syntax
# Test whether trust (TR) moderates innovation (IN) → satisfaction (SA)
SA ~  IN + TR + IN*TR
IN =~ in1 + in2 + in3
TR =~ tr1 + tr2 + tr3
SA =~ sa1 + sa2 + sa3

POST /ipma

Importance-Performance Map Analysis (Ringle & Sarstedt 2016; Hair et al. 2022 Ch. 7). Computes for each predictor of a target latent variable: Importance = total effect (direct + all indirect paths) and Performance = mean composite score rescaled to 0–100.

POST /ipma IPMA → IPMAResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset
modelrequiredstringlavaan syntax
target_lvrequiredstringName of the outcome LV for which importance is computed
algorithmoptionalstringpls
scale_minoptionalfloatobserved minTheoretical scale minimum (e.g. 1 for Likert 1–5)
scale_maxoptionalfloatobserved maxTheoretical scale maximum (e.g. 5 for Likert 1–5)
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → IPMAResult

FieldTypeNotes
target_lvstringThe outcome LV specified
entriesIPMAEntry[]Sorted by importance descending
scale_min / scale_maxfloatScale range actually used for 0–100 rescaling
algorithmstring
warningsstring[]Emitted when scale range is inferred from data

IPMAEntry fields

FieldTypeNotes
lvstringPredictor construct name
importancefloatTotal effect on target_lv
performancefloat0–100 rescaled composite mean (clamped)
Pass scale_min and scale_max matching your survey instrument (e.g. 1 and 5 for a five-point Likert scale) for correct 0–100 performance rescaling. When omitted, NAVAL-SEM uses the observed data range and appends a warning.

POST /nca

Necessary Condition Analysis (Dul 2016, 2020). Tests whether each predictor is a necessary (not merely sufficient) condition for an outcome. Computes CE-FDH (staircase ceiling) and CR-FDH (regression ceiling) effect sizes plus permutation-based significance.

POST /nca NCA → NCAResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset
modelrequiredstringlavaan syntax; all structural IV→DV pairs are tested
n_permutationsoptionalint1000Permutation samples for p-value (max 20 000)
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → NCAResult

FieldTypeNotes
entriesNCAEntry[]One per unique IV→DV pair
n_permutationsint
warningsstring[]Pairs skipped due to insufficient n

NCAEntry fields

FieldTypeNotes
iv / dv / n_obsstring / int
ce_fdh_d / ce_fdh_label / ce_fdh_pfloat / string / floatStaircase ceiling effect size and permutation p
cr_fdh_d / cr_fdh_labelfloat / stringRegression ceiling effect size
cr_fdh_slope / cr_fdh_intercept / cr_fdh_pfloatRegression ceiling line parameters
significantboolTrue when max(ce_p, cr_p) < 0.05
scatter_x / scatter_yfloat[]Sampled scatter plot coordinates (≤ 200 pts)
ceiling_x / ceiling_yfloat[]CE-FDH staircase coordinates (≤ 100 pts)

NCA Effect Size Benchmarks (Dul 2016)

dLabel
< 0.10negligible
0.10 – 0.29small
0.30 – 0.49medium
≥ 0.50large

POST /mod-mediation

Moderated Mediation / Conditional Process Analysis (Edwards & Lambert 2007; Hayes 2018 Chapters 11–14). Detects interaction terms in the structural syntax and computes the Index of Moderated Mediation (IMM) with bootstrap 95 % CI plus conditional indirect effects at W = −1 SD, 0, +1 SD.

POST /mod-mediation Moderated Mediation → ModMediationResult

Supported Hayes PROCESS patterns

PatternModelSyntax
a-path moderationModel 7M ~ X + W + X*W / Y ~ X + M
b-path moderationModel 14M ~ X / Y ~ X + M + W + M*W
Both pathsModel 58/59Combine both interaction terms above

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset
modelrequiredstringlavaan syntax with at least one X*W term
algorithmoptionalstringpls
bootstrap_noptionalint500Bootstrap resamples for IMM CI and conditional IEs (max 20 000)
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → ModMediationResult

FieldTypeNotes
pathsModMediationPath[]One per detected X→M→Y chain
parametersPathParameter[]Full model parameter table
fitFitIndices
n_obs / bootstrap_nint
warningsstring[]

ModMediationPath fields

FieldTypeNotes
x / m / y / wstringVariable names
moderated_pathstring"a" or "b"
a_path / b_path / c_primefloatX→M, M→Y, direct X→Y
a3_interaction / b3_interactionfloat | nullInteraction β on a- or b-path
immfloatIndex of Moderated Mediation (a₃·b or a·b₃)
imm_ci_lower_95 / imm_ci_upper_95float | nullBootstrap percentile CI
imm_significantboolTrue when IMM CI excludes 0
conditional_effectsConditionalIndirectEffect[]IE at W = −1 SD, 0, +1 SD
a-path moderation example (Model 7)
# H1: W moderates the X → M relationship
M ~  X + W + X*W
Y ~  X + M
X =~ x1 + x2 + x3
M =~ m1 + m2 + m3
W =~ w1 + w2 + w3
Y =~ y1 + y2 + y3
Utilities

GET /logs/{run_id}

Server-Sent Events stream for a running analysis. Open immediately after submitting any endpoint that returns a run_id. The stream emits JSON objects and terminates with a done packet.

GET /logs/{run_id} SSE log stream

Stream events

Event typeFieldsNotes
log entryt, level, msglevel = step | info | ok | warn | error
donedone: true, fingerprint, auditStream closes after this

Stream auto-closes after 4 hours; results continue in background.

GET /fingerprint/{run_id}

Retrieve the full SHA-256 audit record for a completed run. The fingerprint covers model syntax hash, data hash (SHA-256 of sorted column hashes), algorithm, environment versions, and key fit metrics.

GET /fingerprint/{run_id} Reproducibility audit record

Returns 404 if run_id is unknown; 425 if the run is still in progress.

POST /upload/preview

Parse an uploaded file and return column names, row count, first 5 rows, and dtype map — without running any analysis. Useful for validating uploads before model submission.

POST /upload/preview Dataset preview
ReturnsTypeNotes
columnsstring[]All column names
n_rowsintTotal row count
previewobject[]First 5 rows as records
dtypesDict[str, str]pandas dtype per column

GET /health

GET /health Liveness check
{ "status": "ok", "version": "0.7.1" }
Reference

Schemas

All response models are Pydantic v2 classes. Key schemas:

PathParameter

One row per model parameter (measurement loading, structural path, or covariance). std_error, z_value, and p_value are null for ~~ rows.

PathParameter
lhs str
op str =~ | ~ | ~~
rhs str
estimate float
std_estimate float?
std_error float?
z_value float?
p_value float?
ci_lower / ci_upper float?
significant bool
FitIndices
cfi / tli float?
rmsea float?
rmsea_ci_lower/upper float?
srmr float?
chi_square / df / p_value float?
aic / bic float?
r_squared Dict?
ave / composite_reliability Dict?
cronbach_alpha Dict?
fornell_larcker Dict?
cfi_good / rmsea_good / srmr_good bool?
IndirectEffect
from_var / to_var str
through str[] mediator chain
indirect_effect float
bs_se float?
ci_lower_95 / ci_upper_95 float?
significant bool?
F2Entry
lhs / rhs str
r2_full / r2_reduced float
f2 float ΔR²/(1−R²_full)
effect str negligible–large
Q2Entry (v0.5)
lv str endogenous LV
q2 float 1 − SSE/SSO
sse / sso float
omission_distance int
predictive_relevance str
HTMTEntry
construct_a / b str
htmt float
acceptable bool HTMT < 0.90

v0.9 Schemas

CVIResult
item_cvi Dict[str, float] I-CVI per item
s_cvi_ave float mean I-CVI
s_cvi_ua float universal agreement
kappa_star float modified κ*
n_experts / n_items int
interpretation str Excellent/Acceptable/Poor
ScaleDevelopmentResult
method str e.g. PCA_Varimax
n_factors int
kmo / bartlett_chi2 / bartlett_p float
eigenvalues float[]
variance_explained float[] per factor
cumulative_variance float
loadings Dict[] {item, factor, loading}
cross_loadings Dict[]? secondary |λ| > 0.30
warnings str[]
NomologicalResult
construct_name str (JSON key: "construct")
r_squared float observed R²
benchmark float minimum R² threshold
passed bool R² ≥ benchmark
interpretation str Substantial/Moderate/Weak/Not supported
MeasurementInvarianceResult
group_col / groups str / str[]
configural MeasurementInvarianceLevel
metric MeasurementInvarianceLevel
scalar MeasurementInvarianceLevel
partial_invariance str[]? released items
conclusion str Full scalar / Partial scalar / Metric only / Configural only
NCAESSEResult
entries NCAESSEEntry[]
threshold_range float[]
benchmark str "joint_uniform"
n_permutations / n_benchmark_reps int
warnings str[]
NCAESSEEntry
iv / dv / n_obs str / int
thresholds NCAESSEThresholdPoint[]
recommended_threshold float?
recommended_effect_size float?
recommended_label str? negligible–large
ceiling_x / ceiling_y float[] staircase at recommended threshold
warnings str[]
NCAESSEThresholdPoint
threshold / pct_excluded float
empirical_d float CE-FDH at this step
theoretical_d float uniform benchmark
delta_empirical / delta_theoretical float?
delta_diff float? >0 = genuine signal
p_value float? permutation p
significant bool p < 0.05
MeasurementInvarianceLevel
model str configural | metric | scalar
cfi / rmsea / srmr float?
delta_cfi / delta_rmsea float? vs. preceding model
passed bool ΔCFI > −0.010

Fit Thresholds

Verdict flags set automatically by the engine:

IndexAcceptableGoodField
CFI≥ 0.90≥ 0.95cfi_acceptable / cfi_good
TLI (NNFI)≥ 0.90≥ 0.95tli_acceptable / tli_good
RMSEA≤ 0.08≤ 0.06rmsea_acceptable / rmsea_good
SRMR≤ 0.08srmr_good
AVE≥ 0.50per-LV in fit.ave
Composite Reliability≥ 0.70≥ 0.80fit.composite_reliability
Cronbach's α≥ 0.70fit.cronbach_alpha
VIF< 5.0< 3.3 (PLS strict)vif[].acceptable
HTMT< 0.90< 0.85htmt[].acceptable

Effect Sizes

Cohen's f² (structural paths)

Label
< 0.02negligible
0.02 – 0.14small
0.15 – 0.34medium
≥ 0.35large

Stone-Geisser Q² (predictive relevance)

Label
≤ 0none
0 – 0.25small
0.25 – 0.50medium
≥ 0.50large

NCA Effect Size d (Dul 2016)

dLabel
< 0.10negligible
0.10 – 0.29small
0.30 – 0.49medium
≥ 0.50large
v0.8

POST /fimix

FIMIX-PLS (Finite Mixture PLS) detects unobserved heterogeneity by running an Expectation-Maximisation algorithm over PLS-SEM path weights to identify latent segments with distinct structural coefficient profiles. Reference: Hahn et al. 2002; Ringle et al. 2010.

Segment selection: run with k = 2 to 5 and compare AIC3 / CAIC / relative entropy (EN ≥ 0.5 indicates acceptable separation).
POST /fimix FIMIX-PLS → FIMIXResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset (CSV, XLSX, SAV)
modelrequiredstringlavaan syntax (PLS-SEM)
n_segmentsrequiredintNumber of segments k (2–5)
max_iteroptionalint100EM iterations before convergence
seedoptionalint42Random seed for reproducibility
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → FIMIXResult

FieldTypeNotes
n_segmentsintk as requested
segmentsFIMIXSegment[]One entry per segment
aic / bic / aic3 / caicfloatInformation criteria for model selection
entropyfloatRelative entropy EN (0–1; ≥ 0.5 recommended)
n_obsintEffective sample size
warningsstring[]

FIMIXSegment fields

FieldTypeNotes
segment_idint1-indexed
size / size_pctint / floatObservations assigned to this segment
path_coefficientsdict[str, float]Segment-specific β values keyed by "lhs~rhs"
r_squareddict[str, float]R² per endogenous construct in this segment
posterior_probsfloat[]Per-observation membership probability
v0.8

POST /pos

PLS Prediction-Oriented Segmentation (PLS-POS) assigns observations to segments by minimising within-segment residuals iteratively — no distributional assumptions required. Reference: Becker et al. 2013.

POST /pos PLS-POS → POSResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset (CSV, XLSX, SAV)
modelrequiredstringlavaan syntax (PLS-SEM)
n_segmentsrequiredintNumber of segments k (2–5)
max_iteroptionalint100
seedoptionalint42
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → POSResult

FieldTypeNotes
n_segmentsint
segmentsPOSSegment[]One entry per segment
convergedboolWhether assignment stabilised before max_iter
iterationsintActual iterations run
n_obsint
warningsstring[]

POSSegment fields

FieldTypeNotes
segment_idint1-indexed
size / size_pctint / float
path_coefficientsdict[str, float]Segment-specific β values
loadingsdict[str, float]Outer loadings for this segment
r_squareddict[str, float]R² per endogenous construct
observation_idsint[]0-indexed row numbers assigned to this segment
v0.8

POST /gaussian-copula

The Gaussian Copula approach (Park & Gupta 2012; Hult et al. 2018) corrects for endogeneity arising from non-normal, non-elliptical predictor distributions by augmenting the structural model with copula terms derived from the empirical CDF of each non-normal predictor.

Precondition: non-normality of the predictor is a necessary condition — normally distributed predictors cannot form valid copula terms. NAVAL-SEM screens automatically using Henze-Zirkler and skewness tests.
POST /gaussian-copula Endogeneity correction → GaussianCopulaResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileDataset (CSV, XLSX, SAV)
modelrequiredstringlavaan syntax
algorithmoptionalstringpls
bootstrap_noptionalint500Bootstrap resamples for copula coefficient CIs
significanceoptionalfloat0.05α threshold for non-normality test
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → GaussianCopulaResult

FieldTypeNotes
correctionsCopulaCorrection[]One entry per endogenous path corrected
screened_predictorsdict[str, bool]Non-normality test result per predictor
n_obsint
bootstrap_nint
warningsstring[]

CopulaCorrection fields

FieldTypeNotes
lhs / rhsstringOutcome and predictor construct names
copula_coeffloatCopula term coefficient in augmented model
ci_lower_95 / ci_upper_95float | nullBootstrap percentile CI
significantboolTrue when CI excludes 0 — endogeneity confirmed
original_coef / corrected_coeffloatPath coefficient before and after correction
f2_correctionfloatCohen's f² for endogeneity increment
v0.8

POST /export/pdf

Generate a publication-ready PDF report from any completed run. The report covers measurement model validity, structural path estimates, bootstrapped confidence intervals, model fit indices, and any advanced analysis results (FIMIX, PLS-POS, Gaussian Copula, IPMA, NCA) that were included in the run. Tables follow APA 7th edition formatting conventions.

POST /export/pdf Run results → application/pdf (binary stream)

Form Parameters

FieldTypeDefaultDescription
run_idrequiredstringUUID of the completed run to export
include_advancedoptionalbooltrueInclude FIMIX / PLS-POS / Copula / IPMA / NCA sections if present
paperoptionalstringA4A4 | Letter

Response

HeaderValue
Content-Typeapplication/pdf
Content-Dispositionattachment; filename="naval-sem-{run_id}.pdf"
Example — cURL
curl -X POST http://localhost:8000/export/pdf \
  -F "run_id=abc-123" \
  --output report.pdf
v0.9 — New

POST /cvi

Content Validity Index (Lynn 1986; Polit & Beck 2006). Accepts an expert ratings matrix — rows are experts, columns are scale items, values are 1–4 relevance ratings — and returns item-level I-CVI, scale-level S-CVI/Ave and S-CVI/UA, and modified kappa (κ*) correcting I-CVI for chance agreement.

Acceptability thresholds (Lynn 1986): I-CVI ≥ 0.78 per item; S-CVI/Ave ≥ 0.90 for excellent content validity. Use a minimum of 5 experts; κ* ≥ 0.74 is considered excellent agreement beyond chance.
POST /cvi Expert ratings → CVIResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV or XLSX — rows = experts, columns = items, values = 1–4 ratings
n_expertsrequiredintNumber of expert raters (rows in the file)
relevant_scaleoptionalstring3,4Comma-separated rating values counted as "relevant" (default top-two of a 4-pt scale)
missingoptionalstringlistwise

Returns → CVIResult

FieldTypeNotes
item_cviDict[str, float]I-CVI per item (proportion of experts rating it relevant)
s_cvi_avefloatMean of all I-CVI values
s_cvi_uafloatUniversal Agreement: proportion of items with I-CVI = 1.00
kappa_starfloatModified kappa averaged across items — adjusts for chance agreement
n_experts / n_itemsint
interpretationstring"Excellent" (S-CVI/Ave ≥ 0.90 and all I-CVIs ≥ 0.78) · "Acceptable" (≥ 0.80) · "Poor"
Input file format
# CSV — rows are experts (E1…E7), columns are items (Q1…Q6)
    ,Q1,Q2,Q3,Q4,Q5,Q6
E1 , 4, 3, 2, 4, 3, 4
E2 , 3, 4, 4, 4, 3, 3
E3 , 4, 4, 3, 3, 4, 4
# ... up to n_experts rows
cURL example
curl -X POST http://localhost:8000/cvi \
  -F "file=@expert_ratings.csv" \
  -F "n_experts=7"
v0.9 — New

POST /efa

Exploratory Factor Analysis for early-stage scale development. Computes KMO adequacy and Bartlett's test of sphericity as suitability diagnostics, applies the Kaiser criterion (eigenvalue > 1) or a user-specified factor count, and extracts factors via sklearn's FactorAnalysis with the requested rotation. Flags weak-loading items (|λ| < 0.40) and cross-loading items (secondary |λ| > 0.30).

EFA is intended for early item screening and dimensionality exploration. Confirm final factor structure with CFA via POST /run before reporting measurement quality metrics (AVE, CR, HTMT).
POST /efa Exploratory Factor Analysis → ScaleDevelopmentResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV or XLSX — respondents × items (numeric only)
n_factorsoptionalintKaiser (eigenvalue > 1)Number of factors to extract; omit for automatic Kaiser selection
rotationoptionalstringvarimaxRotation method passed to sklearn FactorAnalysis (e.g. varimax, quartimax)
missingoptionalstringlistwise

Returns → ScaleDevelopmentResult

FieldTypeNotes
methodstringE.g. "PCA_Varimax"
n_factorsintNumber of factors extracted (auto or specified)
kmofloatKaiser-Meyer-Olkin adequacy statistic (≥ 0.60 acceptable, ≥ 0.80 good)
bartlett_chi2 / bartlett_pfloatBartlett's test of sphericity χ² and p-value (p < 0.05 needed)
eigenvaluesfloat[]Full eigenvalue spectrum (descending)
variance_explainedfloat[]Proportion of variance explained per factor
cumulative_variancefloatTotal variance explained by all retained factors
loadingsDict[]Array of {item, factor, loading} — primary assignment per item
cross_loadingsDict[] | null{item, primary_factor, secondary_factor, secondary_loading} — only items where secondary |λ| > 0.30
warningsstring[]Weak-loading items, KMO below threshold, non-significant Bartlett

Diagnostic thresholds

StatisticAcceptableGood
KMO≥ 0.60≥ 0.80
Bartlett p< 0.05< 0.001
Primary loading |λ|≥ 0.40≥ 0.60
Secondary loading |λ|< 0.30 (no cross-loading)
cURL example — 3-factor solution with varimax
curl -X POST http://localhost:8000/efa \
  -F "file=@survey_items.csv" \
  -F "n_factors=3" \
  -F "rotation=varimax"
v0.9 — New

POST /nomological

Nomological Validity (Hair et al. 2019). Fits the structural model and checks whether each endogenous construct's R² meets the expected benchmark — the minimum explanatory power consistent with the theoretical nomological network the construct is embedded in. Returns a per-construct verdict (Substantial / Moderate / Weak / Not supported) using Cohen's (1988) conventional R² bands.

POST /nomological Nomological validity → NomologicalResult[]

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV, XLSX, or SAV dataset
modelrequiredstringlavaan syntax
algorithmoptionalstringplspls | cb | wls
benchmarksoptionalJSON string{"*": 0.10}Per-construct minimum R² map; use "*" as wildcard default
missingoptionalstringlistwise

Returns → NomologicalResult[] (one per endogenous construct)

FieldTypeNotes
construct_namestringEndogenous construct name (JSON key: "construct")
r_squaredfloatObserved R² from model fit
benchmarkfloatMinimum R² threshold used (from benchmarks map)
passedboolTrue when R² ≥ benchmark
interpretationstring"Substantial" (R² ≥ 0.26) · "Moderate" (≥ 0.13) · "Weak" (≥ benchmark) · "Not supported"

R² Interpretation Bands (Hair et al. 2019)

Label
≥ 0.26Substantial
0.13 – 0.25Moderate
≥ benchmark (default 0.10)Weak
< benchmarkNot supported
Example — custom benchmarks per construct
curl -X POST http://localhost:8000/nomological \
  -F "file=@data.csv" \
  -F "model=Y =~ y1+y2+y3\nX =~ x1+x2+x3\nY ~ X" \
  -F 'benchmarks={"Y":0.15,"*":0.10}'
v0.9 — New

POST /invariance

Measurement Invariance testing via a configural → metric → scalar sequence (Vandenberg & Lance 2000; Cheung & Rensvold 2002). Tests whether the same measurement model holds equivalently across groups, a prerequisite for meaningful multi-group structural comparisons. Uses ΔCFI ≤ −0.010 as the invariance failure criterion (robust to sample size). Returns a plain-English conclusion and, when scalar fails, a partial-invariance item release list.

Prerequisite for MGA: at minimum, metric invariance (ΔCFI > −0.010 from configural to metric) must hold before interpreting path-coefficient differences from POST /mga. Full scalar invariance is required before comparing latent means.
POST /invariance Measurement Invariance → MeasurementInvarianceResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV, XLSX, or SAV — must contain the grouping column
modelrequiredstringlavaan measurement syntax (=~ blocks)
group_colrequiredstringColumn name whose values define groups (≥ 2 distinct values)
missingoptionalstringlistwise
run_idoptionalstringauto UUIDSSE tracking ID

Returns → MeasurementInvarianceResult

FieldTypeNotes
group_colstringGrouping variable name
groupsstring[]Sorted distinct group labels
configuralMeasurementInvarianceLevelBaseline — free parameters per group; always passes by definition
metricMeasurementInvarianceLevelLoadings constrained equal; ΔCFI vs configural
scalarMeasurementInvarianceLevelLoadings + intercepts constrained; ΔCFI vs metric
partial_invariancestring[] | nullItems released when scalar partially holds
conclusionstring"Full scalar" · "Partial scalar" · "Metric only" · "Configural only"

MeasurementInvarianceLevel fields

FieldTypeNotes
modelstring"configural" | "metric" | "scalar"
cfi / rmsea / srmrfloat | nullFit indices for this constrained model
delta_cfi / delta_rmseafloat | nullChange vs. preceding model in the sequence
passedboolTrue when ΔCFI > −0.010
The engine fits each constrained model on the pooled stacked dataset (all groups combined). Per-group fit in the configural step is averaged using harmonic-mean weighting by group size.
Example
curl -X POST http://localhost:8000/invariance \
  -F "file=@data.csv" \
  -F "model=X =~ x1+x2+x3\nY =~ y1+y2+y3" \
  -F "group_col=gender"
v0.9 — New · Unscheduled

POST /nca-esse

NCA with Effect Size Sensitivity Extension (Becker, Richter, Ringle & Sarstedt 2026, Journal of Business Research, 206, 115920 — CC BY 4.0). Extends deterministic NCA (Dul 2016) by sweeping an ECDF removal threshold (default 0–5% in 0.5% steps) and recomputing CE-FDH ceiling lines at each step after discarding the most extreme ceiling-violating observations. Benchmarks the empirical sensitivity curve against a joint-uniform random distribution (no necessity by construction) and permutation-tests the effect size at every threshold, to distinguish genuine necessity from artefactual ceiling movement.

When to use: run NCA-ESSE after a standard POST /nca when you suspect a small share of atypical response combinations may be collapsing a true necessity effect to zero. The recommended threshold tells you the smallest exclusion level at which the empirical effect consistently beats the no-necessity benchmark.
POST /nca-esse NCA Sensitivity Extension → NCAESSEResult

Form Parameters

FieldTypeDefaultDescription
filerequiredFileCSV, XLSX, or SAV dataset
modelrequiredstringlavaan syntax; all structural IV→DV pairs are tested
thresholdsoptionalJSON float[][0.0, 0.005, … 0.05]ECDF removal thresholds to sweep (0–1 fractions)
n_permutationsoptionalint200Permutation samples per threshold per pair
n_benchmark_repsoptionalint200Joint-uniform benchmark replications per pair
seedoptionalint42RNG seed
missingoptionalstringlistwise
run_idoptionalstringauto UUID

Returns → NCAESSEResult

FieldTypeNotes
entriesNCAESSEEntry[]One per unique IV→DV structural pair (requires ≥ 30 valid observations)
threshold_rangefloat[]The threshold sweep list used
benchmarkstring"joint_uniform" — theoretical no-necessity distribution
n_permutations / n_benchmark_repsint
warningsstring[]Pairs skipped (insufficient n, data errors)

NCAESSEEntry fields

FieldTypeNotes
iv / dv / n_obsstring / int
thresholdsNCAESSEThresholdPoint[]One point per threshold step
recommended_thresholdfloat | nullLargest threshold in a contiguous benchmark-beating gain run from the first nonzero step
recommended_effect_sizefloat | nullCE-FDH d at the recommended threshold
recommended_labelstring | nullnegligible / small / medium / large (Dul 2016)
ceiling_x / ceiling_yfloat[]CE-FDH staircase at the recommended threshold (≤ 100 pts)
warningsstring[]Per-pair notices

NCAESSEThresholdPoint fields

FieldTypeNotes
thresholdfloatECDF removal fraction (e.g. 0.0, 0.005, … 0.05)
pct_excludedfloatActual fraction removed (may differ from threshold on discrete data)
empirical_dfloatCE-FDH effect size after removal
theoretical_dfloatMean CE-FDH on joint-uniform benchmark at same threshold
delta_empirical / delta_theoreticalfloat | nullGain vs. previous threshold step
delta_difffloat | nulldelta_empirical − delta_theoretical; > 0 means genuine necessity signal
p_valuefloat | nullPermutation p-value (proportion of shuffled-Y runs ≥ empirical_d)
significantboolTrue when p < 0.05
A minimum of 30 valid observations per IV→DV pair is required for a meaningful threshold sweep. Pairs below this threshold are skipped and reported in warnings. Pairs with ties at identical (x, y) coordinates are handled by removing the full tied cell at each threshold step.
cURL example
curl -X POST http://localhost:8000/nca-esse \
  -F "file=@data.csv" \
  -F "model=Y =~ y1+y2+y3\nX =~ x1+x2+x3\nY ~ X" \
  -F "n_permutations=500" \
  -F "n_benchmark_reps=500"
Reference
Becker, J.-M., Richter, N. F., Ringle, C. M., & Sarstedt, M. (2026).
Must-have, or maybe not? A sensitivity-based extension to necessary
condition analysis. Journal of Business Research, 206, 115920.
https://doi.org/10.1016/j.jbusres.2025.115920  (CC BY 4.0)

Changelog

v0.9
  • Content Validity Index: I-CVI per item, S-CVI/Ave, S-CVI/UA, modified kappa (κ*) — POST /cvi (Lynn 1986; Polit & Beck 2006)
  • Exploratory Factor Analysis: KMO, Bartlett's sphericity, Kaiser criterion, configurable rotation, weak- and cross-loading detection — POST /efa
  • Nomological Validity: per-construct R² vs Hair et al. (2019) benchmarks, Substantial/Moderate/Weak/Not-supported verdicts — POST /nomological
  • Measurement Invariance: configural → metric → scalar sequence, ΔCFI ≤ −0.010 criterion, partial-invariance item release — POST /invariance
  • NCA-ESSE (unscheduled): ECDF threshold sweep 0–5%, joint-uniform benchmark, permutation significance, recommended threshold and ceiling line — POST /nca-esse (Becker et al. 2026, JBR)
  • pytest suite: 47 unit tests across all analysis engines (pytest tests/)
v0.8
  • FIMIX-PLS: EM-based finite mixture segmentation, k=2–5, AIC/BIC/AIC3/CAIC/EN, segment-specific path coefficients and R²
  • PLS-POS: prediction-oriented segmentation via iterative residual-based assignment
  • Gaussian Copula: endogeneity correction for non-normal predictors (Park & Gupta 2012), bootstrap CIs, f² effect size
  • PDF Report Export: APA-style publication-ready PDF via POST /export/pdf
  • Centralised versioning: app/version.py single source of truth, CI-injected from git tag
  • CI/CD: sync-to-master step removed from release workflow; all platform builds clean
v0.7
  • Moderation: product-of-composites, OLS fallback for manifest models, bootstrap simple slopes at −1 SD / 0 / +1 SD, Δ R², Cohen's f²
  • IPMA: total-effect importance, 0–100 rescaled performance, configurable theoretical scale range
  • NCA: CE-FDH staircase ceiling, CR-FDH regression ceiling, permutation p-values, scatter / ceiling coordinates for frontend rendering
  • Moderated Mediation (Hayes Models 7, 14, 58/59): IMM with bootstrap CI, conditional indirect effects at 3 moderator levels
  • ModelSummary digest in /run response: structural path table, construct validity table, verdicts
  • Auto reverse-scoring via r-prefix convention (auto_reverse_score)
  • Residual covariance expansion fix (TC-52): multi-target ~~ shorthand correctly split into individual pairs
  • Reproducibility fingerprint (SHA-256) in all /run responses and accessible via GET /fingerprint/{run_id}
v0.6
  • Higher-Order Constructs: repeated-indicator and two-stage approaches
  • GitHub Actions CI/CD: version injected from git tags
  • Full-width results drawer with live SSE logging
  • MGA and MICOM tabs wired in UI
  • SourceForge distribution connector via native GitHub integration
v0.5
  • Predictive relevance suite: Q², PLSpredict, CVPAT (POST /predict)
  • Common Method Bias marker variable analysis (POST /cmb)
  • Outer weights bootstrap with t-statistics
v0.4
  • Multi-Group Analysis with MICOM (POST /mga)
  • Indirect effects decomposition (POST /indirect)
  • VIF collinearity table, Cohen's f² for all structural paths
v0.3
  • HTMT discriminant validity (POST /htmt)
  • AVE, composite reliability, Cronbach's α in FitIndices
  • Fornell-Larcker criterion matrix
≤ v0.2
  • Initial public release: PLS-SEM / CB-SEM / WLS via semopy backend
  • Bootstrap standalone (POST /bootstrap)
  • CSV / XLSX / SAV parser, SSE log stream, /health endpoint
  • PyInstaller distributable for Windows, macOS, Linux