ubb / Unique Business Basic Free report

Platform · How the runtime works

Written from scratch.Measured against yours.

UBB is four subsystems: an engine that executes your programs and owns your data files, a terminal layer that draws your screens, a SQL layer that reads those same files directly, and the cloud underneath it. None of it is a translation pass, a transpiler, or a wrapper around somebody else's product. It was written from the language definition and then measured against the runtime you use today until the two agreed.

The terminal isn't a detail of the runtime. It's a public interface.

Why most reimplementations fail here
The incumbent runtime passes terminal mnemonics through raw rather than translating them — so your programs were written against the terminal itself. We had to become the authority on rendering it.

atlas-prod-01 · 80×24 · UBB runtime

Three screens from the runtime: a native SQL console showing a key-indexed lookup returning in 2 milliseconds against a full scan of the same 1,344,450-record file at 3,665 milliseconds; a vendor lookup window drawn over a live purchase-order entry form; and a vendor maintenance screen showing the character-level field editor with dotted templates, insert mode and masked input.

Three example screens rendered by the UBB runtime.

Three of the hard parts: a key-aware SELECT straight against the ERP's own keyed files, a window drawn over a live form with character and attribute state saved underneath it, and the character-level field editor with its dotted templates and insert mode.

01 The engine

Lexer, parser, AST, evaluator. No shortcuts in the middle.

The front end reads your source and the evaluator executes it. Between those two things sit the parts that decide whether a distribution ERP gives the same answers tomorrow that it gave yesterday: the decimal model, the file format, and the error model. Each of them is matched to the incumbent rather than approximated.

Front end

Lexer, parser, AST, evaluator — all ours

Source becomes tokens, tokens become a syntax tree, the tree is executed. Written from the language definition, not lifted from anywhere. Against a real production corpus — 5,079 programs, 536,000 lines — the parse rate is 100%, including the forty-year-old parts nobody would write that way today. Multi-statement lines, line labels, tab-stop formatting and the punctuation-heavy idioms all survive the trip.

Arithmetic

Exact decimals, with the incumbent's rounding semantics

A per-value scale model carrying 16 significant digits, with the incumbent's PRECISION rounding applied where and when it applies. Not binary floating point, because this is financial software and the pennies have to match: half a cent of drift compounds across a 4,000-line invoice register and turns into a phone call from your controller. 245 of 245 arithmetic conformance cases are penny-exact against the incumbent runtime.

File I/O

The native keyed-file format, read and written directly

Multi-level B-tree indexed files and fixed-record direct files, opened in place — no conversion step, no import, no shadow copy. That means node splitting on insert, deletion with successor replacement, and free-list handling, all producing the same bytes on disk the incumbent would have produced. The largest file verified so far is 1,344,450 records, compared record for record rather than sampled. The write path is gated: what our engine writes has to read back byte-identical in the incumbent runtime before the change ships.

Program flow

Cross-program CALL and by-reference ENTER

A called program gets its parameters by reference with copy-in/copy-out semantics, so a subroutine that mutates its arguments behaves the way its author expected in 1991 — including the receiver-less case, where the callee shares the caller's variable scope outright. Get this subtly wrong and nothing crashes; a total is just quietly stale three programs downstream.

Error model

Error branching is matched, not approximated

SETERR, ERR=, DOM= and END= branch where they are supposed to branch — including the quirk where a branch to a line number that doesn't exist rounds up to the next line that does. Thirty years of programs use error branches as ordinary control flow: a missing record is a DOM=, end of file is a business event. "Nearly right" here means a nightly posting run finishes in the wrong place at two in the morning.

Where the manual and the runtime disagreed, we implemented the runtime. Documented behaviour is a starting hypothesis; the measured behaviour is what your programs were actually written against.

02 The terminal

This is where reimplementations fail.

Because the incumbent passes terminal mnemonics through raw instead of translating them, the terminal is not an implementation detail — it's an interface your programs target directly. Every one of these behaviours was captured off the real runtime and replayed against ours, character by character and attribute by attribute.

Full-screen forms

80×24 addressed by character position, with the cursor put exactly where the program asked for it. Fields, headings, totals lines and the status bar all land on the same rows they have landed on for thirty years.

Windows and POP, with a real screen model

Opening a window saves the characters underneath it and their attributes; popping it puts both back. Colour, reverse video and highlighting return exactly as they were, which is the part a naive redraw gets wrong the first time a lookup closes.

Scroll regions that actually confine

A defined region scrolls on its own and cursor addressing stays inside it, so a line-item pane scrolls while the header and the totals block above and below it sit still.

Per-terminal colour and box drawing

Colour configured per terminal type rather than hardcoded, and the line-draw character set resolved from the terminal's own description. Your green screens stay green; the boxes stay boxes instead of turning into rows of lowercase letters.

The character-level field editor

