feat(v4): the mesh boot to spec -- Hera born empty in the kernel's fabric; births, kills, every node stepping together (#189)

ENGINE step 4 Phase 1, Tasks 5b-5d, and the edge cases (Captain Bob, 2026-11-13: "Build it to proper
spec"; "Check for the edge cases"; "Yes, add it to v4-checks").

- v4/system/mesh.c, v4/include/v4/mesh.h: the nucleus assembled by the ROM and given to Hera as F18
  cells; Hera born empty at place 0, the kernel on port 0, the console on port 1; told she is 10, in the
  registry, the kernel's words, FORTH-79, sealed, POST, the kernel's capsules. NODE-BORN / NODE-KILL in
  the owner's room.
- No scheduler: v4_mesh_tell returns once the node told says how its text ended, and
  v4_mesh_step / v4_mesh_busy let the host step the fabric while it waits, so nodes run between
  lines as during them. A text left "waiting" is owed its end: the next line ends it "Interrupted"
  and is then run (MESH.md 7b.6).
- kernel: sk_v4.c boots through the mesh; its idle steps the fabric while a node can run, and halts
  only when none can (#151 kept). stadium_return_quota and stadium_ops_forget on a kill.
- Tests: v4/tests/test_mesh_boot.c (32 checks: the boot, births, kills, rebirth, a live number, a
  fault, no such node, Hera not killing herself, no room, a line too long, a node running for ever,
  a wait broken by the next line), run by `make -C v4 test` and under ASan+UBSan by `sanitize`
  (v4-checks); kernel/tests quota return; scripts/qemu_session.py births() and the edges on bare
  metal.
- Docs: ENGINE.md 6 "who runs next" struck (settled: no scheduler); the Phase 1 plan; FABRIC-3
  XLVIII.23; .claude/memory/rules.md: alpha.5 closed to new work.
- Evidence: v4-checks 80 programs under the sanitizers, 0 failures; the hosted builds alike; two
  stopped v4-checks runs labelled STOPPED; three development amd64 boots labelled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RzZgrf7V7Zk2iczBXDRbm
This commit is contained in:
Claude
2026-11-13 17:00:08 +00:00
parent d7d3e088db
commit 046ce0be65
34 changed files with 1166 additions and 181 deletions
+88 -133
View File
File diff suppressed because it is too large Load Diff
+36
View File
@@ -667,6 +667,42 @@ int stadium_grant_quota(VMUuid new_vm_id, VMUuid from_vm_id) {
return 0;
}
int stadium_return_quota(VMUuid vm_id, VMUuid to_vm_id) {
int slot, to_slot;
size_t idx, last = STADIUM_CELL_NONE, count = 0;
if (!stadium_initialized) return -1;
slot = quota_slot_for_vm(vm_id);
to_slot = quota_slot_for_vm(to_vm_id);
if (slot <= 0 || to_slot < 0 || slot == to_slot) return -1; /* slot 0 is patron zero's */
/* its patrons leave, their heat to its reservoir */
while (stadium_quotas[slot].resident_head != STADIUM_CELL_NONE)
if (stadium_evict(stadium_quotas[slot].resident_head) != 0) return -1;
/* its free cells to `to`'s free list */
for (idx = stadium_quotas[slot].free_head; idx != STADIUM_CELL_NONE;
idx = link_to_size(stadium_cell_array[idx].header.link)) {
stadium_owner[idx] = (uint16_t)to_slot;
last = idx;
count++;
}
if (last != STADIUM_CELL_NONE) {
stadium_cell_array[last].header.link = size_to_link(stadium_quotas[to_slot].free_head);
stadium_quotas[to_slot].free_head = stadium_quotas[slot].free_head;
stadium_quotas[to_slot].free_count += count;
}
stadium_quotas[slot].vm_id = vm_uuid_none();
stadium_quotas[slot].in_use = 0;
stadium_quotas[slot].free_head = STADIUM_CELL_NONE;
stadium_quotas[slot].free_count = 0;
stadium_quotas[slot].resident_head = STADIUM_CELL_NONE;
stadium_quotas[slot].reservoir = 0;
stadium_quotas[slot].consumed = 0;
return 0;
}
/*
* stadium_best_donor - FABRIC-3.md SXVI donor-floor fix: which currently
* in-use VM has the most free (unclaimed) cells right now. Callers granting
+14
View File
@@ -136,6 +136,20 @@ void stadium_ops_charge(VMUuid vm_id, const uint64_t counts[STADIUM_OPS_COUNT],
}
}
void stadium_ops_forget(VMUuid vm_id)
{
int slot;
unsigned k;
if (!ops_initialized) return;
slot = stadium_quota_slot_for_vm(vm_id);
if (slot < 0) return;
for (k = 0; k < STADIUM_OPS_COUNT; k++) {
op_slots[slot][k].cell_index = STADIUM_CELL_NONE;
op_slots[slot][k].last_tick = 0;
op_slots[slot][k].last_count = 0;
}
}
uint64_t stadium_ops_heat(VMUuid vm_id, unsigned op)
{
int slot;