Case study

Masār — case study

A practice-first learning platform, built in six weeks alongside a job search, to answer a question a prospective client actually asked: what would you deliver, and how would I know it was any good?

01The problem

A course is not a pile of PDFs with a quiz at the end. The failure mode is specific: content gets published at whatever depth it happened to be written at, assessment is assembled from whatever questions exist, and nobody can say which objective any of it serves.

It looks like a course and teaches like a document.

Three ideas were worth building to answer that. Depth is a property of a lesson rather than a separate lesson. Assessment is assembled from a blueprint rather than a pile. And the content pipeline that produces the lessons ships in the same repository as the platform, with the gates that constrain it.

02One paragraph, three depths

This is the whole design argument in one example. The same source material, published at three depths, with the decision behind each one.

The source paragraph

“A claim that arrives complete and correct on the first attempt is called a clean claim. Claims that are not clean have to be corrected and resubmitted, which delays payment. The most common causes are data errors rather than clinical ones — a date of birth that does not match the member card, a service date outside the coverage period, a missing rendering provider.”

L1 — Structured publishing

Clean claim — a claim that passes the payer’s edits on the first submission, with no correction and no request for further information.

Plus a table contrasting self-pay and insured encounters: who is billed, when money arrives, what can go wrong, what document is produced.

Decision: Split into a definition card and a comparison table rather than left as prose. The definition is the thing a learner will come back for, so it gets a stable place on the page instead of being buried mid-paragraph. Nothing is added that the source did not carry — L1 is a publishing decision, not an authoring one.

L2 — Interactive lesson

Worked example. A claim reaches the payer for 1,260. The date of birth reads 11 March 1988; the member card reads 14 March 1988. Three steps, each showing the action and the reason: compare against the source document, classify the error, correct before submission rather than after rejection.

Scenario. The rendering provider is missing and today is the deadline. Three options, each with its real consequence — including the one that looks efficient and creates a documentation failure.

Decision: The learner is asked to do something with the idea before being told whether they are right. The worked example uses the mismatch from the source paragraph but makes the reasoning visible step by step, because "what to do" without "why" is a solution rather than a worked example. The scenario adds consequences: every option returns its outcome, not just the wrong ones, because the point is that choices have consequences rather than that there is a hidden right answer to guess.

L3 — Applied practice

Claim review. Nineteen flaggable fields, six seeded errors, an evidence panel holding the clinical record and the member card. Scored on F1: flagging four fields correctly scores 80% and passes; flagging all nineteen scores 48% and fails.

Decision: The learner produces work that is scored the way a professional would judge it. Six errors are seeded, one per class, and the scoring is published rather than hidden — because a score a learner cannot interrogate teaches nothing. Every miss links back to the exact block that taught it. Without that link this is a quiz with a nicer interface, and the link is the pedagogical argument of the entire project.

03Decisions I would defend

  1. Lesson content is validated JSON on one row, not a relational block store. A block table plus an editor over it roughly doubles the build for no visible benefit. What it cost: no drag-and-drop authoring UI, so content is edited as files by someone comfortable with that.
  2. Select-then-place is the only interaction, not a fallback beside drag and drop. One code path, keyboard-native, and better on a phone — where dragging between columns is the worst possible affordance. What it cost: it looks less impressive in a screenshot than a drag interaction does.
  3. The seeded errors never reach the browser before submission. The same rule that strips answer keys from an in-progress attempt. What it cost: a round trip on submission, and scoring that cannot be done offline.
  4. Authorization reads the database row, not the session token. A JWT outlives the account it describes. What it cost: a database query on every authorized request, which is the correct price.
  5. The gates were built before the generation. A generator built first and gated afterwards is gated to whatever it already produces. What it cost: the pipeline has gates that provably refuse things and has not yet been run end to end — a weaker headline than the reverse order would have produced, and an honest one.

04What failed

