WAIWNK

Complete AI SDLC Quiz Nov 6, 2026, 14:16 UTC – 15:04 UTC
— share the final standings
— the board for a call or a projector

Score over time

Final Results

viktornovak-epam wins with 759 pts.

Linked sessions

6 sessions in this group
  1. 1
    GT622Y
    3 players
    Finished
  2. 2
    IO5H5U
    3 players
    Finished
  3. 3
    QRF3M6
    1 player
    Cancelled
  4. 4
    WAIWNK
    2 players
    This session
  5. 5
    GYVWFD
    2 players
    Finished
  6. 6
    L5OOOW
    3 players
    Finished

Final standings

Every session has finished and been judged
#PlayerSessionPoints
1V viktornovak-epam WAIWNK 759
2M Mathieu Cuvellier L5OOOW 662
3G glenncartercorilus GT622Y 650
4T thibault IO5H5U 577
5B Bohdana Pylypets GYVWFD 387
6N nicolas.gigot L5OOOW 340
7G Geo GT622Y 157
8B Bavo Van Craeyenest IO5H5U 123
9J Jonathan Baltus WAIWNK 102
10M Marco Guido GT622Y 84
11B benoit-wauquier GYVWFD 72
12J Jeroen Arens QRF3M6 24
13X Xavier L5OOOW 1
14I ikram IO5H5U 0

Arena Points

V
viktornovak-epam received +110 AP (10 participation + 30 performance + 45 placement + 25 project record) · finished 1st of 2 · rating 1683
J
Jonathan Baltus received +10 AP (10 participation) · finished 2nd of 2 · rating 1464

Badges earned

viktornovak-epam

Play-by-play

Commentary

  1. Wrap-up Final podium: viktornovak-epam takes gold with 759 points and all tasks done, and Jonathan Baltus takes silver with 102. Baltus's verdicts landed in the final two minutes, a 102-point surge that came too late to close a gap built over the full 40 minutes. Thanks to the room for a sharp, honest session.

  2. Quiet moment with 1m 45s on the clock. viktornovak-epam still sits on 757 with every task closed, and Jonathan Baltus is chasing his first point on "Build the quiz" with the final seconds running out. Nothing has moved, so the question is whether a late verdict can still change the story.

  3. Under five minutes on the clock and the scoreboard has gone silent. viktornovak-epam sits on 757 with every task closed, and Jonathan Baltus is still hunting his first point on "Build the quiz".

  4. Jonathan Baltus has pushed a commit labeled "ololo snapshot: final" with no line changes, and still no points on "Build the quiz" with 8 minutes 5 seconds left. viktornovak-epam holds 757 with every task done, so the board is set unless a late verdict lands.

  5. Nine minutes left and the board is frozen: viktornovak-epam holds 757 with every task done. Jonathan Baltus added probe #24 but is still on zero, so the clock is the only thing gaining ground on him.

  6. Jonathan Baltus keeps grinding on "Build the quiz", adding probe #23 and another artifact sync, but the board still reads zero with 10 minutes 55 seconds left. viktornovak-epam holds 757, and both players' code health sits level at B, 81.

  7. UX Review gave viktornovak-epam 18 more for the live workshop game, with the countdown, leaderboard and podium all checked in the stills, lifting them to 757. Jonathan Baltus is still scoreless with 12 minutes 55 seconds left, adding probe #22 and two artifact syncs on "Build the quiz".

  8. Still 679 for viktornovak-epam, who added a phone podium screenshot as another artifact delivery. Jonathan Baltus answered with a mobile card image but is still on zero, with 13 minutes 45 seconds left on the clock.

  9. Quiet stretch with 14 minutes 35 seconds on the clock. viktornovak-epam holds 679 after three more probes, #33 through #35, with no new lines of code. Jonathan Baltus has three probes of his own, #19 through #21, and still no points on the board.

  10. viktornovak-epam blows past 650 to 679 with six judge verdicts landing in under forty seconds, Correctness at 23 the biggest of them, and the live workshop game is now on the board. Jonathan Baltus is still scoreless on "Build the quiz" with 15 minutes left, and the gap is now more than 650 points.

  11. Viktornovak-epam sits on 571 with 16 minutes left, and their latest push is a "Run it live in a workshop" commit with probe #31 behind it. Code health is nearly level, B at 81 for them and B at 80 for Jonathan Baltus, but Jonathan still has no points on the board, and three probes are the only sign of movement on his side.

  12. viktornovak-epam climbs to 571 on a UX Review verdict of 21 for the study wiki, with the judge praising four clean stills and all ten cards sitting under their topic headings. Jonathan Baltus is still on zero with 17 minutes left, and the gap keeps stretching.

  13. Quiet stretch on the board: viktornovak-epam holds 550 and pushed three artifact syncs, including a new mobile card image. Baltus has nothing new to score, with 17 minutes and 55 seconds left.

  14. Jonathan Baltus has pushed probes #18 and #19 on "Build the quiz" plus an artifact sync, with no new lines of code, and still no points on the board. viktornovak-epam holds 550 with 18 minutes and 45 seconds left, and the gap stays wide open.

  15. viktornovak-epam holds 550 and just pushed a 409-line live workshop feature, adding a new live rooms module and its own test file. Jonathan Baltus is still on zero with 19 minutes left, and that gap is now the story.

  16. Architecture hands viktornovak-epam 10 more on the study wiki to reach 550, though the judge flags that the core still imports HttpError and node:crypto and takes a concrete store. Jonathan Baltus is still scoreless with 20 minutes left.

  17. viktornovak-epam blows the board open, jumping from 375 to 540 on the back of five straight scores on "Add the study wiki and review," with Correctness's 27 the biggest of them. Jonathan Baltus is still stuck on zero with 21 minutes left and no verdict yet.

  18. viktornovak-epam jumps to 375 with a UX Review verdict of 20 points on "Add cost practice", praised for a Cost practice report that is largely correct. Jonathan Baltus is still on zero with 22 minutes left and no verdict yet.

  19. Jonathan Baltus has pushed a 221-line change on "Build the quiz" with a new server/cost.js generated cost practice topic and its own test file, still without a scored verdict. viktornovak-epam holds 355 with nothing new, and 22 minutes remain for Baltus to turn that code into points.

  20. Probe 23 landed for viktornovak-epam on the study wiki, followed by two artifact syncs with no line changes, so the 355 holds. Jonathan Baltus is still waiting on his first scored point with 23 minutes on the clock.

  21. viktornovak-epam holds 355 with an artifact delivered for "Add cost practice" and a fresh report screenshot in the repo, while Jonathan Baltus is still stuck on 0 with 24 minutes left. Jonathan's last three probes landed without a verdict, so the clock is his enemy now.

  22. viktornovak-epam pushed a 389-line study wiki and a done flag, with probe 22 now on the record, and the board holds at 355. Jonathan Baltus is still without a scored point on "Build the quiz" with just under 26 minutes left.

  23. Quiet stretch on the board: viktornovak-epam holds 355 with the study wiki still in progress. Jonathan Baltus has pushed probes fourteen and fifteen on "Build the quiz" with no line changes, and no verdict has landed for him yet. About 26 minutes remain.

  24. viktornovak-epam is sitting on 355 with a new commit stack landing on "Add the study wiki and review": a 111-line cards.js and progress.js pair, with the study wiki's pinned concept cards linked to their bank questions. Jonathan Baltus is still on zero with 27 minutes left and no verdict yet.

  25. viktornovak-epam is up to 355 after a Data verdict worth 20 on "Add cost practice", and the judge's note is that the cost quiz keeps its answers on the server until an answer is locked. Jonathan Baltus is still on 0 with 28 minutes left, and the gap is now 355 points.

  26. Five verdicts on "Add cost practice" just pushed viktornovak-epam to 335, with Correctness topping out at 29 and Code Quality at 20. The judges want more evidence, though: no browser test of the cost flow, and the screencast is still missing. Jonathan Baltus is still at zero with 29 minutes left.

  27. viktornovak-epam pushed probe fifteen on "Add cost practice": a new costs module and a line-by-line price table, 216 lines in. The board still reads 179 with no new verdict, and Jonathan Baltus has only sent more artifact syncs, with about thirty minutes on the clock.

  28. Jonathan Baltus has pushed three artifact syncs, the newest adding a mobile screenshot of the quiz, but the board hasn't moved and viktornovak-epam still sits on 179. With 30 minutes left, Baltus needs a scored verdict to get back into the race.

  29. viktornovak-epam holds 179 after probe number fourteen on "Add cost practice" and two artifact syncs, though this push shows no line changes. Jonathan Baltus is still on zero with 31 minutes left, and his best finish so far is a second place.

  30. UX Review gave viktornovak-epam 18 more points, lifting the lead to 179. The judge praised the green-for-right, red-for-wrong quiz screens and the per-topic report. Jonathan Baltus is still on zero, with a core-done flag and probe #12 on the board.

  31. viktornovak-epam is running away with it: six judge verdicts landed on "Build the quiz" in under twenty seconds, taking the total to 161 and sending the board to 101 points up since the last call. Creativity, Data, Code Quality, Architecture, Test Quality and Correctness all scored, with Correctness topping out at 26 and Architecture docking the HTTP status codes leaking into the business rules.

  32. viktornovak-epam has broken the deadlock with 60 points, the first score on the board, and has switched to a new task, "Add cost practice." Jonathan Baltus is still on zero on "Build the quiz" with 34 minutes left to close the gap.

  33. Heavy push from viktornovak-epam: 1,134 lines in one commit, with probes #5 through #7 landing on "Build the quiz." His code health has climbed to B at 82, edging Jonathan Baltus's 79. Still 0-0 on points, with 35 minutes left.

  34. Jonathan Baltus has stacked three probe runs on the board, numbered four through six, and his code health already reads B at 79 against viktornovak-epam's C at 63. Nothing is scored yet, and with about 35 minutes left, the first real diff is what everyone is waiting for.

  35. viktornovak-epam has landed 187 lines in one push: a project brief, a package file, and a seed file with the pinned topics and ten starter questions. Jonathan Baltus is still at zero with no code diff yet, and 36 minutes remain.

  36. Still 0-0 with 37 minutes left. viktornovak-epam's first real push is a settings file with one permission rule, "cd . *", and no quiz code yet. Jonathan Baltus has three probe and start commits on the board but no diff.

  37. Jonathan Baltus is officially on the clock now, and the first thing on his record is a probe run and a session-start snapshot, with no code diff yet. Both players are still at 0 points with 38 minutes left, so the first real code is still to come.

  38. Jonathan Baltus has just walked in, and his record is a solid one: one session, one podium, a best finish of second, rating 1531, which is actually higher than the veteran's. viktornovak-epam has pushed three commits on "Build the quiz" and the probes are running, but nothing is scored yet.

  39. Five seconds in and viktornovak-epam is already on the clock with Claude, chasing "Build the quiz" with 39 minutes left. This one's a veteran: three sessions, three podiums, a best finish of first, and a 1448 rating. Nobody else has typed the join code yet, so the floor is his.

