Saved means saved
A failed save could stay queued and later undo a newer successful action.
Case study
CodeHerWay brings lessons, quizzes, coding challenges, notes, and review tools into one place. Making those features available was only part of the work. The harder question was whether learners could trust what the platform told them: that their work was saved, that a checkpoint reflected understanding, and that opening the platform would not load tools they had not chosen to use. This case study follows three changes that made those promises more dependable.
Learner trust lens
Three places in CodeHerWay fell short of that. Each one was a mismatch between what the interface implied and what the code underneath actually did. The work stayed inside the existing architecture: reproduce a specific failure, repair the path that caused it, and confirm the tests could detect the original defect.
A failed save could stay queued and later undo a newer successful action.
Template-generated quizzes could reward recognizing an answer pattern without testing the lesson.
Opening the platform downloaded the code editor's dependency graph, although the editor was meant to load later.
Consider a learner who unmarks a lesson while her connection is unreliable. That request fails, so the platform queues it for retry. She then marks the lesson complete again, and this save succeeds. Before the fix, reconnecting could replay the old removal and erase the completion. The interface had confirmed an action that a stale background operation could later reverse. Bookmarks had the same failure pattern.
The repair clears obsolete queued writes after a newer write for the same record succeeds. It first covered direct progress writes (pull request 1020, August 17, 2026), then extended to the lesson-page buttons, which save through a different path (pull request 1211, September 17, 2026).
On a failed save, the queued item is the retry. Dropping it would lose the write entirely, which is the opposite data loss and just as bad.
Keep the retry system. Clear queued work only after a confirmed success, and only for the same record, identified by the queue's own resource keys.
Clearing the whole queue would have been simpler, but it could discard unrelated work that still needed to sync. Precision cost more code and more tests.
The important detail was deciding which operations were actually obsolete. A lesson bookmark and a concept bookmark inside that lesson are separate records, so clearing one must not discard the other, and there is a test for that refusal. Older lesson-key spellings that a browser might still hold also had to be matched.
The original reproduction failed before the first repair and passed afterward. For the second repair, each production change was reverted in place to confirm its tests failed without it. One revert initially passed, which exposed an untested line; a test was added and the revert then failed as it should.
What this does and does not promise: covered progress and bookmark writes can recover in the same browser without an obsolete queued operation undoing a later successful save. That is verified in automated tests against the real write queue. The reconnect flow was not exercised by hand, and this is not a claim of universal offline or cross-device recovery.
"I'd rather show no checkpoint than record a false one."
I withheld the generated checkpoints because a quiz that can be passed by recognizing an answer pattern still produces a score. The submission path treated that score as ordinary quiz evidence, and the platform used quiz scores as a signal of mastery.
The affected banks covered Next.js, React + TypeScript, and TypeScript Foundations. Their templates lacked the lesson-specific context needed to write plausible wrong answers. I did not think rewriting those templates would fix what the quizzes measured, even if it made the coverage report look better. Changing the label was also not enough: calling a quiz "generated" changes what the learner is told, but the score and review-card write path did not distinguish those banks from authored ones.
So the checkpoint is withheld until authored questions exist. That accepts visible gaps in the assessment experience and a smaller reported inventory, in exchange for keeping those checkpoints out of the normal score and review-card paths.
The decision is enforced where the quiz would render. The layout checks the bank's own "generated" marker and omits the whole checkpoint, heading included. Because the quiz never mounts, its submission handler cannot run. The gate reads the marker rather than a course list, so a checkpoint returns lesson by lesson as an authored bank replaces a generated one.
The quiz audit counted 316 lessons across 8 courses as having active quiz coverage, and reported that coverage as complete.
177 lessons across 5 courses. 139 generated checkpoints and their 417 template questions are reported separately as withheld placeholders.
These counts describe the assessment inventory, not learner achievement. No quiz questions or saved learner records were deleted. The 417 questions are unchanged.
A database check recorded the same day found no score or review-card rows matching any generated quiz. The outcome was preventive: a path that could record misleading evidence was blocked before anyone used it. The audit finding was closed on that basis, with the closure note stating plainly that the three courses still do not have authored quizzes. Writing those questions is tracked separately as curriculum work (pull requests 1218 and 1222, September 17, 2026).
Remaining limitation: the quiz submission hook still writes scores and queues review cards without checking the generated marker. The rendering gate is the current protection. A future surface that mounts a generated bank and submits through that hook could reintroduce the problem, so a check in the write path itself is an open engineering follow-up.
CodeHerWay includes an in-browser coding environment, but a visitor should not need its full editor payload just to open the platform.
An investigation into a small bundle-headroom item found something much larger. Vite's shared preload helper, which every chunk with a dynamic import depends on, had been placed inside a Monaco language chunk. Because the app entry needed that helper, it pulled in the editor's dependency graph with it.
The existing budget check did not reveal the cost. It measured the assets referenced by the entry HTML, while the extra dependencies arrived through static imports between JavaScript chunks. The check reported about 109 kB while the real figure was over 1,000 kB.
Entry dependency graph: 1,019.42 kB gzip JavaScript across 13 chunks, 7 of them Monaco.
109.10 kB across 7 chunks, none of them Monaco. The fix was one rule in the build configuration that gives the helper its own 0.66 kB chunk.
That is about 89.3% less gzip JavaScript in the measured entry graph. It is a payload reduction, not a measured 89.3% improvement in loading time.
The small configuration change depended on a larger investigative step: checking what the dependency graph actually contained instead of accepting a passing budget result (pull request 880, July 26, 2026).
Left open: strengthening the budget check to walk static imports from the entry was deferred as a separate decision, because it changes what CI measures. The fix removed the observed problem. It did not make every similar regression impossible.
I am CodeHerWay's designer and builder, and the pull requests described here were opened and merged under my account.
These results support a case for stronger implementation and more accurate product promises. They do not demonstrate higher completion rates, better retention, or improved learning outcomes.
None of the three changes altered keyboard, focus, or screen-reader behavior, and this page makes no new accessibility claim. One detail is relevant: a withheld checkpoint is removed together with its eyebrow and heading, so no empty section is left in the page. The platform's accessibility coverage is described on the platform overview.
A passing check is useful only when it measures the behavior that matters. The save queue needed tests spanning a failure, a later success, and a replay. Quiz assessment needed to protect the meaning of a recorded score, not only the accuracy of a coverage report. Performance measurement needed to account for dependencies beyond the assets listed in the HTML.
The common lesson was to make the product claim concrete enough to challenge. Can a successful save be undone? Can a quiz be passed without understanding? Does the first page really defer the editor?