From 445af7e80f0efd17c706173ab8651f086660aabe Mon Sep 17 00:00:00 2001
From: Will Binns
Date: Sun, 11 Oct 2026 13:16:28 +0000
Subject: [PATCH 1/7] Prior art and qualification path pages; Degradation-first
nav item points to its section
Prior art lists only verified references (von Neumann, Lyons and
Vanderkulk, STAR, Sklaroff, Meyer, Lamport et al., Spector and Gifford,
Rasmussen) with how Mru relates to each. Qualification path maps what
exists to NPR 7150.2, NASA-STD-8739.8, ECSS-E-ST-40C and ECSS-Q-ST-80C by
topic and makes no compliance claim. Metadata for both, and descriptions
updated for the shrinking quorum, quorum crate and Dusk pages.
---
src/data/metadata.json | 22 ++-
src/data/nav.ts | 27 +++-
src/pages/concepts/prior-art.astro | 175 +++++++++++++++++++++
src/pages/concepts/qualification.astro | 203 +++++++++++++++++++++++++
4 files changed, 421 insertions(+), 6 deletions(-)
create mode 100644 src/pages/concepts/prior-art.astro
create mode 100644 src/pages/concepts/qualification.astro
diff --git a/src/data/metadata.json b/src/data/metadata.json
index 6002109..9e2bb0f 100644
--- a/src/data/metadata.json
+++ b/src/data/metadata.json
@@ -10,7 +10,7 @@
{
"url": "https://docs.mru.space/concepts/shrinking-quorum/",
"title": "Shrinking quorum · Mru Docs",
- "description": "Vote on three replicas, compare on two, self-check on one. The rule, its Kani-proved guarantees, its cost, and how replicas are diagnosed.",
+ "description": "Vote on three replicas, compare on two, self-check on one. What Kani proves per tick, what is tested per run, the cost and the command path.",
"ogTitle": "Shrinking quorum",
"cardLabel": "Docs · Concepts",
"schema": ["TechArticle", "BreadcrumbList"]
@@ -23,10 +23,26 @@
"cardLabel": "Docs · Concepts",
"schema": ["TechArticle", "BreadcrumbList"]
},
+ {
+ "url": "https://docs.mru.space/concepts/prior-art/",
+ "title": "Prior art and related work · Mru Docs",
+ "description": "TMR, degradable systems, Byzantine agreement, Space Shuttle redundancy management and deep-space fault protection, and how Mru relates.",
+ "ogTitle": "Prior art and related work",
+ "cardLabel": "Docs · Concepts",
+ "schema": ["TechArticle", "BreadcrumbList"]
+ },
+ {
+ "url": "https://docs.mru.space/concepts/qualification/",
+ "title": "Qualification path · Mru Docs",
+ "description": "What exists for Mru against NPR 7150.2, NASA-STD-8739.8, ECSS-E-ST-40C and ECSS-Q-ST-80C, and what has not started. No compliance claim.",
+ "ogTitle": "Qualification path",
+ "cardLabel": "Docs · Concepts",
+ "schema": ["TechArticle", "BreadcrumbList"]
+ },
{
"url": "https://docs.mru.space/core/quorum-crate/",
"title": "quorum crate API reference · Mru Docs",
- "description": "API reference for the quorum crate: Policy, Mode, Reply, Outcome, Verdict, decide(), Health. no_std, no allocation, four Kani proofs.",
+ "description": "API reference for the quorum crate: Policy, Mode, Reply, Outcome, Verdict, decide(), Health. no_std, no allocation, nine Kani proofs.",
"ogTitle": "The quorum crate",
"cardLabel": "Docs · Core runtime",
"schema": ["TechArticle", "SoftwareSourceCode", "BreadcrumbList"]
@@ -58,7 +74,7 @@
{
"url": "https://docs.mru.space/simulation/dusk/",
"title": "Dusk simulator reference · Mru Docs",
- "description": "Run Dusk, the Monte Carlo of redundancy policies: options and defaults, the fault model, default results, sweeps and what it does not claim.",
+ "description": "Run Dusk, the Monte Carlo of redundancy policies: options, the fault model, results and their definitions, sweeps, ground support and limits.",
"ogTitle": "Dusk",
"cardLabel": "Docs · Simulation",
"schema": ["TechArticle", "SoftwareSourceCode", "BreadcrumbList"]
diff --git a/src/data/nav.ts b/src/data/nav.ts
index 0774146..3abb441 100644
--- a/src/data/nav.ts
+++ b/src/data/nav.ts
@@ -1,5 +1,10 @@
// Docs navigation, from the DocsNav artboard. The nav follows concepts and
// layers, not repository names. Prev/next follow PAGES.
+//
+// A page marks one item active: the item for the page itself. Items that link
+// to a section of a page (an href with #) are never active; the page item is.
+// So on /concepts/shrinking-quorum/ "Shrinking quorum" is active, not
+// "Degradation-first" or "Graceful Degradation Index".
export type NavId =
| 'home'
@@ -8,6 +13,8 @@ export type NavId =
| 'quorum'
| 'gdi'
| 'layers'
+ | 'prior'
+ | 'qual'
| 'crate'
| 'cli'
| 'proofs'
@@ -36,10 +43,12 @@ export const NAV: NavGroup[] = [
{
title: 'Concepts',
items: [
- { id: 'dfp', label: 'Degradation-first', href: '/concepts/shrinking-quorum/' },
+ { id: 'dfp', label: 'Degradation-first', href: '/concepts/shrinking-quorum/#degradation-first' },
{ id: 'quorum', label: 'Shrinking quorum', href: '/concepts/shrinking-quorum/' },
{ id: 'gdi', label: 'Graceful Degradation Index', href: '/concepts/shrinking-quorum/#gdi' },
{ id: 'layers', label: 'Layers 0 to 5', href: '/concepts/architecture/' },
+ { id: 'prior', label: 'Prior art', href: '/concepts/prior-art/' },
+ { id: 'qual', label: 'Qualification path', href: '/concepts/qualification/' },
],
},
{
@@ -87,7 +96,7 @@ export const PAGES: DocPage[] = [
{
path: '/concepts/shrinking-quorum/',
short: 'Shrinking quorum',
- updated: '7 Oct 2026',
+ updated: '11 Oct 2026',
file: 'src/pages/concepts/shrinking-quorum.astro',
},
{
@@ -96,10 +105,22 @@ export const PAGES: DocPage[] = [
updated: '11 Oct 2026',
file: 'src/pages/concepts/architecture.astro',
},
+ {
+ path: '/concepts/prior-art/',
+ short: 'Prior art',
+ updated: '11 Oct 2026',
+ file: 'src/pages/concepts/prior-art.astro',
+ },
+ {
+ path: '/concepts/qualification/',
+ short: 'Qualification path',
+ updated: '11 Oct 2026',
+ file: 'src/pages/concepts/qualification.astro',
+ },
{
path: '/core/quorum-crate/',
short: 'The quorum crate',
- updated: '7 Oct 2026',
+ updated: '11 Oct 2026',
source: 'quorum/src/lib.rs',
file: 'src/pages/core/quorum-crate.astro',
},
diff --git a/src/pages/concepts/prior-art.astro b/src/pages/concepts/prior-art.astro
new file mode 100644
index 0000000..23f9a34
--- /dev/null
+++ b/src/pages/concepts/prior-art.astro
@@ -0,0 +1,175 @@
+---
+import DocsLayout from '../../layouts/DocsLayout.astro';
+import DocsEnd from '../../components/DocsEnd.astro';
+import Breadcrumbs from '../../components/Breadcrumbs.astro';
+
+const crumbs = [
+ { label: 'Docs', href: '/' },
+ { label: 'Concepts', href: '/concepts/shrinking-quorum/' },
+ { label: 'Prior art' },
+];
+---
+
+
+
+
+ Prior art and related work
+
+ The shrinking quorum builds on decades of work in fault-tolerant computing. Stepping down from three replicas to
+ two to one is not new. This page lists the work Mru draws on and how Mru relates to each.
+
+
+ TMR and its origins
+
+ -
+
+ von Neumann, 1956. Shows that reliable computation can be built from unreliable components
+ through redundancy. Mru: the shrinking quorum is one use of that idea, with the redundancy shrinking as parts
+ fail.
+
+
+ J. von Neumann, "Probabilistic Logics and the Synthesis of Reliable Organisms from Unreliable
+ Components," in C. E. Shannon and J. McCarthy (eds.), Automata Studies, Princeton University Press, 1956,
+ pp. 43-98.
+
+
+ -
+
+ Lyons and Vanderkulk, 1962. Triple modular redundancy with a majority vote, applied to
+ reliability. Mru: fixed TMR in this form is the baseline on these pages. With three replicas, the shrinking
+ quorum votes the same way.
+
+
+ R. E. Lyons and W. Vanderkulk, "The Use of Triple-Modular Redundancy to Improve Computer
+ Reliability," IBM Journal of Research and Development, 6(2):200-209, 1962.{' '}
+ doi:10.1147/rd.62.0200
+
+
+
+
+
+
+ -
+
+ Meyer, 1980. Defines performability, a measure that combines performance and reliability for
+ systems that degrade. Mru: Dusk's figure of merit, useful work summed over the whole decline, is a measure
+ of this kind. The whitepaper cites Meyer for it.
+
+
+ J. F. Meyer, "On Evaluating the Performability of Degradable Computing Systems," IEEE Transactions
+ on Computers, C-29(8):720-731, 1980.{' '}
+ doi:10.1109/TC.1980.1675654
+
+
+
+
+ Byzantine agreement
+
+ -
+
+ Lamport, Shostak and Pease, 1982. Sets the limits of agreement when faulty components can
+ give conflicting information to different parts of a system. Mru: the shrinking quorum assumes replicas that
+ are damaged, not malicious. It does not solve input agreement: all replicas must already have the same input.
+ See Open questions.
+
+
+ L. Lamport, R. Shostak and M. Pease, "The Byzantine Generals Problem," ACM Transactions on
+ Programming Languages and Systems, 4(3):382-401, 1982.{' '}
+ doi:10.1145/357172.357176
+
+
+
+
+ Redundancy management on the Space Shuttle
+
+ -
+
+ Sklaroff, 1976. The Shuttle's general-purpose computers ran as a redundant set. Voting
+ detected and identified two failures. The remaining two used comparison and self-test to tolerate a third.
+ Mru: degradation from voting to comparison to self-test is not new. Mru does it with no ground team.
+
+
+ J. R. Sklaroff, "Redundancy Management Technique for Space Shuttle Computers," IBM Journal of
+ Research and Development, 20(1):20-28, 1976.{' '}
+ doi:10.1147/rd.201.0020
+
+
+ -
+
+ Spector and Gifford, 1984. A case study of the Shuttle's primary computer system. Mru: a
+ reference for how a flown redundant system was designed and managed.
+
+
+ A. Spector and D. Gifford, "The Space Shuttle Primary Computer System," Communications of the ACM,
+ 27(9):872-900, 1984. doi:10.1145/358234.358246
+
+
+
+
+ Autonomous fault protection on deep-space missions
+
+ -
+
+ Avizienis et al., 1971 (STAR). JPL's self-testing and repairing computer, designed for
+ outer-planet spacecraft. Standby spares replaced failed units by automatic recovery. Mru: autonomous recovery
+ in deep space is decades old. The shrinking quorum steps down instead of relying on spares. The F´{' '}
+ RedundancyManager can admit a spare after a known-answer test.
+
+
+ A. Avizienis, G. C. Gilley, F. P. Mathur, D. A. Rennels, J. A. Rohr and D. K. Rubin, "The STAR
+ (Self-Testing And Repairing) Computer: An Investigation of the Theory and Practice of Fault-Tolerant Computer
+ Design," IEEE Transactions on Computers, C-20(11):1312-1321, 1971.{' '}
+ doi:10.1109/T-C.1971.223133
+
+
+ -
+
+ Rasmussen, 2008. Fundamentals of fault-tolerant design for spacecraft guidance, navigation
+ and control, from JPL. Mru: the shrinking quorum is one autonomous response to processor loss. It is not a
+ full fault-protection system and does not replace one.
+
+
+ R. D. Rasmussen, "GN&C Fault Protection Fundamentals," 31st Annual AAS Guidance and Control
+ Conference, Breckenridge, CO, 2008. Jet Propulsion Laboratory. Companion presentation:{' '}
+ NASA NTRS 20100020171.
+
+
+
+
+
+
+
+
+
+
+ What Mru adds
+
+ -
+ Autonomy with no ground team. The step-down from three replicas to one runs on board, with no
+ command from the ground.
+
+ -
+ A small decision core with proofs. The quorum crate is{' '}
+
no_std with no allocation. Kani proves four properties of decide() for every set of
+ three replies. See Kani proofs for the scope of each.
+
+ -
+ Published trade data. Dusk and the{' '}
+ bench publish what the step-down buys in useful work and what it costs in wrong
+ results, with the code to reproduce them.
+
+
+
+
+
diff --git a/src/pages/concepts/qualification.astro b/src/pages/concepts/qualification.astro
new file mode 100644
index 0000000..b5fc681
--- /dev/null
+++ b/src/pages/concepts/qualification.astro
@@ -0,0 +1,203 @@
+---
+import DocsLayout from '../../layouts/DocsLayout.astro';
+import DocsEnd from '../../components/DocsEnd.astro';
+import Breadcrumbs from '../../components/Breadcrumbs.astro';
+
+const crumbs = [
+ { label: 'Docs', href: '/' },
+ { label: 'Concepts', href: '/concepts/shrinking-quorum/' },
+ { label: 'Qualification path' },
+];
+---
+
+
+
+
+ Qualification path
+
+ What exists today, and the NASA and ECSS software standards it relates to. No qualification evidence exists yet.
+ Mru makes no compliance claim.
+
+
+ Standards
+ This page maps Mru to four software standards, two from NASA and two from ECSS:
+
+
+
+
+ | Number |
+ Title |
+
+
+
+
+ | NPR 7150.2 |
+ NASA Software Engineering Requirements |
+
+
+ | NASA-STD-8739.8 |
+ Software Assurance and Software Safety Standard |
+
+
+ | ECSS-E-ST-40C |
+ Space engineering: Software |
+
+
+ | ECSS-Q-ST-80C |
+ Space product assurance: Software product assurance |
+
+
+
+
+
+ The tables below map by topic, not by clause. No clause of any standard has been checked against Mru.
+
+
+ What exists
+
+ These activities run today. They are engineering evidence, not qualification evidence: none was planned, reviewed
+ or recorded under a standard.
+
+
+
+
+
+ | Activity |
+ What exists |
+ Related standards |
+
+
+
+
+ | Unit tests |
+
+ Unit tests of the core and the C interface, run in CI on every change. See{' '}
+ the quorum crate.
+ |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+ | Formal proofs |
+
+ Nine Kani proofs, four on the core and five on the C interface, run in CI on every change. Each has a
+ stated scope. See Kani proofs.
+ |
+ NPR 7150.2, NASA-STD-8739.8, ECSS-E-ST-40C, ECSS-Q-ST-80C |
+
+
+ | Continuous integration |
+
+ Build and test on Linux x86_64, Linux ARM64 and macOS, plus static ARM Linux binaries tested under
+ emulation and a bare-metal ARM Cortex-M build.
+ |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+ | Scenario tests |
+
+ scripts/scenarios.sh runs the demo program and checks its output: faults, limits, resets and
+ the comparison with fixed TMR.
+ |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+ | Bench |
+
+ 300 runs per host with injected faults on three general-purpose processors. Not radiation testing, not
+ target hardware. See Bench.
+ |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+ | F´ unit tests and system test |
+
+ 37 unit tests of the F´ components, and a 60-case system test against the demo's counts. Not run
+ on flight hardware. See F´ components.
+ |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+
+
+
+ Not started
+
+
+
+
+ | Activity |
+ Status |
+ Related standards |
+
+
+
+
+ | Software classification and criticality |
+ Not started |
+ NPR 7150.2, NASA-STD-8739.8, ECSS-Q-ST-80C |
+
+
+ | Requirements traceability |
+ Not started |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+ | Independent verification and validation |
+ Not started |
+ NPR 7150.2, NASA-STD-8739.8, ECSS-E-ST-40C |
+
+
+ | Tool qualification (compiler, Kani, test tools) |
+ Not started |
+ NPR 7150.2, ECSS-Q-ST-80C |
+
+
+ | Rust toolchain qualification plan: TODO |
+ Not started |
+ NPR 7150.2, ECSS-Q-ST-80C |
+
+
+
+ | Coding standard compliance |
+ Not started |
+ NPR 7150.2, ECSS-Q-ST-80C |
+
+
+ | MC/DC structural coverage |
+ Not started |
+ NPR 7150.2, ECSS-E-ST-40C |
+
+
+ | Software development and assurance plans |
+ Not started |
+ NPR 7150.2, NASA-STD-8739.8, ECSS-E-ST-40C, ECSS-Q-ST-80C |
+
+
+
+
+
+ Status as of 11 Oct 2026, flight v0.2.0. The F´ components and the C interface have numbered requirements,
+ each with a verification method, but no trace to mission or standard requirements.
+
+
+
+
+
+
+
From 8942c505f09dcc310a0e84214a972cdd0ae3b941 Mon Sep 17 00:00:00 2001
From: Will Binns
Date: Sun, 11 Oct 2026 13:16:28 +0000
Subject: [PATCH 2/7] Shrinking quorum: proved per tick vs tested per run, two
replicas, command path, open questions
New lede without 'decides exactly as fixed TMR'. Each Kani harness is
linked with its scope. Fixed TMR is framed as the baseline, not as what
spacecraft fly; the Shuttle and degradable systems are cited as prior art.
Adds the Degradation-First Principle and corollary (whitepaper section 5),
the KAT outcomes at two replicas with their gaps, the command path, and
open questions. The 1.34x states its no-ground-support assumption. A
RISK-METRIC marker holds the place for Dusk's per-mission risk.
---
src/pages/concepts/shrinking-quorum.astro | 196 ++++++++++++++++++++--
1 file changed, 178 insertions(+), 18 deletions(-)
diff --git a/src/pages/concepts/shrinking-quorum.astro b/src/pages/concepts/shrinking-quorum.astro
index 5c15dc7..595422d 100644
--- a/src/pages/concepts/shrinking-quorum.astro
+++ b/src/pages/concepts/shrinking-quorum.astro
@@ -8,6 +8,7 @@ const crumbs = [
{ label: 'Concepts', href: '/concepts/shrinking-quorum/' },
{ label: 'Shrinking quorum' },
];
+const proofs = 'https://github.com/mruspace/flight/blob/v0.2.0/quorum/src/lib.rs';
---
@@ -27,8 +32,14 @@ const crumbs = [
Shrinking quorum
- A redundancy policy: vote on three replicas, compare on two, self-check on one. It decides exactly as fixed TMR
- while TMR can run, and continues after TMR stops.
+ A redundancy policy for unattended missions with no repair path: vote on three replicas, compare on two,
+ self-check on one. It keeps running on the last replica, where fixed TMR stops.
+
+
+ Kani proves that, with two or more replicas alive, decide() gives the same outcome under both
+ policies, for every set of three replies. The shrinking quorum also sets diagnose at two replicas, so
+ it can retire a stuck replica and continue where fixed TMR stays in disagreement. Over a whole run, never less
+ than fixed TMR is tested, not proved.
The trouble with a fixed threshold
@@ -37,8 +48,20 @@ const crumbs = [
still detect a disagreement. One cannot outvote anything, so the system stops.
- With a repair crew in reach, stopping is safe: someone swaps the board. With no one in reach, stopping throws away
- the last processor's whole remaining life.
+ Most fault tolerance assumes someone can step in eventually. With a ground team in reach, stopping is safe: the
+ team finds the fault and commands a fallback. With no one in reach, stopping throws away the last processor's
+ whole remaining life.
+
+
+ Fixed TMR is the baseline on these pages because both policies give the same outcome while two or more replicas
+ live. It is not what most spacecraft fly. Most fly dual-string radiation-hardened processors with EDAC, watchdogs
+ and autonomous fault protection. Stepping down from three to two to one is not new either: the Space Shuttle's
+ redundant set of general-purpose computers did it, and Meyer gave degradable systems a measure, performability, in
+ 1980. See Prior art.
+
+
+ What Mru adds: the step-down runs with no ground team, the decision core is small and checked with Kani, and the
+ trade data is published (Dusk, bench).
Three modes
@@ -92,24 +115,117 @@ const crumbs = [
{'}'}
{'}'}
- What it guarantees
+ Degradation-first
+ The shrinking quorum applies the whitepaper's design principle:
+
+ Principle
+
+ "A system intended to operate for millennia without intervention must treat its own physical decay, of
+ power, computation, memory, and thermal capacity, not as an exceptional fault to be handled, but as the
+ constant, governing condition around which every architectural decision is made."
+
+
+
+ Corollary
+
+ "Capability is a depleting resource to be spent, not a fixed budget to be defended. The objective is not to
+ preserve function but to maximize the cumulative useful work extracted across the entire descent from full
+ capability to silence."
+
+
+
+ W. Binns, Mru whitepaper, section 5,
+ doi:10.5281/zenodo.20579438. Dashes in the original are shown as commas.
+
+
+ For the shrinking quorum, the figure of merit is useful work over the whole decline, not correct operation at full
+ strength. Dusk measures it, along with the wrong results it costs.
+
+
+ What is proved and what is tested
+ Proved (per tick)
+
+ Four Kani proofs on decide(). Each reply is any of Absent, Single or{' '}
+ Pair, with any u64 values, so each proof covers every set of three replies to{' '}
+ decide().
+
-
- Never less than fixed TMR. While TMR can still run, both policies make exactly the same
- decision. They differ only after TMR has stopped.
+
+
identical_while_tmr_can_run
+
+ : with two or more replies present, both policies give the same outcome. It compares the outcome only, not the
+ mode or diagnose.
-
- It halts only with nothing left. Fixed TMR stops below two replicas. The shrinking quorum stops
- at zero.
+
+
tmr_stops_below_two
+
+ : with fewer than two replies present, the fixed TMR outcome is Halted.
-
- Only agreed results go out. A delivered value came from at least two replicas, or from both
- runs of the last replica's self-check.
+
+
shrink_halts_only_with_nothing_left
+
+ : the shrinking quorum's outcome is Halted if and only if no reply is present.
+
+ -
+
+
delivers_only_agreed_values
+
+ : if either policy delivers a value, at least two replies agree on it, or exactly one replica is alive and it
+ returned Pair(v, v).
- Each property is a Kani proof over every possible input, run in CI on every change. See{' '}
- Kani proofs.
+ CI runs cargo kani -p quorum -p quorum-ffi on every change. Five more proofs show that the C
+ interface gives the core's answer. The proofs do not cover the health record, the diagnosis, the known-answer
+ test, timing, or the system over a run. See Kani proofs.
+
+
+ Tested (per run)
+ Never less useful work than fixed TMR over a whole run is a test result, with these scopes:
+
+ -
+ Scenario tests.
scripts/scenarios.sh in CI: ten seeds, two kill faults per run,
+ 20,000 ticks. Kill faults only.
+
+ -
+ Bench. 150 pairs of runs per host, five fault schedules, on three hosts with general-purpose
+ processors. The three replicas are processes on one host, not separate processors. No pair below fixed TMR. See{' '}
+ Bench.
+
+ -
+ Dusk. 10,000 simulated missions. The two policies are identical until fixed TMR stops, by
+ construction of the model, and a unit test checks it over 200 seeds. See Dusk.
+
+
+
+ Two replicas
+
+ With two replicas left, decide() compares them. Equal values are delivered. Unequal values give{' '}
+ Detected, and nothing goes out that tick. Under the shrinking quorum it also sets{' '}
+ diagnose. Fixed TMR does not.
+
+
+ The demo then runs a known-answer test (KAT) on both replicas: a fixed input whose result is known. There are
+ three cases.
+
+
+ -
+ Both pass. Nothing is retired. The tick is lost, and nothing escalates. A persistent fault that
+ the KAT cannot see keeps every tick
Detected.
+
+ -
+ Both fail or time out. Both are retired, and the run halts. Fixed TMR would keep comparing.
+
+ -
+ One fails. It is retired. The survivor goes on in self-check.
+
+
+
+ This is the current behavior. The first two cases are gaps: no escalation for a fault the KAT cannot see, and a
+ halt where fixed TMR would go on.
What it costs
@@ -121,15 +237,30 @@ const crumbs = [
Trade
In Dusk's default run, fixed TMR comes out ahead only if one wrong result costs more than 136 years of
- useful work (95% CI 131 to 142).
+ useful work (95% CI 131 to 142). The run assumes no ground support after launch. Planned: a per-mission risk
+ metric from Dusk, the probability of at least one wrong result.
+
+ Command path
+
+ Self-check on one replica can deliver a few wrong results before the KAT catches a stuck fault. The KAT runs every{' '}
+ --kat-period ticks, 64 by default. An upset that hits both self-check runs alike can also get
+ through.
+
+
+ This mode is for data products, not spacecraft commands, unless the mission adds its own command safety layer.
+ Integrators can gate commands on Verdict.mode: issue a command only when the mode is{' '}
+ Vote or Compare and the outcome is Deliver. See the{' '}
+ example.
+
+
Health and diagnosis
A replica outvoted STRIKES = 3 times within STRIKE_WINDOW = 200 ticks is diagnosed with
- a known-answer test: a fixed input whose result is known. Pass, and its strikes are cleared, because the upsets
- were transient. Fail, and it is retired.
+ a known-answer test. Pass, and its strikes are cleared, on the assumption that the upsets were transient. Fail,
+ and it is retired. The strike record has unit tests, not proofs.
Graceful Degradation Index
@@ -139,6 +270,29 @@ const crumbs = [
decline.
+ Open questions
+
+ -
+ Common-mode faults, such as shared power, clock or thermal. Dusk models correlated deaths with{' '}
+
--p-corr. The demo models an upset that hits both self-check runs alike with{' '}
+ --common-mode. Neither models shared power, clock or thermal faults.
+
+ -
+ Input agreement between replicas. In the demo, all replicas get the same input because it is a
+ function of the tick. Real sensor inputs need an agreement step. Mru does not provide one yet.
+
+ -
+ Replica determinism under interrupts and scheduling. The replicas must compute the same bits.
+ In the demo this holds only because the task is a pure function of the tick. Neither Dusk nor the bench tests
+ it.
+
+ -
+ KAT coverage on real hardware. Dusk sets self-check coverage as a parameter,{' '}
+
--coverage. The bench's stuck fault returns the same wrong value for every input, so the KAT
+ always sees it. Neither measures the share of real hardware faults a KAT catches.
+
+
+
-
@@ -148,7 +302,13 @@ const crumbs = [
: the decision core, in Rust
-
- Dusk: 10,000 missions, 1.34× the useful work of fixed TMR
+ Dusk: 10,000 missions, 1.34× the useful work of fixed TMR. This assumes no
+ ground support after launch. The gain falls to 1.00× when support never ends. See{' '}
+ Ground support.
+
+ -
+ Prior art: TMR, degradable systems, the Space Shuttle and deep-space fault
+ protection
-
Research log № 002: the results, written up
From 29e116fb3b0811059bb10856dd5790aa3a194445 Mon Sep 17 00:00:00 2001
From: Will Binns
Date: Sun, 11 Oct 2026 13:16:28 +0000
Subject: [PATCH 3/7] quorum crate: Kani table with scope for all nine proofs,
what is not covered, and a command gate example
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The gate example compiles and runs against v0.2.0; its output is pasted.
F´ page: name the four functions the C interface proofs cover; null
pointers are unit-tested, not proved.
---
src/pages/core/fprime.astro | 6 +-
src/pages/core/quorum-crate.astro | 189 ++++++++++++++++++++++++++++--
2 files changed, 181 insertions(+), 14 deletions(-)
diff --git a/src/pages/core/fprime.astro b/src/pages/core/fprime.astro
index aab51a4..dbf6918 100644
--- a/src/pages/core/fprime.astro
+++ b/src/pages/core/fprime.astro
@@ -238,8 +238,10 @@ void quorum_health_clear(quorum_health *health, uint32_t replica);
Only plain values cross. The health record lives in the caller's memory. Out-of-range input gets the safe
answer: a policy that is not 0 or 1 halts, an unknown reply kind counts as absent, a replica above 2 changes
- nothing, and a null pointer does the same. Five Kani proofs show that each function gives the core's answer
- for every valid input and the safe answer for every other.
+ nothing, and a null pointer does the same. Five Kani proofs show that quorum_mode,{' '}
+ quorum_decide, quorum_health_strike and quorum_health_clear give the
+ core's answer for every valid input, and the safe answer for a bad policy, an unknown reply kind or a replica
+ above 2. Unit tests check the null pointers. See Kani proofs.
Verification
diff --git a/src/pages/core/quorum-crate.astro b/src/pages/core/quorum-crate.astro
index 03fe810..51296cf 100644
--- a/src/pages/core/quorum-crate.astro
+++ b/src/pages/core/quorum-crate.astro
@@ -17,6 +17,7 @@ const crumbs = [
toc={[
{ href: '#install', label: 'Install' },
{ href: '#example', label: 'Example' },
+ { href: '#gate', label: 'Gate commands' },
{ href: '#api', label: 'API' },
{ href: '#proofs', label: 'Kani proofs' },
{ href: '#targets', label: 'Targets and builds' },
@@ -36,7 +37,7 @@ const crumbs = [
no allocation
no dependencies
- 4 Kani proofs
+ 9 Kani proofs
v0.2.0
@@ -65,6 +66,66 @@ quorum = {'{'} git = "https://github.com/mruspace/flight"
{'}'}
{'}'}
+ Gate commands on the mode
+
+ On one replica, self-check can deliver a few wrong results before the periodic known-answer test catches a stuck
+ fault. Use that mode for data products, not spacecraft commands, unless the mission adds its own command safety
+ layer. This example issues a command only when the mode is Vote or Compare and the
+ outcome is Deliver. See Command path.
+
+ //! Gate commands on the mode. Only a result that two or more replicas agree
+//! on (vote or compare) may command the spacecraft. A result from the last
+//! replica's self-check goes out as a data product only.
+use quorum::{'{'}decide, Mode, Outcome, Policy, Reply, REPLICAS{'}'};
+
+/// What to do with one tick's result.
+enum Action {'{'}
+ /// Agreed by two or more replicas: may be used as a command.
+ Command(u64),
+ /// Self-check on the last replica: data product only.
+ Data(u64),
+ /// Nothing to send this tick.
+ Hold,
+{'}'}
+
+fn gate(replies: &[Reply; REPLICAS]) -> Action {'{'}
+ let verdict = decide(Policy::Shrink, replies);
+ match (verdict.mode, verdict.outcome) {'{'}
+ (Mode::Vote | Mode::Compare, Outcome::Deliver(x)) => Action::Command(x),
+ (Mode::SelfCheck, Outcome::Deliver(x)) => Action::Data(x),
+ _ => Action::Hold,
+ {'}'}
+{'}'}
+
+fn main() {'{'}
+ use Reply::{'{'}Absent, Pair, Single{'}'};
+ let ticks = [
+ [Single(7), Single(7), Single(9)], // vote: two agree on 7
+ [Absent, Single(7), Single(7)], // compare: both say 7
+ [Absent, Single(7), Single(9)], // compare: mismatch
+ [Absent, Absent, Pair(7, 7)], // self-check on the last replica
+ [Absent, Absent, Absent], // nothing left
+ ];
+ for replies in &ticks {'{'}
+ match gate(replies) {'{'}
+ Action::Command(x) => println!("{'{'}replies:?{'}'}: command {'{'}x{'}'}"),
+ Action::Data(x) => println!("{'{'}replies:?{'}'}: data product {'{'}x{'}'}"),
+ Action::Hold => println!("{'{'}replies:?{'}'}: hold"),
+ {'}'}
+ {'}'}
+{'}'}
+
+ Its output, from cargo run against v0.2.0:
+
+ [Single(7), Single(7), Single(9)]: command 7
+[Absent, Single(7), Single(7)]: command 7
+[Absent, Single(7), Single(9)]: hold
+[Absent, Absent, Pair(7, 7)]: data product 7
+[Absent, Absent, Absent]: hold
+
API
const REPLICAS: usize = 3
Number of replicas.
@@ -190,13 +251,16 @@ quorum = {'{'} git = "https://github.com/mruspace/flight"
reset or hand it to C.
- From C or C++, use the C interface, quorum.h. Kani proves that each of
- its functions gives this crate's answer.
+ From C or C++, use the C interface, quorum.h. Kani proves that{' '}
+ quorum_mode, quorum_decide, quorum_health_strike and{' '}
+ quorum_health_clear give this crate's answer.
Kani proofs
- Run with cargo kani -p quorum. Each holds for every possible input.
+ Nine proofs: four on the core in quorum, five on the C interface in quorum-ffi. CI runs
+ cargo kani -p quorum -p quorum-ffi on every change. In the core proofs, each reply is any of
+ Absent, Single or Pair, with any u64 values.
@@ -204,28 +268,129 @@ quorum = {'{'} git = "https://github.com/mruspace/flight"
| Proof |
Property |
+ Scope |
- | identical_while_tmr_can_run |
- With two or more replicas alive, both policies decide the same. |
+
+
+ identical_while_tmr_can_run
+
+ |
+ With two or more replies present, both policies give the same outcome. |
+
+ Every set of three replies with two or more present. Outcome only, not mode or diagnose.
+ |
+
+
+ |
+ tmr_stops_below_two
+ |
+
+ With fewer than two replies present, fixed TMR's outcome is Halted.
+ |
+ Every set of three replies with fewer than two present. |
+
+
+ |
+
+ shrink_halts_only_with_nothing_left
+
+ |
+
+ The shrinking quorum's outcome is Halted if and only if no reply is present.
+ |
+ Every set of three replies. |
+
+
+ |
+
+ delivers_only_agreed_values
+
+ |
+
+ A delivered value has two agreeing replies, or exactly one replica alive that returned{' '}
+ Pair(v, v).
+ |
+ Every set of three replies, under both policies. |
+
+
+ |
+ decide_is_the_core
+ |
+
+ quorum_decide gives the core's verdict. An unknown reply kind counts as absent.
+ |
+ C interface: policy 0 or 1, any reply kind and values. |
- | tmr_stops_below_two |
- Fixed TMR halts below two replicas. |
+
+ bad_policy_halts
+ |
+
+ Any other policy code halts quorum_decide and quorum_mode.
+ |
+ C interface: any policy code above 1. |
- | shrink_halts_only_with_nothing_left |
- The shrinking quorum halts only at zero. |
+
+ mode_is_the_core
+ |
+
+ quorum_mode gives the core's mode.
+ |
+
+ C interface: policy 0 or 1, any u32 count.
+ |
- | delivers_only_agreed_values |
- A delivered value had two votes, or a clean self-check. |
+
+ strike_is_the_core
+ |
+
+ quorum_health_strike gives the core's answer and record. A replica above 2 changes
+ nothing.
+ |
+
+ C interface: any record with counts in the u32 range, any replica and cycle.
+ |
+
+
+ |
+ clear_is_the_core
+ |
+
+ quorum_health_clear gives the core's record. A replica above 2 changes nothing.
+ |
+
+ C interface: any record with counts in the u32 range, any replica.
+ |
+ Each proof name links to its source at v0.2.0.
+ Not covered
+
+ -
+
+
Health in the core.
+ {' '}
+ Unit tests only.
+
+ -
+ Diagnosis and the known-answer test. They run in the demo and in F´, not in the core.
+
+ -
+ Timing. The proofs say what
decide() returns, not how long it takes. The
+ bench measures that.
+
+ -
+ The system over a run. Never less than fixed TMR over a whole run is tested, not proved. See
+ Tested (per run).
+
+
Targets and builds
CI builds and tests on every change:
From dcbcf5d9ac397224e2b4f77c5ecf6cf3d48bde66 Mon Sep 17 00:00:00 2001
From: Will Binns
Date: Sun, 11 Oct 2026 13:16:29 +0000
Subject: [PATCH 4/7] Dusk: --bin dusk in the commands, column definitions from
the model, ground support section
cargo run needs --bin because the package has two programs. Times are
from a run on an Apple M4. Useful, service and wrong days are defined as
src/model.rs computes them. The ground table is pasted from a real run and
the 1.34x states that it falls to 1.00x when support never ends. A
DUSK-BASELINES marker holds the place for the new baselines.
---
src/pages/simulation/dusk.astro | 83 +++++++++++++++++++++++++++------
1 file changed, 70 insertions(+), 13 deletions(-)
diff --git a/src/pages/simulation/dusk.astro b/src/pages/simulation/dusk.astro
index 5c36e2f..6d6764b 100644
--- a/src/pages/simulation/dusk.astro
+++ b/src/pages/simulation/dusk.astro
@@ -15,7 +15,9 @@ const crumbs = [{ label: 'Docs', href: '/' }, { label: 'Simulation', href: '/sim
{ href: '#options', label: 'Options' },
{ href: '#model', label: 'The fault model' },
{ href: '#results', label: 'Default results' },
- { href: '#sweep', label: 'Sweeps and ground' },
+ { href: '#definitions', label: 'What the columns mean' },
+ { href: '#sweep', label: 'Sweeps' },
+ { href: '#ground', label: 'Ground support' },
{ href: '#bench', label: 'Checked against the bench' },
{ href: '#claims', label: 'What this does not claim' },
]}
@@ -40,13 +42,14 @@ const crumbs = [{ label: 'Docs', href: '/' }, { label: 'Simulation', href: '/sim
cargo run --release # the default scenario, about 2 s
-cargo run --release -- --spares 2 # add salvaged processors
-cargo run --release -- --sweep # sensitivity, about 30 s
-cargo run --release -- --ground # against TMR with a ground team, about 10 s
-cargo run --release --bin charts # redraw the charts and data.json
+ >cargo run --release --bin dusk # the default scenario, about 2 s
+cargo run --release --bin dusk -- --spares 2 # add salvaged processors
+cargo run --release --bin dusk -- --sweep # sensitivity, about 1 minute
+cargo run --release --bin dusk -- --ground # against TMR with a ground team, about 12 s
+cargo run --release --bin charts # redraw the charts and data.json, about 2 minutes
- Times are for an 8-core laptop. Results depend only on the seed, never on the thread count.
+ The package has two programs, so cargo run needs --bin. Times are for an Apple M4 with
+ 10 cores. Results depend only on the seed, never on the thread count.
Options
@@ -154,18 +157,72 @@ fixed TMR 99.0 37.6 92.7 168.9 99.0 0.000
standby simplex 83.1 38.4 78.3 134.0 166.4 0.603
shrinking quorum 132.6 64.3 126.6 208.3 166.4 0.246
- 1.34× the useful work of fixed TMR in total (95% CI 1.33× to 1.35×). Never less on any single mission.
+ 1.34× the useful work of fixed TMR in total (95% CI 1.33× to 1.35×). This assumes no ground support after launch.
+ The gain falls to 1.00× when support never ends. See Ground support. Never less on any
+ single mission, by construction: the two policies are identical until fixed TMR stops.
+
+
+ Standby simplex is the nearest model here of dual-string with autonomous switchover. It runs one self-checking
+ processor at a time and swaps in the next when it dies.
+
+
+ What the columns mean
+
+ Each mission runs one day at a time. On each day the policy runs in one mode, set by the number of live
+ processors, and the lowest-numbered live processors do the work. These are the definitions in{' '}
+ src/model.rs.
+
+
+ -
+ Useful. The sum over days of throughput credit for a correct delivered result: 1.0 for a vote
+ day with at most one upset, 1.0 for a pair day with no upset, 0.5 (
--selfcheck-throughput) for a
+ single self-check day with no upset, and 0 for lost, wrong and idle days. Shown as the mean in years, with the
+ 10th, 50th and 90th percentiles.
+
+ -
+ Service. The first day the policy can never produce output again, or the horizon. For fixed
+ TMR, the first day with fewer than two live processors. For the others, the first day with none left. The model
+ ends the run that day, so a spare due to join later is not used. Shown as the mean in years.
+
+ -
+ Wrong days. Days whose delivered result was corrupted by an upset that nothing caught. One day
+ is one result. Only a lone processor can make one: its self-check misses an upset with probability 1 minus{' '}
+
--coverage. Shown as the mean per mission.
+
+
+
+ A vote day with two or more upsets and a pair day with any upset are lost: the policy catches the disagreement and
+ delivers nothing.
- Sweeps and ground support
+
+
+ Sweeps
--sweep varies each parameter the model cannot pin down. Across every row, the gain over fixed TMR
- stays between 1.11× and 1.68×.
+ stays between 1.11× and 1.68×. Every row assumes no ground support after launch.
+
+ Ground support
- --ground adds a ground team that commands the fallback by hand while support lasts. With 49 years of
- support, Voyager's so far, the gain is still 1.25×. Answer time barely matters. What matters is whether anyone
- is still there.
+ The 1.34× above assumes no ground support after launch. --ground compares the shrinking quorum with
+ fixed TMR plus a ground team. When TMR drops to one processor, the team commands it into self-check after an
+ answer time, if support has not ended. The gain falls as support lasts longer:
+
+ 10000 missions, seed 1; shrinking quorum's useful work vs TMR + ground fallback
+
+ground support ends 1 day 30 days 180 days 95% CI at 30 days
+at launch 1.34x 1.34x 1.34x 1.33x to 1.35x
+after 10 years 1.33x 1.33x 1.33x 1.33x to 1.34x
+after 25 years 1.31x 1.31x 1.31x 1.30x to 1.32x
+after 50 years 1.25x 1.25x 1.25x 1.24x to 1.25x
+after 100 years 1.11x 1.11x 1.11x 1.10x to 1.11x
+after 200 years 1.01x 1.01x 1.01x 1.01x to 1.01x
+never 1.00x 1.00x 1.00x 1.00x to 1.00x
+
+ With support that never ends, the gain is 1.00×: the ground does by hand what the shrinking quorum does alone.
+ With 49 years of support, Voyager's so far, the charts program gives 1.25×. Answer time barely matters. What
+ matters is whether anyone is still there.
Checked against the bench
From 5c94909d1ebc5e106ae5867e4290b94ea852ae67 Mon Sep 17 00:00:00 2001
From: Will Binns
Date: Sun, 11 Oct 2026 13:16:29 +0000
Subject: [PATCH 5/7] Commands and outputs from real runs; layers not built;
OPS-SAT proposed; llms.txt summary
Quickstart uses --bin quorum and --bin dusk (cargo run alone is
ambiguous in both repos) and shows the real output lines. Bench run times
measured on an Apple M4. Bench page no longer says both policies 'make the
same decision'. Architecture labels Layers 0 and 2 to 5 'Not built' and
the 1.34x states its ground assumption. llms.txt: no TRL, nine proofs (four
core, five C interface).
---
scripts/seo/config.mjs | 2 +-
src/pages/concepts/architecture.astro | 30 +++++++++++++---------
src/pages/core/bench.astro | 11 ++++----
src/pages/core/quorum-cli.astro | 29 +++++++++++++--------
src/pages/index.astro | 36 ++++++++++++++++-----------
5 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/scripts/seo/config.mjs b/scripts/seo/config.mjs
index 0b5d7ff..f45f72a 100644
--- a/scripts/seo/config.mjs
+++ b/scripts/seo/config.mjs
@@ -6,7 +6,7 @@ export default {
drop: ['script', 'style', 'button', 'form', '.prevnext'],
title: 'Mru docs',
summary:
- "Reference for Mru's open core: the shrinking-quorum decision crate and its fault-injection demo (Rust, no_std, four Kani proofs), the Dusk simulator and the Mru 2049 browser flight simulator. Prototype at TRL 3; code under Apache 2.0.",
+ "Reference for Mru's open core, for unattended missions with no repair path: the shrinking-quorum decision crate and its fault-injection demo (Rust, no_std, nine Kani proofs: four on the core, five on the C interface), the Dusk simulator and the Mru 2049 browser flight simulator. Prototype on general-purpose processors, not flight hardware; code under Apache 2.0.",
intro:
'Product pages, use cases and research results are at https://mru.space/llms.txt. Questions: contact@mru.space.',
sections: [
diff --git a/src/pages/concepts/architecture.astro b/src/pages/concepts/architecture.astro
index 33d2b60..f9d93b1 100644
--- a/src/pages/concepts/architecture.astro
+++ b/src/pages/concepts/architecture.astro
@@ -72,7 +72,7 @@ const crumbs = [
Layers 0 to 5
- Only Layer 1 has code today. Layers 0 and 2 to 5 exist only in the whitepaper.
+ Only Layer 1 has code today. Layers 0 and 2 to 5 are not built. They exist only in the whitepaper.
@@ -88,7 +88,7 @@ const crumbs = [
| 0 · Survival kernel |
§7 |
- None |
+ Not built |
Paper |
None |
@@ -111,28 +111,28 @@ const crumbs = [
| 2 · Navigation and orientation |
§9 |
- None |
+ Not built |
Paper |
None |
| 3 · Science and knowledge triage |
§10 |
- None |
+ Not built |
Paper |
None |
| 4 · Communication |
§11 |
- None |
+ Not built |
Paper |
None |
| 5 · Bounded self-modification |
§12 |
- None |
+ Not built |
Paper |
None |
@@ -259,13 +259,13 @@ const crumbs = [
Products and research
-
- Mru Flight runs Layer 1 on spacecraft. The F´ components
RedundancyManager,{' '}
+ Mru Flight is Layer 1 for spacecraft. The F´ components RedundancyManager,{' '}
HealthRegistry and ReplicaHost are built and tested: 37 unit tests, and a system test
- that gives the demo's counts on the bench schedules. They have not run on flight hardware. A launcher for{' '}
- ESA's OPS-SAT is in the repository.
+ against the demo's counts on the bench schedules. They have not run on flight hardware. A launcher for a{' '}
+ proposed experiment on ESA's OPS-SAT is in the repository.
-
- Mru Field runs the same Layer 1 core on systems on Earth that are hard to reach. See{' '}
+ Mru Field is the same Layer 1 core for systems on Earth that are hard to reach. See{' '}
Mru Field.
-
@@ -301,10 +301,16 @@ const crumbs = [
mru.space
-
- Shrinking quorum: the Layer 1 rule and its guarantees
+ Shrinking quorum: the Layer 1 rule, what is proved and what is tested
+
+ -
+ Qualification path: what exists against the NASA and ECSS software
+ standards
-
- Dusk: 10,000 missions, 1.34× the useful work of fixed TMR
+ Dusk: 10,000 missions, 1.34× the useful work of fixed TMR. This assumes no
+ ground support after launch. The gain falls to 1.00× when support never ends. See{' '}
+ Ground support.
diff --git a/src/pages/core/bench.astro b/src/pages/core/bench.astro
index bcd21bb..e8c1448 100644
--- a/src/pages/core/bench.astro
+++ b/src/pages/core/bench.astro
@@ -227,9 +227,10 @@ const results = 'https://github.com/mruspace/flight/tree/main/bench/results';
20,000 ticks per run. Results for all three upset rates are in the JSON files.
In all 150 pairs of runs, the shrinking quorum delivered at least as many correct results as fixed TMR on the same
- seed and faults. While two or more replicas live, both policies make the same decision, as the{' '}
- Kani proofs show. The gain comes after TMR stops: TMR halts at the second
- loss, or, in the stuck schedule, keeps comparing a good replica with a stuck one and rejects every result.
+ seed and faults. This is a test result over these runs, not a proof. On the same replies, both policies give the
+ same outcome each tick, as the Kani proofs show. The runs differ because
+ the shrinking quorum keeps going and retires bad replicas: TMR halts at the second loss, or, in the stuck
+ schedule, keeps comparing a good replica with a stuck one and rejects every result.
Wrong results
@@ -453,8 +454,8 @@ const results = 'https://github.com/mruspace/flight/tree/main/bench/results';
Run it
# in a clone of mruspace/flight
-./scripts/bench.sh # 300 runs, about 2 minutes on an Apple M4
-./scripts/bench.sh --quick # 2 seeds, 5,000 ticks
+./scripts/bench.sh # 300 runs, about 3 minutes on an Apple M4
+./scripts/bench.sh --quick # 2 seeds, 5,000 ticks, about 15 s
cargo run --release -p bench # the cost of the core only
The script writes bench/results/<date>-<host>.json and .csv, with the host,
diff --git a/src/pages/core/quorum-cli.astro b/src/pages/core/quorum-cli.astro
index b59256d..c385216 100644
--- a/src/pages/core/quorum-cli.astro
+++ b/src/pages/core/quorum-cli.astro
@@ -190,15 +190,23 @@ const crumbs = [
stopped, halted and sensor flips. --progress-every N adds running totals.{' '}
--summary file.txt writes the final report for downlink.
- quorum --policy shrink ... useful=14989 detected=11 wrong=0 halted_at=never
+
+ The run from the Quickstart,{' '}
+ --policy shrink --ticks 20000 --seed 1 --upset-rate 0.001 --fault kill:0@5000 --fault kill:1@10000,
+ prints:
+
+ policy=shrink ticks=20000 seed=1 upset_rate=0.001
+useful=14989 detected=11 wrong=0 halted_at=never alive_at_end=1 stopped=completed last_useful=20000
+footprint: voter_max_rss=1920KiB replica_max_rss=1808KiB cpu=0.48s wall=0.46s
+limits: memory=128MB/process cpu_time=none cpu_share=none max_run=none reply_timeout=2000ms
+
+ flight v0.2.0 on an Apple M4. The footprint line varies by host.
+
- The summary also gives last_useful, the tick of the last correct result. With a scheduled stuck, hang
- or corrupt fault, it adds a detection: line: the faults injected, how many the voter caught, and the
- mean and longest ticks from fault to first reaction. The bench runs this program over a
- matrix of faults.
+ last_useful is the tick of the last correct result. With a scheduled stuck, hang or corrupt fault,
+ the output adds a detection: line: the faults injected, how many the voter caught, and the mean and
+ longest ticks from fault to first reaction. The bench runs this program over a matrix
+ of faults.
Resets and power cuts
@@ -221,8 +229,9 @@ const crumbs = [
On OPS-SAT
- opssat/run.sh starts, checks and stops a run with all limits set. Tagged releases ship each static
- Linux binary (three ARM, one x86_64) with the launcher, a sample fault schedule and the operations note.
+ For a proposed experiment on ESA's OPS-SAT. The experiment has not been accepted. opssat/run.sh{' '}
+ starts, checks and stops a run with all limits set. Tagged releases ship each static Linux binary (three ARM, one
+ x86_64) with the launcher, a sample fault schedule and the operations note.
diff --git a/src/pages/index.astro b/src/pages/index.astro
index b8ca37b..c697730 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -7,16 +7,18 @@ import DocsLayout from '../layouts/DocsLayout.astro';
Overview
Mru documentation
- Reference for Mru's open core: the shrinking-quorum runtime, the Dusk simulator, and the tools around them.
+ Reference for Mru's open core, for unattended missions with no repair path: the shrinking-quorum runtime, the
+ Dusk simulator, and the tools around them.
Where to start
@@ -151,19 +161,29 @@ cargo run --release --bin charts # redraw the char
Default results
- policy useful p10 p50 p90 service wrong days
- mean y mean y mean / run
-fixed TMR 99.0 37.6 92.7 168.9 99.0 0.000
-standby simplex 83.1 38.4 78.3 134.0 166.4 0.603
-shrinking quorum 132.6 64.3 126.6 208.3 166.4 0.246
+ policy useful p10 p50 p90 service wrong days risk
+ mean y mean y mean / run P(>=1)
+fixed TMR 99.0 37.6 92.7 168.9 99.0 0.000 0.0%
+standby simplex 83.1 38.4 78.3 134.0 166.4 0.603 43.2%
+shrinking quorum 132.6 64.3 126.6 208.3 166.4 0.246 20.1%
+TMR + unchecked simplex 166.2 76.9 156.7 267.9 166.4 24.715 87.2%
+cold standby, aging 0.1 144.7 69.7 139.3 226.7 289.8 1.043 61.3%
+cold standby, aging 1.0 83.1 38.4 78.3 134.0 166.4 0.603 43.2%
- 1.34× the useful work of fixed TMR in total (95% CI 1.33× to 1.35×). This assumes no ground support after launch.
- The gain falls to 1.00× when support never ends. See Ground support. Never less on any
- single mission, by construction: the two policies are identical until fixed TMR stops.
+ {t('dusk.work_vs_tmr')} the useful work of fixed TMR in total (95% CI {ci('dusk.work_vs_tmr')}). This assumes no
+ ground support after launch. The gain falls to {t('dusk.ground.never')} when support never ends. See{' '}
+ Ground support. Never less on any single mission, by construction: the two policies are
+ identical until fixed TMR stops. Fixed TMR comes out ahead only if one wrong result costs more than{' '}
+ {t('dusk.break_even_years')} years of useful work (95% CI {ci('dusk.break_even_years')}), next to a risk of{' '}
+ {t('dusk.risk.shrink')} against {t('dusk.risk.tmr')}.
- Standby simplex is the nearest model here of dual-string with autonomous switchover. It runs one self-checking
- processor at a time and swaps in the next when it dies.
+ Cold standby is the nearest model here of dual-string with autonomous switchover. Standby simplex is the same
+ design with spares that age as fast as a powered processor, so it equals cold standby at aging 1.0. See{' '}
+ Baselines.
What the columns mean
@@ -176,8 +196,8 @@ shrinking quorum 132.6 64.3 126.6 208.3
Useful. The sum over days of throughput credit for a correct delivered result: 1.0 for a vote
day with at most one upset, 1.0 for a pair day with no upset, 0.5 (--selfcheck-throughput) for a
- single self-check day with no upset, and 0 for lost, wrong and idle days. Shown as the mean in years, with the
- 10th, 50th and 90th percentiles.
+ single self-check day with no upset, 1.0 for an unchecked day with no upset, and 0 for lost, wrong and idle
+ days. Shown as the mean in years, with the 10th, 50th and 90th percentiles.
Service. The first day the policy can never produce output again, or the horizon. For fixed
@@ -187,7 +207,10 @@ shrinking quorum 132.6 64.3 126.6 208.3
Wrong days. Days whose delivered result was corrupted by an upset that nothing caught. One day
is one result. Only a lone processor can make one: its self-check misses an upset with probability 1 minus{' '}
- --coverage. Shown as the mean per mission.
+ --coverage, and an unchecked processor delivers every upset. Shown as the mean per mission.
+
+
+ Risk. The share of missions with at least one wrong day, with a paired bootstrap 95% CI.
@@ -195,12 +218,38 @@ shrinking quorum 132.6 64.3 126.6 208.3
delivers nothing.
-
+ Baselines
+
+ Fixed TMR is one baseline, not what most spacecraft fly. Two more act with no ground team, on the same fault
+ histories.
+
+
+ -
+ TMR + unchecked simplex steps down on its own, but its last processor does not check itself. It
+ isolates the value of self-check. The shrinking quorum does {t('dusk.work_vs_unchecked')} of its useful work and
+ makes {t('dusk.wrong_vs_unchecked')} of its wrong results (95% CI {ci('dusk.wrong_vs_unchecked')}). Risk:{' '}
+ {t('dusk.risk.unchecked')} against {t('dusk.risk.shrink')}.
+
+ -
+ Cold standby keeps one processor powered and switches on the next, in order, when it dies. The
+ active one self-checks. Here it has three strings, on the same hardware as TMR. Correlated deaths follow the
+ powered fault history, which slightly under-counts them for an unpowered spare.
+
+
+
+ How fast an unpowered spare ages is not known, so --sweep varies it from 0.1 to 1.0 of the powered
+ rate. Against cold standby, the shrinking quorum does {t('dusk.work_vs_cold.01')} the useful work at 0.1 (95% CI{' '}
+ {ci('dusk.work_vs_cold.01')}) and {t('dusk.work_vs_cold.10')} at 1.0 (95% CI {ci('dusk.work_vs_cold.10')}). Cold
+ standby does more useful work below an aging rate of about {t('dusk.cold.crossing')}. At every rate it has more
+ missions with a wrong result: {t('dusk.risk.cold_10')} to {t('dusk.risk.cold_01')}, against{' '}
+ {t('dusk.risk.shrink')}. With two strings (--nodes 2), the shrinking quorum does{' '}
+ {t('dusk.nodes2.work_vs_cold.01')} to {t('dusk.nodes2.work_vs_cold.10')} the useful work of cold standby.
+
Sweeps
- --sweep varies each parameter the model cannot pin down. Across every row, the gain over fixed TMR
- stays between 1.11× and 1.68×. Every row assumes no ground support after launch.
+ --sweep varies each parameter the model cannot pin down. Across every row, the gain over fixed TMR is{' '}
+ {t('dusk.sweep.range')}. Every row assumes no ground support after launch.
Ground support
diff --git a/src/styles/shared/site.css b/src/styles/shared/site.css
index cba5bd5..9a3e64a 100644
--- a/src/styles/shared/site.css
+++ b/src/styles/shared/site.css
@@ -167,10 +167,25 @@ html.js .quorum-fallback {
.log a.entry[hidden] {
display: none;
}
-/* First section of a research entry: its heading sits on the top rule. */
-.entry-body > .article:first-child .body > h2:first-child {
+/* Research entry sections: the space between sections sits above the section,
+ not on its heading, so a margin note starts level with its own heading
+ (the first heading sits on the top rule). */
+.entry-body > .article .body > h2:first-child {
margin-top: 0;
}
+.entry-body > .article + .article {
+ margin-top: 56px;
+}
+/* A number cell that may wrap at its space on a narrow screen, e.g. a ratio
+ with the lowest seed in brackets: "1.50 (1.50)". */
+.tbl td.m.wrap {
+ white-space: normal;
+}
+/* A margin note is running text: the label on its own line, then links and
+ code inline. .note is a flex column for cards, which split it at each link. */
+.article .note {
+ display: block;
+}
/* Tablets (no canvas artboard): from 641 to 920 px the seven nav links and the
button do not fit, so the header uses the phone menu, as below 640 px. */
From 02cf618c56349a1009b0e6a07ac71923303c54df Mon Sep 17 00:00:00 2001
From: Will Binns
Date: Sun, 11 Oct 2026 13:44:50 +0000
Subject: [PATCH 7/7] Architecture page: Dusk numbers from claims.json
---
src/pages/concepts/architecture.astro | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/src/pages/concepts/architecture.astro b/src/pages/concepts/architecture.astro
index dcf739b..a2108c7 100644
--- a/src/pages/concepts/architecture.astro
+++ b/src/pages/concepts/architecture.astro
@@ -2,6 +2,7 @@
import DocsLayout from '../../layouts/DocsLayout.astro';
import DocsEnd from '../../components/DocsEnd.astro';
import Breadcrumbs from '../../components/Breadcrumbs.astro';
+import { t } from '../../data/claims';
const crumbs = [
{ label: 'Docs', href: '/' },
@@ -309,9 +310,9 @@ const crumbs = [
standards
- Dusk: 10,000 missions, 1.34× the useful work of fixed TMR. This assumes no
- ground support after launch. The gain falls to 1.00× when support never ends. See{' '}
- Ground support.
+ Dusk: {t('dusk.runs')} missions, {t('dusk.work_vs_tmr')} the useful work of
+ fixed TMR. This assumes no ground support after launch. The gain falls to {t('dusk.ground.never')} when support
+ never ends. See Ground support.