Activity

J
Jonathan Baltus evaluated by Correctness on Task 0 +15 points
product 4.5 The core quiz works: pinned wording and answers match the brief in the screenshots, answers are checked server-side, and the report shows the total, per-topic scores and every question. But the app adds a generated 'Cost practice' topic that the brief does not allow. Its questions are not from the bank, and they are merged into 'All topics' (app.js: `topic ? fromBank : [...fromBank, ...costQuestions()]`; AGENTS.md says 'All topics: 10 + 5'). That breaks the scenario 'all topics gives all ten questions' and the rule that the bank is the only source besides author additions. The completion note does not mention this topic. Per the scenario rule, this caps product at 5.0, and the undisclosed extra source pulls it lower. The screenshots show a polished UI, with clear right/wrong feedback, a keyboard-friendly flow, and a readable report with the answer and explanation for each question.
03:04 PM +48m 16s
J
Jonathan Baltus evaluated by UX Review on Task 0 +17 points
ux 8.0 The quiz screen has a clear hierarchy: a small 'Question 1 of 5 · Token economy' line and progress bar sit above a large question headline, then lettered options and a feedback panel. The report leads with a large '6 / 10' score, then a 'By topic' card, then per-question review cards. Right and wrong states are distinct: the correct option is green, the chosen wrong option is red, and the feedback reads 'Not quite.' with the explanation. Spacing and the purple accent read as deliberate. Minor deduction: the header nav is a little cramped on desktop and the report's review cards are dense. accessibility 7.0 Correct and wrong states are carried by text as well as colour ('✓ Right' / '✗ Wrong' badges, 'Not quite.' feedback, 'Your answer' / 'Right answer' labels), so colour is not the only signal. Text contrast in the screenshots is readable, and the muted grey on white is legible. The markup has lang="en" (index.html:2), an h1 per view, labelled radio inputs and option buttons with letter keys, role="progressbar", role="status"/alert on messages, and a visible focus outline. Deduction: the in-page nav links use small grey text on the header, and the screenshots do not show the author or wiki screens, so their accessibility could not be checked. mobile 7.0 At about 375px the quiz card, options, feedback and 'Next question' button all fit without horizontal scrolling, and the options stack and wrap cleanly. The report's review cards also reflow to a single column, and the 'Your answer' label/value grid stays legible. The media query at max-width 420px tightens the header (style.css). Deduction: the header wraps 'Agent Quiz' and 'Last report' onto two lines and the nav pills look cramped, which reads as unpolished at phone width.
03:03 PM +47m 42s
J
Jonathan Baltus evaluated by Architecture on Task 0 +13 points
architecture 5.5 The business rules that matter are mostly pure and testable alone, but the core is not separated from I/O and the HTTP edge carries some logic. What works: - `server/bank.js` `validate()` (lines ~9-30) is pure: no fs, no HTTP, no clock. `test/bank.test.js` exercises it with no server. - `server/cost.js` builds and checks the arithmetic from a seeded id (`build`, `checkCost`), with no stored state. Its rules are plain functions. - The browser never holds a key. `POST /api/answers` in `server/app.js` decides correctness, and `public/quiz.js` only renders the response. The dependency direction from UI to server is correct. - The tree names the domain: `bank`, `cost`, `wiki`, `quiz`, `report`, `author`, `seed`. What fails the rule: - `server/bank.js` line 1-3 imports `node:fs`, `node:path` and `node:crypto` (`randomUUID`) into the same module as the validation rules. The persistence adapter (`createBank(file)`, `save`, `load`) and the rules live in one closure with no port. Ids and storage are chosen by the core, not injected. - `server/cost.js` line 1 imports `randomInt` from `node:crypto` and calls it inside `costQuestions()`. Randomness is not injected, so the generator is not deterministic under test without patching. - `server/app.js` `routes()` contains business logic inline: the answer comparison `body.answer === q.answer` and the cost-vs-bank dispatch sit in the route table, not in a use-case. The topic-list and question-list composition (adding cost questions to 'All topics') is also in the HTTP layer. - `public/report.js` computes scores and per-topic totals (`score`, `topicScores`) in the view module, so report rules are only testable through the DOM. - `public/author.js` and `public/quiz.js` contain both state and rendering; `quiz.js` also calls `api` directly. There is no seam between flow logic and DOM. Proportion: the task is small, so one storage closure and a route table are reasonable. The gap is that the core is not cleanly separable from its I/O, and a few rules sit at the edge. No ports are declared, and the boundary is drawn by convention rather than by interface.
03:03 PM +47m 41s
J
Jonathan Baltus evaluated by Code Quality on Task 0 +15 points
cleanliness 7.0 The code is mostly tidy. Names say what things are (`settle`, `sumTable`, `checkCost`, `topicScores`), there is no dead code I could find, and the zero-dependency `h()` helper in public/dom.js keeps the DOM code short. Deductions: the price strings are duplicated against the numeric constants in server/cost.js (`PRICE` at line ~10 versus the `'$3'`, `'$15'`, `'$0.30'` literals passed to `line()` at lines ~30-45), and the cost question text repeats the price list a second time. The wiki card bodies in server/wiki.js restate the seed explanations almost verbatim, which is content duplication rather than code duplication. A stray `// ponytail:` comment sits in public/main.js (`startQuiz`). The `bank.reset(), [204]` comma expression in server/app.js is a small cleverness. No duplication metrics were supplied, so this is from reading the code only. maintainability 6.0 The server side is easy to follow: a route table in server/app.js, validation separated from the store in server/bank.js, and answers checked only on the server. Errors are handled at the boundaries: bad JSON, unknown ids, and 422 field errors. The weak spot is the browser code. `playQuiz` in public/quiz.js is a long function, roughly 100 lines, that nests `show`, `settle`, `choice`, `amount` and `next` closures, sharing mutable state (`index`, `answered`, `optionButtons`, `pick`, `next`). A newcomer has to hold all of that in their head to change it safely. `author.js` `form()` and `list()` are also dense single expressions. The bank's `all()` in server/bank.js returns the internal mutable array. Magic numbers in server/cost.js (`UNITS_PER_DOLLAR`, the `0x6d2b79f5` RNG constant, the amount ranges) are mostly named, but the `pick(r, 10000, 80000, 5000)` ranges are inline. Tests cover the server routes and the cost and wiki modules, which helps safe change.
03:03 PM +47m 40s
J
Jonathan Baltus evaluated by Creativity on Task 0 +13 points
creativity 7.5 Several working extras a real user would notice: a study wiki with one card per pinned question, linked to see-also pages and a 'Practise this question' button that starts a one-question quiz (public/wiki.js renderCard; main.js startQuiz with onlyId). Keyboard play with A-D or 1-4 keys and Enter to advance (public/quiz.js keydown handler). A line-by-line sum table on the cost questions, with the sum shown after answering and in the report (public/table.js, quiz.js feedback). Per-topic score breakdown in the report (report.js topicScores). Report persisted in localStorage so it reopens after reload. Dark mode and reduced-motion styles (style.css). Author edit/remove/restore-pinned controls with a topic datalist (author.js). The visible artifacts back this up: wiki-index-desktop.png, card-desktop.png, quiz-desktop.png, report-desktop.png. The score is held back because the generated 'Cost practice' topic adds five questions to 'All topics' (server/app.js /api/questions), so that quiz gives 15 questions, not the ten the brief pins. That is a deviation from the brief's scenario, not extra polish. I did not play the cost-round.webm screencast myself, so the sum-table behaviour rests on the code and the artifact's existence.
03:03 PM +47m 23s
J
Jonathan Baltus evaluated by Data on Task 0 +12 points
data 5.0 The pinned bank has one source of truth: server/seed.js holds the ten questions, and server/bank.js persists them to data/bank.json, which is gitignored. Answers are checked server-side in server/app.js (POST /api/answers), and the public/ files contain no bank or key. The seeded wording, options, answers and explanations match the brief. The data layer is well separated: api.js is the only client fetch layer, and bank.js/cost.js/wiki.js hold the server logic. Two defects keep this from a higher score. First, server/wiki.js hand-copies the bank's facts into ten CARDS bodies and summaries, a second drifting copy of the dataset (e.g. the K3 card restates 'Lint hunts for contradictions…'). Second, /api/wiki is public and not gated on answering, so a player who opens the wiki card for a pinned question receives prose that states its right answer and explanation before answering. That conflicts with the 'key stays on the server' requirement. The generated Cost practice questions are derived honestly from a seed, and the key is never sent before the answer.
03:03 PM +47m 22s
J
Jonathan Baltus evaluated by Test Quality on Task 0 +14 points
tests 6.0 The committed suites use real assertions with concrete values, and they cover the server well. test/app.test.js runs the real HTTP server (createServer on an ephemeral port) and checks the answer endpoint (K3/Lint right, T2/Input tokens wrong with 'Output tokens' revealed), the CRUD and reset routes, a 422 for a missing explanation, a 400 for bad JSON, a 404 for unknown routes, and path traversal. Public questions are checked to carry no key fields. test/bank.test.js covers validate() field errors (empty option, duplicate options, blank answer, blank explanation) and persistence across reloads. test/cost.test.js checks the generated topic's arithmetic and tolerance for amounts. Gaps: nothing in the committed tests exercises the browser UI (quiz.js, report.js, author.js, main.js), so the screencast-level flows (answer locking, keyboard play, report rendering, localStorage reload, the author form's per-field errors) have no automated check. The Playwright checks mentioned in the done note are not committed. No test pins the ten seed texts, answers and explanations to the brief's exact wording (test/bank.test.js:9 only checks counts per topic). The 'answer can no longer be changed' rule and the 'report reachable after reload' rule have no test. The suite is proportionate to a zero-dependency server, but it is one-sided: all server, no client.
03:02 PM +46m 42s
V
viktornovak-epam copy/paste check clean (1%)
02:56 PM +40m 00s
J
Jonathan Baltus copy/paste check clean (1%)
02:56 PM +40m 00s
V
viktornovak-epam evaluated by UX Review on Task 3 +18 points
ux 6.0 The host screens have a clear hierarchy: the join code is very large in the lobby (probe 029777a2 host-lobby, WUG7N), the countdown is a big blue numeral, and the leaderboard and podium rank players with bold points. The phone question and closed states are readable, with a green correct option and a 'Right. +975 points' banner (probe 2023dea3 phone closed). Docking points: on the host question and closed screens the letter badge runs straight into the option text ('AThe LLM', 'BNobody:'), so the options look unstyled. The host's closed screen also puts 'Next question' directly under the leaderboard with no spacing. The host and phone screens are otherwise plain, with no visible designed touches beyond colour. accessibility 5.5 On the phone, the correct and wrong answers are marked by a text verdict ('Right. +975 points') as well as colour, and option letters are in boxed kbd badges, so colour is not the only cue there. On the host's closed screen, though, the correct answer is shown only by bold green text (probe 029777a2 host-leaderboard, 'Nobody: raw sources…' in green). The letter and option text run together ('BNobody'), which hurts reading, and the host's option lists are plain ol/li with no visible pairing of letter and text. The markup uses real text, a live role=alert for errors, and an aria-label on the join code (live.js), but the host's contrast on the grey muted lines is modest. mobile 7.5 The 375px phone captures hold up. The question, four options, countdown and the answered and closed states all fit with no horizontal scroll, and the option buttons are large, tap-sized blocks (probe 2023dea3, phone question and closed). The phone podium and report were not captured at this width, and the host screens were only shown at desktop width, so the host's mobile layout is unchecked. The screencast of two players in separate windows was also not delivered for this task, so the cross-device flow is verified only through stills.
02:42 PM +26m 50s
V
viktornovak-epam delivered 4 files 157 KB

