# Sheet Engine Build Plan

## Goals

- Deliver a Vite + TypeScript + Vitest mini-spreadsheet that satisfies the exported engine contract in `src/lib/engine.ts`.
- Prioritize hidden-test correctness for parsing, dependency tracking, incremental recalculation, circular references, and error propagation.
- Keep the UI useful but lightweight: a 100 x 100 grid with keyboard navigation, formula editing, and visible errors.

## Architecture

- `src/lib/refs.ts`
  - Pure cell-reference helpers: column conversions, canonicalization, parsing absolute refs, range expansion, and coordinate validation.
- `src/lib/parser.ts`
  - Tokenizer and recursive-descent parser producing a small AST.
  - Operators: unary `+/-`, `^` as right-associative, `* /`, `+ -`, comparison operators for `IF` conditions, parenthesized expressions, refs, ranges, strings, booleans, and function calls.
- `src/lib/evaluator.ts`
  - Pure AST evaluator that resolves references through a sheet callback, coerces empty cells to `0` in arithmetic, implements `SUM`, `AVERAGE`, `MIN`, `MAX`, `COUNT`, `IF`, and a few stretch helpers.
  - Represents errors as string codes and propagates them consistently.
- `src/lib/graph.ts`
  - Directed dependency graph from formula cells to precedents and reverse dependents.
  - Updates only changed formula edges after `Sheet.set`.
- `src/lib/engine.ts`
  - Public acceptance-contract module.
  - Owns cell records, parser cache, graph, dirty-cell scheduling, and circular-reference detection.
  - `set()` updates one raw cell, rebuilds its direct dependencies, then incrementally recalculates only the edited cell and its downstream dependents in topological order.
- `src/app.ts`, `src/main.ts`, `src/styles.css`
  - DOM UI for a 100 x 100 grid, formula bar, selected-cell indicator, keyboard navigation, edit commit/cancel, copy/paste input behavior, and the optional `window.__buildoff` perf hook.
- `tests/`
  - Vitest suites for references, parser/evaluator behavior through `Sheet`, functions/ranges, errors/cycles, and incremental recalculation instrumentation.

## Libraries

- Runtime dependencies: none beyond browser APIs. This keeps bundle size small and avoids dependency risk.
- Dev dependencies: `vite`, `typescript`, `vitest`, `eslint`, and the packages required by the shared ESLint config if necessary.
- No spreadsheet parser library: the brief rewards parser/AST/evaluator separation, and a hand-written recursive-descent parser is small enough for this scope.

## Recalculation Approach

- Store each cell as `{ raw, formula, ast, value, error, deps }`.
- On `set(ref, content)`:
  1. Canonicalize the ref.
  2. Parse formula content if it starts with `=`, otherwise store a literal value.
  3. Extract direct precedents from the AST, expanding ranges.
  4. Update graph edges only for that edited cell.
  5. Recalculate the edited cell plus transitive downstream dependents.
- Scheduling:
  - Collect affected downstream cells with BFS over reverse edges.
  - Detect cycles in the affected subgraph with DFS recursion state. Cells in cycles get `#CIRC!`.
  - Topologically evaluate non-cyclic affected formula cells by visiting precedents before dependents.
  - Literals evaluate immediately and do not force unrelated formulas to run.

## UI Approach

- Render fixed row and column headers plus a 100 x 100 CSS grid of buttons/inputs.
- Keep DOM stable: one element per cell is acceptable for 10,000 cells when using event delegation and CSS grid.
- Track selected cell and editing cell in app state; commit edits on Enter/Tab/blur and navigate with arrows.
- Update only visibly affected cells after an edit by asking the engine for downstream dependents and refreshing those DOM nodes.

## Risks and Mitigations

- Hidden tests may expect strict spreadsheet semantics. Mitigation: implement documented semantics first, plus pragmatic comparisons and string/boolean literals without overextending.
- Circular references can be indirect or introduced after prior valid formulas. Mitigation: run cycle detection on every affected recalculation and overwrite involved values with `#CIRC!`.
- Incremental recalculation may accidentally skip transitive dependents. Mitigation: graph exposes reverse dependencies and tests cover downstream chains and fan-out.
- Shared ESLint config may require extra packages. Mitigation: inspect and install exact dev dependencies after copying configs.
- Large engine files could hurt cleanliness. Mitigation: split parser, evaluator, refs, graph, and UI into focused modules.