Dotted templates, insert mode, backspace, delete, home, end, and the field-exit rules that decide when a keystroke ends the field. This is the subsystem your users feel in their hands. Close enough is a retraining cost and a data-entry error rate.

Function keys and masked input

Per-terminal function-key maps, so F2 is still lookup and F4 is still prior on the emulator your branch office standardised on in 2009. Password fields mask on the way in and never echo.

All of it measured, none of it guessed: sessions were captured off the real runtime, byte stream and all, and replayed against ours until the rendered screen matched cell for cell — characters, attributes and cursor position.

03 Native SQL

SELECT straight against the keyed files.

Not a copy of your data. Not a nightly export. The same files your ERP has open right now, queried in place — and the planner knows what the key indexes are for.

  • 2 msKeyed lookup — the planner turns a WHERE on a key into a cursor seek
  • 3,665 msThe same query as a full sequential scan, when there is no key to use
  • 1,344,450Records in the file both numbers were measured against

A key-index-aware planner

A WHERE clause on a key becomes a cursor seek down the B-tree — a handful of node reads instead of a scan. A clause on a non-key column is honest about being a scan, and the console tells you which one you got before you put the query in a report. That distinction is the whole reason the first number above is 2 ms.

A CLI and an HTTP endpoint

Query interactively from a shell, or POST to the endpoint from anything that speaks HTTP — a spreadsheet, a dashboard, your website, the warehouse scanner app somebody wrote last year. No bridge product to license, no driver to install on every desk, and nothing to keep in sync.

Not yet

No JOINs and no aggregates

Today this is single-table SELECT with key-aware access — which is exactly what makes a 2 ms lookup possible, and exactly what it can't do yet. Joins and aggregate functions are on the roadmap and not in the build. If your reporting leans on them, you keep the tooling you have and use this for the lookups it is good at.

What this replaces: the JDBC bridge, the ODBC gateway, the licensed connector, and the overnight dump into a reporting database that is already wrong by nine in the morning.

04 Delivery

Two ways in. One place it runs.

Your people reach the system the way they reach it today, or through a browser if that suits them better. Underneath both, there is exactly one deployment model — ours, operated by us.

SSH, exactly as they work today

Same green screens, same function keys, same keystrokes, same muscle memory. The terminal habits in your building are thirty years old and extremely fast, and we don't touch them. Point the existing emulator at a new host and the operator on the receiving desk does not need to be told anything.

A browser terminal — real, built, running

The same 80×24 screen in a browser tab. Nothing to install, no SSH client, no terminal emulator to configure, no support call about the function keys. Multiple concurrent sessions, each user landing on their own terminal identity. This is what finally gets remote and warehouse staff onto the ERP without shipping them a laptop somebody had to set up first.

Managed cloud · the only deployment model

A dedicated, isolated tenant that we operate.

Backups, disaster recovery, patching and monitoring are ours to do, and a restore is a drill somebody has actually run end to end. One delivery model means one thing to get right, one thing to secure and one thing to keep correct — every customer runs the same verified build, and nobody is stranded on a version that shipped years ago and can no longer be reached.

How the move works

The SQL endpoint is the third door, and it isn't for people — reporting tools, integrations and anything else that needs to read the files can call it directly.

Today a session is a process. That's the part that's changing.

It already costs nothing at idle — 0% CPU per idle session, because the naive way to build this busy-loops and that's how servers get sized wrong. The density story is the next piece, and it is landing now rather than shipped.

05 Where the architecture is going

One runtime, many sessions.

Stated plainly, because you'll find out anyway: here is what the process model looks like today, what is being merged right now, and what that buys you when it lands.

NOWToday

A process per session.

Every signed-on user gets their own interpreter process. It works, it is isolated, and it is already cheap while nobody is typing — but memory per session is the number that sizes the machine, and it is the honest limit on how far one host goes.

  • Isolated per user
  • 0% CPU at idle
  • Memory-bound

NEXTLanding now

The shared daemon.

One long-lived runtime with an in-memory shared file cache, and lightweight per-user sessions on virtual threads instead of operating-system processes. The B-tree nodes everybody reads get read once. The sessions stop being the expensive part.

  • Shared file cache
  • Virtual threads
  • One runtime

THENWhat it buys

A hundred concurrent users on one machine.

That's the target the shared daemon is being built to hit, and the reason it's worth doing rather than just adding more hosts. Until it is merged and measured, treat it as our direction and not as a number we've proved — everything else on this page is measured.

  • PROCESS per session
  • SHARED daemon
  • ONE host

Design partners

Point it at your corpus.

The fastest way to find out how much of this applies to you is to run your own programs through the parser. That report is free and automated, and you keep it whether or not we ever speak.

or read the detail

What runs today lists the verified surface and the gaps in the same place. Migration covers the parallel run and the cutover weekend. Or email hello@uniquebb.com and a person who wrote this will answer you.