Courses & video courses, Challenges, Tracks, Daily Challenges, Debug Detective, Code Lab, Typing Quest, My Solutions, Tools · Requires: learner account (tester-learner-1..5) · Related: doc 03 for platform-wide rules (themes, sessions, toasts, offline), doc 06 for cross-feature journeys
Shared facts for this whole document
Run and Submit pace: at most 10 Run/Submit/Validate Fix starts per minute across all of practice. A refusal counts down — "Run again in 7 seconds." / "Try again in 47 seconds." — with the buttons unavailable until it ends; a refused start costs no start.
Editor shortcuts everywhere:Ctrl+Enter Run · Ctrl+Shift+Enter Submit / Validate Fix · Ctrl+Shift+F Format · Ctrl+F Find. A disabled control stays inert from the keyboard too.
Drafts are device-only. Practice code is "kept on this device alone" — the editor's foot says so — and clears at sign-out or an account change. It is never promised as a cloud save.
Empty work is refused before it is sent: code holding only spaces → "Your code is empty, so nothing was sent. Write your code first."; an empty custom input → "Your input is empty, so nothing was run…". A NUL character in code → "That request could not be understood, so nothing was run."
Verdicts are named exactly: Accepted · Wrong answer · Compile error · Runtime error · Time limit exceeded · Memory limit exceeded. Pending, refused and platform-unavailable are not verdicts and are never shown as a wrong answer.
Hidden test cases show one row each saying only passed or failed — never input, expected output, your output, time or memory.
XP: easy 30 · medium 60 · hard 100 · extreme 150 — first solve only, per owned item.
Solve rate / Fix rate shows "Not enough data yet" under 20 distinct eligible submitters, with its counts ("12 learners have submitted; a rate is shown from 20."); never 0% for an unreadable figure.
No Credits, no generated help on this deployment (GENERATED_ASSISTANCE=false): no "Analyse my code", "Analyse the selected code", "Explain this error" or paid reveal anywhere in this doc's pages. The one exception by design: a lesson page's right card shows "Ask WizBit about this lesson" marked Coming soon.
The product day is 09:00 → 09:00 IST for both dailies. Everything else uses midnight-to-midnight dates.
Courses — written subjects & video courses
Courses teaches through Subject → Chapter → Lesson — one hierarchy for both written and video formats, kept on two separate catalogue pages with separate learning records and rewards. Written lessons complete explicitly; video lessons complete at 95% verified watched coverage; quizzes are unproctored practice. A written subject pays 250 XP once plus an achievement (never a certificate); a video subject pays an achievement plus a certificate when its switch is on (never XP).
Route
Page
Notes
/courses
Courses catalogue
Written subjects only — search, filters, Continue strip, 20 cards + Load more
/video-courses
Video courses catalogue
Video subjects only; same layout; may be empty on this seed — empty ≠ broken
/courses/:subject
Subject
Facts row, outline by chapter, standing card, prerequisites, change brief
/courses/:subject/changes
What changed
Every published change since publication, by month, 20 at a time
/lessons/:lesson
Lesson (reading)
One player for every lesson kind; outline beside the shell nav from 1280 px
What must work: enrolment once per subject (video only — written subjects just lead to lessons); the one Continue target rule everywhere (last opened unfinished lesson → first unfinished in order → first unfinished); sequential navigation locks where authored; prerequisites with named status; completion once and forever — later edits never un-complete or re-pay; XP offered only while it would actually pay.
Seed content to use
Written subjects on this deployment: Data Structures in Python (20 lessons), Python Fundamentals (16), SQL Basics (13) — 13 chapters, 49 lessons total; each chapter has reading lessons, a quiz and a "Practice:" lesson. If no video subject is published, video-course cases marked "if seeded" can be N/A — the empty catalogue must still be honest, never fake content.
Courses — catalogues (/courses, /video-courses)
TC-CRS-001Catalogue shows real subject cards with learner standingP1
Preconditions
Signed in as a learner who has not started "Python Fundamentals".
Steps
Open /courses.
Read the three subject cards.
Open /video-courses.
Expected
Each card shows: cover (subject banner/logo mark or format icon), title, difficulty, a line about it, "n chapters, n lessons" plus lessons by kind, its length in words ("About 40 minutes"), Certificate mark where the subject awards one, and a footer standing — Not started, a progress bar while learning, or Completed.
A written subject not yet completed shows "250 XP on completion"; a completed one offers no XP figure.
Cards tile by page width: 1 column at ~390 px, 2 at ~768 px, 3 at ~1280 px, 4 only on very wide screens. The whole card opens the subject.
/video-courses is a separate page with its own Continue strip, search and filters; if nothing is published it says so plainly (not an error, not fake subjects).
The two pages' learnings are independent — progress on one never appears on the other.
Also try
A subject requiring another first offers no "Start now" on its card.
TC-CRS-002Search, filters, chips and counts on the catalogueP2
Steps
On /courses, type "SQL" in search.
Open the Filters control (popover on a computer; bottom sheet on a touch device) and apply a difficulty and a topic.
Remove one filter via its chip; press Clear filters.
Apply a progress filter (e.g. "Learning").
Switch between Courses and Video courses tabs and back.
Expected
The count of matching subjects updates with each search and filter; applied filters show as removable chips beside "Clear filters".
Filters (not the search text) are kept per page on this device until sign-out — reopening /courses in the same browser keeps them; they do not leak onto /video-courses.
While a progress filter is set the page shows how many it has loaded without claiming a total.
"No matches" and "nothing published" are different states: no-match offers clearing filters; an empty catalogue offers the topic-request callout, whose request starts its title from the search that found nothing.
Load more appears past 20 cards and never jumps your scroll position.
TC-CRS-003Continue strip returns to the right lesson and positionP1
Preconditions
Learner is part-way through "Python Fundamentals" — has opened but not finished a middle lesson.
Steps
Open /courses and find the Continue strip above the cards.
Press it.
Expected
Exactly one Continue strip per catalogue page, for that page's format only; it leads to the same lesson the subject page's Continue would open (the last lesson opened while unfinished, else the first unfinished in reading order).
For a video stopped part-way it offers Resume at the recorded second; for a reading lesson it reopens where you were.
A completed subject is never offered as unfinished. If the Continue read fails, the strip says it could not be read and the catalogue still browses fine.
TC-CRS-004Subject page explains itself before any enrolmentP1
Steps
Open /courses/data-structures-in-python (or any seeded subject) as a learner who has not started it.
Read the header, sections and outline without pressing anything.
Expected
Header names its catalogue as the way back ("Courses") and shows the cover plus the facts row: difficulty, what it holds counted by kind, length, order rule (open/sequential), Certificate where offered, and "250 XP on completion" for a written subject while it would pay.
Sections under their own headings: what it covers, what you will learn (1–8 short outcomes), before you start (prior knowledge — "None" where none expected), about the subject, what to learn next.
The outline lists chapters; each lesson marked Done, Up next, Optional, or waiting for the lessons before it — with kind and length, a quiz's best score or a video's watched share where relevant.
"Your standing" card shows a progress ring (a dash while nothing is required), the next lesson, the one main action (Start course), and "Finish these first" with each prerequisite's standing and link where prerequisites exist.
Opening the page enrolls nothing and records nothing; no toast, no "welcome to the course".
Also try
On a phone the one action sits in a bar at the foot of the screen; the standing card stacks above the outline.
TC-CRS-005Start course / Continue / sequential locks and prerequisitesP1
Steps
On a subject not started, press Start course (a written subject) twice quickly.
Finish a lesson, return to the subject page, press Continue.
In a sequential subject, paste the address of a later locked lesson directly into the address bar.
If any subject has prerequisites: try to start it before finishing them.
Expected
Start opens the subject's first lesson; repeated clicks create one enrolment, not two.
Continue opens the lesson the Continue rule picks (last opened unfinished → first unfinished → first unfinished anywhere).
A direct link to a locked lesson shows the outline and the lesson's place with an explanation naming what opens it — never the protected lesson body; its quiz/video views are locked the same way.
Unmet prerequisites keep Start waiting and show each required subject with your standing (Done, Learning with how far, Not started) and a link; an unmet-prerequisite direct link to a lesson names the course and lists what to finish first.
Staff are never held back (staff tester: every lesson opens, even past locks and prerequisites).
TC-CRS-006Completed subject stays completed — "Course completed" and "New since you completed it"P2
Preconditions
A learner who has completed a written subject (use an account that finished one, or complete "SQL Basics" — its chapters are short).
Steps
Reopen the completed subject's page.
Open a lesson inside it that was published before your completion.
If staff have added a lesson since your completion, find it in the outline.
Expected
Chapters read Completed; a lesson's head says "Course completed" rather than "n of m done"; every lesson — including anything added later — still opens; sequential order holds nothing back.
A lesson first published after your completion reads "New since you completed it" in the outline and the player until you open or do it; opening it re-completes and re-pays nothing.
The catalogue card and subject page offer no XP — "250 XP on completion" is gone once paid, forever.
Your standing card leads with what it earned, not a progress bar pretending more is required.
TC-CRS-007Reading lesson: layout, outline, bar, steps and completionP1
Steps
Open a reading lesson in "Python Fundamentals".
Read it; scroll to the foot.
Press Complete and continue.
On the subject's last unfinished required lesson, check the action reads Complete lesson.
Expected
One player inside the learner shell: the shell's navigation stays as you chose it (sidebar folds to its icon rail); the subject's outline stands beside it from 1280 px (1024 px with the dock), and opens as a sheet below that.
The lesson head (tinted in the Courses colour) gives its chapter, "Lesson n of m", title, kind and length, its chapter's lessons as a row of bars with "n of m done", and "You'll learn" outcomes.
The bar holds the way back to the course, text size as three choices drawn A / A+ / A++ (Standard text, Large text, Larger text), and Align (Left default or Centre) — the device remembers both.
Previous and Next at the foot name the neighbouring lessons (arrows alone on a phone); Back in the browser leaves the reader rather than stepping through every lesson visited.
Pressing Complete and continue records the lesson and opens the next one; the last required lesson's press completes the subject and opens the completion panel with what it earned.
A done lesson says Completed beside the way on; the main action stays findable on every lesson, for staff too (with "As staff, your completion is not counted").
TC-CRS-008Completion that fails to save is said, and never double-recordsP2
Steps
Complete a lesson, then double-press the action on the next one.
With dev tools throttling or a blocked request, press Complete and continue so the save fails.
Retry.
Expected
Repeated presses and retries produce one completion and one recognition — no duplicate counts in the outline ring.
A failed save says the completion could not be saved, right above the steps, and the button stays usable — the lesson is not marked done.
Only the answer that finished the lesson (or the subject) announces it: re-opening a done lesson or pressing again tells nothing anew, and WizBit does not celebrate the same completion twice.
TC-CRS-009Outline search, On this page, and reading position memoryP3
Steps
In the outline, use "Find a lesson" — search a word in another lesson's title, then a nonsense word.
Scroll a long reading lesson halfway, leave, reopen it.
On a ≥1280 px screen with a lesson that has ≥2 headings, use the On this page tab.
Expected
Search matches titles across all chapters, grouped by chapter, without closing the open lesson; no match is explained while the open lesson stays readable.
A reading lesson you were part-way through reopens at the heading you reached, with "Back to the top".
On this page uses authored headings only, marks the heading being read, and is omitted for fewer than two headings or on narrow layouts.
The outline's current lesson is tinted and scrolled into view; a held-back lesson is no link and its reason is read to a screen reader.
TC-CRS-010Content sections: text, callouts, tables, images, code to readP2
Steps
Walk a reading lesson that has headings, text, a callout, an image, a display-code block and a table.
Narrow the window under a wide table's width.
Check a callout in both themes.
Expected
Markdown renders: lists, emphasis, inline code, safe links; a table in GitHub table syntax draws as a real table with its headers and authored alignment, scrollable sideways in its own named region when wider than its room — the page itself doesn't scroll.
A callout carries text and an identifying symbol, not colour alone; it reads as note/tip/warning in both Prism and Halo.
Images have alt text (or are marked decorative), may have a caption/credit, and reserve their space while loading; a broken image reports its own problem without taking the lesson down.
Display code is syntax-highlighted and copyable, shows its language and optional filename, and offers no Run.
Plain text never executes pasted scripts; an unsupported or damaged section says it is unavailable rather than silently vanishing.
Find a lesson with a runnable example (a code block marked as an example with Edit / Run).
Press Edit, change the code, press Run.
For a program that reads input, type into the input box before Run.
Press Stop mid-run; press Run again; leave the page and come back.
For an HTML/CSS/JS example, Run it and click a link inside the preview that points off-page.
Expected
The example opens as authored code to read, with Edit, Reset, Stop and Run; Edit opens the shared editor and moves focus into it once ready — no editor is loaded until asked.
An execution-service example always shows its input box; "Ran" when no input was given, "Ran with your input" when there was. One example holds one run — re-running replaces the last.
Stop ends the run or clears the preview; an unconfirmed stop is explained, not declared successful. Errors name the file as you know it (main.py), never a server path.
Example runs are run-only: no verdict, no history, no skill evidence, no XP — the page says so, and what you typed is gone when you leave (said plainly, no draft-recovery promise).
A browser preview renders in a fresh isolated frame with its own console; a link inside it does not navigate — the preview says "That link goes to …, which this preview does not follow, so it stays on this page."
Examples run on the shared per-minute Run allowance but hold none of the three running-program places; during a server-execution outage browser previews still work and a terminal example preserves code, explains and offers retry.
TC-CRS-012The right card: WizBit tab, Contents, Code — and the Coming soon cardP3
Steps
On a computer ≥1280 px, open a lesson that has a runnable example and "code beside" on.
Open the right card's tabs: WizBit, Contents, Code.
Press "Open beside" on an example.
Look for "Ask WizBit about this lesson".
Expected
The right card (340 px, 460 px while Code is open) holds tabs: WizBit (greeting, one tip at a time, "More help" opening the help panel), Contents where ≥2 headings, and Code.
"Ask WizBit about this lesson" shows a Coming soon card — this is the designed exception while generated help is off; there is no working paid/AI action behind it.
Open beside puts that example in the Code tab's editor, one at a time; runs there are unmarked and unkept, and the page says so.
While WizBit shows beside the lesson, WizBit's floating corner steps aside and its messages wait.
Narrower screens drop the right card into sheets from the lesson's bar; a phone has no Code tab.
Courses — video lessons (/lessons/:lesson/video) — if seeded
Coverage rules to test against
A video completes at 95% verified watched coverage: the union of stretches actually played. Seeking past a range leaves it unwatched; re-watching counts once; paused, buffering, hidden-tab and disconnected time counts nothing. Reports go out every 30 s while playing and at once on pause, at the end, and on leaving/hiding.
TC-CRS-013Video playback, seek, resume and the watched stripP1
Steps
Open a video lesson; play 30 seconds, seek past a minute, play 10 more.
Leave the page; reopen it.
Look under the video for the watched strip.
Expected
Playback is the service's own player opened on a signed address made for this learner — no download offered anywhere; an old or unsigned address is refused (renewal happens quietly before it runs out).
Returning offers Resume at the recorded second or Start from the beginning; the catalogue/subject Continue also resumes there.
The strip under the video marks every stretch watched — across visits — and the 95% completion point.
Skipped ranges stay unmarked on the strip; a rewatched stretch counts once.
TC-CRS-015Captions, transcript, transcript search — and Mark as completeP2
Steps
Turn captions on; open the transcript beside the video.
Search a word within the transcript (in-lesson).
On an unwatched video lesson, use the foot's Mark as complete.
Expected
Every published video carries captions and a transcript — a required video missing either cannot have gone live.
Captions that fail to load are described as unavailable, never as nonexistent; a transcript load failure is not reported as "no matches".
Mark as complete works on any lesson kind (by design — someone who knows the material can move on) and the video view then shows the lesson as complete.
Staff watching sends no coverage and records nothing.
Unproctored practice — no XP, no skill evidence, works on phones and tablets. Question kinds: one answer, several answers (all-or-nothing), true/false, a number (exact unless an authored tolerance). Marks are whole numbers 1–10. Completion defaults to submission unless the author set a pass mark 1–100% judged on marks, not the rounded percentage. Optional timer 5–120 min submits on expiry. The full review shows once, right after submission, and is gone on revisit. Retakes are unlimited but ≥10 seconds apart.
TC-CRS-016Quiz: Before you start, answering, submit, score and the one-time reviewP1
Steps
Open a quiz lesson (each seeded chapter has one) → read "Before you start".
Press Start the quiz; answer all questions; press Submit.
Read the review carefully, then leave and reopen the quiz view.
Expected
"Before you start" states the completion rule (submission vs required pass), the timer if any, earlier scores, that leaving loses an unfinished take, and that full review exists only right after submission. The clock starts with Start the quiz, not on opening.
While answering, an answer bar shows how many are answered, a way to each question, the clock and Submit; submitting with unanswered questions asks in place first.
After submission: score as earned/possible marks with a whole-number percentage, then the full review — each question numbered, your answer, correct answers, explanations — plus up to three "Review this lesson" links for the most-missed material.
Review speaks of a pass only where the author set a pass mark; otherwise it gives marks and says the lesson is complete. A miss on the pass mark says the marks needed, e.g. "2 of 3 marks. That is not a pass yet. A pass needs 3 of 3 marks."
Revisiting shows latest and best scores and take count — never the answer-by-answer review again; the page told you so before and after.
Where submission completes the lesson, its outline mark updates; the review offers Take it again and Next lesson.
Find a several-answers question: select a strict subset of the correct options, submit.
Immediately (under 10 s) press Take it again and submit a second take.
If a quiz has a numerical question with tolerance, try a value inside and outside it.
Expected
Multiple-select is all-or-nothing: a partial selection earns 0 — no partial marks, no negative marking (deliberately different from tests).
A numerical answer is exact unless the author set an absolute or relative (≤10%) tolerance.
A second take inside 10 seconds of the first is not marked — the page says to try again in a few seconds, even if two are sent at the same moment; nothing is recorded as a zero.
A failed submission is retryable and never recorded as a zero or shown as completed.
Shuffled questions/options change order only, never the set or meaning; a take's review refers to the option itself, not its position.
A timed quiz that expires submits what is there — and the timer creates no proctoring or skill evidence.
TC-CRS-019Project lesson opens a Course Workspace and completes on the checklist + your confirmationP1
Preconditions
A subject containing a "Practice:"/project lesson (seeded subjects include practice lessons; find a Project kind lesson — the outline marks the kind).
Steps
Open the project lesson → its project view (/lessons/:lesson/project).
Open/start the Course Workspace from it.
In the workspace, check every task in the checklist; return to the lesson and press Mark complete; confirm it is your own assessment.
Expected
The project view shows the brief and what the workspace starts with; opening it creates/opens your Course Workspace (it does not consume your personal project count).
Completion needs a nonempty, all-checked checklist — an unreadable checklist is not ready — and your explicit Mark complete confirmation; checking the last task alone does not complete.
The lesson records completion once; reopening tasks or deleting the workspace afterwards does not reverse the lesson (or subject) completion already earned.
Mark as complete also works from the lesson itself, as on every kind (by design).
A missing/archived template or unopened assignment on an archived subject says why the subject cannot currently be completed — it is never waived or invented.
TC-CRS-020Practice (integration reference) lesson completes from the real itemP1
Steps
Open a "Practice:" lesson in a seeded subject → its practice view (/lessons/:lesson/reference).
Note the item it points to and your standing; open it where it lives and solve it (or pick one already solved).
Return to the lesson's practice view.
Expected
Learners read "Practice" for this lesson kind (staff see "integration reference"); the view names the item, your standing as its own area records it (Not started, In progress, Completed), and a link to open it where it lives.
Completed means: a solve for a challenge, every challenge solved for a track, a validated fix for a Debug case — the item's own verdict, not a second judgement.
Completion records when you open the practice view after finishing the item — once, with everything a lesson's completion brings; a completion from before the lesson existed counts too.
If the item is no longer published, the view says so; an already-complete lesson stays complete.
The lesson never invents the item's result and never lets Courses' Mark-as-complete rules be bypassed for the item itself.
TC-CRS-021Written subject completion pays 250 XP once, shows the completion page and the completion panelP1
Steps
Complete every required lesson of a written subject ("SQL Basics" is shortest).
On the final completion, watch the panel and open /courses/:subject/completion.
Check your XP history (header level or /xp-history) and Achievements.
Complete nothing new; reload the completion page.
Expected
The finishing answer opens a completion panel in place — what it earned and the certificate's state — and WizBit does not separately celebrate the same completion.
The completion page leads with the certificate in its state (a written subject never awards one — it says so through its state), then what it earned: "Finishing a written subject earned you 250 XP, once. It is in your XP history." — then where next: the author's suggested subject, challenges to practise, the catalogues, the subject to look over.
XP history shows the 250 XP once; the achievement unlocks once; repeated completion requests produce one completion and one recognition.
Afterwards the subject page and catalogue card offer no XP — completing it again would pay nothing, so nothing is promised.
Later staff edits (new lessons, moves, archival) never un-complete it or demand new work; a lesson added later reads "New since you completed it".
TC-CRS-022Video subject completion: achievement + certificate state, never XP — if seededP2
Steps
If a video subject is published: complete all its required lessons.
Open its completion page; check XP history and Certificates.
Expected
Completion pays the achievement, and a certificate when the subject's switch is on — the completion page leads with the certificate in whichever of its states it is (earned, needs a name, etc.).
No course-completion XP — a video subject never inherits the written 250 XP, and me.xpEarned-style wording never appears; the completion page does not name an XP figure.
A video subject's page and completion mark "Video courses" as the current navigation section even though the addresses sit under /courses; its lessons do the same under /lessons.
Course-content changes never rewrite an issued certificate's title, name or dates and never revoke it for a curriculum change.
TC-CRS-023Change brief and the changes page — published edits reach enrolled learners honestlyP2
Preconditions
Coordinate with a staff tester: they publish a small visible change to a subject you're enrolled in.
Steps
After the staff publish, open the subject page.
Read the change brief; press Got it.
Open /courses/:subject/changes.
Have staff save a draft edit (unpublished) — confirm nothing announces it.
Expected
The brief is a tinted panel above the sections, grouped Added / Updated / Moved / Removed, holding the oldest five unseen changes, newest first; it is dismissible and never blocks learning.
Got it marks only the changes shown — the next visit shows the next five, not the same ones; a first visit after enrolment invents no "since you last visited" changes.
The changes page shows the brief then every change since publication by month, twenty at a time.
Draft autosaves announce nothing; a published change arrives at once (hard-refresh not needed beyond a reload) — and a notice-delivery failure never claims the notice was delivered.
Changes never expose staff notes or internal details.
TC-CRS-024Draft preview links are signed-in, scoped, read-only and honest when deadP2
Preconditions
Coordinate with a staff tester for a /course-previews/:previewId link.
Steps
Open the preview link signed in as the intended learner.
Sign out / open it in a browser signed in as a different learner (if scoped) or after staff revoke it.
Try to edit anything on it.
Expected
The preview shows the draft lesson for review — read-only; no controls complete, run submissions on your record, or enrol you.
A signed-out visitor is sent to sign in; a learner outside the link's scope, an expired link and a revoked link all get the same plain not-found — no hint which it was.
Revocation by staff works; the link then opens nothing.
From /courses, open "SQL Basics" (13 lessons — fastest to finish).
Start course; work each lesson in order: read → Complete and continue; take each chapter's quiz (submit any take).
Open a "Practice:" lesson and complete the item it points to, then return to record the lesson.
Finish the last lesson.
Expected
Enrolment happens once; Continue always returns to the right place mid-way (close the browser mid-course and confirm).
Every completion record lands once; the outline ring reaches full on the last required lesson.
The completion panel and /courses/:subject/completion name the 250 XP once; XP history and the achievement each show it once; Home's Continue stops offering the subject.
My Solutions gains an entry for the practice item solved along the way (under its own area), and Profile's courses record counts the finished subject and lessons.
TC-CRS-026Pipeline — a course change mid-learning never loses earned progressP2
Preconditions
Staff tester available; learner part-way through a written subject.
Steps
Learner completes two lessons.
Staff add a new required lesson at the start, reorder two chapters, and publish.
Learner reopens the subject.
Staff then make the new lesson optional and publish again.
Expected
The learner's finished lessons stay finished after both publishes — progress is "completed applicable lessons against currently published requirements", so the remaining work and percentage can change but earned work is never discarded.
Done lessons stay open wherever they were moved to; order holds back only an unfinished lesson past an unfinished required one.
Step 4's publish recognizes completion in the background for anyone who has now done all that is still required — with its XP/achievement as if they had finished it themselves; nothing the learner does is needed.
The change brief explains both publishes in learner-facing words.
Staff tester; learner enrolled-but-unfinished in a subject staff will archive.
Steps
Staff archive the subject.
Learner opens /courses, then opens the subject directly, then a lesson.
Learner completes a lesson and checks the subject can still be finished if all requirements are met.
Expected
The subject leaves new discovery but stays readable to enrolled learners — its page says it is no longer in the catalogue; Continue (catalogue and Home) still leads back to it, and Achievements still counts how far they are.
Only Course Workspaces created before archival remain available; an unopened assignment can't create one — and if that blocks a required assignment, the page says why the subject cannot currently be completed rather than faking completion.
Progress, earned XP and any issued certificate are untouched.
Challenges are independently authored coding problems, each open in every language the grading service runs. Standing runs Not started → Tried → Solved: a valid non-platform-failure submission makes Tried; an all-pass Submit (visible and hidden cases) makes Solved. The first acceptance atomically records the solve, the retained source in My Solutions, the difficulty XP, and one skill contribution. Re-solves pay nothing; a first acceptance in another language adds a Solutions entry and that language's evidence but no second XP.
Route
Page
Notes
/challenges
Catalogue
Search + difficulty/topic/status filters in the URL, remembered on this device; "Pick up where you left off"; Random Challenge
/challenges/:challengeId
Challenge workbench
Test editor: Challenge / Hints / Editorial / Tries tabs + language file tabs (≤4 + More languages)
What must work: run free (visible examples or custom input), submit all-or-nothing, hidden cases opaque, hints free and laddered, editorial locked until first acceptance, drafts per language on this device, accepted code never overwritten by later failure, staff practise without XP/solve-rate/Solutions.
Seed content
40 published challenges — e.g. "Balanced Brackets" (easy), "Longest Common Subsequence" (medium), "Edit Distance" (hard), "Critical Roads" (extreme). Default limits: 5 s processor / 10 s wall / 128 MiB, scaled per language (Java ×2 time+memory, JavaScript ×2 time, Python ×3 time).
Challenges — the catalogue (/challenges)
TC-CHL-001Catalogue cards, search, filters, standing and solve rateP1
Steps
Open /challenges.
Search "brackets"; apply a difficulty filter and your status "Not started"; read a card.
Copy the URL with filters into a new tab.
Expected
Each card: title, difficulty, topics/languages, your standing (Not started, Tried, Solved), the XP a first solve pays (easy 30 / medium 60 / hard 100 / extreme 150), and the Solve rate with its counts.
Solve rate shows a whole percentage with the counts behind it ("40% solve rate · 40 of 100 learners"), "Not enough data yet" under 20 distinct eligible submitters — never a fabricated 0%; it is never rounded up to 100% unless every submitter solved (2,868 of 2,878 reads 99%).
Filters live in the address — the new tab shows the same filters applied; they persist on this device until sign-out while the search text does not.
No-match, empty catalogue and failed-load are different states: no-match offers Clear filters; empty offers a topic request; failure offers Retry — never fake challenges.
Track-owned challenges never appear in this catalogue.
TC-CHL-002"Pick up where you left off" and Random ChallengeP2
Steps
Submit a wrong-answer try on any challenge; return to the catalogue.
Press the pick-up strip.
Apply a difficulty filter; press Random Challenge twice.
Set filters so everything matching is solved, then press Random Challenge.
Expected
"Pick up where you left off" names the last standalone challenge you tried and haven't solved, with how that last try went, and opens its workbench; it disappears while loading, when there is none, and when it can't be read.
Random Challenge picks uniformly from unsolved published standalone challenges matching the current filters — never a solved one, never one outside the filter.
With everything matching already solved it says so ("You have solved every challenge that matches these filters…"); with nothing matching, that nothing is published matching — staying on the page; a failed lookup re-enables the action.
Challenges — the workbench (/challenges/:challengeId)
TC-CHL-003Statement, examples, limits and comparison policy before you submitP1
Steps
Open "Balanced Brackets".
Read the Challenge tab fully before coding.
Expected
The statement gives input/output descriptions, constraints, the visible examples (each a visible test case), the hidden test-case count, and the comparison rule: console output normalizes line endings and ignores one final newline, preserving other whitespace.
The challenge's limits are stated (5 s processor / 10 s total / 128 MiB by default) with each language's scaled allowance.
A SQL challenge states its comparison rule and shows the allowed schema and visible datasets — hidden datasets stay hidden.
Markdown renders (tables draw as tables); raw HTML in a statement never executes.
Opening a challenge marks no standing — standing changes only on a valid submission.
TC-CHL-004Language tabs, per-language drafts and seeding precedenceP1
Steps
Open a challenge; look at the file tabs over the editor.
In Python, type code; switch to Java; type different code; switch back.
Reload the page in each language.
On a challenge you already solved in Python, open it in Java.
Expected
Every language the grading service runs is selectable: up to 4 language file tabs (each with the language's mark), the rest under More languages; none claims to be saved — the editor's foot says the code is kept on this device alone, with the language's version.
Seeding precedence: this device's draft → your retained accepted source for this challenge and language → the starter. A language with no authored starter opens on the standard starter (reads input, prints nothing).
Switching language never discards the other language's draft; each language's work survives a reload (device draft) — but a sign-out or another account's sign-in on the device clears it all, and another person's source never leaks in.
A restored draft is announced only when one was really restored; local saving unavailable is explained, not faked.
Reset to the starter stands at the editor's head, asks first, and leaves other languages' code untouched; Cancel changes nothing.
Another language waits while code runs or is graded.
TC-CHL-005Run is free experimentation — examples, custom input, empty refusalsP1
Steps
On a challenge, Run the starter against the visible examples.
Switch to your own input; Run with it empty; Run with real input.
Clear the editor to spaces and press Run and Submit.
Press Ctrl+Enter from inside the editor.
Expected
Run checks the visible test cases and shows each result under Result; a custom-input run shows output under Your input without a manufactured verdict or expected-output comparison — "Ran", not "Passed".
Run creates no submission, no completion, no reward, no standing change.
Empty input → "Your input is empty, so nothing was run. Type the input your program reads first." — nothing sent, no pace spent.
Whitespace-only code → "Your code is empty, so nothing was sent. Write your code first." — same for Submit; nothing is graded or blamed on the platform.
Ctrl+Enter runs exactly the button's action — including from the language picker's button — and a disabled Run stays inert (no stray newline, no second request).
A program with no usable output is explained through its output, not an invented case result.
TC-CHL-006Submit grades every case — verdicts, per-case rows, hidden opacityP1
Steps
Write a deliberately wrong solution; Submit (Ctrl+Shift+Enter).
Read the verdict and every test-case row.
Write a correct solution and Submit → Accepted.
While another submission is grading, reload the page.
Expected
Submit checks all visible and hidden cases; acceptance needs every case to pass — there is no partial score.
Verdicts are named exactly: Accepted · Wrong answer · Compile error · Runtime error · Time limit exceeded · Memory limit exceeded.
Each test case gets a row: a visible one in full (input, expected, your output, outcome), a hidden one saying only passed or failed — never values, time or memory.
A pending submission stays pending ("grading service is busy" waiting state from ~10 s, with "the result appears under Tries"), never flips to a fake failure; a reload while grading opens with the output showing it being graded, then the verdict.
Two rapid submissions of the same request record one outcome; a platform/capacity failure changes no standing and keeps your code for retry.
Acceptance flips standing to Solved atomically: solve+date, retained source, first-solve XP, skill evidence — they never disagree.
TC-CHL-007After acceptance: editorial unlock, Next challenge, My Solutions handoff, honest re-solveP1
Steps
Accept a challenge (use a different account or an unsolved challenge).
In the accepted result, press Read the editorial, Next challenge and Open it in My Solutions.
Reopen the solved challenge; submit a wrong answer; then check standing, Solutions and XP.
Expected
Before any solve, the Editorial tab exists but its content stays locked — there is no pay-to-reveal, give-up or failure-count unlock.
After first acceptance the editorial opens in that language; missing language coverage may offer a labelled different-language explanation — never the private reference solution.
Next challenge leads to the next unsolved standalone challenge in catalogue order under this device's filters, wrapping to the top; with none left it says every matching challenge is solved.
The My Solutions handoff opens your exact new entry, not the top of the list.
A solved challenge says it is solved before you press anything ("Solved <date>: no further XP"); a later failure cannot clear Solved or overwrite the accepted source; a repeat Accepted in the same language keeps the first source.
A first acceptance in another language files its own Solutions entry with that language's skill contribution — and still no second XP, no second solver in the Solve rate.
TC-CHL-009Tries history: own submissions only, honest ageingP2
Steps
Make several submissions on a challenge; open the Tries tab.
Open one try's source; look for another learner's submission via a guessed identifier (dev tools).
Expected
Tries ({n}) lists each finalized submission: verdict, language, test cases passed, date/time — newest first; the run bar also shows "{n} tries".
Opening a try shows your own retained source; nothing else's source is reachable — a guessed id reads as one that does not exist.
Detail is kept within 90 days or your most recent 80 challenge submissions, whichever keeps more; an aged-out try keeps its row with "Code no longer kept" and can't be reopened or restarted from.
Empty history, unavailable history, pending work and expired detail are four different states — a pending submission reads as pending, never failed.
TC-CHL-010Pace limit and busy grading are platform states, never your failureP2
Steps
Fire Runs/Submits quickly until the per-minute pace refuses (10/min shared across practice).
Read the refusal; wait it out.
If the grading service is busy, watch a submission that waits.
Expected
A pace refusal counts down — "Try again in 47 seconds." — with Run and Submit unavailable, each saying why, until it ends; nothing retries by itself and a refused start costs no start.
A submission the full grading service can't take reads Waiting, code kept, retried with backoff — not marked against you; only a persistent platform fault ends it, or "still turned away a day after it was sent" → not graded, which never counts against you.
While live updates are paused, "Check now" beside the grading message reads it once; a hidden tab re-reads when it comes back into view.
A submitted job that completes after you close the page is still finalized — reopen to the recorded verdict.
A content change during grading rejects the mismatched outcome as a content conflict and lets you resubmit — never treated as your error.
Staff tester: unpublish, then archive or delete a challenge the learner has tried/solved. Republish it after.
Steps
Learner opens the challenge's address while it is unpublished, then archived.
Check the learner's Solutions entry, standing and XP.
Staff republish; learner solves nothing new — check no second reward exists.
Expected
The address shows the item's own not-found page — "We could not find that challenge — it may have been moved or taken down. Your earlier work on it is kept." — named in the browser tab too, with its way back.
Drafts, solves, rewards and retained Solutions entries survive; local drafts stay on the device and the page explains the content is unavailable.
Republishing grants no fresh first-solve reward to prior solvers.
Removal in Challenges never reaches a same-named track or Daily item — each is independently owned.
An explicit prerequisite on a not-yet-started challenge shows the requirement, your standing and a route; a started challenge never gains a surprise lock.
TC-CHL-012Staff on a challenge: free practice, no XP, no solve-rate, no Solutions entryP2
Preconditions
Sign in as staff / tester-staff-1 (Admin) in a second browser or after your learner session.
Steps
Open a challenge; read the staff note.
Submit a correct solve; check the solve rate, the staff member's XP and My Solutions.
Expected
The page says: "You are staff: solving here earns no XP, is left out of the solve rate, and saves nothing to My Solutions." — and where a learner would see XP, "Staff practice earns no XP".
Staff submissions are excluded from the Solve rate's attempted and solved counts.
Staff keep their own tries history but file no Solutions entry and earn no XP or evidence.
TC-CHL-013Pipeline — first solve pays once across every surfaceP1
Steps
Pick an unsolved easy challenge; fail once (Tried); then solve it.
Check: catalogue standing, XP history, My Solutions, the header level, skills.
Solve the "same" challenge again in a second language.
Expected
Tried appears after the first valid non-platform submission; Solved after acceptance — same standing on the card, the challenge page and the filter.
Exactly one XP award (30 for easy) in XP history; the retained source appears as one My Solutions entry; one skill contribution is recorded at the difficulty/classification of solve time.
The second language's acceptance files a second entry (its own language) — no second XP, no double solver in the Solve rate, no double completion.
Closing the tab right after Submit changes nothing: the finalized acceptance still lands exactly once.
A track is ordered practice in one language, owning its own challenge collection — never a link to standalone Challenges. Standing: Not started → In progress → Completed. Its challenges use the shared workbench but with exactly one language tab. Order is guidance, not a lock. Completing all currently published entries earns the track achievement (no XP — each challenge already pays its own first-solve XP).
Route
Page
Notes
/tracks
Tracks
Card grid; your tracks first: in progress → not started → completed
/tracks/:trackId
Track
Stepper path of its challenges + standing card + About this track
/tracks/:trackId/challenges/:challengeId
Track challenge
Same workbench as a challenge but one fixed language tab
What must work: Start once, Continue to the first unsolved, fixed language, own first-solve XP per challenge, completion once and durable through content changes, "See your track solutions" onward.
Seed content
"Arrays and Strings" and "Recursion and DP" — 17 track challenges total.
Tracks — the list and the track page
TC-TRK-001Tracks grid: cards, ordering and standingP1
Steps
Open /tracks.
Start one track, return to the grid; finish a track on another account, return.
Expected
Each card: the track's language mark as cover, title, a line about it, its language and version, how many challenges; its foot shows your standing — progress bar of challenges solved while in progress, Completed (with the solved count beside it when challenges were published since), Not started, or "No challenges yet".
Your tracks come first — in progress, then not started, then completed, each group newest first; the whole card opens the track.
A track with no published challenges says "No challenges yet" — it cannot start or fake a completion on an empty set.
Missing content and a failed read are different states.
Solve one challenge out of order; return and press Continue.
Expected
The challenges show in the author's order as a path/stepper: numbered steps, ticked once solved, the step Continue leads to ringed; each step card gives difficulty, first-solve XP, Solve rate and your standing (Solved, Up next, Not solved yet) — the whole card opens the challenge.
The standing card (beside the path where there's room, above where not) shows a ring of challenges solved now, the track's state, the day started or completed, challenges published since completion, what's up next, and Start track or Continue.
Start Track records the start once and opens the first unsolved published challenge — repeated presses create one start, no deadline, no reward.
Opening any challenge in the track also records the start; order is guidance — any published entry opens in any order (subject only to an explicit authored prerequisite).
"About this track" gives the description; each challenge's Solve rate uses the same rule as Challenges with "Not enough data yet" for small samples.
TC-TRK-003Track challenge: one language tab, track place shown, own recordsP1
Steps
Open a track challenge.
Look for a language selector; try to change language.
Check the strip under the title and the workbench tabs.
Expected
Under the title: the challenge's place on its track, and a strip of the track's challenges as numbered steps — ticked once solved — with previous and next a press away (until the track loads it shows only the track's name).
Exactly one language file tab — the track's language — with no More languages and no selector; the run bar shows "Submit" and its keys work across the page.
The workbench is the shared one: Challenge/Hints/Editorial/Tries tabs, per-item device draft, retained accepted source then starter, free Run with visible cases or custom input, Submit all-or-nothing, hidden rows opaque.
Drafts are scoped to this track challenge — never borrowed from a same-worded standalone challenge.
A temporarily unavailable runtime keeps your work safe and explains — it never silently switches language.
TC-TRK-004First solve in a track challenge pays its own XP and files under TracksP1
Steps
Accept a track challenge.
Check XP history and My Solutions → Tracks.
Re-solve the same track challenge.
Expected
First acceptance records this owned challenge's solve and date, its difficulty-based first-solve XP and its own practice evidence — calculated for this item, not by matching text across the platform.
The accepted source files a My Solutions entry under Tracks, naming its track as called at acceptance.
Re-solving earns no more XP or evidence; a failed later submission cannot overwrite the accepted source or remove Solved.
Its editorial (where authored) unlocks after acceptance and stays unlocked even if source later expires.
Track submission detail is kept within 90 days or your 80 most recent track submissions across all tracks, whichever keeps more.
TC-TRK-005Pipeline — completing a track: achievement, no XP, completion survives new contentP1
Steps
Solve every published challenge in a track.
Read the finishing submission's result; return to the track page.
Ask a staff tester to publish a new challenge into the completed track; reopen the track.
Expected
The solve that finishes the track says so in its result — "Solved. You earned 60 XP. That finishes <track>." — with See the track.
The track records Completed once with its date and completed coverage: the achievement unlocks once, and there is no bonus XP (each challenge already paid).
After staff add a challenge: the track stays Completed with its original date, and the new work shows separately — never flipped back to in-progress; the new challenge can still pay its own first-solve XP.
The completed track's standing card offers See your track solutions → My Solutions filtered to Tracks.
Staff unpublishing/archiving/deleting a published challenge settles completion in the background for learners who have solved all that remains — the worker completes the track for them.
Staff tester to unpublish/republish a track and to archive one challenge a learner is mid-way through.
Steps
Staff unpublish a track the learner started; learner opens /tracks and the track's address.
Staff republish it; learner resumes.
Staff archive the learner's "current" entry; learner presses Continue.
Expected
An unpublished track stops being available including its challenges — while earned completion, solves, rewards, drafts and retained solutions survive; republishing after checks pays nothing again.
An archived current entry doesn't strand navigation — Continue offers another available entry or the track overview.
Coverage is solved published challenges ÷ currently published count: adding changes unfinished coverage, removing changes the requirement — never erasing an earned solve or an unknown coverage into 0.
Deleting a track never touches a standalone challenge, a Daily, a Debug case or another track's challenge.
One staff-selected challenge per product date (09:00 → 09:00 IST), the same for every learner. A first accepted solve pays difficulty XP plus any authored bonus (0–200, default 40) — catch-up on a past date pays the same in full. Daily owns the platform's daily streak: consecutive eligible dates solved on their dates. The Daily can be switched off in settings; a voided date is neutral for everyone.
The challenge for that date; catch-up solving still pays in full
What must work: the on-time rule is the platform's receipt time during the product date (not device clock, not grading finish); pending grading is named, not a fake break; catch-up pays full but never repairs a streak; the switch and calendar states are honest.
Seed content
30 Dailies — one per day, IST today−14 → today+15. The 21:00 IST evening reminder goes only to eligible learners who submitted to any Daily in the last 14 days, have it on, and haven't disabled the preference.
Daily — today's page (/daily-challenges)
TC-DLY-001Today page: the challenge, the countdown and your stateP1
Steps
Open /daily-challenges before 09:00 IST and after (visit twice across the boundary if timing allows).
Read the challenge card and the countdown.
Expected
Today's scheduled challenge shows its facts, difficulty, base reward and bonus where present ("60 XP + 40 XP bonus for a first solve" style), supported languages, your state (unsolved / "Solved on its day" / "Solved · catch-up" / Tried) and the Solve rate.
The countdown reads "Open until 09:00 IST this morning" from midnight to 09:00 and "Open until 09:00 IST tomorrow" after — counted from your day on the product clock, never the device clock, and never negative.
An open page refreshes itself at the 09:00 boundary; a failed refresh keeps the previous view under an explicit stale-view notice with Retry — it never claims yesterday is still today.
A date with no Daily (neutral) and a failed read are different states.
Future dates disclose no future challenge title, difficulty or content.
TC-DLY-002Solve today's Daily on time → full award + streak dayP1
Steps
Open today's Daily; solve it within its product date (before 09:00 IST tomorrow).
Check XP history, the streak panel, the calendar cell and My Solutions.
Expected
The workbench is the shared one: statement, language tabs, free Run, Submit (all cases), hidden counts opaque; per-item device draft → retained accepted → starter; Reset asks first.
First acceptance pays difficulty XP + authored bonus once, files a Solutions entry under Daily Challenges, records one Daily skill contribution, and extends the streak by one day.
The calendar cell for today reads solved-on-its-day; the streak panel's "At risk today" clears.
A celebration plays for a real recorded result — revisiting never replays it; completing a Daily sends no separate achievement notification (streak milestones are separate).
Reopening a solved Daily says when it was solved and that another solve is free practice — "Solved: practice here earns no further XP".
TC-DLY-003On-time is receipt time: submission just before 09:00 still counts for its dateP1
Steps
At ~08:58–08:59 IST (or as close as feasible), submit a solution to today's Daily.
Let grading finish after 09:00 if it does.
Check the streak and the calendar cell.
Expected
On-time eligibility uses the platform's confirmed receipt time during the Daily's product date — not the device clock and not when grading finishes; a submission received before the date ends and accepted later still counts for its scheduled date.
While grading is pending, the date reads as awaiting its result — "Submitted on time, being graded" — never as a missed day.
A delayed successful result reconciles the streak from the recorded receipt: no false break, no duplicate reward, no replayed milestone.
A refused or failing submission earns no on-time completion — your own wrong code or slow connection never makes a date neutral.
TC-DLY-004Grading pending / platform failure keeps code and never fakes a break or a solveP2
Steps
Submit; throttle the connection or catch a platform failure while grading.
Close the tab mid-grading; reopen.
If the content changed mid-grading (staff edit), watch the outcome.
Expected
A waiting grade is pending — shown as pending (Waiting/busy-service wording), never recorded as a failure.
A platform failure or refused execution changes no solve, reward, evidence, streak or valid-submission count; code is preserved and a real retry offered.
A submission that finishes after the tab closes is still finalized; reopening shows the recorded verdict, and a closed page never invents a completion for work that never ran — resubmission is explained.
A content change while grading rejects the mismatched outcome as a platform/content conflict — inviting resubmission, never blaming you.
Repeated submissions of the same request record one outcome.
TC-DLY-005Past Dailies list and catch-up pays in fullP1
Steps
Open /daily-challenges/past; scroll and load older history.
Open a past date you haven't solved; solve it.
Check XP history, its Solutions entry, the calendar cell and your streak.
Expected
Past published Dailies are listed and solvable; older history loads on request — the first batch is not a permanent cap; months earlier can be navigated.
The past list and the calendar describe the same available dates and your records — a voided date reads "Neutral for everyone" in both, not "No Daily"; an archived Daily's date opens only for a learner whose records refer to it.
A catch-up solve pays the full difficulty XP + bonus, files the Solutions entry (marked as solved later, as catch-up), and labels the calendar cell "Solved later, as catch-up".
Catch-up never repairs a missed on-time date or reconnects a broken streak — the missed cell stays Missed.
Empty history and failed loading have different messages.
TC-DLY-006Calendar: nine date states, never colour aloneP1
Steps
Read the month calendar on /daily-challenges; hover/focus cells of each kind.
Navigate to an earlier month.
Compare with Home's seven-day strip.
Expected
States: Solved on its day · Missed · Today, still open · Today, solved · Upcoming · No Daily · Neutral for everyone (voided) · Before you joined · Daily turned off — plus "Solved later, as catch-up" and "…, being graded" marks.
Each state is told by its own mark, edge and words — never colour alone; the same cell draws on Home's strip.
A date that has had its Daily opens it; a voided date still opens for Runs and hints.
An unloaded or failed-to-load month never draws invented missed days.
Navigation stops at the current month and loads earlier months on request.
Dates before your membership began read "Before you joined" — they neither count toward nor break the streak.
TC-DLY-007Streak panel: current, At risk today, longest, milestones, lapseP1
Steps
Build a short streak over consecutive days (or use an account that has one).
Read the streak panel while today is unsolved, then after solving.
Miss a day; read the lapse acknowledgement.
Expected
Until today's eligible challenge is solved, the panel shows the streak ending yesterday at full length with At risk today; solving today extends it.
Milestones are 7, 30, 100, 200, 365 days — the panel shows distance to the next and an all-complete reading at the last; crossings are announced once under Streaks, with the 100/200/365-day achievements named in that one notice (no second Economy notice).
A lapse is acknowledged once with the previous length and a fresh-start message — not repeated blame and never an offer to buy a repair.
The longest streak is a separate lifetime record — it does not shrink when code detail ages out or when a Super Admin resets only the current streak.
An unreadable streak shows Unavailable — never 0; a neutral date carries no At risk warning.
Staff keep their own streak — staff solves count toward it but reach no milestones, and staff have no switch.
TC-DLY-008The Daily switch: off cancels honestly, on starts fresh, practice stays openP1
Steps
With a live streak, turn the Daily off on the streak panel (and check the same switch at /profile/settings/dailies).
Solve today's Daily while it is off; read the streak panel and Home.
Turn it back on; solve on time; check the streak.
Expected
Turning off asks first when there is a streak to lose; the streak cancels at once with no "your streak ended" message — it is your choice, not a lapse.
While off: no At risk today, no reminder, no milestone, no WizBit streak moment; Home and Profile say "Daily turned off" — never a zero — with one way to turn it back on.
The Daily stays open as ordinary practice: solving pays the usual XP + bonus but adds no streak day; missed dates while off draw "Daily turned off", never Missed.
Turning on applies at once and starts a fresh streak with the first on-time solve — a solve earlier that same day while off does not count; switching never repairs a streak.
Kept across switches: the longest streak (runs before each turn-off still count), milestones reached, achievements, XP, solve history.
Both places — the streak panel and Settings' Dailies — show the same switch.
TC-DLY-009Reward facts: bonus shown, difficulty locked at acceptance, repeat pays nothingP1
Steps
Read today's pay line before solving ("n XP + n XP bonus for a first solve").
Solve it; re-solve it; change language and solve again.
Where a Daily's XP can't be read, check the wording.
Expected
The first accepted solve pays difficulty XP plus any authored bonus — shown as e.g. "60 XP + 40 XP bonus"; the bonus is authored 0–200 (default 40).
Reward values and difficulty at acceptance are preserved — a later staff edit does not reprice a finished solve.
Re-solving, changing language or a progress reset never pays the same Daily again; a first accepted language can still file its own Solutions entry under Daily Challenges.
"XP could not be read" is said where the figure is unavailable — never a zero.
Staff see "Staff practice earns no XP" and staff solves count toward their own streak but reach no milestones.
TC-DLY-010Hints, editorial and My Solutions on a DailyP2
Steps
Reveal hints on a Daily; solve it; open its editorial where authored.
Open its My Solutions entry and compare where an editorial exists.
Check that hidden test cases, reference solutions and unrevealed hints stay hidden.
Expected
Hints are optional, authored, ordered and free — usable without WizBit; absent, exhausted and unavailable are distinct.
A Daily's editorial (per language, where authored) unlocks after first acceptance; My Solutions compares a Daily solution with it as for Challenges.
Hidden test cases reveal pass/fail counts only; the private reference solution and unrevealed hints never leak — including through error strings or dev tools.
On a SQL Daily the comparison rule is stated first and hidden datasets stay hidden.
Run costs nothing and creates no submission — the Solve rate counts only valid submissions.
TC-DLY-011Neutral and voided dates: no streak harm, honest statesP2
Preconditions
Find a neutral date (a date with no Daily scheduled — likely outside the seeded window or an unscheduled gap); a voided date exists only if a Super Admin voids one.
Steps
Read the calendar on a neutral date between two solved days.
Open a voided date's Daily if one exists; Run and read hints.
Check the streak.
Expected
A neutral date neither increases nor breaks any streak: Monday solved → Tuesday neutral → Wednesday solved = streak of two.
No At risk today shows on a neutral day.
A voided date reads "Neutral for everyone", still opens for Runs and hints, and is not falsely described as missing; existing valid solves and rewards survive the void but the date adds no streak day.
A learner's own missed visit never makes a date neutral — neutrality is platform-wide, never per-person.
The calendar never draws "missed" for a month it hasn't loaded.
TC-DLY-012Evening reminder: opens the actual date's challengeP2
Preconditions
Learner eligible (submitted to a Daily in the last 14 days), Daily on, reminder preference enabled; today unsolved by 21:00 IST.
Steps
At/after 21:00 IST, check the inbox/bell for the reminder.
Open it the next day.
Expected
At most one in-app reminder at 21:00 IST, twelve hours into the Daily's day — only if that date's published unvoided Daily is still unsolved; a last-minute solve before delivery gets none (rechecked at delivery).
The reminder stores the actual date and challenge: opening it the next day opens that challenge as catch-up — not the next day's challenge under yesterday's wording; it shows the date and timezone, not a stale "Today".
When your streak is at risk the reminder says how long it is; neutral dates produce none.
In-app only — no email/SMS/push promise; an already-delivered reminder isn't recalled if the date is later voided — it opens that date's explanatory page.
Each case ships broken code; acceptance means your repaired program passes every test case — no bug-location quiz, no partial score. Standing: Not started → Tried → Fixed. Two modes: Practice only (free, untimed) and Timed then practice (explicit windows — default 30 minutes, 3 per case — that never pause). Cases are offered only in the languages the author wrote broken code for. First fix pays the difficulty XP once either mode; only a qualifying timed acceptance contributes skill evidence.
Readable address; test editor + Debug additions (changed-lines bar, compare, restore)
What must work: broken-code seeding, changed-lines marking that never reveals where the bug is, free Run with one "This is the bug" cue, Validate Fix all-or-nothing, debrief unlock on first fix, one timed window at a time, honest deadline checkpointing, allowance restored on platform invalidation.
Seed content
12 cases — 4 easy ("Attendance Total and Best Day", "Grade Bands", "Leap Year Check", "Word Count"), 6 medium, 2 hard ("Spiral Order of a Grid", "Batch Rosters"). Bug types include off-by-one, boundary, state, logic, resource, typo.
Filter by bug type, language, your status and mode.
Read both Fix rates on a timed case.
Expected
Cards read as case files: title, difficulty, a line about the case, the planted bugs and their types ("2 planted bugs · Off-by-one, Boundary"), the languages its broken code is in, mode with a timed case's minutes and windows left, topics — then your standing (Not started, Tried, Fixed), first-fix XP and the Fix rates.
Practice and timed Fix rates are kept separately labelled — "Practice fix rate 88%" / "Timed fix rate 41%" — never averaged; each counts distinct learners, with "not enough data yet" under the threshold.
Filters (status, mode, difficulty, language, bug type, topic) live in the address bar; applied ones show as removable chips with Clear filters.
Timed cases disclose duration and remaining allowance before Start ("Timed then practice · 30 minutes a window · 3 of 3 windows left").
Empty board, no filter matches and failed loading are distinct states; a filtered board never changes lifetime personal counts; Load more pages the list.
Edit in one language, switch to another, come back.
Expected
The brief identifies console or SQL behavior, the comparison policy, every visible test case and the hidden test-case count — it never supplies the reference fix, internal bug note, hidden data or unrevealed hints.
Only the languages the author wrote broken code for appear as file tabs (not every graded language).
Seeding: this device's draft → your retained last submitted source for this case/language → the broken starter; on another device only acknowledged retained work can be recovered.
Each language's work is its own — per-language drafts and retained sources never cross.
The editor's foot says how the code is kept (this device alone, outside a timed window) — the save status distinguishes local draft from platform-held source.
TC-DBG-003Changed lines, "This is the bug", compare — and nothing marks the bugP1
Steps
In a case, edit a few lines — watch the editor's head and gutter.
Run so the examples fail (first failing run of the visit).
Press Compare with the broken code; then Back to your code.
Try Reset to the broken code and Restore last submitted.
Expected
A slim accent bar stands beside each line changed from the broken code; the head counts them — "3 lines changed", "No lines changed" — a changed stretch counting by its longer side.
The first failing practice Run of a visit may show the authored "This is the bug" cue — once per visit, beside the run; during a live recorded test the cue is withheld like hints.
No bug is ever marked: only what you changed is marked (against the broken code, never against the fix); no hint, gutter mark or diff reveals where the planted bugs are.
Compare shows broken code and yours side by side, read-only, lines facing each other where they agree, changed lines tinted neutral grey with a minus on the broken side and a plus in the accent on yours — never red/green — until Back to your code; your code (undo history included) survives untouched.
Reset to the broken code and Restore last submitted stand at the head, each asks first, and each leaves other languages' code untouched; Cancel does nothing; an unavailable starter blocks reset; reset is unavailable during execution; Restore is offered only while that language's source is retained. Neither returns the private reference fix.
Run the broken code against the visible cases; Run with your own input.
Press Validate Fix (Ctrl+Shift+Enter) with an incomplete fix; read the rows.
Complete the fix and Validate → accepted.
Expected
Run is ungraded and free: visible cases or one supplied input; empty input or an empty editor can't start a run (the same refusal sentences as Challenges).
Validate Fix checks the complete visible and hidden set and accepts only all-pass — each test case gets a row: visible in full, hidden pass/fail only.
The shared execution outcome is shown — never an invented "Debug score"; a platform failure is not a wrong fix and a never-completed run can't become an invented result.
Repeated requests record one submission; a job completes even if the tab closes; a case-content change mid-evaluation explains the conflict and invites validation again — no mismatched verdict recorded.
A fixed case offers Next case: the next unfixed case in board order under this device's filters, wrapping round; or "every matching case is fixed" / "no other matches".
Refusals (rate, capacity) say what's limited and how to recover — spending no result allowance or reward.
TC-DBG-005First fix: standing Fixed, XP once, debrief unlock, Solutions entry with modeP1
Steps
Validate a full fix on an unfixed case.
Open the Debrief tab; check XP history and My Solutions → Debug Detective.
Fail a later validation; check Fixed stays.
Expected
The first accepted fix records completion once — whichever mode produced it — with the difficulty XP once, and files the Solutions entry; the entry says whether the fix was accepted "In a timed window" or "In practice" (older entries without it say so — nothing is guessed).
A "Fixed" banner appears before another action and explains free re-practice; later successes make history but never another reward.
The per-language debrief unlocks: root cause, why the starter failed, repair approach, an important edge case and corrected learner-facing code — authored, never copied from the private reference.
A failed later validation cannot overwrite the accepted source or remove Fixed.
Using up timed windows does not unlock the debrief; no Give up or paid Reveal exists — an unfixed learner keeps hints and practice.
TC-DBG-006Recent submissions: outcomes, history window, honest ageingP2
Steps
Make several validations; open the Tries tab.
Open one's source; look for an aged-out entry.
Expected
Each entry shows outcome, test cases passed, language and time — your own only.
Detail and source kept within 90 days or your most recent 40 Debug submissions, whichever keeps more; aged-out entries keep their row with "Code no longer kept" — explained as such while the case keeps Fixed.
A failed validation is never presented as a fix; a platform-invalidated attempt is never presented as a wrong answer.
Personal volume (cases submitted/fixed, timed vs practice fixes, bug types practised, XP earned) never invents "Bugs found" or sums planted bugs into a claim.
Explicit start, one language, fixed minutes (default 30, configurable 5–120) and allowance (default 3, configurable 1–10) per case — the allowance spans all languages. One active timed window across all of Debug Detective; it may coexist with one live Mock/Company test (neither pauses). The checkpoint saves on Run, Save/Ctrl+S, Validate Fix and after 30 s of idle typing; a save within 5 s of the end is still taken. Closing the page doesn't discard the window.
TC-DBG-007Starting a timed window: disclosure, one language, one window at a timeP1
Steps
On a timed case, choose a language and press Start timed window.
While it runs, try starting a window on another case.
Check the board's disclosed allowance.
Expected
Before starting, the case discloses minutes per window and windows left; the window's language, duration and allowance are fixed at start.
Windows start on a computer only — a phone/tablet is refused at Start (as for tests), honestly.
Starting another window while one is active names the current case and time remaining and offers Resume or an explicit finish — never two at once; if the window state can't be established, no misleading Start is offered.
Inside a window the workbench keeps to that language: one tab, saying whether the code shown has reached the deadline — a filled dot while it hasn't, a turning ring while saving, a warning mark (press to save again) when it couldn't.
The timer does not pause when you leave or disconnect; the clock and Finish now sit under the title.
TC-DBG-008Deadline checkpointing: what reaches the deadline and what doesn'tP1
Steps
In a window, type a partial fix without saving; check the tab's save mark.
Press Save and Ctrl+S; type more and idle 30 s; press Run.
Close the tab mid-window; reopen the case.
Expected
One private acknowledged checkpoint per window, updated on explicit Run, explicit Save/Ctrl+S, Validate Fix, and after 30 s idle in the focused editor; the broken starter is itself acknowledged.
The tab says whether the on-screen code has reached the checkpoint — locally typed text is not promised as a saved deadline answer.
Closing the page doesn't discard the window: the workbench opens on the checkpointed code in a draft of its own.
A save arriving within 5 s of the end is still taken; later ones are refused.
A window open past its time ends within about a minute, or at once when you open a case or start another window.
TC-DBG-009Window endings: accept / finish now / timeout — and platform invalidation restores the windowP1
Steps
Window A: validate a full fix inside it.
Window B (new window or another case): press Finish now and confirm.
Window C: let time run out with unsent local edits past the last checkpoint.
If a staff tester can: have a case's grading-relevant content changed (or unpublished) mid-window.
Expected
Accepted validation inside the window → finishes immediately with the accepted timed result; it uses one window and the timed fix contributes skill evidence.
Finish now → grades the current acknowledged checkpoint after confirmation — uses one window.
Time running out → grades the last acknowledged checkpoint, not unseen typing — uses one window; the temporary checkpoint is then removed.
Checkpointed code that is all spaces → validated as not accepted (every case failed, nothing printed), the window used — never sent to grading as a platform fault; Validate Fix with such code is refused and leaves the checkpoint as it was.
Platform can't honestly grade (execution/checkpoint fault) → platform invalidation is explained, code preserved, and the allowance is restored — no window used; a material content change or unpublish does the same (ends the window, restores the allowance, says why, with the kept code shown to copy).
A failed validation consumes no extra window and doesn't end the current one; a closing validation turned away by a full grading service waits — the window stays ended, reads waiting, is not returned while it waits; only if still turned away a day after sending is it ungraded and the window returned.
TC-DBG-010After the windows: unlimited practice, a live test's restrictions apply, both populations countedP2
Steps
Use all timed windows on a case.
Keep practising; read the board and case for both Fix rates.
While a live Mock/Company test is in progress (stage one if possible), open a timed window.
Expected
Exhausted timed allowance → unlimited practice immediately, no wait, no dead end; the board keeps showing practice and timed Fix rates apart.
One timed Debug window may coexist with one live recorded test — neither clock pauses; while that test is live its account-wide restrictions (hints, companion/generated help, Notes and other prohibited assistance) apply here too, including the "This is the bug" cue being withheld; the test's end releases only those restrictions — Debug's own rules and deadline continue.
A timed fix on a case already fixed in practice adds skill evidence — never a second XP.
The case page keeps saying how your last window ended, with its date; code kept by a window a change ended is shown there to copy.
Staff may use timed windows but stay out of every figure — no XP, no evidence, not counted in either Fix rate.
Start a timed window; edit and let a checkpoint save (Run or 30 s idle); make further unsent edits.
Let the window expire (or coordinate a short-window case with staff); reopen the case.
Check: windows left, last-window outcome, Fix rates.
Expected
The expired window grades the last acknowledged checkpoint — not the unsent edits; the case page says how the window ended, with its date.
The allowance drops by one exactly; a failed deadline grading shows the checkpoint's outcome (e.g. all cases failed), never a platform-shaped failure; an accepted deadline fix ends Fixed with the timed-mode entry in Solutions.
Another window can then start normally; a material staff edit or unpublish mid-window ends it platform-caused with the allowance restored and kept code recoverable.
Practice and timed Fix rates each move only in their own population.
One scratch buffer per language — free, ungraded, unrecorded. A run is an interactive terminal (cloud or your own device) or a browser preview for HTML/CSS/JS; SQL runs in-browser on SQLite. No XP, no history, no solve rate, no skill evidence. Limits: 60 s per run, 256 MB (Java 384 MB), half a processor, 1 MB output, 2 minutes waiting for input; 10 starts/minute; 3 concurrent programs across Code Lab + Workspace; a program stops within 15 s of the session ending.
Route
Page
Notes
/code-lab
Code Lab
Editor beside output (terminal or preview); prepared input fold above; supplied page + environment folds under
What must work: Auto detection vs manual choice, per-language device drafts, honest run states (Ready/Queued/Running/Complete/Failed/Unavailable), Stop, Reset, download, format, environment view, queue position, every refusal named.
Code Lab — languages, drafts and the scratch
TC-CLB-001Language picker: Auto first, real registry, coming-soon entries honestP1
Auto stays first and may identify the current code's language, displaying its result; manual selection always wins and detection never rewrites code or silently changes the environment after Run.
Coming-soon entries (TypeScript, Kotlin, Swift, Scala, React) show with their reason and cannot be selected; a language the execution service isn't running now is listed with that reason — unless it also runs on your device, where the run is placed.
If the registry can't be read, the page says so rather than guessing: existing source stays visible, selection/run controls are honest, work is preserved.
A remembered language now unchoosable stays on screen with its scratch and Run says why; only one the registry no longer lists opens Auto.
With a language chosen, detection that settles on another offered language says "This looks like JavaScript, not Python." under the picker — it moves nothing and changes no code.
When detection is uncertain (e.g. browser JavaScript vs Node.js), the page asks you to choose before running — it never guesses.
TC-CLB-002One scratch per language: drafts on this device, starters, saved-locally honestyP1
Steps
Pick Python; edit its starter; switch to JavaScript; switch back.
Reload the page; sign out on the main site and sign back in; check the scratch.
Watch the page's foot after edits.
Block localStorage (dev tools) and reload.
Expected
Each language has one scratch and a runnable starter with a friendly welcome; a manual language change preserves the previous draft and opens the selected language's own draft or starter — saying which happened.
The foot follows the latest event — once an edit is written to the device it says so with the time ("Your changes, last saved at 14:32 IST."), until another language or Reset opens the scratch afresh.
The scratch, language and prepared input are device-local and scoped to the signed-in learner — cleared at sign-out or identity change; another account's scratch never leaks in.
"Saved locally" — or "Not saved locally" plainly when storage can't be written, said until a later write works; a local failure leaves editing usable and recommends downloading before leaving. No cloud-sync promise anywhere.
A new runtime version, supplied page, formatter or starter never rewrites existing code — a relevant change is explained once during the visit; Reset is how you deliberately take the newer starter.
TC-CLB-003The run bar names where it runs: "This device · Python 3.14.2" vs "Cloud · Python 3.14.10"P1
Steps
Pick Python; read the run bar's language label before running.
Run; read where the run was placed.
Open the environment fold under the editor.
Expected
The run bar says what Run will use and where, with an icon and the exact version — "This device · Python 3.14.2" (Pyodide on your device) or "Cloud · Python 3.14.10" — with Change opening the picker; or "Choose a language" while nothing is settled.
The picker itself names each language to its first two numbers — "Python 3.14" — since choosing doesn't fix where it runs; the run and the environment view name the exact version of the place it ran.
Python and plain browser JavaScript run on your own device where possible (held to the same limits); the cloud is used on a phone/tablet or when the device can't — and a cloud run is labelled "Ran in the cloud…".
Learner-facing text calls the execution service "the cloud" — never internal service names; a device run is described as this browser's worker with the device's version, its time/output limits, and no server limits claimed.
A run that can't finish on the device offers Run in the cloud — your choice, never a silent reroute.
TC-CLB-004Interactive terminal: output streams, typing input, prepared input, idle and time limitsP1
Steps
Write a program that prints, then asks for input (e.g. Python input()); Run it and type into the terminal.
Open the prepared-input fold and pre-fill lines; Run again.
Write a program that prints nothing; Run it.
Write an infinite loop; Run and wait past 60 s.
Expected
Output arrives as the program produces it; you can type into a running program — "Typing here reaches the program." — and waiting-for-input stays visible until the program ends, Stop is pressed or the stated idle limit (2 minutes) reaches.
Prepared input is a fold above the terminal, closed and empty by default; its lines are what the program reads first; input never read is not an error.
Run uses the code at the moment it's pressed — editing during the run doesn't change the running program; at most one active run on the page (waiting for input counts).
A program finishing normally is Complete — including one printing nothing ("Ran in the cloud and finished, printing nothing…" or the device equivalent — explained, not an error).
Over 60 s → ended at the named time limit ("Stopped at the time limit…"); over 1 MB output → a truncation notice, never a claim all output is shown.
A cloud run's errors name your file as you know it (main.py), never the cloud's folder.
TC-CLB-005Browser preview: isolated frame, console, supplied page, links never followedP1
Steps
Pick HTML (or CSS / browser JavaScript); Run.
Cause a console error in the preview script.
Put a link in the page pointing anywhere and click it.
Download the source; check what it contains.
Expected
Browser-native scratches render in a fresh isolated preview each Run, on the runner's own domain in a sandboxed frame — with their own console messages and errors; Copy and Clear operate on the console and changing language clears it.
CSS and browser JS get a supplied surrounding page — labelled and readable but not editable — and it is not included in the source download.
A link inside the preview is never followed — the preview stays and says "That link goes to …, which this preview does not follow, so it stays on this page."; preview content can't act on the surrounding app page.
Previews need no server-execution capacity — during an execution outage they still run, and they are never silently routed to a server.
The preview is described as a browser preview — never as if it were a server terminal.
TC-CLB-006SQL in the browser: SQLite on your device, fresh database each runP1
Steps
Pick SQL (in the browser); write CREATE TABLE + INSERT + SELECT; Run.
Run again — check the second run doesn't see the first's tables.
Write a long-running query; Stop it.
Check where its version is shown.
Expected
SQL runs on SQLite inside your browser (sql.js) in its own worker — never on the page, never on the server: the program socket refuses it; its version shows (SQLite 3.49) and the library loads only when SQL first runs.
Each run starts on a fresh database — state never persists between runs.
Stop ends a SQL run; one still going after 60 s is stopped and says so.
The registry names it by what it's for ("SQL in the browser"), distinct from "SQL for grading" used by challenges — no list shows two lookalike entries.
TC-CLB-007Stop, Reset, queued runs and cancelled runsP1
Steps
Start a run; press Stop before it finishes.
Start a run that queues; cancel while queued.
Edit the scratch; press Reset; confirm; then Reset and cancel.
Expected
Stop ends the program or cancels its queue place; an unconfirmed stop is explained — "The connection closed before the stop was confirmed. Whether the program ended is not known from here." — never declared stopped; late output from a discarded run never appears as the next run's result.
A queued run shows its real position — "Waiting for a place: 2 of 5 in line" (an estimate only where genuine) — and Stop leaves the line; an expired startup wait is Unavailable with code and input intact.
Reset asks before replacing the source with the selected language's starter and clearing output, naming the language once ("Replace your Python 3.14 scratch"); Cancel changes nothing.
Language changes, Format and Reset are unavailable during an active run (an unfinished preview load included) — Stop is the way to end it first.
Leaving, refreshing or losing connection ends the run — the page returns Ready with source, language and input restored, not a promised persistent terminal.
TC-CLB-008Shared limits and refusals — each one named, never your code's faultP1
Steps
Start programs until you hold 3 concurrent (across Code Lab/Workspace).
Try to start another; open "See your running programs".
Start 10 programs within a minute; try an 11th.
Disconnect the network and Run.
Expected
Over the concurrent limit → "You already have as many programs running as you may at once…" — with the running-programs list naming each by its project or area, and Stop process ending a selected program after confirmation (one that ended alone disappears as Stop is pressed).
Over 10 starts/minute → "You have started as many programs as you may in a minute, so this one did not start." then a countdown "Run again in 7 seconds." with Run unavailable until it ends — nothing retries by itself; a refused start costs no start.
Offline/unreachable → "The connection is down, so this page could not fetch what the run needs, and nothing ran. Your code is untouched; run it again once the connection is back." — the honest "nothing ran".
Capacity unreadable → explained as unknown, never called busy or a code fault; maintenance → named; execution unavailable → code preserved + retry; each refusal says what is limited and how to recover.
A session ending mid-run stops the program within ~15 s with the access reason ("Your session ended, so this program was stopped… your scratch is saved locally.") — never a compilation error.
TC-CLB-009Standard-execution alternative is honest about not being builtP2
Steps
Catch a run where the interactive terminal never started (throttle/network or observe a genuine startup failure).
Look for the standard-execution choice.
Expected
The alternative is offered only when an interactive program never started, the language supports checked standard execution, and no access/capacity/pace/maintenance refusal blocks it — nothing starts before you choose.
Where it isn't built, it is named honestly — "Running without the live terminal isn't offered yet. Try the terminal again in a moment." — never a dead button and never a fake result.
If a program already started, failure never triggers an automatic second run.
TC-CLB-010Download, Format, Expand, environment view — and no generated-help controlsP2
Steps
Press Download; check the file.
Press Format (Ctrl+Shift+F) where offered; undo it.
Expand the editor and restore.
Open the environment fold; read it.
Select code and look for any Analyse/Explain actions.
Expected
Download saves the current source with the language's normal extension (or .txt), available during a run, containing only your file.
Format applies as one undoable edit where supported — unavailable during active execution; a formatting failure changes no source and doesn't run the program.
Expand gives the editor the work pane's height; restore returns output and focus (Escape also restores).
The environment view shows real values — language/version, runtime, processor and memory limits, elapsed-time and source-size limits, network availability, temp-filesystem behaviour, input mode; an unknown value says "Unavailable", never an invented number.
No generated-help controls exist on this deployment: no "Analyse the selected code", "Analyse the whole file" or "Explain this error" — absent entirely, not dead or "coming soon".
Ctrl+Enter on the language picker runs rather than opening the list; a disabled action stays inert from the keyboard.
Typing Quest — typing practice in English and in code
Typing Quest trains typing on the learner's device — no keystroke goes over the network; each finished round sends one summary. Speed is WPM for English, CPM for code. The Typing Daily (own streak, own calendar, same 09:00 IST day) pays 20 XP once per date — everything else pays nothing, so practice can't be farmed. Computers only: a touch device gets the notice where the round would be. Thirteen achievements including WPM 40/60/80/100 at ≥95% accuracy on a 60-second English test, code 200/300/400 CPM on a whole snippet, Touch typist, From memory, and typing streaks at 100/200/365 days.
Route
Page
Notes
/typing-quest
Typing Quest (hub)
Test / Level check / Custom text + Typing Daily card, streak, recent bests; the round runs in place
/typing-quest/daily
Typing Daily
Today's round, streak panel, calendar, switch
/typing-quest/learn
Learn to type
Ordered keyboard lessons with finger zones; a lesson opens as a page state
/typing-quest/drills
Drills
Symbol and Bracket Blitz · My weak spots · Boilerplate Speedrun
/typing-quest/results
Typing results
Filters, bests, speed over time, key heatmap, slowest pairs, recent rounds
What must work: the round (Editor/Plain mode, ghost and bots, keyboard at the foot), honest save states and fair-result checks, the daily's streak/switch/calendar, lessons passing at target accuracy, drills from your own figures, honest empties everywhere.
Seed content & the fair-result checks
123 published texts: English simple/complex/placement/common-words; code in C, C++, Java, JavaScript, Python; templates; 7 lessons. A round is kept unverified when implausible — over 250 WPM, too short for its characters, machine-even key delays, contradictory figures, or longer than the server saw (+5 s leeway). Unverified rounds stay in your history but earn nothing. Paste and drop are refused. Pace: 30 round starts/minute; a finish window of 2 hours.
Typing — the hub and the tests (/typing-quest)
TC-TYP-001Start panel: kinds, lengths, modes — choices kept on the deviceP1
English offers a level (Common words, Simple paragraphs, Complex paragraphs) by time (15/30/60/120 s) or words (10/25/50/100); code offers a language by whole snippet or the same times, plus Editor or Plain mode (English is always Plain).
The Typing Daily card, the streak and recent bests sit beside the start choices; "Your results" leads to /typing-quest/results.
Choices and text size are kept on the device until sign-out — reload restores them; they are listed as "Your page choices" in Data & privacy.
The text is drawn at random from published texts for the choices; a words-length test cuts the text after that many words; a Common words draw is never the same twice running; a time draw gives as much as 250 WPM types in the time; none published says so plainly.
Touch device (or emulated coarse pointer): "Typing Quest needs a computer with a keyboard. Open this page on one to type." where the round would be — choices, streak and bests stay readable; a narrow window on a computer is still a computer.
TC-TYP-002A round: first key starts the clock, mistakes marked, backspace, paste refusedP1
Steps
Start an English 30-second test; type with some deliberate mistakes and corrections.
Try to paste into the text; try drag-and-drop.
Let the time run out; on another round type to the last character early.
Expected
The clock starts at the first key and ends at the time or the last character, whichever first.
A wrong character is coloured and underlined and the caret moves on; a newline typed wrong is marked at the line's end; Backspace takes back the last character and counts as a correction.
Paste and drop are refused — only typed characters count.
Restart, Next text or a changed choice leaves no result; Same again types the same text afresh; keys still being typed as a round ends start nothing (the result takes keys only after they've rested a second).
Live speed/accuracy/time update during the round without per-key repainting the page.
TC-TYP-003Editor mode vs Plain mode behave differently — and bests are kept per modeP1
Steps
Code test in Editor mode: type an opening bracket and a quote; press Enter on an indented line.
Same in Plain mode: type brackets and use Tab at a line start.
Check personal bests after rounds in both modes.
Expected
Editor mode: a typed opening bracket/quote inserts its partner (typing the closer steps over it); a new line starts at the right indentation and the caret never stops in it — what the editor inserts counts toward no speed and no keystroke; taking the opener back removes the partner.
Plain mode: every character is typed — Tab types spaces to the text's own next indent step, each space checked; where Tab doesn't indent it moves on; Esc leaves the text.
Personal bests are kept per mode — an Editor-mode best and a Plain-mode best never compete.
Brackets pair by nesting; a quote pairs with the next of its kind on its line.
TC-TYP-004Ghost cursor and benchmark bots race honestlyP2
Steps
Set a best on a test choice; pick Race → My best on the same choice.
Pick a bot at 40/60/80 WPM (200/300/400 CPM on code) and race it.
On a choice with no best, look at the Race options.
Expected
Race offers No one, My best, or a bot — My best only while a best exists for the same kind, level/language, length and mode; with none, the round races no one.
A line beside Restart/Next text says what is raced — "Racing your best, 52 WPM" / "Racing a 60 WPM bot"; the race starts with the round's first key.
The ghost is a second caret in the warning colour that glides by transform at the best round's pace; the bot keeps an even pace; under reduced motion the ghost jumps whole characters.
TC-TYP-005On-screen keyboard at the foot: press feedback, hints, hide options, finger zones in lessonsP3
Steps
On a ≥768 px screen, type a round watching the keyboard.
Toggle Hide keyboard and Hide key hints (Show again).
Type a wrong key; open a lesson and look at the finger zones.
Enable reduced motion (setting or OS) and type.
Expected
The keyboard stands at the foot of the window under the text (from 768 px), each key with its Shift character; a pressed key dips and glows; a mistake gives the expected key a short shake; key hints light the next key (Shift keys included).
Hide keyboard and Hide key hints are kept on the device; hidden, the keyboard gives its room back and never covers text, figures or WizBit's corner.
In a lesson the keyboard marks each finger's keys three ways — accent shade, an edge style per finger (solid index, dashed middle, dotted ring, double little, foot-of-space for thumbs) and labels (LP…RP, T) — never colour alone; a legend names each ("LP Left little finger"); the step's new keys are ringed and named above the round.
Under reduced motion: keys change colour without moving and nothing shakes; the caret and ghost jump instead of gliding; all animation is transform/opacity.
The keyboard is the one decoration that may move while you type — it answers the typing itself.
Finish a test; read the whole result before it saves and after.
Throttle the network so the save fails; press Retry.
Check the figures: accuracy never rounds up.
Expected
The result shows: speed (CPM with WPM beside it for code), raw speed, accuracy, corrections, consistency, time; a second-by-second speed chart with mistakes marked (loads after the figures); the missed words; the five slowest keys and pairs (seen at least twice).
The save state is literal: Saving… → Saved → "Not saved, tap to retry" — retrying sends the same finish again and the round saves once whichever try lands; a refusal the server words (text no longer offered, round too old, already saved) shows "Not saved" with the sentence and no retry where none can work; nothing says Saved before the server does.
A share is never rounded up: 89.6% accuracy reads 89% — a figure never claims a target it missed.
Actions: Drill my mistakes, Same again, Next text; nothing is celebrated until the save lands.
A round whose start couldn't reach the server is started again at save time and can't count — said honestly.
An unverified round is still saved and says without blame: "This round is in your history, but it can't count toward your bests and rewards: its figures are outside what our checks expect from typing by hand."
TC-TYP-007Personal bests and celebrations: announced once, only after save, never on revisitP2
Steps
Finish your first verified round on a test choice; read the result.
Beat that best; reload the page.
Check the confetti behaviour.
Expected
A best is your fastest verified round per kind + level/language + length + mode; a round only as fast is not a new best; the same finish sent again tells it again without doubling.
On first best: "Your first personal best for this test: 52 WPM."; on beating: "A new personal best: 56 WPM, 4 WPM faster than your last." ("just ahead of your last" under one WPM).
The confetti burst plays once behind the result — from what the save answered, never from a read; leaving/reloading shows nothing again; it lies behind controls, takes no click, lasts ~1.2 s; lite mode throws fewer pieces and reduced motion draws it still; a failed save celebrates nothing.
Drills, lesson steps, the Level check and custom rounds set no personal best; a Typing Daily round sets none either.
TC-TYP-008Level check and Custom text: their own kinds, their own rulesP2
Steps
On the hub, choose Level check; type a passage.
Choose Custom text; paste 20–3,000 characters with curly quotes and accents; type it.
Check Results filters for both.
Expected
Level check draws a published level-check passage at random with its minutes (1–5), typed in Plain mode always; its result adds Your starting level — "52 WPM at 97% accuracy" — kept under Level check in results; it races no one, sets no best, pays no XP, counts toward no speed achievement; with none published the page says so.
Custom text is made typeable on the device: accents stripped, curly quotes/dashes straightened, tabs → four spaces, edge blanks removed, non-US-keyboard characters dropped — the page says how many were left out; the field counts toward its 20–3,000 limit.
The custom text never leaves the device (check the network tab — no request carries it); its summary keeps no missed words and files under Custom; it counts toward nothing — no Daily, best, or achievement (not even First round).
"Remember this text in this browser" keeps it until sign-out; unticked forgets it; Data & privacy lists it as "Your custom typing text".
TC-TYP-009Today's round: one English slot or your code language, 90% accuracy completesP1
Steps
Open /typing-quest/daily; read today's offer.
Type today's round; finish under 90% accuracy; type it again at ≥90%.
Check the date's state and XP history.
Expected
Each date offers one English passage and one snippet per code language (Python, C, C++, Java, JavaScript), drawn from the Daily pool — the same for everyone; your code-language choice lists only languages the date has a snippet in (a language without one gives way).
Completion = a verified round finished at 90% accuracy or more, received during its product date — paste never counts.
The first completion of a date pays 20 XP once ("You finished today's Typing Daily. It paid 20 XP."), on-time or as catch-up — keyed by the date, so a retried finish or another round pays nothing more; XP history says "Typing Daily completed: <date>" and opens that date.
The result has Same again and no Next text; after Saving, the date says "You finished this date on its day. Another round is practice."
A date offering nothing says so ("Nothing to type on this date…"); a future date says it opens at 09:00 IST.
TC-TYP-010Typing streak panel, calendar and switch — its own streak, not the Daily'sP1
Steps
Complete today's Typing Daily on two consecutive days (or read an account that has).
Read the streak panel and the month calendar.
Turn the switch off and on (at /typing-quest/daily and /profile/settings/dailies).
Expected
The Typing streak is its own record, separate from Daily Challenges': current (with At risk today / Today done), longest, next milestone and distance (7/30/100/200/365), the lapse said once with OK, the rule in a line, and the switch.
The calendar draws the shared date states in the Typing Daily's words: Done on its date · Missed · Today still to type · Today done · Upcoming · Nothing to type · Typing Daily turned off · Done later, as catch-up — each with mark and words, never colour alone; each begun date opens its text (?date=YYYY-MM-DD) as catch-up with Back to today.
The switch mirrors Daily's rules: off cancels at once with no lapse message and asks first with a streak to lose; on starts fresh — a round earlier the same day while off does not count; the longest, milestones, achievements and XP are kept; staff are told their rounds reach no milestones and are refused the switch.
A round completed while off still pays its 20 XP.
Milestones announce once under Streaks ("You have finished the Typing Daily 7 days in a row…"), naming the badge at 100/200/365; a date completed while off or before a reset counts for nothing.
The page counts down on the platform's clock to 09:00 IST and re-reads once it passes; a failed refresh keeps what was shown under "The Typing Daily could not be refreshed" with Try again.
Open a lesson; type a step under its target accuracy, then at or over it.
Finish every step of a lesson; watch the completion.
Expected
Lessons list in order — each with steps passed or "Completed", the first not-completed marked Up next; with none published, "No lessons yet"; a lesson opens at its first unpassed step, any step re-typable.
Each step types whole in the tests' round, Plain mode, with the keyboard showing the step's new keys and finger zones.
A step passes at a verified round at/above its target: "Step passed: 96% accuracy against a target of 90%." / "Not passed yet: 82% accuracy against a target of 90%. Try it again." (unverified: "Not passed yet: this round can't count…") — with Next step; passing again changes nothing.
Completing the last unpassed step completes the lesson: one confetti celebration + "Lesson complete: you have passed every step." beside Next lesson and All lessons — never again on a repeat pass or revisit.
Finishing every published lesson unlocks Touch typist once (its gallery progress shows lessons completed of those published); a lesson added later keeps it earned.
A lesson step pays no XP, sets no best and counts in results only under Rounds/Time typed/Recent rounds ("Learn to type · step 2").
TC-TYP-012Symbol and Bracket Blitz: language symbols, 30 s, slowest keys namedP2
Steps
Open /typing-quest/drills; run Symbol and Bracket Blitz in Python, then JavaScript.
Read the result.
Expected
30 seconds, Plain mode, symbols drawn at random from the chosen language's list (shared {} [] () => ; : ' " < > ! == && || $ _ plus the language's own — e.g. __ ** // # @ -> != in Python, === !== ... ${} ?. ?? and backtick in JavaScript), a space between, never the same twice running; Next text draws again.
The result names the slowest symbols (each typed right ≥2×), slowest first, against your letters' pace — "{ 280 ms against 110 ms on letters"; with under 20 letters on record it says "Type a test or two, and your letters' pace shows beside these."; a failed read says so with the symbols standing alone.
The drill is a real saved round in results (Rounds/Time typed/Recent rounds) — but its speed is kept out of bests, averages, heatmap and achievements, with a line saying why the speeds are kept apart.
TC-TYP-013My weak spots and Drill my mistakes — built from your own figures, never inventedP2
Steps
Type a few tests first if the account is new (200 keystrokes needed).
Open My weak spots in English and in a code language.
On any round's result, press Drill my mistakes; then open the drills page fresh without a result.
Expected
Until your figures hold 200 keystrokes typed right, the page says so plainly with how many they hold and offers Start a test — a drill is never made up.
My weak spots (60 s, Plain mode) drills your four slowest keys, three most-missed keys, slowest pairs and most-missed words from your last 90 days — words drawn at random, never twice running; the page names the keys, pairs and words it drills; nothing to draw from says so.
Drill my mistakes opens the drills page with a drill made from that round's own missed keys/words — offered only when the round had ≥2 such words, carried in page history, never sent; opened without them it says to choose it from a round's result.
TC-TYP-014Boilerplate Speedrun: Learn it then From memory — 95% match counts it doneP1
Steps
On the drills page, pick a template in a language; Learn it (typed with it shown, Editor or Plain mode).
Choose From memory: type it as best you can (paste/drop/undo refused — verify), press Done.
Read the match, differences and time; try again for a better time.
Expected
Templates list by name in the chosen language with target time and your best from memory where you have one; none published says so; a template is offered only to Learn it / From memory.
From memory hides the template: Tab types to its indent steps, paste/drop/undo/redo refused, length capped at twice the template's; Done ends it.
The result shows the match (spaces/blank lines ignored), the time against the target ("1:12 against a target of 1:30: 18 seconds under."), speed and corrections — and the differences: template lines missing and extra lines typed, first ten shown, or "Every line matches the template."
≥95% match = Done from memory, verified on the server — the first ever unlocks the From memory achievement once; a faster verified time beats your best ("A new best time from memory: 1:05, 7 seconds quicker…") with confetti.
Learn it again / Same again round-trip correctly; what you typed for From memory is compared and never kept.
TC-TYP-015Dashboard filters and which rounds countP1
Steps
Open /typing-quest/results; switch Rounds filters (All, an English level, a code language) and Period (7/30/90 days, All time).
Finish a drill and a Level check; check the filters again.
Find an unverified round in Recent rounds.
Expected
Filters: Rounds (All, English levels, Code languages; Drills, Level check and Custom appear once you've finished one — before that the filters say "No drills yet" / omit them) and Period (7 days, 30 days default, 3 months as 90 days, All time).
Rounds and Time typed count every finished round in the filter; the speed/accuracy/consistency figures, speed-over-time, key heatmap, pairs and words count only verified rounds — unverified rounds show in Recent rounds marked "Not counted".
Drills filter shows Rounds, Time typed, a line saying why speeds are kept apart, and Recent rounds — with "No drills yet" in an empty period.
Level check and Custom filters show their own verified figures (no missed words for Custom — none are kept); under All they count in Rounds/Time typed/Recent only.
A figure with no verified round reads "Not yet" — never zero; a failed read says Unavailable with Try again; empty filter shows "No rounds yet" with Start a test.
Recent rounds name their kind — "Typing Daily · 27 Oct 2026 · English", "Symbol and Bracket Blitz · Python", "Level check · 3 minutes", "Custom text · Code", "Learn to type · step 2" — newest first, 20 a page with Show more rounds.
TC-TYP-016Bests, speed over time, key heatmap and honest empty statesP2
Steps
On a fresh account (or a filter with no rounds), read the whole dashboard.
After some rounds, read personal bests, speed over time, the heatmap by speed and by mistakes, slowest pairs and most-missed words.
Check the All-time heatmap note.
Expected
Personal bests list each kind + length + mode with the date set — with an honest empty like "No 60-second English test completed at 95% accuracy yet"-style where nothing qualifies.
Speed over time shows each day's average (IST) of verified rounds with the period's average, best and improvement (improvement only from a second day of rounds).
The heatmap shades each key by average delay or share of misses — character and Shift character together; key/pair/word detail reaches back 90 days max, so All time says "This heatmap covers the last 90 days: the detail by key is kept for 90 days."
Slowest pairs (five, seen ≥2×) and most-missed words (ten, with how many rounds missed each) show over the same 90 days.
The Typing streak panel sits under the dashboard whatever the filter — read once, with its switch.
Every empty figure says how to start or why nothing shows — never a fabricated zero.
TC-TYP-017Pipeline — test → saved round → best → achievement thresholdsP1
Steps
Finish a first verified round (any kind) → check the First round achievement.
Type a 60-second English test at ≥95% accuracy over a WPM threshold you can reach.
Type a whole code snippet at ≥95% over a CPM threshold.
Check Achievements and the results' progress.
Expected
The first verified round of any kind unlocks First round once (custom text's round does not count).
English speed achievements unlock at 40/60/80/100 WPM in a 60-second English test at ≥95% accuracy; code at 200/300/400 CPM on a whole snippet at ≥95% — every threshold the round reaches unlocks at once, announced once each.
Only verified rounds count — an unverified round unlocks nothing (no XP, achievement, milestone or leaderboard place).
Gallery progress shows the best qualifying figure against each threshold — honest numbers, never invented.
Staff unlock nothing — a staff round is excluded from achievements and pays no XP.
TC-TYP-018Pipeline — Typing Daily across two days: 20 XP once per date + streakP1
Steps
Finish today's Typing Daily on its date; check XP history and the streak.
Finish a past date's round as catch-up (?date=… on the daily page); check XP and the streak.
Retype today's round and send the finish again.
Expected
20 XP paid once per date — the same finish again, or another round of the same date, pays nothing more; a catch-up completion pays its 20 XP but never repairs the streak.
Consecutive on-time days grow the Typing streak independently of the Daily Challenges streak — each keeps its own calendar and milestones.
A round typed while a date turns (past the boundary) isn't kept for the new date — its date had ended, so it could only be catch-up.
Retyping today's text gives practice only — the date stays completed and no second XP lands.
My Solutions — the read-only archive of accepted code
Every first accepted submission per learner × owned item × language files one entry automatically — Challenges, Tracks, Daily Challenges and Debug Detective. Read-only: no Run, Submit or editing here. Entries last for the account's life; source is kept 90 days or while among your most recent (80 challenges · 80 tracks · 30 dailies · 40 debug), whichever keeps more. Staff never file entries.
Route
Page
Notes
/solutions
My Solutions
Four kind cards with counts, how-far-through figures, retention explanation
/solutions/:type
One kind's solutions
List beside the open entry where there's room
/solutions/entry/:entryId
Solution entry
Read-only code under its file tab, language tabs for other accepted languages
/solutions/entry/:entryId/compare
Compare solution
Your code beside the editorial — closes while a live test is in progress
What must work: exact-entry handoff after acceptance, per-language tabs, own highlighter (never the code editor), Wrap/Copy/line numbers, honest expiry vs fetch failure, editorials beside code where unlocked, milestone celebrations at 5/10/25/50/100/250.
Solutions — browse and open
TC-SOL-001Hub: four kind cards with real counts and reachP1
Steps
Open /solutions.
Read each kind's card and the collection's figures.
Expected
Four kinds — Challenges, Tracks, Daily Challenges, Debug Detective — each card shows its entries count and how far through the kind you are: "26 of 90 challenges solved · 28%" (Debug counts "fixed"); a total its area can't read says unknown — "…; the total can't be read just now" — never 0.
With none chosen, the collection's figures by difficulty and how long code is kept show: "Each entry is kept for good. Its code is kept for 90 days, or while it is among your most recent 80 in Challenges, 80 in Tracks, 30 in Daily Challenges and 40 in Debug Detective, whichever keeps more."
Counts are saved accepted entries — the total equals the four category counts; entries whose code expired still count.
Empty collection, no search matches and failed loading are three different states; temporarily unavailable data is never replaced with zero.
Newest entries first, with search and a difficulty filter kept on this device until sign-out.
TC-SOL-002Entry view: file tab, language tabs, line numbers, Wrap, Copy — own highlighterP1
Steps
Solve a challenge in two languages; open its Challenges entry.
Switch the language tabs; use Wrap and Copy; check line numbers.
Try to type in the code.
Expected
The accepted code stands under its file's tab — the language's mark before the name it ran as (main.py, Main.java) — with line numbers, Wrap (kept on this device) and Copy.
Where the item was accepted in more than one language, each language has a tab (oldest first); choosing one opens that entry — an entry in one language shows its own tab alone; an entry whose code aged out still shows its other languages' tabs.
The view is the product's own highlighter — read-only (selection and Copy work, typing goes nowhere); it never loads the code editor, and no Run/Submit/editing controls exist.
The entry shows language, title, solve date, captured difficulty and only measurements actually recorded — test cases passed and runtime where kept; missing measurements are omitted or explained, never zeroed.
With an entry open, the kind's list sits beside it where there's room (a way back where not); visiting an entry never fails because recording the visit failed.
TC-SOL-003Origin facts: Debug mode, Daily date and on-time/catch-up, Tracks' track nameP1
Steps
Open a Debug entry, a Daily entry and a Tracks entry.
Read each one's occasion line.
Expected
A Debug entry says "In a timed window" or "In practice"; an older one without it says "Timed or practice wasn't recorded for this older entry" — never guessed.
A Daily entry says "The Daily of <date>, solved on its day" or "…, solved later as catch-up"; an older one without it says the date wasn't recorded — never guessed.
A Tracks entry names its track as it was called when the code was accepted — kept even after the track is archived.
Each entry keeps its originating area, challenge identity, captured difficulty and solve date — a later statement/editorial change is presented as current content beside older code, never as the historical original.
TC-SOL-004Editorials beside your code — unlock rule, language match, live-test closingP1
Steps
Open an entry whose challenge has an editorial; press Compare.
Open an entry for a challenge with no editorial in your language.
Start a live Mock/Company test, then try the compare view (coordinate or mark N/A).
Expected
Compare puts your code beside the current editorial — same page, side by side where wide enough — in the entry's language, or another language named as another ("in Java" labelled clearly); it stays offered even when your code has aged out, since the editorial is still reachable.
The editorial is authored learner-facing content — never the private reference solution and never another learner's code; missing language coverage is stated, missing explanation is never filled from a secret answer.
Where the owning challenge can no longer be opened (unpublished/archived/deleted), the entry says so and offers neither "Practise it again" nor Compare — no broken link, no promise it will return.
An unlocked explanation never relocks when source expires or WizBit is unavailable.
While a live recorded test is in progress, the compare surface closes (the test's assistance restriction) — it reopens after.
TC-SOL-005Code expiry vs fetch failure vs privacy — three different truthsP2
Steps
Open an entry whose code has aged out (find one, or simulate by ageing on an account with old solves).
Throttle the network so a source fetch fails on an entry that should have code.
Try opening another learner's entry id directly.
Expected
Expired source keeps title, solve date, language, captured facts and the counted entry — saying source is no longer retained — with no empty editor, error styling, Retry, Restore or recovery promise.
A failed fetch where code should exist is a genuine temporary error with retry — never presented as expiry.
Another person's entry is indistinguishable from a missing one — plain not-found, no hint it exists.
Re-solving never resurrects expired accepted code or silently replaces the original source.
There is no public collection, no sharing, no export of learner code and no staff view — the area holds learners' work alone.
TC-SOL-006Pipeline — acceptances across areas file separate entries; milestones celebrate onceP1
Steps
Solve a standalone challenge, a track challenge, a Daily and a Debug case.
Open each kind's page and each entry from its area's handoff.
Cross a saved-solutions milestone (5/10/25/50/100/250) if near one.
Re-solve one item in the same language; check the entry.
Expected
Four separate entries under their four kinds — independent origins even for identical exercises.
Each post-acceptance "Open it in My Solutions" opens the exact new entry.
A milestone (5, 10, 25, 50, 100, 250 saved solutions) is celebrated at most once — a small review moment, no XP/achievement/notification; replayed saves or source expiry never replay it; a missing/unreadable total triggers no invented celebration.
A repeat acceptance in the same language does not overwrite the first accepted source or file a second entry; its newer source may live in the item's Tries while retained.
An acceptance whose required source capture failed reports the failure honestly — no falsely recorded "solved with no saved solution".
Ten small helpers that run entirely in the browser — nothing typed ever leaves the device: no backend, no history, no XP, no skill evidence, invisible to staff figures. Work saves locally under the signed-in account and clears at sign-out. The one thing a tool reports is that it's being used (minutes toward your own active time — the tool's name and the minute, nothing typed).
Route
Tool
Route
Tool
/tools
Catalogue (all ten, grouped)
/tools/cron
Cron Explainer
/tools/resume
Résumé Builder
/tools/complexity
Complexity Estimator
/tools/algorithms
Algorithm Animator
/tools/git
Git Sandbox (pretend repo)
/tools/regex
Regex Tester
/tools/schema
Schema Sketch
/tools/compare
Text Compare
/tools/code-image
Code Image
/tools/sample-data
Sample Data
What must work everywhere: "Saved locally" honesty; bounded inputs with the limit said where reached; keyboard-operable; mobile layouts; no network traffic for the work itself; honest estimates; a corrupt saved value starts afresh with a toast, never silently overwritten.
Tools — the catalogue and shared rules
TC-TOL-001Catalogue lists all ten tools and each opens at its own addressP1
Steps
Open /tools.
Open each of the ten tools.
Expected
Every tool listed with its name and one line on what it's for, in five groups side by side on a wide screen (two across, three on the widest); each opens under /tools/….
Résumé Builder · Algorithm Animator · Regex Tester · Text Compare · Cron Explainer · Complexity Estimator · Git Sandbox · Schema Sketch · Code Image · Sample Data — all present; a not-yet-built tool would show Coming soon inside the shell.
Tools sits in the Build space of navigation with one Tools link.
TC-TOL-002Nothing leaves the browser; saved locally; clears at sign-outP1
Steps
Open dev tools → Network; use several tools (type a résumé, a regex, a schema).
Reload a tool mid-work; check "Saved locally".
Sign out on the main site and back in; reopen the tools.
Open the same tool in two tabs; edit in one, watch the other.
Expected
No request carries the work itself — typed content never leaves the device (only active-time minutes, naming the tool, are ever sent).
Work returns on reload under the signed-in account, saying Saved locally; sign-out or another account's sign-in clears it.
A tool whose work is worth keeping (résumé, schema) also offers its own file to download and open again.
Two tabs of the same tool keep one copy: a tab with no change of its own waiting takes what the other saved — neither writes an older copy over the other's work; a tab still opening takes the other's save and says Saved locally of it.
Storage that can't be written says so plainly and the work stays while the page is open; a corrupt saved value starts afresh with a toast — never silently overwritten.
No XP, no history list, no skill evidence, no streak, no notification is created by any tool.
TC-TOL-003Bounded, mobile, accessible — the shared tool rulesP2
Steps
Push a stated limit in any tool (e.g. 1,001 rows in Sample Data, 81 lines in Code Image).
Walk one tool entirely by keyboard.
Open tools at 390 px and 768 px.
Enable reduced motion.
Expected
Every input has a stated limit and reaching it is said where it happens — nothing is cut short without a word; work that could run long is capped with the cap said, never a frozen page.
On a small screen controls stack above the result; every control works from the keyboard; colour is never the only signal; animations follow reduced motion.
Tools use the shell's themes; a printed/exported result (résumé) uses its own plain print style.
Estimates are labelled estimates with what was looked at — nothing is presented as a measure of the learner.
TC-TOL-004Résumé Builder: sections, templates, live preview, PDF with real textP1
Steps
Open /tools/resume; Fill with an example (confirm).
Edit entries, hide/rename/move sections; move and remove an entry (undo from the toast).
Switch templates (Classic / Modern / Two-column), accent, text size, A4/Letter, margins.
Read the advice; Save as PDF via the browser print; Download the file and Open a file back; Copy as text.
Expected
Sections: contact (name, headline, email, phone, location, up to four links), summary, education, experience/internships, projects, skill groups, certifications, achievements/positions, languages, one custom — each hideable, renamable, movable; each entry movable; removing a section/entry is undone from the toast that says so, restored in place.
Descriptions are points per line, shown as bullets; the live page-by-page preview says how many pages it runs to.
Save as PDF prints the résumé alone through the browser — real selectable text, not a picture; the page tells you to choose "Save as PDF" in the print window.
Advice beside the form — never a score: contact present, each experience/project has points, action-word starts, numbers in points, first-person words, dates running backwards, summary length, fits on one page.
Download saves the résumé as a file named after you (JSON); Open a file loads one back and refuses a non-résumé or too-large file; Copy as text copies plain text for a job form; Fill with an example and Start again each ask first.
TC-TOL-005Algorithm Animator: step through sorts/searches/graphs with counts and predict modeP1
Steps
Open /tools/algorithms; run Bubble sort on random values.
Step forward and back; change speed; use Space / arrows / Home.
Turn on predict; run and answer the swap questions.
Run Binary search (it asks for the value to find) and BFS/DFS on the graph; try data over the bounds.
Expected
Algorithms: six sorts (bubble, selection, insertion, merge, quick, heap), two searches (linear, binary), BFS and DFS on a small graph (seven nodes A–G, connected, neighbours in letter order; new random graph on request, chosen start).
Data: random, sorted, reversed, nearly sorted, few distinct; 5–20 values 1–99, or your own list within bounds — outside is refused with the bounds said.
Every step shows the values as bars (or the graph), what's compared/swapped/written, the pseudocode with the current line highlighted, the variables, the step in a sentence, and running counts of comparisons and writes (a swap counts as two writes).
Predict mode stops before each comparison and asks what happens — the answer shows and right predictions are counted for that run.
Each algorithm's best/average/worst time, extra space and stability sit beside the animation; at most 2,000 steps — a bigger run says so and suggests fewer values; keyboard controls work unless the focused control owns them.
TC-TOL-006Regex Tester: live matches, groups, plain-words errors, replace, boundedP1
Steps
Open /tools/regex; pattern \b\w+@\w+\.\w+\b on text with emails — watch matches highlight as you type.
Toggle flags (g, i, m, s, u); read the part-by-part explanation; try a replacement.
Type a broken pattern; load a common pattern; try a catastrophic pattern like (a+)+$ on a long non-matching string.
Expected
Every match highlights live with its groups listed and each match's start as a character number from 1; the pattern is explained part by part in plain words; common patterns load to learn from.
A non-compiling pattern says why in plain words — not the browser's own error.
Matching runs in its own worker and stops after one second — a runaway pattern stops with a message, never freezing the page; a worker that can't load says so rather than blaming the pattern.
Replace computes after matches show, on its own budget; a too-long result is cut with that said; a too-long replace stops without losing the matches.
Bounds stated: text up to 50,000 characters; matches listed 100 at a time up to 1,000; a match/group over 200 characters is listed by start with its full length; the listing stops with that said once 200,000 characters are listed.
The page says patterns are JavaScript's — other languages follow closely but not everywhere.
TC-TOL-007Text Compare: real diffs, whitespace honesty, folds and boundsP1
Steps
Open /tools/compare; paste program output on one side, expected on the other, differing in a trailing space and a missing final newline.
Toggle ignore-whitespace and ignore-case; switch side-by-side/one-column.
Compare texts with a long unchanged run.
Expected
Lines added, removed and changed are marked, with the differing characters inside a changed line; whitespace differences (trailing space, tab, missing final break) are shown — and ignorable on request, as is letter case.
Each changed/removed/added line and each differing character run is named for screen readers as well as marked.
Unchanged runs longer than eight lines fold and open on request.
Bounds: 2,000 lines a side and 1,000 differences (past that it asks for a smaller part); lines over 500 characters compare whole; past 200 changed lines, character-marks apply to the first 200 only — the page says so.
The comparison follows typing once it pauses, worked in its own worker — the page never waits on it.
TC-TOL-008Cron Explainer: plain words, next ten runs in IST, builder, odd cases honestP1
Steps
Open /tools/cron; read */15 9-17 * * 1-5 in words and its next runs.
Try @daily, @hourly; try 0 0 30 2 * (30 Feb) and a non-five-field entry.
Build a schedule by choosing fields.
Expected
A standard five-field schedule reads in plain words with its next ten runs in IST — the page names IST — looked five years ahead and recomputed each minute while the page is in view.
Shortcuts @hourly @daily @weekly @monthly @yearly read too; anything else says what it cannot read.
Day-of-month and day-of-week together mean "either" as cron does — unless one starts with a star (e.g. every second day), when a day must fit both; 7 is Sunday too (1-7 = Mon–Sun).
The builder's tick columns fit the room it has — no name runs under the next tick at any width or theme.
Open /tools/complexity; paste a nested-loop Python function; read the estimate and the marked lines.
Try a recursive function; a function with a sort/in call; an empty box; prose with no function.
Read the growth-rate table at a chosen size.
Expected
An estimate of time complexity from loops, nesting and visible recursion — always labelled an estimate — with the deciding lines marked; languages: Python, JavaScript, Java, C, C++.
What it can't judge it says so (a library call it can't read, a bound it can't see); common library calls that go through every item count as a loop; in on a Python collection reads as constant and marked unsure, as is any other call without a known cost.
An empty box or text with no function/loop says to paste a function — it does not give a rate.
Bounds: 20,000 characters / 400 lines; the growth table covers sizes 10 to 1,000,000 on a log scale stopping past 10²⁰, with a time at a hundred million simple steps a second — beside the steps on a computer, under them on a phone; six examples load.
Open /tools/git; run status, add, commit, branch, switch, merge, log — watch the commit graph.
Create a conflict (same file on two branches) and resolve it; check git status mid-conflict.
Pick a guided exercise; reach its goal; Start again.
Push a bound (13th branch, 121st commit, 201-char message).
Expected
A pretend repository — nothing touches a real one; the commit graph changes with each command; it knows commit, branch, switch, merge, rebase, reset, log, status, add, commit -am, checkout, tag, revert, merge --abort, reset --soft/--mixed/--hard, ls, touch, rm, edit and help.
Files hold no text — edit <file> makes a new version, so history is what is practised; two branches changing one file conflict, settled by editing it, adding it and committing; during a conflict git status lists each conflicted file once under "Unmerged paths" as "both modified" — never "clean".
Seven guided exercises (first commit → taking one back) each set a start and a goal the sandbox confirms reached; Start again resets; choosing another exercise or free play asks first once the sandbox has changed.
Bounds, each refused with the limit said: 12 branches, 120 commits, 24 tags, 20 files, 200-character messages — so a saved sandbox always opens again; the sandbox and terminal (last 300 lines) save locally.
TC-TOL-011Schema Sketch: tables, columns, relationships, SQL for three dialects, file round-tripP1
Steps
Open /tools/schema; load an example (shop/college/blog).
Add a table with columns (name, type, primary key, not null, unique); draw a relationship by choosing the column a column refers to; move tables.
Switch SQL dialect (PostgreSQL / MySQL / SQLite); copy or download the SQL; Download the sketch file and Open it again; remove a column and undo from the toast.
Expected
Relationships draw forked at the many end and barred at the one end, listed in words; only a column that picks out one row (unique, or its table's only primary key) can be referred to; a referring column takes its type.
The SQL writes alongside in the chosen dialect (ten column types, each named as that database names it): tables created after the ones they refer to, circular references added afterwards with ALTER TABLE (SQLite needs none and is asked to check references); SQL is held back with the reason while anything in the sketch wouldn't run there.
A table moves by dragging its header or arrow keys from its Move button; removing a column is undone from a toast; bounds: 20 tables × 30 columns.
The sketch file is JSON — downloads and re-opens; three examples load.
TC-TOL-012Code Image: styled snippet to PNG — own colours, honest limitsP1
Steps
Open /tools/code-image; paste a Python snippet; pick a language, colour set (Night/Ink/Paper/Sand), background (incl. clear), padding (16/32/64), text size, window frame, line numbers, title.
Download the PNG; Copy the image.
Paste over 80 lines.
Expected
Eleven languages (Python, JavaScript, TypeScript, Java, C, C++, C#, Go, Rust, SQL, plain text) coloured by kind of word — the preview is the picture itself, drawn at twice its size so the saved image stays sharp.
The picture keeps its own colours whatever the shell's theme (like a printed résumé); the title shows in the window frame — it goes when the frame does; a line over 100 characters carries on below.
The file is a PNG named after the title; a browser that can't copy a picture says so.
Bounds: up to 80 lines of 5,000 characters — over 80 lines there is no picture, and Copy and Download stay off until shortened.
TC-TOL-013Sample Data: made-up rows in JSON/CSV/SQL — bounded, reproducible, honestP1
Steps
Open /tools/sample-data; load an example (students/orders/employees).
Build fields (name, email, date in range, number in range, one of a list, UUID); generate 500 rows as CSV, then SQL inserts for each dialect.
Note the seed; regenerate with the same seed; try 1,001 rows and a 21st field.
Expected
Sixteen field kinds — row number, first/last/full name, email, city, company, job title, whole/decimal numbers in a range, yes/no, date in a range, one of a list, a word, a sentence, UUID — up to 20 fields and 1,000 rows, said where reached.
The values are made up in the browser and say so; a seed reproduces the same rows; each field draws from its own sequence so changing one leaves others as they were.
Names and email in a row belong to one made-up person; emails use example.com (a domain kept for examples); there are no phone numbers — a made-up one could be somebody's real number.
Any field but the row number can leave ~1 in 10 values empty; removing a field is undone from a toast.
Output as JSON, CSV or SQL inserts for PostgreSQL/MySQL/SQLite — starting with CREATE TABLE unless switched off, 100 rows a statement.
Cross-cutting checks — every page in this document
Run these sweeps once per area while you are in it. Any failure is a bug on that page.
TC-X-001Absence of Credits and generated-help UI across all practice surfacesP1
Steps
Walk every page in this doc (challenge, track challenge, Daily, Debug case, Code Lab, Solutions, lessons, typing, tools).
Search each page's text for "Credit", "Analyse", "Explain this error", "generated".
Expected
No Credit balance, price, or spend prompt anywhere; no "Analyse the selected code", "Analyse my code", "Explain this error" or paid reveal controls — absent entirely, not disabled.
Single designed exception: a lesson page's right card may show "Ask WizBit about this lesson" marked Coming soon.
Hints and editorials are free authored content — nothing suggests paying or waiting to unlock them.
TC-X-002Honesty invariants on every list, figure and saveP1
Steps
Throttle the network (Slow 3G / offline) on each page type: catalogue, workbench, results, archive.
Read every count, percentage and save label it shows.
Expected
Unavailable ≠ empty: a catalogue that can't load says so (with Retry); a figure that can't be read says unknown/"Not enough data yet" — never 0 or a silently absent list.
Save states are literal: saving · saved · not saved, tap to retry · saved locally — device-only saving is always labelled as such, never implied as a cloud promise.
Pending is named: "being graded", "Waiting", "Submitted on time, being graded", "could not be checked" — never converted into a provisional pass/fail.
Platform failures name the platform ("the cloud", "the grading service", "could not be checked") — never dressed as your wrong answer, your limit reached, or your fault.
Interface text is for people: no "Labs", no internal state names, no spec sentences; numbers use Indian grouping and times label IST.
TC-X-003Hidden material stays hidden everywhere — dev-tools checkP1
Steps
On a challenge, Daily and Debug case, open dev tools → Network and inspect the API responses the page received.
Submit a failing solution; inspect what hidden-case rows contain.
Look for reference solutions, expected outputs, hidden datasets and unrevealed hints anywhere in page data.
Expected
Hidden test cases arrive as opaque rows — pass/fail only; no input, expected output, your output against them, time or memory is ever sent to the page.
Private reference solutions, answer keys, staff notes and unrevealed hint text are absent from every response — not merely hidden visually.
A compiler/runtime diagnostic never discloses protected material through an error string.
Another learner's submissions, drafts or solutions are unreachable — a guessed identifier reads as nonexistent.
TC-X-004Shared editor behaviour is identical across solving surfacesP2
Steps
On a challenge, a track challenge, a Daily and a Debug case, check the same set: shortcuts, Reset at the head, editor foot, output area, dividers, text size/wrap.
Drag the divider between code and output; reload.
Paste a NUL character into code (e.g. via console) and Run.
Expected
Same test editor everywhere: item/Hints/Editorial-or-Debrief/Tries tabs, language file tabs, Reset at the head, foot saying how the code is kept + language version + text size + wrapping + cursor place, Result and Your input under the code, run bar worn by the dock where the theme says.
The code/output divider is keyboard-operable and remembered per window width; code never squeezes below six lines — the output folds to its heading when the column can't hold both, opening at its least on Run/Submit/Escape.
A page opened while a submission is still being graded (a reload among them) opens its output as a Submit does — showing grading, then the verdict.
LF line endings whatever the OS; a NUL character in code is refused before anything runs — "That request could not be understood, so nothing was run."; a printed NUL shows as ␀ in output.
Expand collapses output to its heading without losing state; Escape restores.
Open the same challenge in two tabs; submit in both.
Replay a network request (dev tools) for a finish/submit call.
Expected
Every action records once: one submission, one window, one start, one completion — no duplicate rows, XP, solutions or streak days.
Two tabs can't create two of anything; a replayed identical request answers as it did without saving twice.
Another tab of yours, on a settling submission, refreshes what it can show (item, tries, area pages, header XP) without claiming a result it hasn't seen.
TC-X-006Not-found is privacy-safe and named per areaP2
Steps
Open made-up addresses: /challenges/does-not-exist, /tracks/0, /daily-challenges/1900-01-01, /debug-detective/nothing-here, /solutions/entry/000, /courses/no-such-subject, /lessons/99999.
Open a hidden/archived item's address.
Expected
Each problem page with nothing at its address is headed by its own words — "We could not find that challenge — it may have been moved or taken down. Your earlier work on it is kept." — named in the browser tab too, with its way back.
Missing, hidden, unpublished and another person's private objects all give the same plain not-found — no hint which it was.
No stack trace, no raw error, no redirect to home without explanation.
TC-X-007Vocabulary and surface honesty across this doc's pagesP3
Steps
Read labels on a sample of pages: standings, buttons, notices.
Check a phone-width pass on each catalogue and board.
Expected
Words are the product's: standing reads Not started · Tried · Solved (Fixed on Debug); "test" never "attempt"; "example" never "sample"; "editorial" for worked explanations; "Solve rate"/"Fix rate"; "saved locally" for device drafts; "Tries" for submission history.
Computer-only surfaces behave so: challenges/tracks/daily/debug workbenches and typing rounds are not offered on touch devices (quiz lessons are the one exception — they work on phones); a narrow desktop window is still a computer.
Every reachable page loads its content in ~3 s on an ordinary connection; in-page reads ~1 s; longer states are named honestly rather than hanging.
Lists page with Load more without jumping your place; no skeleton that resolves to a different truth.
Wizly Learning Testing Handbook · doc 01 of 7 · generated from the product specification (docs/) and source of Sprinkle-Jelly-V1 · November 2026 · test-case prefixes in this doc: CRS · CHL · TRK · DLY · DBG · CLB · TYP · SOL · TOL · X