Publish path, no dispatch -- FABRIC-3.6.md task 3.3
sk_hermes_publish() allocates one SkHermesMessage per channel member (heat-cost ruling 2026-09-21: one message per subscriber, funded by the publisher's own reservoir) and enqueues each onto a new per-subscriber SkHermesPendingQueue -- found-or-created lazily by vm_id, sized from stadium_max_vm_count() like the channel/switch tables. Best-effort across subscribers: a failed allocation or full queue skips and rolls back just that one subscriber, not the whole publish -- the natural reading of "ledger and stadium_conserved() hold across N publishes to M subscribers" (the task's own check), not a separate ruling. Dispatches nothing -- sk_hermes_pending_count()/peek()/pop() are the read/drain primitives task 3.4's real checkpoint-driven drain will build on; this task's own self-test uses them directly since no checkpoint hook exists yet. Verified live on all three architectures: pending-queue table sized 50/202/50 slots (tracking the channel table's own per-arch sizing), a synthetic publish self-test (2 publishes to 3 subscribers) confirms exact per-subscriber delivery counts, and ledger/stadium_conserved() invariants hold both mid-publish and after manually draining every queue back to baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a4afdfa591
commit
1f6343bc03
+27
-1
@@ -830,12 +830,38 @@ ruling]** cannot be written precisely until Captain Bob settles the named sub-it
|
||||
architectures. `dict_hash` for Hermes (`0xc95ef2d92fa0781f`) and Hestia
|
||||
(`0xfbde9fe105fd3b3d`) identical across all three architectures, unmoved from task 3.1's
|
||||
values (this task touches no capsule).
|
||||
- [ ] **3.3** — **Publish path, no dispatch** (§XLIII.3). Publish allocates via
|
||||
- [x] **3.3** — **Publish path, no dispatch** (§XLIII.3). Publish allocates via
|
||||
`sk_hermes_alloc()`, enqueues onto each subscriber's own pending queue, and records the
|
||||
fact; it dispatches nothing. Self-test only. *Check:* ledger audit and
|
||||
`stadium_conserved()` hold across N publishes to M subscribers (heat cost per subscriber
|
||||
is a design point to settle **before** writing this: one message per subscriber, or one
|
||||
shared message with a reference count — **[needs ruling]**).
|
||||
2026-09-22 · `logs/20260922-002857/amd64/`, `logs/20260922-003404/aarch64/`,
|
||||
`logs/20260922-003922/riscv64/` — all three reach `[zuse@Hera] ok>`, zero `UNKNOWN WORD`,
|
||||
`mkcapsule --lint capsules/` clean (38 files, 0 violations, unchanged -- no capsule
|
||||
touched). Heat cost ruled 2026-09-21 (one message per subscriber); `sk_hermes_publish()`
|
||||
allocates one `SkHermesMessage` per channel member via `sk_hermes_alloc()` (funded by the
|
||||
publisher's reservoir) and enqueues each onto a new per-subscriber `SkHermesPendingQueue`
|
||||
(found-or-created lazily by `vm_id`, same shape as `stadium.c`'s `quota_slot_for_vm()` --
|
||||
not pre-populated at birth like channel membership is, since not every VM ever receives a
|
||||
message). Table sized from `stadium_max_vm_count()`, same pattern as tasks 3.1/3.2.
|
||||
Best-effort, not atomic across subscribers -- a failed allocation or full queue skips just
|
||||
that one subscriber and rolls back its own allocation; not a separate ruling, the natural
|
||||
reading of the task's own check (ledger/`stadium_conserved()` invariants hold under partial
|
||||
delivery too), documented as such in the header. Added `sk_hermes_pending_count()`/
|
||||
`_peek()`/`_pop()` as the read/drain primitives task 3.4's real checkpoint-driven drain
|
||||
will build on -- this task's own self-test uses them directly for cleanup since no
|
||||
checkpoint hook exists yet. New console line confirmed live on all three architectures:
|
||||
`Kernel-Hermes: N pending-queue slots` (**50 amd64, 202 aarch64, 50 riscv64** -- tracks
|
||||
the channel/switch-signal tables' own per-arch sizing exactly). Self-test (synthetic
|
||||
publisher lo=7, three synthetic subscribers lo=8/9/10, N=2 publishes to a 3-member
|
||||
synthetic channel) confirms `sk_hermes_publish()` returns 3 each time, each subscriber's
|
||||
queue holds exactly 2 afterward, ledger audit and `stadium_conserved(publisher)` hold
|
||||
mid-publish, then confirms the same invariants return to baseline after draining every
|
||||
queue by hand (`pending_peek()`/`release()`/`pop()`) -- `PASS` on all three architectures.
|
||||
`dict_hash` for Hermes (`0xc95ef2d92fa0781f`) and Hestia (`0xfbde9fe105fd3b3d`) identical
|
||||
across all three architectures, unmoved from tasks 3.1/3.2's values (this task touches no
|
||||
capsule).
|
||||
- [ ] **3.4** — **Drain at the outermost checkpoint** (§XLIII.3–.5). Reuse
|
||||
`sk_vm_at_outermost_interpret()`; one message per checkpoint **[needs ruling 3.0e]**.
|
||||
*Check:* a nested interpret does not drain; a queued payload is interpreted exactly once at
|
||||
|
||||
Reference in New Issue
Block a user