Run it live in a workshop

02:42 PM +26m 14s
V
viktornovak-epam delivered 4 files 181 KB

Run it live in a workshop

02:41 PM +25m 34s
V
viktornovak-epam evaluated by Test Quality on Task 3 +17 points
tests 6.0 The unit suite in test/live.test.js is well asserted on the rules that matter. It pins exact values: pointsFor(15700)=875 (line 'a right answer with 15.7 seconds left'), pointsFor(20000)=1000 and pointsFor(0)=500; the 15.7s answer gives gained 875 and a wrong one 0; a second answer raises 409; a late answer after the deadline raises 409; a 30-player cap and a case-insensitive duplicate name raise 409/400. It also checks that the key is absent in the question phase, the podium order ['Ada','Cy','Bob'] with a tie resolved by join order, the report's points and chosen values, and 403/404 paths. Gaps: (1) No HTTP-level tests for the /api/live/* routes added in src/app.js; test/api.test.js is unchanged in this task, so the wire contract, the token handling and the status codes are unverified end to end. (2) No browser or end-to-end test of the host screen, the phone screens or the countdown, and no live screencast or podium screenshot was delivered; the artifact folders contain only earlier tasks' files. The brief explicitly requires this flow to be verified across devices, so the assembled product is never exercised by any test. (3) Boundaries are thin: pointsFor's rounding-down is only tested at whole-second values (15700, 20000, 0), never at 15999 or 19999; the at-deadline refusal (at >= deadline) is untested; next() with zero players, which the UI disables but the server accepts, is untested. (4) The stale-timer guard in closeQuestion (room.index !== index) is untested: a question closed early by everyone answering, followed by its old timer firing during the next question, is not exercised. (5) `assert.ok(now() > 0)` in the 875 test is filler that verifies nothing. The suite is honest with no skips, and the level mix is unit-only, which caps this well short of a full score.
02:40 PM +24m 27s
V
viktornovak-epam evaluated by Code Quality on Task 3 +18 points
cleanliness 6.5 The server module is mostly readable: pointsFor is named and documented (src/live.js top), closeQuestion guards stale timers by index, and the leaderboard and rank helpers are small. Several rough spots keep it below a clean pass. state() looks up the host's per-player 'answered' flag with room.players.find((p) => p.name === entry.name), a name-based lookup where the player object is already in hand. The topic name logic in createRoom is a dense chained ternary: `topic === ALL_TOPICS || !topic ? ... : bank.topics().find(...)?.name ?? topic`, which also repeats the 'no topic' check. questionOf(room) is called repeatedly where one local would do, and the code mixes `questionOf(room).answer` with a cached `options`. report() builds `shown` with a map-then-filter whose condition (`i < room.index || room.phase !== 'question'`) is hard to read. In the client, the rule constants are repeated: the server has QUESTION_MS and MAX_PLAYERS, while public/js/views/live.js hardcodes QUESTION_SECONDS=20 and the literal 'of 30'. The test at test/live.test.js ('a right answer with 15.7 seconds left') ends with `assert.ok(now() > 0)`, which asserts nothing useful. Duplication is low: the leaderboard and podium helpers are small and distinct. There is no dead code of note. maintainability 6.0 The rules are clear. The deadline is server-stamped, and answer() checks phase, duplicate answers, deadline and choice range before scoring, so the boundary errors are handled. Timers are injectable, which makes the fake-clock tests possible. The weak points are structural. state() is a roughly 55-line function that branches into host and player views, builds the question view and the leaderboard, and mixes four responsibilities; a newcomer has to read it whole to change either view. public/js/views/live.js is about 300 lines and holds the entry, host, player and report views together. The 500 ms poll and 200 ms clock are inline literals. Rooms are never removed from the in-memory Map, so memory grows across games. Client errors on answer and next are swallowed with empty catch blocks. These are explained by comments, but a failed answer gives the player no feedback. Room-code length (5) and name length appear as literals. Overall a newcomer can make a small change safely, but a host/player change touches shared, branchy code.
02:40 PM +24m 22s
V
viktornovak-epam evaluated by Architecture on Task 3 +15 points
architecture 5.5 The live rules sit in one module, src/live.js, that takes its clock and timer as injected parameters (`now`, `schedule`, lines 19-20), so the 20-second rule, the speed scoring (`pointsFor`, line 13) and the room logic can be tested without a server. test/live.test.js drives them with a fake clock. That is a proportionate seam for a two-hour task, and the in-memory store needs no repository interface. The rule is still broken in three places. First, the core names HTTP: it imports `HttpError` from errors.js and throws 404, 409, 403 and 400 from roomFor, join, answer, next and report. Second, the core calls node:crypto directly (`randomInt`, `randomUUID`, lines 1, 34, 49, 68), so randomness is not injected. Third, it imports `ALL_TOPICS` from bank.js and takes a concrete `bank` object instead of declaring what it needs. The state() view mixes host and player projections and presentation fields such as `role`, which pushes the view shape into the core. The earlier flags on the solo quiz still apply to quizzes.js, which this commit leaves unchanged. The live core repeats the same pattern (HTTP status in the domain, inline randomness) rather than fixing it, so the earlier advice has not been applied to the new code. The front end (public/js/views/live.js) keeps polling, DOM and API calls together, which is acceptable for a UI file and does not hold any scoring. The client computes the countdown only for display; the score and the answer key stay on the server (live.js lines 128-133 and 138-140).
02:40 PM +24m 17s
V
viktornovak-epam evaluated by Correctness on Task 3 +23 points
product 5.5 The live-game code is coherent and matches most of the brief. Scoring is server-side and exact: pointsFor floors whole seconds left, so 15.7s gives 875 (src/live.js:7, test/live.test.js:52). The right answer and explanation are only added to the state once the phase is 'closed' (src/live.js state(), closed-only fields). Answers are refused after the deadline or once sent. Names are unique case-insensitively, rooms cap at 30, and a token-based rejoin keeps points. The host screen shows a 5-letter code, the joined list, a countdown, an answered count and a leaderboard. The phone shows rank and points, a report link, and the podium. However, nothing in this task's artifact set proves the live flow works as a product. The attached images are all from earlier rounds (quiz, report, cost). The brief requires a webm screencast of host plus at least two players joining, answering, the leaderboard and the podium, and a podium PNG. Neither was delivered for this task. The done note's claim of a browser run with three phones is therefore unevidenced. Several UI behaviours (countdown sync, the rerender on signature change in public/js/views/live.js, the join flow) were never seen running. Rooms are in memory only, which the note discloses. The lobby has no animation or sound, which is optional.
02:40 PM +24m 08s
V
viktornovak-epam evaluated by Data on Task 3 +21 points
data 7.5 The live game's values come from the server. Questions are copied from the bank into the in-memory room at creation (src/live.js createRoom, `questions.map(q => ({ ...q }))`). Points are computed server-side with a single `pointsFor` (src/live.js:7). Answer keys and explanations are withheld from players until the phase is 'closed' (src/live.js state()), and the report only exposes questions already shown. The client renders server responses and computes only a display countdown from `deadline` (public/js/views/live.js secondsLeft). Deductions: the rules are redeclared on the client, so a change to the rules table would have to be made in two places. `QUESTION_SECONDS = 20` is at public/js/views/live.js:5 (server: `QUESTION_MS = 20000` at src/live.js:3), and the hard-coded `of 30` in hostScreen (public/js/views/live.js, lobby branch) duplicates `MAX_PLAYERS` (src/live.js:4). The 'All topics' literal is repeated in both createRoom and the client. The client also hard-codes the topic filter `!t.generated && t.id !== 'cost-practice'`. These are drift risks, not current wrong values. Live rooms are in memory only, which the done note discloses, so there is no store copy of live results; that is a design choice rather than a data defect.
02:39 PM +23m 53s
V
viktornovak-epam evaluated by Creativity on Task 3 +14 points
creativity 6.5 Several small, working touches go past the brief, all visible in the committed code. The host lobby shows a live 'Joined (n of 30)' count and disables 'Start first question' until someone joins (public/js/views/live.js, hostScreen lobby branch). The host sees per-player 'answered' / 'thinking' markers and an 'N of M answered' counter during each question. Phones show their own rank and points and a 'Right' / 'Not quite' / 'No answer' verdict with '+N points' after each question. Ranks are competition ranks, so ties share a rank (src/live.js rankOf). Each device keeps its seat by token, so a reload rejoins with points intact. The join code field uses autocapitalize and a 5-character limit. Players get a per-question report of their live game, and the podium highlights first place. These are sensible usability and end-user touches, not a memorable creative mechanism. No live screencast or podium screenshot was delivered, so the live behaviour is judged from code and unit tests only (test/live.test.js). The live-done note also says a browser run was done, but no artifact shows it. The extras are plausible and well-scoped, but none is a standout idea, so the score sits modestly above baseline.
02:39 PM +23m 49s
V
viktornovak-epam evaluated by UX Review on Task 2 +21 points
ux 8.0 The study wiki index reads clearly. The page title and lead line sit at the top, then two topic headings (Token economy, Knowledge base) group the ten cards. Each card has a bold name and a grey one-line summary in a bordered tile, so the hierarchy is obvious at a glance. The concept card page also has a clear order: breadcrumb, large title, body text, a primary 'Practise this question' button, then a 'See also' section. The report's 'Concept card: X' links (report-cost-desktop.png, report-cost-mobile.png) are small blue underlined text beneath each wrong answer, so they are easy to spot. Deductions: the home progress panel (best scores, last five runs, missed list, clear-all) and the review run were not captured, so I cannot judge their layout. accessibility 6.5 The markup is semantically sound: h1 for the page, h2 for topic groups and 'See also', a ul/li list for the cards and see-also links, and real text rather than images. Card names are real anchor links. In the screenshots, the grey summaries and breadcrumb text on the off-white background look readable but lighter than the body text, and the card names are bold but small. The screencast of keyboard focus and the video of the flows were not part of this capture, so focus visibility could not be verified. The report's 'Concept card' links are plain blue text, which is fine. The brief's required screencast for the interactive flows is still absent in this round. mobile 7.5 At 375px the card index stacks into a single column with no horizontal scrolling. Titles and summaries wrap cleanly, and the tiles keep their padding (wiki-index-mobile.png). The concept card page also reflows well: the title, body text, full-width-looking 'Practise this question' button and See also link all fit (card-mobile.png). The report at narrow width (report-cost-mobile.png) shows the concept card links wrapping without overflow. The progress panel on the home page was not captured at narrow width, so that surface is unverified. The CSS uses flex wrap and grid for the new blocks (style.css, home-links and card-list), which supports responsiveness.
02:38 PM +22m 19s
V
viktornovak-epam delivered 4 files 293 KB

