Study screen now matches the provided mockup's layout: a "Current Deck" panel with a circular mastery-progress ring, and a "Spaced Repetition" panel (New/Due/Learning/Review counts, streak, daily goal) on either side of the card. Kept the app's real global sidebar rather than the mockup's own nav, per direction. Mastery/Streak/Daily Goal weren't tracked anywhere, so this adds real backend support rather than showing fabricated numbers: - Mastered = graduated to review state AND FSRS stability >= 21 days (FlashcardScheduleStore.MasteryStabilityDaysThreshold), stricter than the plain Review-state count - CurrentStreakDays = consecutive UTC days with a review, computed from review-log timestamps in the new pure FlashcardScheduling .ComputeStreakDays (unit tested, habit-streak semantics: doesn't reset to 0 the instant a new day starts before today's first review) - DailyGoal/ReviewsToday reuse the account's existing ReviewsPerDay setting rather than inventing a new one Also removes the exit "X" button in favor of the same Escape/pause menu the question-player flow uses (main.gd's shared app_menu, with an "Exit Study Session" action), and adds a new circular_progress.gd reusable ring control plus a real "Options" menu (bury/suspend the current card) wired to schedule endpoints that had no UI before.
QuestionsApi
STEP-style question bank service for study games and clients.
Endpoints
GET /healthzHealth check.GET /api/questions/systemsList available systems.POST /api/questions/searchSearch or build a block of questions.GET /api/questions/admin/exportCursor-paginated full-bank export (SUPER only).GET /api/questions/{id}Get one question.POST /api/questionsCreate question (SUPER only).POST /api/questions/bulkUpsert questions byexternalId(SUPER only).POST /api/questions/admin/references/bulkUpdate only embedded verification references byexternalId(SUPER only).PUT /api/questions/{id}Update question (SUPER only).DELETE /api/questions/{id}Delete question (SUPER only).POST /api/question-reportsSubmit a categorized question report (USER or SUPER).GET /api/question-reportsList and filter reports, newest first (SUPER only).GET /api/question-reports/{id}Get a report and its question snapshot (SUPER only).PATCH /api/question-reports/{id}/statusResolve or dismiss an open report (SUPER only).POST /api/app-feedbackSubmit general feedback with safe client context (USER or SUPER).GET /api/app-feedbackList and filter app feedback, newest first (SUPER only).GET /api/app-feedback/{id}Get one app feedback report (SUPER only).PATCH /api/app-feedback/{id}/statusResolve or dismiss app feedback (SUPER only).POST /api/review-queue/nextGet one random pending review question, excluding IDs already shown in the current pass.POST /api/review-queue/attemptsIdempotently record the first answer for a review cycle.
Player reads require USER or SUPER JWT auth. Authoring endpoints require SUPER.
Answer tracking
The QuestionAttempts collection is the immutable source of truth and enforces
one first attempt per question and user with a unique compound index. Updated
clients submit the five choice IDs that were presented. Choice rates are the
percentage of presentations that resulted in selection, served from 32-way
materialized counter buckets and cached for up to five minutes. These rates are
independent and are not expected to sum to 100% when users see different
distractor subsets.
Submitted incorrect first attempts are materialized in ReviewQueueItems.
Skips are excluded. Review attempts are stored separately, do not affect Elo
or first-attempt statistics, and clear an item only when the first answer in a
review cycle is correct. Per-user incremental backfill checkpoints populate
the queue from historical first attempts without requiring a manual migration.
A background service snapshots the original choice IDs, backfills historical
attempts into v2 exposure counters, and reconciles recently active questions
every five minutes. The metric
step3_answer_statistics_v2_backfill_complete must equal 1 before adding
extra distractors to existing questions.
Search clients that set supportsChoicePools: true receive each complete
choice pool. Older clients receive five server-selected choices that always
include the correct answer. Published questions require 5-20 unique choices,
an explanation for every choice, a follow-up for every incorrect choice, and at
least one embedded authoritative verification reference. Legacy published
questions without references remain readable but must add references before a
future authoring update.
GET /readyzverifies MongoDB connectivity for readiness checks.GET /metricsexposes Prometheus-format service and reconciliation metrics.
The manifests in k8s/ configure 2-10 API replicas. The cluster must have
Kubernetes Metrics Server installed before applying them with
kubectl apply -k k8s/.
Questions submitted through authoring endpoints must have authoritative direct reference links recorded as described in the repository's Question Verification References policy. The references must verify the keyed answer and the material claims in the explanation; search-result links are not acceptable.