FABRIC-2.md: §12 Q5 eight-loop interference analysis -- found a real §22.4 violation
Traced every loop's actual firing cadence from source. Headline finding: the fleet-capacity loop (vm_physics_heartbeat_tick, the exact mechanism §22.4 cites as precedent) shares a global counter fed by every live VM, so with Tripod's real multi-VM topology it can fire faster in wall-clock terms than any single VM's own heat-inference loop -- the opposite of §22.4's required ordering. STADIUM_CAPACITY_TICK, the Kconfig symbol §22.4 specified as the fix, exists but is never read anywhere. Reported, not fixed; left open for Captain Bob's call.
This commit is contained in:
+61
@@ -238,6 +238,67 @@ and recorded.
|
||||
- [ ] **§12 Q5 — the full eight-loop interference analysis has not been done.** Its stated
|
||||
blocker ("no real time base on all three ISAs") is gone — Phase 0 completed that — so this
|
||||
is now unblocked and simply never picked back up.
|
||||
|
||||
> **ANALYSIS DONE 2026-08-13 — found a real violation of §22.4's required ordering, left
|
||||
> open pending Captain Bob's call on how to handle it.** Traced every loop's actual firing
|
||||
> cadence from source (`src/starkernel/vm/vm_core.c`, `vm_runtime.c`,
|
||||
> `capsule_vm_physics.c`), in execution counts, not the nominal per-loop constant names:
|
||||
>
|
||||
> - **Cadence 1 execution:** Loop #1 (heat), Loop #2 (rolling-window record), Loop #4
|
||||
> (pipelining) — every word dispatch.
|
||||
> - **Cadence `HEARTBEAT_CHECK_FREQUENCY` = 256 executions:** Loop #3 (background decay,
|
||||
> batched), `rolling_window_service()`, `dict_adaptive_optimization_pass()`, L8 Jacquard
|
||||
> vote, fleet-capacity-counter increment — all five in the same `vm_heartbeat_run_cycle()`
|
||||
> call, zero separation between them.
|
||||
> - **Cadence `HEARTBEAT_INFERENCE_FREQUENCY` ticks × 256 = 256,000 executions:** Loop #5
|
||||
> (window width) + Loop #6 (decay slope) + Loop #7 (adaptive heartrate) — all three
|
||||
> merged into one `vm_tick_inference_engine()` call, zero separation between them.
|
||||
>
|
||||
> Two real findings, not just tidiness:
|
||||
>
|
||||
> 1. **The fleet-capacity loop can fire *faster* than a VM's own heat loop, not slower —
|
||||
> the opposite of §22.4's "capacity must be the slower loop."** §22.4 cites
|
||||
> `vm_physics_heartbeat_tick()` (`capsule_vm_physics.c:454-459`) by name as the existing
|
||||
> precedent for the required 1000:1 separation. But that function is called from *every*
|
||||
> live VM's own `vm_heartbeat_run_cycle()` (`vm_runtime.c:502`), incrementing one shared
|
||||
> global `fleet_heartbeat_tick_count`, and fires `vm_physics_tick()` once that shared
|
||||
> counter — fed by all VMs at once — reaches `HEARTBEAT_INFERENCE_FREQUENCY` (1000). A
|
||||
> lone VM needs 1000 of *its own* 256-execution cycles to trip its own inference gate;
|
||||
> with `STADIUM_MAX_VM_COUNT`'s real default of 4 (Hera + 2×Hermes + Artemis, Tripod's
|
||||
> actual topology), the shared fleet counter can reach the same threshold up to ~4×
|
||||
> sooner in wall-clock terms. So in a live multi-VM fleet, capacity arbitration can run
|
||||
> *more* often in real time than any individual VM's own heat-inference loop, not less —
|
||||
> exactly the ordering §22.4 calls "required, not preferred" because getting it backwards
|
||||
> "produces a system that thrashes while every individual rule looks correct."
|
||||
> 2. **The fix §22.4 already specified was never actually built.** §22.4's own resolution
|
||||
> text says the capacity-tick should get "its own named constant rather than literally
|
||||
> sharing `HEARTBEAT_INFERENCE_FREQUENCY`... named and made a Kconfig symbol at
|
||||
> implementation time (item 3.1)." `STADIUM_CAPACITY_TICK` exists in `Kconfig.kernel`
|
||||
> exactly as promised, default 1000 matching the cited precedent — but repo-wide grep
|
||||
> confirms it is never read by any code path. Its only other appearance is a
|
||||
> compile-time static assertion in `include/starkernel/vm/stadium.h:118` checking it's
|
||||
> `> 0`, which gates nothing at runtime. `vm_physics_heartbeat_tick()` still literally
|
||||
> shares `HEARTBEAT_INFERENCE_FREQUENCY`, i.e. the code is still in the
|
||||
> *pre-implementation* state §22.4 described as its starting precedent, not the resolved
|
||||
> design it specified.
|
||||
>
|
||||
> Also found in passing, minor and not a correctness issue: `vm_tick()`'s own header
|
||||
> comment (`vm_runtime.c:104`, "Aggregates all periodic optimization tasks (Loop #3 and
|
||||
> Loop #5) into one place") is stale — Loop #3 is not called inside `vm_tick()`, it's
|
||||
> called separately from `vm_heartbeat_run_cycle()` on the faster 256-execution cadence,
|
||||
> not the 256,000-execution one `vm_tick()` itself gates.
|
||||
>
|
||||
> Where this leaves Q5: within a single cadence tier (the 256-execution cluster, or the
|
||||
> 256,000-execution cluster), several nominally-distinct loops share one gate with zero
|
||||
> separation between them — apparently intentional unification (Phase 2's "Unified
|
||||
> Inference Engine" merged #5/#6, L8 explicitly reads #1–#7's latest outputs each vote),
|
||||
> not obviously a bug. *Between* tiers, separation is comfortably past the order-of-magnitude
|
||||
> minimum (256:1 and 1000:1). The one place separation is required by name and is not
|
||||
> actually present is the heat/capacity pair finding #1 above — that's the concrete,
|
||||
> verified answer to "the risk is interference." **Left open, not fixed**, per this
|
||||
> document's discipline — whether to wire `STADIUM_CAPACITY_TICK` in for real (giving Hera
|
||||
> her own slower cadence independent of per-VM tick counts) or something else is Captain
|
||||
> Bob's call, not made here.
|
||||
- [ ] **§17.4 — the framebuffer utility's internal heat/decay dynamics are undesigned.**
|
||||
Explicitly "Open, deferred": not a Stadium patron, but what physics (if any) governs it
|
||||
internally was never designed. Not blocking anything.
|
||||
|
||||
Reference in New Issue
Block a user