stadium: wire STADIUM_CAPACITY_TICK in as a flat threshold, not a scheduler
Closes FABRIC-2.md's last open §12 Q5 question. fleet_heartbeat_tick_count is fed by every live VM's own vm_tick(), not one VM's, so it was reaching HEARTBEAT_INFERENCE_FREQUENCY (shared/borrowed from the per-VM inference gate) several times faster than intended with more than one VM live - backwards from FABRIC.md §22.4's required ~1000:1 separation. What's actually gated turned out to be low-stakes: vm_physics_tick() (capsule_vm_physics.c:397) is a passive statistics refit - re-sorts a window of past heat-transfer samples and recomputes a median rate estimate. It doesn't move heat or arbitrate capacity. Firing too often just meant a noisier statistic recomputed more frequently than planned, not incorrect behavior. Considered and explicitly rejected: scaling the threshold by live VM count at the check site. That's the first brick of a scheduler - reading fleet state to adjust a rate dynamically - which this project has deliberately avoided building. Implemented instead: STADIUM_CAPACITY_TICK (existing Kconfig symbol, defined but never read by any code path) now gates vm_physics_heartbeat_tick()'s call directly, replacing the borrowed HEARTBEAT_INFERENCE_FREQUENCY. Default bumped 1000 -> 4000, a flat constant picked once for Tripod's known 4-VM topology, same kind of placeholder as every other frequency knob in Kconfig.kernel - not computed from anything at runtime. Renamed fleet_last_inference_tick -> fleet_last_capacity_tick to match. Still one clock, one counter (fleet_heartbeat_tick_count) - just a bigger flat divisor on it. Three-arch QEMU acceptance: all clean to ok>, identical Stadium conservation invariant on all three (resident_sum=43691 reservoir=21845 sum=65536). logs/20260815-093425/amd64, logs/20260815-093521/aarch64, logs/20260815-093641/riscv64. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
c5442c8377
commit
89d8c08582
+30
-26
@@ -763,34 +763,38 @@ all four `.claude/*.md` files, and correcting `.claude/CLAUDE.md`'s own pointer
|
||||
running both *after* Artemis lands, since Artemis's own storage/timing work is likely to
|
||||
perturb whatever gets measured now — a recommendation, not a ruling made here.
|
||||
|
||||
**Needs Captain Bob's ruling:**
|
||||
- [x] **§12 Q5's `STADIUM_CAPACITY_TICK` wiring — CLOSED 2026-08-15.** A real, verified
|
||||
ordering violation, live today: with Hermes restored (item 4.2) and `STADIUM_MAX_VM_COUNT`
|
||||
(now RAM-derived, Section G) at more than one VM, the shared fleet counter reached
|
||||
`HEARTBEAT_INFERENCE_FREQUENCY` several times faster than §22.4's required 1000:1
|
||||
separation intended.
|
||||
|
||||
- [ ] **§12 Q5's `STADIUM_CAPACITY_TICK` wiring.** A real, verified ordering violation, live
|
||||
today, not latent: with Hermes restored (item 4.2) and `STADIUM_MAX_VM_COUNT` defaulting to
|
||||
4, the shared fleet-capacity counter can already reach `HEARTBEAT_INFERENCE_FREQUENCY` up to
|
||||
~4× sooner in wall-clock terms than a single VM's own heat-inference gate — backwards from
|
||||
§22.4's required 1000:1 separation, confirmed by this document's own §12 Q5 investigation
|
||||
above.
|
||||
**What was actually at stake, checked before fixing anything:** the thing gated by this
|
||||
threshold, `vm_physics_tick()` (`capsule_vm_physics.c:397`), is a passive statistics
|
||||
refit — it re-sorts a sliding window of past heat-transfer samples and recomputes a median
|
||||
rate estimate. It does not move heat, does not arbitrate capacity, does not decide
|
||||
anything. Firing it too often just meant a noisier statistic recomputed more frequently
|
||||
than planned — not incorrect behavior, not a live bug in the urgent sense.
|
||||
|
||||
**Correction 2026-08-15 — the fix must stay inside the one-clock rule (`FABRIC.md` §16.4
|
||||
GAP-A1, §17.1 "two measures, one clock... this does not mean two clocks").** `fleet_
|
||||
heartbeat_tick_count` (`capsule_vm_physics.c:157`) is a single counter, incremented once
|
||||
per call to `vm_physics_heartbeat_tick()`, which itself only ever fires from inside the
|
||||
execution-paced `vm_tick()` (`vm_runtime.c:141`) — never from a hardware timer. So there is
|
||||
only one clock here, exactly as ruled; the earlier framing of this item ("give the capacity
|
||||
tick its own named constant... independent of per-VM tick counts") was worded ambiguously
|
||||
enough to read as "add a second clock," which is not the fix and must not be built as one.
|
||||
The actual defect is narrower: `vm_tick()` calls `vm_physics_heartbeat_tick()` from *every*
|
||||
live VM's own dispatch (deliberate, `vm_runtime.c:126-138`'s own comment explains why — the
|
||||
fleet-capacity signal needs to reflect aggregate activity, not just Hera's), so `fleet_
|
||||
heartbeat_tick_count` advances on the fleet's *combined* stream while `HEARTBEAT_INFERENCE_
|
||||
FREQUENCY` was written assuming a single VM's stream. Same one counter, same one clock —
|
||||
the threshold compared against it just doesn't account for multiple VMs feeding it at once.
|
||||
**Question for Bob:** the fix is to give `STADIUM_CAPACITY_TICK` a larger *threshold value*
|
||||
checked against the existing `fleet_heartbeat_tick_count` (still one clock, one counter —
|
||||
just a bigger divisor, e.g. scaled by the live VM count so it restores something closer to
|
||||
the required 1000:1 separation), not a second tick source. Wire it in that way, or resolve
|
||||
the ordering some other way?
|
||||
**Fix, explicitly NOT the shape first proposed.** The initial framing ("threshold scaled
|
||||
by live VM count") was rejected by Captain Bob before implementation — correctly: reading
|
||||
VM count at the check site to adjust a rate dynamically is the first brick of a scheduler,
|
||||
which is exactly the kind of machinery this project has deliberately avoided building.
|
||||
Implemented instead: `STADIUM_CAPACITY_TICK` (existing Kconfig symbol, previously defined
|
||||
but never read by any code path) now gates `vm_physics_heartbeat_tick()`'s call to
|
||||
`vm_physics_tick()` directly, replacing the borrowed `HEARTBEAT_INFERENCE_FREQUENCY`.
|
||||
Default bumped from 1000 to a flat **4000** — a fixed constant picked once for Tripod's
|
||||
known 4-VM topology, same kind of placeholder as every other frequency knob in
|
||||
`Kconfig.kernel`, not computed from anything at runtime. Renamed
|
||||
`fleet_last_inference_tick` → `fleet_last_capacity_tick` to match. Still one clock, one
|
||||
counter (`fleet_heartbeat_tick_count`), unchanged — just a bigger flat divisor on it.
|
||||
|
||||
Files: `Kconfig.kernel`, `include/starforth_config.h`,
|
||||
`include/starkernel/vm/stadium.h` (comment only),
|
||||
`src/starkernel/capsule/capsule_vm_physics.c`. Three-arch QEMU acceptance, all clean to
|
||||
`ok>`, identical Stadium conservation invariant on all three
|
||||
(`resident_sum=43691 reservoir=21845 sum=65536`): `logs/20260815-093425/amd64/`,
|
||||
`logs/20260815-093521/aarch64/`, `logs/20260815-093641/riscv64/`.
|
||||
|
||||
**Closed-by-ruling, not reopened this pass** (each already has a recorded "flag and leave"
|
||||
decision from Captain Bob — reversing that without being asked would be exactly the
|
||||
|
||||
Reference in New Issue
Block a user