release history

What's changed

Every version, newest first, straight from CHANGELOG.md — the same file the repo keeps. The oldest entries are collapsed; the newest is open.

v0.12.02026-09-25The hot-path release.

Added

  • **Hot-path panel** — the playground's new readout shows where the recorded run spent its steps: the ten hottest instructions ranked by executed count with each one's share of the window (operands from its first execution), plus a call-stack-depth sparkline whenever the program called anything. `instructionHeat` and `stackDepthSeries` in `cfg.ts`, with tests pinning the rankings, the shares, and CALL/RET nesting.
  • **Walkthrough export** — story mode can copy the captured run as markdown: every notable beat with its narrator's sentence and the machine-state line (registers, SP, SIGN, OVF). `storyToMarkdown`, tested.
  • **Why balanced ternary?** (`/why`) — the case for three states per digit: a live digits-vs-values slider showing how far 3ⁿ outruns 2ⁿ, balanced rounding's centered digit set, the sign that lives inside the digits, and history notes on Setun.
  • **Printable ISA cheat sheet** (`/cheat`) — the whole instruction set on one print-ready page: syntax, opcode, and effect per category, the flags contract, and the rounding rule. A print-only stylesheet inverts the dark theme to ink on paper; the spec's instruction-set section links it.
  • **Two new examples** — "Sort three values" (a swap network ending ascending at addresses 100..102) and "First prime after 10" (trial division with REM — 11 is prime, sent out after a full sweep).
  • **Two new practice generators** — "divide-and-round" and "shift-by-one" shuffle cards join the random-add card in the labs, each seeded so "new numbers" remounts a fresh quiz.

Notes

  • 9 new tests across the batch (342 total). CI now smoke-checks the built server: `scripts/smoke.mjs` against the built worker served by `wrangler dev` — all 11 routes must return 200 with their expected `<title>` and a real body.
v0.11.02026-09-17The ISA sandbox release.

Added

  • **Parameterized word core** — `trits.ts` builds any width's geometry via `createWord(n)`: ring sizes (3ⁿ states, ±(3ⁿ−1)/2), wrap, trit conversion and formatting, with every existing export delegating to the default 6-trit `WORD6`. 40 property tests round-trip every representable value at widths 3–9 and pin the ring laws.
  • **Word lab** (`/lab`) — pick 3–9 trits and the number system reshapes: a width-aware trit dial and number ring (ticks downsampled so a 9-trit ring stays light), the "what fits" table with the wrap spelled out ("100 exceeds ±121 — wraps to −43"), an interactive wrap calculator, a count-to-the-top counter, and an assemble & run sandbox that validates literals and addresses against the selected width.
  • **Word-threaded machine and assembler** — `new Machine(word)` and `assemble(source, origin, word)`: every bound (memory size, addresses, SP, value/address/`.word`/label ranges) derives from the width, with the legacy 6-trit behavior byte-identical (every prior test untouched).
  • **Spec at any width** — `/spec`'s "specified word" selector reshapes the number-system facts, machine-word fields, SP, memory, and the instruction benches — whose narration speaks the width's own ring ("exceeds ±121").
  • **Compare two widths** — the lab runs one literal-free Fibonacci program against two rings side by side, annotating each output's wrap point ("11 values before the wrap — the term after 89 no longer fits ±121").
  • **Width-sensitive labs** — "The 4-trit machine" (10 × 10 wraps to 19 in the 81-state ring — the literal 100 is illegal) and "The 5-trit address" (address 900 lives at −72 when addresses are five-trit words).

Notes

  • 53 new tests across the five phases (333 total). The existing eleven lessons, the examples, and every pre-sandbox page stay pinned to the 6-trit machine by design — the sandbox is additive, never a retrofit.
v0.10.02026-09-17The program anatomy release.

Added

  • **Control-flow graph panel** — the playground draws the program's static graph: instructions as nodes, fall-through edges below, jumps and calls as arcs above. Executed edges render in primary with thickness proportional to how often the recorded run took them; never-taken edges are dashed; instructions that never ran are dimmed with a coverage list in the footer. Clicking a node rewinds the storyboard to that instruction's first execution.
  • **CFG engine** (`src/lib/ternary/cfg.ts`) — `buildCfg` extracts the graph from the assembler's instruction map (per-opcode edge semantics, HALT/RET terminals, no fall-through into `.word` regions); `executedEdgeCounts` weights the edges from the ledger, tallying RET's dynamic returns as off-graph.
  • **Call list & register spotlight** — the panel lists every call with how many times the run took it, and the storyboard can follow one register: rows that don't write it dim, so its life across the run stands out.
  • **Find-the-bug labs** — three new lessons where exactly one instruction is wrong: the extra zero (JEQ vs JGT keeps the countdown running at 0), the sign flipped (JGT vs JLT sends the negatives), the stubborn zero (ADD R1, R2 doubles nothing). Machine-checked like everything else — eleven lessons total.
  • **Random-add quiz** — a shuffleable "new numbers" card on the quizzes grid driven by a seeded generator (`randomAddQuiz`), so predictions can be practiced at volume; deterministic per seed.
  • **Editor ELI5 hover** — hovering an instruction line in the playground editor shows the opcode's ELI5 from the spec explorer; the newest OUT value in the I/O console pulses once when it lands.
  • **Learning path count** — the hub's labs station reports N/11 solved.