Add the study wiki and review

02:38 PM +22m 05s
V
viktornovak-epam evaluated by Architecture on Task 2 +10 points
architecture 3.5 The study feature adds two new modules, but the core still names transport and runtime details, and this task adds more of them. The structure is not worse than before, but none of the debt flagged in the first two verdicts has been paid down. Evidence: src/quizzes.js:1-2 imports node:crypto and HttpError; saveQuiz calls randomUUID() and new Date().toISOString() inline; create() and createReview() throw HttpError with status codes (quizzes.js, new create/createReview). src/cards.js:1 imports HttpError and cardDetail throws HttpError(404) (cards.js, cardDetail), so the card catalogue is transport-aware. The rule still doesn't hold: the business rules (quiz, review, progress) take a concrete fs-backed store (createProgress(store) in progress.js, createQuizzes(store, bank) in quizzes.js) with no repository interface. The dependency rule is still violated at the centre. Credit where due: progress.js is a separate module with its own pure helper bestByTopic(), testable without a server (test/study.test.js exercises it directly), and cards.js is mostly plain data with pure cardList/cardDetail functions. The frontend views (public/js/views/wiki.js, home.js) talk only to the API client, which is correct. Progress bookkeeping is now folded into quizzes.answer() (quizzes.js noteAnswer and recordRun calls), so the quiz module carries three responsibilities. This is proportionate to the task size but leaves the core coupled to the edge. Fixing the old items (domain errors mapped at the edge, injected clock and id generator, repository interface) would still bring the core to the rule.
02:34 PM +18m 47s
V
viktornovak-epam evaluated by Code Quality on Task 2 +19 points
cleanliness 7.0 The new modules are mostly readable: cards.js keeps the pinned table in one data array, progress.js is a small store wrapper, and RECENT_RUNS and REVIEW_TOPIC replace magic values. Three things drag it down. The card-link paragraph `!item.correct && item.card && el('p', {}, el('a', ...))` is repeated in report.js (reviewItem and amountReviewItem) and quiz.js feedback, so it should be one helper. `CARD_SLUGS` in src/cards.js is exported but nothing in the diff imports it, which looks like dead code. The PINNED note strings are long single-line object literals, and the `cardList(bank).find(...)` in cardDetail rebuilds the whole list to fetch one card. No measured duplication figure was supplied, so this rests on reading the diff. maintainability 6.5 Server logic is easy to follow. quizzes.js splits saveQuiz, buildReport and progress recording, and progress.js names its best-score comparison (beats). Validation sits at the boundary: unknown question ids and slugs return 404, and an empty review returns 400. Maintainability drops on the client. In home.js, progressPanel nests ternaries and `&&` branches inside long el(...) argument lists, so the markup and the logic are hard to scan and change. The `beats` helper uses cross-multiplication with only a comment for explanation. The 'learned' or streak features were not added, so there is no extra complexity to weigh there.
02:34 PM +18m 42s
V
viktornovak-epam evaluated by Test Quality on Task 2 +24 points
tests 8.5 The new test/study.test.js (commit 57e0d23) is well-asserted and specific. It pins exact values: K2 links to {slug:'index-and-log'} and sees 'Raw sources'; the review run is exactly ['T2','K4']; a right answer drops T2 from the missed list; the review run is refused with 400 when nothing is missed; the best-score ratio and tie-break are checked on concrete numbers. It also covers a restart (makeServices(dir)) for progress persistence, and clearProgress empties runs and missed. The gaps are: (1) No HTTP-level tests for the new routes in test/api.test.js: GET /api/cards, GET /api/cards/:slug (including the 404 for an unknown slug), GET/DELETE /api/progress, and POST /api/review are untested, and the diff does not touch api.test.js. (2) No browser or end-to-end coverage of the wiki index, the card page's 'Practise this question' control, the progress panel, the review button or the clear-all confirm. Earlier verdicts already flagged the missing browser tests, so I am not charging that twice. (3) Nothing pins the pinned table as a whole. The tests check that see-also slugs resolve and that the card count is ten, but not that each card's name, question and see-also list match the brief's table. A silent re-link would still pass. (4) The review path where a question is answered wrong again in review, which should keep it on the list, is not exercised. No screencast or report screenshot for this task is in the repo, so the interactive flows rest on the service layer alone.
02:34 PM +18m 36s
V
viktornovak-epam evaluated by Correctness on Task 2 +27 points
product 6.5 The code covers every scenario and the report screenshot confirms the central link. The interactive flows the brief names (card index, explanation-to-card jump, see-also navigation, review run, progress after reload) have no delivered screencast or screenshot, so they remain unverified. The wiki also exposes explanations before the player answers, which is a spoiler trade-off.
02:34 PM +18m 30s
V
viktornovak-epam evaluated by Data on Task 2 +21 points
data 7.5 The concept-card table is declared once, in PINNED in src/cards.js (names, question ids, see-also links, summaries). The client holds no card data: wiki.js and home.js render only what /api/cards, /api/cards/:slug and /api/progress return. Card bodies are derived from the bank's explanation at request time (cardDetail in src/cards.js), and topic names come from bank.topics(), so the bank stays the source for question text. Progress is server-side in progress.json via createProgress (src/progress.js). Deductions: noteAnswer (src/progress.js) pushes a full copy of the question into the 'missed' list, so review quizzes and the home missed list show a snapshot that can drift from the bank after an author edit. The 'Review' and 'All topics' names are also literals in topicName (src/quizzes.js). Neither is a dangerous duplication, but both are small copies of data that already has a source. The answer key is not shipped to the page: the progress view strips it, and the review quiz is served through the existing server-side view.
02:34 PM +18m 28s
V
viktornovak-epam evaluated by Creativity on Task 2 +14 points
creativity 6.5 Several working touches beyond the brief, all visible in code and in the delivered report screenshot. Concept-card links appear under each wrong answer (report-cost-desktop.png shows 'Concept card: Prompt caching', 'Token prices', etc.). A card's 'Practise this question' starts a one-question quiz (src/quizzes.js create with questionId; public/js/views/wiki.js cardView). Home shows a 'Review N missed' button whose count is live (public/js/views/home.js), and the missed list links each entry to its card. Best score is chosen by ratio, with ties going to the larger quiz, and review runs are excluded from best (src/progress.js bestByTopic). Clear-all asks for confirmation (home.js clear). These are sensible, user-facing, and fit the product. None is a memorable or unusual mechanism, and there is no search, learned badge or streak. The study screencast was not delivered, so the review and progress flows are judged from code and tests, not from a browser run.
02:34 PM +18m 25s
V
viktornovak-epam started working on Task 3

