321 lines
17 KiB
Markdown
321 lines
17 KiB
Markdown
# Work Log: July 5, 2026
|
||
## K-PUSH Dictionary Shadowing Fix → Dynamic VM Fleet Physics Design & Implementation
|
||
|
||
**Branch:** `lithosananke`
|
||
**Last commit this session:** `7a1383a0` — "docs: note future BIRTH-permission question in out-of-scope section"
|
||
**Tree state at session end:** clean, fully pushed to `origin/lithosananke`
|
||
|
||
---
|
||
|
||
## Why this log exists
|
||
|
||
This session ran long enough to need archiving. It covers two large, sequential
|
||
efforts: (1) root-causing and fixing a real VM crash bug, and (2) using that
|
||
bug as the trigger to design and implement a full replacement for the
|
||
hardcoded 3-VM Tripod fleet's heat/conservation mechanism. Read this before
|
||
resuming work — it's the fast path back to full context without re-deriving
|
||
everything from the git log.
|
||
|
||
**Start here for the live design doc:**
|
||
`docs/working/architecture/VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md` (rev g
|
||
as of session end). That doc is the authoritative, up-to-date record of the
|
||
design — this worklog is a narrative companion, not a replacement.
|
||
|
||
**Also authoritative for this session's bug:**
|
||
`docs/working/architecture/K-PUSH-DICTIONARY-SHADOWING-BUG-20260704.md` — the
|
||
full bug report (root cause, fix, verification), written and committed before
|
||
this session's design work began.
|
||
|
||
---
|
||
|
||
## Part 1: K-PUSH dictionary shadowing bug (carried in from prior session, closed out here)
|
||
|
||
**Symptom:** `K-PUSH` (in the old `fleet-k.4th`) crashed with a NULL-cell
|
||
fault under certain heat-reorg timing.
|
||
|
||
**Root cause:** A kernel C primitive and a FORTH capsule constant were both
|
||
named `VM-COUNT`. Dictionary lookup picked whichever one happened to be
|
||
"newest" by bucket position — and the heat-reorg pass (`dict_reorganize_buckets_by_heat`,
|
||
a wall-clock-gated `qsort` by `execution_heat`) could reshuffle bucket order
|
||
in a way that broke the assumption that "newest" meant "most recently
|
||
defined." This made word resolution non-deterministic under specific timing,
|
||
and `K-PUSH` (which needed the FORTH constant, not the C primitive) sometimes
|
||
got the wrong one.
|
||
|
||
**Fix:** `vm_dict_resolve_in_bucket()` (`src/dictionary_management.c`) — a
|
||
full-bucket scan that walks `vm->latest`'s link chain to determine true
|
||
definition age, independent of physical bucket/array position. Applied to
|
||
every lookup path: `vm_find_word`, the hotwords cache's Stage-2 fallback,
|
||
and `dict_find_word_heat_aware`. Cache coherence fixes (eviction on
|
||
hide/smudge/redefine) went in alongside it.
|
||
|
||
**Verification:** Three-arch QEMU acceptance with **matching `dict_hash`
|
||
across amd64/aarch64/riscv64** — the first time in the project's history this
|
||
had been achieved. This was the acceptance criterion that closed the bug out.
|
||
|
||
**A false start along the way (reverted cleanly):** An initial hypothesis
|
||
blamed a mid-compile forward-reference race in the capsule loader, and a
|
||
speculative "atomic colon-definition rollback" fix was built for it
|
||
(`a8ea30e7`, marked WIP). It turned out not to be the real bug — it never
|
||
engaged for the actually-failing block, and it caused a real regression
|
||
(Hermes `CH-SCAN` infinite loop, observed at ~2.9 trillion ticks before being
|
||
killed). Once the real fix (age-honoring resolution) made it unnecessary, it
|
||
was reverted via `git checkout a8ea30e7^ -- src/starkernel/capsule/capsule_loader.c`
|
||
(commit `6816063f`), restoring the original proven per-line defer mechanism.
|
||
Captain Bob explicitly approved chasing the harder, correct C-level fix over
|
||
a quick capsule-loader patch: *"I say fix the C99 part is the correct
|
||
solution. I know it's the harder one too."*
|
||
|
||
**Full report:** `docs/working/architecture/K-PUSH-DICTIONARY-SHADOWING-BUG-20260704.md`
|
||
(commit `89024043`).
|
||
|
||
---
|
||
|
||
## Part 2: From bug fix to architectural question
|
||
|
||
Fixing the shadowing bug exposed a deeper issue Captain Bob flagged directly:
|
||
Hera's fleet is hardcoded to exactly 3 VMs (`VM-COUNT`), in two ways —
|
||
fixed-size arrays (`CREATE ... VM-COUNT ... ALLOT`, no realloc in this FORTH)
|
||
and hand-unrolled loops (`K-REBALANCE`, `K-STATUS`, `VM-HOTTEST`, `CD-TICK`
|
||
all spelled out exactly three VM indices).
|
||
|
||
Captain Bob's framing for the fix, given verbatim because it set the
|
||
direction for everything that followed:
|
||
|
||
> "I'm actually trying to eliminate any notion of special cases. Once we have
|
||
> the capsule registry written, we're going to wire in the same machinery we
|
||
> use for word execution to decide VM execution turn... we do NOT want a
|
||
> scheduler. The execution depends on the VM state."
|
||
|
||
> "there is a slope calculation with words that is a 0-1 Q48.16 calculation
|
||
> for decay and a feedback loop reshaping the slope every heartbeat. same
|
||
> concept for vm's" — pointing directly at Loop #6 (`inference_engine.c`,
|
||
> `infer_decay_slope_q48`) as the template to mirror, not reuse.
|
||
|
||
This produced the core design commitment: VM-level heat governance becomes a
|
||
**structural parallel** to the existing word-level physics engine (heat
|
||
accrual, decay, rolling-window history, regression-inferred adaptive slope)
|
||
— not a shared implementation, and explicitly **not a scheduler**. Physics
|
||
stays a passive observer of real `VM-EXEC`/`VM-CALL`/`VM-STEP` dispatch; it
|
||
never decides whose turn it is to run.
|
||
|
||
---
|
||
|
||
## Part 3: The design doc — iterative gap-closing (revs a→g)
|
||
|
||
`docs/working/architecture/VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md` went
|
||
through 7 revisions this session, each committed separately:
|
||
|
||
- **rev a** (`119bfc83`) — initial doc.
|
||
- **rev b** (`5ba733db`) — Captain Bob posted concrete struct definitions,
|
||
weighting formulas, concurrency notes; two explicit open items.
|
||
- **rev c** (`ee87ec0e`) — closed all four implementation gaps found during
|
||
an honest self-audit (Captain Bob asked directly: *"do you have enough
|
||
information to build this over several breaks in the session?"* — the
|
||
audit found gaps rather than assuming yes).
|
||
- **rev d** (`c85c0f95`) — corrected an incomplete consumer-migration audit
|
||
(first pass missed `capsules/hermes/init.4th` and `capsules/artemis/init.4th`
|
||
entirely — Hermes turned out to be a real, previously-unaudited consumer of
|
||
the doomed hooks) and posed the "fold-in question" (does Hermes/Artemis's
|
||
own heat economy merge into VM-fleet heat, or stay separate?).
|
||
- **rev e** (`cacac77a`) — settled the fold-in question: **no merge, sibling
|
||
instances.** Each level (words, VMs, messages, blocks) keeps its own
|
||
independent heat quantity; only the *mechanism* (passive accrual, lazy
|
||
decay, rolling window, regression-inferred slope) is meant to generalize.
|
||
Evidence: `Q-DECAY = 65208` was independently hand-copied into three
|
||
separate files (`compudynamics.4th`, `hermes/init.4th`, `artemis/init.4th`)
|
||
with zero coordination — the literal "before" picture words already moved
|
||
past via Loop #6.
|
||
- **rev f** (`be611cba`) — execution rules added at Captain Bob's explicit
|
||
instruction before implementation began: small units, clean+make at
|
||
checkpoints, QEMU when a unit affects boot behavior, one ISA at a time
|
||
during iteration (full three-arch reserved for milestones).
|
||
- **rev g** (`c8af58c7`) — kill's heat-return mechanism replaced mid-implementation
|
||
(see Part 5) and the doc updated to match what was actually built.
|
||
|
||
---
|
||
|
||
## Part 4: Implementation — small units, each checkpointed
|
||
|
||
Executed strictly per the rev-f rules: build clean, checkpoint, QEMU when the
|
||
unit touched boot behavior, one ISA (amd64) during iteration.
|
||
|
||
1. **`cc9a4da2`** — New kernel-only file pair, `capsule_vm_physics.c`/`.h`.
|
||
`VMPhysics` (execution_heat_q48/last_active_ns/is_live) and `VMFleetWindow`
|
||
(64-deep circular touch-history buffer) as file-scope state, mirroring
|
||
`capsule_birth.c`'s own `vm_registry_head` pattern rather than a public
|
||
`VMRegistryEntry` field. `vm_physics_transfer` (subtract-then-add, clamped
|
||
at 0) is the one conservative primitive everything else composes from.
|
||
The fleet-wide inference reimplements `infer_decay_slope_q48`'s closed-form
|
||
log-linear OLS regression against the fleet's own touch-history — new
|
||
code, same math, no link-time dependency on the hosted-shared inference
|
||
engine. Pure addition, no wiring yet — amd64 build-only checkpoint.
|
||
|
||
2. **`1090d57f`** — Wired the primitives into the three existing dispatch
|
||
points identified in the design doc: `mama_word_birth` (`vm_physics_init`),
|
||
`mama_word_kill` (`vm_physics_retire`, resolving `vm_id` by name first
|
||
since `capsule_vm_kill` tears the entry down), and
|
||
`vm_step`/`vm_exec`/`vm_call` (`vm_physics_touch`). `vm_physics_tick` wired
|
||
into `vm_tick()` (`vm_runtime.c`), gated to Mama's own heartbeat only
|
||
(`sk_get_mama_vm() == vm`) since fleet physics is fleet-wide, not per-VM.
|
||
amd64 QEMU: clean boot, no faults.
|
||
|
||
3. **`09c5f1cc`** — `VM-CONSERVED?` and `VM-PHYSICS-STATUS` FORTH primitives,
|
||
registered in both vocabularies alongside `VM-COUNT`.
|
||
|
||
4. **`5be3f251`** — **The mid-implementation design change** (see Part 5
|
||
below for the full story): kill's heat-return mechanism replaced outright.
|
||
|
||
5. **`c8af58c7`** — Design doc rev g, brought back in sync with what was
|
||
actually implemented.
|
||
|
||
6. **`9323f776`** — The big one: migrated every consumer capsule off the old
|
||
mechanism and deleted it.
|
||
- `init.4th`: dropped the `compudynamics.4th`/`fleet-k.4th` `EXEC` lines.
|
||
`TRIPOD-TEST` rewritten to call `VM-CONSERVED?` directly — **no more
|
||
artificial tick-pumping before checking conservation**, since it now
|
||
holds continuously by construction rather than needing a warmed rolling
|
||
average. Dropped the `K-KILL-HOOK`/`K-SPAWN-HOOK` calls around the
|
||
Hermes kill+rebirth sequence (heat bookkeeping is automatic inside
|
||
`BIRTH`/`KILL` now).
|
||
- `process.4th`: `SPAWN` drops its `K-SPAWN-HOOK` call; `CD-PHASE@` deleted
|
||
(dead code, confirmed no callers, read the now-gone `VM-HEAT@`/`K-TARGET`
|
||
directly).
|
||
- `hermes/init.4th`: `EVENT-EMIT`'s dispatch to `HERA-NOTIFY-SPAWN`/
|
||
`HERA-NOTIFY-KILL` (which called the doomed hooks *remotely* via
|
||
`VM-EXEC`) removed; both notify words deleted outright.
|
||
- `compudynamics.4th` and `fleet-k.4th` deleted entirely (`git rm`).
|
||
- Hit two `mkcapsule` format limits along the way and fixed them inline:
|
||
64-char max line length, 16-content-line max per block (had to trim
|
||
`VM-PHYSICS-STATUS` out of `TRIPOD-TEST`'s body to fit — it's still
|
||
available standalone, just not auto-printed during acceptance).
|
||
- **amd64 acceptance: full `TRIPOD-TEST` pass** — `PASS: fleet K`,
|
||
`PASS: Hermes liveness`, `PASS: Artemis ready`, `PASS: reap`, `K soak` —
|
||
entirely on the new mechanism.
|
||
|
||
7. **`8464907a`** — Full three-arch acceptance (this was the milestone the
|
||
rev-f rules called for: "after the deletions land, before declaring the
|
||
design implemented"). **amd64/aarch64/riscv64 all pass, with dict_hash
|
||
matching exactly (`0x5115727b8d7cf008`) across all three** — deterministic
|
||
parity held through the entire migration.
|
||
|
||
8. **`7a1383a0`** — Small doc addendum (see Part 6).
|
||
|
||
---
|
||
|
||
## Part 5: The mid-implementation design change — parent-pointer kill
|
||
|
||
After step 4 above landed (proportional-to-current-heat fan-out across all
|
||
LIVE survivors on kill), Captain Bob proposed a cleaner replacement
|
||
mid-session, unprompted by any bug:
|
||
|
||
> "Model it explicitly as a graph: every VM has one outbound edge
|
||
> (parent_vm_id) to whoever birthed it, Tripod VMs (Hera/Hermes/Artemis) are
|
||
> the only nodes with no outbound edge — flagged is_root, not special-cased
|
||
> by name — and kill's heat-return is a single generic function that follows
|
||
> edges until it lands on a root."
|
||
|
||
This eliminated three problems the proportional formula had at once: it
|
||
needed division (an all-cold survivor set breaks the split), it needed a
|
||
"no survivors" fallback, and it invited a weighting-policy argument nobody
|
||
had actually asked to have.
|
||
|
||
**Investigation before implementing (this mattered):** I asked what happens
|
||
if a *root itself* is killed, since the model as stated gave three peers
|
||
(Hera/Hermes/Artemis) no outbound edge and therefore no obvious receiver.
|
||
Captain Bob's answer — *"I'd say [drop it] but I'm questioning why we do that
|
||
to begin with? is this a smell?"* — sent me back to `capsules/init.4th` to
|
||
check. **`TRIPOD-TEST` (block 2051) deliberately kills and rebirths Hermes as
|
||
a resilience test** (the `"K soak"` check) — not leftover boot cruft. That
|
||
finding flipped the answer: dropping heat on root-kill would make that exact
|
||
test's own conservation check fail (or pass by luck). "Fall through to Hera"
|
||
was the option that actually matched the test's intent.
|
||
|
||
That in turn simplified the whole model further: if every root-kill falls
|
||
through to Hera specifically, then **Hera is the only true root** — Hermes
|
||
and Artemis are just her ordinary children. Captain Bob confirmed: *"yes!,
|
||
Hera is always the only root. later she will be capable of rebirthing of
|
||
Hermes and Artemis if they fail out"* — which is exactly why getting the
|
||
root-kill case right now matters for real, not hypothetically.
|
||
|
||
**A pleasant surprise during implementation:** `capsule_birth.c` already had
|
||
dead scaffolding for exactly this — a `parent_vm_id` field on the internal
|
||
registry node, hardcoded to `0` everywhere, never read anywhere, with the
|
||
comment `/* VM 0 = Hera for direct children */`. Renamed `VMRegistryEntry`'s
|
||
unused `reserved` field to `parent_vm_id` and exposed it publicly instead of
|
||
inventing new state; `vm_physics_retire` now walks it via the existing
|
||
`capsule_vm_registry_get`, stopping at Hera's self-referential entry
|
||
(`parent_vm_id == vm_id == 0`).
|
||
|
||
---
|
||
|
||
## Part 6: Loose thread deliberately left open
|
||
|
||
Captain Bob, after the three-arch acceptance landed:
|
||
|
||
> "remember that birth is possible for any VM. they have to ask for
|
||
> permission to birth. perhaps that's a question better asked when we start
|
||
> creating messages and the glue utilities to make this an os"
|
||
|
||
Recorded in the design doc's "Explicitly out of scope" section (final commit,
|
||
`7a1383a0`): today `BIRTH` is MAMA-only (only Hera's VM has it registered),
|
||
so `parent_vm_id` hardcoded to `0` at every allocation site is correct *as
|
||
written*, not a stand-in for something smarter. The future question — any VM
|
||
birthing another, gated by a permission ask rather than by which VM holds the
|
||
`BIRTH` word — is explicitly deferred to when messaging/OS-glue work begins.
|
||
`parent_vm_id` is the field that question will need; it's just not being
|
||
generalized yet.
|
||
|
||
---
|
||
|
||
## State at session end
|
||
|
||
- **Branch `lithosananke`, clean tree, fully pushed.** Last commit `7a1383a0`.
|
||
- **Design doc at rev g**, status line: "Implementation underway... amd64-only
|
||
acceptance so far, three-arch acceptance still pending" — **this line is
|
||
now stale**, three-arch acceptance completed in commit `8464907a` after the
|
||
doc's last edit. Update the status line first thing next session.
|
||
- Every item in the design doc's original "What gets deleted" list is done:
|
||
`compudynamics.4th` gone, `fleet-k.4th` gone, `process.4th`'s `CD-PHASE@`
|
||
gone, `VM-PHYSICS-STATUS`/`VM-CONSERVED?` primitives live and working.
|
||
|
||
### Explicitly not done — pick up here
|
||
|
||
1. **Update the design doc's status line** to reflect three-arch acceptance
|
||
is complete (small, immediate, do this first).
|
||
2. **`capsules/MANIFEST.md`** (hand-written block registry, "authoritative
|
||
for capsule block assignments" per its own header) still documents blocks
|
||
4400–4404 and other content that no longer exists (`K-FLEET`, `K-SPAWN-HOOK`,
|
||
`K-STATUS`, etc.). Flagged as doc debt during the migration commit, not
|
||
fixed. Needs a pass to bring it back in sync.
|
||
3. **`doe-campaign.4th`** is broken (references `VM-STATUS`, `VM-INIT`,
|
||
`K-BUMP`, `VM-HERA`/`VM-HERMES`/`VM-ARTEMIS`, all deleted). This was
|
||
explicitly flagged in the design doc as its own separate decision
|
||
(migrate, deprecate, or leave broken until needed) — not part of standard
|
||
boot, so it doesn't block anything, but it's sitting broken right now.
|
||
4. **Hermes's `COMMON-CH` floor** (`Q.1 3 /`, a literal `3`, not a broken
|
||
reference) is still hardcoded. Deliberately left alone this session — the
|
||
fold-in resolution (rev e) already deferred its real fix to Hermes's own
|
||
sibling physics doc, which doesn't exist yet.
|
||
5. **Hermes message-physics and Artemis block-physics sibling design docs**
|
||
— only the decision that they should exist (rev e's fold-in resolution)
|
||
has been made. Not started.
|
||
6. **DoE rewrite** — scoped (four independent metric spaces identified: word,
|
||
VM-fleet, message, block), not designed or written up as its own doc yet.
|
||
7. **BIRTH-by-any-VM-with-permission** — recorded as a future question (Part
|
||
6 above), not designed.
|
||
8. Two Verification-approach items from the design doc were never explicitly
|
||
exercised as isolated tests (though the full acceptance run exercises the
|
||
spirit of both): the "4th throwaway VM" conservation test, and the
|
||
"kill-during-warm-up" dead-`vm_id`-in-trajectory test. Worth doing as
|
||
focused checks before calling the design fully verified, per the doc's own
|
||
Verification approach section.
|
||
|
||
### Quick orientation for next session
|
||
|
||
- Read `docs/working/architecture/VM-PHYSICS-DYNAMIC-FLEET-DESIGN-20260705.md`
|
||
in full (rev g) — it's the living source of truth, this worklog is not.
|
||
- `src/starkernel/capsule/capsule_vm_physics.c`/`.h` is the new mechanism.
|
||
- `git log --oneline 379bf16c..HEAD` gives the exact commit sequence this
|
||
worklog describes, in order.
|