Client-State Sync (SRS and Verified Recall Progress)
This document defines the backend contract for syncing flashcard progress to the backend. The browser uses it for local SRS backups; learning-coach/GPT verification also writes its per-card verifiedRecall results into the same node state.
Endpoint
GET /api/ui/learners/{skillpilotId}/client-state/{nodeId}
PUT /api/ui/learners/{skillpilotId}/client-state/{nodeId}
Browser and learning-coach tools can use the UI-facing endpoints above. GPT hard-recall tools use session-based AI endpoints; the GPT never receives the permanent SkillPilot ID in the normal flow:
POST /api/ai/{lang}/sessions/{chatSessionToken}/verified-recall/start
POST /api/ai/{lang}/sessions/{chatSessionToken}/verified-recall/answer
POST /api/ai/{lang}/sessions/{chatSessionToken}/verified-recall/result
start returns the next prompt but not the answer. It may receive goalId or use the active goal; retest: true can request a fresh card even when all cards are already verified. answer returns the expected answer only after the learner has submitted their response. result stores passed/failed, updates SRS scheduling, and returns the next prompt status.
Purpose
- Persist SRS and verified recall progress per memorization node (
nodeId) periodically (e.g., after 20 cards), on-demand, or after learning-coach/GPT hard-recall decisions. - Keep the backend PII-free. Browser/UI routes use the pseudonymous
skillpilotId; GPT routes use only a temporarychatSessionToken, which the backend resolves internally. - Allow later recovery or cross-device continuity via export/import.
Request
Headers
- Content-Type: application/json
Body
{
"updatedAt": "2026-02-02T19:30:00.000Z",
"srsState": {
"math_analysis_c01": {
"id": "math_analysis_c01",
"interval": 3,
"easeFactor": 2.4,
"repetitions": 2,
"nextReview": 1706892870000,
"lastReviewed": 1706806470000,
"verifiedRecall": {
"status": "passed",
"attempts": 1,
"failures": 0,
"lastTestedAt": "2026-02-02T19:28:00.000Z",
"passedAt": "2026-02-02T19:28:00.000Z"
}
},
"math_funbas_c02": {
"id": "math_funbas_c02",
"interval": 1,
"easeFactor": 2.3,
"repetitions": 1,
"nextReview": 1706806500000,
"verifiedRecall": {
"status": "failed",
"attempts": 2,
"failures": 1,
"lastTestedAt": "2026-02-02T19:29:00.000Z",
"lastFailedAt": "2026-02-02T19:29:00.000Z"
}
}
}
}
Notes:
- nodeId is the memorization node (learning goal) ID.
- The srsState object mirrors the per-node card-state entry and is stored as a JSON blob by the backend.
- Fields inside each card entry follow the SRS model (interval, ef/easeFactor, repetition/repetitions, nextReview, optional lastReviewed) plus optional verifiedRecall hard-test metadata.
- The verified recall lane is stored inside the card entry to keep the persistence shape backward-compatible. The backend may still inspect this lane for mastery calculation and learning-coach/GPT verification tools.
Read (GET)
200 OK
{
"updatedAt": "2026-02-02T19:30:00.000Z",
"srsState": {
"math_analysis_c01": {
"id": "math_analysis_c01",
"interval": 3,
"easeFactor": 2.4,
"repetitions": 2,
"nextReview": 1706892870000,
"lastReviewed": 1706806470000
}
}
}
Response
200 OK
{
"status": "ok",
"savedAt": "2026-02-02T19:30:02.123Z",
"storedKeys": 42
}
404 Not Found - If the endpoint is not implemented on the backend. The client should silently keep local storage and continue.
Backend Storage Recommendation
- Store as a JSON blob per learner + nodeId (e.g., table
learner_client_state). - Prefer last-write-wins using
updatedAt. - No PII in payload; do not add names/emails.
Security / Privacy
- Same authentication/authorization rules as other
/api/ui/learners/*endpoints. - Payload contains only SRS progress, no personal identifiers.
Client Behavior
- Auto-sync after every 20 reviewed cards.
- learning-coach/GPT verification writes after each hard-test decision.
- Manual Save button available in the UI where exposed.
- On sync failure, UI indicates an error but continues to work locally.