# GPCM scope and current limitations

`mfrmr` includes a scope-bounded implementation of the Generalized Partial Credit Model (GPCM; Muraki 1992). The estimator is available under the documented constraints, while several downstream reporting helpers remain restricted because score-side semantics under free discrimination differ from the Rasch-family case. This vignette documents which helpers are available, which are not, and what to use as a substitute when a helper is restricted.

In this guide, bounded describes the supported model and workflow boundary; it does not mean finite lower and upper parameter bounds. The JML route uses an unpenalized identified joint likelihood. A non-representable slope proposal can be rejected during line search for numerical safety, but that is not a statistical penalty. If the likelihood has a certified recession direction, the finite optimizer iterate is retained only as a numerical trace and the primary result carries an extended-real or typed boundary status.

## Relationship to generalized many-facet models

Ordinary GPCM adds a positive discrimination parameter to the partial-credit kernel; it does not replace the item position or step parameters. In the current many-facet notation,

\[ \log\frac{P(Y_o=k)}{P(Y_o=k-1)} = \alpha_{g(o)}\{\eta_o-\tau_{g(o),k}\}, \qquad \prod_g\alpha_g=1, \]

where the additive predictor \(\eta_o\) contains person ability and the signed locations of the observed facets. Thus the selected slope multiplies the complete adjacent-category predictor: person ability, every facet location or fitted interaction inside \(\eta_o\), and the owned step. It is not a loading-only formulation in which discrimination multiplies ability but leaves rater severity and other intercept effects unscaled. Unit slopes reduce this expression to the equal-discrimination PCM kernel.

The phrase generalized many-facet Rasch model is broader and is not a unique synonym for this implementation. For example, Uto and Ueno (2020, equation 9) use multiplicative task and rater slope blocks, \(\alpha_i\alpha_r\), together with rater severity and rater-specific steps. By contrast, mfrmr 0.2.3 requires one facet to own both the slope and step blocks: `slope_facet == step_facet`. It does not jointly estimate task and rater slopes, decouple the slope owner from the step owner, or introduce a multidimensional ability vector. The precise name used in the 0.2.3 evidence map is therefore aligned single-owner relative-slope GPCM.

A rater-owned fit is close to a restricted Uto–Ueno form after suppressing the task-slope block, provided the remaining step and identification contracts are also aligned. A criterion-owned fit instead has criterion-owned slopes and steps and should be described as an analogous restricted many-facet GPCM, not as an exact fit of Uto and Ueno’s equation. Because free discrimination relaxes the defining equal-discrimination Rasch restriction, “generalized MFRM” means a model generalized from the MFRM baseline rather than a strict Rasch model.

### Which facet receives different slopes?

The slope is not one common number for the entire fitted GPCM. The selected `slope_facet` contributes one positive slope for each of its levels. If it has \(G\) levels, the returned table contains \(G\) slopes and the model estimates \(G-1\) free relative log-slope contrasts because their geometric mean is fixed to one.

Configuration | Meaning | Current status
--- | --- | ---
`step_facet = "Criterion"`, `slope_facet = "Criterion"` | Each criterion has its own relative discrimination and criterion-specific steps. | Supported bounded route.
`step_facet = "Rater"`, `slope_facet = "Rater"` | Each rater has its own model-conditional relative discrimination and rater-specific steps. | Code-supported with rater-interpretation caveats; a slope is not automatically evidence of rater consistency.
Criterion steps with rater slopes, or conversely | Slope owner and step owner differ. | Unsupported in 0.2.3.
Criterion slopes and rater slopes together | Effective discrimination could involve two slope blocks. | Unsupported in 0.2.3; this is closer to a multiplicative generalized-MFRM extension.

Every facet that is not selected remains an additive location term inside \(\eta\). For example, a criterion-owned GPCM can still estimate rater severity, but it does not give each rater a separate discrimination parameter. The criterion slope nevertheless scales that rater-severity contribution because the contribution is inside \(\eta\). “No separate rater slope” and “rater severity is unscaled” are therefore not the same statement.

### An explanation for a high-school reader

Imagine that several teachers grade presentations on several criteria.

