Skip to content

Design prompt: the ExamHall candidate app

Four guarantees: the paper is sealed and local before 09:00, no answer is lost or overwritten, outages are survivable, and every locale saves one value.

Predict first

Before you read: predict

ECON-201 opens at 09:00:00 for 2,400 candidates, and its paper is 1.8 MB. In rehearsals every candidate pressed Start within 4 s of it appearing. The team wants three things: at most 100 MB of paper sent in any one second between 09:00:00 and 09:01:00; every candidate reading question 1 by 09:00:10; and no candidate able to read the paper before 09:00:00.

Which plan meets all three?

Pick one

The 30-second version

Four end-to-end guarantees shape the candidate app. Move the paper's bytes before 09:00 as an encrypted copy, so the opening second carries only a small key, released by the server's clock. Save every edit locally first: one row per question, with a rising revision the server keeps only if higher. Judge offline by failed saves. Normalize typed numbers per locale.

Four guarantees: the paper is sealed and local before 09:00, no answer is lost or overwritten, outages are survivable, and every locale saves one value.

How it works

Step 1 of 14

Herd on the calendar. At 09:00:00 every browser acts in the same second, because one server instant opens the exam for all of them.
In the kitchen
  • a store selling downloads only at launch: every full download in one minute → fetching the paper at Start: the herd (step 1)

Analogy: A video game pre-loaded before its launch

Players download a large game days early, still encrypted; at the release hour, kept on the store's servers, each launcher fetches a small key.

At a game launch In the candidate app
the encrypted files downloaded in the days before the sealed paper downloaded during check-in (steps 2–3)
each player's download starting when that player chooses each client's own moment, never 09:00 itself (step 2)
the small key fetched at the release hour the one request the opening second carries (step 3)
moving the PC's clock forward unlocks nothing the server's clock opens the paper (step 4)
a store selling downloads only at launch: every full download in one minute fetching the paper at Start: the herd (step 1)

In real terms: the opening instant moves a few bytes to every client; the megabytes moved earlier, at moments each client chose.

Breaks down when: a player who waits loses nothing, while a candidate whose paper arrives late loses exam minutes. A game launch also has no answers to keep, so steps 5–12 have no counterpart in it.

Contrasting case: a concert's ticket sale at 10:00. What is sold cannot be delivered in advance, so the herd stays at the opening and needs a waiting room (sc-exam-start-spike).

Examples, run for real

4.1 ExamHall EXH-2030 → MR !2330: two drafts received out of order

After a reload, a candidate's Q9 showed an older draft. Its autosaves of revision 1 and revision 2 were in flight together on separate connections, and the server received revision 2 first. The server stored whichever save arrived last. MR !2330 is step 7's fix.

EXH-2030 last arrival wins · received rev 2, then rev 1 · Q9 stores rev 1

Arrival order is not edit order, so a server that keeps the last arrival can keep the older draft (step 7).

4.2 Proof domain, e-commerce checkout: a flash sale's prices, sealed before noon

A shop sends its 50 sale prices to every open checkout page at 11:52, encrypted. At 12:00 on the shop's server clock, each page fetches the 32-byte key.

checkout 11:52 · browser holds 1451 bytes of ciphertext · read without the key: Unsupported state or unable to authenticate data
checkout 12:00 · key fetched: 32 bytes · read with the key: 50 prices

Before the key arrives, the browser holds bytes it cannot read: GCM refuses a read with the wrong key. The noon second moves 32 bytes per page (steps 2–4).

4.3 The board for "Design the candidate-facing exam page" (worked, not executed)

Risk On the board Mechanism owner
the 09:00 herd the opening second carries no paper bytes (steps 1–4) this lesson; the anchored clock: fsd-clock-sync-timers
a lost or overwritten answer every edit survives a reload and a late arrival (steps 5–8) this lesson; the outbox and replay: fsd-client-retry-resilience
minutes offline answering continues, and queued saves still arrive (steps 9–12) this lesson
locale one stored value per typed answer (steps 13–14) this lesson; catalogs and plurals: fsd-i18n-architecture

Try it

Answer first, then check. Nothing is saved.

Question 1 of 5

Q7's autosave sends PUT /answers/q7 with the draft's text, and the server queues each save as a job that writes the text it carries. A job that hits a database timeout is retried 30 s later. The page loaded Q7 at draft 2; the candidate then saves drafts 3, 4 and 5 at 88:10, 88:20 and 88:30. In run 1 the job for draft 3 hits a timeout; in run 2 the job for draft 5 does. Today, run 1 ends with draft 3 stored.

Which change makes Q7 store draft 5 in both runs?

Pick one

Question 2 of 5

A candidate's answers must keep reaching the server through Wi-Fi or building outages of a few minutes. Four rules for the candidate app's offline handling are on the design board.

Which rule should the design keep?

Pick one

Question 3 of 5

Q12 asks for a price elasticity to one decimal place, and its key is 3.5. Three candidates type ٣٫٥ on /ar-EG/exam, 3,5 on /fr/exam and 3.5 on /en/exam. Today the answer box saves parseFloat(input.value), and the grader compares the saved number with the key.

Which change saves 3.5 for all three?

Pick one

Question 4 of 5

Every client keeps its outbox like this:

During a 90-second loss of the hall's internet link, the edits on each of the 2,400 clients were, in order, q3, q3, q7, q3, q7, q12, q7, q3, q12, q12, q3, q7, and the save of q3's first draft was in flight when the link failed. When the link returns, every client runs flush().

How many save requests do the flushes send in all?

Code for this question
const outbox = await openStore('outbox', { keyPath: 'q' });async function onEdit(q, text) { await outbox.put({ q, rev: ++revs[q], text }); trySend(q); }async function flush() {  for (const row of await outbox.getAll()) if ((await send(row)).ok) await outbox.delete(row.q);}
Pick one

Question 5 of 5

ECON-201 ends at 90:00 of attempt time, and the server stores a save received up to 60 s after the deadline. In a rehearsal, the hall's internet link is down from 88:30 to 90:40, and the candidate writes five drafts across Q37, Q39 and Q40 during it. Every edit typed in AnswerEditor is first written to an IndexedDB outbox row, and flush() sends each row; an accepted save deletes it. The app:

clock is the server-anchored clock, and every() returns a function that stops the repeat. The team must choose where clock.every(5000, flush) runs.

Which home gets the latest draft of all three questions stored by 95:00, both in a run with no reload and in a run where the candidate reloads the page at 90:20?

Code for this question
function App() {  const [route, setRoute] = useState('exam');  useEffect(() => clock.every(1000, (now) => {    if (deadline - now <= 0) setRoute('time-up');  }), []);  return route === 'exam' ? <AnswerEditor /> : <TimeUp />;}
Pick one

Go deeper

Pro tip
  1. In the first minutes of the prompt, name the two riskiest parts, the 09:00 herd and never losing an answer, and say you will open them before any component tree. When: a 45-minute frontend round on this product (the deep-dive choice itself is fsd-radio-framework's). Status: SELF (the curriculum row's own tip); not run.
Source

Checked against the tools and docs as of 2026-10-01.