Algorithm Report

Civix Learning Algorithm Report

This document describes the learning algorithm in apps/mobile/lib/algorithm.ts: behavior, constants, and optimization status. It is maintained to reflect the implementation and tests in that file.


1. Algorithm version and USCIS constants

  • Version: ALGORITHM_VERSION = 3.1.0 (competency milestones + deterministic shuffle support).
  • USCIS test format:
    • Standard: 128 questions in pool; 20 asked at interview; 12 correct required to pass.
    • 65/20 (senior): 20 designated questions; 10 asked; 6 correct required to pass.

Constants in code: USCIS.TOTAL_QUESTIONS, USCIS.EXAM_QUESTIONS, USCIS.PASSING_SCORE, USCIS.SENIOR_QUESTIONS, USCIS.SENIOR_EXAM_QUESTIONS, USCIS.SENIOR_PASSING.


2. Mastery levels

Each question is classified into one level via getMasteryLevel(stats):

LevelMeaningHow it's computed
newNever seen!stats or stats.lastSeen === 0
learningSeen but not yet learnedNot mastered, stats.correct < 3
reviewingIn review cycle, not yet dueHas nextReview in the future
dueDue for reviewnextReview > 0 and now >= nextReview and within 24h of due
overduePast duenow > nextReview + 24h
masteredFully masteredstats.mastered === true (streak ≥ 3, seen ≥ 5, correct ratio ≥ 80%)

Usage in selection: Priority scoring favors new (base 10000+), then overdue, due, weak (streak 0), weak topics, low ease factor, and deprioritizes mastered (with exceptions when deadline is near). Review mode filters to due questions when any exist; learn mode favors new/learning; weak mode favors low streak or ease < 2.0.


2.1 Competency milestones (4-tier model)

computeCompetencySnapshot(pool, stats, options) computes a learner competency snapshot from:

  • mastered percent
  • rolling accuracy
  • overdue ratio
  • weak-topic density
  • pass-risk distribution

Tiers:

  • foundation
  • developing
  • proficient
  • interview_ready

Snapshot includes score (0-100), confidence, reasons, next tier target, and points-to-next-tier.


3. Study modes

ModePurposeFilter / fallback
learnNew and learning questionsFilter: no stats or lastSeen === 0 or correct < 3. Fallback: full pool if fewer than count.
reviewDue reviewsFilter: nextReview > 0 and now >= nextReview. Fallback: full pool if no due questions.
weakWeak topicsFilter: no stats (count as weak) or streak < MASTERY.MIN_STREAK or easeFactor < 2.0. Fallback: full pool.
coverageEnsure all seenReserves ~30% of slots for unseen; rest by priority.
categorySpecific categoryFilter by category or tags.
senior65/20Filter to senior-only pool (senior65 or SENIOR_QUESTION_IDS) and prioritize evaluatable questions (state-dependent items require stateProfile). No fallback to non-senior pool.
examExam simulationHandled by selectExamQuestions: category round-robin, 20 (standard) or 10 (senior) questions; senior exam uses same evaluatable-first guard.

4. Priority factors (calculatePriority)

Order of application (conceptually):

  1. New questions: Base 10000; +500 easy, +250 medium; deadline critical/intensive adds 3000/1500.
  2. Recently answered: -10000 unless due/overdue (then -500).
  3. Overdue: 5000 + min(daysOverdue × 200, 2000) + 500 × urgencyMultiplier.
  4. Due: 3000 + 300 × urgencyMultiplier (within 24h of due).
  5. Weak (streak 0, wrong > 0): 2000; +500 if seen < 1 day ago; +1000 × urgencyMultiplier if deadline.
  6. Weak topics: Sum of (weakTopics[tag] × 100) × urgencyMultiplier.
  7. Low ease factor (< 2.0): (2.5 - easeFactor) × 500; +300 × urgencyMultiplier when deadline and not relaxed.
  8. Spaced timing: Bonus by days since last seen (e.g. 1–3 days +300; >7 days up to +400); deadline critical/intensive tightens windows.
  9. Difficulty progression: If doing well (correct ≥ 3, streak ≥ 2), +200 hard, +100 medium.
  10. Mastered: Penalty -3000 (relaxed) / -1500 (intensive) / -500 (critical); reduced if days since > 7 or deadline near and days since > 3.
  11. Pass-risk layer: Adds weighted risk score (wrong-rate trend, streak breaks, low ease factor, overdue days, low-quality recent answers, deadline pressure) to prioritize likely failure points.

Deadline urgency multipliers: relaxed 1.0, moderate 1.5, intensive 2.0, critical 3.0.


5. SM-2 and mastery constants

  • SM2: Initial ease 2.5, min 1.3; initial interval 1 day; graduating interval 6 days; easy bonus 1.3.
  • MASTERY: MIN_STREAK 3, MIN_SEEN 5, MIN_CORRECT_RATIO 0.8, TEST_READY_THRESHOLD 0.9 (90% mastered = test ready).
  • Quality (0–5): Used in SM-2; correct answers get 3–5 by response speed; wrong get 0–2.

6. Optimization status

  • Correctness: MasteryProgress.learning returns only the count of questions in the learning and reviewing levels (no double-count with due/overdue). Unit test enforces separate counts for new, learning, due, overdue, mastered.
  • Selection: All study modes (learn, review, weak, coverage, category, senior) have defined filters and fallbacks. Review mode prefers due questions when present; coverage mode reserves slots for unseen; exam mode returns exactly 20 (standard) or 10 (senior) when pool is sufficient.
  • Senior hardening: Senior mode now avoids unanswerable state-dependent items when stateProfile is missing (e.g., governor/senator prompts), while still including them when profile context exists. Store fallbacks for practice and exam preserve senior-only scope.
  • Pass-rate optimization: Priority now includes calculatePassRisk(...) to surface weak/overdue/high-risk items earlier with urgency-aware weights.
  • Deterministic scenarios: shuffleArraySeeded(...) and optional shuffleSeed in selection APIs enable reproducible question order for testing and simulation.
  • Recommendations: getStudyRecommendations(...) accepts { isSeniorMode?: boolean } and generates mode-aware copy when the user is in senior mode.
  • Performance: weightedShuffle pre-normalizes weights once (O(n)); each pick is O(remaining length). Total cost O(n × count) instead of O(n²) per call.

7. Related files