2 Commits
Author SHA1 Message Date
Robert Allan JamesandClaude Sonnet 5 4ce28edf8f 3-arch QEMU acceptance + live diagnostic logs for the WIREBIND overflow trigger
Build / build-amd64-iso (push) Canceled after 0s
Build / build-aarch64-iso (push) Canceled after 0s
Build / build-riscv64-img (push) Canceled after 0s
Per .claude/CLAUDE.md's non-negotiable acceptance criteria, ran
`make -f Makefile.starkernel ARCH=<amd64|aarch64|riscv64> clean qemu`
sequentially (one instance at a time, TCG) against the preceding commit.
All three booted cleanly to `(zuse) ok>` with identical dictionary hashes,
no regression from the new idle-tick overflow check.

Also includes the amd64 run (20260905-161517) that carried the temporary
TEST-OWNER-CLAIM diagnostic via SK_CMD, confirming blk_owner_has_claim()
live before the diagnostic word itself was reverted: PASS, no FAIL lines.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EjXFo7mPXjUMjfJeuUUz4
2026-09-05 16:17:35 -04:00
Robert Allan JamesandClaude Sonnet 5 4d4ab59189 Build the FIRSTTOUCH overflow trigger flagged in FABRIC-2.md §I.2
The overflow-triggered migration path (a WIREBIND-attached identity's own
drive running low on space) was scoped but never built -- only the
trigger-detection call site was missing, per this section's own text.

- capsule_wirebind.c now tracks the attached blkio_dev* alongside the
  already-tracked VM id, set in try_attach() and cleared in both
  EJECT/UNCLEAN paths.
- New capsule_wirebind_overflow_idle_check(), called once per idle tick
  in repl.c right alongside blk_migration_idle_check() (same cadence):
  reads the attached drive's free/total via blk_get_device_free_blocks(),
  and if free space is below a fixed 10% threshold, extends the
  identity's pool with a one-time blk_firsttouch_claim() of 8 additional
  devblocks on Artemis's system-resident device.
- New blk_owner_has_claim(owner_fp) in block_subsystem.c answers the
  debounce question blk_firsttouch_claim()'s own doc comment had left
  open: a disk scan, not a RAM flag, so the already-extended answer
  survives reboot/reattach, matching BMAPFMT's "ownership travels with
  the block" model.

Premise checked before building (does a WIREBIND-attached drive actually
give a real free/total signal, or does it stay PROVISIONAL/raw): traced
repl.c's attach sequence and confirmed blk_subsys_attach_device() runs on
the same dev pointer right after WIREBIND, and a WIREBIND-eligible drive
is always already STFR/v2-formatted, so the signal is real. Premise held,
unlike the BAM item's overstated one.

