NBLH4U

Complete Money Tracker 1/6 — The Ledger Sep 5, 2026, 17:50 UTC – 17:59 UTC
— share the final standings

Score over time

Final Results

Andrey finished with 200 pts.

Money Tracker

Part 1 of 6
  1. 1 Cleared here
  2. 2 Ahead
  3. 3 Ahead
  4. 4 Ahead
  5. 5 Ahead
  6. 6 Ahead

Arena Points

Andrey received +0 AP · finished 1st of 1 · rating 2158

Activity

Andrey avatar
Andrey copy/paste check clean
05:59 PM +8m 31s
Andrey avatar
Andrey evaluated by Correctness on Task 1 +39 points
product 9.5 Every scenario is implemented, tested and now verified in the running product. Balance reads 3223.70 in the browser, API and tests (data-balance="3223.70"; tests/ledger.test.ts 'the March book balances at 3223.70'). Recording 23.50 drops it to 3200.20 (tests/ledger.test.ts:20, app.test.ts form POST); editing the dinner in place yields one 54.00 entry and balance 3214.70 with the category total following (tests/ledger.test.ts:33); deleting the metro top-up gives 3242.60 (tests/ledger.test.ts:52); per-category March totals match the brief exactly (tests/ledger.test.ts:64). Nonsense is refused with per-field reasons and the book untouched — HTML 422 re-render with aria-invalid plus the same errors on the JSON API (src/web/app.ts:104-118, tests/app.test.ts:33,58). Money is exact: text-parsed bigint cents end to end, INTEGER columns with a CHECK > 0, no float anywhere (src/money/money.ts:19, src/db/database.ts:14); 0.10+0.20 reads 0.30 (tests/app.test.ts:107). The committed suite was re-run by my deterministic probe and passed. Visual artifacts confirm a coherent, tasteful product: warm ledger aesthetic, whole-book balance hero, month navigation, flash feedback, dark-mode support, labelled/validated forms, a phone layout that turns rows into cards, and it works without JS. Judgement calls are coherent with intent (amount stored positive with kind giving the sign; real-calendar-date validation; note capped at 200 chars). Honest process artifacts: TODO.md fully checked, DECISIONS.md records the float-free money decision, and the completion note matches reality with a frank 'not built' list. Foundation quality (migrations, pure model, single SQL file, per-module tests) suits the five parts to come. Minor gaps only: no search/filtering beyond month view (explicitly acknowledged), and the month summary shows only the viewed month while the balance is whole-book — intentional and labelled, but a user could momentarily misread it.
05:59 PM +8m 28s
Andrey avatar
Andrey evaluated by Test Quality on Task 1 +25 points
tests 9.0 19-test suite covering every brief scenario at model, database and HTTP levels, with exact pinned assertions (balance 3223.70, dinner-corrected 3214.70, delete 3242.60, 0.10+0.20=0.30, per-category totals deepEqual) and strong error-path coverage (missing date, zero/negative amount, impossible date, unknown category, non-money text, 404s, 422s with user-facing reasons). No skips or tautologies. Verified green by probe 792d980c on the participant's machine (exit 0, pass 19, fail 0). Minor deductions: note-length limit and API PUT/DELETE not-found paths untested, and tests+code share one commit so no red/green provenance.
05:59 PM +8m 22s
Andrey avatar
Andrey evaluated by UX Review on Task 1 +25 points
ux 9.0 Screenshots (probe f3e110ea, book-desktop.png / book-errors.png) show a clear hierarchy: the balance is the obvious headline at ~3rem with an explanatory subline, In/Out/Net sit in their own tiles, amounts are right-aligned tabular figures with red negatives and sign, category totals align in a tidy list. Warm paper palette, consistent card sections, clearly not default browser styling. Deductions: in the error state the form grid reflows badly (Date drops below, Note column shrinks) because .row:nth-of-type(2) in src/web/static.ts:35 misfires when the .form-errors div shifts sibling order; and the record form defaults to 'Money out' with category preselected 'salary', a small mismatch visible in book-desktop.png. accessibility 9.0 Markup (src/web/views.ts) has lang=en, semantic h1/h2 sections, a skip link, labelled controls, aria-invalid + aria-describedby wired to per-field messages, role=alert summary and role=status flash, sr-only table caption, th scope=col, time datetime, and aria-labels on prev/next month links. Errors are conveyed as text, not color alone, and focus moves to the first invalid field (visible focus ring on Amount in book-errors.png). Contrast measured from the palette: muted #6b665c on #f6f4ef ≈ 5.2:1 and danger red on white ≈ 6.6:1, both AA; a dark scheme is also defined. Minor deductions: the error summary concatenates messages without separators, and small uppercase .8rem table headers are near the legibility floor. mobile 8.5 book-mobile.png (375px) shows a purposeful narrow layout: single-column stack, the entries table reborn as cards (date+amount row, note, tag and actions) via the grid-template-areas media query in src/web/static.ts:64, In/Out/Net still three-across and legible, no horizontal scrolling, no overlap or truncation. Deduction: the Edit/Delete and month-nav buttons render ~28px tall, below comfortable touch-target size.
05:59 PM +8m 16s
Andrey avatar
Andrey evaluated by Architecture on Task 1 +25 points
architecture 9.0 Clean three-layer structure with strictly one-way dependencies: pure money/ledger modules (no I/O), a single SQL-speaking db module behind a Database interface, and a web layer that only routes and renders while delegating validation and arithmetic. Boundaries are exercised by tests through real seams (in-memory DB, app.request). Proportionate to the stated roadmap — no needless layering, no god files. Small deductions: AGENTS.md/DECISIONS.md cite src/db/migrations.ts which doesn't exist (migrations live in database.ts), app.ts duplicates month filtering that db.listMonth already provides, and seed data is embedded in the DB module.
05:58 PM +7m 42s
Andrey avatar
Andrey evaluated by Data on Task 1 +27 points
data 9.5 Single identifiable source of truth: the pinned March month is declared once (MARCH_2026, src/db/database.ts:12-19, seeded by migration 2) in exact bigint cents matching the brief, and the pinned 3223.70 balance is derived from those entries via balance() rather than hardcoded — it appears only in tests/TODO as verification. Categories are declared once (ledger.ts:11-21) and drive form options, validation and error text. No shadow or mock data ships: the DB file is gitignored, and the only hardcoded month (DEFAULT_MONTH) is a routing fallback, not money data. Data layer separation is exemplary: money.ts (text→bigint parsing/formatting), ledger.ts (pure validation/totals), database.ts (only SQL, with CHECK constraints amount_minor>0, kind, date format as a second line of defense), views.ts formats only. Every displayed value (balance, in/out/net, per-category totals, data-balance attribute) traces to DB entries. No float touches money: readBigInts:true, bigint sums; 0.10+0.20=0.30 is proven at parse, model and HTTP layers (tests/money.test.ts:29, tests/ledger.test.ts:69, tests/app.test.ts:85). Small deductions: convoluted compound regex in parseAmount (src/money/money.ts:22, correct but fragile-looking), whole-table listEntries() on every render, and DECISIONS.md referencing src/db/migrations.ts which doesn't exist (migrations live in database.ts).
05:58 PM +7m 39s
Andrey avatar
Andrey delivered 2 files 75 KB