- PCM gives everyone rulers with the same magnification. One criterion may be harder and one teacher may be stricter, but a one-unit ability difference changes the rating probabilities at the same basic sharpness everywhere.
- The current mfrmr GPCM lets you choose one box of rulers. If the box is `Criterion`, each criterion can have a different magnification. If the box is `Rater`, each rater can have a different magnification. You may choose only one box, and the same box also owns the category steps.
- A broader generalized MFRM can give both the task/criterion and the rater their own magnification knobs. In the Uto–Ueno example, the effective sharpness is the product of the task and rater settings. It can also model rater severity and rater-specific use of rating categories.

Thus the current GPCM is a smaller branch inside the broader family: it adds a carefully controlled slope vector to a many-facet PCM, but it is not the full two-knob generalized MFRM. Also, once discrimination is allowed to vary, the model is generalized from the Rasch baseline; it no longer retains the strict equal-discrimination Rasch restriction.

## Before fitting: model-choice triage

Do not choose `GPCM` only because it is the most flexible model in the menu. Start with the score interpretation.

Model | Use when | Main risk if over-used
--- | --- | ---
`RSM` | The rating scale is intended to share one category-threshold structure across the step facet. | Real threshold differences can be hidden in residual diagnostics.
`PCM` | Thresholds may differ by item, criterion, task, or another designated step facet, but rating events should still contribute equally after conditioning on the modeled facets. | It can absorb threshold heterogeneity without asking whether some levels are more discriminating.
bounded `GPCM` | The analysis explicitly allows discrimination-based reweighting and treats slopes as part of the substantive sensitivity question. | Better statistical fit can be mistaken for a better operational scoring rule.

This ordering matters for reporting. `RSM` and `PCM` are the package’s equal-weighting reference route; bounded `GPCM` is a slope-aware extension. If equal contribution of items, criteria, or raters is part of the validity argument, a better-fitting bounded `GPCM` should be reported as sensitivity evidence rather than as an automatic replacement.

### Comparing PCM and bounded GPCM

The package provides three complementary comparison layers:

1. `compare_mfrm()` displays same-data log likelihood, AIC, Person-based BIC, SABIC, deltas, and candidate-set weights. Automatic ranking requires inference-ready MML fits, identical prepared rows and constraints, a common quadrature identity, and at least 31 quadrature points. Always inspect `comparison$table$ICComparable` first.
2. `build_weighting_review()` shows what the GPCM slopes changed: the slope profile, facet-measure shifts, and redistribution of information across levels.
3. `build_model_choice_review(..., run_weighting_review = TRUE)` bundles the statistical comparison, operational model roles, support boundaries, and the weighting review.

    fit_pcm <- fit_mfrm(
      dat, "Person", c("Rater", "Criterion"), "Score",
      method = "MML", model = "PCM",
      step_facet = "Criterion", quad_points = 31
    )

    fit_gpcm <- fit_mfrm(
      dat, "Person", c("Rater", "Criterion"), "Score",
      method = "MML", model = "GPCM",
      step_facet = "Criterion", slope_facet = "Criterion",
      quad_points = 31
    )

    comparison <- compare_mfrm(PCM = fit_pcm, GPCM = fit_gpcm)
    comparison$table[, c(
      "Label", "LogLik", "AIC", "BIC", "SABIC", "ICComparable"
    )]

    weighting <- build_weighting_review(fit_pcm, fit_gpcm)
    summary(weighting)
    weighting$comparison_contract

    review <- build_model_choice_review(
      PCM = fit_pcm,
      GPCM = fit_gpcm,
      run_weighting_review = TRUE
    )
    summary(review)
    review$model_roles[, c(
      "Model", "StepStructure", "StepCoordinates", "FreeStepParameters",
      "SlopeStructure", "SlopeCoordinates", "FreeSlopeParameters",
      "FitReadiness", "FormalInference", "Interpretation"
    )]

`StepCoordinates` and `SlopeCoordinates` count the values shown in fitted tables. `FreeStepParameters` and `FreeSlopeParameters` count the independent coordinates optimized after identification constraints. For example, with four score categories and four levels of the step facet, PCM and GPCM display 12 step coordinates but optimize 8 free step parameters because each three-step ladder is sum-zero. GPCM additionally displays four relative slopes but optimizes three free log slopes because their geometric mean is one.

The `comparison_contract` keeps four situations separate:

Evidence tier | What may be concluded?
--- | ---
`same_basis_mml_information_criteria` | AIC, Person-BIC, and SABIC may be read as candidate-set evidence, together with slope stability and a denser common-grid check.
`mml_screening_or_review_grid_only` or other non-comparable MML tier | Raw fit values are descriptive; repair integration selectability, readiness, or comparison identity first.
`jml_descriptive_reweighting_only` | The fitted slopes, measure shifts, and information redistribution may be reviewed, but the unpenalized JML likelihood gain does not select GPCM.
`jml_optimizer_trace_only_not_inference_ready` | Even the likelihood difference is only a comparison of retained optimizer traces; it is not inferential model evidence.

For a JML question, follow that table with recovery conditions rather than an IC or LRT claim. `evaluate_mfrm_recovery()` already distinguishes `unit_slopes`, `near_flat`, `moderate`, and `high_dispersion` generator conditions. The unit-slope condition asks how often harmless sampling and optimizer variation can create an apparent slope spread; the non-unit conditions ask whether the declared heterogeneity can be recovered. FACETS can support the aligned PCM/JML side of this review, but its Table 7 discrimination remains a post-fit diagnostic and not a free-slope GPCM fit.

PCM is obtained from the aligned GPCM response kernel by setting all slopes to one. Nevertheless, the current conservative nesting contract does not compute a PCM-versus-GPCM chi-square likelihood-ratio test. Calling `compare_mfrm(..., nested = TRUE)` records the relation `PCM_in_GPCM_ic_only` and withholds the LRT. This keeps an attractive information-criterion result from being overstated when GPCM parameter or boundary readiness remains unresolved. When the IC comparison is suppressed, the raw fit values and weighting review remain descriptive evidence rather than an automatic selection rule.

## Response-family boundary

Every current `fit_mfrm()` likelihood is ordered categorical. The distinction between response values and observation frequencies is essential:

Input or estimand | 0.2.3 treatment
--- | ---
Ordered binary response | Supported as a two-category ordered response.
Ordered polytomous response | Supported through RSM, PCM, or bounded GPCM.
Unordered nominal/multinomial response | Unsupported; category order enters the current likelihood.
Poisson, negative-binomial, or grouped binomial-trial count | Unsupported as a response family. An integer `Score` is only an ordered category code.
Row-frequency/replication weight for an ordered rating | A positive numeric `weight` can weight that row’s conditional ordered-category likelihood contribution.

Thus, the fact that the fitted category probabilities sum to one does not make the model a nominal-response or multinomial-logit model. Likewise, a frequency weight does not turn the score into a Poisson count or account for dependence among replicated ratings. Nor is it a general collapsed-person frequency table: under MML, powering responses inside one Person’s conditional pattern is not equivalent to replicating a complete Person pattern after marginalization. FACETS provides separate `Bn` and `P` response models; those are outside the current mfrmr estimator even though FACETS-style coverage documentation describes the handoff boundary.

Within that supported scope, an explicit identification contract is still required. With default MML, `gpcm_mml_identification = "free_population"` estimates an intercept-only person distribution \(N(\beta_0,\sigma^2)\), while the level-specific log slopes are constrained to sum to zero (geometric mean 1). The fitted slopes are therefore relative discriminations with \(G-1\) free contrasts, and \(\sigma\alpha_g\) gives the equivalent slope on a fixed-latent-standard- deviation scale. This retains the conventional common-discrimination degree of freedom. The explicit legacy mode `gpcm_mml_identification = "fixed_standard_normal"` instead fixes both \(\sigma=1\) and the slope geometric mean to one and is a narrower model.

## GPCM is not one estimator

Muraki (1992) supplies the GPCM response model and an MML-EM estimation route; it is not a source for the present JML implementation. The present mfrmr JML route is an identified fixed-effects, unpenalized joint likelihood with post-fit boundary/recession auditing. This differs from penalized JML for GPCM (Wijayanto et al. 2021), whose quadratic regularization changes the objective, and from software routes that impose finite parameter boxes. A penalized, adjusted, or box-constrained point estimate can be a useful comparator, but it is not the maximizer of mfrmr’s original unpenalized JML objective.

