Skip to content

Add joint MAP hierarchical CT-AR Rasch slice (stacked on #976) - #982

Merged
seonghobae merged 2 commits into
cursor/rust-longitudinal-state-4683from
cursor/joint-hierarchical-ctar-irt-3da5
Aug 18, 2026
Merged

Add joint MAP hierarchical CT-AR Rasch slice (stacked on #976)#982
seonghobae merged 2 commits into
cursor/rust-longitudinal-state-4683from
cursor/joint-hierarchical-ctar-irt-3da5

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Dependency

This PR is stacked on #976 (cursor/rust-longitudinal-state-4683). It must not be merged to main until #976 lands. It does not relabel the #976 OLS / caller-supplied AR kernels as random effects.

Duplicate check

Inspected open PRs/issues before starting, including #978, #979, and #981. No open PR implements jointly estimated hierarchical longitudinal IRT. #976 is the OLS/AR base; closed #848 is the same OLS/AR tree.

What this adds

Smallest scientifically valid jointly estimated longitudinal latent-state IRT slice:

logit P(Y_pti = 1) = theta_pt - b_i,   sum_i b_i = 0
theta_p,1 ~ N(mu, tau^2)
theta_p,t | theta_p,t-1 ~ N(
    mu + exp(-lambda * Delta_pt) * (theta_p,t-1 - mu),
    tau^2 * (1 - exp(-2 * lambda * Delta_pt))
)

Delta_pt is elapsed days from exact millisecond offsets.

Honest labels:

  • estimand_scope = joint_map_hierarchical_ctar_rasch
  • transition_kind = continuous_time_ar1_ou
  • interval_kind = wald_measurement_observed_information
  • population_random_effects_estimated = True (shared mu, tau; states shrunk toward mu)
  • ar_coefficient_source = joint_map
  • multiple_membership_estimated = False
  • gpu_parity = False

This is joint MAP, not Fox & Glas Gibbs, not Jeon & Rabe-Hesketh adaptive quadrature, not independent OLS, and not caller-supplied discrete AR.

Exclusions (contracted)

  • Multiple-membership / crossed u_h: not in this joint likelihood. Next step is a dedicated identification study combining Fox & Glas multilevel IRT with Browne et al. MMMC.
  • GPU: the existing wgpu path owns MLSIRM distance/likelihood kernels, a different estimand. No GPU kernel is claimed.

Recovery honesty

Multi-seed tests recover known person-occasion states (RMSE / measurement-information Wald coverage) and the population mean. Joint MAP shrinks tau. Short irregular series leave lambda weakly identified; tests require a finite positive decay and unit-day phi in (0, 1), plus irregular-gap phi ordering, not tight unbiased-ML recovery of lambda.

Docs

ADR-0019 (Proposed), doctoring, ARCHITECTURE, traceability, PRD-FR-061 / TRD-MLT-004–005, VV-SCI-008, CHANGELOG. APA 7th primary citations; journal PDFs are copyrighted so they are cited + linked + summarized, not attached.

Evidence on this head

  • cargo test --locked --manifest-path crates/mlsirm-core/Cargo.toml --lib longitudinal_irt: 11 passed
  • cargo test --locked --workspace: passed
  • cargo test --locked --manifest-path crates/fast-mlsirm-py/Cargo.toml: 9 passed
  • pytest hierarchical IRT + longitudinal OLS/AR + loader + architecture/changelog/docs: 17 + supporting tests passed
  • Rust default backend assertion: resolve_backend(auto) == rust
  • Existing Atheris fuzz_config harness: 8s bounded run completed without crash
  • Existing GPU-smoke test test_marginal_gpu_agrees_with_cpu_loosely: skipped here (no Vulkan adapter). This slice adds no GPU kernel; CI gpu-smoke remains the MLSIRM path and must not be claimed from this environment.
Open in Web Open in Cursor 

Introduce a Rust-owned jointly estimated longitudinal IRT kernel stacked
on the #976 OLS/AR state layer: shared (mu, tau, lambda), elapsed-day
OU transitions, measurement-information Wald state intervals, and
honest estimand metadata. Multiple-membership u_h and GPU parity are
excluded. Python remains marshalling-only.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: d01be734-7247-43cf-ae8f-0c94b6e8e168

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

NumPy 2 no longer treats ndarray as a Sequence, so the hierarchical
simulator now accepts both sequences and arrays. Empirical-scale helpers
used only by unit tests are cfg(test) so the production lib stays clean.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@seonghobae
seonghobae marked this pull request as ready for review August 18, 2026 01:32
@cursor

cursor Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@seonghobae
seonghobae merged commit 17bebdc into cursor/rust-longitudinal-state-4683 Aug 18, 2026
11 checks passed
@seonghobae
seonghobae deleted the cursor/joint-hierarchical-ctar-irt-3da5 branch August 18, 2026 01:32
seonghobae added a commit that referenced this pull request Aug 25, 2026
#1005)

* feat: add Rust-owned longitudinal OLS and AR state layer

Land a focused successor to #848 on live main: independent per-respondent
OLS trends and caller-supplied discrete AR predictions, with honest
estimand metadata, fail-closed worker joins, checked AR gaps, and
scale-relative slope degeneracy. Number the decision ADR-0018 so it does
not collide with main ADR-0015 or #948 ADRs 0016/0017.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* test: recover OLS parameters with valid respondent identifiers

Use two-token snake_case respondent IDs and cover NumPy scalar
observation conversion on the public longitudinal boundary.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* docs: index ADR-0016/0017 so the longitudinal PR stays merge-safe

PR 948 already records Angoff delta-plot and Bradley-Terry MM. Carry
those accepted ADRs in this branch so the index does not skip numbers
and a later merge with the citation work does not drop them.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* Revert "docs: index ADR-0016/0017 so the longitudinal PR stays merge-safe"

This reverts commit eafb302.

* test: cover unused worker shards and real observation scalars

Close the leftover llvm-cov paths in the longitudinal state engine: skip an
unused worker chunk, test first-to-last sequence-span underflow as a helper,
and recover an AR series that starts after a leading missing occasion.
Accept Python int and NumPy integer scalars at the public boundary.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* ci: retrigger org CodeQL after GitHub API 503

The required default-setup Analyze (actions) job is still the 17:40 UTC
init failure (feature-enablement HTTP 503). The repository CodeQL copy
already passed on a later rerun. This integration cannot call
`gh run rerun` (403, needs actions: write), so retrigger the stale org
check without changing product code.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* Add joint MAP hierarchical CT-AR Rasch slice (stacked on #976) (#982)

* Add joint MAP hierarchical continuous-time AR(1) Rasch slice.

Introduce a Rust-owned jointly estimated longitudinal IRT kernel stacked
on the #976 OLS/AR state layer: shared (mu, tau, lambda), elapsed-day
OU transitions, measurement-information Wald state intervals, and
honest estimand metadata. Multiple-membership u_h and GPU parity are
excluded. Python remains marshalling-only.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* Accept NumPy intercept vectors and hide test-only scale helpers.

NumPy 2 no longer treats ndarray as a Sequence, so the hierarchical
simulator now accepts both sequences and arrays. Empirical-scale helpers
used only by unit tests are cfg(test) so the production lib stays clean.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>

* test(longitudinal): align single-occasion fit error

* test(multilevel): require longitudinal state binding registration

* docs(architecture): keep proposed longitudinal ADRs non-shipped

* fix(multilevel): bound simulator arrays before copying

* docs(multilevel): distinguish OLS from discrete AR spacing

* test(longitudinal): expose hostile execution-control callbacks

* fix(longitudinal): harden execution-control boundary

* chore(longitudinal): leave aggregate changelog to release serialization

* fix(longitudinal): align bounded gradients and Hessian evidence

* fix(longitudinal): enforce identified simulator controls

* fix(longitudinal): bound raw inputs and diagonal intervals

* fix(longitudinal): close current review boundary gaps

* docs: keep ADR index unique and ordered

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants