Channel-open policy hook -- FABRIC-3.6.md task 3.7

Added HERMES-CHANNEL-OPEN? ( req-hi req-lo -- allow? ) at
capsules/ACL.4th block 4008 (default: approve everything) -- the one
word policy authors edit. sk_hermes_channel_open_policy(VM*, VMUuid)
(kernel_hermes.h/.c) is the C-side query that calls it via plain
word-dispatch against the target VM's own dictionary/stack, never
vm_interpret() (avoids task 3.4's input-buffer cursor hazard entirely)
and never decides the answer itself. Fails closed: no policy word,
a policy error, or stack underflow all deny, matching CLAUDE.md's
posture that absence of policy must never mean "always allow."

Two real bugs found and fixed before this was called done:
missing current_executing_entry assignment before calling the word's
func pointer (colon words silently no-op without it, vm_core.c:730 --
no crash, just a wrong answer); and a second FAIL with debug
instrumentation still in place whose precise cause isn't
reconstructable, since no intermediate commit exists for that attempt.

Self-test proves the task's check four ways against the same
unchanged C function: default approve, live redefinition to deny
(zero C change), restore, and a VM with no ACL.4th loaded at all
(fail closed). A fifth check wires the result into task 3.6's
sk_hermes_channel_respond() end to end: a denied policy produces a
NACK and no channel, ledger/stadium_conserved() holding throughout.

Scope, per Captain Bob's ruling: closes with the query built and
proven; sk_hermes_channel_respond() still takes a caller-supplied
approved bool rather than calling the policy internally. Wiring a
real channel-open call site to only this query is deferred to
whichever later task first needs a live decision.

dict_hash identical across amd64/aarch64/riscv64 for every VM, zero
UNKNOWN WORD, mkcapsule --lint clean (38 files, 0 violations).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-09-22 09:08:48 -04:00
co-authored by Claude Sonnet 5
parent 205a49ecd0
commit f37aa0fb17
11 changed files with 46618 additions and 12 deletions
+43
View File
@@ -727,6 +727,49 @@ int sk_hermes_channel_respond(VMUuid target, VMUuid requester, int approved);
* @return 0 on success, -1 on refusal. */
int sk_hermes_channel_close(VMUuid closer, int channel_id);
/*
* Channel-open policy hook (FABRIC-3.6.md task 3.7, B1, ruling 3.0b:
* "kernel-Hermes asks ACL.4th, never decides in C, never gates on
* zuse_session"). sk_hermes_channel_open_policy() is the CALL SITE task
* 3.6's own doc comment named as replacing sk_hermes_channel_respond()'s
* caller-supplied `approved` bool with a real query -- this function IS
* that query; sk_hermes_channel_respond()'s own signature stays
* unchanged, as promised.
*
* Deliberately NOT vm_interpret() (contrast task 3.4's drain, which
* genuinely needs to run arbitrary payload text): HERMES-CHANNEL-OPEN?
* is a FIXED, known word name, so this uses the plain-word-dispatch
* pattern FABRIC-3.md SXX already established for Hera's own MSG-TICK
* self-drain ("a plain word dispatch in her own dictionary, not a
* VM-EXEC dispatch into anyone else's input buffer -- no reentrancy
* risk") -- vm_find_word() + calling the entry's own func pointer
* directly, with the requester passed via the target's own data stack.
* This touches neither target_vm->input_buffer nor input_pos, so it
* carries none of task 3.4's cursor-preservation hazard; it DOES still
* touch target_vm's own data stack (dsp), which is the correct and
* expected thing for a word call to do. Calling this from within a live
* checkpoint on a VM that is itself mid-dispatch is deferred, undecided
* territory -- this task (like every Phase 3 task before Stage C/3.8+)
* is self-test only, not wired into any real checkpoint yet.
*
* Fails CLOSED, not open: if target_vm has no HERMES-CHANNEL-OPEN? word
* (e.g. ACL.4th was never loaded into it) or the word itself sets
* target_vm->error or leaves too few stack items, this returns 0
* (denied) -- absence of policy must never silently mean "always
* allow" (CLAUDE.md's own posture on ACL policy). A policy-word bug's
* own error state is cleared on target_vm before returning, so a
* broken policy word cannot leak an error into whatever else target_vm
* is doing.
*
* @param target_vm The VM being asked -- its own dictionary is
* consulted, its own data stack is used for the call.
* @param requester Passed to HERMES-CHANNEL-OPEN? as (hi, lo) on
* target_vm's own stack.
* @return 1 if HERMES-CHANNEL-OPEN? approved (returned a nonzero top of
* stack), 0 otherwise (denied, missing, or errored).
*/
int sk_hermes_channel_open_policy(VM *target_vm, VMUuid requester);
#endif /* __STARKERNEL__ */
#endif /* STARKERNEL_VM_KERNEL_HERMES_H */