This distinction matters even when all methods return finite numbers. With a fixed number of observations per person, jointly estimated person coordinates are incidental parameters; structural JML estimates can retain finite-test- length bias as the number of persons grows (Hessen 2025). An extreme response pattern can additionally make the ordinary finite JML maximum unattained. mfrmr therefore keeps recovery/bias evidence, boundary handling, numerical convergence, and cross-software agreement as separate gates. Under JML, the geometric-mean constraint resolves the scale of the jointly estimated person coordinates and slopes.

## Report wording templates

Use wording that matches the model actually fitted:

- `RSM`: “We fit a many-facet rating-scale Rasch model, treating category thresholds as common across the step facet.”
- `PCM`: “We fit a many-facet partial-credit Rasch model, allowing thresholds to vary by the designated step facet while retaining equal discrimination.”
- bounded `GPCM`: “We fit a bounded generalized partial-credit many-facet model as a slope-aware sensitivity analysis; interpretation focused on whether discrimination-based reweighting changed the substantive conclusions.”

Avoid wording that says bounded `GPCM` “improves the score” solely because it improves log-likelihood, `AIC`, or `BIC`. The model can fit better while changing the scoring contract.

## Checking the support boundary

`gpcm_capability_matrix()` is the canonical reference. It returns one row per helper family with a `Status` column drawn from `supported`, `supported_with_caveat`, `blocked`, and `deferred`. Read `Boundary` for the interpretive limit and `RecommendedRoute` for the route to use next. The default print is deliberately compact; subset by status to inspect a focused set of rows.

    library(mfrmr)
    gpcm_capability_matrix("supported")[, c("Area", "Status")]

    gpcm_capability_matrix("supported_with_caveat")[, c("Area", "Status")]

    gpcm_capability_matrix("blocked")[, c("Area", "Status", "RecommendedRoute")]

    gpcm_capability_matrix("deferred")[, c("Area", "Status", "Boundary", "RecommendedRoute")]

The matrix is intentionally conservative. A row stays in `blocked` or `deferred` even when some individual computation is already available, because the scope statement includes the interpretation needed for a complete public workflow rather than only checking whether code executes.

## Slope values, boundaries, and uncertainty

The finite `LogEstimate` and `Estimate` columns in `fit$slopes` are optimizer outputs, not automatic evidence of a finite estimand. Use `ParameterStatus` and the `Primary*` columns first. Under JML, mfrmr can certify a monotone sum-to-zero log-slope path while holding the retained additive coordinates fixed. Such a result yields `unbounded_low`, `unbounded_high`, or `unbounded_both`. If no such path is certified, the joint Person–facet–step– slope problem remains unevaluated; the finite optimizer output is retained only as a numerical trace. A second bounded check lets additive coordinates move with an ordered positive/negative log-slope pair. A competitive path from this family is recorded as a candidate, but `ParameterStatus` remains `not_evaluated` and the primary value remains unavailable: this sufficient path result does not determine the global maximum of the non-concave GPCM likelihood. Failure to find such a path is equally limited to that family. Under MML, Persons are integrated out, so neither conditional JML result is reused as marginal-likelihood evidence. The MML branch records a separate sufficient-path check for the fitted finite-quadrature objective, but that check is not a complete analysis of the continuous marginal likelihood. Whether it finds a path or not, free MML slopes remain `not_evaluated` until the applicable parameter-level readiness conditions are established. Use [gpcm_mml_quadrature_sensitivity()] to inspect movement across quadrature grids; grid stability is numerical evidence, not proof that a finite global maximum exists or that slope uncertainty is inferentially eligible.

The same distinction applies to uncertainty. `diagnose_mfrm()` can retain the local covariance calculation as `Optimizer*SE` and `Optimizer*CI` fields for numerical review. Ordinary slope `SE` and confidence-limit fields remain unavailable when `SEEligible` or `CIEligible` is false. This avoids presenting a local Hessian around a finite stopping point as uncertainty for a parameter whose applicable global boundary status has not been established.

## What can and cannot be compared across programs

A column labelled “discrimination” is not sufficient evidence that two programs fitted the same GPCM. FACETS reports an element-discrimination diagnostic after estimating its Rasch measures and explicitly does not allow that diagnostic to alter the other estimates. It is therefore not a matched counterpart of a jointly estimated free slope in `mfrmr`. FACETS remains useful for unit- or explicitly fixed-discrimination reductions, category/threshold and facet-measure comparisons within a common Rasch specification, and as a deliberately different-model diagnostic benchmark.

TAM’s MML 2PL/GPCM route does estimate slopes, including grouped or designed slopes, but TAM documents that slopes are not estimated by its many-facet fitting function. A TAM comparison must therefore use a provably equivalent non-faceted or re-expressed design and must match the latent variance, threshold convention, slope grouping, category map, and retained observations before computing differences. `sirt::rm.facets()` provides a useful second MML reference: it estimates item and/or rater slopes under product-one centering and an estimated normal trait spread. Its item-only GPCM and equal-discrimination many-facet reductions are candidate matched lanes after category, threshold, quadrature, and centering conventions are aligned. Its general free-slope rater kernel is not the current mfrmr kernel: sirt uses the product of item and rater slopes on the trait term while rater severity remains a separate location term, whereas mfrmr assigns one slope owner and multiplies the complete adjacent- category predictor. Such results are different-model sensitivity evidence, not automatic numerical validation. `immer` provides PCM-design JML/CML/CCML routes and a hierarchical rater model, not a direct free-GPCM many-facet match. Its role is consequently a unit-slope reduction or alternative-model sensitivity analysis rather than free-slope numerical validation.

TAM also documents a multifacet slope construction that sends a facet-model intercept design `A` and a slope-group design `E` to `tam.mml.2pl()`. That is not automatically the current mfrmr kernel. In the TAM construction the slope weights the latent-trait term while shared Rater and step effects remain linear intercepts; in mfrmr the selected slope weights the complete adjacent-category predictor, including Rater severity and steps. Matching the latter would require products such as an estimated Criterion slope times an estimated Rater severity, which the two independent linear designs do not impose. A q=31 `example_core` re-expression was therefore retained as different-model sensitivity evidence, not as an exact full-model comparison. This algebraic screen makes a second quadrature run unnecessary.

A bounded validation comparison exercises the exact item-only TAM overlap on TAM’s `data.gpcm` fixture at q=31 and q=41. TAM fixes the latent variance and estimates absolute slopes; mfrmr fixes the geometric mean of its relative slopes and estimates the latent variance. After applying the analytic scale and location transformation, maximum q-specific differences were about `1.8e-5` for relative slopes, `1.3e-5` for transition thresholds, `6e-6` for fitted category probabilities, and `1.4e-6` for deviance. The transformed TAM probability formula itself agreed to binary64 precision. This is external evidence for the item-only GPCM kernel, coordinate map, and continuous MML target; it is not a comparison of the rater-plus-slope model, a cross-engine SE validation, or permission to override mfrmr readiness. The distinction follows TAM’s documented separation between `tam.mml.2pl()` and `tam.mml.mfr()`.

The same coordinate discipline prevents a direct SE comparison. TAM 4.3-25 retains marginal slope and intercept SEs, but not the joint slope covariance or slope–intercept cross-covariance required by the nonlinear transformation to mfrmr’s relative slopes, thresholds, and free population scale. Two positive- definite covariance matrices can preserve exactly those reported marginal SEs while producing different transformed SEs. The repository audit demonstrates this explicitly and withholds the comparison rather than assuming zero covariance. TAM’s documented `tam.se()` route also ignores parameter covariances, so it does not close this gap.

These distinctions also govern diagnostics. FACETS’ discrimination, `mfrmr` residual PCA or bias screens, and hierarchical-rater variance components answer different questions. Agreement among them can be supporting evidence; a difference is not a software error until the fitted likelihood, estimand, identification, data rows, and output transformation have first been shown to match.

A population-level validation also asked whether the current complete-predictor slope and a loading-only slope are merely two coordinate systems. They reduce exactly when slopes are all one or when the non-owner Rater contrast is zero. In a fully crossed four-Criterion/four-Rater design, however, their identifying adjacent-logit difference in differences is zero for loading-only and \(-\{\alpha_c-\alpha_d\}\{\rho_r-\rho_s\}\) for the current kernel. After all available slopes, severities, and transition boundaries were re-estimated, moderate and strong fixed conditions retained population KL losses of about 0.0016 and 0.0085–0.0088 per response, with maximum common-grid probability differences of about 0.047–0.184. q=31 and q=41 conclusions agreed closely. These are fixed model-form demonstrations, not practical cutoffs or finite-sample operating characteristics. They support treating a loading-only kernel as a separate possible future family rather than as an interpretation switch for an existing `GPCM` fit.

