Stage D: CONSOLE-CMD-EVENT real cutover -- FABRIC-3.6.md task 3.9
Send-side cutover: sk_repl_dispatch_line()'s FORTH-string
"CONSOLE-CMD-EVENT 0 3 S\" ...\" 0 MSG-SEND" interpret is replaced with
a direct sk_hermes_send_one() call (SK_HERMES_MSG_TYPE_CONSOLE_CMD,
kernel_hermes.h, deliberately reusing CONSOLE-CMD-EVENT's own value 7,
same partition-rule reasoning as task 3.8's BLK-ATTACH-EVENT cutover).
Real finding along the way: kernel-Hermes's drain only ever runs as a
side effect of vm_interpret() being called on the target VM. Task
3.8's target (Hera) is always being interpreted via the interactive
REPL loop; task 3.9's target is a WIREBIND identity's own ~user VM, a
passive receiver nothing else drives. The existing idle-loop pump only
ticked VMs with the old FORTH MSG-TICK word ACL-allowed -- a VM minted
with the STD79-lockdown personality never has it, so the pump silently
skipped it forever and queued messages never delivered. Fixed by
adding an unconditional, direct sk_hermes_drain_checkpoint() call in
the same pump loop, independent of the MSG-TICK gate.
Verified live on all three architectures: WIREBIND-attach a real
identity, USE into it, type a plain console line, confirm the Stage D
evidence line and correct relayed execution result. Zero UNKNOWN WORD,
dict_hash identical across all three ISAs and matching task 3.8's own
baseline. The FABRIC-3.md-documented USE/BINDSTEP crash did not
reproduce in any of these live sessions (recorded as a finding, not
chased further).
Depends on the zuse_root_pubkey_known fix already landed in ac4d431 --
without it, WIREBIND cannot attach any identity on a fresh boot at
all, which blocked this task's own verification until found and fixed
separately.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ac4d431aee
commit
3975dc61cd
+78
-9
@@ -816,6 +816,30 @@ static void sk_repl_idle(VM *active_vm)
|
||||
if (capsule_vm_registry_get_by_index(i, &ent) == 0 &&
|
||||
ent.state == VM_STATE_LIVE &&
|
||||
ent.vm_ptr != (void *)mama) {
|
||||
/* FABRIC-3.6.md task 3.9, found live 2026-09-22: kernel-
|
||||
* Hermes's own drain (sk_hermes_drain_checkpoint(), task
|
||||
* 3.4) only ever runs as a side effect of vm_interpret()
|
||||
* being called ON the target VM (vm_core.c's own outermost-
|
||||
* interpret checkpoint hook) -- it has nothing to do with
|
||||
* the old FORTH MSG-TICK word this loop was built around.
|
||||
* A WIREBIND identity minted with the STD79-lockdown
|
||||
* personality (MINT_PERSONALITY_STD79_LOCKDOWN) never loads
|
||||
* common:messaging.4th, so the MSG-TICK gate just below
|
||||
* always skips it -- meaning it never got an interpret
|
||||
* tick at all, meaning a CONSOLE-CMD-EVENT queued for it
|
||||
* sat in its pending queue forever, silently. Confirmed
|
||||
* live: sk_hermes_send_one() returned 0 (queued OK) but no
|
||||
* drain ever ran. Called unconditionally here, independent
|
||||
* of the MSG-TICK check below -- kernel-Hermes doesn't need
|
||||
* a FORTH word to exist, it just needs its target VM to get
|
||||
* an outermost interpret call periodically. Direct C call,
|
||||
* not routed through VM-EXEC/vm_interpret: drain_checkpoint
|
||||
* already saves/restores the target's own interpret state
|
||||
* internally (kernel_main.c's own self-test calls it the
|
||||
* same standalone way), so no vm_interpret() wrapper is
|
||||
* needed to reach it from here. */
|
||||
(void)sk_hermes_drain_checkpoint((VM *)ent.vm_ptr);
|
||||
|
||||
/* FABRIC-3.md, 2026-09-09: a per-VM flag (e.g. "this one is
|
||||
* std79-locked") doesn't generalize -- any VM whose own
|
||||
* dictionary lacks MSG-TICK, for whatever reason (never
|
||||
@@ -1343,6 +1367,27 @@ static int sk_repl_line_calls_use(const char *input)
|
||||
return (len == 3) || (input[len - 4] == ' ' || input[len - 4] == '\t');
|
||||
}
|
||||
|
||||
/* FABRIC-3.6.md task 3.9 -- static, not stack-local, for the same reason
|
||||
* g_kh_blk_attach_buf (task 3.8) is: sk_hermes_send_one() stores
|
||||
* payload_addr out-of-line and the caller must keep it alive until
|
||||
* drained. Sized to the largest single payload kernel-Hermes will ever
|
||||
* accept (SK_HERMES_CHUNK_MAX_PAYLOAD, task 3.5's one-block bound) --
|
||||
* console lines up to INPUT_BUFFER_SIZE-1 (1024) content bytes are
|
||||
* silently capped to SK_HERMES_CHUNK_MAX_PAYLOAD-1 (1023) to leave room
|
||||
* for the NUL terminator sk_hermes_drain_checkpoint() requires; chunking
|
||||
* a console line across multiple messages is out of this task's scope
|
||||
* (task 3.5 built the primitives, not a sender for this use) and the cap
|
||||
* is not expected to be reached by ordinary interactive typing. Only one
|
||||
* console-proxy session exists today (console.c's own singleton, per
|
||||
* memory project_multiseat_console_idea) so the single shared buffer
|
||||
* carries the same payload-aliasing defect g_kh_blk_attach_buf has
|
||||
* (FABRIC-3.6.md task 3.8's write-up wrongly called this shape benign;
|
||||
* corrected in the findings log, entry "found while starting task 3.9",
|
||||
* once task 3.8's own defect was found). Fix deferred: Captain Bob
|
||||
* ruled 2026-09-22 to land task 3.9's send-side cutover first and fix
|
||||
* the aliasing separately. */
|
||||
static char g_kh_console_cmd_buf[SK_HERMES_CHUNK_MAX_PAYLOAD];
|
||||
|
||||
static void sk_repl_dispatch_line(VM *vm, const char *input)
|
||||
{
|
||||
/* H1 reentrancy guard: while this dispatched line executes on Hera
|
||||
@@ -1376,16 +1421,40 @@ static void sk_repl_dispatch_line(VM *vm, const char *input)
|
||||
console_println("console: line contains '\"' -- can't relay "
|
||||
"as a message safely yet, interpreting directly");
|
||||
} else {
|
||||
char cmd[INPUT_BUFFER_SIZE + 64];
|
||||
/* to-index 3: the fixed convention this console's own
|
||||
* VM-NAME-REG entry for its paired user VM uses (set
|
||||
* once at pairing time -- see the pairing word). */
|
||||
int n = snprintf(cmd, sizeof(cmd),
|
||||
"CONSOLE-CMD-EVENT 0 3 S\" %s\" 0 MSG-SEND", input);
|
||||
if (n > 0 && (size_t)n < sizeof(cmd)) {
|
||||
vm_interpret(vm, cmd);
|
||||
goto out;
|
||||
/* FABRIC-3.6.md task 3.9 (Stage D, SXXXIV.2/.3):
|
||||
* CONSOLE-CMD-EVENT's real cutover -- the FORTH
|
||||
* "CONSOLE-CMD-EVENT 0 3 S\" ...\" 0 MSG-SEND" string
|
||||
* interpret is gone; this now calls kernel-Hermes
|
||||
* directly. `paired.vm_id` (just resolved above) is
|
||||
* the real target VMUuid -- no name-index translation
|
||||
* needed, unlike the FORTH convention's local "index
|
||||
* 3" hack. `from` is the console-proxy VM's own real
|
||||
* identity (`vm->stadium_vm_id`), not the FORTH
|
||||
* convention's hardcoded "0" (which read as Hera in
|
||||
* every console-proxy's shared VM-NAMES-INIT table,
|
||||
* regardless of which console actually sent it) --
|
||||
* more correct provenance, a deliberate refinement
|
||||
* task 3.9 makes possible, not a silent behavior
|
||||
* change: the receiving side never read `from` for
|
||||
* anything but bookkeeping. The `"` guard above is
|
||||
* kept even though kernel-Hermes's payload is a raw
|
||||
* pointer+length, not a FORTH string literal, and no
|
||||
* longer needs it -- removing a documented v1
|
||||
* limitation is its own decision, not a side effect
|
||||
* of this one (per advisor() review). */
|
||||
size_t ilen = strlen(input);
|
||||
if (ilen >= SK_HERMES_CHUNK_MAX_PAYLOAD)
|
||||
ilen = SK_HERMES_CHUNK_MAX_PAYLOAD - 1; /* leave room for the NUL --
|
||||
* see g_kh_console_cmd_buf's
|
||||
* own doc comment */
|
||||
memcpy(g_kh_console_cmd_buf, input, ilen);
|
||||
g_kh_console_cmd_buf[ilen] = '\0';
|
||||
if (sk_hermes_send_one(vm->stadium_vm_id, paired.vm_id,
|
||||
SK_HERMES_MSG_TYPE_CONSOLE_CMD, 0,
|
||||
g_kh_console_cmd_buf, (uint32_t)(ilen + 1)) != 0) {
|
||||
log_message(LOG_ERROR, "console: kernel-Hermes refused CONSOLE-CMD-EVENT send");
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#ifdef __STARKERNEL__
|
||||
|
||||
#include <string.h>
|
||||
#include "freestanding/stdio.h" /* task 3.9 evidence print -- snprintf() */
|
||||
#include "starkernel/vm/kernel_hermes.h"
|
||||
#include "starkernel/vm/stadium.h"
|
||||
#include "starkernel/q48_16.h"
|
||||
@@ -586,6 +587,31 @@ int sk_hermes_drain_checkpoint(VM *vm) {
|
||||
saved_error = vm->error;
|
||||
saved_abort = vm->abort_requested;
|
||||
|
||||
/* FABRIC-3.6.md task 3.9 evidence: CONSOLE-CMD-EVENT has no fixed
|
||||
* FORTH handler word to hang a print on (task 3.8's BLK-ATTACH-ACK
|
||||
* did) -- its payload is an arbitrary console line, interpreted
|
||||
* as-is below. So the evidence line lives here instead, gated on
|
||||
* msg->type, printed before vm_interpret() runs while this
|
||||
* message's heat is still held (release()/pop() are further down
|
||||
* in this same function) -- the same mid-hold-instant evidence task
|
||||
* 3.8 used, same honest limit: evidence for mid-hold, not
|
||||
* post-release. console_println, not log_message() (confirmed
|
||||
* invisible in this build's serial capture, task 3.8's own
|
||||
* finding); fires once per relayed console line, not per word. */
|
||||
if (msg->type == SK_HERMES_MSG_TYPE_CONSOLE_CMD) {
|
||||
uint64_t held, pulled, returned, consumed;
|
||||
char line[160];
|
||||
int conserved = stadium_conserved(self);
|
||||
sk_hermes_ledger(&held, &pulled, &returned, &consumed);
|
||||
snprintf(line, sizeof(line),
|
||||
"Kernel-Hermes CONSOLE-CMD-EVENT (real, Stage D): ledger held=%llu "
|
||||
"pulled=%llu returned=%llu consumed=%llu stadium_conserved(self)=%s",
|
||||
(unsigned long long)held, (unsigned long long)pulled,
|
||||
(unsigned long long)returned, (unsigned long long)consumed,
|
||||
conserved ? "true" : "FALSE");
|
||||
console_println(line);
|
||||
}
|
||||
|
||||
vm->mode = MODE_INTERPRET; /* a payload is never compiled into whatever
|
||||
* the enclosing context was mid-defining */
|
||||
vm_interpret(vm, (const char *)msg->payload_addr);
|
||||
|
||||
Reference in New Issue
Block a user