AmberCalc: columnar spreadsheet
First-party on-device program #7 (ADR-0042).
Implementation status (GWP-752). Every operation in the Tier-2 summary is built and driven from the keyboard: entry, cell/range references, the aggregate floor, recalculation, typed columns (INFO), the per-column printers, sort/filter (LINK / EQ), cell editing (QUOTE), clearing and cancelling (NIL), CAR-drill with a BACK nav stack, GoTo, and the ADR-0035 trackpoint handlers. Two things remain deliberately open, both flagged in Tier 3: signed-relative coordinates (
@-1$0) are still absolute-only in the parser, and the hledger-style query language is still the tracked ownership question — the filter mechanism exists and would drive it. v1.1 | 2026-07-18
Canonical per ADR-0042. This spec resolves the design stub’s four open questions to the v1 design taken with Josh on 2026-06-25 (see the design doc
../../plans/2026-06-25-ambercalc-blackledger-design.md(deleted 2026-07-29; recover from git history) §3 + Appendix A). The formula model and the:world/dossier-commitFFI surface it leans on are formalized in the AmberCalc formula/FFI ADR (ADR-0049); where this and that ADR disagree, the ADR wins. See the program roster.
Tier 1 — Treatment
Section titled “Tier 1 — Treatment”Gate: draft (stub). Basics from the ADR-0042 charter and the Tier 2 spec; the treatment pass has not been written and this stub invents no design.
The hook
Section titled “The hook”The deck’s columnar spreadsheet: the generic, always-on, content-free analytics lens (the VisiCalc / ses.el floor). A calculator over a table, where “type the money column and the data comes alive.” Its headline tenant is forensic accounting (the Black Ledger cart), but AmberCalc knows nothing about accounts or fraud; it crunches whatever table the world region holds.
What the operator does
Section titled “What the operator does”Navigate a grid by cell cursor, type a column to turn dead text into sortable / summable data, write a formula in host Lisp, and export a finding to DOSSIER. The repeating decision: which column to type and which cell to dive next in the hunt for the anomaly.
Owed to the treatment pass.
Feasibility verdict
Section titled “Feasibility verdict”- Reuses: the host Fe evaluator (formulas are Lisp, ses.el-style), the canonical cell grid, the trackpoint cart-FFI, the World Engine’s dataset region, and the sanctioned
dossier-commitpath. - New surface required: the SES formula model over cell coordinates, formalized in ADR-0049.
Open questions
Section titled “Open questions”- Deferred to the tiers below (see Open / deferred in Tier 3).
Tier 2 — Operator spec
Section titled “Tier 2 — Operator spec”Gate: approved (the v1 design; merged through PR review).
Identity
Section titled “Identity”AmberCalc is the deck’s columnar spreadsheet: the generic, always-on, content-free analytics lens (the VisiCalc / ses.el floor). It is a calculator over a table: a grid, a cell cursor, formulas, recalc, typed columns, sort/filter, and a sanctioned export to DOSSIER. It ships in the system image and runs bare on an empty world; it is never superseded by a cart.
Like every first-party program, AmberCalc is a lens and a cart supplies the world it looks at (enrichment-contract.md §1). Its headline tenant is the forensic-accounting domain: Black Ledger (cart 0x03) hands AmberCalc a generated shell-company ledger and overlays the FORENSICS vocabulary on the navigable grid AmberCalc returns. But AmberCalc is content-free: it knows nothing about accounts, double-entry, or fraud (see What AmberCalc does NOT own). It crunches whatever table the world region holds.
Operations summary
Section titled “Operations summary”| Operation | How |
|---|---|
| enter a value / label / formula | first-keystroke type routing (digit / " / () |
| reference a cell / range | (cell @r$c) / (range @r$c @r$c) in a formula |
| aggregate | sum / avg / min / max / count over a range (host Fe builtins) |
| type a column | $ currency · @ date · # int: turns text into sortable/summable data |
| display | per-column printer (currency / date / acct / raw) |
| navigate | CAR / CDR / BACK · GoTo @r$c · trackpoint aim+click |
| ingest a dataset | :world handle from launch-app (live region) |
| export a finding | (dossier-commit <key>): sanctioned fact-node, never a raw write |
What AmberCalc does NOT own
Section titled “What AmberCalc does NOT own”AmberCalc is a calculator over a table. It does not own:
- Accounts. The colon-path account namespace is the world the cart installs, not an AmberCalc concept.
- Double-entry. The zero-sum invariant, elided-amount inference, register-vs-balance lenses are Black Ledger’s ledger model.
- Fraud / forensics. TRACE, FLAG, CROSS/RECONCILE, CHAIN, reconcile-by-assertion, scoring, the verdict: all are the cart’s FORENSICS grammar overlaid on AmberCalc’s grid.
- Missions / economy. Contracts, the objective graph, the move budget / case clock, credits / reputation / mastery, threat caps. AmberCalc emits no economy events; durable consequence is the cart’s via the sanctioned outcome path.
AmberCalc gives the table a navigable, typed, formula-bearing surface; the cart gives the table meaning. (Black Ledger’s design is specified separately in ../cartridges/modules/black-ledger.md.)
Tier 3 — Detailed design
Section titled “Tier 3 — Detailed design”Gate: approved (the v1 design; merged through PR review).
Implementation seam (GWP-608 / GWP-614): file names, FFI signatures, coordinate/formula grammar, and ADR contracts appear from here down.
The grid
Section titled “The grid”- Renders on the canonical 128×75 surface (see the Canonical Hardware Specification). Content draws on Rows 1–73; Row 0 (firmware status bar) and Row 74 (firmware action bar) are firmware-owned and never drawn by AmberCalc. Grid dimensions are runtime-queried via the cell-API getters (
(cell-cols)→ 128,(cell-rows-usable)→ 73), not hard-coded. - Per-region integer scale (per the animation / scale convention): a dense transaction table renders at 1× (≈73 body rows visible), column headers at 2×. Exact per-region scale figures are an on-glass tuning detail (deferred; see Open / deferred).
- One cell cursor. Movement is by CAR/CDR navigation (descend / next sibling) and by trackpoint (aim + click; see Navigation).
- GoTo over scrolling. For large grids, jump-by-coordinate to a target cell is the primary long-distance motion; scrolling follows the cursor. This is the chord-scarce-friendly idiom (jump, don’t page).
Coordinates: all-numeric @row$col
Section titled “Coordinates: all-numeric @row$col”AmberCalc adopts Org-mode’s @row$col addressing, not A1.
- All-digit:
@3$2is row 3, column 2. “Which letter is column 28” is hostile on a digit-first keyboard with a small glyph set;@r$cparses trivially and reads naturally on the digit pad. - Signed-relative is the relative form:
@-1$0is the cell directly above the current cell; absolute (@3$2) is the default. - Ranges are
@r$c..@r$c: e.g.@2$1..@4$3is the 3×3 block from row 2 col 1 to row 4 col 3.
Formula language: host Fe sexp, SES model (resolves stub Q1)
Section titled “Formula language: host Fe sexp, SES model (resolves stub Q1)”Formulas are KEC Lisp expressions, not a bespoke mini-DSL. On a machine that already tree-walks Fe, the spreadsheet is a Lisp environment, exactly as ses.el is to Emacs:
-
A cell is a bound symbol.
(cell @3$2)resolves the value stored at that coordinate; a cell’s formula is an ordinary Fe expression evaluated in an environment where coordinate symbols are bound to cell values. -
A range is a real Lisp list.
(range @2$1 @4$1)evaluates to the list of values in that span, so the aggregate functions are just function application over a list:(sum (range @2$1 @4$1)),(count (range …)),(map …)are not special syntax. -
The aggregate floor (the 47-year VisiCalc set) is exposed as ordinary Fe builtins:
sum,avg,min,max,count, plus arithmetic (+ - * /) andif. Anything else an operator can write as Lisp is available; the formula surface is the host language, not a fenced subset. -
First-keystroke type routing (the universal spreadsheet idiom) decides cell intent from the first character typed, eliminating a “is this text or a value” mode:
First keystroke Cell becomes a digit ( 0–9)a number "a label (literal text) (a formula (an Fe expression)
Because formulas are host Fe, the spreadsheet inherits the deck’s existing evaluator, REPL inspectability, and macro/lambda recording for free: a column’s formula can be recorded once and replayed, scripted, or inspected at the TERM prompt.
Value / display split: per-column printers
Section titled “Value / display split: per-column printers”Stored value ≠ rendered glyphs. As in ses.el, a column carries a printer function that maps the stored value to its on-screen representation:
| Printer | Renders |
|---|---|
currency | right-aligned amount with a thousands separator (and the currency glyph) |
date | ISO date (YYYY-MM-DD) |
acct | colon-path account string (Shell:Cayman:Holdings:042) |
raw | the value verbatim, no transform |
The printer is display only: sorting, filtering, and aggregation operate on the stored value, never the rendered string. This is how “type the money column and the data comes alive” works, and it satisfies the screen-design rule that numerics right-align to a consistent column and never truncate.
Typed columns (the analysis unlock)
Section titled “Typed columns (the analysis unlock)”Borrowing VisiData’s typed columns: typing a column turns dead text into sortable / summable data. Applying a type both sets the column’s stored interpretation and selects its printer:
| Type | Sigil | Effect |
|---|---|---|
| currency | $ | text → money values; currency printer; sortable / summable |
| date | @ | text → dates; date printer; sortable / range-filterable |
| int | # | text → integers; raw/numeric printer; sortable / summable |
Typing a column (a single keystroke on the column) is the first satisfying beat of any investigation and the precondition for sort / filter / aggregate over that column.
Dataset ingestion: :world handle, not :payload blob (resolves stub Q2)
Section titled “Dataset ingestion: :world handle, not :payload blob (resolves stub Q2)”AmberCalc reads its dataset through the :world handle, not a :payload snapshot. A generated shell-company ledger (or any non-trivial dataset) is large and live: exactly the case the enrichment contract reserves for :world (a handle to the cart-installed mission-data region), not a copied :payload blob (enrichment-contract.md §3–§4):
(launch-app :ambercalc :world ledger-topology ; handle to the live mission-data region (the ledger) :payload '(:view register :threat 3)) ; small params only: initial view, scale:worldis the dataset. AmberCalc reads and navigates the region live: a node a cart reveals stays revealed, and AmberCalc sees mission-state changes as they happen. The mission-data region is run-state, never durable: it resets at the mission-instance boundary, and nothing AmberCalc does to the region touches UDS.:payloadcarries only small launch parameters: the initial view, the display scale, a threat level, never the dataset itself.
Supersession (explicit). This supersedes the walkthrough/stub shorthand
(launch-app :ambercalc :payload ledger-dataset), which passed the whole dataset as a payload blob. That framing contradicted the enrichment contract’s:payload(small params) /:world(live region handle) split; the dataset now arrives via:world, and the stub’s:payloadopen question is closed. A program launched bare (no cart context) gets the empty/default world and still runs; enrichment never gates (ADR-0042).
Export to DOSSIER: fact-node via dossier-commit (resolves stub Q3)
Section titled “Export to DOSSIER: fact-node via dossier-commit (resolves stub Q3)”A “finding” is a DOSSIER fact-node, not a free write. AmberCalc (and the Black Ledger vocabulary on top of it) never raw-writes DOSSIER; it calls the sanctioned (dossier-commit <key>) primitive and the engine refiles the fact under the matching profile (enrichment-contract.md §5–§6, dossier-data-model.md §4). This is the same sanctioned-write boundary mission outcomes use (ADR-0040 §6): durable consequence happens only through key emission, never through touching the world region.
A finding carries the canonical fact-node fields (dossier-data-model.md §3):
| Field | What AmberCalc supplies |
|---|---|
:key | the typed, addressable key id: e.g. acct:shell:caribbean-trust:beneficiary |
:value | the datum (the amount, the account, the name) |
:prov | provenance: (:mission … :via ambercalc :phase analyze) |
:conf | confidence: :rumored / :inferred / :verified, set by trace depth |
:links | typed edges: :routes-to, :owns, :contradicts, … |
dossier-commit lands the fact in the DOSSIER inbox; the engine auto-refiles it under the profile its :key type names (or holds it for the operator to refile). AmberCalc cannot create profiles or write canonical intel directly: it reports a discovery and the engine commits it.
Navigation
Section titled “Navigation”- CAR / CDR: keyboard cell motion. CAR descends into the head (drill a cell / a reference), CDR moves to the next sibling (next cell / row), BACK ascends (pop the nav stack). These reuse the canonical Lisp-primitive key semantics verbatim, so AmberCalc cell-diving and Black Ledger account-tracing share the same dive/pop core.
- GoTo: jump-by-coordinate (
@r$c) for long-distance motion on large grids, in preference to scrolling. - Trackpoint: aim the cursor at a cell or column and click to dive (VisiData’s two-cursor feel), complementing CAR/CDR. AmberCalc consumes the v0.1 trackpoint cart-FFI per ADR-0035:
(cursor-position)to read the cell under the cursor,(on-trackpoint-move …)to react to cell crossings,(on-trackpoint-click …)to react to a click. The cursor is in cell coordinates on the main grid and is clamped to the content area (Rows 1–73): it never lands on the firmware-owned Row 0 / Row 74. v0.1 is a single merged cursor with a primary click; per-pointer differentiation is deferred (ADR-0035 / ADR-0032 v2).
Interfaces
Section titled “Interfaces”- Launch:
(launch-app :ambercalc :world <region-handle> :payload '(:view … :scale …))— NoshAPI Tier 1 (ADR-0005, amendment 2026-06-21).:worldis the live mission-data region (the dataset);:payloadis small params only. - Export:
(dossier-commit <key>)— sanctioned fact-node deposit (ADR-0005, amendment 2026-06-21). - Trackpoint:
(cursor-position)/(on-trackpoint-move h)/(on-trackpoint-click h)— cell-coordinate cursor on Rows 1–73 (ADR-0035). - Display: draws on the cartridge/content rows (1–73) per the canonical grid; grid queried via the cell-API getters.
- Authored in KEC Lisp. Program source lives at
runtime/programs/ambercalc/(ADR-0042 Decision-5).
Open / deferred
Section titled “Open / deferred”- Grid scale figures. Exact 1× vs 2× per-region scale (rows/columns visible at each) is an on-glass tuning detail (the stub’s Q4); deferred to bring-up.
- Query language ownership. Whether AmberCalc exposes a first-party hledger-style filter language (
amt:>N,status:,acct:) or Black Ledger contributes it as cart vocabulary on top of the grid. Tracked with the Black Ledger spec. assert-balance/ reconcile-by-assertion. The win mechanic and its exact FFI signature live in Black Ledger, not AmberCalc; AmberCalc only provides the navigable typed grid the cart asserts against.
Migration notes
Section titled “Migration notes”- 2026-07-18 tier migration: content re-cut under tier headings from the v1 design; no mechanics changed. Grid-scale/formula/coordinate detail moved behind the Tier 3 implementation seam; the identity and operations summary stayed at Tier 2. No design drift against ADR-0049 / ADR-0005 was found.
References
Section titled “References”../../plans/2026-06-25-ambercalc-blackledger-design.md(deleted 2026-07-29; recover from git history) §3 + Appendix A — the v1 design + TUI-spreadsheet research grounding (ses.el / Org-mode / VisiData / ledger-cli).enrichment-contract.md— lens / world /:world-handle /dossier-commitcontract (§3–§6).dossier-data-model.md— the fact-node schema a finding commits as (§3–§6).../cartridges/modules/black-ledger.md— the forensic-accounting cart that enriches AmberCalc.../runtime/baselines/audit.md— the:auditmission baseline (the bare transaction generator Black Ledger supersedes).- ADR-0042 — the thirteen first-party programs; carts enrich, never gate.
- ADR-0005 — NoshAPI (
launch-app,dossier-commit; amendment 2026-06-21). The AmberCalc formula/FFI ADR (ADR-0049) amends this surface for the SES formula model. - ADR-0035 — trackpoint cart-FFI (cursor-position / on-trackpoint-move / on-trackpoint-click, content-rows clamp).
- ADR-0040 — the UDS sanctioned-write boundary
dossier-commitrespects.
Inspirations
Section titled “Inspirations”Assigned by Josh in the kn86-inspo workbench. Full map: cart-inspiration-map.md.
| Source | Category |
|---|---|
| VisiCalc (1979) | spreadsheet |
| VisiData | spreadsheet |
| csvlens | spreadsheet |
| l123 | spreadsheet |
| sc-im | spreadsheet |
| sheetsui | spreadsheet |