Verified with the mandatory 3-arch QEMU acceptance (identical dictionary
hashes, no regression) plus a live logic test of blk_owner_has_claim():
a temporary TEST-OWNER-CLAIM word, run once via SK_CMD and reverted,
confirmed it correctly detects the claiming owner and rejects an
unrelated one. The low-disk-space-triggers-a-claim path itself is not
verified end-to-end -- that needs a real minted WIREBIND-user thumbdrive
with deliberately tiny capacity, out of scope for this pass; noted as
such in the FABRIC-2.md §I.2 closure note rather than overclaimed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018EjXFo7mPXjUMjfJeuUUz4
2026-09-05 16:17:19 -04:00
15 changed files with 36094 additions and 0 deletions
+29
View File
@@ -4431,6 +4431,35 @@ stale the way the original carry-forwards did.
scoped, mirroring `blk_subsys_detach_device()`'s own internal lookup, now exposed) exist
specifically so that call site is a small addition when someone picks it up, not a redesign.
**CLOSED 2026-09-05.** Premise checked before building, not trusted from this item's own
text (same discipline that caught the BAM item's overstatement): traced `repl.c`'s USB-attach
sequence and confirmed `capsule_wirebind_try_attach(&usb_blk_dev, ...)` (the regular-identity
WIREBIND path, `HOMEBLOCKS_SIG_OK` only) runs immediately before `blk_subsys_attach_device
(&usb_blk_dev)` on the same pointer — since a WIREBIND-eligible drive is already a real
STFR/v2-formatted home-blocks drive, `blk_format_or_load_disk()` takes the recognized-header
branch, not PROVISIONAL, so `blk_get_device_free_blocks()` returns real numbers by idle-check
time. Premise held. **Built**: `capsule_wirebind.c` now tracks the attached `blkio_dev*`
(`g_wirebind_attached_dev`, set alongside `g_wirebind_attached_vm_id` in `try_attach()`,
cleared in both `EJECT`/`UNCLEAN`); new `capsule_wirebind_overflow_idle_check()`, called once
per idle tick in `repl.c` right alongside `blk_migration_idle_check()` (same cadence), reads
the attached drive's free/total via `blk_get_device_free_blocks()` and, if free space is
below a fixed 10% (`WIREBIND_OVERFLOW_FREE_THRESHOLD_PCT`, "fixed first" per this project's
own standing sequencing), extends the identity's pool with a **one-time**
`blk_firsttouch_claim()` of 8 additional devblocks (`WIREBIND_OVERFLOW_CLAIM_DEVBLOCKS`) on
Artemis's system-resident device. **New `blk_owner_has_claim(owner_fp)`** (`block_subsystem.c`)
answers the debounce question this section's own doc comment on `blk_firsttouch_claim()`
had left as "a separate, not-yet-decided question" — decided on the reboot-survival axis: a
disk scan (same shape as `blk_firsttouch_claim()`'s own scan), not a RAM flag, matching
BMAPFMT's "ownership travels with the block, no centralized table" model, so the
already-extended answer survives reboot/reattach for free. **Verified**: full 3-arch QEMU
acceptance (identical dictionary hashes, no regression) plus a live logic test of
`blk_owner_has_claim()` itself — a temporary `TEST-OWNER-CLAIM` word, run once via `SK_CMD`
and reverted, confirmed it correctly detects the claiming owner and correctly rejects an
unrelated one. **Not verified end-to-end**: the actual low-disk-space-triggers-a-claim path
itself, which needs a real minted WIREBIND-user thumbdrive with deliberately tiny capacity to
reproduce naturally — out of scope for this pass; the plumbing exercises its no-op branch
every idle tick with no crash, but the "drive actually runs low" branch is unexercised.
**Also left open, a real correctness gap, not swept under**: `blk_meta_t`'s `owner_fp`/
`BLK_FLAG_CLAIMED` (BMAPFMT's distributed ownership) and the pre-existing, separate BAM
(`blk_bam_entry_t{allocated,dirty}`, the generic free/allocated bitmap `blk_allocate()`/
+21
View File
@@ -444,6 +444,27 @@ int blk_get_first_disk_range(uint32_t *out_start_lbn, uint32_t *out_count);
*/
int blk_firsttouch_claim(const uint8_t owner_fp[8], uint32_t count, uint32_t *out_chain_head);
/* blk_owner_has_claim - FABRIC-2.md §I.2's own "an existing claim is a
* separate, not-yet-decided question" (see blk_firsttouch_claim()'s doc
* comment above), decided 2026-09-05 for the overflow-trigger call site
* (capsule_wirebind.c): answered by a disk scan, not a RAM flag, matching
* BMAPFMT's own "ownership travels with the block, no centralized table"
* model -- the answer survives a reboot/reattach for free, the same way
* blk_firsttouch_claim()'s own free/claimed scan already does.
*
* One linear scan over blk_get_first_disk_range()'s representative LBNs
* (same shape as blk_firsttouch_claim()'s own scan); returns as soon as
* any devblock's blk_meta_t has BLK_FLAG_CLAIMED set and owner_fp equal
* to the argument.
*
* @param owner_fp 8-byte fingerprint, same convention as
* blk_firsttouch_claim()'s own owner_fp argument.
* @return 1 if owner_fp already owns at least one claimed devblock, 0 if
* not (including "no disk-backed device attached" -- nothing to
* own in that case).
*/
int blk_owner_has_claim(const uint8_t owner_fp[8]);
/* blk_meta_relocate_devblock - the real migration primitive (FABRIC-2.md
* §I.2, migration state machine, 2026-09-04): moves one devblock's full
* content and blk_meta_t ownership from home_devblock to target_devblock.
+23
View File
@@ -122,6 +122,29 @@ void capsule_wirebind_unclean_detach(void);
*/
const char *capsule_wirebind_attached_username(void);
/**
* capsule_wirebind_overflow_idle_check - FABRIC-2.md §I.2's own "overflow
* trigger," decided and built 2026-09-05. Called once per idle tick
* (sk_repl_idle(), repl.c, alongside blk_migration_idle_check() -- same
* ~1 Hz cadence), same as that function's own convention.
*
* No-op if nothing is attached via WIREBIND. Otherwise reads the attached
* drive's own free/total via blk_get_device_free_blocks() (real numbers:
* a WIREBIND-attached drive is always HOMEBLOCKS_SIG_OK, i.e. already
* STFR/v2-formatted, by the time blk_subsys_attach_device() runs on the
* same dev pointer right after WIREBIND itself -- not PROVISIONAL, not
* raw). If free space is below a fixed threshold AND the attached
* identity does not already own a claim (blk_owner_has_claim() -- a disk
* scan, not a RAM flag, so this decision survives reboot/reattach for
* free), claims a fixed number of additional devblocks on Artemis's own
* device via blk_firsttouch_claim() -- a one-time-per-identity extension,
* not a growth loop, deliberately: this does not free space on the
* user's own drive, it only extends their pool onto system-resident
* space, so re-claiming every tick once already extended would walk
* Artemis's device to exhaustion for no benefit.
*/
void capsule_wirebind_overflow_idle_check(void);
#endif /* __STARKERNEL__ */
#endif /* STARKERNEL_CAPSULE_WIREBIND_H */
Binary file not shown.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+25
View File
@@ -1481,6 +1481,31 @@ int blk_firsttouch_claim(const uint8_t owner_fp[8], uint32_t count, uint32_t *ou
return BLK_OK;
}
/* blk_owner_has_claim - FABRIC-2.md §I.2, 2026-09-05. Disk-scan answer to
* "does owner_fp already own a claim," per the decision recorded in
* block_subsystem.h: matching BLK_FLAG_CLAIMED devblock, not a RAM flag. */
int blk_owner_has_claim(const uint8_t owner_fp[8]) {
if (!owner_fp) return 0;
blk_dev_slot_t *slot = first_disk_slot();
if (!slot) return 0;
for (uint32_t lbn = slot->start_lbn;
lbn < slot->start_lbn + slot->user_blocks;
lbn++) {
uint32_t rel_pbn = lbn_to_slot_pbn(slot, lbn);
if (slot_pbn_pack_offset(rel_pbn) != 0) continue;
blk_meta_t meta;
if (blk_get_meta(lbn, &meta) != BLK_OK) continue;
if ((meta.flags & BLK_FLAG_CLAIMED) &&
memcmp(meta.owner_fp, owner_fp, 8) == 0) {
return 1;
}
}
return 0;
}
int blk_meta_relocate_devblock(uint32_t home_devblock, uint32_t target_devblock) {
if (home_devblock == target_devblock) return BLK_EINVAL;
+57
View File
@@ -39,6 +39,11 @@ static int g_wirebind_attached_valid = 0;
* user_vm_name ("<username>~user"), not the bare form the (user) prompt
* segment wants (FABRIC-2.md §I.1/4.4s). */
static char g_wirebind_attached_username[USER_IDENTITY_USERNAME_MAX] = {0};
/* FABRIC-2.md §I.2 overflow trigger, 2026-09-05: the attached drive's own
* blkio_dev pointer, tracked alongside the two fields above so
* capsule_wirebind_overflow_idle_check() can query its free space later
* without a new attach-time argument threaded through the idle loop. */
static struct blkio_dev *g_wirebind_attached_dev = (struct blkio_dev *) 0;
/* WIREBIND_CERT_MAX_DEVBLOCKS: a sane upper bound on how much cert
* content this reads, independent of whatever sig->cert_devblocks
@@ -47,6 +52,17 @@ static char g_wirebind_attached_username[USER_IDENTITY_USERNAME_MAX] = {0};
* generous headroom, not a real constraint. */
#define WIREBIND_CERT_MAX_DEVBLOCKS 4u
/* FABRIC-2.md §I.2 overflow trigger, 2026-09-05: fixed constants, "fixed
* first" per this project's own standing sequencing (MIGRATION_WEAR_
* THRESHOLD, ZUSE_SESSION_TTL_SECONDS -- adaptive only after a real,
* measured baseline exists, not from day one). A single DoE-tunable knob
* apiece, not yet wired to Kconfig -- revisit once real usage data exists.
* 10% is a conservative first guess (extend well before actually full);
* 8 devblocks (24 Forth blocks, ~24 KiB) is a modest first extension, not
* a large land-grab. */
#define WIREBIND_OVERFLOW_FREE_THRESHOLD_PCT 10u
#define WIREBIND_OVERFLOW_CLAIM_DEVBLOCKS 8u
/* Read exactly one devblock (4096 bytes) at devblock offset `devblock`
* -- same convention capsule_runcap.c/capsule_mint.c already use. */
static int read_devblock(struct blkio_dev *dev, uint32_t devblock, uint8_t *buf4096) {
@@ -184,6 +200,7 @@ void capsule_wirebind_try_attach(struct blkio_dev *dev,
* actually owns block-subsystem state). */
g_wirebind_attached_vm_id = user_id;
g_wirebind_attached_valid = 1;
g_wirebind_attached_dev = dev;
memcpy(g_wirebind_attached_username, username, sizeof(g_wirebind_attached_username));
/* Register the pairing in the console's own routing table, index 3
@@ -233,6 +250,7 @@ int capsule_wirebind_eject(void) {
capsule_vm_kill(entry.name);
g_wirebind_attached_valid = 0;
g_wirebind_attached_dev = (struct blkio_dev *) 0;
g_wirebind_attached_username[0] = '\0';
console_puts("EJECT: ");
@@ -254,6 +272,7 @@ void capsule_wirebind_unclean_detach(void) {
capsule_vm_kill(entry.name);
g_wirebind_attached_valid = 0;
g_wirebind_attached_dev = (struct blkio_dev *) 0;
g_wirebind_attached_username[0] = '\0';
console_puts("WIREBIND: ");
@@ -265,3 +284,41 @@ const char *capsule_wirebind_attached_username(void) {
if (!g_wirebind_attached_valid) return (const char *)0;
return g_wirebind_attached_username;
}
void capsule_wirebind_overflow_idle_check(void) {
if (!g_wirebind_attached_valid || !g_wirebind_attached_dev) return;
VMRegistryEntry entry;
if (capsule_vm_registry_get(g_wirebind_attached_vm_id, &entry) != 0 ||
entry.state != VM_STATE_LIVE || !entry.vm_ptr) {
return;
}
uint64_t free_blocks, total_blocks;
if (blk_get_device_free_blocks(g_wirebind_attached_dev, &free_blocks, &total_blocks)
!= BLK_OK || total_blocks == 0) {
return;
}
if (free_blocks * 100u >= total_blocks * WIREBIND_OVERFLOW_FREE_THRESHOLD_PCT) {
return; /* plenty of room left on the drive itself */
}
uint8_t owner_fp[8];
memcpy(owner_fp, ((VM *)entry.vm_ptr)->identity.owner_pubkey, sizeof(owner_fp));
if (blk_owner_has_claim(owner_fp)) {
return; /* already extended once -- not a growth loop, see header doc */
}
uint32_t chain_head;
if (blk_firsttouch_claim(owner_fp, WIREBIND_OVERFLOW_CLAIM_DEVBLOCKS, &chain_head)
!= BLK_OK) {
console_println("WIREBIND: overflow trigger fired but Artemis has no room to extend into");
return;
}
console_puts("WIREBIND: ");
console_puts(g_wirebind_attached_username);
console_println(" running low on drive space -- extended onto system-resident storage");
}
+7
View File
@@ -368,6 +368,13 @@ static void sk_repl_idle(VM *active_vm)
* migration, needs a call site threaded from WIREBIND). */
blk_migration_idle_check();
/* FABRIC-2.md §I.2's own overflow trigger, closed 2026-09-05: the
* call site named above, now built. Same cadence, same idle-tick
* neighbor -- see capsule_wirebind_overflow_idle_check()'s own doc
* comment for what it does and why it's a one-time extension, not a
* growth loop. */
capsule_wirebind_overflow_idle_check();
/* FABRIC-2.md Phase C (2026-08-28): distributed messaging pump. Every
* live VM except Hera herself now owns its own MSG-ARENA/CH-ARENA and
* MSG-TICK word (see capsules/common/messaging.4th) instead of only