Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c38a7b1e6 | ||
|
|
96bc60883d | ||
|
|
a58ddbfc24 | ||
|
|
c587678dbd | ||
|
|
b4d673f929 | ||
|
|
0b49d03526 | ||
|
|
6627f710b2 | ||
|
|
7dca7fb699 | ||
|
|
715c09a9d1 | ||
|
|
c38f4f4965 | ||
|
|
8b1ba39040 | ||
|
|
429eb72aa2 | ||
|
|
91a7150276 | ||
|
|
607ae1c2da | ||
|
|
da800ce844 | ||
|
|
cff3787b92 | ||
|
|
dc9a086603 | ||
|
|
bcd51cb33d | ||
|
|
19a8a036c2 | ||
|
|
258842aafc | ||
|
|
727a707580 | ||
|
|
634a49b533 | ||
|
|
56e4d60844 | ||
|
|
68919741fc | ||
|
|
0e1c9650b4 | ||
|
|
9ed9cf1ad0 | ||
|
|
bfe3506aec | ||
|
|
8f1ba02b3c | ||
|
|
a293eab1d4 | ||
|
|
cac4e7fb50 | ||
|
|
199720e769 | ||
|
|
d54e2fe276 | ||
|
|
44264d0781 | ||
|
|
55613350c4 | ||
|
|
f747ab78a6 | ||
|
|
1928d53b6b | ||
|
|
a083c5b834 | ||
|
|
88b962b29e | ||
|
|
4d0b9ab771 | ||
|
|
0dbad0f278 | ||
|
|
6bbf4b1afd | ||
|
|
1e3f211daa | ||
|
|
171b3947dd | ||
|
|
1d4898496f | ||
|
|
777f739708 | ||
|
|
b8951bc26b | ||
|
|
50d2bc98d9 | ||
|
|
2d43db252a | ||
|
|
37f62d688b | ||
|
|
cabe974872 | ||
|
|
4a125cdd21 | ||
|
|
d8bf2e1121 | ||
|
|
04006bff12 |
@@ -6,6 +6,7 @@
|
||||
#
|
||||
# org.starship:kernelImage:<LITHOS_VERSION>-SNAPSHOT, starshipos-snapshots
|
||||
# classifier pc StarshipOS.iso amd64, UEFI -- the ISO the amd64 acceptance boot booted
|
||||
# classifier pc-stick pc-stick.img.xz a PC's USB stick, for any UEFI PC (make boot_image TARGET=PC)
|
||||
# classifier raspi5 raspi5.img.xz Raspberry Pi 5, for Raspberry Pi Imager
|
||||
# classifier milkv MilkV.img.xz Milk-V Mars
|
||||
# classifier logs logs.tar.gz this run's serial logs and DoE CSVs (the proof log is in
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
# acceptance protocol, the proofs, the board images -- and the documents, and publishes both to
|
||||
# starshipos-releases at that version:
|
||||
#
|
||||
# org.starship:kernelImage:<version> classifiers pc, raspi5, milkv, logs (nightly.yml)
|
||||
# org.starship:kernelImage:<version> classifiers pc, pc-stick, raspi5, milkv, logs (nightly.yml)
|
||||
# org.starship:documentation:<version> classifiers book, vol1, vol2, vol3, api (nightly-docs.yml)
|
||||
#
|
||||
# and makes the tag a Gitea release -- a pre-release for v<x.y.z>-alpha.N and the like -- with the
|
||||
# images, SHA256SUMS, the documents and the StarshipOS Root CA's certificate attached, for anyone
|
||||
# to download (#126; scripts/nightly.sh gitea-release). Needs the secret RELEASE_TOKEN: a token
|
||||
# that may write the repository.
|
||||
#
|
||||
# The tag must name the version the tree says it is: v<LITHOS_VERSION> (kernel/Makefile). A tag
|
||||
# that does not is refused before anything is built. A release repository takes a version once.
|
||||
name: Release
|
||||
@@ -54,7 +59,10 @@ jobs:
|
||||
echo "NIGHTLY_VERSION=${tree#v}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Install the dependencies
|
||||
run: make ARCH=amd64,aarch64,riscv64 init # the image has all but the documents' packages
|
||||
# INIT_PROOFS=0: the image's Isabelle has HOL-Library prebuilt; a full init would fetch a fresh
|
||||
# Isabelle into the workspace and point isabelle at it, and the proofs would build HOL-Library
|
||||
# from scratch -- killed (release run 196, v4.0.0-alpha.1)
|
||||
run: make ARCH=amd64,aarch64,riscv64 init INIT_PROOFS=0 # the image has all but the documents' packages
|
||||
|
||||
- name: Acceptance amd64
|
||||
run: scripts/nightly.sh accept amd64
|
||||
@@ -81,6 +89,11 @@ jobs:
|
||||
scripts/nightly.sh publish https://nexus.starshipos-f18.org/repository/starshipos-releases
|
||||
scripts/nightly.sh publish-docs https://nexus.starshipos-f18.org/repository/starshipos-releases
|
||||
|
||||
- name: Gitea release # the downloads anyone can fetch (#126): no Nexus login
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }} # a token that may write the repository
|
||||
run: scripts/nightly.sh gitea-release "${{ github.ref_name }}"
|
||||
|
||||
- name: Keep the release
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-11-07 — LithosAnanke v4.0.0-alpha.3: the first published alpha
|
||||
|
||||
`v4.0.0-alpha.2` (`2d43db25`) used the image's HOL-Library as intended, but its release run (200) ran
|
||||
the proofs with Isabelle's defaults -- Java's heap up to 4 GiB, a thread per CPU -- and they were
|
||||
killed in the StarForth session. Nothing was published; the tag stays where it is. The proofs now run
|
||||
capped (`scripts/nightly.sh proofs`: one thread, Java 512 MiB, Poly/ML 900 MiB; 47 s, ~1.8 GiB), and
|
||||
`v4.0.0-alpha.3` is the first alpha published. `docs/fabric/FABRIC-3.md` XLVII.6.
|
||||
|
||||
## 2026-11-07 — LithosAnanke v4.0.0-alpha.2: not published
|
||||
|
||||
`v4.0.0-alpha.1` (`233025da`) was accepted and tagged, but its release run (196) built HOL-Library
|
||||
from scratch in the proofs step and was killed: `release.yml`'s full `make init` replaced the
|
||||
image's Isabelle, the one with HOL-Library prebuilt. Nothing was published; the tag stays where it is
|
||||
(Captain Bob, 2026-11-07). `release.yml` now runs `init INIT_PROOFS=0`, and `v4.0.0-alpha.2` is the
|
||||
first alpha published -- the same system as below. `docs/fabric/FABRIC-3.md` XLVII.5.
|
||||
|
||||
## 2026-11-07 — LithosAnanke v4.0.0-alpha.1: the first alpha release
|
||||
|
||||
The first alpha of the kernel, `v4.0.0-alpha.1`: v4, StarForth's F18 engine, is the system every
|
||||
|
||||
+4
-1
@@ -3,7 +3,10 @@
|
||||
# 2026-11-07: "New root CA on the CI box. Valid StarshipOS rather than snake oil intermediate").
|
||||
#
|
||||
# StarshipOS Root CA Ed25519, 20 years, self-signed. Its key never leaves this box:
|
||||
# not in the repository, not in Gitea, not in any image.
|
||||
# not in the repository, not in Gitea, not in any image. Its
|
||||
# certificate (public) is ci/pki/starshipos-root-ca.pem, made on
|
||||
# 2026-11-07, SHA-256 in starshipos-root-ca.sha256; every release
|
||||
# attaches it.
|
||||
# StarshipOS Capsule Signing Ed25519, 10 years, signed by the root; CA:TRUE, pathlen:0.
|
||||
# Its certificate is built into every image (capsules/pki/
|
||||
# starshipos-intermediate.der) and checks each capsule at boot;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBaDCCARqgAwIBAgIUCwt1JkPxCfwr9PTCOadol/m9PCQwBQYDK2VwMDIxEzAR
|
||||
BgNVBAoMClN0YXJzaGlwT1MxGzAZBgNVBAMMElN0YXJzaGlwT1MgUm9vdCBDQTAe
|
||||
Fw0yNjExMDcxNjUwNTZaFw00NjExMDcxNjUwNTZaMDIxEzARBgNVBAoMClN0YXJz
|
||||
aGlwT1MxGzAZBgNVBAMMElN0YXJzaGlwT1MgUm9vdCBDQTAqMAUGAytlcAMhANcn
|
||||
fPpowbNgzMPtDEA7EYJoSkBLPljM6dEBFONfrhHso0IwQDAPBgNVHRMBAf8EBTAD
|
||||
AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQU5eU4Iy/Al5g9KZI5+u4jKllG
|
||||
shswBQYDK2VwA0EAjRK1ybZE/VaH31dt3sc8DgqJVTPB6CYovdqWKcJMXC8UKfYJ
|
||||
co9o8MhiIauvSCgZZA2+5VMv4zlke7Lu5TNLDg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1 @@
|
||||
DA:A7:40:56:65:41:1A:FE:E6:08:85:3F:6E:AD:83:3A:38:30:83:E6:F0:6D:69:A6:A8:9E:92:BD:85:93:39:81
|
||||
@@ -0,0 +1,96 @@
|
||||
# Deploying "Try it" on the server
|
||||
|
||||
The public demo: each visitor gets a StarshipOS machine of their own in the browser, resumed at
|
||||
Zuse's prompt, gone when they leave. Two at a time on today's server (384 MiB each); a third visitor
|
||||
is told every machine is busy and to try back in a few minutes. Issues #115, #116, #117.
|
||||
|
||||
Run as root on the server, **after PR #148 is merged** (it carries the 384 MiB guests and the busy
|
||||
message), **while CI is idle** (each step that boots QEMU boots one, in the foreground).
|
||||
|
||||
## 1. The checkout and what the build needs (~15 min)
|
||||
|
||||
```bash
|
||||
apt-get install -y ttyd qemu-system-x86 ovmf python3 git
|
||||
git clone https://gitea.starshipos-f18.org/rajames/LithosAnanke.git /opt/starshipos-demo
|
||||
cd /opt/starshipos-demo
|
||||
git checkout master # after #148: alpha.3's kernel, and the demo's limits
|
||||
make ARCH=amd64 init INIT_DOCS=0 INIT_PROOFS=0 # amd64 only: no docs, no Isabelle
|
||||
```
|
||||
|
||||
Master after #148 is the `v4.0.0-alpha.3` kernel unchanged, plus #148's scripts.
|
||||
|
||||
## 2. The demo's own Zuse (~3 min, two QEMU boots)
|
||||
|
||||
```bash
|
||||
demo/mint-zuse.sh /var/lib/starshipos-demo-zuse
|
||||
ls -la /var/lib/starshipos-demo-zuse/zusestick.img # the stick every session attaches
|
||||
```
|
||||
|
||||
Never anyone's real Zuse: minted for the demo (#111), its writes discarded in every session.
|
||||
|
||||
## 3. The image and the saved machine (~2 min, one QEMU boot)
|
||||
|
||||
```bash
|
||||
demo/build-iso.sh /tmp/StarshipOS.iso
|
||||
DEMO_PROMPT='[zuse@Hera]' demo/make-snapshot.sh /tmp/StarshipOS.iso /var/lib/starshipos-demo \
|
||||
/var/lib/starshipos-demo-zuse/zusestick.img
|
||||
ls -la /var/lib/starshipos-demo/ # StarshipOS.iso identity.img vars.fd state
|
||||
```
|
||||
|
||||
The saved machine belongs to this image, this QEMU and 384 MiB: re-run step 3 after any of them
|
||||
changes. Sessions already running keep theirs.
|
||||
|
||||
## 4. The service (~5 min)
|
||||
|
||||
Ubuntu's `ttyd` package starts its own `ttyd.service`, which runs **`login` on port 7681** -- our
|
||||
port. Left running, it takes the port, and Apache hands visitors the server's own login prompt
|
||||
(found 2026-11-08, after step 5). Disable it first:
|
||||
|
||||
```bash
|
||||
systemctl disable --now ttyd # the package's service: a login prompt on 7681
|
||||
useradd --system --home /var/lib/starshipos-demo --shell /usr/sbin/nologin starshipos-demo
|
||||
chown -R starshipos-demo: /var/lib/starshipos-demo
|
||||
cp demo/starshipos-demo.service /etc/systemd/system/
|
||||
systemctl daemon-reload && systemctl enable --now starshipos-demo
|
||||
systemctl status starshipos-demo --no-pager | head -5
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:7681/ # 200: ttyd answers
|
||||
ss -ltnp | grep 7681 # the ttyd of starshipos-demo, nothing else
|
||||
```
|
||||
|
||||
The service expects the checkout's `demo/` at `/opt/starshipos-demo/demo` (step 1 put it there).
|
||||
|
||||
## 5. TLS and Apache for try.starshipos-f18.com (~10 min)
|
||||
|
||||
DNS: `try.starshipos-f18.com` must point at this server (an A record) before certbot.
|
||||
|
||||
```bash
|
||||
a2enmod proxy proxy_http proxy_wstunnel headers ssl rewrite
|
||||
certbot certonly --apache -d try.starshipos-f18.com
|
||||
cp demo/apache-demo.conf /etc/apache2/sites-available/starshipos-demo.conf
|
||||
a2ensite starshipos-demo && apachectl configtest && systemctl reload apache2
|
||||
curl -sI https://try.starshipos-f18.com/ | head -3 # 200, its own certificate
|
||||
```
|
||||
|
||||
`apache-demo.conf` lets only the .com frame the terminal (`frame-ancestors`).
|
||||
|
||||
## 6. The check (done 2026-11-08)
|
||||
|
||||
From outside: a session ready 1.5 s after the page opens; `3 4 + .` answers `7 ok`, `: SQUARE DUP *
|
||||
; 7 SQUARE .` answers `49 ok`; a third visitor at once is told every machine is busy. The
|
||||
certificate is try.starshipos-f18.com's own (Let's Encrypt), and only the .com may frame it.
|
||||
|
||||
## 7. Tell Claude
|
||||
|
||||
Then I check from outside: a session reaches `[zuse@Hera] ok>`, `3 4 + .` answers `7 ok`, a third
|
||||
visitor gets the busy message, and the .com's Try it page shows the console. Then the "Try it" link
|
||||
goes into the .com's navigation (#117).
|
||||
|
||||
## If something goes wrong
|
||||
|
||||
- `journalctl -u starshipos-demo -n 50` -- ttyd and the sessions
|
||||
- A session that ends at once: the saved machine does not match (re-run step 3)
|
||||
- Memory: `free -h` -- a session's QEMU holds ~150 MB of its 384 MiB guest; two at most
|
||||
(`DEMO_MAX_GUESTS` in the service)
|
||||
- CPU: an idle guest keeps a host core busy (the kernel's idle loop polls -- its own issue), so the
|
||||
service caps all sessions together at one core (`CPUQuota=100%`, `Nice=19`). After changing the
|
||||
service file: `systemctl daemon-reload && systemctl restart starshipos-demo`
|
||||
+2
-1
@@ -20,7 +20,8 @@ XWiki "Try it" page (iframe) -> Apache: TLS, websocket -> ttyd -> start-session.
|
||||
| `start-session.sh` | One visitor's session: resumes the saved machine, ends it on hang-up, close or time-out (#112) |
|
||||
| `console.py` | Joins the visitor's terminal to the machine only once it runs, discarding keys typed while it loads |
|
||||
| `qemu-args.sh` | The machine, shared by the two above: a resumed machine must match the saved one exactly |
|
||||
| `starshipos-demo.service` | ttyd as a systemd service, on localhost, at most 3 sessions (#114) |
|
||||
| `starshipos-demo.service` | ttyd as a systemd service, on localhost; two guests at once, a busy message for the rest (#114, #116) |
|
||||
| `DEPLOY.md` | Putting it on the server, step by step |
|
||||
| `apache-demo.conf` | Example vhost: TLS, the websocket, framing allowed for the `.com` only (#115) |
|
||||
| `xwiki-try-it.xwiki` | The "Try it" page, its own page on the `.com` XWiki (`TryIt`), in the landing page's style |
|
||||
|
||||
|
||||
+5
-3
@@ -3,8 +3,10 @@
|
||||
# A session resumes a machine saved by make-snapshot.sh, and QEMU can resume a saved machine only
|
||||
# into the same machine: the same board, CPU, memory, firmware and devices. Both scripts build the
|
||||
# command line here, so they cannot drift apart. It is the machine `make -f kernel/Makefile
|
||||
# ARCH=amd64 qemu` boots (q35, TCG, 1 GiB, OVMF, the ISO as a CD), less what a visitor must not
|
||||
# have: no network device, no Artemis disk, no display, and QEMU's seccomp sandbox on.
|
||||
# ARCH=amd64 qemu` boots (q35, TCG, OVMF, the ISO as a CD) -- in 384 MiB, not its 1 GiB: v4 boots
|
||||
# to Zuse's prompt from 256 MiB, refuses at 128 ("no memory for the block chain"), measured
|
||||
# 2026-11-07 (#116) -- less what a visitor must not have: no network device, no Artemis disk, no
|
||||
# display, and QEMU's seccomp sandbox on.
|
||||
#
|
||||
# demo_qemu_args <state-dir> <vars.fd> -> fills the array QEMU_ARGS
|
||||
#
|
||||
@@ -18,7 +20,7 @@ demo_qemu_args() {
|
||||
QEMU_ARGS=(
|
||||
-machine q35,accel=tcg
|
||||
-cpu qemu64,+rdrand
|
||||
-m 1024
|
||||
-m 384 # v4 boots from 256 MiB; 384 leaves room (#116)
|
||||
-smp 1
|
||||
-drive "if=pflash,format=raw,readonly=on,file=$OVMF_CODE"
|
||||
-drive "if=pflash,format=raw,file=$vars"
|
||||
|
||||
@@ -13,8 +13,13 @@ User=starshipos-demo
|
||||
Group=starshipos-demo
|
||||
Environment=DEMO_STATE=/var/lib/starshipos-demo
|
||||
Environment=DEMO_SESSION_LIMIT=1800
|
||||
# -m: sessions at once -- each a QEMU of about 1 GiB and most of a core (issue #116 measures it)
|
||||
ExecStart=/usr/bin/ttyd --port 7681 --interface lo --writable --max-clients 3 \
|
||||
Environment=DEMO_MAX_GUESTS=2
|
||||
# the guests' slot locks (start-session.sh): /run/starshipos-demo, made for this user, gone at stop
|
||||
RuntimeDirectory=starshipos-demo
|
||||
# --max-clients: the guests and a few more, so a visitor over the limit reaches the busy message
|
||||
# instead of a refused connection; still a cap on open connections
|
||||
# each guest a QEMU of 384 MiB and most of a core (demo/qemu-args.sh; #116)
|
||||
ExecStart=/usr/bin/ttyd --port 7681 --interface lo --writable --max-clients 6 \
|
||||
--client-option titleFixed=StarshipOS --client-option disableLeaveAlert=true \
|
||||
/opt/starshipos-demo/demo/start-session.sh
|
||||
Restart=on-failure
|
||||
@@ -25,8 +30,15 @@ ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
ReadOnlyPaths=/var/lib/starshipos-demo
|
||||
MemoryMax=4G
|
||||
CPUQuota=300%
|
||||
# Sized for this server (3.8 GiB, two cores; both wikis, Gitea, Nexus, CI). Since #151 an idle guest
|
||||
# halts (1% of a core at the prompt, was 100%), so a session costs CPU only while its visitor runs
|
||||
# something. All sessions together get 1.5 cores at the lowest priority (Captain Bob, 2026-11-08):
|
||||
# one busy visitor a full core, two busy at once three-quarters each, and half a core always left
|
||||
# to the wikis and Gitea. 1 GiB holds two sessions (~150 MB resident each) with room. Raise both
|
||||
# with the server (8 GB: MemoryMax=2G, CPUQuota=200% or more).
|
||||
MemoryMax=1G
|
||||
CPUQuota=150%
|
||||
Nice=19
|
||||
TasksMax=200
|
||||
|
||||
[Install]
|
||||
|
||||
+24
-3
@@ -12,8 +12,29 @@ here=$(cd "$(dirname "$0")" && pwd)
|
||||
. "$here/qemu-args.sh"
|
||||
dir=${1:-${DEMO_STATE:-/var/lib/starshipos-demo}}
|
||||
limit=${DEMO_SESSION_LIMIT:-1800} # seconds a session may last
|
||||
guests=${DEMO_MAX_GUESTS:-2} # machines at once: 384 MiB each (qemu-args.sh, #116)
|
||||
slots=${DEMO_SLOTS:-/run/starshipos-demo} # a lock file per machine
|
||||
|
||||
[ -f "$dir/state" ] || { echo "The demo is not set up yet: no saved machine in $dir." >&2; exit 1; }
|
||||
|
||||
# One of $guests slots, or a busy message (Captain Bob, 2026-11-07: "Limit guests and have a Busy,
|
||||
# try back in a few minutes"). A slot is a lock this script holds for the session's life (flock -n:
|
||||
# two visitors cannot both take the last one); it goes when the script does, however it ends. The
|
||||
# machine's processes are started without the lock's descriptor ({slot}>&-), so it is this
|
||||
# script's alone.
|
||||
mkdir -p "$slots"
|
||||
slot=
|
||||
for i in $(seq 1 "$guests"); do
|
||||
exec {fd}>"$slots/slot-$i.lock"
|
||||
if flock -n "$fd"; then slot=$fd; break; fi
|
||||
exec {fd}>&-
|
||||
done
|
||||
if [ -z "$slot" ]; then
|
||||
printf '\r\nEvery StarshipOS machine is busy right now (%d at once on this small server).\r\n' "$guests"
|
||||
printf 'Try back in a few minutes.\r\n'
|
||||
sleep 20
|
||||
exit 0
|
||||
fi
|
||||
tmp=$(mktemp -d "${TMPDIR:-/tmp}/starshipos-session.XXXXXX")
|
||||
trap 'rm -rf "$tmp"' EXIT
|
||||
cp "$dir/vars.fd" "$tmp/vars.fd"
|
||||
@@ -28,13 +49,13 @@ printf 'Try: 3 4 + . : SQUARE DUP * ; 7 SQUARE .\r\n\r\n'
|
||||
qemu-system-x86_64 "${QEMU_ARGS[@]}" \
|
||||
-chardev "socket,id=con,path=$tmp/con.sock,server=on,wait=off" -serial chardev:con \
|
||||
-qmp "unix:$tmp/qmp.sock,server=on,wait=off" -monitor none \
|
||||
-incoming "file:$dir/state" </dev/null &
|
||||
-incoming "file:$dir/state" </dev/null {slot}>&- &
|
||||
qemu=$!
|
||||
( sleep "$limit"; kill "$qemu" 2>/dev/null ) &
|
||||
( sleep "$limit"; kill "$qemu" 2>/dev/null ) {slot}>&- &
|
||||
timer=$!
|
||||
# The bridge is a tracked child too: bash runs a trap only once its foreground command returns,
|
||||
# so a hang-up would otherwise wait on the bridge. `wait` returns to the trap at once.
|
||||
python3 -I "$here/console.py" "$tmp/qmp.sock" "$tmp/con.sock" 0<&0 &
|
||||
python3 -I "$here/console.py" "$tmp/qmp.sock" "$tmp/con.sock" 0<&0 {slot}>&- &
|
||||
bridge=$!
|
||||
trap 'kill "$bridge" "$qemu" "$timer" 2>/dev/null; rm -rf "$tmp"' EXIT
|
||||
trap 'exit 0' HUP TERM INT
|
||||
|
||||
@@ -6165,3 +6165,172 @@ Isabelle2025-2 (HOL-Library and its build database) is a package in this reposit
|
||||
`bb247846...e999cb339e`), and the image fetches it into Isabelle's system heaps, checksum pinned,
|
||||
its token a Docker build secret. Shown portable first: a fresh Isabelle home holding only that heap
|
||||
checks the StarForth session without rebuilding HOL-Library (24 s).
|
||||
|
||||
### 5. v4.0.0-alpha.1 not published; v4.0.0-alpha.2
|
||||
|
||||
PR #127 merged (`4f675c8b`, acceptance run 192 with the capsules signed); `runner-image.yml` built
|
||||
`lithosananke-runner:4f675c8b75b2` with HOL-Library fetched (checksum OK, 4.8 s); PR #128 moved the
|
||||
workflows onto it (`233025da`, acceptance run 195 in the new image). `v4.0.0-alpha.1` was tagged on
|
||||
`233025da`. Its release run (196) passed acceptance in full, then the proofs step built HOL-Library
|
||||
from scratch and was killed (exit 137): `release.yml` ran a full `make init` for the documents'
|
||||
packages, which also fetched Isabelle into the workspace and pointed `/usr/local/bin/isabelle` at it
|
||||
-- an Isabelle without the image's HOL-Library. Nothing was published. Ruled (Captain Bob,
|
||||
2026-11-07): the tag stays where it is; `release.yml` runs `init INIT_PROOFS=0` (as
|
||||
`nightly-docs.yml` does), `LITHOS_VERSION` becomes `4.0.0-alpha.2`, and `v4.0.0-alpha.2` is the
|
||||
first published alpha.
|
||||
|
||||
### 6. v4.0.0-alpha.2 not published either; v4.0.0-alpha.3
|
||||
|
||||
PR #130 merged (`2d43db25`, acceptance run 199; run 197 before it failed one riscv64 check, #131);
|
||||
`v4.0.0-alpha.2` tagged there. Its release run (200) passed acceptance and used the image's
|
||||
Isabelle and HOL-Library, as XLVII.5 meant -- then the StarForth session was killed (exit 137) in
|
||||
the proofs: Isabelle ran with its defaults, Java's heap up to 4 GiB and a thread per CPU, more than
|
||||
the server (3.8 GiB, ~2.3 GiB free with the wikis stopped; perhaps a per-job cap besides). Capped
|
||||
-- one thread, Java 512 MiB, Poly/ML 900 MiB, in a settings file of a home made for the run, its
|
||||
heaps linked to the user's -- the session passes in 47 s at ~1.8 GiB, through
|
||||
`scripts/nightly.sh proofs` itself (`logs/20261107-195341`). Nothing was published. Ruled (Captain
|
||||
Bob, 2026-11-07): the tag stays; `LITHOS_VERSION` `4.0.0-alpha.3`, the first published alpha; the
|
||||
review list begun meanwhile goes to the milestone v4.0.0-alpha.4.
|
||||
|
||||
## XLVIII. After the first published alpha: the review, the protocol, the SDK, the demo's limits (2026-11-07)
|
||||
|
||||
### 1. Ruled
|
||||
|
||||
- **A ranked list for the next release** (Captain Bob: "a list of problems, deficiencies, smells and
|
||||
so on placed in issues by rank priority"): milestone **v4.0.0-alpha.4**, its index #147. Must:
|
||||
Gitea's plain-HTTP logins (#133), rotating what was exposed (#134), the riscv64 flake (#131), the
|
||||
developer protocol (#135), CI's litter (#129). Should: a failed check prints its serial log
|
||||
(#136), capsule trust against the root and unsigned capsules (#139, a ruling), the queue's
|
||||
cancelling of waiting runs (#140, a ruling), CLAUDE.md's drift (#137), the Book of Fabric (#138),
|
||||
downloads (#126). Nice: the empty DoE CSVs (#141 -- no DoE has run since 2026-09-16: noise, not
|
||||
breakage), DoE columns always 0 (#142), mkcapsule's warnings (#143), a stale header (#144),
|
||||
tracked files a build rewrites (#145), the sites' small things (#146).
|
||||
- **The developer protocol** (#135): "We can simply run nightly as developers to further make sure
|
||||
nothing sneaks in. Just no Nexus push ... a protocol for programmers. Then the protocol evidence
|
||||
can be submitted in the PR." -- `scripts/nightly.sh protocol`, a `PROTOCOL.md` per run, checked
|
||||
by CI against the PR's head.
|
||||
- **The Book of Fabric** (#138): the FABRIC record as one book, published with every release --
|
||||
and this record kept at the pace of the work, so the book is (Captain Bob: "the book of fabric
|
||||
needs to keep pace").
|
||||
- **v4.0.0-alpha.5: the SDK**, for FORTH and capsule developers; a systems SDK later, FPGA when we
|
||||
get there (milestone 11). In it:
|
||||
- **A capsule repository in blocks**, like `~/.m2/repository` (#149): on Artemis, indexed by
|
||||
coordinates and capsule hash, a TTL by default as the rest of the system has, pinning one-way,
|
||||
verified in and on use, composed in FORTH; filled by hand now, from Nexus once there is
|
||||
networking. To rule: its block range and size, the default TTL, what is pinned.
|
||||
- **K under network latency** (#150): "Networking latency will be a super good K test." -- the
|
||||
repository pulling from Nexus with delay, jitter, loss and bandwidth dialled in (`tc netem`),
|
||||
K and the DoE's measures per architecture. After networking, #141 and #142.
|
||||
- **The demo's limits** (#116): "Limit guests and have a Busy, try back in a few minutes."
|
||||
|
||||
### 2. Built
|
||||
|
||||
- **#136:** `scripts/qemu_session.py`'s `check()` prints, on a FAIL, the serial lines after an anchor
|
||||
the check names (the boot-disk checks: `Boot successful!`), else the log's last lines, control
|
||||
characters as escapes -- so #131's next occurrence explains itself in the job's output.
|
||||
- **The demo:** guests of **384 MiB** (`demo/qemu-args.sh`); `start-session.sh` takes one of
|
||||
`DEMO_MAX_GUESTS` slots (2), a lock held for the session's life, and with every slot taken tells
|
||||
the visitor every machine is busy and to try back in a few minutes; the service makes the locks'
|
||||
directory and lets ttyd take 6 connections so the extra visitors reach the message.
|
||||
|
||||
### 3. Verified
|
||||
|
||||
- The demo machine, booted here with only `-m` changed: POST 538/538 and Zuse's prompt at 1024, 512,
|
||||
384 and 256 MiB (82-84 s); at 128 MiB POST passes, then "StarForth v4: no memory for the block
|
||||
chain". The slots: every slot held -- the busy message; slot 1 held -- slot 2 taken.
|
||||
- `excerpt()` against a real riscv64 serial log, with an anchor and without; a riscv64 acceptance
|
||||
with the new script, passing as before.
|
||||
- With both wikis up again (Shenandoah, the .com's heap at 512 MiB, the .org's given 256 more): the
|
||||
server at 2.6 of 3.8 GiB used, 1.2 GiB available, 2 GiB of swap used; Build 204 (three images, the
|
||||
v4 tests) passed alongside them.
|
||||
|
||||
### 4. Try it, deployed (2026-11-08)
|
||||
|
||||
Captain Bob ran `demo/DEPLOY.md` on the server (#115): try.starshipos-f18.com with its own Let's
|
||||
Encrypt certificate, ttyd behind Apache, framing allowed to the .com alone. Checked from outside: a
|
||||
session ready 1.5 s after the page opens, `3 4 + .` -> `7 ok`, `: SQUARE DUP * ; 7 SQUARE .` ->
|
||||
`49 ok`, a third visitor at once told every machine is busy.
|
||||
|
||||
Found on the way:
|
||||
- Ubuntu's `ttyd` package starts its own `ttyd.service` -- `login` on port 7681, ours -- and
|
||||
until it was disabled the page served the server's login prompt to anyone. `DEPLOY.md` step 4
|
||||
now disables it first and checks what listens on 7681.
|
||||
- **An idle StarshipOS keeps a host core 100% busy** (#151): the demo machine at its prompt, idle
|
||||
20 s, QEMU at 100% of a core, 148 MiB resident -- the kernel's idle loop polls, never halts. Two
|
||||
visitors' sessions with Gitea's diff statistics on a burst of pushes (#152, 1.75 GiB) filled the
|
||||
server's swap and stalled both wikis. The service now caps all sessions together at one core at
|
||||
the lowest priority (`CPUQuota=100%`, `Nice=19`, `MemoryMax=1G`), until #151 is fixed.
|
||||
- **Try it in the .com's navigation** (#117): "Try it" added to the canvas's Home and Inquiries
|
||||
artboards, the .com rebuilt from them (`site/com`) and installed. Checked as a visitor: the home
|
||||
page, the "Try it" link, the Try it page in 1.1 s, its framed console Ready.
|
||||
|
||||
### 5. #151: the idle loop halts (2026-11-08)
|
||||
|
||||
Ruled (Captain Bob): "Fix the kernel problem." The v4 system waited for a key -- `sk_v4_readline()`
|
||||
with nothing typed, and `sk_v4_identity_wait()` headless until Zuse -- in `arch_relax()`, a spin.
|
||||
Both now wait in `arch_halt()` (`hlt` on amd64, `wfi` on aarch64 and riscv64) until the next
|
||||
interrupt: the heartbeat's timer, which is ISR-driven on all three (`heartbeat_tick()`), wakes them
|
||||
at 100 Hz, so a key is seen within a tick, as the cursor's blink and the identity beat already
|
||||
were. v3's REPL (`repl.c`) still spins; v3 is not in acceptance.
|
||||
|
||||
Verified: idle at Zuse's prompt for 20 s, QEMU's CPU **100% -> 1%** of a core on amd64 (the demo
|
||||
machine), and **1%** on aarch64 and riscv64 (`logs/20261108-011614`, `-011931`); the acceptance
|
||||
protocol passes -- amd64 `logs/20261108-005539`, aarch64 `-005753`, riscv64 `-010136`, POST
|
||||
538/538, `dict_hash 0xfec8c47cfc6f437f` on all three, `7 ok` typed and answered; the stick loaded
|
||||
high; `test-32` (39 programs, 0 failures). The demo's CPU cap (`CPUQuota=100%`) can be relaxed
|
||||
once this reaches the server.
|
||||
|
||||
### 6. #131 closed: QEMU's capture, not our kernel (2026-11-08)
|
||||
|
||||
Run 197's riscv64 serial log, read from Gitea's artifact store on the server (`acceptance-logs-185`),
|
||||
had the line with one character doubled -- "Boot diisk: not a StarshipOS stick" -- and a doubled
|
||||
byte in OpenSBI's banner too, printed before our kernel runs. So the byte was doubled in QEMU's
|
||||
serial capture under the server's load, not by the kernel (Captain Bob closed #131). The check that
|
||||
failed was right to: it refuses a line that is not what was printed. The capture itself (the log is
|
||||
`logfile=` on the socket chardev the acceptance types through) is what is left to harden.
|
||||
|
||||
### 7. Downloads (#126): what a release publishes, and what a download must boot to (2026-11-08)
|
||||
|
||||
- **Ruled** (Captain Bob): the Downloads page goes live with alpha.4, filled by the release itself;
|
||||
the StarshipOS Root CA's certificate is published with it.
|
||||
- **Built:** the release builds the PC's USB stick too (`scripts/nightly.sh images`, classifier
|
||||
`pc-stick`; `pc` stays the ISO QEMU boots), and makes the tag a Gitea release -- a pre-release for
|
||||
an alpha -- with the images, `SHA256SUMS`, the documents and the Root CA's certificate attached
|
||||
for anyone to download (`scripts/nightly.sh gitea-release`, run by `release.yml` with the secret
|
||||
`RELEASE_TOKEN`). Tested against a stand-in Gitea API: the release, its notes and ten files; a
|
||||
second run adds nothing.
|
||||
- **Found:** a downloaded image boots headless today -- "Zuse: no genesis on this disk -- the system
|
||||
stays headless"; minting Zuse on a stick's first boot (`docs/v4.0.0/STICK.md` section 6) is #92.
|
||||
**Ruled:** #92 into alpha.4, so the PC stick downloaded from alpha.4 on boots to
|
||||
`[zuse@Hera] ok>` at its first boot.
|
||||
|
||||
### 8. #92, Task 1: the proxy Zuse -- a stick's first boot mints its own (2026-11-08)
|
||||
|
||||
Plan `docs/v4.0.0/plans/2026-10-29-stick-5-proxy-zuse-and-real-zuse.md`, Task 1; `STICK.md` section 6.
|
||||
|
||||
- **Built:** the genesis marker's version 2 (`zuse_genesis_marker_v2_t`: the proxy's key and the
|
||||
real Zuse's, zero until she is minted), read and written by the v4 boot alone
|
||||
(`kernel/src/v4/sk_v4_marker.c`; a version 1 marker -- the minted pair's -- reads as a proxy with
|
||||
no real Zuse). The identity check and the genesis mint are split out of v3's
|
||||
`capsule_zuse_boot.c` (`capsule_zuse_boot_check_key`, `capsule_zuse_boot_genesis_mint`) as D1
|
||||
split the check from the VM; v3's callers are unchanged in behaviour. On v4
|
||||
(`sk_v4_identity.c`), a stick with no marker and a blank identity partition mints the proxy Zuse,
|
||||
reads her back, and only then writes the marker that names her; she is logged in. A marker with a
|
||||
real key gives the proxy no session (the fixed screen is Task 5).
|
||||
- **Tested first, seen to fail:** `genesis` (a fresh data stick, booted twice) failed on amd64 with
|
||||
"Zuse: no genesis on this disk -- the system stays headless", both boots. After: `genesis` passes
|
||||
on all three ISAs (first boot minted, second recognised, not minted again); `stick_genesis` -- the
|
||||
PC stick as built, no `STICK_PAIR` -- reaches `[zuse@Hera] ok>` with nothing set up: plug and play.
|
||||
Regressions pass: `zuse`, `stick_boot`, `stick_zuse`, `stick_artemis`, `two_sticks`,
|
||||
`artemis_unsigned`, `raw_ident`, `hotplug`, `midpull`, `waitpull`, `typeahead`, the seven GPT
|
||||
modes, `v3_keys`.
|
||||
- **My slip, written down:** `stick_boot` and `stick_artemis` were first run without
|
||||
`KERNEL_ARGS=--log-level=info`, which their disk-size checks read; they failed on that check alone,
|
||||
and passed when rerun at the info level. Both runs' logs are in the tree.
|
||||
- **Left as it is (the plan's order):** a genesis whose marker write fails leaves Zuse on the
|
||||
identity partition with no marker naming her; that stick then logs no one in until it is
|
||||
rewritten. Said once, "Zuse: genesis marker write failed -- headless".
|
||||
- **Accepted** (`scripts/nightly.sh accept` amd64, aarch64, riscv64, stick-high; `make -C v4
|
||||
test-32`): `PARITY:V4_POST tests=538 pass=538 fail=0` and `POST: PASSED` on all three and the
|
||||
stick loaded high; `dict_hash 0xfec8c47cfc6f437f` on the three, unchanged (Task 1 adds no word);
|
||||
test-32: 39 programs, 0 failures.
|
||||
|
||||
@@ -146,7 +146,7 @@ xHCI USB sticks, `scripts/qemu_session.py`.
|
||||
- **The Artemis partition must be formatted to take the marker:** `blk_subsys_confirm_format` only
|
||||
if the slot is provisional and its `artemis_sig_t` checked out (§4).
|
||||
|
||||
- [ ] **Step 1: Failing tests** (harness):
|
||||
- [x] **Step 1: Failing tests** (harness):
|
||||
- **`genesis`** (three ISAs): a fresh data stick (`DATASTICK=1 ZUSEDISK=`), built once into the
|
||||
session directory (`DATASTICK_IMG=<work>/data.img DATASTICK_DEP=`) and booted twice, one QEMU at
|
||||
a time. First boot: the genesis line, `[zuse@Hera] ok> `, `3 4 + .` → `7 ok`. Second boot:
|
||||
@@ -155,12 +155,12 @@ xHCI USB sticks, `scripts/qemu_session.py`.
|
||||
reaches the prompt. Today: FAIL (headless).
|
||||
- **Changed:** `stick_boot` expected the blank stick headless; it now expects the genesis line and
|
||||
the prompt.
|
||||
- [ ] **Step 2:** Run each: FAIL as listed.
|
||||
- [ ] **Step 3:** Implement.
|
||||
- [ ] **Step 4:** The new sessions pass; regression: `zuse` (the pair, version 1: logs in as the
|
||||
- [x] **Step 2:** Run each: FAIL as listed.
|
||||
- [x] **Step 3:** Implement.
|
||||
- [x] **Step 4:** The new sessions pass; regression: `zuse` (the pair, version 1: logs in as the
|
||||
proxy), `stick_zuse`, `stick_artemis`, `two_sticks`, `artemis_unsigned`, `raw_ident`, `hotplug`,
|
||||
`midpull`, `waitpull`, `typeahead`, the GPT modes, `v3_keys` (v3's genesis and marker unchanged).
|
||||
- [ ] **Step 5:** Suite; full acceptance; commit `feat(kernel): the proxy Zuse -- a stick's first
|
||||
- [x] **Step 5:** Suite; full acceptance; commit `feat(kernel): the proxy Zuse -- a stick's first
|
||||
boot mints its own Zuse; the genesis marker's version 2` with the logs.
|
||||
|
||||
### Task 2: Artemis grows to fill the stick
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user