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:
Robert Allan James
2026-08-15 09:37:58 -04:00
co-authored by Claude Sonnet 5
parent c5442c8377
commit 89d8c08582
10 changed files with 25755 additions and 46 deletions
+18 -10
View File
@@ -64,17 +64,25 @@ config STADIUM_CONTAINS_DEPTH_MAX
patrons held inside patrons within one Stadium.
config STADIUM_CAPACITY_TICK
int "Capacity arbitration cadence, in virtual ticks (STADIUM_CAPACITY_TICK)"
default 1000
int "Fleet transfer-slope re-estimation cadence, in virtual ticks (STADIUM_CAPACITY_TICK)"
default 4000
help
How often Hera re-evaluates capacity transfers between VMs
(FABRIC.md item 1.4), expressed in virtual ticks -- never
wall-clock. Default matches the existing precedent at
capsule_vm_physics.c's vm_physics_heartbeat_tick()
(HEARTBEAT_INFERENCE_FREQUENCY, also 1000), comfortably past
the "order of magnitude apart from the heat tick" minimum
(FABRIC.md §22.4). No consumer yet -- capacity arbitration
itself is not yet on the punch list.
How often vm_physics_heartbeat_tick() re-fits the fleet's
transfer-slope estimate (vm_physics_tick() -- a passive median
recompute over recent touch samples, not a capacity/transfer
decision itself), expressed in virtual ticks -- never wall-clock.
Wired in 2026-08-15 (FABRIC-2.md F.2/§12 Q5): this counter is fed
by EVERY live VM's own vm_tick(), not one VM's, so it previously
shared HEARTBEAT_INFERENCE_FREQUENCY (1000) and fired roughly
(live VM count) times faster than a single VM's own heat-inference
gate -- backwards from the "order of magnitude apart" minimum
(FABRIC.md §22.4). Default of 4000 is a flat, untuned placeholder
picked to roughly restore that separation at Tripod's known
4-VM topology (Hera + two Hermes + Artemis) -- not computed from
live VM count at runtime, deliberately: a fixed constant, same
as every other frequency knob here, not adaptive logic. Real
tuning is DoE work (item 5.1), same treatment as the other
placeholder constants in this file.
config STADIUM_MEMORY_PERCENT
int "Percent of free physical memory the Stadium claims at boot (STADIUM_MEMORY_PERCENT)"