Files
calctext/_bmad-output/implementation-artifacts/1-8-sheet-context.md
2026-03-16 19:54:53 -04:00

2.2 KiB

epic, story, title, status
epic story title status
1 1.8 Sheet Context draft

Epic 1 — Core Calculation Engine (Rust Crate)

Goal: Build calcpad-engine as a standalone Rust crate that powers all platforms. This is the foundation.

Story 1.8: Sheet Context

As a CalcPad engine consumer, I want a SheetContext struct that holds all evaluation state including variables, line results, and dependency graphs, So that multi-line sheets are evaluated correctly and undo/redo is cheap.

Acceptance Criteria:

Given a new SheetContext is created via SheetContext::new() When it is inspected Then it has no lines, no variables, and an empty dependency graph

Given a SheetContext with ctx.set_line(0, "x = 10") and ctx.set_line(1, "x * 2") When ctx.eval() is called Then it returns a Vec<CalcResult> of length 2 And the first result is 10 and the second result is 20

Given a SheetContext where line 0 defines x = 10 and line 2 references x When line 0 is changed to x = 20 and ctx.eval() is called Then line 2 is re-evaluated and reflects the updated value x = 20

Given a SheetContext with established state When it is cloned via ctx.clone() Then the clone is a deep copy that can be modified independently And the clone operation is cheap enough for undo/redo snapshots (sub-millisecond for 100-line sheets)

Given a SheetContext with a dependency graph where line 3 depends on line 1 When only line 1 is modified Then the engine re-evaluates line 1 and line 3 but skips lines that are not in the dependency chain And unchanged, independent lines are not recomputed

Given a SheetContext where a circular dependency is introduced (e.g., line 1 references line 2 and line 2 references line 1) When ctx.eval() is called Then both lines return CalcResult::Error with a circular dependency message And the engine does not enter an infinite loop

Given a SheetContext with lines that include aggregator references such as total or sum When ctx.eval() is called Then the aggregators compute over the appropriate preceding lines And the dependency graph correctly tracks which lines feed into each aggregator