Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Psychometrics and educational assessment design for researchers
.claude/skills/brycewang-stanford-assessment-design-guide/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 20% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 103% | 0% |
| case-07 | ✓→✓ | = Same ✓ | 113% | 0% |
A skill for designing, validating, and analyzing educational assessments using modern psychometric methods. Covers classical test theory, item response theory, test construction, validity evidence, and computerized adaptive testing.
Classical test theory (CTT) models observed scores as the sum of a true score and error:
X = T + EKey reliability coefficients:
| Coefficient | Method | Interpretation | |-------------|--------|----------------| | Cronbach's alpha | Internal consistency | Homogeneity of items | | Test-retest | Stability over time | Temporal consistency | | Parallel forms | Equivalent test versions | Form equivalence | | Split-half (Spearman-Brown) | Odd-even item split | Internal consistency | | Inter-rater (Cohen's kappa) | Multiple raters | Scoring agreement |
pythonimport numpy as np import pandas as pd def item_analysis(responses: pd.DataFrame, total_scores: pd.Series) -> pd.DataFrame: """ Classical item analysis: difficulty, discrimination, point-biserial. responses: binary DataFrame (1=correct, 0=incorrect), items as columns. total_scores: total test score for each examinee. """ results = [] for item in responses.columns: scores = responses[item] difficulty = scores.mean() # p-value (proportion correct) # Point-biserial correlation corr = scores.corr(total_scores) # Upper-lower discrimination (top/bottom 27%) n = len(total_scores) cutoff_high = total_scores.quantile(0.73) cutoff_low = total_scores.quantile(0.27) upper = scores[total_scores >= cutoff_high].mean() lower = scores[total_scores <= cutoff_low].mean() discrimination = upper - lower results.append({ "item": item, "difficulty": round(difficulty, 3), "discrimination": round(discrimination, 3), "point_biserial": round(corr, 3), "flag": "review" if difficulty < 0.2 or difficulty > 0.9 or discrimination < 0.2 else "ok" }) return pd.DataFrame(results)
IRT provides a more rigorous framework than CTT by modeling the probability of a correct response as a function of ability and item parameters:
pythonimport numpy as np def irt_3pl(theta: float, a: float, b: float, c: float) -> float: """ Three-parameter logistic IRT model. theta: examinee ability (typically -3 to +3) a: discrimination parameter (slope, typically 0.5 to 2.5) b: difficulty parameter (location, same scale as theta) c: guessing parameter (lower asymptote, typically 0.0 to 0.35) Returns: probability of correct response """ exponent = -a * (theta - b) return c + (1 - c) / (1 + np.exp(exponent)) # Item characteristic curves for three items thetas = np.linspace(-3, 3, 100) item_easy = [irt_3pl(t, a=1.0, b=-1.0, c=0.2) for t in thetas] item_medium = [irt_3pl(t, a=1.5, b=0.0, c=0.2) for t in thetas] item_hard = [irt_3pl(t, a=1.2, b=1.5, c=0.2) for t in thetas]
python# Using the 'mirt' package in R (called via rpy2 or standalone) # R code for fitting a 2PL model: r_code = """ library(mirt) # responses: binary matrix (examinees x items) mod <- mirt(responses, model = 1, itemtype = "2PL") # Item parameters coef(mod, simplify = TRUE) # Ability estimates (Expected A Posteriori) theta_hat <- fscores(mod, method = "EAP") # Model fit M2(mod) # limited-information fit statistic itemfit(mod, fit_stats = "S_X2") """
| Model | Parameters | Use Case | |-------|-----------|----------| | Rasch (1PL) | b only | Equal discrimination assumed; measurement-focused | | 2PL | a, b | Different discrimination; general purpose | | 3PL | a, b, c | Multiple choice with guessing | | Graded Response | a, b_k | Likert-scale or partial credit items | | Nominal Response | a_k, c_k | Multiple choice with informative distractors |
Following the Standards for Educational and Psychological Testing (AERA/APA/NCME, 2014), validity is a unitary concept supported by five types of evidence:
pythonfrom factor_analyzer import FactorAnalyzer # Confirmatory approach: check dimensionality fa = FactorAnalyzer(n_factors=3, rotation="promax") fa.fit(item_responses) # Eigenvalues for scree plot eigenvalues, _ = fa.get_eigenvalues() print("Eigenvalues:", eigenvalues[:10]) # Factor loadings loadings = pd.DataFrame( fa.loadings_, columns=["Factor1", "Factor2", "Factor3"], index=item_names ) print(loadings.round(3))
Computerized adaptive testing selects items in real time to match examinee ability:
Initialize: theta_0 = 0 (prior mean)
For each item i = 1, 2, ..., until stopping rule met:
1. Select item with maximum Fisher information at current theta
2. Administer item, observe response
3. Update theta estimate using maximum likelihood or Bayesian EAP
4. Check stopping rule:
- Fixed length (e.g., 30 items)
- SE(theta) < threshold (e.g., 0.30)
- Maximum time reached
Return: final theta estimate and standard errorTo prevent overuse of high-quality items and maintain test security:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-07 | pass→pass | 11,720 | 16,444 | +40% | 1 | 1 | 0% | 2,008 | 4,271 | +113% | 0 | 0 | — |
case-12 | pass→pass | 14,466 | 9,611 | -34% | 1 | 1 | 0% | 2,500 | 3,395 | +36% | 0 | 0 | — |
case-01 | fail→pass | 20,894 | 32,229 | +54% | 1 | 1 | 0% | 3,843 | 4,604 | +20% | 0 | 0 | — |
case-02 | fail→fail | 19,386 | 23,581 | +22% | 1 | 1 | 0% | 3,651 | 6,268 | +72% | 0 | 0 | — |
case-03 | fail→pass | 16,183 | 14,275 | -12% | 1 | 1 | 0% | 2,598 | 4,338 | +67% | 0 | 0 | — |
case-04 | pass→pass | 11,631 | 12,554 | +8% | 1 | 1 | 0% | 1,813 | 3,988 | +120% | 0 | 0 | — |
case-05 | fail→pass | 17,462 | 11,856 | -32% | 1 | 1 | 0% | 2,540 | 3,893 | +53% | 0 | 0 | — |
case-06 | pass→pass | 14,073 | 15,123 | +7% | 1 | 1 | 0% | 2,253 | 4,210 | +87% | 0 | 0 | — |
case-08 | pass→pass | 8,157 | 11,138 | +37% | 1 | 1 | 0% | 1,397 | 3,654 | +162% | 0 | 0 | — |
case-09 | pass→pass | 11,997 | 11,637 | -3% | 1 | 1 | 0% | 2,154 | 4,323 | +101% | 0 | 0 | — |
case-10 | pass→pass | 11,640 | 11,501 | -1% | 1 | 1 | 0% | 2,037 | 3,799 | +86% | 0 | 0 | — |
case-11 | pass→pass | 12,590 | 14,448 | +15% | 1 | 1 | 0% | 1,907 | 4,311 | +126% | 0 | 0 | — |
case-13 | pass→pass | 20,378 | 24,720 | +21% | 1 | 1 | 0% | 2,838 | 5,632 | +98% | 0 | 0 | — |
case-14 | pass→pass | 11,203 | 8,123 | -27% | 1 | 1 | 0% | 1,711 | 3,095 | +81% | 0 | 0 | — |
case-15 | pass→pass | 5,980 | 4,351 | -27% | 1 | 1 | 0% | 907 | 2,631 | +190% | 0 | 0 | — |
case-16 | pass→pass | 7,918 | 11,544 | +46% | 1 | 1 | 0% | 1,144 | 3,745 | +227% | 0 | 0 | — |
case-17 | pass→pass | 12,131 | 12,967 | +7% | 1 | 1 | 0% | 1,932 | 4,240 | +119% | 0 | 0 | — |
case-18 | pass→pass | 10,463 | 5,866 | -44% | 1 | 1 | 0% | 1,697 | 2,903 | +71% | 0 | 0 | — |
case-19 | pass→pass | 4,593 | 3,579 | -22% | 1 | 1 | 0% | 707 | 2,507 | +255% | 0 | 0 | — |
case-20 | pass→pass | 8,359 | 6,696 | -20% | 1 | 1 | 0% | 1,368 | 2,979 | +118% | 0 | 0 | — |
case-21 | fail→pass | 18,243 | 25,142 | +38% | 1 | 1 | 0% | 3,137 | 6,373 | +103% | 0 | 0 | — |
case-22 | pass→pass | 20,728 | 19,920 | -4% | 1 | 1 | 0% | 3,937 | 5,326 | +35% | 0 | 0 | — |
case-23 | pass→pass | 18,026 | 19,597 | +9% | 1 | 1 | 0% | 2,686 | 4,663 | +74% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +17 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.