Files
LithosAnanake/docs/working/archive/session-logs/2026-07-05-worklog.md
T

321 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
44004404 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.