e01c4e33e48a16a2eaead183ba28f179b1ddb5b0
35
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6a97fa4c98 |
logs: add boot-run audit trail and DoE CSVs from item 4.3.5 work
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
fa300ef4c6 |
starkernel: item 4.3.4 -- checkpoint, draw a cube (no new bugs)
Adds VERT/EDGE/CUBE to capsules/fabric.4th (blocks 4913-4915). VERT ( n -- x y z ) reads bits 0/1/2 of a corner index as the X/Y/Z sign (+-CS from center), so all 8 cube corners come from one word. EDGE resolves both corners via VERT and calls LINE; CUBE is 12 EDGE calls (4 bottom, 4 top, 4 vertical). First item in the 4.3.3.x sequence with no new bug found -- a small signal that Q.TO-INT, the VARIABLE alignment fix, and the LINE-STUCK? cap were the real gaps rather than something still lurking in LINE/PROJECT/CART-Y. Verified live on amd64: a centered, half-size-100 cube renders correctly -- front/back face squares, back face offset diagonally up-right by exactly the 45-degree cavalier projection's depth term, all 12 edges connecting at the right corners. All three architectures boot clean to ok> with the DoE completing; dict_hash identical across all three and unchanged from 4.3.3a/4.3.3b. FABRIC.md item 4.3.4 marked done. This is the checkpoint -- 4.3.x groundwork stops here for review per this item's own acceptance criterion. |
||
|
|
cb4326c712 |
starkernel: item 4.3.3b -- geometry drawing wordset, fixed Q.TO-INT sign bug
Adds LINE (Bresenham in raster space, endpoints projected once each -- valid because the cavalier projection is linear), CIRCLE/ELLIPSE (36-segment polygon approximation), and ARC (18 segments over a caller radian range) to capsules/fabric.4th (blocks 4903-4912). TO-RASTER factored out of CART-PLOT (same behavior) so LINE can reuse the projection+flip for both endpoints. Found mid-implementation: colon definitions cannot span block boundaries in this capsule loader -- verified with a throwaway test capsule, the continuation lands in a [CAPSULE][DEFER] path that never resolves. LINE's body is split across LINE-SETUP/LINE-DONE?/LINE-STUCK?/LINE-STEP, each self-contained within its block, rather than one long definition. A fourth real bug, serious this time: CIRCLE's first live test rendered only one quadrant, then hung the VM for several minutes on a follow-up call. Root cause: q48_to_u64() (include/q48_16.h and include/starkernel/q48_16.h, backing Q.TO-INT) did an unsigned logical shift, corrupting any negative Q48.16 value into a huge garbage integer instead of sign-extending -- inevitable once Q.SIN/Q.COS leave the first quadrant. That garbage became a bogus LINE target with no bound on LINE-STEP's Bresenham loop. Fixed q48_to_u64 to shift through a signed int64_t intermediate (bit-identical for the non-negative case). Also added LINE-STUCK? (LSTEPS vs FB-WIDTH+FB-HEIGHT, the true worst case for an on-screen line) as a defense-in-depth cap against any future bad target. Verified live on amd64 after both fixes: -65536 Q.TO-INT . now prints -1; LINE/CIRCLE/ARC/ELLIPSE all complete without hanging or erroring, and a combined screendump shows all four rendering correctly and distinctly. All three architectures boot clean to ok> with the DoE completing; dict_hash identical across all three and unchanged from 4.3.3a (expected -- fabric.4th isn't loaded at boot, and the Q.TO-INT fix doesn't change dictionary structure). FABRIC.md item 4.3.3b marked done with full acceptance evidence. |
||
|
|
36389e9d4a |
starkernel: item 4.3.3a -- Q48.16 trigonometry (Q.SIN/Q.COS)
Adds q48_reduce_angle() (range-reduce a signed Q48.16 angle into [-PI_Q48, PI_Q48] via one integer division plus a bounded fix-up loop) and q48_sin_approx/q48_cos_approx (Taylor series, terms n=3,5,7,9,11 for sin and n=2,4,6,8,10 for cos, early exit below 10). Q.SIN/Q.COS registered as FORTH words in q48_words.c, same pattern as Q.LOG/Q.EXP/Q.SQRT. Found mid-implementation: this codebase has two independent Q48.16 implementations -- src/word_source/q48_16_words.c (hosted/vendored) and src/starkernel/math/q48_16.c (kernel-only; the kernel build does not compile the former at all). The hosted build linked fine after the first pass; the kernel build failed with undefined references until the same two functions were added to both .c files and both q48_16.h headers (include/q48_16.h and include/starkernel/q48_16.h). Not fixed at the root -- Q.LOG/Q.EXP/Q.SQRT already had this same four-file duplication, unremarked until now -- just navigated correctly for this item. Verified live on amd64 via serial injection: sin/cos at 0, +-pi/2, pi, and 3pi (range-reduction across multiple turns) all match expected values within Taylor-series truncation error (<0.2%). All three architectures boot clean to ok> with the DoE completing; dict_hash identical across all three (0x291a660b05fa7b52). FABRIC.md item 4.3.3a marked done with full acceptance evidence. |
||
|
|
ef9806977a |
starkernel: item 4.3.3 -- Cartesian coordinate machinery, found and fixed a VARIABLE alignment bug
Adds Module 28 (framebuffer_words.c/.h): PLOT ( x y color -- ), FB-WIDTH, FB-HEIGHT -- raw hardware-boundary C primitives, kernel-only, no-op on hosted builds, same pattern as every other module. Adds capsules/fabric.4th (blocks 4900-4902, mkcapsule --lint clean): COS45/Z->DELTA/PROJECT/CART-Y/CART-PLOT -- the 45-degree cavalier orthographic projection and Y-flip, in FORTH per the compose-in-FORTH-first rule (this is policy, not hardware access). Found and fixed a second real bug while live-testing CART-PLOT over the serial socket: defining_word_variable() (defining_words.c) captured vm->here as a VARIABLE's address with no alignment call first, while vm_load_cell/vm_store_cell require 8-byte-aligned addresses. This capsule's VARIABLE ZD landed misaligned (945) purely by chance of what preceded it; other capsules' variables happened to land aligned by luck, not guarantee. Real deviation from FORTH-83/ANS, which specifies VARIABLE reserves an aligned cell. Fixed with vm_align(vm) before capturing addr -- ALIGN already existed as a word but VARIABLE wasn't calling it. Verified end-to-end on amd64 via manual serial injection + QEMU screendump: plotted 4 marker points (origin, +100 X, +100 Y, +50 Z) and confirmed all landed at hand-calculated raster coordinates, including the diagonal up-right shift for the Z-axis point -- the projection math is correct, not just non-crashing. fb/fabric-test-cart-plot.png. 4.3.1's corner diagnostic still renders correctly in the same shot, confirming no regression. All three architectures (amd64/aarch64/riscv64) boot clean to ok> with the DoE completing; dict_hash identical across all three (0xc7f9adf885e306d2), confirming parity is unaffected. FABRIC.md item 4.3.3 marked done with full acceptance evidence. |
||
|
|
ab96ac0970 |
starkernel: item 4.3.1 -- framebuffer orientation test, found and fixed a real color-swap bug
Adds fb_draw_orientation_test() (framebuffer.c/.h): fills the four raster corners RED/GREEN/BLUE/YELLOW via fb_fill_rect. Wired into kernel_main.c calling fb_init() directly -- console_fb_init()/vt100_init() removed from the boot path, since vt100.c/console.c are superseded by the Console drawing-fabric redesign (FABRIC.md ss27) and should not be exercised even incidentally. The diagnostic caught a real, pre-existing bug on its first run: framebuffer.c's pack_pixel() had its FB_PIXEL_RGBX32/FB_PIXEL_BGRX32 branches swapped relative to UEFI GOP's own byte-order naming convention, producing a clean R<->B channel swap (G unaffected). Spatial placement was already correct -- no flip/rotation. Fixed by swapping pack_pixel's two return bodies to match framebuffer.h's already-correct doc comments; kernel_main.c's GOP-format switch needed no change. Also item 4.3.2 -- QEMU screenshot capability. scripts/qemu_screenshot.sh already existed (monitor socket + socat + HMP screendump), just unwired and unused this session. Redirected its PNG output to a new top-level fb/ directory (tracked in git, not logs/, not a gitignored temp dir) and added a python3+PIL fallback for PPM->PNG conversion since imagemagick isn't installed here. Left as a standalone script for now, not wired into a Makefile target. FABRIC.md items 4.3.1 and 4.3.2 marked done with acceptance evidence. |
||
|
|
5a28458b21 |
starkernel: item 4.2 -- Hermes native on the Stadium (complete)
Migrates Hermes's message/channel lifecycle onto the Stadium's unified heat/capacity economy: MSG-ALLOC/FREE-NODE and CH-ALLOC/FREE-NODE now route entirely through stadium_admit()/stadium_evict(), replacing the old local free-list + independent heat-field mechanism. Eight kernel-only STADIUM-* FORTH primitives (ADMIT, EVICT, RES@, RES-PULL, RES-PUSH, HEAT@, HEAT!, WORD-HEAT), VM.stadium_vm_id threaded through all three vm_core.c dispatch sites (replacing item 4.1's hardcoded vm_uuid_hera()), and the stadium_owner[idx] fix so evict-credit lands in the VM that actually admitted a patron, not whoever owned cell 0. This session's own contribution, on top of that pre-existing implementation: found and fixed two bugs blocking the item's own K≡1.0 conservation self-check (HERMES-K was reading 0, not 65536): - Q.SLOT admission-heat fix (capsules/hermes/init.4th): MSG-SEND/ CH-ACCEPT admitted with Q.1 (the entire fleet-wide "1.0" unit) per item, a leftover from before the Stadium migration when each message/channel had its own unconstrained heat field. Instantly drained the shared, finite reservoir. - Reservoir floor for word-execution admission (stadium_words.c): stadium_word_dispatch() (item 4.1) pulls STADIUM_WORD_HEAT_QUANTUM on every word dispatch, not just first admission -- exhausts a VM's entire reservoir in ~32 dispatches, starving any application-level economy sharing that VM's reservoir before it gets a chance to pull anything. word_dispatch_pull() now clamps word-execution's own pulls to leave a Q48_ONE/3 floor (same fair-share figure COMMON-CH's own floor already uses); application-level pulls are unaffected. - STADIUM-WORD-HEAT primitive + stadium_words_resident_heat(): the floor deliberately leaves word-execution residents holding real heat, invisible to HERMES-K's original formula (MSG+CH+reservoir, no term for word patrons). Adding this term closes K to exactly 65536 on all three architectures. Also rules on two open scope questions in FABRIC.md: MBR-ALLOC/ MBR-FREE-NODE stay off the Stadium (membership records have no heat field, never did -- the acceptance bullet's inclusion of them was a completeness gesture predating a check of the actual layout), and records the effort number (12 implementation files, +759/-120 lines). Verified: all three architectures boot clean, full self-test passes, Stadium conservation closes exactly (resident_sum + reservoir = Q48_ONE) at both the C/Stadium level and the FORTH-level HERMES-K check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
3d0b9351bd |
starkernel: item 4.1 -- hot words onto the Stadium, density-ranked eviction
Punch list §25 item 4.1 complete. Replaces the round-robin hotwords cache with Stadium density-ranked admission/eviction on the kernel side, via the §17.7 reservoir mechanism and a kernel-side word_id -> cell_index map (no DictEntry change, dict_hash untouched). Adds stadium_birth_hera() to close the cell-0 panic hazard, STADIUM_WORD_HEAT_QUANTUM/STADIUM_WORD_COOL_RATE_Q48 Kconfig knobs (flagged untuned), and a stadium_word_forget() FORGET coherence hook to close a recycled-word_id aliasing gap. Verified: all five hotwords_cache_* call sites in dictionary_management.c bypassed under __STARKERNEL__; word dispatch feeds the Stadium at all three vm_core.c physics_execution_heat_increment() sites; hosted make unaffected; all three architectures booted to ok> with matching dict_hash (0x3d4e1daf289da94f) and matching conservation stats (promotions=354 evictions=0, resident_sum=65536 reservoir=0 sum=65536). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
9b305a5be7 |
starkernel: item 3.8 -- VM identifiers as UUID/GUID
Punch list §25 item 3.8 complete. Added after starting item 4.1
surfaced the need to thread a vm_id into stadium_admit()'s new quota
parameter; Captain Bob ruled UUID/GUID rather than keeping the
narrower uint32_t.
New VMUuid type (vm_uuid.h/vm_uuid.c): two uint64_t halves, RFC-4122-
shaped for logging. Not real randomness -- checked directly against
QEMU 10.2.1's actual CPU feature set: amd64 RDRAND and riscv64 Zkr are
both real, available features here; aarch64 has no RNG property on any
CPU model including "max" (verified exhaustively via QMP
query-cpu-model-expansion). Captain Bob ruled a uniform fallback
across all three ISAs rather than a per-architecture split.
Fallback is a deterministic PRNG (splitmix64) seeded from the Mama
capsule's content hash, pre-filling a 16-entry FIFO pool at boot and
refilling with another batch of the same stream when exhausted --
exactly the shape requested. Same capsule booted twice produces the
same id sequence, preserving the dict_hash reproducibility this
session has relied on throughout.
Hera keeps a fixed, reserved all-zero id, not drawn from the pool --
capsule_birth.c uses vm_id == 0 as a load-bearing sentinel in three
places (KILL protection x2, fleet heat-fanout parent-chain
terminator), found by reading before writing any code.
Two real sentinel-collision bugs caught before shipping, same class as
STADIUM_CONTAINS_NONE: vm_uuid_none() (all-ones, not all-zero) for
"not yet assigned"/"no VM" placeholders; confirmed item 3.7's quota
table already used an in_use boolean rather than a vm_id sentinel, so
no second collision was actually possible there -- the dead,
never-referenced STADIUM_QUOTA_SLOT_EMPTY macro was removed.
Blast radius larger than first scoped, flagged mid-work rather than
silently absorbed: capsule_vm_physics.c/.h (the fleet heat-transfer
layer item 2.1 modified earlier this session) has its own vm_id-keyed
node table and walks parent_vm_id chains through the same identity
space, so it needed the same change, plus its callers in
mama_forth_words.c and sk_vm_bootstrap.c.
One live FORTH word contract changed, by explicit ruling: CAPSULE-BIRTH
was ( capsule-id -- vm-id ), a single cell -- can't hold 128 bits.
Captain Bob picked pushing two cells ("there is doubles support in the
FORTH std word set anyway"): ( capsule-id -- vm-id-hi vm-id-lo ).
MAMA-VM-ID changed the same way: ( -- 0 0 ).
Verified: full (not standalone-file) kernel rebuild to catch cross-file
breakage given the size of this change -- it surfaced the
capsule_vm_physics.c blast radius a narrower check would have missed.
Three-architecture boot (amd64, aarch64, riscv64), all reaching ok>
with identical dict_hash=0x3d4e1daf289da94f matching the item-3.7
baseline.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
e55111c2c5 |
starkernel: item 3.7 -- per-VM free lists (Phase 3 core complete, for real)
Punch list §25 item 3.7 complete. Added to §25.4 after starting item 4.1 surfaced it as an unbuilt prerequisite -- 3.6's earlier "Phase 3 core complete" claim is corrected in this same commit. StadiumVMQuota table (size STADIUM_MAX_VM_COUNT, linearly searched by vm_id -- capsule_birth.c's vm_id is monotonic and never reused, so it cannot index a table directly, and a 4-entry scan costs nothing). New per-cell stadium_owner byte array records which quota a cell belongs to, needed so eviction returns a freed cell to the correct VM's list and so eviction search stays scoped to the evicting VM's own residents (quota isolation). Free-list linkage reuses each cell's `link` field as a next-free pointer while unresident -- link is documented only as generic "index into the Stadium, not a pointer," so this is a repurposing, not a header change. Does not answer the separate, still-open question of which field carries a multi-cell patron's first continuation-cell index; item 3.5's mass != 1 refusal stands exactly as it was. Boot-time: every cell chained into one list in ascending index order, granted whole to vm_id 0 (Hera), the only VM that exists. Ascending order preserves item 3.6's "Hera is patron zero" invariant once real birth-wiring lands. stadium_admit()'s signature changed to take vm_id -- a change to code shipped in item 3.5, amended there. Pops the calling VM's free-list head first (O(1)); only falls back to a same-VM-scoped eviction search if empty. Caught a real bug before the boot run: the header zero-fill on eviction (and the initial free-list build) both left contains == 0, but 0 is Hera's valid index -- the same collision item 3.1's STADIUM_CONTAINS_NONE fix addressed, recurring at a new site. Fixed by explicitly setting contains = STADIUM_CONTAINS_NONE at both free-list sites. Explicitly out of scope, reported not invented: granting quota to any VM other than Hera is capacity arbitration (item 1.3 left "how much moves per transfer" open). stadium_owner is set once at boot and never rewritten, so quota_slot_for_vm() refuses every vm_id != 0 permanently until item 4.2 adds the grant path and owner-array writes. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.6 baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
72487e7fff |
starkernel: item 3.6 -- Hera as patron zero, pinned (Phase 3 core complete)
Punch list §25 item 3.6 complete. Phase 3 (§25.4) core is now done: items 3.1-3.6 all closed. stadium_evict() now panics via sk_hal_panic() if a resident cell 0 (Hera, patron zero by construction of §6's boot order) is ever selected for eviction. Placement is deliberate: the check runs before the pin/contains refusal checks, not after -- if it ran after, a wrongly-cleared pin would let the ordinary refusal path quietly return -1 instead of ever reaching the panic, defeating the point of a check that's supposed to be independent of pin holding. Per §20.5 #3's explicit wording, not implemented as a filter: stadium_admit()'s least-dense search is unchanged, still relying on the general pin skip from item 3.5. Adding a second filter there would have done exactly what that section warns against ("filtering hides the bug, asserting reports it"). The panic path is, and will remain, unexercised by the acceptance mechanism: sk_hal_panic() halts the machine, and triggering it deliberately is incompatible with the three-arch boot being this project's sole acceptance test. Correctness rests on the placement argument, not a test -- same honesty precedent as items 3.4 and 3.5's other unexercised paths. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.5 baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
f8a50561b0 |
starkernel: item 3.5 -- admission and eviction
Punch list §25 item 3.5 complete. stadium_admit(candidate) places into an unused cell if one exists (no comparison needed), otherwise finds the least-dense resident -- skipping pinned and contains-gated patrons, which are never eviction candidates -- and evicts it only if the candidate is strictly denser, per §19.3. stadium_evict(cell_index) dispatches the departing patron's behaviour before clearing its slot, per §17.2. Caught a real bug before it ran: the first draft used contains == 0 to mean "holds nothing," but cell index 0 is a valid index (Hera, item 3.6). Fixed with a proper sentinel, STADIUM_CONTAINS_NONE (UINT32_MAX). A second-pass review found mass was not accounted for: both functions handled exactly one cell regardless of the candidate's stated mass, which leaks cells on eviction of any mass > 1 patron and breaks capacity conservation. Fixed by refusing any candidate with mass != 1 -- multi-cell patrons need the per-VM free lists item 3.2 already deferred (§22.3), not built here. Documented, not fixed: the discriminator bitmap can't distinguish free from continuation cells, so the free-cell scan reads continuation-cell payload bytes under the header layout -- latent since nothing creates continuation cells yet, and the mass != 1 refusal keeps it provably latent. Superseded by the free list when it exists. Unexercised at runtime: nothing calls either function yet (no real patron kind is wired to the Stadium). No self-test added -- filling ~74,000+ cells to reach the eviction-on-full branch was judged impractical, following item 2.2's own precedent for its unexercised fleet-full path. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.4 baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
0b47c256fc |
starkernel: item 3.4 -- density ranking
Punch list §25 item 3.4 complete. stadium_density(cell_index) reads a header's heat and mass and returns heat / mass -- a division on demand from fields already stored in the cell, matching §19.3's "read, not computed by a scheduler" literally. Stays valid Q48.16 without a special fixed-point routine, since heat is already Q48.16 and mass is a plain integer divisor. mass == 0 and an out-of-range cell_index both return 0 rather than dividing by zero -- an empty or never-admitted slot has no footprint to be dense within. Deliberately not built here, per the item's own wording: finding the densest or least-dense resident (§19.3's admission/eviction comparison) is item 3.5's scope, not this one's. Nothing calls stadium_density() yet either. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.3 baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
378d688898 |
starkernel: item 3.3 -- behaviour enumeration and dispatch
Punch list §25 item 3.3 complete. StadiumBehaviour (stadium.h) enumerates exactly the four tags §18.3 already names -- MIGRATE, DELIVER, EXPIRE, COOL -- mapped from §17.1's patron table: blocks->MIGRATE, messages->DELIVER, ACLs->EXPIRE, words and VMs both->COOL. Nothing invented; the tag set and mapping were already in the document. stadium_dispatch(cell_index, behaviour) dispatches on the tag only, never asks what kind of patron departed. Handlers are stubs -- the real actions belong to subsystems not yet migrated onto the Stadium (Phase 4). Nothing calls stadium_dispatch() yet; item 3.5 is its first consumer. The switch is exhaustive with no default case, making §13's "closed enumeration, fixed at build time" a compiler-enforced property under this project's -Wall -Werror rather than just prose. Verified live: temporarily deleted the COOL case, rebuild failed with error: enumeration value 'STADIUM_BEHAVIOUR_COOL' not handled in switch [-Werror=switch], restored it, confirmed clean again. The header's behaviour field stays uint8_t, not the enum type itself, since C does not guarantee an enum's underlying type and that field's offset is load-bearing for item 3.1's validated 64-byte layout. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.2 baseline. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
eb0fd4fffa |
starkernel: item 3.2 -- Stadium boot-time allocation
Punch list §25 item 3.2 complete. stadium_boot_init() (src/starkernel/vm/stadium.c) sizes the global cell array at boot from a real memory-budget query rather than a hardcoded count: pmm_get_stats().free_bytes at the point of allocation, times the new STADIUM_MEMORY_PERCENT Kconfig symbol (default 1%), rounded down to whole 64-byte cells. Matches §17.6's position (b) literally. Also allocates the header/continuation discriminator bitmap item 3.1 declared but did not allocate. Both are kmalloc'd and explicitly zero-filled (kmalloc does not zero). Called from kernel_main.c immediately before sk_vm_bootstrap_parity(), i.e. before any VM exists (§6). Failure is soft -- logs and continues, does not halt boot -- matching the existing precedent one line below it (VM bootstrap parity failure does the same). Added a "Stadium: N cells (M KB)" boot console line at the allocation site so the acceptance logs are evidence the array was actually allocated, not just that the kernel still boots -- the same blind spot item 3.1's uncompiled-header gap exposed. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-3.1 baseline, and the Stadium boot line confirmed present in all three serial logs (amd64: 74234 cells/4639 KB, aarch64: 161329 cells/10083 KB, riscv64: 76122 cells/4757 KB). Not built here, reported per §25.0 rule 3: per-VM free lists (§22.3) -- granted when Hera assigns quota, not this item's scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
1b2f0677de |
starkernel: item 3.1 reopened -- two Kconfig symbols items 1.1/1.4 deferred here
Punch list §25 item 3.1 re-closed after reopening. Items 1.1 and 1.4's resolutions both explicitly named this item as where their Kconfig symbols would be implemented, but 3.1's own stated scope never mentioned them, so the first close missed both: - STADIUM_CONTAINS_DEPTH_MAX (default 5) -- item 1.1's contains-chain depth cap. No consumer yet; reap-gating enforcement is item 3.5. - STADIUM_CAPACITY_TICK (default 1000) -- item 1.4's capacity arbitration cadence in virtual ticks. No consumer yet; capacity arbitration itself is not on the punch list. Both added following STADIUM_MAX_VM_COUNT's exact pattern: Kconfig.kernel entry, Makefile.starkernel kconfig_int + VM_FEATURE_FLAG_VARS forwarding, starforth_config.h fallback default. stadium.h now includes starforth_config.h and carries two more C99-portable compile-time checks proving both symbols are defined and sane, same discipline as the byte-count checks. Declaration only -- not inventing the consuming logic to close this out early. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f, re-run after the reopening. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d55ec3241b |
starkernel: item 3.1 -- the Stadium cell and header
Punch list §25 item 3.1 complete. Defines StadiumPatronHeader and StadiumContinuationCell in new include/starkernel/vm/stadium.h, unioned as StadiumCell per §3's closed two-valued union. src/starkernel/vm/stadium.c added to Makefile.starkernel's LOADER_EXTRA_SRCS/KERNEL_EXTRA_SRCS so the header's compile-time size checks are actually compiled, not merely included by something that never builds. Discriminator ruled an external side bitmap (Captain Bob), not a header field -- amended into §3 and §23.3 before this code was written. Item 3.1 declares the bitmap's purpose/indexing in a comment only; allocating it is item 3.2's scope. Both cell shapes counted for real at exactly 64 bytes with zero compiler-inserted padding (three C99-portable negative-array-size assertions -- no _Static_assert, this project targets C99). Header matches §23.3's original 32+32 split unchanged, since the discriminator moving outside the cell left nothing to compete for that space. Continuation cell matches item 1.12's 4+60 figure unchanged for the same reason. Verified the size assertion is actually live: broke it to 63, confirmed the build failed with the expected negative-array-size error, restored it, confirmed a clean compile. Verified: three-architecture boot (amd64, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-2.2 baseline. Confirmed stadium.o present in both obj/loader/vm and obj/kernel/vm post-build on amd64, closing the gap the item-2.2 WIP exposed (an uncompiled header proves nothing). Left open, not fabricated: §23.4 #2 ("does a typical message fit in one cell") is unanswerable today -- no message patron struct exists anywhere in this tree yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
b0416794de |
starkernel: item 2.2 complete -- bound the VM registry
Wires the birth-refusal check into capsule_birth_baby(): calls vm_registry_live_count() (added in the prior WIP commit) between capsule validation and vm_registry_alloc(), returning the new CAPSULE_RUN_ERR_FLEET_FULL and logging via capsule_parity_log_birth_failed() before any EMBRYO registry slot is consumed. Also fixes a gap in that WIP commit: STADIUM_MAX_VM_COUNT was only ever defined via a Kconfig .config-driven -D flag, with no fallback default the way every sibling knob in starforth_config.h has -- a build with no .config present (this one) failed with the macro undeclared. Added STARFORTH_CONFIG_STADIUM_MAX_VM_COUNT_DEFAULT (4, matching Kconfig.kernel) following the existing HEARTBEAT_INFERENCE_FREQUENCY pattern exactly. All three architectures boot clean to ok> with dict_hash=0x3d4e1daf289da94f, matching the item-0.10/2.1 baseline. FABRIC.md item 2.2 checked off. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
542d7dbf0d |
starkernel: restate VM fleet heat transfer on the virtual tick
Punch list §25 item 2.1 complete. vm_physics_touch() no longer takes a wall-clock timestamp -- it reads fleet_heartbeat_tick_count internally, which is execution-paced (vm_runtime.c:143), not wall-clock. VMPhysics.last_active_ns -> last_active_tick, VMFleetTouchSample.elapsed_us -> elapsed_ticks, and a new explicit `touched` flag replaces the old `> 0` sentinel (tick 0 is a legitimate value a first touch can land on, unlike wall-clock ns). Verified: three-architecture boot (amd64 x2, aarch64, riscv64), all reaching ok> with identical dict_hash=0x3d4e1daf289da94f matching the item-0.10 baseline. No new compiler warnings in the touched files. Honestly flagged, not fixed: with Tripod pruned to Hera alone (item 0.1), vm_physics_touch()'s fan-out has no other live VM to pull heat from, so the fleet-heat-sum acceptance criterion is trivially satisfied rather than genuinely stress-tested -- a real check needs Phase 4's multi-VM fleet. fleet_transfer_slope_q48's seed (65536/3) was calibrated for elapsed microseconds and has not been re-fit for elapsed ticks; left as-is rather than guessed, deferred to item 5.1's DoE work. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
024f8a84b5 |
starkernel: Phase 0 acceptance -- three-arch boot + reproducibility (item 0.10)
Adds a one-time boot diagnostic in kernel_main.c, right before sk_repl() is entered: bounded wait for 3 real heartbeat ticks, then prints tick count, TIME-TRUST, and variance. Needed because printing immediately after apic_timer_start() (as first tried) measured 1 tick on amd64 and 0 on riscv64 -- not evidence the heartbeat doesn't work, just that almost no wall time elapses between arming the timer and that point in boot; report it honestly rather than let it stand as a false negative. Verified this session (logs/20260804-001727, -001805, -001850, -001948, -002021): - All three architectures boot to ok>. - Tick count non-zero: amd64 4, riscv64 3, aarch64 3. - riscv64: trust=Q48_ONE exactly, variance=0 -- architecturally invariant counter, as designed. - amd64: dict_hash=0x3d4e1daf289da94f, identical to the pre-item-0.8 baseline (logs/20260803-231322) -- unchanged output, satisfying the GAP-A1 control. - Two consecutive amd64 boots produced the identical dict hash -- reproducible, no wall-clock leakage into patron state. Phase 0 (Substrate) is complete. Punch list §25 item 0.10 complete. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
3699be964d |
starkernel: converge the tick path and wire the adaptive heartbeat (item 0.8)
Introduces src/starkernel/heartbeat.c as the shared top/bottom-half implementation of heartbeat_init/tick/service/ticks/trust/state, replacing the per-architecture duplicates in amd64/riscv64/aarch64 timer.c. Each arch's timer.c now contributes only heartbeat_read_counter() (rdtsc / rdtime / CNTPCT_EL0). Per the GAP-A1 ruling the top half stays counter+ latch only; heartbeat_service() (called every REPL idle iteration, unconditionally per FABRIC.md's fidelity note) does the window/variance/ trust work outside interrupt context. vm_tick()'s call sites are unchanged -- the engine still runs on the virtual tick. Per FABRIC.md §26 (ruled 2026-08-03): wires Loop #7's execution-derived stable/volatile signal into the physical re-arm period. vm_runtime.c's existing Loop #7 site now calls heartbeat_set_adaptive_period_ns() with tick_target_ns ratio-rescaled onto a 10ms kernel base (not the hosted 10us HEARTBEAT_TICK_NS -- see §26.3 for the scale mismatch). Each architecture's re-arm function (apic_timer_rearm() on amd64/aarch64, riscv64_timer_rearm()) now converts heartbeat_next_period_ns() to its own raw counter units instead of a fixed constant; amd64 gained a rearm function it didn't previously need, since periodic-mode auto-reload never required one before this item. Verified: all three architectures build with no new warnings and boot cleanly to ok> with dict_hash=0x3d4e1daf289da94f, unchanged from the pre-change baseline -- no regression. Verified NOT achieved: live re-arm period variation under load. A temporary diagnostic (added and reverted) confirmed Loop #7 never actually fired during a live QEMU session -- a synthetic word-execution loop drove ~6,500 executions, past the 1000-tick inference frequency, without tripping vm_tick_inference_engine()'s pre-existing !vm->rolling_window.is_warm gate. That gate predates this item and was not investigated -- out of scope. FABRIC.md's Done-when is amended to record this honestly rather than claim it. Punch list §25 item 0.8 complete (per amended, weaker acceptance -- see the item's own annotation). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
43aa0a2a36 |
aarch64: arm the ARM Generic Timer -- CNTP/CNTHP TVAL+CTL, per-tick re-arm
Punch list §25 item 0.7 complete. This is what finally makes items 0.5 and 0.6 provably work end to end. apic_timer_start(): writes CNTP_TVAL_EL0 (or CNTHP_TVAL_EL2 at EL2 -- aarch64_current_el(), same EL-aware discipline as 0.4-0.6) to s_timer_period_tsc, then CTL.ENABLE=1/IMASK=0, followed by an ISB. The ISB is not decorative: confirmed against Linux's own arch_timer_reg_write_cp15() (arch/arm64/include/asm/arch_timer.h) that only the *control* register write needs synchronising before the enable/mask state is guaranteed visible to the interrupt pipeline -- TVAL/CVAL writes do not carry the same requirement, which is why apic_timer_rearm() omits it. TVAL is architecturally 32-bit but MSR-to-system-register is always a 64-bit instruction form -- passing a uint32_t operand directly failed to build (-Wasm-operand-widths). Fixed by truncating to 32 bits ourselves then zero-extending back to 64 for the operand, which supplies explicit, provably-correct zeros in the RES0 upper field rather than depending on unverified hardware behaviour -- Linux's own driver never exercises this path (it always uses the 64-bit CVAL form instead), so there was no local source to confirm the alternative against. apic_timer_rearm() (new): re-writes TVAL only, no ISB needed. TVAL is relative to "now," not an absolute deadline like riscv64's SBI interface (item 0.3), so there is no drift-correction bookkeeping -- each write means "N ticks from this instant." Wired into aarch64_irq_handler() and called *first*, before heartbeat_tick(), matching riscv64_timer_rearm()'s ordering discipline exactly: the ARM Generic Timer does not auto-reload, so a return path that skips this leaves the interrupt condition latched, which the GIC would redeliver the instant it's EOI'd -- a real storm, the same class of failure item 0.6's verification investigated (and that time found absent, because nothing was armed yet). Verified: builds clean; every generated instruction checked against disassembly, not just reviewed by eye (both EL branches, correct TVAL/CTL register names, single shared ISB in apic_timer_start(), no ISB in apic_timer_rearm()). Boots to ok> with no regression, dict_hash 0x3d4e1daf289da94f unchanged. Rate measured directly against real wall-clock time via QEMU's own -d int trap trace (same method as riscv64's item 0.3), two independent windows: 1,090 interrupts over 11.05 s (98.679 Hz) and 4,031 over 40.88 s (98.614 Hz) -- consistent across both, so this is a real, small, systematic bias (~1.3-1.4% slow), not measurement noise from polling granularity, which would have shrunk with the longer window and did not. Attributed to genuine per-interrupt service latency: TVAL is rewritten mid-ISR, so the trampoline save/restore, GICC_IAR read, EL branch and GICC_EOIR write all lengthen the effective period slightly versus the nominal 10 ms, inherent to any relative-countdown re-arm scheme. Reported as measured, not smoothed over. The interrupt sustained continuously across both windows with no stall and no storm, which is the primary evidence re-arm-every-tick is correct; the small rate bias is overhead, not a defect. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
cabb0e8bd4 |
aarch64: minimal GICv2 driver -- distributor, CPU interface, timer PPI
Punch list §25 item 0.6 complete. Ruling applied (AskUserQuestion, this session): DTB is confirmed unreachable on this system's aarch64 firmware too (qemu-efi-aarch64 2025.11-3ubuntu7, same finding as riscv64's item 0.3), so GICD/GICC base addresses and the timer PPI are named QEMU-virt constants with a recorded caveat, not DTB-discovered as the item originally asked. Nothing here was recalled from memory. Base addresses (GICD 0x08000000, GICC 0x08010000) and the timer PPI (30, non-secure EL1 physical) were read out of QEMU 10.2.1's own internal devicetree via `qemu-system-aarch64 -machine virt,dumpdtb=...`, decoded with this tree's own fdt.c reader rather than a new tool -- correct for this exact QEMU version, not assumed stable across others. Bonus finding from the same dump: PPI 26 for the EL2 hypervisor timer, which item 0.7 will need for its EL2 path. Register offsets within each block (GICD_CTLR, GICC_IAR, etc.) are GICv2 architectural constants, not board-specific, and were cross-checked against Linux's own arm-gic.h driver header rather than recalled either. Acceptance amended before implementing (§25.0 "when an item is genuinely wrong"): the original text required observing a delivered-and-acknowledged timer interrupt, which cannot happen within this item's own scope -- apic_timer_start() (item 0.7) is still the no-op stub, so nothing arms the timer. This is the same defect the earlier review's C2 fix already applied to items 0.2 and 0.5; it was missed here. Acceptance is now: GIC initialises without fault, the IAR/EOIR path is wired into aarch64_irq_handler() and ready, boots with no regression -- item 0.7's tick-advance is what proves delivery, exactly as 0.5 already defers to 0.7. EL-aware (B3, same discipline as items 0.4/0.5): apic_init() selects PPI 30 or 26 from aarch64_current_el(), decided once and cached, not re-derived per interrupt. aarch64_irq_handler() now does real work: reads GICC_IAR (the GICv2 acknowledgement step), dispatches to heartbeat_tick() when the INTID matches the timer PPI, and always completes with GICC_EOIR (INTID 1023 = spurious handled per the GICv2 spec, not as a special case of "unrecognised"). This mirrors exactly how riscv64's item 0.2 built full cause-dispatch logic before its timer was armed in 0.3. Investigated and resolved a real scare during verification: QEMU's `-d int` trace showed 1,728 "Taking exception 5 [IRQ]" events by the time boot reached the prompt, which looked exactly like an interrupt storm (hypothesis: EDK2 firmware leaves CNTP_CTL_EL0 enabled with a stale comparator, and enabling the GIC path exposes it before item 0.7 reprograms the timer). A direct one-shot probe inside aarch64_irq_handler() itself -- ground truth for whether this code path runs at all -- fired zero times across a clean, bounded boot. The trace events were almost certainly from EDK2 firmware's own internal timer usage during its own boot phase, before control passes to this kernel; the earlier conclusion was drawn from the external trace alone without checking that distinction, and the probe (not the trace) is what settled it. Probe code fully reverted; not part of the commit. Verified: builds clean, boots to ok> with no regression, dict_hash 0x3d4e1daf289da94f unchanged from the item 0.1-0.5 baseline, EL banner and IDT-installed lines still print in order, GIC init line confirms PPI 30 selected. Only aarch64-scoped files touched; amd64/riscv64 not rebuilt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
8d8f3aaae2 |
aarch64: split irq_spx into a real save/dispatch/restore/ERET trampoline
Punch list §25 item 0.5 complete.
irq_spx now branches (one instruction, well inside the 128-byte vector slot)
to irq_spx_trampoline, a 672-byte-frame save/restore sequence that calls a
C handler and returns via ERET. The other fifteen vectors are untouched,
still routing to the existing fatal handler.
EL selection (B3) happens once, in aarch64_install_vectors(), not per
interrupt: aarch64_current_el() (item 0.4) picks VBAR_EL1 or VBAR_EL2, and
the same answer is cached in a byte flag (el2_mode_flag) that the trampoline
reads to choose ELR_EL1/SPSR_EL1 vs ELR_EL2/SPSR_EL2 -- the two forms are
genuinely different MRS/MSR encodings, not runtime-selectable operands, so
this is the cheapest correct design: decide once at install time, branch
twice (save, restore) per interrupt afterward. VBAR_EL1 was previously
written unconditionally; this closes that half of item 0.4's known gap.
EL2 is coded from the architecture reference and cannot be boot-tested in
this environment (QEMU's aarch64 virt/EDK2 combination here yields EL1) --
reported as unverified rather than asserted as tested.
FP/SIMD save is not optional (B2, carried from item 0.4's finding that the
build has no -mgeneral-regs-only): the AAPCS64 caller-saved set -- v0-v7,
v16-v31, full 128 bits each -- plus FPSR/FPCR is saved and restored around
the C handler call. v8-v15 are callee-saved by the ABI and deliberately
excluded: the handler, being ordinary compiled C, preserves those itself.
aarch64_irq_handler() (interrupts.c) is deliberately empty. Distinguishing
which interrupt fired needs the GIC's IAR, which does not exist until item
0.6; nothing unmasks or routes any source to this vector yet, so the
function is not reachable during a normal boot. Per the item's own text,
no attempt was made to manufacture an interrupt to exercise this path early
-- 0.6 (GIC) and 0.7 (timer) are what prove it took and returned one.
Verified: every hand-computed frame offset (0, 16, 32 ... 640, frame size
0x2a0=672) checked against the actual disassembly of the built kernel, not
just visually reviewed -- save and restore sequences mirror exactly, and
aarch64_install_vectors' branch on the detected EL, the flag write, and the
trampoline's read of the same flag address all confirmed consistent. Boots
clean on real QEMU output, no regression: dict_hash 0x3d4e1daf289da94f
unchanged from the item 0.1-0.4 baseline, and the item 0.4 EL banner
("AArch64: running at EL1") still prints correctly ahead of "IDT installed.".
Only aarch64-scoped files touched (isr.S, interrupts.c) -- no shared loader
or header changed, so amd64 and riscv64 are provably unaffected; not
rebuilt for this item.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
||
|
|
f43f3f4482 |
aarch64: detect exception level at runtime, cached accessor
Punch list §25 item 0.4 complete. Adds aarch64_current_el() in arch.c: reads CurrentEL[3:2] on first call, caches the result (CurrentEL cannot change post-ExitBootServices, so every consumer gets the same answer without repeating the MRS). Called from arch_interrupts_init() in interrupts.c -- the earliest point with both a working console (up since M1) and a genuine first consumer (vector installation is the first EL-dependent operation) -- and the detected level is printed to the boot log there. Declared via extern-in-place in interrupts.c rather than added to the shared arch.h: "exception level" has no amd64/riscv64 equivalent, matching the convention already used for riscv64_timer_rearm() in item 0.3. Verified on real QEMU output: "AArch64: running at EL1", correctly positioned immediately before "IDT installed." in the serial log. Boots clean, dict_hash 0x3d4e1daf289da94f unchanged from the item 0.1-0.3 baseline. Scope: this item establishes the detection and exposes it; it does not yet change VBAR/ELR/SPSR or timer-register selection to use it. arch_interrupts_init() still writes VBAR_EL1 unconditionally, and now says so explicitly in its own doc comment -- if aarch64_current_el() ever reports 2 on real hardware, exceptions taken at EL2 vector through VBAR_EL2, which nothing programs yet. That gap is items 0.5 (vectors/saved-state) and 0.7 (CNTP vs CNTHP) to close, per FABRIC.md's GAP-B3 finding. The boot-log EL2 case prints a note pointing at both. Only aarch64-scoped files touched (arch.c, interrupts.c) -- no shared loader or header changed, so amd64 and riscv64 are provably unaffected; not rebuilt for this item. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
5784d8a1a8 |
riscv64: finish SBI timer verification and clean up stale timer docs
Punch list §25 item 0.3 complete.
The functional work (FDT reader, `time` CSR switch, SBI TIME extension
arm/re-arm, sie.STIE) was committed separately by Captain Bob as
|
||
|
|
accd79fc70 |
riscv64: integrate minimal flattened devicetree reader and switch timer to time CSR
Punch list §25 item 0.3 NOT complete. - Added `starkernel/fdt.h` and `fdt.c` for minimal read-only devicetree parsing: sufficient for boot-time lookups such as `timebase-frequency`. - Bootloader now captures the devicetree blob (DTB) from `EFI_DTB_TABLE_GUID` into `BootInfo::dtb`. - RISC-V timer subsystem now uses the `time` CSR as the primary timestamp source, abandoning the hardcoded `cycle` frequency assumption. - Timer rate is read from `timebase-frequency` in the DTB when accessible; otherwise, a fallback value is used with a RELATIVE trust level. - Integrated the SBI TIME extension for one-shot timer deadlines, ensuring re-arming occurs after each tick to avoid missing heartbeats. Verified: riscv64 builds clean, boots to the ok> prompt with no regression; `riscv64/timer.c` reports accurate frequencies on QEMU's default firmware. Signed-off-by: Robert Allan James <robert.allan.james@gmail.com> |
||
|
|
f3821ed686 |
riscv64: real trap entry with save/restore and SRET return
Punch list §25 item 0.2 complete. Verified: riscv64 builds clean and boots to the ok> prompt with no regression; dict_hash 0x3d4e1daf289da94f, unchanged from item 0.1's baseline. Disassembly confirms the 320-byte frame, all 16 integer caller-saved registers, the FS check, and SRET on exit; riscv64_trap_entry lands at 0x414fa8, 4-byte aligned as stvec direct mode requires. Not verified, and the item says so: neither new path was exercised. No timer is armed until 0.3, so riscv64_interrupt_handler never ran, and no exception occurred during boot, so the fatal path was not observed -- it is preserved structurally, same branch to the same unchanged handler. This is why C2 rewrote the acceptance to no-regression rather than to having taken and returned from a trap. Register set is the LP64D psABI caller-saved list, not this document's summary: integer ra/t0-t6/a0-a7 (16), FP ft0-ft11/fa0-fa7 (20) plus fcsr, and sepc + sstatus. Callee-saved registers are the C handler's responsibility. The FP half is conditional on sstatus.FS != Off, which the item did not anticipate. Nothing in boot.S or kernel_entry.S programs FS, so its value is whatever firmware leaves; touching an f-register with FS == Off raises an illegal-instruction trap, and doing that inside the trap handler would be unrecoverable. Omitting the FP save is not an option either -- the built riscv64 image contains 530 FP instructions (fld, fmul.d, fcvt.lu.d among them), confirming B2's finding against the binary rather than the build flags alone. So the save is conditional, and sstatus is restored after the f-registers. Dispatch: scause bit 63 routes to riscv64_interrupt_handler with scause in a0; cause 5 (supervisor timer) calls heartbeat_tick(). Other causes are ignored rather than fatal -- none are enabled to arrive. Everything else still falls through to riscv64_exception_handler, unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
c3e4fc282c |
capsules: prune init.4th to Hera alone
Punch list §25 item 0.1 complete. Verified: all three architectures build clean and boot to the ok> prompt with Hera alone. Blocks executed are exactly 2057 -> 2049 (-> lib.4th/4050) -> 2050. Zero occurrences of "Hermes" or "Tripod" in any of the three serial logs, and the only parity record is MAMA_INIT -- no baby VM is born. mkcapsule --lint passes 26 files, 0 failing, 0 violations. Deleted blocks 2051, 2052, 2053, 2054, 2055, 2056, 2058, 2059 -- readiness handshake, broadcast test, TRIPOD-TEST, HERMES-E2E and the fleet-DoE scaffolding. Edited 2057 (banner), 2049 (dropped both births with their CD-INIT calls and the common:msg.4th / process.4th loads, which are wholly Hermes-dependent; kept lib.4th; VM-TREE and VM-CHILDREN no longer name absent children) and 2050 (kept the BOOT-BANNER call, dropped the two calls to the deleted words). capsules/hermes/ and capsules/artemis/ untouched on disk. New Hera-alone parity baseline, identical across all three ISAs: dict_hash=0x3d4e1daf289da94f capsule_hash=0xb4c4b5559146a3bd This supersedes the pre-prune baselines in logs/ and is what item 0.10's double-boot reproducibility check compares against. Commit contents beyond the item's own edit, noted rather than slipped in: capsules/BLOCK_MAP.md is regenerated by any build; the three serial logs are this item's acceptance evidence and CLAUDE.md requires committing them; the DoE CSVs are auto-extracted by the qemu target on every run. Leaving generated output from this item's acceptance run for a later item to sweep up would be worse than including it here. Reported, not fixed: tools/mkcapsule.c emits two -Wstringop-truncation warnings on the host build (:404, :562), pre-existing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
7597a9ccd4 |
Add Artemis compudynamics implementation plan; add stress campaign fixture
The 30-replicate Artemis surface-stress campaign ran across all three architectures: 30 reps x 50 trials x 3 arches = 4500 trials, zero failures. The block_words.c stale-pointer cache-aliasing fix holds at scale. Adds ART-STRESS-CAMPAIGN (block 4174) plus ART-STRESS-REP rep-tagging in the CSV header/summary emitters, so a multi-replicate run is distinguishable in the serial log. Campaign auto-invoke is left enabled in block 4170 for now; Makefile.starkernel's QEMU boot deadlines stay at 12h to accommodate long-running experiments. Adds docs/working/architecture/ARTEMIS-COMPUDYNAMICS-IMPLEMENTATION-PLAN-20260802.md, which documents the real gap this campaign exposed: block heat and message heat do not decay at all. ART-TICK has zero call sites anywhere in the tree, and HERMES-TICK has zero C call sites -- every caller is Hera poking it by hand. BLK-HEAT@/MSG-HEAT@ read a number nothing ages, so blocks never reap by cooling and message TTL never expires on its own. The plan mirrors word-level physics as the reference model: lazy decay at each access point against vm->heartbeat.tick_count, plus a bounded background sweep with a resumable cursor (the existing answer to "sweeping 22,998 blocks per tick is too expensive"). Phase 1 Artemis, Phase 2 Hermes, Phase 3 K participation deferred behind the Logical BAM. The plan's preamble also records a wrong turn taken while investigating: chasing VM-fleet heat instead of block heat, and building synthetic Hera-driven VM-EXEC calls to force a physics reading -- which TRIPOD.md prohibits outright. That work was reverted; the record is kept so it isn't repeated. Status: plan approved in shape, NOT final and NOT started. Six open questions need answers and further design discussion is pending. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
1cb68502fb |
Add Artemis stress test for detecting cache aliasing bugs. Include statistical hypothesis evaluations, fix validation data, and run reports for validation across architectures.
Signed-off-by: Robert Allan James <robert.allan.james@gmail.com> |
||
|
|
148c4aa12c |
Fix silent disk overwrite of unrecognized Artemis disks
The generic block subsystem (blk_format_or_load_disk) auto-reformatted any disk lacking its own low-level 'STFR' header at attach time, before Artemis's Forth-level BLANK/LithosAnanke/Unrecognized classification ever ran -- so ART-HALT-UNRECOG's "Disk preserved" message was false. Split detection from commit: an unrecognized/blank disk is now left PROVISIONAL (geometry computed in memory only, all writes refused) until explicitly confirmed via the new blk_subsys_confirm_format() / BLK-CONFIRM-FORMAT primitive. Artemis calls it from ART-FORMAT and ART-RESUME, never from ART-HALT-UNRECOG. Verified on amd64/aarch64/riscv64: parity intact (identical dict_hash), normal recognized-disk resume + persist-read unaffected, and a regenerated disk/artemis-unrecognized-test.img (the old copy had itself been silently corrupted by this exact bug) now stays byte-for-byte identical across a halted boot on amd64 and riscv64. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
757ce97dc1 | Add riscv64 benchmark results to CSV output | ||
|
|
a852db2209 | misc | ||
|
|
a5ed8c3d87 | Initial commit — LithosAnanke kernel |