# Development Log

## 2026-06-26

- Wrote `PLAN.md` before implementation, as required by the build-off protocol.
- Chose a vanilla Vite + TypeScript app instead of React. The brief does not require a framework, and a DOM-based grid keeps the bundle smaller while letting the engine remain a pure module for hidden tests.
- Copied the shared ESLint, TypeScript, and Prettier configs into the project root to match the objective harness.
- Started with a split engine design: references, parser, evaluator, graph, and public sheet API.
- Implemented the parser as recursive descent rather than using a generated parser. This keeps the dependency footprint at zero for runtime and makes precedence explicit: comparisons, addition/subtraction, multiplication/division, unary signs, and right-associative exponentiation.
- Kept dependency extraction separate from evaluation. Formula ASTs are walked once after parsing to update graph edges; recalculation then uses the reverse graph to collect only the edited cell plus transitive downstream dependents.
- Used Tarjan strongly connected components during affected-cell recalculation. That marks all cells involved in a cycle as `#CIRC!` before downstream formulas evaluate, which lets normal error propagation handle formulas that reference cyclic cells.
- Made `IF` branch evaluation lazy in the evaluator, while still recording dependencies from both branches. This favors spreadsheet-like dependency tracking without forcing errors from an untaken branch.
- Added stretch functions `CONCAT`, `ROUND`, `AND`, and `OR` because they fit the existing evaluator design without adding complexity or dependencies.
- Added the optional `window.__buildoff` hook. `warmup()` creates a 10,000-cell dependency chain and `workload()` edits `A1` 200 times while measuring engine recalculation time.
- Initial dev dependencies used older Vite/Vitest ranges and `npm audit` reported Vite/Vitest advisories. Updated to Vite `^8.1.0` and Vitest `^4.1.9`, which are compatible with the local Node 22 runtime and audit cleanly.
- A local invalid-reference test revealed that parse-time `#REF!` values were being overwritten as `#ERR!` during recalc for formula records without ASTs. Fixed recalc to preserve stored parse errors for malformed formulas.
- Added `.prettierignore` for generated output and formatted the project with the shared Prettier config. Verified `npm ci && npm run build && npm test && npm run lint && npx prettier --check .` passes.
