Over the last few days we added Stabileo Research and Stabileo Tools, and tightened the checks behind them. Stabileo is free, open-source structural engineering software with AI, published by Ergodic Group. LambdaClass is its development arm.
Research you can run
We are putting published structural-engineering papers and classic benchmarks in the browser, with Stabileo’s own viewer. Every page states what it reproduces, how it was checked and the limits of the comparison. We are completing pages that still show open comparisons.

The live paper pages cover Shauer (2025) phase-field fracture; Grossman and Boudaoud (2026) spring networks; Andreassen et al. (2011) topology optimization; Ferrari and Sigmund (2025) Roorda-frame stability; Pastrana et al. (2026) cable-net form finding; Zmyślony, Khan and Biggins (2026) snapping arches; and Fairclough et al. (2026) gridshells.
The engine classics are MacNeal–Harder, the shell obstacle course, Mattiasson elastica, Riks/Crisfield, Newmark, CQC, plastic collapse, the Navier plate, the Lee frame and the DaDeppo–Schmidt arch. Pages distinguish live computation from recorded replay and show their comparison limits. Ferrari’s Koiter comparison is unfinished; Fairclough covers one five-node example; the snapping-arch equilibrium jump is not a transient simulation.
We publish the scope and evidence and review them in the open. Research results are not design results, and benchmark agreement is not certification.
| Offering | Count |
|---|---|
| Runnable paper pages | 7 |
| Engine benchmark pages | 10 |
| Calculators | 8 |
The tests need checking too
Some pages were wrong because our test models were wrong. Each engine benchmark page and its engine CI test now read the same case file, so a model fix updates both. Some provisional comparisons remain explicitly ignored in CI and do not yet block merges; we are completing those comparisons.
We corrected the Mattiasson references and treatment of axial extension (#845), a rigid-jointed frame compared against an axial-only truss formula (#846), and incorrect shell support and loading models (#810). We are changing how benchmarks are built so this class of mistake can’t pass again. The first part is in: each benchmark is a specification with two independent references that must agree, and automatic checks of applied load, reaction balance and symmetry, including half-model against full-model. We are adding convergence over three or more meshes, a sign-error test that proves each benchmark can fail, and engineer sign-off on the core set.

We are also building units into the type system (#864), so kN/N or m/mm mix-ups are caught at compile time. The first slice, for the material and section path of 2D frames, landed on 3 November.
Round 2: every page reviewed again
Each live research page then went through a second review, by three AI models in turn (Kimi, then Codex, then Claude), and every finding we could verify was fixed. Fifteen pages were revised together and published on 4 November (#1068): six papers (Shauer, Pastrana, Ferrari, Zmyślony, Grossman and Fairclough) and nine engine benchmarks (Newmark, Riks/Crisfield, Navier, Lee, MacNeal–Harder, DaDeppo–Schmidt, the plastic collapse example after Horne, SRSS/CQC, and Mattiasson, which had a third round). No tolerance was loosened and no test was removed. Review by practising engineers is still to come.
- MacNeal–Harder compared absolute values, so a result with the wrong sign would have passed. References now carry their sign, and a test rejects a reversed response for every case.
- Riks/Crisfield could report a limit point without a drop in load. A limit now needs one between converged steps; the page says the run passes the upper limit point instead of “traces the snap-through”, and its tolerances went from 5 % to between 5e-3 and 1e-5.
- Navier explained the MITC4 error instead of measuring it. It is now compared with an independent Reissner–Mindlin series, and the hard-support MITC4 error falls from −1.951 % at 4×4 to −0.036 % at 32×32, at second order.
- Pages say what they are compared with. Newmark is checked against exact closed-form solutions, not “the author’s code”; SRSS/CQC is a method illustration, not a reproduction of the paper’s building; the plastic collapse bounds are our own hand derivations, not a quotation; the Lee frame’s 1.83 kN reference is a reading of a published figure, so only whole-percent differences are claimed.
On phones and tablets
Measured on the live site, the research pages did not overflow on a phone, but the experiment sat below the whole article, the viewer was cramped (356×189 px for a square plate), and each page had 25 to 40 controls under 32 px and 14 to 20 pieces of text under 12 px. Now the experiment comes right after the title, the viewer is sized to the model, controls are at least 44 px and text at least 12 px (#831).

A permanent check renders the gallery and every runnable page at 360, 390, 844×390 and 810 px, in Spanish, English and Portuguese, and fails on horizontal overflow, small controls, small text, or a viewer that is missing, too small or too far down. Its first runs found real bugs, and the layouts were fixed rather than the check: the Mattiasson viewer was 187 px tall in phone landscape and is now 280 px, and a convergence plot printed its labels at 9 px. A reflow test found that Shauer’s tabs overflowed in Portuguese and Turkish at 360 px.
Eight calculators, with a way into the editor
Stabileo Tools now has free calculators for simply supported beams, cantilevers, elastic column buckling, continuous beams, single-bay portals, planar trusses, moving-load influence lines and beam bending frequencies. They use the production engine, show independent classical comparisons and state their assumptions. Each opens its model in the full editor. These are analysis tools, not complete code design checks.

Containing wrong results
We are containing every known wrong-result issue: refusals or warnings in the engine carry the known-issue ID, instead of returning an unchecked number (#807, merged on 5 November). Every refusal is tested, including unsupported dynamic models with member or shell offsets.
Metamorphic tests exposed invariance bugs: equivalent models could be refused after rotation, mirroring or unit scaling. We now run the metamorphic suite on every change to catch these regressions. We are adding a nightly run of random models that groups findings by root cause and files one issue per root cause.
Since then: 1 to 3 November
- PRO’s analysis mode is finished. Results that were wrong without a warning are fixed: the load generator no longer loads a shed’s eaves as a floor, and a level’s seismic weight now includes the slabs and walls drawn as shells, which it had left out (#1076).
- Exports work on real buildings. Large Excel sheets are written row by row, and the report of a six-storey building takes about ten seconds instead of four minutes. “Check an exported report” now compares the printed numbers, not only the fingerprints (#1076).
- PRO gained inline help that can be turned off, a save status in the header, a report after the analysis, plate results, and a read-only viewer for shared models with “Duplicate and edit” (#1077, #1078).
- A buckling factor above its independently certified upper bound is now refused, in 2D and 3D (#817, results version 6). Re-run the certification before relying on an earlier buckling certificate.
- Share links with non-finite numbers, or with members, supports or loads that point to something missing, are refused instead of opened (#1058).
- The invariance suite now checks six priority analyses under rotation, mirroring and superposition, and four of them under uniform stiffness scaling (#1060).
Checks that answer in twenty minutes
Before it reaches main, every change to Stabileo passes the checks it can affect, and a change to the engine passes all of them: engine tests, web unit tests, production builds, end-to-end tests in a browser, the results snapshots and the determinism check. A safety fix is only as fast as those checks, so on 4 November we worked on their speed. We measured first. In a clean merge-queue run of 44 to 47 minutes, the engine and unit tests finished 8 to 15 minutes before the end, so adding more of them in parallel would have gained nothing. The time went to building the research bundles one after another, and to the slowest end-to-end shard. Once those were shorter, the slowest shard was slow because of setup: in one run it spent 7.2 of its 16 minutes on tests and six and a half downloading browser packages from a slow mirror.
- Build once, test what was built. The production-build tests made five more builds of their own, four of them of the same tree CI had just built; those four now read that build (#1411). Each build carries a stamp of everything it was built from, and a test fails, never skips, if the stamp does not match the tree it runs on.
- Cache by input. Each research bundle is cached under a key of its own inputs, including the engine every bundle links, so a change to one paper rebuilds only that paper and a change to the engine rebuilds all of them. A pull request reuses bundles the merge queue already built from the same inputs, after checking every file against its checksum, and it can read that cache but never write it (#1395). Browser packages come from a cache too, instead of the mirror (#1413).
- Run only what a change can affect. A change to documentation builds nothing, in one or two minutes instead of a whole run. A change to the site alone skips the engine jobs but keeps every end-to-end shard, because 59 of the 281 specs read text on screen (#1381). In the queue, each entry is scoped by its own diff against the entry ahead of it, which is sound because an entry merges only if every entry ahead of it passed; when the diff is missing or unclear, it runs everything (#1400).
- Balance the slowest path. End-to-end tests run in 14 shards instead of 10, balanced on measured timings (#1382). The old timing table predicted 41.5 minutes of tests where a run took 69.8.
| Runs | Count | Median | Range |
|---|---|---|---|
| Merge queue, before | 20 | 42 min | 25 to 56 min |
| Merge queue, after | 10 | 20 min | 15 to 26 min |
| Pull requests (first attempt), before | 69 | 59 min | 35 to 127 min |
| Pull requests (first attempt), after | 19 | 27 min | 16 to 45 min |
A red check that is not the change’s fault
A failure caused by the network or a lost machine is noise, but it is also a red check that someone must look at, and a habit of rerunning red checks is how a real failure gets waved through. So a pull request’s failed jobs are rerun once, automatically, only when every failed job carries positive evidence of an infrastructure failure: a timeout in a download step, a CI machine lost mid-job, a network error that ends the last attempt of a download (#1380). Anything that looks like a test failure anywhere in the log blocks the rerun, and so does anything the classifier does not recognise. That keeps it conservative: it reruns at most once and never after a failed test step. It is not a guarantee: an intermittent failure the classifier misreads as infrastructure could pass on the rerun, which is why anything it does not recognise blocks the rerun.
Two more fixes removed false alarms. A pull-request run cancelled because a newer run on the same commit replaced it used to show a red required check; it now skips that check, but only after confirming that the newer run exists and has not failed, because a skipped required check counts as passed (#1397). And a stalled download could leave a process holding the package manager’s lock, so the retry failed on the lock rather than the download; an attempt now counts as stalled only after minutes without output, is stopped together with everything it started, and the retry waits for the lock (#1408).
What comes next
We are completing the open comparisons and making the site and solver faster. Next on the roadmap are a Python package (pip install stabileo) and a public verification manual generated from the benchmarks.