# Reasoning Log

## Plan

- Chose a no-dependency TypeScript engine because hidden tests import a pure `src/lib/engine.ts` API and correctness/bundle size dominate the rubric.
- Split parser/evaluator/refs/engine to preserve architecture clarity and avoid a single god-file.
- Incremental recalculation will traverse only reverse dependents of the edited cell, then topologically evaluate affected formulas and mark DFS cycle participants as `#CIRC!`.
- UI is intentionally thin: 100×100 grid of inputs backed by one `Sheet`; all spreadsheet semantics remain in `src/lib`.

## Build log

- Wrote `PLAN.md` before code, copied the shared build-off config files, and created contract-focused Vitest tests first.
- Confirmed the initial RED state: `npm test` failed because `../src/lib/engine` did not exist.
- Implemented `refs.ts` for normalization, column conversions, and range expansion.
- Implemented `parser.ts` as a small recursive-descent parser with right-associative exponentiation and reference extraction for dependency tracking.
- Implemented `evaluator.ts` with lazy `IF`, numeric aggregation, empty-reference-as-zero arithmetic behavior, and error propagation.
- Implemented `engine.ts` with direct dependencies, reverse dependents, downstream affected-set traversal, DFS cycle marking, and topological recomputation only within the affected set.
- Added a DOM-based 100×100 grid UI, formula bar, keyboard navigation, error styling, and optional `window.__buildoff` hook.

## Verification

- `npm test` passed: 6 tests.
- `npm run build` passed and emitted `dist/` with a ~4.43 kB gzipped JS bundle.
- `npm run lint` initially caught one parser constant-condition loop; replaced it with an explicit loop flag.
- Final full contract passed: `npm ci && npm run build && npm test && npm run lint`; `dist/` exists.