Notes

  • 12 new tests (280 total): CFG edge semantics and exact dynamic weights on real machines, the bug-lab pins, and the seeded quiz generator.
  • The bug labs are the first lessons where the objective is debugging, not building: the starter fails in an instructive way, and the hints talk about what the fault does rather than what to type.
v0.9.02026-09-17The watch-the-machine-think release.

Added

  • **Execution ledger** — every executed instruction records a `LedgerEntry` (step, address, operands, full register file, SP, flags, memory writes with wrapped values, IN/OUT values, errors) directly on the Machine; a 256-entry cap keeps runs at amortized O(1) per step, and restores truncate the ledger so it always describes what actually happened.
  • **Watchpoints** — `run()` takes conditional stops: stop when a register becomes a value (transition semantics — an already-equal value never retriggers) or when an address is written. The playground watch bar (register / memory kinds, add, removable chips) names the fired condition in the log, and a stopped run resumes like a breakpoint does.
  • **Write heatmap** — all 729 addresses as a grid colored by how often the recorded window wrote each one, with hover readouts.
  • **Step storyboard** — the ledger as a table with per-row deltas (registers, SP, SIGN, OVF, memory writes, I/O, errors); clicking a row rewinds the machine deterministically (reload + run forward), keeping the ledger, trace, ring, and datapath in step with where you are.
  • **Datapath dataflow badge** — a badge glides along the executed instruction's route on every step, carrying the value it actually moved (the result, the written word, SIGN, the branch target, I/O values); STORE travels registers → memory.
  • **Advanced labs** — four more machine-checked lessons on `/labs`, tier-tagged: `.word` tables with DIV/REM (the tie rounds away from zero), a max-of-table seek, factorial via CALL/RET, and catching the Fibonacci wrap by its sign (233).
  • **Predict-the-result quizzes** — five quiz cards on `/labs`: tiny program, one question (register, output, or OVF), graded reveal backed by the machine and the narrator's final beat. New engine module `src/lib/ternary/quiz.ts`.
  • **Learning path** (`/learn`) — the six stations in order with progress tracking: visited pages and the solved-labs count live in the browser; the shell records visits automatically.
  • **Keyboard shortcuts** — space = step, s = slow run, r = run in the playground (never fires while typing in the editor or a field).

Notes

  • All of the above is pinned: 22 tests added across the ledger, watchpoints, labs tiers, and quizzes (268 total), every lab starter still fails and every solution still passes on the real machine.
  • The dataflow badge animates client-side only, and STORE's route is the one place the datapath metadata's unit order is overridden.
v0.8.02026-09-14The guided labs release.

Added

  • **Guided labs** (`/labs`) — four scaffolded lessons that close the loop from the narrator and the spec explorer to writing code: a first program (load a constant, send it out), a countdown loop (SUB/CMP/JGT), a compare & branch filter over a real input stream (only positives pass), and a stack & CALL subroutine (double the input, return for the OUT). Each lesson has a plain-language objective with its I/O contract, a starter that compiles but fails the check, progressive "need a hint?" reveals, a revealable solution, and a goal the machine itself grades.
  • **`src/lib/ternary/labs.ts`** — the lesson catalog and checker: every lab's starter is pinned to FAIL and its solution to PASS through the real assembler and machine (no drift possible); failures come back as plain sentences ("output should be [3, 9], got [3, -7, 0, 9, -2]") alongside an output/register readout.
  • **Progress tracking** — solved labs persist per browser; lesson cards carry a "solved" tag.
  • **Labs contract tests** — catalog order, starter-fails/solution-passes, exact expected outputs for all four lessons, failure wording, and hint quality (6 tests, 246 total).

Notes

  • This completes the teaching arc: overview → converter → arithmetic tutor → spec explorer → narrator → story → labs.
v0.7.02026-09-14The story mode release.