18 so far. The first five form a pattern worth naming: the falsifiable claims are the ones that break, and they only break when you try to game them. Every one of those passed code review, passed its schema, passed CI, and looked right on the screen. The last four each break the pattern in a different direction.

  1. The scoring formula failed its own published claim. The case study said shotgun-flagging scores worse than reading carefully. Written as a test, it did not: flagging all nineteen fields scored 79% and passed, against 77% for four careful fields. The formula only supported the claim on a form with more than 27 fields. Padding the form would have made the number come out right; switching to F1 made the claim true at any size.
  2. The item bank was trivially gameable and nothing flagged it. Answering the first option every time scored 89% and passed. The bank was authored with the correct answer first in eleven of fourteen items. The schema validated it, the content gate passed it, every option had proper feedback — and a reviewer trying “always answer A” would have dismantled the entire assessment story in five minutes. Options are now shuffled per attempt; the same strategy scores 22%, 28%, 11%.
  3. A panel reported itself visible and rendered nothing. The evidence panel — without which two of the six seeded errors are guesswork — rendered empty on desktop. CSS cannot reveal the children of a closed <details>. getComputedStyle said display: block; only reading the text found it.
  4. A deleted account’s session still worked. After deleting an account, the same cookie returned 200 from the data-export endpoint. A JWT outlives the row it describes. The code comment claiming otherwise had been written without checking.
  5. A test file reported 16/16 while two tests never ran. Two cases were appended below the entry point, so the decorator registering them executed after the process had exited. The suite was green and measuring nothing — the most expensive kind of green, because it removes the incentive to look again.
  6. The code was correct and the product was wrong. Six weeks of work — the depth model, the course, this page, the pipeline page — was unreachable from the landing page. The only route in was the guest button. The site was also still wearing its own build schedule: “Under construction — Week 1” on the hero, “Week 1 — placeholder” in the footer. Every page worked, every page had tests, every test passed. No test asserts that a visitor can find a feature. Found by opening the deployed site as a stranger, which is a different discipline from testing.
  7. The tool was wrong and the product was right. The 390px mobile screenshot came out with the Arabic labels sheared off the right edge — exactly like an RTL layout overflow, on the one shot whose job is to prove the mobile pattern works. The layout was fine. Chrome’s headless screenshot mode lays RTL out wider than the window and clips the capture, and a clipped capture is pixel-for-pixel indistinguishable from a real overflow. Re-measuring in a browser settled it. The near-miss was “fixing” a page that had nothing wrong with it.
  8. A check written to keep a screenshot honest found the page lying. Two shots needed scripted interaction, so each step asserted what it had actually done — otherwise a selector matching nothing produces a real screenshot of an untouched page. One step checked the exam’s item count against the blueprint and stopped: the page had rendered sixteen questions while telling the learner there were nine, in both languages, in production. Nothing was broken and no test could have failed. The count now interpolates from the blueprint instead of restating it.
  9. A conditional that was never conditional. The dark palette was not an alternate — it was the only one. Tailwind 4 lifts @theme out of whatever it is nested in, so a dark block written inside a prefers-color-scheme media query was emitted unconditionally and the query gated nothing. Every visitor got the dark site regardless of their setting, and the light default had never rendered anywhere — not in a browser, not in a single one of six weeks of screenshots. It surfaced when a capture forced to light came back dark while the page itself reported prefers-color-scheme: light. A media query cannot be true and not apply, and that contradiction was the whole tell: when output disagrees with a condition, read the compiled artefact rather than the source.

Five of these were found by attacking the system. The sixth was found by arriving at it, the seventh by disbelieving an instrument, the eighth by a check that was not looking for defects at all, and the ninth by noticing that the page and the browser disagreed about what the browser had asked for.

05Disclosure

  • No practitioner reviewed this content. It was authored from public sources by an instructional designer. All code sets are fictional training codes, and a real deployment would use a deploying organisation’s own payer rules and licensed code sets, reviewed by someone who works in the field.
  • Self-initiated. No employer’s or client’s material was used, referenced or paraphrased, and no employer is named anywhere in the repository, its history, or this page.
  • No users, no revenue, no outcomes. Any figure shown in analytics comes from real use of this demonstration and is deliberately sparse. Item statistics need roughly twenty first attempts per item before they mean anything, and this has nowhere near that.
  • Payments are a mock adapter. No provider is activated, no money moves, and the price never renders without a test-mode banner.
  • Not a credential. Certificate of completion for a self-initiated training course. Not affiliated with, or recognized by, any certification body.
  • Total infrastructure cost: $0/month. Free tiers throughout, on an already-owned domain.

06Deliberately not built

A second simulation, module quizzes, a mastery engine, content CRUD editors, an instructor role, real payment adapters, SCORM export, and a mobile app. Each was scoped out in writing before the build started rather than dropped when time ran short, and each is recorded with the reason.