diff --git a/FABRIC-3.8.md b/FABRIC-3.8.md index 23ce8e7b..173446ff 100644 --- a/FABRIC-3.8.md +++ b/FABRIC-3.8.md @@ -1398,3 +1398,7 @@ explicit instruction. share), not in the DoE capsule. - Only the one capsule line is reverted. This entry stays as the record; the two logs were removed afterwards, on Captain Bob's instruction (see above). +- **Continued in `FABRIC-3.9.0.md` (design) and `FABRIC-3.9.8.md` (execution), 2026-09-24.** + Captain Bob: the Tripod (Hera, Artemis, Hestia) stops participating in the compudynamic + calculations. Its members observe them and act on events. That design, not a heat-share + charge, is how "Hera the major consumer" gets fixed. The DoE relaunch moves there as stage O-D. diff --git a/FABRIC-3.9.0.md b/FABRIC-3.9.0.md new file mode 100644 index 00000000..7d29b22b --- /dev/null +++ b/FABRIC-3.9.0.md @@ -0,0 +1,156 @@ +# FABRIC-3.9.0.md — Observers and participants: the Tripod steps outside the compudynamics + +**Status: DESIGN, for Captain Bob's review. Nothing here authorizes an edit.** The execution +plan and log are in `FABRIC-3.9.8.md`. + +**Provenance.** Opened 2026-09-24. This design follows `FABRIC-3.8.md`, whose Stages A–I are +all done. The per-ISA DoE relaunch on the rebuilt driver (`FABRIC-3.8.md` §6) was stopped once a +progress check showed: +- Hera's `MU-WAIT-ALL` busy loop took an equal share of the CPU as workers finished; +- it wrote 43% of all heartbeat rows so far (Hera 75,117 against `mu0`'s 75,114). + +Two fixes were tried and set aside: +- **A capsule-level `100 WAIT`,** reverted. Captain Bob: *"not liking this much … redistribute + work when hera is the major consumer."* The application must not steer its own scheduling. +- **A kernel-side absolute-heat-share charge.** Built and tested (a cfg-0 trial took about 150 s + against about 210 s), but never committed. It is superseded by this design (§5). + +Captain Bob, 2026-09-24: +- *"Hera, Hestia, and Artemis no longer participate in the calculations. However, they observe + them and act on them."* +- *"let's do it."* + +--- + +## 1. The idea + +The fleet splits into two roles. + +- **Participants** are every VM that does the work being done and measured: DoE workers, + WIREBIND user and console VMs, and anything `BIRTH`-ed. For these, FABRIC-3.8's compudynamics + stays exactly as built: + - per-beat charge; + - work heat, with floor on contact; + - coolest VM with work goes next; + - ties to the incumbent, then to the one waiting longest. +- **Observers** are Hera, Artemis and Hestia, the Tripod. They are not compared, not charged work + heat, and not counted in any floor. They **observe** the participants' physics and **act on + events**: mail, console input, device events. + +**In thermodynamic terms,** the observers are the environment (the heat bath) and the +participants are the system under study. +- Hera already behaves like a reservoir: she starts holding all of `Q48_ONE`, as the root that + `vm_physics_retire()` returns heat to. +- Every problem since Stage G came from making the reservoir compete as if it were one more + particle: + - her endowment made her "hottest"; + - her busy-wait took a fair share of the CPU and polluted the data; + - two fixes had to push her back out. + +## 2. What changes for observers + +**2.1 Who is an observer.** It's a structural fact, set by the kernel, not a name test in the +switcher. +- `capsule_birth_baby()` already computes `is_fleet_foundation` (Hera/Artemis/Hestia) for session + pinning. The observer role reuses that. +- Hera, born through `capsule_birth_mama()`, is marked where `kernel_main.c` registers her. +- Nothing a VM executes can set or clear the role. + +**2.2 Not in the calculation.** +- `sk_vm_switch_decide()` never offers an observer as a heat candidate. +- `vm_physics_charge()` doesn't accrue observers' work heat. +- `sk_vm_switch_signal_note_work_gained()` leaves observers out of the floor. +- Proposed (ruling O-2): observers aren't charged **absolute** heat either. The reservoir doesn't + heat itself by running. Participants still pull absolute heat off it through their own charges, + and `retire` returns it, so fleet K stays conserved. + +**2.3 Observers act on events.** An observer is runnable only when it has an event: +- **Mail:** its kernel-Hermes queue is non-empty (`MU-DONE`, `BLK-ATTACH`, `ELEVATE-REQUEST`, a + relayed console line). +- **Console input**, for Hera: `sk_console_key_available()`, as today. +- **A device event**, for Hera: xHCI and USB attach or detach. See §4, ruling O-4. + +**2.4 When an observer runs (ruling O-1: the central question).** Proposed: **at the next clean +boundary, an observer with an event goes ahead of the participants.** +- The boundaries are the same owned checkpoints, trampoline points and idle point FABRIC-3.8 + built. +- Among several observers with events, the one waiting longest (the existing unique wait stamps) + goes first, with no heat. +- Once it has no events left it parks, and the participants' physics resumes. + +Why this isn't a scheduler: +- There is no run queue, no priority number, and no ordering computed or kept. +- It is a **role** (environment versus system), not a rank among peers. +- Observers never compete with participants on the same scale; they respond to what happens. +- The honest risk: an observer with a long event (a heavy command typed at Hera's own prompt) + holds the CPU until it finishes, because nothing displaces an observer. §4 lists this. Work + meant to share the CPU belongs in a participant. A user's commands already go to their own + WIREBIND user VM, which is a participant. + +The alternative, observers run only when no participant has work, is pure but brings back +C-4 (α)'s starvation: under load, the console, USB and storage wait until every worker is idle. + +**2.5 Hera's own mail is delivered at the idle point, not on the timer.** +- Today her queue is drained by `sk_repl_idle()`'s pump at the `SK_IDLE_BEAT_INTERVAL` cadence + (timer-paced; the last such delivery left, `FABRIC-3.8.md` Stage I). +- As an observer that acts on events, her mail must be acted on promptly, so her drain moves to + `sk_vm_idle_point()`. +- It keeps the readline `n > 0` mid-edit gate, so a drained payload never prints into a line + being typed. + +## 3. What this lets the DoE become + +**The driver becomes event-driven. Hera never waits in a loop.** +- `DOE` sets up the campaign and starts trial 1 (birth all, send all), then returns to the prompt. +- Each worker's final `SEND` delivers `MU-DONE` to Hera as mail. +- She acts on it at her idle point: increments the count, and on the last one ends the trial + (`KILL` all, marker, persist) and starts the next. +- After the last trial she prints `MU-CAMPAIGN: complete`. +- `MU-WAIT-ALL` is deleted. This is the §3.9 design's own "ordinary words" rule, applied: Hera + reacts to messages, which is what messages are for. + +**The heartbeat rows then measure the system, not the environment.** +- An observer produces rows only while acting on an event. +- Proposed (ruling O-3): its rows stay in the CSV, tagged by `vm_name` as today, and the analysis + filters by role. This keeps the CSV layout unchanged. The alternative is to suppress them. + +## 4. Known limits and open questions + +- **O-4: device servicing.** xHCI event polling and USB attach/detach run in `sk_repl_idle()` at + the timer-paced `SK_IDLE_BEAT_INTERVAL`, and only when Hera reaches her idle point. + - Under participant load, Hera reaches it only when she has another event, so USB goes + unserviced. A USB keyboard is a device event that can only be *seen* by polling. + - Options: (a) treat "the device-poll interval elapsed" as a Hera event; that's I/O + housekeeping triggering a switch, not a scheduling decision, but it is timer-paced. (b) Move + xHCI polling to an interrupt path. (c) Accept it for now; the DoE doesn't need USB mid-run. + - Proposed: (c) for the relaunch, (b) as later work. +- **A long event on an observer holds the CPU** (§2.4). Accepted by the role design: heavy work + belongs in participants. +- **Artemis and Hestia become observers too.** + - Artemis's storage work (attach, block sync) and Hestia's framebuffer are responses to events, + which fits. + - If a future Tripod duty is compute-heavy, it would have to move to a participant. +- **Stage G's evidence** (two participants interleave) and C-b's walk-order property are + unaffected: observers aren't candidates. +- **The WIREBIND relay** stays participant-delivered: the user VM gets the console line as mail + and is switched to by heat among participants. Only Hera's own forwarding is observer work. + +## 5. What this supersedes + +- **Absolute-heat-share charge** (uncommitted: `capsule_vm_physics.c/.h` working-tree changes on + 2026-09-24). No longer needed once Hera isn't compared. Proposed: discard it. +- **`MU-WAIT-ALL`**, and every busy-wait in the DoE driver. +- **The C-4 (α) consequence** recorded at C-b, where the console got no turn under worker load. + An observer with console input goes ahead of the participants at the next boundary. + +## 6. Rulings needed from Captain Bob + +1. **O-1:** observers with an event go ahead of participants at the next clean boundary + (proposed), or observers run only when no participant has work. +2. **O-2:** observers aren't charged absolute heat either (proposed), or they keep the C-a + absolute charge and are only left out of work heat. +3. **O-3:** observer heartbeat rows kept and tagged, filtered in analysis (proposed), or + suppressed. +4. **O-4:** device servicing under load: (c) accept for the relaunch and (b) interrupt-driven + later (proposed), or (a) treat the device-poll interval as a Hera event. +5. **Discard the uncommitted absolute-heat-share charge** (proposed), or keep it as a safety net. diff --git a/FABRIC-3.9.8.md b/FABRIC-3.9.8.md new file mode 100644 index 00000000..0f17511d --- /dev/null +++ b/FABRIC-3.9.8.md @@ -0,0 +1,40 @@ +# FABRIC-3.9.8.md — Observers and participants: execution plan and log + +**Status: PLANNED. No stage started.** The design and its open rulings (O-1 to O-4, plus the +discard question) are in `FABRIC-3.9.0.md`. + +Each stage: +- needs Captain Bob's explicit go; +- gets its own commit; +- gets its own three-architecture acceptance (`clean qemu`; amd64, then aarch64, then riscv64; + foreground; visible framebuffer; one at a time; coupled images reset before each). + +Evidence is named **before** each stage runs. + +**The standing acceptance sequence for every stage**, unchanged from `FABRIC-3.8.md`: +- a boot to `[zuse@Hera] ok>` with zero `UNKNOWN WORD`, faults and frame corruption; +- the `dict_hash` set identical across ISAs; +- the Stage G interleave (two workers, `A`/`B`), byte-identical across ISAs; +- mint → WIREBIND → `USE` → `1 2 + .` → `3`; +- 0 bytes of idle log growth over 20 s. + +## 1. Staged plan + +| Stage | Change | Evidence (named in advance) | +|---|---|---| +| **O-A** | Observer role (`FABRIC-3.9.0.md` §2.1). The absolute-heat-share charge is discarded (ruling 5). Observers are left out of the decision's candidates, the work-heat charge and the floor. (Also the absolute charge, if O-2 is ruled so.) Observers with events go ahead at clean boundaries, among themselves by wait stamp (§2.4, per O-1). | The standard sequence. A probe (reverted after capture) shows the decision never returning an observer as a heat candidate, and an observer with mail switched to at the next participant checkpoint. **The busy-wait DoE driver, unchanged, run as a cfg-0 trial with rows on for a fixed window:** Hera's share of rows falls from about ½ (the stopped relaunch's tail) to near 0 while both workers have work. That is the measured symptom this design exists to fix. | +| **O-B** | Hera's own mail drained at `sk_vm_idle_point()`, with the readline `n > 0` gate; the timer-paced pump drain removed (§2.5). | The standard sequence, plus: a message sent to Hera while she sits idle at the prompt is acted on **without waiting for the idle beat**. A probe records the delay in beats from admission to drain; it must be well under `SK_IDLE_BEAT_INTERVAL`. The relay and BLK-ATTACH flows are unchanged. | +| **O-C** | An event-driven DoE driver (§3): `DOE` starts trial 1 and returns to the prompt; `MU-DONE` counts, ends trials and starts the next; `MU-WAIT-ALL` is deleted. Capsule only. | A 1-rep smoke campaign on amd64 runs all 6 cells to `MU-CAMPAIGN: complete`, with every trial `fail=0` and N/N `KILL … dead`. Hera's rows during trials are only event handling. The prompt answers typed input while trials run. Then the standard sequence on all three ISAs. | +| **O-D** | The DoE relaunch: `12345 3 S" " DOE`, amd64, then aarch64, then riscv64, with the ring extracted between ISAs and `artemis.img` **not** reset in between. | A fresh time estimate from O-C's measured row rate, **before** launch. Then per ISA: 18 `MU-TRIAL` markers, `fail=0`, `MU-CAMPAIGN: complete`. | +| **Merge** | This branch to `master`, once all three ISAs have completed O-D. | Per this project's own merge practice, at Captain Bob's word. | + +**Stop conditions** (re-plan rather than push on): +- `dict_hash` diverges across ISAs; +- conservation (`vm_physics_conserved()`, `stadium_conserved()`) goes false; +- an observer is ever returned as a heat candidate; +- a switch storm: log growth at an idle prompt, with QEMU pinned; +- a trial that never produces its marker. + +## 2. Execution log + +*(empty: no stage started)*