Completion Is a Weak Memory Model
A learner can finish a lesson on Monday, answer the drill on Tuesday, and stare at the same idea on Friday with nothing to say. The checkbox still says done. The brain has moved on. That mismatch is the problem I wanted Neuroloq to handle. A completion flag records that contact happened. Tutoring needs a better question: what can this learner retrieve today? The technique is time-decayed mastery. Each concept keeps evidence about interaction, retrieval, decay, accuracy consistency, and the next useful card. The schedule comes from current memory, not yesterday's path through the course. 1. Completion misses time Reading, drilling, and explaining aloud leave different traces, and Neuroloq already held them in attempt history, confidence checks, exercise results, voice summaries, and study context. The design change was to treat them as one learner model. Four related changes shipped together on March 15, 2026: forgetting curve modeling, shared learner context across browser and phone sessions, knowledge stability scoring, and adaptive curriculum recommendations. They amount to one architectural move: progress became time-aware. flowchart TD lastSuccess[last_success] --> decay[decay score] halfLife[half-life per learner] --> decay accuracy[accuracy curve] --> stability[stability score] successRate[success rate] --> stability decay --> nextCard[recommended next card] stability --> nextCard caller[caller identity] --> profile[learner profile] profile --> context[study context] context --> nextCard nextCard --> interaction[new interaction] interaction --> lastSuccess interaction --> accuracy The diagram has two paths because Neuroloq has two study surfaces. Browser sessions can update the model in place. Phone tutoring has to identify the learner, load the profile, then continue from the same study context. If those paths diverge, the learner gets two tutors with separate memories. 2. Decay belongs to the concept The implementation is organized around concepts rather than pages. lib/cognitiveEngine.ts handles calibration, stability, transfer, and related scoring. lib/conceptTopology.ts supplies prerequisite relationships. lib/learnerProfile.ts loads and saves the learner record. lib/forgettingCurve.ts owns the decay model. That boundary matters. Updating memory is a transformation on a concept entry, driven by success or failure and the current time. It is not a user interface side effect. The price is stricter instrumentation. A loose event like “finished page” is cheap to emit. A concept-level update asks every surface, lessons, drills, flashcards, and voice, to agree on which idea was touched. 3. The scheduler needs decay, not recency A simple planner sorts by what the learner opened recently or what comes next. That helps navigation. It does not protect fragile memory. lib/forgettingCurve.ts separates untouched material from material that has started to fade. Concepts with zero attempts belong to curriculum progression. Concepts with prior attempts have a trace worth reviewing. The review list computes decay against the current time, keeps entries below a threshold, and orders the weakest concepts first. That split gives the curriculum engine room to choose between repair and advance. It also creates friction: a learner may want novelty while the tutor points back to a weaker prerequisite. I accept that cost because a tutor that only follows appetite becomes a playlist. 4. Stability is separate from decay Decay answers, “how much should time have eroded this memory?” Stability answers, “how consistent has recent performance been?” They feed the same planning loop, but they are computed differently. In lib/cognitiveEngine.ts, stability comes from recent accuracy values and variance. Classification also checks overall success rate. export function computeStabilityScore( accuracyCurve: Array ): number | null { if (accuracyCurve.length < 5) return null; const values = lastN(accuracyCurve, 10).map((c) => c.value); const m = mean(values); const variance = values.reduce((sum, v) => sum + (v - m) ** 2, 0) / values.length; return Math.max(0, Math.min(1, m * (1 - variance))); } export function classifyStability( stabilityScore: number | null, successRate: number ): StabilityTier { if (stabilityScore === null || successRate < 0.4) return "unstable"; if (stabilityScore >= 0.8 && successRate >= 0.7) return "locked"; if (stabilityScore >= 0.5) return "stable"; if (stabilityScore >= 0.3) return "forming"; return "unstable"; } lastN and mean are small helpers defined in the same file. That distinction keeps the model inspectable. A concept can be recent but shaky, old but reliable, or both stale and inconsistent. A single completion bit cannot express any of those cases. The concept entry carries five signals, each answering one question. Signal Question it answers lastInteractionDate When was this concept touched? halfLifeDays How quickly does it fade for this learner? decayScore How much retrieval strength remains now? accuracyCurve Has recent performance been consistent? successRate Is the learner succeeding often enough to trust the score? The tradeoff is compression. A stability tier is legible enough for interface decisions, but it reduces messy behavior to a small label. The tutor still needs recent sessions, weak topics, and study history when speaking to the learner. Take decorators: last touched nine days ago against a six day half-life, which leaves a decay score near 0.35, low enough for the review list. The half-life is stored per learner per concept, so the same nine day gap erodes one learner's decorators further than another's. The accuracy curve reads differently: the last ten values sit around 0.8 with little variance, which classifies as stable. Faded but stable means the memory erodes on schedule and holds up when tested. The planner queues a short retrieval rather than a reteach or new material. 5. Phone tutoring reloads the same model Phone tutoring adds one hard requirement: the learner is outside the browser session. The tutor has to identify the caller and fetch the same profile and study context before it can teach adaptively. The phone path lives under agents/tutor-agent/src/. The agent tools include getLearnerProfile, getStudyContext, resolveCallerIdentity, recordConceptProgress, saveDailyNote, logVoiceSummary, and endCallSummary. The matching application routes sit under app/api/agent/, including learner profile, study context, record progress, daily note, and voice summary endpoints. Phone number storage is part of the profile surface through app/api/profile/phone-number/route.ts and components/PhoneNumberSettings.tsx. The summaries a call leaves behind land in the same record the browser reads later. The same plumbing draws the failure boundary. A caller with no profile match cannot get adaptive tutoring, because there is no learner record to load. Guessing is the one option off the table: writing progress against the wrong identity would push one learner's evidence into another's memory, and that corruption is quieter and more expensive than a generic session. Identity resolution runs first because every later write depends on it being right. The downside is operational weight. A static lesson bot only needs a prompt and a transcript. A memory-aware phone tutor needs identity, profile access, context loading, progress writes, and summaries. I chose the heavier path because changing channels should not reset the learner. 6. The next card is a consequence The tempting way to build suggestions is to start with a ranked list. I prefer the reverse order: get the concept memory right, then let the next card fall out of it. The chain is small enough to inspect. A successful retrieval updates concept evidence. Time changes decay. Recent accuracy consistency changes stability. The curriculum engine weighs review against progression. Each step has a narrow job and a clear failure mode. Completion still has value as a navigation fact. It can say whether the learner reached the end of a lesson. It cannot say whether decorators, context managers, async, typing, or testing should come back today. Neuroloq became more useful when I stopped asking whether a concept was done and started asking how much of it was still available right now. 🎧 Listen to the audiobook — Spotify · Google Play · All platforms 🎬 Watch the visual overviews on YouTube 📖 Read the full 13-part series
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to