From 2c225215ee53502ea63451f20fbacb9b263db99d Mon Sep 17 00:00:00 2001 From: Frankie Robertson Date: Sat, 4 Jul 2026 12:11:27 +0300 Subject: [PATCH 1/4] Add AGENTS.md, devcontainer, and fill documentation gaps - AGENTS.md: development conventions (DRY/config-bits style, dispatch over branching, sister-package reuse), build/test commands, and a worktree-then-PR git workflow, with pointers to README/docs/docstrings. - .devcontainer: Julia 1.12 via juliaup feature + gh CLI; verified to build, instantiate, and load the package. - Docstrings/block comments for previously undocumented core pieces: Responses, TrackedResponses, ability estimator taxonomy, Sim module, hacks.jl broadcast patch rationale, logitembank. - docs/src/api.md: include Stateful, DecisionTree, Compat, Comparison modules; README repo layout updated; contributing.md links AGENTS.md. Co-Authored-By: Claude Fable 5 --- .devcontainer/devcontainer-lock.json | 14 +++++++ .devcontainer/devcontainer.json | 19 ++++++++++ AGENTS.md | 57 ++++++++++++++++++++++++++++ README.md | 13 ++++++- docs/src/api.md | 2 +- docs/src/contributing.md | 5 +++ src/Aggregators/Aggregators.jl | 10 +++++ src/Aggregators/ability_estimator.jl | 56 +++++++++++++++++++++++++++ src/Responses.jl | 49 ++++++++++++++++++++++++ src/Sim/Sim.jl | 5 +++ src/hacks.jl | 11 ++++++ src/logitembank.jl | 17 +++++++++ 12 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 .devcontainer/devcontainer-lock.json create mode 100644 .devcontainer/devcontainer.json create mode 100644 AGENTS.md diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json new file mode 100644 index 0000000..d5b9eff --- /dev/null +++ b/.devcontainer/devcontainer-lock.json @@ -0,0 +1,14 @@ +{ + "features": { + "ghcr.io/devcontainers/features/github-cli:1": { + "version": "1.1.0", + "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671", + "integrity": "sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671" + }, + "ghcr.io/julialang/devcontainer-features/julia:1": { + "version": "1.2.0", + "resolved": "ghcr.io/julialang/devcontainer-features/julia@sha256:748ff7272e392e0c2ac7c837dbdc6c8cfa1dd3f81819fd29a111c718e3c4199d", + "integrity": "sha256:748ff7272e392e0c2ac7c837dbdc6c8cfa1dd3f81819fd29a111c718e3c4199d" + } + } +} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..5e8a869 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "name": "ComputerAdaptiveTesting.jl", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu-24.04", + "features": { + "ghcr.io/julialang/devcontainer-features/julia:1": { + "channel": "1.12" + }, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "postCreateCommand": "julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()'", + "remoteEnv": { + "JULIA_NUM_THREADS": "auto" + }, + "customizations": { + "vscode": { + "extensions": ["julialang.language-julia"] + } + } +} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7b215f2 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,57 @@ +# AGENTS.md + +ComputerAdaptiveTesting.jl implements Computer Adaptive Testing (CAT) in +Julia: composable building blocks for item selection, ability estimation, +termination rules, and simulation. See the [README](README.md) for motivation +and installation, `docs/src/` for tutorials, and docstrings/block comments in +`src/` for specifics — keep those up to date as you change code; they are the +primary documentation for humans too. + +## Layout + +- `src/ComputerAdaptiveTesting.jl` includes each submodule: `Aggregators` + (ability estimation), `NextItemRules` (item selection), `TerminationConditions`, + `Sim` (simulation loop), `Stateful` (step-wise interface), `DecisionTree`, + `Compat`/`Comparison` (R catR/mirtCAT shims and cross-checks). +- Workspaces: `test/` and `docs/` have their own `Project.toml` (Julia 1.12 + workspace feature). + +## Style — DRY and reuse first + +Follow the patterns already in the codebase rather than inventing new ones: + +- **Config composition**: user-facing constructors take a varargs "bag of + config bits" resolved with `@requiresome`/`@returnsome`/`find1_instance` + from `PsychometricsBazaarBase.ConfigTools` (see + `src/Aggregators/ability_estimator.jl`, `src/NextItemRules/`). Extend this + machinery; don't hand-roll keyword plumbing. +- **Dispatch over branching**: use trait/marker types (`DomainType`, + `IntValue`) and multiple dispatch instead of `if`/`isa` chains. +- **Composable wrappers**: prefer wrapper types (e.g. + `GuardedAbilityEstimator`) over conditionals embedded at call sites. + Configs are functors — callable strategy objects rooted at `CatConfigBase`. +- **Sister packages**: item banks come from FittedItemBanks.jl; integrators, + optimizers, and config machinery from PsychometricsBazaarBase.jl. Never + duplicate their functionality here. +- **Docstrings**: use DocStringExtensions (`$(TYPEDEF)`, `$(SIGNATURES)`); + see `src/NextItemRules/prelude/abstract.jl` for house style. New public API + must appear in `docs/src/api.md`. + +## Build, test, docs + +- Julia 1.12 (`Project.toml` compat; CI tests only 1.12). +- Test: `julia --project=test test/runtests.jl` (includes Aqua and JET + checks). `Pkg.test()` currently does not work — see issue #52. +- Docs: `cd docs && ./build.sh` (needs R via CondaPkg; CI uses + `JULIA_CONDAPKG_BACKEND=System` with conda). + +## Workflow + +Work in a git worktree per task, never directly on `main`: + +```sh +git worktree add ../ComputerAdaptiveTesting.jl- -b +``` + +Commit there, push with `git push -u origin `, and open a pull request +with `gh pr create`. Clean up with `git worktree remove` after merge. diff --git a/README.md b/README.md index 667477a..912df71 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,15 @@ also contains a number of examples. ## Repo organisation + * `/src`, Source code for the main ComputerAdaptiveTesting.jl package. The + main submodules are `Aggregators` (ability estimation), `NextItemRules` + (item selection), `TerminationConditions`, `Sim` (simulation loop), + `Stateful` (step-wise interface for interactive use), `DecisionTree`, and + `Compat`/`Comparison` (interoperability with and cross-checking against + the R packages catR and mirtCAT) + * `/docs`, Documentation source code, built with Documenter.jl via + `docs/build.sh` * `/docs/examples`, Example code - * `/docs`, Documentation source code, build with Documenter.jl - * `/src`, Source code for the main ComputerAdaptiveTesting.jl package + * `/test`, Test suite, including Aqua.jl and JET.jl quality checks + * `/AGENTS.md`, Development conventions (style, testing, workflow) for + coding agents and human contributors alike diff --git a/docs/src/api.md b/docs/src/api.md index 8755a67..e073d05 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -8,5 +8,5 @@ CurrentModule = ComputerAdaptiveTesting ``` ```@autodocs -Modules = [ComputerAdaptiveTesting, ComputerAdaptiveTesting.Aggregators, ComputerAdaptiveTesting.Responses, ComputerAdaptiveTesting.Sim, ComputerAdaptiveTesting.TerminationConditions, ComputerAdaptiveTesting.NextItemRules, ComputerAdaptiveTesting.Rules] +Modules = [ComputerAdaptiveTesting, ComputerAdaptiveTesting.Aggregators, ComputerAdaptiveTesting.Responses, ComputerAdaptiveTesting.Sim, ComputerAdaptiveTesting.TerminationConditions, ComputerAdaptiveTesting.NextItemRules, ComputerAdaptiveTesting.Rules, ComputerAdaptiveTesting.Stateful, ComputerAdaptiveTesting.DecisionTree, ComputerAdaptiveTesting.Compat, ComputerAdaptiveTesting.Comparison] ``` diff --git a/docs/src/contributing.md b/docs/src/contributing.md index c0a0dee..0fcaad1 100644 --- a/docs/src/contributing.md +++ b/docs/src/contributing.md @@ -3,6 +3,11 @@ Contributions are welcome. Please discuss any larger changes in the issues before making a pull request to avoid wasted work. +Development conventions (code style, testing, git workflow) are documented in +[`AGENTS.md`](https://github.com/JuliaPsychometricsBazaar/ComputerAdaptiveTesting.jl/blob/main/AGENTS.md) +at the repository root. A devcontainer is provided in `.devcontainer/` for a +ready-made development environment. + ## Running tests You can run tests locally like so: diff --git a/src/Aggregators/Aggregators.jl b/src/Aggregators/Aggregators.jl index 4e5b967..7113704 100644 --- a/src/Aggregators/Aggregators.jl +++ b/src/Aggregators/Aggregators.jl @@ -33,6 +33,7 @@ using PsychometricsBazaarBase.Integrators: Integrators, using PsychometricsBazaarBase.Optimizers: OneDimOptimOptimizer, Optimizer, Optimizers using PsychometricsBazaarBase.ConstDistributions: std_normal, std_mv_normal using PsychometricsBazaarBase.IndentWrappers: indent +using DocStringExtensions import Distributions: pdf import Base: show @@ -162,6 +163,15 @@ function AbilityOptimizer(bits...; ability_estimator = nothing) @returnsome Optimizer(bits...) optimizer->FunctionOptimizer(optimizer) end +""" +$(TYPEDEF) + +Responses to items in `item_bank` (as [`BareResponses`](@ref)), together with +an `ability_tracker` that maintains an incrementally-updated ability estimate +(or distribution) as responses are added. This is the object threaded through +a CAT run and passed to next item rules, termination conditions and ability +estimators. +""" @with_kw struct TrackedResponses{ BareResponsesT <: BareResponses, ItemBankT <: AbstractItemBank, diff --git a/src/Aggregators/ability_estimator.jl b/src/Aggregators/ability_estimator.jl index ed2d204..553a812 100644 --- a/src/Aggregators/ability_estimator.jl +++ b/src/Aggregators/ability_estimator.jl @@ -1,3 +1,23 @@ +# Ability estimators come in two flavours: +# * `DistributionAbilityEstimator`s produce a (possibly unnormalized) +# density over ability, via `pdf(est, tracked_responses)`, e.g. the raw +# likelihood (`LikelihoodAbilityEstimator`) or a Bayesian posterior +# (`PosteriorAbilityEstimator`). +# * `PointAbilityEstimator`s reduce such a distribution to a single ability +# value when called as `est(tracked_responses)`, either by optimization +# (`ModeAbilityEstimator`, i.e. MAP/MLE) or by integration +# (`MeanAbilityEstimator`, i.e. EAP). +# `AbilityTracker`s (see ability_tracker.jl) wrap an estimator to maintain an +# incrementally-updated estimate as responses are added, avoiding +# recomputation from scratch after every response. +# +# Constructors here follow the package-wide "bag of config bits" convention: +# `XAbilityEstimator(bits...)` scans the heterogeneous `bits` arguments (which +# may include other estimators, integrators, optimizers, priors, item banks, +# etc.) via `find1_instance`/`find1_type` and assembles a suitable estimator, +# falling back to sensible defaults (e.g. a standard normal prior) when +# nothing more specific is found. + function Integrators.normdenom(integrator::AbilityIntegrator, est::DistributionAbilityEstimator, tracked_responses::TrackedResponses) @@ -30,6 +50,17 @@ function show(io::IO, ::MIME"text/plain", ability_estimator::LikelihoodAbilityEs println(io, "Ability likelihood distribution") end +""" +$(TYPEDEF) + +Ability posterior distribution: the response likelihood times a `prior` +distribution over ability (a standard normal by default). + + $(FUNCTIONNAME)(; ncomp=0) + +Constructs with a standard normal prior (`ncomp=0`) or a `ncomp`-dimensional +standard multivariate normal prior. +""" struct PosteriorAbilityEstimator{PriorT <: Distribution} <: DistributionAbilityEstimator prior::PriorT end @@ -209,6 +240,19 @@ function covariance_matrix( ) end +""" +$(TYPEDEF) + +Point ability estimate given by the mode of `dist_est` (e.g. MLE for a +[`LikelihoodAbilityEstimator`](@ref) or MAP for a +[`PosteriorAbilityEstimator`](@ref)), found using `optim`. + + $(FUNCTIONNAME)(bits...) + +Bag-of-config-bits constructor: uses any given `DistributionAbilityEstimator` +and `AbilityOptimizer` found in `bits`, or builds default ones from the rest +of `bits`. +""" struct ModeAbilityEstimator{ DistEst <: DistributionAbilityEstimator, OptimizerT <: AbilityOptimizer @@ -231,6 +275,18 @@ function show(io::IO, ::MIME"text/plain", ability_estimator::ModeAbilityEstimato show(indent_io, MIME("text/plain"), ability_estimator.optim) end +""" +$(TYPEDEF) + +Point ability estimate given by the mean (EAP) of `dist_est`, computed using +`integrator`. + + $(FUNCTIONNAME)(bits...) + +Bag-of-config-bits constructor: uses any given `DistributionAbilityEstimator` +and `AbilityIntegrator` found in `bits`, or builds default ones from the rest +of `bits`. +""" struct MeanAbilityEstimator{ DistEst <: DistributionAbilityEstimator, IntegratorT <: AbilityIntegrator diff --git a/src/Responses.jl b/src/Responses.jl index 086c513..b0779bd 100644 --- a/src/Responses.jl +++ b/src/Responses.jl @@ -1,3 +1,7 @@ +""" +Types and functions for recording examinee responses and evaluating the +resulting ability likelihood function. +""" module Responses using FittedItemBanks: AbstractItemBank, @@ -5,6 +9,7 @@ using FittedItemBanks: AbstractItemBank, resp, DichotomousPointsItemBank, item_ys using AutoHashEquals: @auto_hash_equals +using DocStringExtensions export Response, BareResponses, AbilityLikelihood, function_xs, function_ys export add_response!, pop_response! @@ -12,6 +17,11 @@ export add_response!, pop_response! concrete_response_type(::BooleanResponse) = Bool concrete_response_type(::MultinomialResponse) = Int +""" +$(TYPEDEF) + +A single response of the given `ResponseType` to the item at `index`. +""" @auto_hash_equals struct Response{ResponseTypeT <: ResponseType, ConcreteResponseTypeT} index::Int value::ConcreteResponseTypeT @@ -19,6 +29,14 @@ concrete_response_type(::MultinomialResponse) = Int Response(rt, index, value) = new{typeof(rt), concrete_response_type(rt)}(index, value) end +""" +$(TYPEDEF) + +A bare (untracked) sequence of responses, stored as parallel vectors of item +`indices` and response `values`, sharing a common `rt` (response type). +See also `TrackedResponses`, which additionally tracks the item bank and +ability estimate. +""" @auto_hash_equals struct BareResponses{ ResponseTypeT <: ResponseType, ConcreteResponseTypeT, @@ -75,12 +93,22 @@ function Base.empty!(responses::BareResponses) Base.empty!(responses.values) end +""" +$(TYPEDSIGNATURES) + +Append `response` to `responses` in-place. +""" function add_response!(responses::BareResponses, response::Response)::BareResponses push!(responses.indices, response.index) push!(responses.values, response.value) responses end +""" +$(TYPEDSIGNATURES) + +Remove and discard the last response from `responses` in-place. +""" function pop_response!(responses::BareResponses)::BareResponses pop!(responses.indices) pop!(responses.values) @@ -92,6 +120,14 @@ function Base.sizehint!(bare_responses::BareResponses, n) sizehint!(bare_responses.values, n) end +""" +$(TYPEDEF) + +The likelihood of ability `θ` given `responses` to items in `item_bank`, i.e. +`θ -> prod(P(response | θ) for response in responses)`. Callable as a function +of `θ`; also has [`function_xs`](@ref)/[`function_ys`](@ref) methods for item +banks that support evaluation at a fixed grid of `xs`. +""" struct AbilityLikelihood{ItemBankT <: AbstractItemBank, BareResponsesT <: BareResponses} item_bank::ItemBankT responses::BareResponsesT @@ -112,10 +148,23 @@ function (ability_lh::AbilityLikelihood)(θ) ) end +""" +$(TYPEDSIGNATURES) + +The grid of ability values (`xs`) at which `ability_lh`'s item bank tabulates +response probabilities. +""" function function_xs(ability_lh::AbilityLikelihood{DichotomousPointsItemBank}) return ability_lh.item_bank.xs end +""" +$(TYPEDSIGNATURES) + +The likelihood of `ability_lh`'s responses evaluated at each point in +[`function_xs`](@ref), i.e. the product over responses of the tabulated +response probability at each grid point. +""" function function_ys(ability_lh::AbilityLikelihood{DichotomousPointsItemBank}) return reduce( .*, diff --git a/src/Sim/Sim.jl b/src/Sim/Sim.jl index 75511c9..f755f23 100644 --- a/src/Sim/Sim.jl +++ b/src/Sim/Sim.jl @@ -1,3 +1,8 @@ +""" +Runs a configured CAT ([`CatRules`](@ref)) in a loop ([`CatLoop`](@ref)/[`run_cat`](@ref)), +obtaining responses interactively or from simulated data, and optionally +recording the run (see recorder.jl). +""" module Sim using DataFrames: DataFrame diff --git a/src/hacks.jl b/src/hacks.jl index 879e213..3f2a87d 100644 --- a/src/hacks.jl +++ b/src/hacks.jl @@ -1,5 +1,16 @@ import Base.Broadcast +# Ability likelihoods/estimators are built by composing many small closures +# (see IntegralCoeffs, FunctionProduct, etc.), giving deeply nested broadcast +# and getindex call chains. Julia's type inference uses `recursion_relation` +# on method signatures to detect (and stop inlining/specializing) genuine +# recursion, but for these chains it produces false positives, so inference +# bails out early and the resulting code allocates heavily instead of fusing +# into an allocation-free broadcast. `moneypatch_broadcast` works around this +# by patching `recursion_relation` on the relevant Base.Broadcast/getindex/copy +# methods to always return `true`, so these (non-recursive) call chains are +# always fully specialized. Set `CAT_DISABLE_HACKS` in the environment to +# disable this patch (e.g. to check whether it's still needed). function moneypatch_broadcast() if "CAT_DISABLE_HACKS" in keys(ENV) return diff --git a/src/logitembank.jl b/src/logitembank.jl index bfb19c1..87df56b 100644 --- a/src/logitembank.jl +++ b/src/logitembank.jl @@ -11,7 +11,16 @@ using FittedItemBanks: AbstractItemBank, ItemResponse, PointsItemBank, using LogarithmicNumbers: ULogarithmic import FittedItemBanks using Lazy: @forward +using DocStringExtensions +""" +$(TYPEDEF) + +Wraps `inner`, an item bank whose response function `FittedItemBanks.log_resp` +gives log-probabilities, exposing it as an ordinary `AbstractItemBank` whose +`resp`/`resp_vec` return `ULogarithmic` values. Used where response +probabilities are so small that computing in log-space avoids underflow. +""" struct LogItemBank{ItemBankT <: AbstractItemBank} <: AbstractItemBank inner::ItemBankT end @@ -40,6 +49,14 @@ FittedItemBanks.domdims, FittedItemBanks.ResponseType, FittedItemBanks.DomainType +""" +$(TYPEDEF) + +A `DichotomousPointsItemBank` (`inner_bank`) with its tabulated response +probabilities precomputed in log-space (`log_ys`), so that likelihoods over +many responses can be accumulated by summation instead of repeated +multiplication. +""" struct DichotomousPointsWithLogsItemBank{DomainT} <: PointsItemBank inner_bank::DichotomousPointsItemBank{DomainT} log_ys::Array{Float64, 3} From db3358baa316fe87fd89f0dd445f93c034bcf7e7 Mon Sep 17 00:00:00 2001 From: Frankie Robertson Date: Sat, 4 Jul 2026 14:26:12 +0300 Subject: [PATCH 2/4] Add Claude Code to the devcontainer Follows https://code.claude.com/docs/en/devcontainer: installs the official claude-code devcontainer feature and mounts a per-project named volume at /home/vscode/.claude so authentication and settings persist across rebuilds (chowned to vscode in postCreate, since fresh volumes mount root-owned). Verified with `devcontainer up`: claude 2.1.197 runs as the vscode user with a writable ~/.claude, and Julia 1.12.6 still loads the package. Co-Authored-By: Claude Fable 5 --- .devcontainer/devcontainer-lock.json | 5 +++++ .devcontainer/devcontainer.json | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer-lock.json b/.devcontainer/devcontainer-lock.json index d5b9eff..6be6053 100644 --- a/.devcontainer/devcontainer-lock.json +++ b/.devcontainer/devcontainer-lock.json @@ -1,5 +1,10 @@ { "features": { + "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": { + "version": "1.0.5", + "resolved": "ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a", + "integrity": "sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a" + }, "ghcr.io/devcontainers/features/github-cli:1": { "version": "1.1.0", "resolved": "ghcr.io/devcontainers/features/github-cli@sha256:d22f50b70ed75339b4eed1ba9ecde3a1791f90e88d37936517e3bace0bbad671", diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5e8a869..4532d26 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,9 +5,13 @@ "ghcr.io/julialang/devcontainer-features/julia:1": { "channel": "1.12" }, - "ghcr.io/devcontainers/features/github-cli:1": {} + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {} }, - "postCreateCommand": "julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()'", + "mounts": [ + "source=claude-code-config-${devcontainerId},target=/home/vscode/.claude,type=volume" + ], + "postCreateCommand": "sudo chown vscode:vscode /home/vscode/.claude && julia --project=. -e 'using Pkg; Pkg.instantiate(); Pkg.precompile()'", "remoteEnv": { "JULIA_NUM_THREADS": "auto" }, From 5eba8eda5b6ca6a66c5f8d1f2c9e96a6ed5c4edb Mon Sep 17 00:00:00 2001 From: Frankie Robertson Date: Sat, 4 Jul 2026 19:33:16 +0300 Subject: [PATCH 3/4] Fix up docs building --- docs/make.jl | 2 +- docs/src/api.md | 2 +- docs/src/contributing.md | 2 +- docs/src/stateful.md | 8 ++++---- src/Aggregators/ability_estimator.jl | 7 +++++++ 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index ce21ff6..8c0bacc 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -45,7 +45,7 @@ makedocs(; ], "Contributing" => "contributing.md", ], - warnonly = [:missing_docs], + checkdocs_ignored_modules = [ComputerAdaptiveTesting.Compat], linkcheck = true) if build_demos diff --git a/docs/src/api.md b/docs/src/api.md index e073d05..a437bb8 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -8,5 +8,5 @@ CurrentModule = ComputerAdaptiveTesting ``` ```@autodocs -Modules = [ComputerAdaptiveTesting, ComputerAdaptiveTesting.Aggregators, ComputerAdaptiveTesting.Responses, ComputerAdaptiveTesting.Sim, ComputerAdaptiveTesting.TerminationConditions, ComputerAdaptiveTesting.NextItemRules, ComputerAdaptiveTesting.Rules, ComputerAdaptiveTesting.Stateful, ComputerAdaptiveTesting.DecisionTree, ComputerAdaptiveTesting.Compat, ComputerAdaptiveTesting.Comparison] +Modules = [ComputerAdaptiveTesting, ComputerAdaptiveTesting.Aggregators, ComputerAdaptiveTesting.Responses, ComputerAdaptiveTesting.Sim, ComputerAdaptiveTesting.TerminationConditions, ComputerAdaptiveTesting.NextItemRules, ComputerAdaptiveTesting.Rules, ComputerAdaptiveTesting.Stateful, ComputerAdaptiveTesting.DecisionTree, ComputerAdaptiveTesting.Compat, ComputerAdaptiveTesting.Comparison, ComputerAdaptiveTesting.ItemBanks, ComputerAdaptiveTesting.ConfigBase] ``` diff --git a/docs/src/contributing.md b/docs/src/contributing.md index 0fcaad1..59f7f13 100644 --- a/docs/src/contributing.md +++ b/docs/src/contributing.md @@ -4,7 +4,7 @@ Contributions are welcome. Please discuss any larger changes in the issues before making a pull request to avoid wasted work. Development conventions (code style, testing, git workflow) are documented in -[`AGENTS.md`](https://github.com/JuliaPsychometricsBazaar/ComputerAdaptiveTesting.jl/blob/main/AGENTS.md) +`AGENTS.md` at the repository root. A devcontainer is provided in `.devcontainer/` for a ready-made development environment. diff --git a/docs/src/stateful.md b/docs/src/stateful.md index 0fea784..5fe4721 100644 --- a/docs/src/stateful.md +++ b/docs/src/stateful.md @@ -4,13 +4,13 @@ CurrentModule = ComputerAdaptiveTesting ``` -```@docs +```@docs; canonical=false Stateful.Stateful ``` ## Interface -```@docs +```@docs; canonical=false Stateful.StatefulCat Stateful.next_item Stateful.ranked_items @@ -27,10 +27,10 @@ Stateful.get_ability There is an implementation in terms of [CatRules](@ref): -```@docs +```@docs; canonical=false Stateful.StatefulCatRules ``` ## Usage -Just as [CatLoop](@ref) can wrap [CatRules](@ref), you can also use it with any implementor of [Stateful.StatefulCat](@ref), and run using [Sim.run_cat](@ref). \ No newline at end of file +Just as [CatLoop](@ref) can wrap [CatRules](@ref), you can also use it with any implementor of [Stateful.StatefulCat](@ref), and run using [Sim.run_cat](@ref). diff --git a/src/Aggregators/ability_estimator.jl b/src/Aggregators/ability_estimator.jl index 553a812..4d2dfbd 100644 --- a/src/Aggregators/ability_estimator.jl +++ b/src/Aggregators/ability_estimator.jl @@ -39,6 +39,13 @@ function pdf(ability_est::DistributionAbilityEstimator, pdf(ability_est, tracked_responses)(x) end +""" +$(TYPEDEF) + +The ability likelihood distribution. + + $(FUNCTIONNAME)(; ncomp=0) +""" struct LikelihoodAbilityEstimator <: DistributionAbilityEstimator end function pdf(::LikelihoodAbilityEstimator, From 86784b83f63e8030f289d50ea75797330c6e0861 Mon Sep 17 00:00:00 2001 From: Frankie Robertson Date: Tue, 7 Jul 2026 09:26:19 +0300 Subject: [PATCH 4/4] Fix incorrect docstring for LikelihoodAbilityEstimator --- src/Aggregators/ability_estimator.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aggregators/ability_estimator.jl b/src/Aggregators/ability_estimator.jl index 697638f..65e71e2 100644 --- a/src/Aggregators/ability_estimator.jl +++ b/src/Aggregators/ability_estimator.jl @@ -44,7 +44,7 @@ $(TYPEDEF) The ability likelihood distribution. - $(FUNCTIONNAME)(; ncomp=0) + $(FUNCTIONNAME)() """ struct LikelihoodAbilityEstimator <: DistributionAbilityEstimator end