Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang

## [Unreleased]

- `psychometric_core` recovers the Driver, Oud, and Voelkle (2017, Eq. 5, p. 5; Table 3, p. 13 `T0TIPREDEFFECT`; Table 2, p. 12 `LAMBDA`/`MANIFESTVAR`; p. 16; §7.2, pp. 20–21; 2017-era ctsem `summary.ctsemFit.R`; JSS PDF re-opened 2026-08-30T14:06Z from https://www.jstatsoft.org/index.php/jss/article/download/v077i05/1104) scalar extra observed-indicator time-independent predictor variance of 2017-era `addedT0TIPREDVAR` on current main after `0ce16e8` dropped the pre-consolidation code while research notes already named the map (register items 71–72). Equation 5 writes `y_i(t) = Γ + Λ η_i(t) + ζ_i(t)` with `ζ ~ N(0, Θ)` and `Γ ~ N(τ, Ψ)`. Immediately after `T0TIPREDEFFECTstd`, the 2017-era `summary.ctsemFit.R` in ctsem 2.1.0 (lines 429–431) forms `addedT0TIPREDVAR = T0TIPREDEFFECT %*% TIPREDVAR %*% t(T0TIPREDEFFECT)` when `verbose = TRUE` and `'TOTIPRED'` is not in `stationary`. That source comments `#is this valid?`. The scalar analog of that quadratic form is `t0_b² v`. Equation 5 of that extra, with `θ = 0` and `ψ = 0`, is `λ² t0_b² v`. Form `t0_b` first, then square, then multiply by `v`, then `(λ extra) λ`. Do not form `λ²` first. A zero loading or zero extra is exactly zero. `v < 0` fails closed. `T0` is an event-time occasion, so a non-event clock fails closed. Free `T0TIPREDEFFECT` does not require stable `a < 0`. The latent extra is formed inline; unpublished `#307` `recover_initial_time_independent_predictor_variance` is not a dependency. `t0_b² v` is the latent extra, not this observed extra. `λ² p_0 + θ` is first-occasion observed variance, not this extra. `λ² (B / a)² v` is Eq. 5 of `addedTIPREDVAR`, not this first-occasion observed extra. `MANIFESTVAR` `θ` is measurement error, not this extra. `Ψ` is intercept variance and is not extra TI. Meredith (1993) remains unread (Unpaywall historically `is_oa: false`; Springer `content/pdf` is an HTML stub). Mislevy (1991, *Psychometrika, 56*, 177–196) remains unread on the same terms (DOI `10.1007/bf02294457`). Still not a Kalman filter, not a matrix `expm`, not ESEM estimation, not DSEM, and not ctsem estimation.
- Removed the repository-local hourly PR-maintenance caller now covered by the central required scheduler, retired stale workflow registrations, narrowed documentation triggers, keyed PR concurrency by fixed workflow name, repository, and pull-request number without cancelling non-PR runs, and combined line/branch coverage on one sequential runner while preserving both 100% gates and diagnostics.

- `event_core` adds bounded Allen interval-consistency classification, atomic path-consistency closure, contradiction/resource refusals, and an explicit dependency-error fallback without claiming unrestricted global satisfiability.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions crates/psychometric_core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,23 @@ pub enum PsychometricError {
/// p. 16 `TRAITVARstd`. Extra first-occasion TI variance is not
/// the correlation form of between-subject `TRAITVAR`.
InitialTimeIndependentVarianceIsNotStandardisedTraitVariance,
/// Driver Eq. 5 of 2017-era `addedT0TIPREDVAR` `λ² t0_b² v` was
/// treated as the latent extra `t0_b² v`. The observed extra is
/// not the latent extra.
InitialTimeIndependentObservedVarianceIsNotInitialTimeIndependentVariance,
/// Driver Eq. 5 of 2017-era `addedT0TIPREDVAR` `λ² t0_b² v` was
/// treated as first-occasion observed variance `λ² p_0 + θ`.
/// The extra is not the full first-occasion `Var(y_0)`.
InitialTimeIndependentObservedVarianceIsNotInitialObservedVariance,
/// Driver Eq. 5 of 2017-era `addedT0TIPREDVAR` `λ² t0_b² v` was
/// treated as Eq. 5 of `addedTIPREDVAR` `λ² (B / a)² v`. The
/// first-occasion observed extra uses free `T0TIPREDEFFECT`,
/// not `-B / a`.
InitialTimeIndependentObservedVarianceIsNotAsymptoticTimeIndependentObservedVariance,
/// Driver Eq. 5 of 2017-era `addedT0TIPREDVAR` `λ² t0_b² v` was
/// treated as `MANIFESTVAR` `θ`. Measurement error is not extra
/// observed TI variance.
InitialTimeIndependentObservedVarianceIsNotMeasurementError,

/// Driver p. 16 `discreteCINTstd` was requested without a strictly
/// positive `asymDIFFUSION`. Footnote 4 standardises using only the
Expand Down Expand Up @@ -1183,6 +1200,18 @@ impl fmt::Display for PsychometricError {
Self::InitialTimeIndependentVarianceIsNotStandardisedTraitVariance => {
"initial time-independent predictor variance is not standardised trait variance"
}
Self::InitialTimeIndependentObservedVarianceIsNotInitialTimeIndependentVariance => {
"initial time-independent observed variance is not initial time-independent predictor variance"
}
Self::InitialTimeIndependentObservedVarianceIsNotInitialObservedVariance => {
"initial time-independent observed variance is not initial observed variance"
}
Self::InitialTimeIndependentObservedVarianceIsNotAsymptoticTimeIndependentObservedVariance => {
"initial time-independent observed variance is not asymptotic time-independent observed variance"
}
Self::InitialTimeIndependentObservedVarianceIsNotMeasurementError => {
"initial time-independent observed variance is not measurement-error variance"
}



Expand Down Expand Up @@ -2002,6 +2031,30 @@ mod tests {
);
}

#[test]
fn initial_time_independent_observed_variance_boundary_messages_are_stable() {
assert_eq!(
PsychometricError::InitialTimeIndependentObservedVarianceIsNotInitialTimeIndependentVariance
.to_string(),
"initial time-independent observed variance is not initial time-independent predictor variance"
);
assert_eq!(
PsychometricError::InitialTimeIndependentObservedVarianceIsNotInitialObservedVariance
.to_string(),
"initial time-independent observed variance is not initial observed variance"
);
assert_eq!(
PsychometricError::InitialTimeIndependentObservedVarianceIsNotAsymptoticTimeIndependentObservedVariance
.to_string(),
"initial time-independent observed variance is not asymptotic time-independent observed variance"
);
assert_eq!(
PsychometricError::InitialTimeIndependentObservedVarianceIsNotMeasurementError
.to_string(),
"initial time-independent observed variance is not measurement-error variance"
);
}

#[test]

fn standardised_discrete_continuous_intercept_boundary_messages_are_stable() {
Expand Down
Loading
Loading