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,704,372 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 behavior is a starting hypothesis; the measured behavior 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 behaviors 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. Color, 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 color and box drawing

Color 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. The plan line names the access path it took and the number of records it touched, so you know exactly what you have 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.

Reporting

Native SQL over your own keyed files, key-index aware

The query rides the file's own key index instead of scanning it, which is what a lookup on a 1.7 million-record file needs in order to stay a lookup at 2 ms. The query shapes your business depends on — the report the company runs on, the extract your salespeople live in, the feed somebody built against this data in 2004 — come out of your assessment and get built into your migration. Query work is engineered against real corpora, yours included, by the engineers who wrote the engine.

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. The people who operate it are the people who wrote it; nothing goes through a partner network.

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.

A session is a process. Nothing else is shared.

Every signed-on user runs inside their own operating-system process. The only thing any two of them touch in common is the data files, arbitrated by the operating system — which is exactly what a program written in 1991 already assumed. When a session ends, however it ends, the operating system takes back everything it was holding.

05 The engine architecture

Two binaries, five dependencies, and a process per user.

The engine is written in Rust and ships as a single native binary. There is no virtual machine beneath it, no application server in front of it and no pool of anything shared between your users. What follows is the part an operations manager has to live with: what a session actually is, what happens when one dies at 4:55 on a Friday, and what happens when our engine and the one you license today have the same file open at the same moment.

4.4MB

The whole platform, on disk

Engine 3.4 MB, browser terminal 921 KB. Our previous engine ran on a Java virtual machine and needed about 306 MB, roughly 90 times the engine, each in its default configuration.

5total

Third-party dependencies

Four at runtime, one at build time. That is the entire outside supply chain — the list your security team has to read, and they can finish it in an afternoon.

2.41ms

Cold start, median of ten runs

Against 56.88 ms for our previous engine: 23 times faster to start. Start-up is a cost you pay every time somebody signs on, runs a report or spools a print job — which on a distribution floor is all day.

Isolation

One operating-system process per terminal session

Every signed-on user gets their own process. Nothing sits between them — no shared address space, no connection pool, no application server holding everybody's state in one heap. The only common ground is the data files themselves, and the operating system arbitrates those. One user's session cannot corrupt another's, because there is nothing between them to corrupt through. And a session that dies needs no cleanup: the operating system releases the memory, the file handles and the locks the moment the process goes away. There is no reaper to run, no stale entry to clear by hand, and no reason to bounce everybody else because one terminal wedged.

Record locking

Built from measured behavior, not from a manual

We did not read the documentation and hope. We measured what the runtime you license today actually does on disk — which lock it takes, over which bytes, at which moment — and built ours to arbitrate against that protocol rather than against a description of it. The consequence is the one that decides how your migration feels: both engines can hold the same files open at the same time and neither corrupts the other. You can put one department on ours while the rest of the building stays where it is, against one live set of files, and move people across a desk at a time — instead of a weekend cutover with nothing behind it but the backup.

Footprint

4.4 MB, five dependencies, nothing underneath

The engine is 3.4 MB and the browser terminal is 921 KB, and that is the platform. No virtual machine to install below it, no heap settings to guess at, no second runtime with its own patch cycle and its own advisories landing on your desk. The third-party supply chain is five packages — four at runtime, one at build time — and we wrote the HTTP, the WebSocket layer, the JSON and the pattern matching ourselves rather than inheriting somebody else's. An upgrade is one file replaced atomically; a rollback is the same move in reverse.

Data path

The SQL layer reads the ERP's own keyed files

It is part of the engine, not a product bolted on beside it. The same code that executes your programs opens the same files, and the planner understands what their key indexes are for — so a lookup stays a lookup at 2 ms rather than degrading into a 3,665 ms scan of the same 1,344,450 records. No export, no nightly copy, no reporting database that is already wrong by nine in the morning. You report against the numbers your order desk is looking at right now.

None of this is a roadmap item — it is what the engine does today. Every number above was measured against the stack it replaces rather than estimated, and where a comparison would not be honest to publish yet, we have left it off the page.

What runs today, measured program by program

Direct from the engineers

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, program by named program. Migration covers the parallel run and the cutover weekend. Security names the five dependencies one at a time and accounts for every block of low-level code in the engine. Or email hello@uniquebb.com and you reach the engineers who wrote the engine directly — nothing here goes through a partner network.