Added

  • **Story mode in the playground** — capture the run, then replay it beat by beat: every branch decision, compare, overflow wrap, memory write, stack touch, I/O, halt, and error becomes a chip. Play/step through the beats (1.1 s apart), scrub by clicking any chip, or jump with ‹/› — each beat lands the machine on its exact state, narrated by the "what just happened" panel. Rewinds are deterministic: the machine reloads and runs forward rather than restoring state.
  • **`src/lib/ternary/story.ts`** — the story engine: `captureStory` runs the machine to the end (or a 25 000-step / 120-beat cap) collecting only the notable instructions, each with its snapshot and narration; deterministic by construction (a second capture is byte-identical).
  • **Datapath execution wave** — the lit units of the most recent instruction now flash in path order (mem → fetch → decode → unit) with a staggered CSS pulse, retriggered on every step.
  • **Changelog page** (`/changelog`) — every version's changes rendered straight from the repo's CHANGELOG.md, newest first with the older entries collapsed; the footer version links to it.
  • **Version pin in the footer** — the footer now shows the real app version (`v0.7.0`), injected from `package.json` by the vite config at build time (`src/lib/version.ts`); dev servers show `v0.0.0-dev` since the define doesn't pass through the dev transform.
  • **Story contract tests** — capture exhaustiveness (kinds for memory, stack, I/O, compare, branch, overflow, halt, error), beat ordering, determinism, and the step-limit path (8 tests, 235 total).

Notes

  • A changed input buffer or re-assembly drops the captured story — the beats would no longer match the run.
v0.6.02026-09-14The spec explorer release.

Added

  • **Interactive instruction explorer on `/spec`** — every row of the ISA table opens a live experiment bench: an ELI5 for the opcode, its constraint notes, and the instruction actually executing on a real Machine with values you can edit (registers, immediates, addresses, memory contents, SIGN for the branches). The bench shows the staged program, the before → after machine state (changed registers highlighted), the narrator's sentence, and any halt-with-error case.
  • **`src/lib/ternary/demo.ts`** — the worked-example engine: stages the operands for any opcode, runs the single instruction, and captures before/after snapshots + narration. Control-flow demos get two HALT targets so taken vs fall-through are distinguishable.
  • **`OP_GUIDES` in `explain.ts`** — the durable ELI5 home: one guide (plain explanation + constraint notes) per opcode, asserted to fully cover the ISA table so the explorer can never silently lack a card.
  • **Engine and content tests** — every one of the 36 opcodes gets a clean staged run (one step, no error, a narrator sentence); spot checks pin ADD 13+29→42, DIV rounding, JEQ taken/skipped, POP seeding, RET, and guide coverage (49 new tests, 227 total).
v0.5.02026-09-14The narrator release.

Added

  • **Step narrator engine** — `src/lib/ternary/explain.ts` turns any executed instruction into one plain-language sentence from before/after snapshots alone: "ADD R2, R3 — 13 + 29: R2 becomes 42 (+---0)." Arithmetic narrates the expression and says why an overflow wraps; CMP and branches spell out the SIGN and whether the jump landed; memory, stack, I/O, CALL/RET, power math (SHL/SHR, DIV/REM rounding), trit-wise LAND/LOR, and the machine's errors (division by zero, empty input, stack underflow) all get their own plain words. Batch runs collapse to a summary line that nudges toward single-stepping.
  • **Machine instrumentation** — snapshots now record the last executed instruction (`lastInstruction` with address and operands), so narration needs no caller plumbing.
  • **Playground "what just happened" panel** — the narrator speaks live under the step controls: one sentence per single step (and per slow-run step), a batch summary for runs, cleared on assemble, reset, and step back.
  • **Narrator contract tests** — 23 new tests pin exact sentences for every instruction family, including the wrap voice ("365 exceeds ±364, so it wraps"), the R0-write gotcha, branch taken/not-taken wordings, and error narratives.

Notes

  • Reading this release's sentences is also a tour of the flags contract: result ops, CMP, and the "everything else leaves flags untouched" rule are all stated out loud.
v0.4.02026-09-13The number converter release.

Added

  • **Number converter** (`/numbers`) — one integer shown in four spellings: decimal, binary, standard ternary, and balanced ternary. Every field is an input; typing in one converts the others, with strict per-base validation and place weights printed beneath short literals so the base pattern ("every digit multiplies a power of the base") is visible at a glance.
  • **Word dial + number ring on the page** — the existing TritDial and NumberRing components, driven live by the converter value inside the word range (−364..+364); out-of-range values get a plain explanation instead.
  • **Count in every base at once** — step (or run) a counter across 0..+364 and watch the bnary/ternary/balanced rows roll over together, including the balanced count's signature two-step per power of three (+, +-, +0, ++, +--), with the wrap to −364 flagged at the top of the ring.
  • **New engine module** `src/lib/ternary/convert.ts` — strict, safe-integer radix conversion (toRadix/fromRadix for bases 2 and 3, plus minimal-form balanced ternary parsing/formatting), pinned by 16 new contract tests (round-trips across ±1 234 567, fixed-digit word-form consistency, and validation rejections).