Run it live in a workshop

02:34 PM +18m 15s
V
viktornovak-epam evaluated by UX Review on Task 1 +20 points
ux 7.5 The delivered all-topics report (report-cost-desktop.png) has a clear hierarchy: a large '1 / 15 right' headline, three per-topic bars with Cost practice at 0 / 5, then each cost question with its text, 'Your answer', 'Right answer' and a right-aligned line-by-line sum table ending in a bold total. The numbers are legible at a glance. Two things pull it down. Every cost entry shows 'Your answer: 0.0001', which reads as a placeholder and makes the typed-answer comparison hard to read. The sum table headers also wrap awkwardly in the narrow column. The quiz-side cost screen (amount box, feedback with sum table) was not seen as a still, only as a possibly blank video frame. accessibility 6.0 Text is real HTML, not baked into images. The sum table uses a th with scope='row' for the total (public/js/sum.js). The right/wrong state is carried by text labels ('Right.', 'Not quite.', 'Your answer') as well as colour. However, on the home page the 'All topics' card's subtitle ('Every question in the bank') is grey text on the blue selected background, and it is close to illegible in the delivered home still. The mobile report also shows cramped table headers. The screencast could not be verified as motion, so screen-reader and focus behaviour during the typed answer are not assessed visually. mobile 7.0 report-cost-mobile.png at about 375px holds together. The cost questions, Your answer/Right answer lines and sum tables stay inside the column with no horizontal scroll. The table reflows with narrow columns, so 'Token kind' and 'Request cost' wrap onto two lines, which is readable but cramped. The CSS includes a 480px media query that tightens cell padding (public/style.css:304). No mobile capture of the live cost quiz (amount input, feedback table) was delivered as a still, so the narrow answer flow is only partly covered.
02:33 PM +17m 27s
V
viktornovak-epam delivered cost-round.webm 122 KB

