SchOS/docs/plan/1.0.md
Nexoniarz cb3d28e3d6 docs: README, plan, guides and the site describe what is built now
README: rewritten around what runs (Linux software, Xorg, apk, Linux's drivers), the honest gaps, measured numbers.
plan/: 1.0.md is the finish line, where each clause of the acceptance test stands, and the register (one failing
clause: a root that survives a reboot); built plans (foundations, hybrid, alpine, xorg) and the decided-against one
(wayland) are gone, their content lives in architecture/; roadmap.md is only what is still open.
guides: building/layout/testing/adding-a-driver (Linux code may be used). history: four entries (ls -lR, TLB
shootdowns, MDIO 0x02460246, netlink MSG_TRUNC). Website: cards, stack, download page, docs index.
Code comments that pointed at deleted plan docs point at the architecture docs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EVRhxi9zpdW2uDUN4FVcao
2026-10-26 08:08:05 +01:00

217 lines
12 KiB
Markdown

# SchOS 1.0
A finish line, so that the list of open work stops being infinite.
---
## Why this document exists
[schapi.md](schapi.md) §3 says the stability freeze starts at 1.0 and covers
whatever is marked `stable` at that moment. 1.0 was never defined, which means
there was no finish line — and with no finish line every gap is equally mandatory,
the list only grows, and the project feels larger every week regardless of how much
gets done.
That feeling is structural, not a judgement about progress. This document fixes the
structure by drawing a line and putting most of the open work on the far side of it.
> **Anything not named in this document is not part of 1.0.** It is not cancelled,
> not forgotten, and not up for reconsideration until 1.0 ships.
---
## What 1.0 is
> **A machine one person can sit down at and use for an afternoon without
> falling off an edge.**
Concretely — boots on real hardware, roots on SchOS's own filesystem, runs a shell
and a real userland, is on the network, and puts a windowed desktop on the screen.
It started as a deliberately small system: *no third-party applications and no package
manager*. That has changed on its own, and is worth recording rather than tidying away:
the root is an **apk root** ([packages](../architecture/packages.md)), Alpine's
programs run on it unmodified, and the desktop is Xorg with Window Maker
([desktop](../architecture/desktop.md)). What did not change is the bar: nothing in the
system lies about what it did.
### The acceptance test
One unattended run, asserted from the host, the way everything else here is tested.
When this passes, it is 1.0:
```
boot on real hardware from a USB stick
→ SchFS root mounts, generation counter advances
→ schinit starts shells on the virtual terminals
→ X starts; a window appears and is asserted by pixel
→ in it: ls, cat, a file written, a network fetch over HTTPS
→ reboot
→ the file is still there and the checksum matches
```
Where each clause stands:
| Clause | State |
|---|---|
| boot from a USB stick on real hardware | **done** on an AMD B550 desktop, an ASUS TUF A15 laptop and an Ivy Bridge HP all-in-one |
| SchFS root, generation counter | **done** — the root is a SchFS image, in RAM when live |
| a terminal to type in | **done** — a shell on the first six of the twelve virtual terminals (`etc/schinit/*-shell.job`); the rest are there to be started |
| X starts, a window appears | **done** (`startx` → Window Maker + xterm); *asserted by pixel* has no automated test yet — `bootcheck` drives the serial console, and the screenshots are looked at |
| `ls`, `cat`, a file written | **done** |
| a network fetch over HTTPS | **done** (`wget`, `curl`, `apk`) |
| reboot, **the file is still there** | **not met on the live image.** The root lives in RAM and everything written is gone at reboot; SchFS is crash-safe on a disk, but nothing writes a disk root. This is the one clause that fails, and it is the open decision below |
### The one open decision
The acceptance test's last clause needs a root that survives a reboot. There are two honest ways to
close it, and which one is the owner's to choose:
1. **Write the installer** (`projects/schinst/`, [roadmap.md](roadmap.md) §5): partition a disk,
write the root, install the loader. Large, and until now frozen.
2. **Narrow the clause**: 1.0 is a *live* system, and the last line becomes "a file written to a
SchFS disk or partition that was attached survives a reboot" — which already works
(`make disk`, `make qemu` with `schfs.img`). Smaller, and it says what the system is.
Nothing else is on the path to 1.0.
---
## The freeze, and the register of unfinished work
**No new capability is started until this register is empty.**
The failure this exists to stop is not laziness and not scope creep — it is
*abandonment by promotion*. A thing gets built to the point where it works, the next
thing becomes more interesting, and the first one is left in a corner: present in the tree,
not finished, not deleted, and not visible in any list. Enough of those and the tree stops
matching its own documentation.
Two rules, and they are the same rule seen from either end:
> **Nothing enters the register except by being finished or being deleted.**
>
> **Adding a row requires closing one.** Two things in flight. Never three.
A row leaves this table in one of exactly two ways. Either it is **finished** — and finished
means a description exists in [../architecture/](../architecture/), not that the code works —
or it is **deleted**, and deleted means gone from the tree, not marked for deletion. A
directory that has said "to be deleted" for months is the corner, not the cure.
### Built, and not connected to anything
| | Where it stopped |
|---|---|
| **`projects/schcom/`** | A compositor v0 (about 700 lines) over a wire format that nothing speaks any more: the desktop is Xorg. It is the one thing in the tree that has ever put a client's pixels on screen by itself, and it has no consumer. **Delete it**, or say what it is for. |
| **The in-kernel LDLS window** | `vm.c` maps the kernel image a second time in the top 2 GB at every boot, and `include/ldls/ldls.h` describes a `/dev/ldls` loader — the start of loading Linux modules *into the kernel*, which [ldls.md](../architecture/ldls.md) rule 2 says is not how it is done. Nothing calls either. **Delete it**, or decide. |
| **`display_ops`** | `acquire` and `wait_vblank` are in the vtable, implemented by one driver at most, with no consumer: Xorg draws through `/dev/fb0`. Kept for the GPU work ([gpu.md](gpu.md)); that is the reason it stays. |
| **Socket activation** | `schinitd` parses `[Socket name]` and remembers the path. Nothing holds the socket. This is the entire reason for copying launchd, and it is the half that was not built. |
| **`sys_delete`, `sys_show`, `sys_showstat`** | Orphaned entries from the old v1 filesystem's recycle bin. They die with `fs.c`. |
### Started, and stopped part-way
| | Where it stopped |
|---|---|
| **LDLS on real hardware** | `r8169` registers its interface on the laptop and reads its PHY; whether it carries traffic there is **not confirmed**. The native driver is out of the registry and stays as the fallback. |
| **The laptop's embedded controller** | The EC is found and served (battery and AC read through it); **SCI queries are not handled**, so events from it are not seen. |
| **Epiphany (WebKit)** | `apk add epiphany` installs it; its web-process child dies at start-up ("short read from the peer"). NetSurf runs. Not diagnosed. |
### Named in a "what it does not do" and still true
Not corners — these were written down honestly on the day and stayed written down. They are here
so the register is the whole picture rather than the flattering part of it. Each is described where
it lives.
| | |
|---|---|
| No page cache | writable `MAP_SHARED` of a file is refused — [kernel.md](../architecture/kernel.md) |
| `mprotect` is a no-op, nothing has NX | [kernel.md](../architecture/kernel.md) |
| No routing table | first interface wins, which is a rule and not routing — [networking.md](../architecture/networking.md) |
| No descriptor garbage collector | a socket passed over itself and never received leaks the pair |
| No udev / uevent socket | Xorg is told its input devices — [desktop.md](../architecture/desktop.md) |
| No EHCI driver | USB 2.0 ports wired only to EHCI do nothing — [usb.md](../architecture/usb.md) |
| Touchpads are mice | no two-finger scroll — [desktop.md](../architecture/desktop.md) |
| `ru_stime` is zero | [kernel.md](../architecture/kernel.md) |
| No IOMMU | a driver in a process is isolated against bugs, not malice — [devices.md](../architecture/devices.md) |
| One audio chip family | AC'97 only; laptops have HDA — [audio.md](../architecture/audio.md) |
### Frozen — scoped, unstarted, and not to be started
Neither cancelled nor in progress. **Do not open these.**
| | |
|---|---|
| `projects/schinst/` | the installer, the installation environment, `.sip` (see the open decision above) |
| `projects/schfs-linux/` | SchFS as a filesystem for Linux |
| [gpu.md](gpu.md) | amdgpu and nouveau through LDLS — measured, with the work it needs written down |
| [finch.md](finch.md) | Finch inside SchOS (the language itself is finished and lives in its own repository) |
| [schapi.md](schapi.md) | the API layering, designed and not built |
Each of those is well argued and none of them is on the path to the acceptance test above. That is
the whole test for whether something belongs in this section: **not "is it worth doing" but "does 1.0
fail without it".**
---
## The gates
In order. **Do not start a gate before the one before it closes**, and closing means a description exists in
[../architecture/](../architecture/).
| Gate | What | State |
|---|---|---|
| **0 — Fix what is already wrong** | the SMP register corruption, `setsockopt` that lied, timestamps that read 1970, the `ls -lR` hang (hunted, not reproducible — [history](../history/kernel.md) §24), … | **closed** |
| **1 — The foundations** | descriptor passing, a shareable memory object (`memfd`), `AF_UNIX` in the filesystem, dynamic linking, the event descriptors | **closed** — [kernel.md](../architecture/kernel.md), [networking.md](../architecture/networking.md) |
| **2 — Init as a role** | `schinit`, the supervisor, the heartbeat, PID 1 re-exec'd in place | **closed** — [init.md](../architecture/init.md) |
| **3 — The desktop** | Xorg on the framebuffer, Window Maker, a terminal | **closed** — [desktop.md](../architecture/desktop.md) |
| **4 — A root that survives a reboot** | the open decision above | **open** |
---
## Not in 1.0
The point of this list is that it is *written down*, so it can stop occupying attention. Nothing here is cancelled.
| | Why it waits |
|---|---|
| **GPU acceleration, Mesa** | [gpu.md](gpu.md). A whole project; software rendering is enough to use the machine. |
| **A page cache** | General writable `MAP_SHARED` of a file is a real project with no 1.0 consumer. |
| **SchFS snapshots, FUSE, a Linux module, sparse files, online fsck** | The format version is the prerequisite and it exists; the rest is [roadmap.md](roadmap.md) §6. |
| **CFF/OTF fonts, kerning, text layout** | TrueType and fixed advances are enough for a terminal. |
| **Routing, IPv6, Wi-Fi** | One interface, one default route, works. |
| **HDA audio, recording, mixing** | AC'97 plays; that is sound. |
| **Threads' loose ends, `ptrace`, `seccomp`** | Whatever a package needs is found by running it. |
| **SchAPI itself** | Deliberately. It should be designed from the desktop's experience, not before it. |
---
## The rule for this list
**Adding to the gates requires deleting something else from them.**
Not a productivity trick — a forcing function. The reason this project felt overwhelming is that ~20 fronts
were open simultaneously, and no amount of discipline makes that workable. The fix is structural.
And one working limit, worth holding to literally:
> **Two things in flight. Never three.**
## How you will know it is going well
Not by velocity. By this: **every closed item leaves a description behind.** When the `ls -lR` hang was
closed, `history/kernel.md` gained an entry. When a gap closed, a "what it does not do" section shrank.
Those sections shrinking is the real progress bar, and it is the only one that does not lie.
## A note worth keeping
This document was written because the work started to feel overwhelming, and that is worth recording rather
than tidying away — because the feeling was about the *shape* of the work and not its quality, and the two are
easy to confuse when you are inside it.
The evidence at the time: SMP working on real hardware after five bugs stacked behind each other; a copy-on-write
filesystem whose crash test cuts the power one write later, 119 times, and demands a clean mount after each; a
TCP/IP stack asserted from both ends; an xHCI driver written from the specification; and a documentation tree that
records why things are strange so they do not get un-fixed by accident. Since then: a desktop, real Linux
programs and Linux's own drivers, running.
None of that is the output of a project in trouble. It was a project with too many tabs open.