Skip to content

solve-engine 1.2.0

Choose a tag to compare

@LiamRiddell LiamRiddell released this 24 Aug 17:49
· 26 commits to main since this release
633b4d6

A minor release. Four things a running note of numbers can now do in place: split a bill, keep a running total, work a savings goal backwards, and total lines by category tag. Every addition is a phrase that reads the way the note is already written, and each names the boundary it deliberately does not cross.

Splitting a bill

split <amount> between <N> and <amount> split <N> ways answer "X each", in either spelling. A tip written as a percentage composes on the same line, since $120 + 18% is already an exact $141.60 before the split divides it.

split $120 between 3         $40.00 each
$120 split 3 ways            $40.00 each
$120 + 18% split 3 ways      $47.20 each

The boundary is the odd penny. split $100 between 3 is not a bare $33.33 each that quietly loses a penny: the extra penny is named, and the shares add back to the total to the cent.

split $100 between 3         $33.33 each, with 1 share paying $33.34

Money stays exact, a bare number splits to a bare number, and split, ways and people are read as the split grammar only inside the full shape, so :split = 5 and a variable named split keep working.

Running totals

A named variable could be assigned but not updated: each new total had to be written out in full. += and -= turn a note into a live ledger, where each line adjusts a balance in place.

:budget = 500
budget -= 120     380
budget -= 63      317
budget            317

A first += or -= on a name not yet set starts it at zero, so a ledger can open straight into spent += 10 rather than an undefined-variable error. The accumulation runs through the engine's own arithmetic, so money stays money and a unit stays its unit, and the right-hand side keeps its own precedence (budget -= 1 + 2 subtracts three).

A running total is re-seeded on every re-evaluation, so a note that opens spent += 10 reads the same total no matter how many times the document is re-parsed (a host re-parses on each keystroke) or a line is edited: the total is reset to its seed at the start of each pass and rebuilt from the ledger, rather than reading its own previous value and growing without bound. The boundary is the colon grammars: the compound forms apply to bare names, not :name or global :name, and += and -= are punctuation, so they never shadow an ordinary word.

Savings goals

The saving maths already ran forwards. It now runs backwards too, answering the two questions a savings note actually asks: how long a goal takes at a given contribution, and what contribution a deadline needs.

how long to save $10,000 at $500 monthly        20 months
how much per month to save $12,000 in 2 years   $500.00

An optional annual rate compounds over the term, so how much per month to save $12,000 in 2 years at 6% is $471.85, less than the flat $500.00, because the interest does part of the work. The period reads in the natural place (monthly, a week, in 2 years), and the words stay ordinary everywhere else.

Category tags

A running note often groups its numbers by hand, a shopping list or a set of expenses scattered down the page. A mid-line #tag labels a line's category and is dropped from that line's own result, and the aggregates gather every line carrying the tag, wherever they sit.

40 + 15 #grocery      55
petrol this week
30 #transport         30

12.50 #grocery        12.50
total of #grocery     67.50

sum of is a synonym for total of, and average of and count of read the same set. The boundaries are deliberate: a tag that is a line's first token is a heading, not a figure; the match is on the whole tag, so #housing does not gather #housingcost; total and average need numbers, while count is about presence, so it counts a non-numeric tagged line too. A tag name starts with a letter, which keeps it clear of the colour literals (#c0ffee is a colour, not a tag). Like line references, these forms only work inside a document, since they read other lines.

Verification

  • One regression spec per feature: bill split (16 cases), running totals (11 for the grammar, 9 at the lexer, and 5 for re-evaluation stability across re-parses and an in-place edit, on both the batch and the incremental evaluators), savings goals (12), and category tags (21, plus 7 for the pure tag scanner).
  • A cross-feature review of the merged surface before this release caught one blocker, the running total reading its own previous value on re-evaluation, now fixed and pinned by the stability spec above. Two narrower findings are tracked for a later release (#197, #198).
  • 7,784 tests across 343 suites, no failures.
  • npm run verify green, and the publish itself runs assert-release-tag, verify and test:consumer against the packed tarball before anything reaches the registry.