SeaOtterAll works

RECKONER

Software · a formula engine17/17 checks passedcleared

A spreadsheet, cloned from Google Sheets and Excel down to the formula bar — with a hand-rolled language, a real dependency graph, and errors that name themselves.


What the checks read

Each line is the buyer's own wording, beside what the check run observed.

17 of 17 checks passed.

Software · a formula engine

Google Sheets and Microsoft Excel are the named donors. The grid, the lettered columns, the formula bar and the =SUM(B3:B9) grammar are theirs. The language underneath is ours: a lexer, a parser and an evaluator written by hand, over a dependency graph that recomputes what changed and says how much it touched.

The accepted bundle runs here. Type into it. Change a speed in column C and watch the fuel state at B16 decide again — nothing is fetched, and the sheet you leave is the sheet you come back to.

What to try, if you only have a minute

Three edits that show it is a real engine and not a picture of one.

  1. Put 5.5 into C3. Leg one slows down, and seven cells downstream move with it — including B16, which flips from OK to REFUEL because the reserve genuinely fell under a fifth of the tank.
  2. Type =J4 into J3, then =J3 into J4. Both cells say #CYCLE! and the sheet stays alive. A spreadsheet has to refuse a loop by name rather than hang on it.
  3. Write anything of your own — =ROUND(AVERAGE(B3:B9),3) is a good one — then reload the page. It is still there, because saving is not a button.

拆解

Their move, ours, and why

A clone is mostly a sequence of decisions about what not to copy. The last row is where we walked away from the donor on purpose.

A1 addressing, lettered columns, numbered rows
kept verbatim
This is the donor's load-bearing convention and a hand already knows it. Renaming it would be vandalism dressed as originality.
The formula bar with its fx sign
kept, with the address block beside it
The cell shows the value, the bar shows the source. Two views of one truth is the whole reason a spreadsheet is legible.
=SUM(B3:B9) and its family
17 functions, hand-rolled lexer to Pratt parser to evaluator
No library and no CDN. Ranges, comparisons, string concatenation, percent and IF all parse in our own grammar.
Recalculation when an input changes
a real dependency graph with a topological pass — and a published receipt
The donor recomputes silently. Ours states how many cells it touched, so the claim that it recomputes dependents rather than the sheet can be checked from outside.
The circular-reference warning
#CYCLE! as a value, carried like any other error
A cycle names itself in the cell and the app stays live. Errors propagate through arithmetic the way the donor's do, so one bad cell spoils a column and not the sheet.
The fill handle
fill-down with relative-reference translation and $ anchoring
Filling =B3*2 down a column writes =B9*2 at the bottom, not seven copies of the first formula.
Autosave and the recent-file list
canonical JSON in local storage; export downloads the exact saved bytes
The file you download is byte-identical to the file that is kept. No re-serialisation in between, so the two can never quietly diverge.
NOW(), TODAY(), RAND()
REFUSED — the language has no volatile function at all
This is the one place we walked away from the donor on purpose. A volatile cell cannot be checked twice and get the same answer, and the acceptance on this job is that a machine recomputes the arithmetic independently. Keeping them would have made the piece unprovable.

What the machine passed and a person sent back

Two of these had green checks and were still wrong: no assertion covered the thing that was wrong. The other three are refusals made during the build.

  1. 1sent backat review

    17/17 driven steps passed, 0 console errors

    Column A is eating the slack on the hand seat. Nobody asked for a 250px name column — the table just never stated its width.

    Stated the table width and made column A wide on purpose. The geometry is now declared rather than inferred.

  2. 2sent backat review

    selection statistics render, assertion green

    It prints “1 cells” at a buyer.

    Reads “J8 selected” for one cell and counts only when there is something to count.

  3. 3declinedat build

    the donor ships NOW(), TODAY() and RAND()

    Then the sheet cannot be checked twice and get the same answer, and the acceptance condition dies with it.

    The language ships no volatile function. Determinism was chosen over surface-area parity with the donor.

  4. 4declinedat build

    split the engine into ES modules

    The piece runs in a sandboxed frame at an opaque origin, where a module script cannot be fetched at all.

    Four classic scripts in load order. It is the older mechanism and it is the one that survives the seal.

  5. 5declinedat build

    re-render the grid after every edit

    That throws away the caret and the selection on every keystroke.

    The grid is built once and painted in place, which is why the caret survives a recalculation.

It recomputes the dependents, not the sheet

A spreadsheet that recalculates everything on every keystroke looks identical from the outside. So the engine publishes the scope of each pass, and the acceptance reads it off the running app.

9 of 75 filled cells, after C3 = 5.5

  • B14
  • B15
  • B16
  • B17
  • C3
  • D11
  • D3
  • F11
  • F3

The acceptance did the arithmetic itself

A screenshot of a number proves nothing about whether the number is right. So the check recomputes the whole passage from the seven raw legs, in its own code, and compares — then drives the real app through create, edit, fill, undo, reload, export and import in a real browser.

17/17driven steps
115injected inputs
0console errors
0volatile functions

playwright_chromium · recomputes the passage from the seven raw legs and compares · docs/qa/artifacts/20260804-reckoner/

The delivered bundle

Six files, no framework and no CDN. The theater serves these exact bytes; every hash is re-read against the served files in CI.

  • index.html50ffaef2affc…
  • styles.cssf7f54c12ed1f…
  • formula.js5edfc4017040…
  • engine.js6e315314ec14…
  • passage.js3a912f62fbde…
  • app.js8031a915302c…

Who made it

SeaOtter's Superteam

SeaOtter's own team — first-party work, labeled so. Every number on this page is read from the production receipts; the file that holds each one is named beside it.

When it refuses

Every check was green and the build was still sent back twice — once for a column that had eaten the layout's slack, once for printing “1 cells” at a buyer.

17/17 driven steps passed, 0 console errors

the banked record

docs/qa/artifacts/20260804-reckoner/acceptance/driven-transcript.json

£623.75settled

Price yours

A job like yours

Last bankedin a browser£225.00passed 2026-08-04

Your job prices on your own words — a fixed quote before any account.

Price a job like this