Notes

  • The converter accepts any safe integer; the dial, ring, and counter live in the machine's 729-value word range.
v0.3.02026-09-13The visualizations and modelling release.

Added

  • **Execution traces** — pick a register (or PC, SP, SIGN, OVF) and chart its value over the steps of a run; instruction-mix histogram aggregated by mnemonic with the live opcode highlighted. recharts-based panel, lazily loaded, downsampled to a 4 000-point cap, end-state always included.
  • **Live datapath diagram** — memory → fetch → decode → control with the ALU, registers, flags, stack, and I/O units; the path the most recently executed instruction took lights up, step by step.
  • **Number ring** — all 729 word values on a circle with the wrap seam at the top; the needle tracks the selected trace series and turns warn on overflow.
  • **Address-space map** — the 729-word memory to scale: program band, stack band, free span, live pc/sp ticks, and a collision overlay matching the machine's push() rule.
  • **Balanced arithmetic tutor** (`/arithmetic`) — step through ADD (carries and the digit rule), MUL (partials and running total), and NEG (trit inversion) column by column, with a result phase showing the wrap column and overflow. New pure engine module `src/lib/ternary/arithmetic.ts` powers it.
  • **Machine instrumentation** — `run(..., onStep)` hook, `opcodeCounts` histogram, `lastOpcode`, and `origin`/`programEnd` in snapshots.
  • **Controlled TritDial** — optional `value`/`onValueChange` props (backward compatible) for the tutor's dials.

Notes

  • recharts is now used (lazily loaded, playground-only chunk); chart colors mirror the CSS tokens as literal oklch values in `src/lib/chart-theme.ts`.
  • Step-back rewinds traces but the instruction-mix histogram may still include the single undone instruction (cosmetic).
v0.2.02026-09-13The correctness, ISA, and tooling release.

Fixed (logic review — 17 findings)

  • **CMP compares the unwrapped difference** — comparisons are exact across the full word range (364 vs −364 is positive).
  • **Standardized flags contract**: result-producing ops set SIGN/OVF via the stored value; CMP leaves OVF untouched; STORE/PUSH/branches/IN/OUT leave both untouched.
  • **Fetch, branch, and register validation**: PC writes are checked for alignment and image bounds; leaving the program image is an error, not a silent NOP-fallthrough; out-of-range register fields halt the machine; a failed fetch no longer executes a phantom NOP.
  • **Stack/program collision guard**; `load()` bounds checks; breakpoints on the first instruction now fire on Run.
  • **Assembler**: labels are case-insensitive (case-variant duplicates error); register typos (`R1X`, `RX`) report "invalid register" instead of a misleading "unresolved label"; unreachable literal branch removed.
  • **Playground**: reload keeps the editor and the running machine in sync; run-n clamps to [1, 200 000]; a step-limit stop hints at a possible infinite loop.
  • Dead code removed: unused shadcn/ui components (46 files), `formatCompact`, `REGISTER_NAMES`, an `OPS` re-export.

Added

  • **ISA v0.2, opcodes 26–35**: DIV/REM (round-to-nearest, ties away from zero; reg + imm variants), SHL/SHR (one-trit shifts), LAND/LOR (trit-wise min/max), IN/OUT (buffered I/O channel).
  • **`.word` data directive** — tables of literals or labels interleaved with instructions; `instructionAddresses` enables branch-into-data rejection.
  • **Debugger tooling**: step-back, stack pane, live disassembly pane, I/O panel, named presets in localStorage, `#src=` URL sharing, slow run with a Stop button.
  • **New examples**: "Divide with rounding" and "Ternary I/O echo".
  • **Vitest contract suite** (116 tests: trits, ISA table, assembler, machine, examples, share) and GitHub Actions CI (lint, typecheck, test, build).
  • Real README; CHANGELOG; `docs/LOGIC-REVIEW.md` and `docs/ROADMAP.md`; spec page → v0.2 with the flags contract, rounding rules, and I/O semantics.
v0.1.02026-09-12Initial release of the balanced ternary machine concept:

Changes

  • **Engine** (`src/lib/ternary/`): 6-trit words (−364..+364), 729-word memory, 26-opcode fixed 3-word ISA, two-pass assembler + disassembler + source map, synchronous step/run with breakpoints and flags (SIGN, OVF, HALT).
  • **Pages**: `/` overview with interactive trit dial, `/spec` architecture spec generated from the ISA table, `/playground` debugger with editor, register/memory panels, execution log, and breakpoints.
  • **Examples**: add, negate, loop multiply, countdown, Fibonacci, Fibonacci-with-overflow, factorial (CALL/RET).
  • **Platform**: dark instrument-panel design system, mobile-optimized layout, editor source persisted to localStorage, SSR error recovery.