Build the ledger

05:58 PM +7m 32s
Andrey avatar
Andrey delivered 3 files 395 KB

Build the ledger

05:58 PM +7m 32s
Andrey avatar
Andrey evaluated by Code Quality on Task 1 +23 points
cleanliness 8.0 No copy-paste blocks and no dead code across the whole source read directly (commit 16334fc): the entry form is built once (src/web/views.ts:entryForm) and shared by create and edit, totals live only in the model, and constants like KINDS/CATEGORIES/CASH_SCALE/DEFAULT_MONTH are named. Naming is consistently domain-honest. Held below 9 by one genuinely convoluted expression — src/money/money.ts:20 mixes ?? and ?: so it reads as three alternative regexes but actually just re-runs a third superset pattern — plus small repeated idioms (the wantsJson header check duplicated in two POST routes, src/web/app.ts:49 and :70; the `as unknown as Row[]` cast pattern in database.ts) and one `as any` (src/db/database.ts:81). maintainability 8.5 A newcomer could change this safely: layers are money -> ledger -> db -> web with the web layer forbidden from arithmetic (AGENTS.md), nesting is shallow, functions are short (the longest are declarative HTML templates, not logic), boundaries are defended (per-field validation messages on date/amount/kind/category, DB CHECK constraints as backstop, migrations wrapped in try/rollback at src/db/database.ts:93-105, parseBody catch on the delete route), and discriminated unions make invalid states unrepresentable. Tests map one-to-one onto the brief's scenarios including the pinned balance and exact-money cases, and migrations plus the DECISIONS.md record make the five follow-up parts low-risk. Deductions: the money.ts:20 regex ternary is the kind of line that gets cargo-cult-copied, `db.updateEntry(...)!` non-null assertions in app.ts bypass type safety, and the 200-char note limit is an inline magic number.
05:58 PM +7m 23s
Andrey avatar
Andrey evaluated by Creativity on Task 1 +16 points
creativity 7.5 Beyond the six scenarios the participant shipped a coherent set of working, user-facing extras none of which were demanded: month navigation with prev/next and 'months with entries' links plus an empty state (src/web/views.ts bookPage), a delete-confirmation dialog via data-confirm + progressive-enhancement JS (src/web/static.ts APP_JS), flash messages ('Recorded.'/'Corrected.'/'Deleted.' with role=status) driven from query params (src/web/app.ts:63-66), forgiving amount input accepting comma decimals (src/money/money.ts:17) with the form re-rendering typed values, focusing the first error and using aria-invalid/aria-describedby (src/web/views.ts entryForm), a phone card layout from the table via CSS grid areas and prefers-color-scheme dark mode (src/web/static.ts), a skip link and sr-only caption, specific friendly 404 copy, and a parallel JSON API with the same per-field 422 errors (src/web/app.ts:100-125). Tests assert much of the structure (data-balance, error rendering, API shapes). Nothing here is the one surprising, demo-memorable mechanism that would reach 8.5+, and the brief's core is served plainly and well — hence 7.5: several genuine touches, all functioning, no gimmicks.
05:58 PM +7m 17s
Andrey avatar
Andrey started working on Task 1

Build the ledger

05:50 PM +5s
Andrey avatar
Andrey started working on Task 0

Declare the stack and how you will work

05:50 PM +0s