Form contract
Every program flowRS exports — an app for this computer, an app for a Linux board, a
microcontroller's whole firmware — carries a FORM.json beside its source. It lists
the properties below, 16 of them, and for each one says what enforces it, whether it holds
for this program (live), holds in part (partial) or does not hold yet (not yet), why,
and the evidence: the tests, proofs and tools in flowRS's gate that enforce it, and what was
checked on this program when it was exported. A property that is not a property of that kind
of program (no heap, on a computer) says so. The project's README.md states the
same contract in plain words.
No status is written by hand. Each is computed when the program is exported,
from the program as generated (its unsafe, read as syntax; its
#![no_std]; its failure path), its graph (the nodes against what the generator
lowers, the units on each wire), its Cargo.lock against flowRS's own, and, for a
firmware, the board's binding, its twin, and the program's own Kani proof: a firmware ships its
harness in proof/ with its record, proof/proofs.json, and the no-panic
property is live only when that record says Kani proved exactly this program (the SHA-256 of
its mod flow), every cover reached. Where flowRS's build host has proved the same
program, the record arrives proved; otherwise flowrsc prove runs it, within a
memory and a time budget. A test holds every live or partial claim to a second reading of the
same files and fails when a status claims more than the code enforces.
The format is published as a JSON Schema: /schemas/form-contract-1.json
($schema in every FORM.json).
The properties
The counts are this build's: each example on the editor's start screen exported as an app (16 exported), and the board generator's acceptance graph (every embedded widget but PWM) exported as a firmware for each board the generator covers, on both executors (10 exported). Each export's own contract is read back and counted.
| # | Property | Enforced by | Example apps | Firmware |
|---|---|---|---|---|
| 1 | Memory safety; no data race between an interrupt and the main loop conformance: the generated program | rustc's borrow checker (with Send and Sync); the generated runtime never enables an interrupt | 16 live | 10 live |
| 2 | No heap: no_std, every buffer sized from the graph conformance: the generated program | the MCU generator (flowrs-core codegen::mcu), then rustc | 16 not applicable | 10 live |
| 3 | A closed node set: nothing silently skipped structure: the graph | the generators, which refuse by name any node they cannot lower | 16 live | 10 live |
| 4 | Pins and buses allocated without collision structure: the graph | codegen::mcu::bind, against the flowrs-boards model and the chip's signal tables | 16 not applicable | 10 live |
| 5 | Exclusive peripheral ownership; no use before configuration structure: the graph | the generated Board: the peripherals taken once, the init order as a chain of typestates (codegen::board) | 16 not applicable | 10 live |
| 6 | A static schedule and bounded queues conformance: the generated program | codegen: one pass of straight-line calls in the graph's order; the partitioner's compile-time link slots | 16 not applicable | 10 live |
| 7 | Loops never faster than their edges allow conformance: the generated program | the partitioner's 10x rule, against tails measured by tools/perfbench | 16 not applicable | 10 not applicable |
| 8 | Units and clocks agree on every wire that carries a number structure: the graph | the wire type check (flowrs-core graph::quantity), with units carried along the wires (graph::units); a mismatch is refused until a conversion node sits between | 8 live 3 partial 5 not applicable | 10 not applicable |
| 9 | Register configuration matches the chip conformance: the generated program | flowrs-regdb's register check (rung 1) and processor-in-the-loop runs on the twin (flowrs-pil) | 16 not applicable | 10 partial |
| 10 | The same behaviour in the browser and in the compiled program conformance: the generated program | one implementation at both tiers; tier-differential tests; scipy and MNE oracles | 16 live | 10 partial |
| 11 | Instruments always returned to a safe state conformance: the generated program | codegen::handles::audit, which refuses any program that could skip an instrument handle's destructor | 2 live 14 not applicable | 10 not applicable |
| 12 | Defined behaviour when a HAL call fails on the microcontroller conformance: the generated program | the generated runtime's failure path (codegen::board, flowrs_hal::rt) | 16 not applicable | 10 live |
| 13 | The generated program cannot panic or overflow conformance: the generated program | Kani | 16 not yet | 10 live |
| 14 | No hardware action without a person's approval conformance: the generated program | flowRS's approval envelope: approve-by-hash, server-held leases, signed policies, a hash-chained audit log | 6 partial 10 not applicable | 10 partial |
| 15 | The export builds the same way anywhere, under open licences conformance: the generated program | the export's Cargo.lock, from flowRS's own; tools/appexport-verify.sh builds it --locked with no credentials; the licence audits | 16 live | 10 live |
| 16 | Behaviour confirmed on the physical device conformance: the generated program | a recorded run on a leased bench | 6 not yet 10 not applicable | 10 not yet |
Not counted, because the exporter refuses them, by name:
ds-sales: the program needs polars, which the Linux project generator has no pinned version fords-regression: the program needs polars, which the Linux project generator has no pinned version forml-classify: the program needs flowrs_ml, polars, tract_onnx, which the Linux project generator has no pinned version fordetect-blobs: the program needs image, imageproc, which the Linux project generator has no pinned version for
The software bill of materials
Every export that carries its Cargo.lock carries sbom.cdx.json beside it: CycloneDX 1.6 JSON made from that lock, so it lists every package the project can build, for any feature and target. Each crates.io crate is there with its package URL, its SHA-256 and the licence its own manifest declares, each flowRS crate in vendor/ with its licence, and the lock's dependency graph with them. FORM.json names it in its sbom member, with its SHA-256 and the lock's, and the exporter refuses to ship one its lock does not bear out. Of the exports counted above, 26 carry one, listing from 15 to 23 components.
What each board's twin models
A firmware's contract carries its board's fidelity contract, generated from the twin census: the rung of the twin ladder its twin stands on, what executes its CPU, and which of its part's peripherals a model answers. The register-configuration property names, for each peripheral the program uses, whether the twin models it.
| Board | Name and part | Twin | Engine | Peripherals modelled | Not modelled |
|---|---|---|---|---|---|
| blue_pill | STM32 Blue Pill stm32f103c8 | Full | flowRS's pure-Rust Cortex-M core, in the page | 26 of 32 | BKP, CAN, CRC, IWDG, RTC, WWDG |
| esp32_c3_devkitm | ESP32-C3-DevKitM-1 esp32c3 | None | nothing executes it | not measured | — |
| esp32_devkitc | ESP32-DevKitC esp32 | Full | Espressif's QEMU, built to wasm64, in the page | 33 of 58 | BB, CPU_CTRL, DAC1, DAC2, ETH, FLASH, FROM_CPU_INTR2, FROM_CPU_INTR3, GPIO_SD, HINF, I2S0, I2S1, IPC, LP_I2C0, NRX, PCNT, PSRAM, RMT, RTC_TIMER, SDHOST, SLC, SLCHOST, TOUCH, UHCI0, UHCI1 |
| esp32_s3_devkitc | ESP32-S3-DevKitC-1 esp32s3 | Partial | Espressif's QEMU, built to wasm64, in the page | 42 of 65 | ASSIST_DEBUG, CPU_CTRL, FLASH, FROM_CPU_INTR2, FROM_CPU_INTR3, GPIO_DEDICATED, GPIO_SD, I2S0, I2S1, IPC, LCD_CAM, LP_I2C0, PCNT, PERI_BACKUP, PSRAM, RMT, RTC_TIMER, SDHOST, SENSITIVE, UHCI0, ULP_RISCV_CORE, USB_FS, WCL |
| feather_rp2040 | Adafruit Feather RP2040 rp2040 | Full | rp2040js, with flowRS's patches, in the page | 33 of 34 | VIRTUAL |
| longan_nano | Sipeed Longan Nano gd32vf103 | CoreOnly | flowRS's pure-Rust RV32 hart, in the page | not measured | — |
| microbit_v2 | BBC micro:bit v2 nrf52833 | Full | flowRS's pure-Rust Cortex-M core, and Renode's tlib (built to wasm) for the FPU and DSP instructions it lacks, in the page | 61 of 70 | AAR, CCM, COMP, FPU, LPCOMP, MWU, NFCT, QDEC, USBD_ERRATA |
| nucleo_f401re | ST Nucleo-F401RE stm32f401re | Full | flowRS's pure-Rust Cortex-M core, and Renode's tlib (built to wasm) for the FPU and DSP instructions it lacks, in the page | 36 of 40 | I2S2, I2S3, SDIO, WWDG |
| nucleo_g071rb | ST Nucleo-G071RB stm32g071rb | Full | flowRS's pure-Rust Cortex-M core, in the page | 38 of 45 | CEC, DAC1, DMAMUX1, TAMP, UCPD1, UCPD2, WWDG |
| nucleo_h743zi | ST Nucleo-H743ZI stm32h743zi | Full | flowRS's pure-Rust Cortex-M core, and Renode's tlib (built to wasm) for the FPU and DSP instructions it lacks, in the page | 79 of 104 | CEC, COMP1, COMP2, CRS, DAC1, DCMI, DFSDM1, DLYB_QUADSPI, DLYB_SDMMC2, DMAMUX2, ETH, HRTIM1, JPEG, MDIOS, MDMA, OPAMP1, OPAMP2, SAI1, SAI2, SAI3, SAI4, SDMMC2, SPDIFRX1, VREFBUF, WWDG1 |
| rpi_pico | Raspberry Pi Pico rp2040 | Full | rp2040js, with flowRS's patches, in the page | 33 of 34 | VIRTUAL |
| rpi_pico2 | Raspberry Pi Pico 2 rp2350 | Full | flowRS's pure-Rust Cortex-M core, and Renode's tlib (built to wasm) for the FPU and DSP instructions it lacks, in the page | 34 of 51 | ACCESSCTRL, BOOTRAM, BUSCTRL, CORESIGHT_TRACE, DMA, GLITCH_DETECTOR, HSTX_CTRL, HSTX_FIFO, OTP, OTP_DATA, OTP_DATA_RAW, PIO0, PIO1, PIO2, SHA256, TRNG, VIRTUAL |
| sparkfun_thing_plus_rp2040 | SparkFun Thing Plus RP2040 rp2040 | Full | rp2040js, with flowRS's patches, in the page | 33 of 34 | VIRTUAL |
| wio_terminal | Seeed Wio Terminal samd51p19a | Full | flowRS's pure-Rust Cortex-M core, and Renode's tlib (built to wasm) for the FPU and DSP instructions it lacks, in the page | 39 of 56 | AC, AES, CCL, DSU, EVSYS, FREQM, HMATRIX, I2S, ICM, PAC, PCC, PDEC, QSPI, RAMECC, SDHC0, SDHC1, TRNG |
Whatever its rung, no twin models:
- the electrical side of the pins: drive strength, rise times, analogue levels and loading
- anything outside the chip that the board's wiring row does not describe
- the air: a radio's registers and timing may be modelled, its transmissions are not