Stage C-b: compudynamic switch decision, idle point, timer path removed (FABRIC-3.8 §3.13.3-§3.13.5)

Who runs next is now sk_vm_switch_decide(): among participants with work
(pending kernel-Hermes mail, parked mid-task, or Hera with console input),
the coolest by VM-physics heat; ties with the incumbent keep the incumbent,
ties among candidates go to the longest waiting (unique wait stamps). No
scheduler state, no timer: heartbeat_tick() no longer touches switching,
readiness/threshold/has_work/take_pending removed. Decided at owned word
checkpoints (colon words and, new, between top-level words) after a beat
or new mail, at the trampoline between messages, and at Hera's idle point
in the console poll loops. The idle pump skips participants (G3 closed for
them): the WIREBIND relay is delivered by a real switch to rajames~user.

Probe (restored away): relay via switch Hera->rajames~user->Hera on all
three ISAs, parked saved_sp inside own stack, walk-order disagreements 0
over tens of millions of decisions, 0 bytes idle log growth. Acceptance:
dict_hash unchanged, relay 3, no faults. Rulings: C-3, C-5 as proposed;
C-4 taken as (alpha), consequence recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-23 17:53:55 -04:00
co-authored by Claude Opus 5.5
parent 7c3736841d
commit 06bcab504d
27 changed files with 64636 additions and 218 deletions
+15 -1
View File
@@ -46,6 +46,8 @@
#include "starkernel/capsule_run.h"
#include "starkernel/vm/bootstrap/sk_vm_bootstrap.h"
#include "starkernel/vm/kernel_hermes.h" /* FABRIC-3.6.md task 3.8 -- sk_hermes_send_one() */
#include "starkernel/vm/switch.h" /* FABRIC-3.8.md §3.13.5 -- sk_vm_idle_point() */
#include "starkernel/capsule_vm_switch_signal.h" /* §3.13.5 -- pump skips participants */
#include "starkernel/vm/stadium.h" /* task 3.8 -- stadium_conserved() evidence print */
#include "block_subsystem.h"
#include "word_source/include/keyboard_words.h"
@@ -912,9 +914,15 @@ static void sk_repl_idle(VM *active_vm)
for (i = 0; i < count; i++) {
VMRegistryEntry ent;
/* FABRIC-3.8.md §3.4 / §3.13.5 (Stage C-b, G3): switch
* participants are skipped -- their mail is delivered on their
* own stacks, by a switch (sk_vm_idle_point() and the trampoline),
* never drained here on Hera's. Only VMs not yet participants
* (Stage E makes every born VM one) are still pumped here. */
if (capsule_vm_registry_get_by_index(i, &ent) == 0 &&
ent.state == VM_STATE_LIVE &&
ent.vm_ptr != (void *)mama) {
ent.vm_ptr != (void *)mama &&
!sk_vm_switch_signal_is_participant(ent.vm_id)) {
(void)sk_hermes_drain_checkpoint((VM *)ent.vm_ptr);
}
}
@@ -1081,6 +1089,7 @@ int sk_console_getkey(VM *active_vm)
VM *live_active = g_repl_active_vm ? g_repl_active_vm : (VM *)sk_get_mama_vm();
sk_repl_idle(live_active);
}
sk_vm_idle_point(); /* FABRIC-3.8.md §3.13.5 -- acts only between lines */
arch_relax();
}
}
@@ -1104,6 +1113,7 @@ void sk_repl_headless_wait(VM *mama)
g_last_beat_tick = now;
sk_repl_idle(mama);
}
sk_vm_idle_point(); /* FABRIC-3.8.md §3.13.5 */
arch_relax();
}
}
@@ -1303,6 +1313,10 @@ int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt)
* On real hardware a wfi/hlt would be appropriate; add it here
* under an #ifdef REAL_HARDWARE guard when that path is needed.
*/
/* FABRIC-3.8.md §3.13.5 (Stage C-b): Hera waiting for a line is
* the idle point -- the coolest VM with work runs now, not at
* the next SK_IDLE_BEAT_INTERVAL (that cadence is the timer's). */
sk_vm_idle_point();
arch_relax(); /* PAUSE — reduce power, maintain tight poll */
continue;
}