Sparsity changes this distinction structurally, not merely by reducing sample size. On an observed Rater-by-Criterion graph with no cycles, the products \(\alpha_c\rho_r\) can be represented exactly by new additive Rater and Criterion coordinates. Thus even a connected tree cannot distinguish the two slope actions. A known-ability validation compared four connected graphs. At 250 Persons, truth-selection rates were about 0.96 under complete crossing, 0.76–0.78 for a balanced eight-edge cycle, and only 0.58 for an eight-edge cycle localized to two Raters and two Criteria; the connected tree remained observationally equivalent. Each Person was observed on every edge, and abilities and both parameter vectors were supplied to the comparison, so these are optimistic fixed-parameter results rather than JML or MML model- selection performance. The design lesson is to inspect which slope and severity contrasts are traversed by cycles, not to infer identifiability from connectedness, density, or an anchor percentage alone.

A subsequent finite-sample validation removed the known-ability advantage and refitted both slope actions by direct MML. The common identification estimated geometric-mean-one relative slopes, sum-zero Rater severities, mean-zero transition boundaries, and a normal population mean and standard deviation. Across 12 replications per truth and design at 250 training Persons, all 96 candidate fits converged and all full 19-coordinate Hessians were positive definite. Two starts differed by at most about `7.9e-6` log-likelihood units, and q=31 versus q=41 changed none of the 48 paired family decisions. Complete crossing selected the true family in every training and independent holdout dataset. Under the balanced cycle, training selected the truth in 7–9 of 12 datasets and median relative-slope RMSE increased from about 0.06 to as much as 0.12. A stricter retained-solution polish reduced the largest gradient by roughly an order of magnitude without materially changing likelihoods. These small fixed counts clarify optimizer, curvature, and design contributions; they do not calibrate a universal selection, standard-error, or readiness rule.

## Source-grounded recovery interpretation

The bounded `GPCM` route follows Muraki’s generalized partial credit model and its information-function extension. The package-specific `slope_regime` labels are narrower than that model theory: they summarize the centered log-slope spread of the simulation generator so recovery evidence can be read against a declared stress condition. They are not model-fit tests and they are not literature-derived adequacy cut points.

For simulation reporting, read direct recovery checks in an ADEMP-style order: the data-generating mechanism first, then the estimands and performance measures, and only then the row-level recovery diagnostics. In practice, this means:

1. Build or extract an explicit `mfrm_sim_spec`.
2. Run `evaluate_mfrm_recovery()` for the direct parameter-recovery question.
3. Run `assess_mfrm_recovery()` with practical RMSE/bias limits.
4. Read `summary(recovery_review)`, then `recovery_review$condition_reporting_notes` and `recovery_review$condition_review`, then `recovery_review$diagnostic_reporting_notes` and `recovery_review$diagnostic_review` when optional diagnostics were retained, then `plot(recovery_review, type = "status")`, then `plot(recovery_review, type = "metrics", metric = "rmse")`.

## Supported routes and verification evidence

The following bounded-`GPCM` routes are documented and verified within the stated constraints:

- Fitting and core summaries via `fit_mfrm(model = "GPCM", step_facet = ...)`. The documented default keeps `slope_facet == step_facet`, with the direct `MML` engine.
- Posterior scoring and information via `predict_mfrm_units()`, `sample_mfrm_plausible_values()`, `compute_information()`, and `plot_information()`.
- Curve and category views via `plot(fit, type = c("wright", "pathway", "ccc", "ccc_surface"))`, `category_structure_report()`, and `category_curves_report()`.
- Slope-aware simulation specifications via `build_mfrm_sim_spec()` and `simulate_mfrm_data()`.
- Direct recovery checks via `evaluate_mfrm_recovery()` and `assess_mfrm_recovery()`, including fitted bounded-GPCM slope recovery on the log-slope scale.

## What works with caveats

The following are exposed for `GPCM` but should be read as exploratory screens rather than as Rasch-style invariance evidence:

- `diagnose_mfrm()` and the residual and unexpected-response stack: `unexpected_response_table()`, `displacement_table()`, `measurable_summary_table()`, `rating_scale_table()`, `interrater_agreement_table()`, `facet_quality_dashboard()`, `plot_qc_dashboard()`, `plot_marginal_fit()`, `plot_marginal_pairwise()`.
- `reporting_checklist()` and `precision_review_report()` route to the supported direct tables and plots. The broader APA/QC/export family is available as caveated sensitivity-reporting output with explicit `gpcm_boundary` rows.
- `build_misfit_casebook()` inherits the exploratory screening framing of its underlying sources.
- `estimate_bias()` now provides bounded-GPCM conditional screening rows with slope-aware information and profile-likelihood columns. Treat these rows as screening evidence for follow-up, not as standalone confirmatory fairness tests. `unexpected_after_bias_table()` provides a descriptive in-sample before/after flag comparison; a lower flag count does not show that bias has been removed.
- `estimation_iteration_report()` provides a slope-aware reconstructed optimization trajectory. It is a diagnostic replay, not the exact optimizer history or an additional convergence test.
- `analyze_dff()`, `analyze_dif()`, `dif_interaction_table()`, `dif_report()`, `plot_dif_heatmap()`, and `plot_dif_summary()` provide bounded-GPCM DFF/DIF screening and reporting surfaces with explicit `gpcm_boundary` rows.
- `build_apa_outputs()`, `build_visual_summaries()`, `run_qc_pipeline()`, `build_mfrm_manifest()`, `build_mfrm_replay_script()`, `export_mfrm_bundle()`, package-native scorefile export, and `build_linking_review()` return caveated bounded-`GPCM` reporting or exploratory-review objects with explicit `gpcm_boundary` rows. The package-native scorefile can include native structural delta-method expected-score SEs and score-side delta SEs selected by `score_se_method` when the required MML diagnostics are available, but those SEs are not FACETS-equivalent score-side uncertainty.
- `evaluate_mfrm_design()`, `predict_mfrm_population()`, `evaluate_mfrm_diagnostic_screening()`, and `evaluate_mfrm_signal_detection()` are available as caveated role-based repeated simulation/refit routes. Treat their outputs as design-level or screening sensitivity evidence, not as operational scoring, calibrated inferential testing, or arbitrary-facet planning validation.

The dashboard marks the fair-average panel unavailable under `GPCM`; use `fair_average_table()` directly for the slope-aware element-conditional table and `fair_average_table(fair_se = TRUE)` when you need structural fair-average SEs for non-person rows.

## What is intentionally restricted

The slope-aware `fair_average_table()` route and package-native scorefile route are available under `GPCM`, including native expected-score uncertainty and score-side delta SEs where the required MML diagnostics support them. Full FACETS-style score-side compatibility remains restricted because free discrimination changes the relationship between the latent measure and operational score-side summaries. Specifically:

- `facets_output_contract_review()` still depends on FACETS-style compatibility semantics that are not generalized to free discrimination.
- posterior-predictive checks and MCMC estimation are not available in mfrmr; use external Bayesian software when those analyses are required.
- Caveated reporting, export, linking, design-forecast, and screening helpers must keep their `gpcm_boundary` wording visible and must not imply FACETS-equivalent score-side uncertainty, operational scoring, calibrated screening gates, or arbitrary-facet planning validation.

## Recommended substitutes

When a restricted helper is needed for a `GPCM` report, the practical paths are:

- Refit with `model = "PCM"` if the discrimination-free assumption is defensible for the data and a full FACETS score-side review is required; `compare_mfrm()` quantifies the loss in fit only after every candidate uses the same selectable q>=31 grid; close decisions require a denser common-grid sensitivity check.
- Keep the report on the `GPCM` fit itself but draft the manuscript section manually around the supported tables: `summary(fit)` for parameters, `diagnose_mfrm()` for residual fit, `facet_quality_dashboard()` for the per-facet quality summary, and `compute_information()` for precision evidence.
- When a Rasch-family baseline comparison is substantively useful, optionally generate a second manifest from a parallel `RSM` or `PCM` fit. The two fits can be reported side by side, with the `GPCM` fit identified as the discrimination-aware counterpart. This is not required to use the caveated bounded-`GPCM` manifest/replay/export route.

Restricted helpers use the capability matrix at runtime. An unsupported bounded-`GPCM` call stops with the relevant limitation and a supported alternative instead of producing a partial score-side or backend result. Use `gpcm_capability_matrix()` or `mfrmr_output_guide("gpcm")` before choosing a downstream route.