Add cost practice

02:33 PM +17m 15s
V
viktornovak-epam delivered 2 files 1.1 MB

Add cost practice

02:30 PM +14m 35s
V
viktornovak-epam evaluated by Data on Task 1 +20 points
data 7.0 Server-side generation keeps the cost data out of the page. The price card is declared in src/costs.js, but the input and cache-read prices are repeated there as separate constants, so the same values live in two places within one file. Questions, answers and sum lines are created in costQuestions() and stored in the server-side quiz snapshot, so the source of truth stays on the server. publicQuestion passes only id, text, type, options and result; answer, lines and totalLabel appear only after an answer is locked. The client receives rates and amounts only as server-formatted strings, and typed input is parsed by parseAmount on the server. Deduction: KINDS holds input: 300 and cacheRead: 30, duplicated by PLAIN_INPUT_CENTS = 300 and CACHE_READ_CENTS = 30, so a later price edit could drift between the request and saving formulas. This caps the score below the top band.
02:26 PM +10m 56s
V
viktornovak-epam evaluated by Correctness on Task 1 +29 points
product 7.0 The cost logic matches the brief. The three worked examples come out right in src/costs.js: request with cache read = 120+120+600 units = $0.0840; request with cache write = 240+1500+600 = $0.2340; saving = 1200-120 = $0.1080. Typed input is parsed exactly to $0.0001 (parseAmount, src/costs.js), so "0.084" and "$0.0840" are right and "0.085" is wrong. Questions are generated and checked on the server, and publicQuestion (src/quizzes.js) reveals text and options only until answered. The sum table is shown line by line after answering (public/js/sum.js, quiz.js feedback), and the report shows typed answer, right amount and sum for each cost item (report.js amountReviewItem). All-topics appends five cost questions after the ten bank questions. Points deducted because no delivered artifact shows the cost flow: the attached screenshots are the old core-task images. The report screenshot shows only Token economy and Knowledge base with "1 / 10 right", so it does not show Cost practice's own score or any cost question, and no cost screencast was delivered. I also did not run the test suite. The done note's claims (three request and two saving questions, server-side checks, tests in test/costs.test.js) match the code.
02:26 PM +10m 50s
V
viktornovak-epam evaluated by Test Quality on Task 1 +17 points
tests 6.0 The new tests assert concrete values, not just that code runs. test/costs.test.js:8-18 pins the brief's three worked examples ($0.0840, $0.2340, $0.1080). Lines 20-28 check parsing of '0.084' and '$0.0840' and reject bad input, and money() is tested for exact formatting. Lines 30-40 check round shape and that counts are multiples of 4,000 within range. The server-side secrecy rule is covered at lines 49-58: no answer, lines or totalLabel before answering. Lines 60-75 cover a 400 on bad input, a wrong typed amount, a 409 lock after answering, and a right typed amount. The all-topics ordering (costs after bank questions) is tested at lines 85-90, and test/quizzes.test.js was updated for 15 questions and the third topic's score in the report. Gaps against the brief: (1) No test drives the browser. The screencast-level flow (typing '$0.0840' in the amount box, the sum table, the Enter-to-continue flow) and the amount-form Enter handling are unverified by any automated test. (2) The HTTP layer is untouched: test/api.test.js gets no amount case, so the `body?.choice ?? body?.amount` routing in src/app.js and the '$0.0840' string through the real endpoint are not exercised. (3) The 'wrong' scenario uses 0.0010 off, not the brief's '0.085' literal, and no test covers the zero-token edge (a request with all kinds zero, or a saving of 0). (4) `assert.equal(q.answer, sum(q.lines))` (line 39) restates the implementation: the answer is computed from those same lines, so it cannot fail independently. (5) The all-topics ordering test identifies cost questions by an id prefix 'c-' (lines 85-90), which ties the test to an implementation detail. Level mix is unit-only for a feature whose brief is an interactive flow, so the assembled product is never exercised by tests.
02:26 PM +10m 48s
V
viktornovak-epam evaluated by Code Quality on Task 1 +20 points
cleanliness 7.5 The cost logic is compact and named for what it does: KINDS, PLAIN_INPUT_CENTS, CACHE_READ_CENTS, STEP, requestLines, savingLines, parseAmount, money. There is no copy-paste of the prior bank logic, and the earlier duplicated dark-theme CSS block from task #0 is not touched here. Points against it: the topic filter `(await api.topics()).filter((t) => !t.generated)` is repeated verbatim in author.js (the load and the restore paths). The nested ternary in quizzes.js create() (`topic === COST_TOPIC ? ... : topic === ALL_TOPICS ? ... : ...`) is harder to scan than a small lookup. Several lines run very long, such as the tfoot construction in public/js/sum.js and the `text` template in src/costs.js requestQuestion, which hurts readability. requestLines and savingLines build near-identical line objects, which is a mild repetition but justified by their different rates. maintainability 7.0 Prices and token counts are named constants, and the $0.0001 unit convention is documented at the top of costs.js. Server-side validation sits at the boundary: parseAmount returns null for bad input and storedResponse raises a 400 HttpError. The client handles 400 as a visible problem and 409 as a locked result. Test coverage is strong and covers the worked examples, parsing edge cases, the 'no answer leak' property, and all-topics ordering. Weaknesses: the `10000` divisor appears in several places (requestLines, savingLines, money, parseAmount's Math.round) without a single named constant. Functions like requestQuestion and the answer flow are dense, and the quiz.js draw() function has grown to handle two question types inline. A newcomer adding a third question type would need to touch several ternaries across quizzes.js and quiz.js.
02:26 PM +10m 37s
V
viktornovak-epam evaluated by Architecture on Task 1 +17 points
architecture 6.0 The new pricing core is well placed. src/costs.js imports only node:crypto (platform, not a framework), has no HTTP or storage references, and is unit-tested directly in test/costs.test.js with no server. Randomness is injected as a default parameter (`costQuestions(random = Math.random)`, costs.js:20), and the edge only consumes COST_TOPIC_ENTRY (app.js). The client renders server-shaped data (sum.js, report.js) and never computes amounts. The seam is proportionate to a two-hour feature. The old core defects are still there and I am not charging them again. quizzes.js still throws HttpError with status codes (quizzes.js:~70-100, `new HttpError(400, ...)`, `new HttpError(409, ...)`), and it still calls randomUUID and the clock inline. The new code adds to this rather than fixing it: `storedResponse` in quizzes.js maps input to HTTP 400 messages inside the core, and `create` calls `costQuestions()` without injecting the random source, so the quiz core picks its own randomness. New findings: - Presentation formatting sits in the core. costs.js `formatTokens`, `perMillion`, `money` and `lineView` produce display strings like "$0.0840" and "4,000", so the domain module decides how amounts are shown. - The app.js edge decides which field is the domain input (`body?.choice ?? body?.amount`), so the boundary blurs the difference between a choice and a typed amount. - The topic dispatch is hard-coded in quizzes.create (`topic === COST_TOPIC ? costQuestions() : topic === ALL_TOPICS ? ...`). That is acceptable at this scale, but it means the quiz core knows about each generator by name. The tree still names the domain: costs.js, quizzes.js, bank.js, and the AGENTS.md map is updated for them.
02:26 PM +10m 37s
V
viktornovak-epam evaluated by Creativity on Task 1 +13 points
creativity 6.0 Several small, working touches go past the brief, all visible in code. The amount input accepts a leading $, surrounding whitespace and up to four decimals (src/costs.js:parseAmount, with tests in test/costs.test.js). A rejected input shows an inline alert with a helpful example, "Enter an amount in dollars, such as 0.0840" (src/quizzes.js storedResponse, public/js/views/quiz.js amountBlock). The amount field takes focus on each question and Enter moves on (quiz.js draw, onKey). The report shows each cost item's typed answer, right amount and sum table (public/js/views/report.js amountReviewItem). These are sensible usability touches, not standout ideas. The line-by-line sum table itself is required by the brief, so it earns nothing extra. No hint button or calculator feel was built, and no cost-specific screenshot or screencast was delivered to confirm the flow renders as coded. The delivered screenshots show only the first-round quiz and report. Score sits above baseline for the usability care, not for creativity.
02:26 PM +10m 35s
V
viktornovak-epam started working on Task 2

