| name | engine-refactor |
| description | Refactor and extend the deterministic calculation engine while preserving correctness and explicit domain boundaries. |
engine-refactor skill
Use this skill for any work in src/engine/ — tokenizer, parser, AST, resolver, evaluator, formatter, conversions, table system, timezone handling, or diagnostics.
Companion files — read these too
.codex/skills/engine-refactor/engine-file-map.md — every engine file with its role and key exports
.codex/skills/engine-refactor/engine-patterns.md — concrete code patterns, type conventions, anti-patterns
Core rule
The deterministic engine is the source of truth for all final results.
Never move arithmetic, conversion, date math, or validation logic into AI, UI, or Tauri layers.
Pipeline order
raw text line
→ tokenizer (tokenizer.ts)
→ parser (parser.ts facade → parser.expression-tree.ts)
→ AST (ast.types.ts)
→ resolver (resolver.ts) — variable references
→ evaluator (evaluator.ts facade → evaluator.*.ts sub-modules)
→ formatter (formatter.ts) — value → display string
→ CalculationLine (line.types.ts) — per-line result for UI
For table blocks, the orchestration path is:
raw text block
→ document-scanner.ts (classify @table lines)
→ table-orchestrator.ts (full table evaluation)
→ table-parser-helpers.ts (row/cell parsing)
→ evaluator sub-modules (cell expressions via EvalContext)
→ TableBlockAnalysis (table.types.ts) — result for UI + export
Domain boundaries — never cross these
src/engine/ imports nothing from src/features/, src/app/, or src-tauri/.
- Engine files are pure TypeScript — no React, no Tauri
invoke, no window.*.
- All engine types flow outward to features, never the reverse.
- The public surface is
src/engine/index.ts — analyzeDocument() and createEvalContext().
Required workflow
- Read
engine-file-map.md to locate the right file before editing.
- Read
engine-patterns.md for the expected code patterns.
- Inspect the specific engine file(s) you will change.
- Preserve all existing
ValueKind and EngineErrorCode values — removing them is a breaking change.
- Add new error codes to
src/engine/types.ts — never use raw string literals for errors.
- Prefer pure functions — if a helper needs state, pass it explicitly.
- After changes:
npm run typecheck && npm run build.
- Update
docs/ENGINE_SPEC.md for any behavior or API change.
Constraints
- Never use
eval or Function constructor.
- Do not add unit tests unless explicitly requested.
- Do not couple engine code to React, Zustand, or Tauri.
- Do not break the
analyzeDocument() public API signature without updating all callers.
- Engine functions that return errors must use
EngineErrorCode from src/engine/types.ts.
EvalContext mutation (variable bindings, aggregates) happens only in eval-context.ts.
Docs to update
docs/ENGINE_SPEC.md — for any behavior, API, or error-code changes
docs/ARCHITECTURE.md — for structural/boundary changes
docs/SYNTAX_REFERENCE.md — for language syntax changes
docs/STATUS_GAP_ANALYSIS.md — when gaps are resolved