Stage B proof: add per-VM consumed term to stadium_conserved -- FABRIC-3.6.md task 2.7
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
313ffc89e6
commit
2a2bf6eb35
@@ -951,6 +951,43 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
if (held4 != pulled4 - returned4 - consumed4) ok = 0;
|
||||
if (stadium_reservoir_peek(alloc_test_id) != reservoir0 - decay_expected) ok = 0;
|
||||
|
||||
/* Task 2.7, Stage B proof (SXXXIV.3 as corrected by SXXXIX.4):
|
||||
* a fresh alloc/decay/free cycle on this VM, checking BOTH the
|
||||
* ledger and stadium_conserved() at every stage. fleet_conserved
|
||||
* is deliberately not consulted (cannot see Stadium heat). The
|
||||
* four-term form must hold before, mid-hold, after decay, and
|
||||
* after release; and after decay the old two-term form must
|
||||
* FAIL while the four-term one holds -- proving the consumed
|
||||
* term is load-bearing, not vacuous. */
|
||||
{
|
||||
uint64_t nb = 0, h, p_, r, c;
|
||||
/* Derived from the CURRENT reservoir: the earlier decay
|
||||
* cycle consumed heat, so fewer than expected_n fit now. */
|
||||
uint64_t expected_b = stadium_reservoir_peek(alloc_test_id) / SK_HERMES_Q_SLOT;
|
||||
int sb = 1;
|
||||
if (!stadium_conserved(alloc_test_id)) sb = 0; /* before */
|
||||
while (nb < SK_HERMES_MSG_MAX && sk_hermes_alloc(alloc_test_id, &msg) == 0) {
|
||||
msgs[nb++] = msg;
|
||||
}
|
||||
if (nb != expected_b || nb == 0) sb = 0;
|
||||
if (!stadium_conserved(alloc_test_id)) sb = 0; /* mid-hold */
|
||||
for (i = 0; i < nb; i++) if (sk_hermes_decay(msgs[i]) != 0) sb = 0;
|
||||
if (!stadium_conserved(alloc_test_id)) sb = 0; /* after decay */
|
||||
if (stadium_consumed_peek(alloc_test_id) == 0) sb = 0;
|
||||
if (stadium_resident_sum(alloc_test_id) + stadium_reservoir_peek(alloc_test_id)
|
||||
== (uint64_t)Q48_ONE) sb = 0; /* two-term must fail */
|
||||
sk_hermes_ledger(&h, &p_, &r, &c);
|
||||
if (!sk_hermes_audit_values(h, p_, r, c)) sb = 0;
|
||||
for (i = 0; i < nb; i++) if (sk_hermes_release(msgs[i]) != 0) sb = 0;
|
||||
if (!stadium_conserved(alloc_test_id)) sb = 0; /* after release */
|
||||
sk_hermes_ledger(&h, &p_, &r, &c);
|
||||
if (h != held0 || !sk_hermes_audit_values(h, p_, r, c)) sb = 0;
|
||||
console_puts("Stage B (ledger + stadium_conserved): ");
|
||||
console_println(sb ? "PASS" : "FAIL");
|
||||
print_uint(" vm_consumed=", stadium_consumed_peek(alloc_test_id));
|
||||
if (!sb) ok = 0;
|
||||
}
|
||||
|
||||
/* Task 2.6: the live audit never fired across both cycles,
|
||||
* and a ONE-unit corruption of each counter in turn (on a
|
||||
* copy -- live state untouched) is caught by the pure
|
||||
|
||||
@@ -151,6 +151,7 @@ int sk_hermes_alloc(VMUuid vm_id, SkHermesMessage **out_msg) {
|
||||
memset(&sk_hermes_msgs[slot], 0, sizeof(SkHermesMessage));
|
||||
sk_hermes_msgs[slot].in_use = 1;
|
||||
sk_hermes_msgs[slot].stadium_cell = (int32_t)cell;
|
||||
sk_hermes_msgs[slot].owner = vm_id;
|
||||
*out_msg = &sk_hermes_msgs[slot];
|
||||
|
||||
/* Task 2.4: the one site where held/pulled increment -- only reached
|
||||
@@ -222,6 +223,7 @@ int sk_hermes_decay(SkHermesMessage *msg) {
|
||||
* pays for it). SXXXVII.3: decay's delta is exact and in hand here. */
|
||||
sk_hermes_consumed += before - after;
|
||||
sk_hermes_held -= before - after;
|
||||
stadium_consumed_record(msg->owner, before - after);
|
||||
sk_hermes_audit();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -107,6 +107,10 @@ typedef struct {
|
||||
* Invariant: Σ(resident patron heat) + reservoir ==
|
||||
* Q48_ONE, checked the same way vm_physics_conserved()
|
||||
* checks the fleet sum. */
|
||||
uint64_t consumed; /* FABRIC-3.5.md §XL.4 -- Q48.16, heat this VM's messages
|
||||
* have decayed away (recorded by kernel-Hermes,
|
||||
* FABRIC-3.6.md task 2.7). Full invariant:
|
||||
* Σ(resident) + reservoir + consumed == Q48_ONE. */
|
||||
} StadiumVMQuota;
|
||||
|
||||
/* kmalloc'd at stadium_boot_init() to stadium_max_vm_count_val entries,
|
||||
@@ -275,6 +279,7 @@ int stadium_boot_init(void) {
|
||||
quotas[i].free_count = 0;
|
||||
quotas[i].resident_head = STADIUM_CELL_NONE;
|
||||
quotas[i].reservoir = 0;
|
||||
quotas[i].consumed = 0;
|
||||
}
|
||||
}
|
||||
quotas[0].vm_id = vm_uuid_hera();
|
||||
@@ -642,6 +647,7 @@ int stadium_grant_quota(VMUuid new_vm_id, VMUuid from_vm_id) {
|
||||
stadium_quotas[new_slot].free_count = half;
|
||||
stadium_quotas[new_slot].resident_head = STADIUM_CELL_NONE;
|
||||
stadium_quotas[new_slot].reservoir = Q48_ONE;
|
||||
stadium_quotas[new_slot].consumed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -764,8 +770,23 @@ uint64_t stadium_resident_sum(VMUuid vm_id) {
|
||||
return sum;
|
||||
}
|
||||
|
||||
void stadium_consumed_record(VMUuid vm_id, uint64_t amount) {
|
||||
int slot = quota_slot_for_vm(vm_id);
|
||||
|
||||
if (slot < 0) return;
|
||||
stadium_quotas[slot].consumed += amount;
|
||||
}
|
||||
|
||||
uint64_t stadium_consumed_peek(VMUuid vm_id) {
|
||||
int slot = quota_slot_for_vm(vm_id);
|
||||
|
||||
if (slot < 0) return 0;
|
||||
return stadium_quotas[slot].consumed;
|
||||
}
|
||||
|
||||
int stadium_conserved(VMUuid vm_id) {
|
||||
return (stadium_resident_sum(vm_id) + stadium_reservoir_peek(vm_id)) == (uint64_t)Q48_ONE;
|
||||
return (stadium_resident_sum(vm_id) + stadium_reservoir_peek(vm_id) +
|
||||
stadium_consumed_peek(vm_id)) == (uint64_t)Q48_ONE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user