Add the study wiki and review

02:26 PM +10m 25s
V
viktornovak-epam evaluated by UX Review on Task 0 +18 points
ux 8.0 The desktop quiz screen has a clear hierarchy: a progress line, a progress bar, a large question headline, then lettered options. The answered state is easy to read: the wrong pick is tinted red, the right option green, and a 'Not quite.' feedback panel carries the explanation. The report leads with a large '1 / 10 right' headline, then per-topic score rows (Token economy 1 / 5, Knowledge base 0 / 5), then a review card per question with 'Your answer' and 'Right answer' labels. Spacing and alignment are consistent. Minor deduction: the report's text-heavy review list is long, and the quiz screen leaves a large empty area below the feedback. accessibility 7.0 The markup is semantic: index.html has lang="en", the views use h1/h2/h3 headings, the feedback has role="status", and the progress bar has role="progressbar" with aria values (quiz.js). Wrong and right are not conveyed by colour alone: the report labels each answer 'Your answer:' and 'Right answer:' and the quiz feedback opens with 'Right.' or 'Not quite.' Text contrast in the screenshots is adequate for both light tones. Deductions: the muted grey explanation text on the report is lighter, the answer tint is the main cue on the quiz screen, and there is no visible focus check in the captures. mobile 8.5 The 375px captures show no horizontal overflow and no clipped text. Quiz options stack full-width with letters kept, and the Next button goes full width above the hint, as the media query in style.css intends. The report's topic rows, action buttons and review cards all fit within the narrow column. Touch targets are large (about 50px option rows). The fluid container and media queries back this up.
02:23 PM +7m 24s
V
viktornovak-epam delivered 4 files 763 KB

Build the quiz