## A worked example

The `example_core` dataset includes a small synthetic block that supports a bounded `GPCM` fit. This example uses compact quadrature and iteration settings to keep optional local execution short; for final evidence, rerun with the package default or a higher quadrature setting and a larger recovery design.

    library(mfrmr)
    toy <- load_mfrmr_data("example_core")

    fit_gpcm <- fit_mfrm(
      data = toy,
      person = "Person",
      facets = c("Rater", "Criterion"),
      step_facet = "Criterion",
      slope_facet = "Criterion",
      score = "Score",
      model = "GPCM",
      method = "MML",
      quad_points = 7,
      maxit = 20
    )

    fit_gpcm
    gpcm_summary <- summary(fit_gpcm, profile = "fit", detail = "brief")
    gpcm_summary$decision
    gpcm_summary$inference_evidence

    diag_gpcm <- diagnose_mfrm(fit_gpcm)
    summary(diag_gpcm)

    info <- compute_information(fit_gpcm)
    plot_information(info)

    rec_gpcm <- evaluate_mfrm_recovery(
      sim_spec = build_mfrm_sim_spec(
        n_person = 30,
        n_rater = 3,
        n_criterion = 4,
        raters_per_person = 2,
        model = "GPCM",
        step_facet = "Criterion",
        slope_facet = "Criterion",
        slopes = c(0.8, 1.0, 1.15, 1.05)
      ),
      reps = 10,
      model = "GPCM",
      fit_method = "MML",
      quad_points = 7,
      maxit = 20,
      include_diagnostics = TRUE,
      diagnostic_fit_df_method = "both",
      seed = 1
    )
    review_gpcm <- assess_mfrm_recovery(
      rec_gpcm,
      max_rmse = c(facet = 0.5, step = 0.5, slope = 0.25),
      max_abs_bias = c(default = 0.25)
    )

    summary(review_gpcm)$overview
    summary(review_gpcm)$reading_order
    review_gpcm$condition_reporting_notes[, c(
      "ConditionArea", "ReportingAttention", "ConditionFinding"
    )]
    review_gpcm$condition_review[, c(
      "Model", "GPCMSlopeRegime", "StressLevel", "ScoreSupportStatus"
    )]
    review_gpcm$diagnostic_reporting_notes[, c(
      "Facet", "ReportingAttention", "DiagnosticFinding"
    )]
    summary(review_gpcm)$diagnostic_review
    plot(review_gpcm, type = "status")
    plot(review_gpcm, type = "metrics", metric = "rmse")

Use the same `Decision` fields as for RSM and PCM. In particular, optimizer convergence does not override incomplete GPCM identifiability, curvature, or slope-boundary evidence. If `FormalInference` is `"No"`, the diagnostic and information calls above are investigative routes for resolving the recorded reason; they do not promote the fit to an inferential result.

The fit, summary, residual diagnostics, information, recovery, fair-average, and conditional bias-screening helpers all run under `GPCM` with the caveats listed above. `build_apa_outputs(fit_gpcm)` returns a caveated sensitivity-reporting object with a `gpcm_boundary`; full FACETS score-side review remains on the `RSM` / `PCM` route.

## Estimator references

- Muraki, E. (1992). A generalized partial credit model: Application of an EM algorithm. Applied Psychological Measurement, 16, 159–176.
- Uto, M., & Ueno, M. (2020). A generalized many-facet Rasch model and its Bayesian estimation using Hamiltonian Monte Carlo. Behaviormetrika, 47, 469–496.
- Wijayanto, F., Mul, K., Groot, P., van Engelen, B. G. M., & Heskes, T. (2021). Semi-automated Rasch analysis using in-plus-out-of-questionnaire log likelihood. British Journal of Mathematical and Statistical Psychology, 74, 313–339.
- Hessen, D. J. (2025). A convexity-constrained parameterization of the random effects generalized partial credit model. British Journal of Mathematical and Statistical Psychology, 78, 401–419.

## Current boundary

Score-side semantics for free-discrimination polytomous models differ from the Rasch-family route. Use the current matrix returned by `gpcm_capability_matrix()` as the workflow contract and `gpcm_score_side_contract()` for score-side alternatives.