diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..5373186 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,104 @@ +FROM julia:1.11 + +ARG TZ +ENV TZ="$TZ" + +ARG JULIA_VERSION=1.11 + +# Install basic development tools and iptables/ipset +RUN apt-get update && apt-get install -y --no-install-recommends \ + less \ + git \ + procps \ + sudo \ + fzf \ + zsh \ + man-db \ + unzip \ + gnupg2 \ + gh \ + iptables \ + ipset \ + iproute2 \ + dnsutils \ + aggregate \ + jq \ + nano \ + vim \ + build-essential \ + curl \ + wget \ + ca-certificates \ + lsb-release \ + nodejs \ + npm \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +ARG USERNAME=julia +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +# Create the user with sudo privileges +RUN groupadd --gid $USER_GID $USERNAME \ + && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \ + && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ + && chmod 0440 /etc/sudoers.d/$USERNAME + +# Persist bash and zsh history +RUN SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" \ + && mkdir /commandhistory \ + && touch /commandhistory/.bash_history \ + && touch /commandhistory/.zsh_history \ + && chown -R $USERNAME /commandhistory + +# Set `DEVCONTAINER` environment variable to help with orientation +ENV DEVCONTAINER=true + +# Create workspace and Julia depot directories and set permissions +RUN mkdir -p /workspace /home/$USERNAME/.julia && \ + chown -R $USERNAME:$USERNAME /workspace /home/$USERNAME/.julia + +WORKDIR /workspace + +ARG GIT_DELTA_VERSION=0.18.2 +RUN ARCH=$(dpkg --print-architecture) && \ + wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \ + dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && \ + rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" + +ARG ZSH_IN_DOCKER_VERSION=1.2.0 +RUN wget "https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh" && \ + chmod +x zsh-in-docker.sh && \ + ./zsh-in-docker.sh \ + -t robbyrussell \ + -p git \ + -p ssh-agent \ + -p 'history-substring-search' \ + -a 'bindkey "\$terminfo[kcuu1]" history-substring-search-up' \ + -a 'bindkey "\$terminfo[kcud1]" history-substring-search-down' && \ + rm zsh-in-docker.sh + +# Configure zsh history for the julia user +RUN echo 'export HISTFILE=/commandhistory/.zsh_history' >> /home/$USERNAME/.zshrc && \ + echo 'export HISTSIZE=10000' >> /home/$USERNAME/.zshrc && \ + echo 'export SAVEHIST=10000' >> /home/$USERNAME/.zshrc && \ + echo 'setopt SHARE_HISTORY' >> /home/$USERNAME/.zshrc + +# Set up Julia development environment +USER $USERNAME + +# Create Julia config directory - startup file will be copied by postCreateCommand +RUN mkdir -p /home/$USERNAME/.julia/config + +# Set Julia depot path +ENV JULIA_DEPOT_PATH="/home/$USERNAME/.julia" + +# Switch back to root for any final setup +USER root + +# Copy and set up firewall initialization script +COPY init-firewall.sh /usr/local/bin/init-firewall.sh +RUN chmod +x /usr/local/bin/init-firewall.sh + +# Switch back to user +USER $USERNAME \ No newline at end of file diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 0000000..5b6f89a --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,190 @@ +# DevContainer for ComputerAdaptiveTesting.jl + +This directory contains the development container configuration for ComputerAdaptiveTesting.jl, based on the [Claude Code reference implementation](https://github.com/anthropics/claude-code/tree/main/.devcontainer). + +## Features + +- **Julia 1.11**: Latest stable Julia version with full development environment +- **Claude Code Pattern**: Follows the same structure as Claude's reference devcontainer +- **Security**: Includes firewall initialization for secure development +- **Modern Shell**: Zsh with Oh My Zsh, Git integration, and history search +- **Enhanced Git**: Git Delta for improved diffs and GitLens integration +- **VS Code Extensions**: Pre-configured with Julia language support and development tools +- **Persistent Storage**: Command history and Julia packages persist across rebuilds + +## Quick Start + +1. **Prerequisites**: Install VS Code and the Dev Containers extension +2. **Open**: Open this repository in VS Code +3. **Reopen in Container**: Command Palette โ†’ "Dev Containers: Reopen in Container" +4. **Wait**: The container will build and set up the environment automatically (first build takes ~10 minutes) + +## What's Included + +### Architecture (Claude Code Pattern) +- **Custom Dockerfile**: Multi-stage build with Julia base image +- **Security-first**: Network capabilities and firewall initialization +- **User-based**: Runs as `julia` user (not root) for security +- **Persistent volumes**: Separate volumes for command history and Julia depot +- **Workspace mounting**: Project mounted to `/workspace` following Claude pattern + +### VS Code Extensions +- Julia Language Support with full IntelliSense +- GitLens for enhanced Git integration +- Code Spell Checker +- Markdown support with linting +- JSON support +- Jupyter support + +### Shell Environment +- **Zsh** with Oh My Zsh (robbyrussell theme) +- **Git integration** with status in prompt +- **History search** with arrow keys +- **Persistent command history** across container restarts +- **SSH agent** support + +### Development Tools +- **Claude Code CLI**: Full Claude Code experience in the container +- **Git Delta**: Beautiful diffs with syntax highlighting +- **GitHub CLI** for repository management +- **fzf**: Fuzzy finder for command line +- **Standard Unix tools**: less, vim, nano, man pages + +### Julia Environment +- **Project instantiation**: Main dependencies automatically installed +- **Registry resolution**: Avoids local path issues by resolving from Julia General registry +- **Startup script**: Automatic loading of development conveniences +- **Depot persistence**: Julia packages cached across container rebuilds + +### Security Features +- **Firewall initialization**: Restricts network access to essential services +- **Julia infrastructure**: Pre-configured access to Julia package registry, GitHub, etc. +- **Network capabilities**: Required for firewall management +- **Allowlist approach**: Only permitted domains/IPs are accessible + +## Usage + +### Running Tests +```bash +# In the container terminal (Zsh) +julia --project=test test/runtests.jl +``` + +### Building Documentation +```bash +julia --project=docs docs/make.jl +``` + +### Interactive Development +```bash +# Start Julia REPL with project activated +julia --project=. + +# Install additional development tools as needed +julia --project=. -e "using Pkg; Pkg.add([\"Revise\", \"OhMyREPL\", \"BenchmarkTools\"])" +``` + +### Git Workflow +```bash +# Enhanced Git experience with Delta +git diff # Beautiful syntax-highlighted diffs +git log --oneline # Clean commit history +gh pr create # Create pull requests via CLI +``` + +### Claude Code Usage + +The container is configured to support Claude Code. Installation requires Node.js/npm: + +```bash +# Install Node.js and npm first (if not already installed) +sudo apt-get update && sudo apt-get install -y nodejs npm + +# Install Claude Code CLI +sudo npm install -g @anthropic-ai/claude-code + +# Use Claude Code within the container +claude # Start interactive Claude session +claude "Explain this Julia function" < src/MyModule.jl +claude --help # See all available options + +# Example: Get help with Julia development +claude "How can I optimize this Julia code for performance?" +``` + +**Note**: +- The firewall configuration may need to be adjusted to allow npm package downloads +- Claude Code requires proper API authentication setup +- Installation may require temporarily disabling the firewall or adding package repository domains to the allowlist + +## File Structure + +- `devcontainer.json` - Main container configuration (Claude Code pattern) +- `Dockerfile` - Custom Julia development image with security features +- `post-create.sh` - Setup script run after container creation +- `init-firewall.sh` - Security initialization (adapted from Claude reference) +- `startup.jl` - Julia startup script for development convenience +- `README.md` - This documentation + +## Key Differences from Simple Devcontainer + +This implementation follows the Claude Code reference pattern with several advantages: + +1. **Security-first**: Firewall and network restrictions +2. **Better shell**: Zsh with full Git integration vs basic bash +3. **Enhanced Git**: Delta for beautiful diffs, GitLens integration +4. **User-based**: Runs as `julia` user vs root +5. **Persistent storage**: Separate volumes for different data types +6. **Build caching**: Optimized Docker layers for faster rebuilds + +## Customization + +You can customize the development environment by: + +1. **Adding VS Code extensions**: Edit the `extensions` array in `devcontainer.json` +2. **Modifying firewall rules**: Update `init-firewall.sh` to allow additional domains +3. **Installing additional packages**: Modify `post-create.sh` +4. **Changing Julia settings**: Update the `settings` in `devcontainer.json` + +## Troubleshooting + +### Container won't start +- Check Docker is running and you have the necessary permissions +- Try rebuilding: Command Palette โ†’ "Dev Containers: Rebuild Container" + +### Network connectivity issues +- Check firewall rules in `init-firewall.sh` +- Firewall initialization failures are non-fatal but may limit network access + +### Julia packages not installing +- The environment resolves packages from the Julia General registry +- Local Manifest.toml is removed to avoid path conflicts +- First-time package installation takes longer due to compilation + +### Slow startup +- First build takes ~10 minutes due to installing development tools +- First Julia package installation takes additional time for compilation +- Subsequent starts are much faster due to Docker layer caching and Julia precompilation + +## Performance Tips + +1. **Package precompilation** is cached in persistent Julia depot volume +2. **Docker build caching** speeds up container rebuilds +3. **Command history persistence** maintains your workflow across sessions +4. **Optimized package resolution** avoids local path conflicts + +## Security Notes + +This devcontainer includes security features following the Claude Code pattern: + +- **Firewall restrictions**: Only essential domains are accessible +- **Network capabilities**: Required for firewall management (NET_ADMIN, NET_RAW) +- **Julia infrastructure**: Pre-configured access to necessary Julia services +- **Non-root user**: Runs as `julia` user for reduced privilege + +## Contributing + +If you improve this devcontainer setup, please: +1. Update this README with your changes +2. Test with `devcontainer up --workspace-folder .` +3. Submit a pull request following the project's contribution guidelines diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..2d14ceb --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,77 @@ +{ + "name": "ComputerAdaptiveTesting.jl Dev Environment", + "build": { + "dockerfile": "Dockerfile", + "args": { + "TZ": "${localEnv:TZ:America/Los_Angeles}", + "JULIA_VERSION": "1.11", + "GIT_DELTA_VERSION": "0.18.2", + "ZSH_IN_DOCKER_VERSION": "1.2.0" + } + }, + "runArgs": [ + "--cap-add=NET_ADMIN", + "--cap-add=NET_RAW" + ], + "customizations": { + "vscode": { + "extensions": [ + "julialang.language-julia", + "ms-vscode.vscode-json", + "streetsidesoftware.code-spell-checker", + "ms-vscode.test-adapter-converter", + "ms-vscode.vscode-markdown", + "davidanson.vscode-markdownlint", + "ms-toolsai.jupyter", + "eamodio.gitlens" + ], + "settings": { + "julia.executablePath": "/usr/local/julia/bin/julia", + "julia.enableTelemetry": false, + "julia.symbolCacheDownload": true, + "julia.enableCrashReporter": false, + "julia.lint.run": true, + "julia.lint.missingRefDoc": "all", + "julia.lint.disabledDirs": ["test"], + "julia.format.indent": 4, + "editor.formatOnSave": true, + "editor.rulers": [92], + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "terminal.integrated.defaultProfile.linux": "zsh", + "terminal.integrated.profiles.linux": { + "bash": { + "path": "bash", + "icon": "terminal-bash" + }, + "zsh": { + "path": "zsh" + } + } + } + } + }, + "remoteUser": "julia", + "mounts": [ + "source=computeradaptivetesting-julia-bashhistory-${devcontainerId},target=/commandhistory,type=volume", + "source=computeradaptivetesting-julia-depot-${devcontainerId},target=/home/julia/.julia,type=volume" + ], + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "workspaceFolder": "/workspace", + "containerEnv": { + "JULIA_DEPOT_PATH": "/home/julia/.julia", + "DEVCONTAINER": "true" + }, + "postCreateCommand": "bash .devcontainer/post-create.sh", + "forwardPorts": [8000, 8888], + "portsAttributes": { + "8000": { + "label": "Development Server", + "onAutoForward": "notify" + }, + "8888": { + "label": "Jupyter", + "onAutoForward": "notify" + } + } +} \ No newline at end of file diff --git a/.devcontainer/init-firewall.sh b/.devcontainer/init-firewall.sh new file mode 100644 index 0000000..d869b96 --- /dev/null +++ b/.devcontainer/init-firewall.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +# Initialize firewall for ComputerAdaptiveTesting.jl development environment +# Based on Claude Code reference implementation + +set -euo pipefail + +# Check if running with required privileges +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root (use sudo)" + exit 1 +fi + +echo "๐Ÿ”’ Initializing firewall for Julia development environment..." + +# Flush existing rules +iptables -F +iptables -X +iptables -t nat -F +iptables -t nat -X +iptables -t mangle -F +iptables -t mangle -X + +# Preserve Docker DNS resolution +iptables -I INPUT -i docker0 -j ACCEPT +iptables -I OUTPUT -o docker0 -j ACCEPT + +# Allow localhost +iptables -A INPUT -i lo -j ACCEPT +iptables -A OUTPUT -o lo -j ACCEPT + +# Allow established connections +iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + +# Create ipset for allowed IPs +ipset create allowed_ips hash:net 2>/dev/null || ipset flush allowed_ips + +# Add common development networks +ipset add allowed_ips 8.8.8.8/32 # Google DNS +ipset add allowed_ips 8.8.4.4/32 # Google DNS alternate +ipset add allowed_ips 1.1.1.1/32 # Cloudflare DNS +ipset add allowed_ips 1.0.0.1/32 # Cloudflare DNS alternate + +# Add Julia package registry and common Julia infrastructure +echo "๐Ÿ“ฆ Adding Julia package infrastructure IPs..." + +# GitHub (for package source code) +GITHUB_IPS=$(curl -s https://api.github.com/meta | jq -r '.git[] | select(. | contains(":") | not)') +for ip in $GITHUB_IPS; do + ipset add allowed_ips "$ip" 2>/dev/null || true +done + +# Add specific Julia-related, Claude, and package repository domains +ALLOWED_DOMAINS=( + "julialang.org" + "pkg.julialang.org" + "juliahub.com" + "githubusercontent.com" + "github.com" + "storage.googleapis.com" # For Julia binaries + "claude.ai" + "api.anthropic.com" + "cdn.anthropic.com" + "deb.debian.org" # Debian package repository + "debian.map.fastlydns.net" # Debian CDN + "security.debian.org" # Debian security updates + "registry.npmjs.org" # npm registry + "nodejs.org" # Node.js downloads + "deb.nodesource.com" # Node.js repository +) + +for domain in "${ALLOWED_DOMAINS[@]}"; do + echo "๐Ÿ” Resolving $domain..." + IPS=$(dig +short "$domain" A | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' || true) + for ip in $IPS; do + echo " Adding $ip for $domain" + ipset add allowed_ips "$ip" 2>/dev/null || true + done +done + +# Allow SSH (in case it's needed) +iptables -A INPUT -p tcp --dport 22 -j ACCEPT +iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT + +# Allow DNS queries +iptables -A OUTPUT -p udp --dport 53 -j ACCEPT +iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT + +# Allow HTTP/HTTPS to allowed IPs +iptables -A OUTPUT -p tcp -m set --match-set allowed_ips dst --dport 80 -j ACCEPT +iptables -A OUTPUT -p tcp -m set --match-set allowed_ips dst --dport 443 -j ACCEPT + +# Allow development ports (forward declared in devcontainer.json) +iptables -A INPUT -p tcp --dport 8000 -j ACCEPT +iptables -A INPUT -p tcp --dport 8888 -j ACCEPT + +# Set default policies +iptables -P INPUT DROP +iptables -P FORWARD DROP +iptables -P OUTPUT DROP + +echo "โœ… Firewall initialized successfully!" + +# Verify basic connectivity +echo "๐Ÿงช Testing connectivity..." + +# Test DNS resolution +if nslookup julialang.org >/dev/null 2>&1; then + echo " โœ… DNS resolution working" +else + echo " โŒ DNS resolution failed" + exit 1 +fi + +# Test HTTPS connectivity to Julia registry +if curl -s --connect-timeout 10 https://pkg.julialang.org >/dev/null 2>&1; then + echo " โœ… Julia package registry accessible" +else + echo " โš ๏ธ Julia package registry test failed (may be expected)" +fi + +# Test Claude API connectivity +if curl -s --connect-timeout 10 https://claude.ai >/dev/null 2>&1; then + echo " โœ… Claude API accessible" +else + echo " โš ๏ธ Claude API test failed (may be expected)" +fi + +echo "๐ŸŽ‰ Firewall setup complete! Julia development environment with Claude Code is secure." diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh new file mode 100755 index 0000000..b51e960 --- /dev/null +++ b/.devcontainer/post-create.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +set -e + +echo "๐Ÿš€ Setting up ComputerAdaptiveTesting.jl development environment..." + +# Set up Julia environment - workspace is mounted to /workspace in Claude reference pattern +cd /workspace + +# Copy startup file to Julia config +cp .devcontainer/startup.jl /home/julia/.julia/config/startup.jl + +echo "๐Ÿ“ฆ Installing Julia packages (main project only)..." + +# Remove Manifest.toml to avoid local path issues and let Pkg resolve from registry +rm -f Manifest.toml + +# Instantiate the project - this will get packages from registry instead of local paths +julia --project=. -e " +using Pkg; +Pkg.instantiate(); +" + +echo "โœ… Julia environment setup complete!" + +# Set up git configuration if not already set +if ! git config --global user.name > /dev/null 2>&1; then + echo "โš ๏ธ Remember to set up your git configuration:" + echo " git config --global user.name \"Your Name\"" + echo " git config --global user.email \"your.email@example.com\"" +fi + +# Skip firewall initialization during development to avoid network issues +echo "๐Ÿ”“ Skipping firewall initialization for package installation..." + +# Install Claude Code CLI as user (post-create, after network is available) +echo "๐Ÿค– Installing Claude Code CLI..." +if sudo npm install -g @anthropic-ai/claude-code; then + echo "โœ… Claude Code CLI installed successfully!" +else + echo "โš ๏ธ Claude Code CLI installation failed - you can install it manually later" + echo " Manual installation: sudo npm install -g @anthropic-ai/claude-code" +fi + +echo "๐ŸŽ‰ Development environment setup complete!" +echo "" +echo "๐Ÿ“‹ Next steps:" +echo " 1. Open the Julia REPL with 'julia --project=.'" +echo " 2. Run tests with 'julia --project=test test/runtests.jl'" +echo " 3. Build documentation with 'julia --project=docs docs/make.jl'" +echo " 4. Try Claude Code with 'claude --help'" +echo "" +echo "๐Ÿ”ง Available development tools:" +echo " - Claude Code CLI for AI assistance" +echo " - Revise.jl for automatic code reloading" +echo " - BenchmarkTools.jl for performance testing" +echo " - ProfileView.jl for profiling" +echo " - OhMyREPL.jl for enhanced REPL experience" +echo " - Zsh with git integration and history search" +echo " - Git Delta for improved diffs" \ No newline at end of file diff --git a/.devcontainer/startup.jl b/.devcontainer/startup.jl new file mode 100644 index 0000000..81a250a --- /dev/null +++ b/.devcontainer/startup.jl @@ -0,0 +1,54 @@ +# Development startup file for ComputerAdaptiveTesting.jl +# This file is automatically loaded when Julia starts in the devcontainer + +try + using Revise + @info "โœ… Revise.jl loaded - automatic code reloading enabled" +catch e + @warn "Could not load Revise.jl" exception=e +end + +try + using OhMyREPL + @info "โœ… OhMyREPL.jl loaded - enhanced REPL experience enabled" +catch e + @warn "Could not load OhMyREPL.jl" exception=e +end + +# Load the project if we're in the right directory +if isfile("Project.toml") + try + using Pkg + Pkg.activate(".") + @info "โœ… Project environment activated" + + # Pre-load common development packages + try + using BenchmarkTools + @info "โœ… BenchmarkTools.jl available (@benchmark, @btime)" + catch e + @debug "BenchmarkTools.jl not available" exception=e + end + + try + using Test + @info "โœ… Test.jl available (@test, @testset)" + catch e + @debug "Test.jl not available" exception=e + end + + catch e + @warn "Could not activate project environment" exception=e + end +end + +@info """ +๐ŸŽ‰ ComputerAdaptiveTesting.jl development environment ready! + +Quick commands: + - Run tests: julia --project=test test/runtests.jl + - Build docs: julia --project=docs docs/make.jl + - Load package: using ComputerAdaptiveTesting + - Benchmark: @benchmark your_function() + - Profile: @profile your_function() +""" diff --git a/.gitignore b/.gitignore index 5a2f3d5..13aa88a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ attic/ /full/Project.toml .CondaPkg/ LocalPreferences.toml +/.claude/settings.local.json diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 0000000..05b5424 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,175 @@ +# ComputerAdaptiveTesting.jl Architecture + +## Overview + +ComputerAdaptiveTesting.jl is organized into several interconnected modules that implement various aspects of Computer Adaptive Testing. The architecture follows a modular design with clear separation of concerns. + +## Core Module Structure + +### 1. Base Layer + +#### ConfigBase (`src/ConfigBase.jl`) +- Defines `CatConfigBase` abstract type +- Provides `walk` function for traversing configuration trees +- Foundation for all configuration structs + +#### Responses (`src/Responses.jl`) +- `Response`: Individual test response +- `BareResponses`: Collection of responses +- `AbilityLikelihood`: Likelihood calculation for abilities +- Response type handling for boolean and multinomial responses + +### 2. Aggregation Layer + +#### Aggregators (`src/Aggregators/`) +Main module for ability estimation and tracking: +- **Ability Estimators**: + - `LikelihoodAbilityEstimator`: Maximum likelihood estimation + - `PosteriorAbilityEstimator`: Bayesian estimation with priors + - `MeanAbilityEstimator`: Expected a posteriori (EAP) + - `ModeAbilityEstimator`: Maximum a posteriori (MAP) +- **Ability Trackers**: + - `NullAbilityTracker`: No tracking + - `PointAbilityTracker`: Tracks point estimates + - `GriddedAbilityTracker`: Grid-based tracking + - `ClosedFormNormalAbilityTracker`: Analytical normal approximation +- **Integration**: Various integrators for numerical integration +- **Optimization**: Optimizers for finding maximum likelihood/posterior + +### 3. CAT Logic Layer + +#### NextItemRules (`src/NextItemRules/`) +Implements item selection algorithms: +- **Strategies**: + - `ExhaustiveSearch`: Evaluates all items + - `RandomNextItemRule`: Random selection + - `RandomesqueStrategy`: Top-k random selection + - `BalancedStrategy`: Content balancing +- **Criteria**: + - `InformationItemCriterion`: Fisher information + - `AbilityVariance`: Minimize ability estimate variance + - `UrryItemCriterion`: Difficulty matching + - `ExpectationBasedItemCriterion`: Expected criteria values +- **Multi-dimensional support**: D-Rule, T-Rule for MIRT + +#### TerminationConditions (`src/TerminationConditions.jl`) +- `FixedLength`: Stop after N items +- `RunForever`: No termination +- `TerminationTest`: Custom termination logic + +### 4. Execution Layer + +#### Rules (`src/Rules.jl`) +- `CatRules`: Main configuration struct combining: + - Next item selection rule + - Termination condition + - Ability estimator + - Ability tracker + +#### Sim (`src/Sim/`) +Simulation and execution: +- `CatLoop`: Configuration for running a CAT +- `run_cat`: Main execution function +- `CatRecorder`: Recording CAT sessions +- Response callbacks and hooks + +### 5. Advanced Features + +#### DecisionTree (`src/DecisionTree/`) +- Pre-computation of CAT decisions into decision trees +- `MaterializedDecisionTree`: Stored decision tree +- Memory-mapped storage for large trees + +#### Stateful (`src/Stateful.jl`) +Stateful interface for CAT implementations: +- `StatefulCat`: Abstract interface +- `StatefulCatRules`: Implementation using CatRules +- Methods: `next_item`, `add_response!`, `get_ability`, etc. + +#### Comparison (`src/Comparison/`) +Tools for comparing CAT configurations: +- Execution strategies for benchmarking +- Statistical comparison tools +- Watchdog for timeout handling + +#### Compatibility (`src/Compat/`) +- `CatR`: Compatibility with R's catR package +- `MirtCAT`: Compatibility with R's mirtCAT package + +### 6. Support Modules + +#### ItemBanks (`src/logitembank.jl`) +- `LogItemBank`: Logarithmic scale item banks +- Temporary workaround to get logprobs, likely to be removed later on + +#### Precompilation (`src/precompiles.jl`) +- Precompilation workloads for faster package loading + +## Key Design Patterns + +### 1. Configuration Trees +Most components use a tree structure of configuration objects: +```julia +CatRules( + next_item = ItemCriterionRule(...), + termination_condition = FixedLength(20), + ability_estimator = MeanAbilityEstimator(...), + ability_tracker = GriddedAbilityTracker(...) +) +``` + +### 2. Implicit Constructors +Many types support implicit construction where components are automatically selected: +```julia +# Explicit +MeanAbilityEstimator(PosteriorAbilityEstimator(), integrator) + +# Implicit - finds appropriate components +MeanAbilityEstimator(bits...) +``` + +### 3. Preallocatable Pattern +Components can be preallocated for performance: +```julia +rule = preallocate(next_item_rule) +``` + +### 4. Tracked Responses +Responses are wrapped with tracking information: +```julia +TrackedResponses( + responses::BareResponses, + item_bank::AbstractItemBank, + ability_tracker::AbilityTracker +) +``` + +## Performance Optimizations + +1. **Preallocation**: Many components support preallocation +2. **Specialization**: Type-stable code with concrete types +3. **Threading**: Thread-safe operations with `init_thread` +4. **Integration caching**: Grid-based integrators cache evaluations +5. **Log-space computations**: Avoid numerical underflow + +## Extension Points + +1. **Custom Item Selection**: Extend `ItemCriterion` or `NextItemRule` +2. **Custom Ability Estimation**: Extend `AbilityEstimator` +3. **Custom Termination**: Implement `TerminationCondition` +4. **Custom Item Banks**: Via FittedItemBanks.jl interface + +## Testing Architecture + +- Unit tests for individual components +- Integration tests for complete CAT runs +- Smoke tests for various configurations +- Aqua.jl for code quality +- JET.jl for type stability + +## Documentation Structure + +- API documentation via Documenter.jl +- Examples using Literate.jl +- Interactive demos with Makie.jl plots +- Compatibility with R packages documented diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..0fc30d1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,105 @@ +# Claude Code Assistant Guide for ComputerAdaptiveTesting.jl + +## Overview + +ComputerAdaptiveTesting.jl is a Julia package that implements Computer Adaptive Testing (CAT) algorithms. The package provides fast implementations of well-known CAT approaches with flexible scaffolding to support new approaches and non-standard item banks. + +## Development Workflow + +This project uses a **pull request workflow**. All changes should be made in feature branches and submitted via pull requests for review. + +### Steps for Contributing: + +1. **Create a feature branch** for your changes: + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make your changes** following the project structure and conventions + +3. **Run tests** before committing: + ```bash + julia --project=test test/runtests.jl + ``` + +4. **Commit your changes** with descriptive commit messages + +5. **Push to your branch** and create a pull request + +6. **Wait for review** before merging + +## Project Structure + +See @ARCHITECTURE.md for detailed information about the codebase structure. + +## Key Areas for Assistance + +### 1. Core Modules +- **Aggregators**: Ability estimation and tracking +- **NextItemRules**: Item selection algorithms +- **Responses**: Response handling and storage +- **Sim**: Simulation and CAT execution + +### 2. Testing +- Tests are in the `test/` directory +- Run tests with `julia --project=test test/runtests.jl` +- Note: `Pkg.test()` currently doesn't work (see issue #52) + +### 3. Documentation +- Documentation source is in `docs/src/` +- Examples are in `docs/examples/` +- Build docs with `julia --project=docs docs/make.jl` + +## Common Tasks + +### Adding a New Item Selection Rule +1. Create new file in `src/NextItemRules/criteria/` +2. Implement the criterion interface +3. Add tests in `test/` +4. Update documentation + +### Adding a New Ability Estimator +1. Create new file in `src/Aggregators/` +2. Extend the `AbilityEstimator` abstract type +3. Implement required methods +4. Add integration tests + +### Working with Item Banks +- Item banks are provided by FittedItemBanks.jl +- See examples in `test/dummy.jl` for creating test data + +## Code Style Guidelines + +1. Use Julia formatting conventions +2. Follow the [SciML style](https://docs.sciml.ai/SciMLStyle/stable/) +2. Add docstrings for public functions using DocStringExtensions +3. Keep functions focused and modular +4. Use meaningful variable names (except in performance-critical inner loops) + +## Performance Considerations + +- The package is designed for speed with large item banks +- Use `@benchmark` from BenchmarkTools.jl for performance testing +- Profile with `profile/next_items.jl` for optimization work +- Other benchmarks are in the external CATExperiment + - This area is in flux and could be improved + +## Dependencies + +Key dependencies include: +- FittedItemBanks.jl for item bank management +- PsychometricsBazaarBase.jl for baseline utilities for the PsychometricsBazaar ecosystem +- Distributions.jl for statistical distributions +- ForwardDiff.jl for automatic differentiation + +## Useful Resources + +- [Package Documentation](https://juliapsychometricsbazaar.github.io/ComputerAdaptiveTesting.jl/dev/) +- [catR](https://cran.r-project.org/web/packages/catR/index.html) - R alternative +- [mirtCAT](https://cran.r-project.org/web/packages/mirtCAT/index.html) - Another R alternative + +## Getting Help + +- Check existing issues on GitHub +- Review the test files for usage examples +- Consult the documentation for API details