docs/PRINCIPLES.md
back to source
# Principles
NumericalOS is developed under a stated set of commitments. They are drawn
from Catholic social teaching, and each one that can be enforced by a test is
enforced by a test in `tests/test_principles.py`. A principle that nothing
checks is decoration.
Two things this document is not. It does not claim any endorsement by the
Church, and it does not speak for the Magisterium: it records what *this
project* has bound itself to, and cites the sources it took those obligations
from. Citations are to the Catechism of the Catholic Church (CCC) as published
at vatican.va, and each quotation below was checked against that text rather
than recalled.
---
## 1. Truthfulness
> **CCC 2469** -- "Men could not live with one another if there were not mutual
> confidence that they were being truthful to one another." The virtue of truth
> gives another his just due.
This is the oldest commitment in the project and predates its articulation
here. Software that will run as PID 1 asks for a great deal of trust, and the
only thing that makes that trust reasonable is an accurate account of what has
and has not been established.
In practice:
- The status line reads **"bootstrap logic tested; x86_64 QEMU self-init PASS
(degraded=0) on kernel+initrd and hybrid ISO/GRUB serial; fleet bare-QEMU
PASS-degraded; metal and non-x86_64 unverified"** and is not softened into a
general “it boots” claim. Hardware and non-x86_64 remain unobserved.
- Only `numericalos-verify-boot` may claim a boot, and only for the one
artifact on the one architecture it observed. Build skills produce artifacts
and say exactly that. A prior QEMU observation does not license the next build.
- `/docs/status/` enumerates every known residual, including the unflattering
ones. **Understating a limitation is treated as the same class of defect as
overstating a capability.**
- A fail-closed halt is reported as correct behaviour with a named reason, not
disguised as success.
Enforced: `TestTruthfulness` asserts the status line is present in both the
README and the published status page, and that no source file claims a
verified boot.
---
## 2. Respect for the person, including privacy
> **CCC 1907** -- the common good "presupposes respect for the person as such",
> including the right "to safeguard . . . privacy".
The owner of a machine is not this project's data source. A boot fetches what
it needs to boot and nothing else.
In practice:
- **No telemetry.** No beacon, no identity ping, no usage report, no
phone-home on failure.
- Every outbound request goes through one function, `numos_fetch`, so there is
exactly one place to audit.
- Requests carry no query parameters, so nothing is smuggled in a URL, and the
boot path issues no POST.
- The base URL is a parameter (`NUMOS_BASE`). A machine can be pointed at a
mirror the operator controls, or given none at all.
Enforced: `TestNoSurveillance` runs a real boot against a recording HTTP
server and asserts the exact set of requested paths, that none carries a query
string, that none is a POST, and that no network tool is invoked outside
`numos_fetch`.
### The topology join, and why it is not a beacon
The join contract sends a capability document to a coordinator. That is an
outbound signal, so the distinction has to be principled rather than
convenient:
> **telemetry** is the *project* harvesting from the *operator's* machine.
> **a join** is the *operator's* machine reporting to the *operator's own*
> coordinator.
The principle protects the person from the project. It does not put a machine
beyond the reach of its owner. Four properties keep the join on the right side
of that line, and all four are load-bearing rather than decorative:
1. **Off by default.** No `NUMOS_COORDINATOR` means no network contact, ever.
The capability is still written to disk, so the node stays observable
without anything leaving it.
2. **Never to this project.** The destination is whatever the operator named.
`numericalos.com` is not a fallback and is not consulted.
3. **Inspectable before sending.** The exact bytes are written to
`$NUMOS_RUNDIR/capability` first, so an operator can read precisely what
would leave the machine.
4. **Refusal is a state, not an error.** `disabled` is a normal, recorded
outcome.
Enforced: `TestJoinIsOffByDefault` runs the join with a live coordinator
listening and `NUMOS_COORDINATOR` unset, and asserts the coordinator received
nothing; a separate test asserts the bytes sent are byte-identical to the file
written first.
---
## 3. Subsidiarity
> **CCC 1883** -- "a community of a higher order should not interfere in the
> internal life of a community of a lower order, depriving the latter of its
> functions, but rather should support it in case of need and help to
> co-ordinate its activity with the activities of the rest of society, always
> with a view to the common good."
This one is not an overlay; it describes the architecture that was already
there, and it is the reason several decisions went the way they did.
In practice:
- **A machine boots with no network, always.** A verified on-disk artifact is
used without contacting anything. The network is a fallback, never a
precondition.
- **Remediation is local first.** A health predicate's `local_action` runs
with no network at all.
- **Escalation is help, not dependency.** An `on_fire` swarm reference is
appended to a queue and drained later. An offline node keeps supervising
itself; nothing about a tick waits on reachability.
- **A degraded node stays in the fleet and says so** rather than dropping out
or pretending to be healthy, so the coordinator can stop scheduling onto it
without losing it.
- The `curl | sh` installer **does not replace PID 1**, even when asked. It
installs into a prefix and prints what taking PID 1 would actually involve.
Enforced: `TestSubsidiarity` runs a node with an unreachable base and asserts
that a health predicate still fires, that local remediation still applies, and
that the escalation is queued and persisted rather than dropped.
---
## 4. The common good, and what we publish
> **CCC 1906** -- the common good is "the sum total of social conditions which
> allow people, either as groups or as individuals, to reach their fulfillment
> more fully and more easily."
The project ships knowledge rather than artifacts. There are no images to
download here; the skills drive a build on the user's own machine, from a
repository they can clone and read first.
In practice:
- The repository is served as static files over dumb-HTTP -- no forge, no
account, no server-side code -- so what you receive can be verified against
its history before you run it.
- What is tracked is source someone could review, not generated output they
could not.
- Every published artifact's hash is computed at build time from the file
actually served, and the manifest is the single authority the boot checks
against.
Enforced: `TestWhatWePublish` asserts that no build output and no tooling
cache is tracked. Both failed once. 917 files of generated site output were
committed and republished before the ignore rule was found to be too narrow,
and a `wrangler` cache carrying the Cloudflare account id and an email-derived
account name was published before it was caught.
---
## 5. Stewardship
The machine belongs to its operator, and its resources are not ours to waste.
In practice:
- Restart backoff doubles to a ceiling, so a crash-looping unit is throttled
rather than spinning at full speed. This was a real defect: the shipped
defaults truncated to `sleep 0` and provided no throttling at all until it
was found.
- The bootstrap is zero-compile-first, so the widest range of hardware can run
it without a toolchain -- including old and slow machines that a
compile-first design would exclude.
- `OSUnit.resource_envelope` is enforced -- or refused. Closing this gap
exposed an honest split in what a POSIX shell can actually do:
| field | on the shell floor |
|---|---|
| `ram_mb` | enforced, via `ulimit -v` on the unit's own process |
| `timeout_s` | enforced, via `timeout(1)`; a unit that overruns is stopped |
| `cpu_pct` | **cannot** be enforced -- a percentage needs cgroups, and `ulimit -t` is cumulative CPU seconds, a different quantity |
A unit declaring `cpu_pct` **halts with a named reason** rather than running
unbounded, and a unit declaring `timeout_s` on a system with no `timeout(1)`
does the same. Declaring a limit that nothing applies is a lie told to
whoever wrote the state: they set a bound expecting protection and got none.
Setting a field to `-` is how an operator opts out of it.
**Still not honoured:** there is no control socket. `numctl status` halts
rather than pretending, and no running instance can be queried or commanded
from outside it.
---
## 6. The universal destination of goods
> **CCC 2452** -- "The goods of creation are destined for the entire human
> race. the right to private property does not abolish the universal
> destination of goods."
This project publishes its source rather than binaries, and argues for that on
common-good grounds: people should be able to inspect and build what will run
as PID 1 on their own machine. That argument does not survive publishing source
under no grant. **Until a licence is chosen, a clone of this repository gives
its recipient no legal right to copy, modify, or redistribute it** -- the
artifact is readable but not usable, which is precisely the withholding the
principle names, one layer down from where the project was looking.
This was found by audit, not volunteered: there was no `LICENSE`, no copyright
statement, and no SPDX identifier anywhere in the repository, the published
site, or the skills bundle, while the site invited people to `git clone` and
shipped skills instructing them to build and run the result.
**Resolved.** The project is licensed **MIT** (`LICENSE`, `SPDX-License-Identifier: MIT`).
A clone now grants what the common-good argument in section 4 assumes: the
right to use, copy, modify, merge, publish, distribute and sublicense.
The choice was surfaced rather than defaulted. Selecting a licence is a grant
of the owner's property made in the owner's name -- a decision about patents,
attribution and relicensing that tooling must not make on an owner's behalf --
so the options and their consequences were put to the owner and MIT was
chosen. Recording *that* it was a decision, and not an inference, is part of
the point: the gap existed for a while precisely because nobody had ever
decided.
The grant travels with the thing granted. `LICENSE` and `NOTICE` are published
at `/LICENSE` and `/NOTICE`, `index.json` advertises the licence, every page
footer links it, and the files that end up inside somebody's initramfs or
container image -- where the repository's `LICENSE` does not follow -- carry an
SPDX identifier in their own header.
The copyright line reads *the NumericalOS authors*. If a legal name or entity
should hold it instead, that is a one-line change in `LICENSE` and `NOTICE`,
and is likewise the owner's to make rather than tooling's.
Enforced: `TestUniversalDestinationOfGoods` asserts the licence exists and
actually grants each right it claims, and that every redistributed file carries
an SPDX identifier.
---
## 7. Solidarity
> **CCC 1939** -- "The principle of solidarity, also articulated in terms of
> 'friendship' or 'social charity,' is a direct demand of human and Christian
> brotherhood."
>
> **CCC 1941** -- socio-economic problems "can be resolved only with the help
> of all the forms of solidarity: solidarity of the poor among themselves,
> between rich and poor, of workers among themselves..."
Solidarity governs what this project owes to commons it draws from, which is a
different question from what it grants to others. The two were being confused.
**The concrete case: busybox.** The build skills instruct an agent to fetch
busybox and bundle it into an initramfs or container image. busybox is GPLv2.
Handing that image to anyone is redistribution and carries obligations --
licence text, corresponding source or a written offer, notices kept intact --
and the skills said nothing about any of it. The project was taking from a
commons and returning nothing to it. Unlike the licence question, **this is
not the owner's choice to make**: it is a pre-existing obligation to other
people's work, so it was simply discharged rather than surfaced as a decision.
Solidarity also names something the project was already living without saying
why. The bootstrap is zero-compile-first so that old, slow and non-mainstream
hardware is not excluded by a toolchain requirement. That is not only
stewardship of resources; it is an account of who is owed a working path.
**Which makes one finding worse, not better.** The architecture registry lists
s390x, mips64el, loongarch64 and armv6 -- and busybox.net publishes prebuilt
binaries for i686 and x86_64 only. The architectures likeliest to belong to
older or cheaper hardware were exactly the ones with no working build path,
while a comment in `numos/seed.py` asserted that the fallback kept "all chip
infrastructures" honest. That is a **truthfulness** failure compounding a
stewardship one, not a new principle: an untested feature is silent, and this
one made a claim. The comment has been corrected to say what is true, and the
build skill now tells an operator plainly that on those architectures they
must supply busybox themselves and must not report a build for an architecture
whose busybox they did not obtain.
---
## Principles deliberately NOT claimed
A document asserting completeness "according to the Magisterium" while
silently omitting principles would be making a claim it has not earned. One
that stretched every principle onto a shell script would be worse. So the
omissions are named:
- **Preferential option for the poor** is not given its own section. It would
attach to the architecture finding and sound weighty, but stewardship and
solidarity already carry that ground concretely. A second citation restating
the first in more devotional language is the decoration this document opens
by forbidding.
- **The dignity of work, just wage, and the rights of workers** have no
referent here. This is a userspace init, not an employer.
- **Teaching on sexual ethics, just war, and the sacraments** has no referent
and is not invoked.
Declining these is not modesty. A principle with nothing to govern cannot be
enforced by a test, and an unenforced principle in this document is exactly
what the opening line says it must not contain.
---
## On applying these
These principles constrain design decisions; they are not a claim that the
resulting software is virtuous, nor that disagreement with them is wrong. Where
a principle and a convenience have conflicted so far -- offline-first over a
simpler always-fetch, no telemetry over easier debugging, publishing residuals
over a cleaner-looking status page -- the principle has won, and the tests
above are what keep that from quietly reversing.