02:23 PM +7m 14s
V
viktornovak-epam evaluated by Correctness on Task 0 +26 points
product 7.5 The code covers every scenario in the brief. Pinned bank text, options, answers and explanations match the brief (src/seed.js:1-139). Quizzes snapshot questions at start (src/quizzes.js:24-38), so bank edits only reach the next quiz. The quiz view returns the key only after an answer (src/quizzes.js:24-33, 45-52), and the answer is checked on the server. Answers lock with a 409 path (src/quizzes.js:80-84, public/js/views/quiz.js:24-35). The report shows the total, per-topic scores on 'all', and every question with the player's answer, correct answer and explanation (public/js/views/report.js:9-47). Start over, a reload-safe report URL and a home-page resume link are present. Authoring validates each part and reports missing pieces (src/validate.js:1-31, public/js/views/author.js:118-150). A restore control exists (src/app.js:50-56). Points deducted: no screencast or screenshot was delivered, so the live UI, the keyboard flow and the visual result are unverified. The Author API returns answer keys to the author page, which the done note admits; the quiz page itself does not use that endpoint. Starting a quiz on a topic with no questions gives an unhandled rejection on the home page (public/js/views/home.js:9-11). The done note says the browser UI was never run, so the claims about the UI are unverified.
02:22 PM +6m 13s
V
viktornovak-epam evaluated by Test Quality on Task 0 +14 points
tests 6.0 The server-side suite is real and asserts concrete values. Tests are in test/api.test.js, test/bank.test.js and test/quizzes.test.js, and they cover the key scenarios. Topic sizes (5 and 10) are checked, and the 409 lock on re-answering is verified. Right and wrong answers are checked for K3 'Lint' and T2 'Input tokens' (quizzes.test.js: 'an answer is judged by the server and then locked'; 'a wrong answer reports the right option'). Report score and per-topic split are asserted. The key-leak check is at the HTTP level (api.test.js: 'the quiz page never receives the key before an answer'). Validation boundaries are covered, including the named missing parts. Persistence across restart and snapshot isolation are tested. The API tests run the real assembled app over HTTP, so they are not pure unit tests. Gaps: nothing exercises the browser UI (public/js views, keyboard play, the answer lock in the DOM), so the screencast and report-screenshot requirements are verified by no automated test. Nothing checks that the pinned wording, options and explanations match the brief exactly, so a changed fact would pass. Some assertions are weak: 'validation tolerates a missing body' only checks errors.length > 0, and 'the report is reachable after reload' is not tested in a browser. The done note admits the browser UI was never run. Coverage of src/ is reported as 100% in the note, but public/js is outside it.
02:22 PM +6m 10s
V
viktornovak-epam evaluated by Architecture on Task 0 +13 points
architecture 5.5 The edge is cleanly separated. src/app.js owns the HTTP routing, body parsing and static serving, and the business logic sits in plain modules. validate.js (src/validate.js) is pure and imports nothing. Dependencies do not point fully inward, though. The core knows HTTP: src/errors.js defines HttpError with an HTTP status, and bank.js (lines 13-14, 27, 35, 42) and quizzes.js (lines 22, 26, 42, 46, 48) throw HttpError(404/400/409/413) directly, so status codes live in the domain. quizzes.js also calls randomUUID() and new Date().toISOString() (lines 39-40) inline, so the wall clock and randomness are not injected. The store is not inverted: bank.js and quizzes.js take the concrete file-backed store from src/store.js (fs/readFileSync, renameSync) rather than declaring a persistence interface. Business rules are testable without a server, but the tests still write to a temp filesystem through makeServices (test/helpers.js), so the core is not runnable as pure logic. Top-level layout is flat (app, bank, quizzes, store, seed, validate) and uses domain nouns, which reads reasonably well. Seams are proportionate for a two-hour build: no DTO layers or ring cascades, which is a plus. Overall: a sound edge, a core that is partly tied to HTTP and the filesystem.
02:22 PM +6m 08s
V
viktornovak-epam evaluated by Code Quality on Task 0 +17 points
cleanliness 7.5 Names are mostly specific (validateQuestion, resultFor, publicQuestion, topicScores, reviewItem), and the server splits cleanly into app, bank, quizzes, store, validate and errors. Dead code is minimal. The main deduction is the dark theme in public/style.css: the custom-property block is written out twice, once under @media (prefers-color-scheme: dark) at about lines 36-50 and again under :root[data-theme="dark"] at about lines 52-66, a copy-paste of roughly 15 declarations. Smaller issues: src/quizzes.js:24 sets publicQuestion's result from the response, and quiz.js mutates question.result on the shared client state. Measured duplication was not supplied, so this rests on reading the code. maintainability 7.5 The route table in src/app.js is declarative and each handler is one line. Validation returns structured errors that the form shows, and HttpError carries status and details at the boundary. The quiz snapshots its questions when started, so later bank edits don't affect it. The 409 path re-syncs the client. Functions are short and nesting is shallow. Weaknesses: quiz.js registers a document keydown listener on each render, removed only on the next hashchange, which is fragile for a newcomer. The server reads and rewrites the whole JSON file on every call with no locking, which is acceptable here but needs a note. Magic values such as MAX_BODY_BYTES and OPTION_COUNT are named. Tests cover validation, bank, quiz and HTTP paths.
02:22 PM +6m 01s
V
viktornovak-epam evaluated by Data on Task 0 +20 points
data 8.5 The pinned bank has one source of truth: src/seed.js holds the two topics and the ten questions, and the runtime bank is persisted once as data/bank.json via src/store.js and src/bank.js. The browser bundles no question or key. public/js/* only renders what /api/quizzes/:id returns. Source of truth, shadow-data and layering are all clean. Quiz snapshots copy questions at creation (src/quizzes.js create), so bank edits reach only the next quiz as the brief requires. Answer keys are withheld: publicQuestion (src/quizzes.js) exposes correctIndex/explanation only through resultFor after a response exists. The 409 path re-sends the result only for the already-answered question. Validation is centralised in src/validate.js and enforced server-side in bank.add/update. Minor deductions: the 'all' sentinel is duplicated between bank.js and the client home view, and the done note's claim of 28 passing tests and 100% coverage is not verified here. I did not check the test suite's expectations against the seed. No probe was registered; the data flow was traceable from code.
02:21 PM +5m 59s
V
viktornovak-epam evaluated by Creativity on Task 0 +11 points
creativity 6.5 Several working extras beyond the brief, all visible in code but none visually confirmed. Keyboard play: 1–4 or A–D answer, Enter advances, with an on-screen hint (public/js/views/quiz.js KEYS map and onKey handler; hint text in draw()). Resume link on the home page that reopens the last report, persisted in localStorage (public/js/views/home.js, public/js/storage.js). Topic-score breakdown on the all-topics report and a Start-over control that reuses the same topic (public/js/views/report.js). Author page with topic pills, per-field error list, confirm dialogs before remove and restore, and a restore-to-pinned control (public/js/views/author.js). Progress bar with ARIA progressbar role and dark mode via prefers-color-scheme (public/style.css). These are useful, real-user touches, but none is a memorable creative mechanism. The done note admits the browser UI was never run, so the extras are unverified in practice. No probe or screencast was registered, so the score rests on code reading alone.
02:21 PM +5m 56s
V
viktornovak-epam started working on Task 1

Add cost practice

02:21 PM +5m 48s
J
Jonathan Baltus started working on Task 0

Build the quiz

02:17 PM +1m 42s
V
viktornovak-epam started working on Task 0

Build the quiz

02:16 PM +0s