StateLib: October 2026

Async state, immutable records, operation ownership, compiled entries

Ultra / Mextner · October 2026

Overview

StateLib, in packages/state-lib of the HyperIDE repository, is a synchronous state Runtime with a Rust compiler for application entries and a documentation site with live examples. In October Ultra / Mextner added async state and immutable records to the Runtime, stopped stale async work from publishing, compiled whole entries with rollback, removed a document copy from cold import, and added live examples that compile in the browser.

The numbers on this page are historical local measurements on benchmark fixtures, each tied to the pull request that recorded it. They are not claims about the whole editor, which does not import state-lib on main. The Style Editor pilot is described in the HyperIDE report.

4.15 → 0.006 ms
point edit on a 10,000-item benchmark fixture, Node median (#802)
63 → 1 ms
completion handler, 1,200 visible rows, Chromium median (#832)
15.6 → 4.7 MB
Chromium retained heap, 10,000 rows with 1,200 visible (#832)

Owner requests behind the library work

These are the owner’s own messages about where the library should live and what it should do. They state direction and wishes. What shipped is in the results below, and this report makes no claim that the Style Editor adopted the library.

Owner request

Original request (RU)

Хм кажется state-lib живет в GitHub hyper-saas
Давай вынесем оттуда
И консолидируй все ворктри по state-lib, доделай и влей все через gh ship

English translation

Hm, it seems state-lib lives in the hyper-saas GitHub repository. Let's move it out of there. And consolidate all the worktrees on state-lib, finish them and merge everything through gh ship.

Source. Ultra / Mextner · Telegram, private chat between Ultra and the assistant bot · tg#23556, bot-side message id 23556 · 22 October 2026, 17:57 UTC. Sender: incoming Telegram message from the owner's account (not the assistant, not another person). Full-message SHA-256 eba04f1a240a15249c1810017ef295947c2d60a0eeb31948db135633622e90ff.

Owner request

Original request (RU)

Ага над hsw продолжай параллельно работать используй пока state-lib как приватную зависимость или вендоренную

English translation

Aha, keep working on hsw in parallel, and use state-lib for now as a private dependency or vendored.

Source. Ultra / Mextner · Telegram, private chat between Ultra and the assistant bot · tg#23559, bot-side message id 23559 · 22 October 2026, 17:59 UTC. Sender: incoming Telegram message from the owner's account (not the assistant, not another person). Full-message SHA-256 5ae64db0c5f19e8742df805c23c4e09f762e86b0c6c17a9ec373cf7058241a13.

Owner request

Original request (RU)

еще мы с денни обсудили что хотим в нашем state lint запретить useEffect и подобные паттерны и сделать продвинутые миграции, надо изучить типичные паттерны и как они будут декларативно решаться в сторе

English translation

Also, Denni and I discussed that we want to forbid useEffect and similar patterns in our state lint and to build advanced migrations; we need to study the typical patterns and how they will be solved declaratively in the store.

Source. Ultra / Mextner · Ultra's Claude Code prompt history, project hyperide · no message id · 4 September 2026, 13:56 UTC. Sender: the owner's own prompt history; it has no per-message author field, so attribution is by account. Full-message SHA-256 699195e29c111b3c883bdfe53c5075ca59c1eb35ac56af7d756556d0b2458ed3.

4 September 2026, before the October period of this report; kept because it states the library's goals.

Owner request (excerpt)

Original request (RU)

еще интересно как мы реализуем описанную ранее идею разделения разных смысловых регионов стейта: busines, automations, ui state, и чтото еще вроде стоит выделить

English translation

Also, I wonder how we will implement the idea described earlier of separating different semantic regions of state: business, automations, ui state, and maybe something else should be separated.

Source. Ultra / Mextner · Ultra's Claude Code prompt history, project hyperide · no message id · 4 September 2026, 12:14 UTC. Sender: the owner's own prompt history; it has no per-message author field, so attribution is by account. Full-message SHA-256 d3afe37f08950cf6323fbb3b27e65f896a9652f41f6ca2770cea5fd5fc5a3908.

4 September 2026, before the October period of this report; kept because it states the library's goals. Only the first sentence of a longer multi-paragraph message is quoted.

What we delivered

One tested async toolkit instead of per-framework glue

A framework-neutral async toolkit now sits on the Runtime, with an async resource, matchAsyncState and a conformance suite. Production and testing entry points are separate, and an import-boundary test checks the split. One implementation means an async-state bug is fixed once instead of once per framework.

Technical detail
  • Package @ultrabricks/state-toolkit-async@0.0.0-pilot.0 under packages/state-lib/toolkit, with a peer on @ultrabricks/state-lib@0.1.0-pilot.1. The . and ./testing exports are checked by import-boundary.test.ts and package-contract.test.ts.
  • Tests: async-conformance.test.ts, async-ownership.test.ts, async-resource.test.ts, async-thenable-once.test.ts and match-async-state.test.ts.

Key pull requests: #810

Validated immutable records on the existing Runtime

createRecord adds validated, deeply frozen records on the Runtime for small plain objects such as editor workspace preferences. Callers cannot change a committed snapshot, and a nested update that re-enters the same record now throws instead of letting a stale draft overwrite it. It reuses the Runtime’s transactions, so there is no second state engine to maintain.

Technical detail
  • A regression test written first reproduced the re-entrancy bug. The error is STATE_RECORD_REENTRANT, thrown before the inner mutation, and async recipes are rejected.
  • record.test.ts runs under a strict tsconfig.record.json; the pull request records 75 tests passing across core, regression, follow-up and adapter cases.

Key pull requests: #803

Stale async work cannot publish

createOperationScope gives each lane of async work a context generation. Once a lane is replaced, its context changes or it is disposed, the old write or feedback cannot publish, and an old finish or cancel cannot release a newer lease. It is library code; the pull request does not turn it on in the inspector.

Technical detail
  • Independent lanes, synchronous commit and notify gates, callback binding checked at invocation, and bounded metadata-only diagnostics.
  • Tests: operation-scope.test.ts, operation-scope-async.test.ts and a type fixture. A real-Chromium check runs the emitted package pair through nine scenarios, and with the stale-publication guard removed, five of seven checks fail.

Key pull requests: #826

Package export fails closed and records provenance

The package exporter assembles in an owner-only staging directory on the destination filesystem and publishes by rename. It refuses to overwrite existing files, directories or dangling symlinks and refuses an output directory inside the source trees. Each export records source and output hashes and tool versions, so a package can be traced to its source.

Technical detail
  • export-package.mjs keeps the original cause on errors and reports both failures if export and cleanup fail. export-filesystem.test.ts covers it, and #826 added cases. The pull request states the limits: the publish is not atomic no-replace and not crash-durable.

Key pull requests: #810

Generated commands and complete entries with rollback

The compiler generates immutable commands for declared edits such as assign, toggle, row assign and move, so on the benchmark fixture those edits no longer copy the whole document. state build compiles complete fixed application entries and publishes each output with rollback, and size budgets reject an oversized entry and keep the previous output. The figures below carry their fixtures and comparators; they are not a general speed or size claim.

Technical detail
  • Native Rust compiler: packages/state-lib/compiler/src/command.rs and lib.rs. Median improved in all 42 Node measurements; 26 of 42 also pass the stricter max-versus-min cell test (#802).
  • One ownership-aware publication and history module runs on a single dedicated Runtime. Entry budgets are maxRawBytes, maxGzipBytes and maxBrotliBytes plus a relative-growth limit (#802).
  • Fingerprint walks went from three to two and path resolution is cached within a build. A lock-cleanup failure after a successful install is only a warning (#832). A hole that let an alias into authored src/node_modules bypass the browser-root check was closed, with nine regression tests; the pull request says this is not a sandbox for third-party code.
  • An optional immutable-row adapter updates completion on existing rows in the board view and falls back to the full renderer for unsupported changes (#832). On the small fixtures the same pull request records about 32 to 38 KB more retained heap, and an entry of 42,166 gzip bytes against 37,132 for the equally optimized original.

Key pull requests: #802 · #832

Cold import skips a full-document copy

importJsonField certifies a JSON field while importing it, and replaceImported adopts that exact root. A cold load skips one whole-document structuredClone, while the normal replace() still copies and behaves as before.

Technical detail
  • replaceImported throws TypeError for anything not produced by importJsonField, so the shortcut cannot be used with an uncertified value. Certification, freezing, history reset and the save payload contract are unchanged.
  • owned-import.test.ts was written red first and has 11 passing tests. The pull request records whole-call structuredClone uses during load going from 3 to 2 and makes no timing claim.

Key pull requests: #834

Live examples, a keyed-row patch boundary and correct docs

The documentation site has two live examples, /repl/board-commands and /repl/issue-triage. Visitors edit multi-file source, compile it with the real Rust compiler in WebAssembly, and see generated commands, readable and minified output, sizes, live state, Undo and Redo, and browser benchmarks. A checked keyed-row patch boundary lets an app update real text edits without rebuilding the list, and the generated API docs keep ordinary member names.

Diagram caption in the docs site

Merged, pull request #810 Before and after: same window, same region, same scale.

StateLib docs diagram before the fix: the caption under the State diagram starts with b, a quote mark and a greater-than sign, then reads Safe label and diagram
Before Docs-site diagram caption before the fix. Full-size original (850×450 PNG)
  1. The caption starts with the stray characters b"> before the words Safe label.
Same docs diagram after the fix: the caption reads Safe label, then diagram
After Same fixture and crop after the fix. Full-size original (850×450 PNG)
  1. The caption reads Safe label, then diagram.

StateLib documentation site, captured for #810 on 14 October 2026 from the same fixture before and after the fix. Both crops cut the same region.

Technical detail
  • Edited code runs in a disposable worker inside an opaque-origin, network-denied frame. Cancellation, latest-request authority, timeout and keeping the last good build after a failed build are tested (#809).
  • patchKeyedRows locates every target before the first row write and rejects a null or invalid plan without applying rows; the pull request documents that a throwing callback leaves a view to rebuild (#833). 14 planner and boundary tests pass.
  • apiSymbolName() used to throw on a real member named like __@iterator@999 and abort API-doc generation. It now accepts such a name only when a declaration’s string literal is exactly that name, and the regenerated docs are unchanged at 119 entries (#807).
  • Diagram captions no longer show quoted attribute text, and docs-site readiness waits for exactly three lazy editors. SVG comparison in the gallery tolerates only narrowly parsed coordinate roundoff (#810).

Key pull requests: #809 · #833 · #807

Before and after in numbers

Historical local measurements, recorded in the pull requests named in the last column; the first column gives the fixture. #802 improves the median in all 42 Node measurements and passes its stricter cell test in 26 of 42. #832 records about 32 to 38 KB more retained heap on small fixtures.

Owner request (excerpt)

Original request (RU)

Надо сравнивать с ней и без нее по разным критериям более детально

English translation

We need to compare with and without it in more detail, using different criteria.

Source. Ultra / Mextner · Ultra's archived ChatGPT conversation about StateLib and the Style Editor · no message id recovered · 16 October 2026, 13:33 UTC. Sender: user message retrieved from the archived conversation and re-read against it on 7 November 2026; no message link was recovered. Full-message SHA-256 8a4cf35e61141626bd5cf3164a66def49f813d75e1f7e5df0bedc366b0988296.

The rest of the message, including its first sentences and the request to write benchmark tests, is not quoted. The full message was re-read from the archived conversation on 7 November 2026; an earlier retrieved copy had added full stops, so its hash is not used.

Owner request

Original request (RU)

Добро погнали. А также желательно чтобы оно давала и в цифрах более хорошей результаты работала быстрее бандл бы весил меньше

English translation

All right, let's go. Also it would be good for it to give better results in numbers: to run faster and for the bundle to weigh less.

Source. Ultra / Mextner · Ultra's archived ChatGPT conversation about StateLib and the Style Editor · no message id recovered · 16 October 2026, 16:32 UTC. Sender: user message retrieved from the archived conversation and re-read against it on 7 November 2026; no message link was recovered. Full-message SHA-256 2c95bb365d37e75dbe0d3a50c6459febef805e388034a4bd7ddaeb9a5ecb8c59.

MeasureBeforeAfterSource
Point edit, 10,000-item benchmark fixture, Node median4.148 ms0.006 ms#802 body
Move, 10,000-item benchmark fixture, Node median4.175 ms0.008 ms#802 body
Entry size, 512-command fixture: raw / gzip / Brotli71,069 / 9,525 / 6,596 bytes42,284 / 8,619 / 5,779 bytes#802 body
Task-completion handler, 1,200 visible rows, median63.2 ms Chromium, 93 ms WebKit1.0 ms Chromium, 1 ms WebKit#832 body
Next animation frame, 1,200 visible rows311 ms Chromium, 546 ms WebKit13.8 ms Chromium, 7 ms WebKit#832 body
Chromium retained heap, 10,000 rows, 1,200 visible15.58 MB4.73 MB#832 body
Whole-document copies during cold load32#834 body
Diagram caption in the docs siteQuoted attribute text shown before the labelOnly the intended labelScreenshots in the live examples result

Proof

Hosted CI runs for the final commit of each pull request, or for the merge commit where noted.

Work by Ultra / Mextner (GitHub alex-mextner, Alex Ultra). Pull requests merged 1 to 31 October 2026 are credited by commit authorship. Status checked 6 November. Source links may require repository access.

Attribution: every commit in these pull requests is by Ultra. #802, #809 and #833 were opened from the smoothbricker account and merged by alex-mextner.

All merged pull requests counted here are listed with their authors and merge commits in the source record.