From a4615148975bed241ae26ffa2655dc9c407107d8 Mon Sep 17 00:00:00 2001 From: polwex Date: Mon, 6 Oct 2025 17:07:33 +0700 Subject: maybe now maybe now --- bootvere.sh | 6 +- ocaml/BOOT_FLOW.md | 172 ++++++++++++++++++++++++ ocaml/BOOT_PROCESS.md | 47 +++++++ ocaml/FINDINGS.md | 113 ++++++++++++++++ ocaml/lib/boot.ml | 271 ++++++++++++++++++++++++++++++-------- ocaml/test/dune | 10 ++ ocaml/test/examine_ivory.ml | 84 ++++++++++++ ocaml/test/test_life_formula.ml | 48 +++++++ ocaml/test/test_two_stage_boot.ml | 27 ++-- vere/build.zig | 10 ++ vere/pkg/noun/life_test.c | 96 ++++++++++++++ vere/pkg/noun/vortex.c | 28 +++- vere/pkg/vere/boot_tests.c | 48 +++++++ vere/pkg/vere/king.c | 7 +- vere/pkg/vere/main.c | 2 + vere/pkg/vere/mars.c | 34 ++++- vere/pkg/vere/solid_boot_test.c | 178 +++++++++++++++++++++++++ zod/.urb/log/0i0/data.mdb | Bin 12832768 -> 12832768 bytes zod/.urb/log/0i0/lock.mdb | Bin 8192 -> 8192 bytes zod/.urb/log/0i0/vere.txt | 2 +- zod/.vere.lock | 2 +- 21 files changed, 1100 insertions(+), 85 deletions(-) create mode 100644 ocaml/BOOT_FLOW.md create mode 100644 ocaml/FINDINGS.md create mode 100644 ocaml/test/examine_ivory.ml create mode 100644 ocaml/test/test_life_formula.ml create mode 100644 vere/pkg/noun/life_test.c create mode 100644 vere/pkg/vere/solid_boot_test.c diff --git a/bootvere.sh b/bootvere.sh index 8c3fd8a..1186667 100644 --- a/bootvere.sh +++ b/bootvere.sh @@ -1 +1,5 @@ -vere/zig-out/x86_64-linux-musl/urbit -B ocaml/solid.pill -F zod -v +cd vere +zig build +cd .. +rm -rf ./zod +vere/zig-out/x86_64-linux-musl/urbit -B ocaml/solid.pill -F zod diff --git a/ocaml/BOOT_FLOW.md b/ocaml/BOOT_FLOW.md new file mode 100644 index 0000000..7f9d417 --- /dev/null +++ b/ocaml/BOOT_FLOW.md @@ -0,0 +1,172 @@ +# Complete Boot Flow in C Vere (`-B solid.pill`) + +## The Simple Truth + +When you run `vere -B solid.pill`, here's exactly what happens: + +### Step 0: Command Line Processing + +**Location**: `main.c:418` +```c +case 'B': + u3_Host.ops_u.pil_c = _main_repath(optarg); // Store pill filepath +``` + +### Step 1: Load Pill File (`_boothack_pill`) + +**Location**: `king.c:611-613` +```c +if ( 0 != u3_Host.ops_u.pil_c ) { + u3l_log("boot: loading pill %s", u3_Host.ops_u.pil_c); + pil = u3m_file(u3_Host.ops_u.pil_c); // Load raw bytes into memory +} +``` + +Returns: `[pil arv]` where `pil` is raw pill bytes, `arv` is optional filesystem + +### Step 2: Cue the Pill Bytes (`u3_mars_boot`) + +**Location**: `mars.c:1958` +```c +u3_weak jar = u3s_cue_xeno(len_d, hun_y); // Cue the pill bytes +if ( (u3_none == jar) || (c3n == u3r_p(jar, c3__boot, &com)) ) { + fprintf(stderr, "boot: parse fail\r\n"); + exit(1); +} +``` + +Expects pill structure: `[%boot com]` + +### Step 3: Extract Events from Pill (`_mars_boot_make`) + +**Location**: `mars.c:1971` +```c +_mars_sift_pill(u3k(pil), &bot, &mod, &use, &cax) +``` + +Pill structure: `[%pill %solid [bot mod use]]` +- `bot`: Lifecycle events (boot sequence) +- `mod`: Module/vane events +- `use`: Userspace/app events + +### Step 4: Write Events to Disk + +**Location**: `mars.c:1985-1987` +```c +u3_disk_plan_list(log_u, ova); // Write events to LMDB +u3_disk_sync(log_u); // Sync to disk +``` + +### Step 5: Read Events Back and Boot + +**Location**: `mars.c:1993` +```c +_mars_do_boot(log_u, log_u->dun_d, cax); // Boot from disk +``` + +Inside `_mars_do_boot` (line 1107): +```c +eve = u3_disk_read_list(log_u, 1, eve_d, &mug_l); // Read from disk +``` + +Then (line 1160): +```c +u3v_boot(eve); // Boot with event list! +``` + +## Event Structure Details + +### Event Creation in `_mars_boot_make` (`mars.c:1814-1836`) +```c +u3_noun now = u3_time_in_tv(&inp_u->tim_u); +u3_noun eve = u3kb_flop(bot); // Start with bot events (NO TIMESTAMP!) + +u3_noun lit = u3kb_weld(mod, use); +while ( u3_nul != t ) { + u3x_cell(t, &i, &t); + now = u3ka_add(now, u3k(bit)); + eve = u3nc(u3nc(u3k(now), u3k(i)), eve); // Add timestamped event [now i] +} + +*ova = u3kb_flop(eve); // Final event list +``` + +**KEY**: Bot events are **NOT timestamped**, mod/use events ARE timestamped as `[timestamp event]` + +### Step 4: Write Events to Disk + +**Location**: `mars.c:1955` +```c +u3_disk_plan_list(log_u, ova); // Write events to LMDB +u3_disk_sync(log_u); // Sync to disk +``` + +### Step 5: Read Events Back and Boot (`_mars_do_boot`) + +**Location**: `mars.c:1107` +```c +eve = u3_disk_read_list(log_u, 1, eve_d, &mug_l); // Read from disk +``` + +Each event is cued from disk: +```c +// disk.c: +*job = u3ke_cue(u3i_bytes(len_i - 4, dat_y + 4)); +ven_u->eve = u3nc(job, ven_u->eve); // Cons onto list +return u3kb_flop(ven_u->eve); // Return flipped list +``` + +## Summary: The Complete `-B` Flow + +1. **Load**: `u3m_file()` loads pill bytes from filepath +2. **Cue**: `u3s_cue_xeno()` deserializes to `[%boot com]` structure +3. **Parse**: `_mars_boot_make()` extracts bot/mod/use events and timestamps them +4. **Persist**: `u3_disk_plan_list()` writes to LMDB, `u3_disk_sync()` commits +5. **Read**: `u3_disk_read_list()` reads events back from disk +6. **Boot**: `u3v_boot(eve)` boots with the event list + +## What We Need to Implement in OCaml + +Just follow the same pattern: + +```ocaml +(* Load pill file *) +let pill_bytes = load_file pill_path in + +(* Cue the pill *) +let pill_noun = Serial.cue pill_bytes in + +(* Extract [%boot com] *) +let com = extract_boot_structure pill_noun in + +(* Parse into bot/mod/use events *) +let (bot, mod_, use_) = parse_pill_structure com in + +(* Timestamp mod/use events (bot events stay bare) *) +let event_list = build_event_list bot mod_ use_ in + +(* For now, skip disk persistence and boot directly *) +Boot.boot event_list +``` + +**Key Insight**: Bot events are **NOT timestamped** (they're bare nouns), while mod/use events **ARE timestamped** as `[timestamp event]` pairs. + +## The "eve=null" Mystery Solved + +From the actual boot log: +``` +lite: arvo formula 4ce68411 +u3v_life: eve=null (atom=yes cell=no) ← First call (ivory pill) +u3v_life: completed successfully +lite: core 641296f + +_mars_do_boot: first event is atom ← Bot events are atoms! +u3v_boot: processing 10 events +u3v_life: eve=null (atom=yes cell=no) ← Second call (from vortex.c) +``` + +There are **TWO** `u3v_life` calls: +1. First: Ivory pill bootstrap (eve=null creates initial kernel) +2. Second: Inside `u3v_boot()` which processes the 10 events + +The `eve=null` log in the second call is likely referring to the **original** `eve` parameter before it's been processed, NOT the actual subject passed to the lifecycle formula! diff --git a/ocaml/BOOT_PROCESS.md b/ocaml/BOOT_PROCESS.md index 08987ef..5a621b6 100644 --- a/ocaml/BOOT_PROCESS.md +++ b/ocaml/BOOT_PROCESS.md @@ -57,6 +57,53 @@ CLAUDE: **Status in OCaml:** ❌ Not applicable for solid pill boot path +--- + +## ✨ CRITICAL DISCOVERY: Ivory Pill Structure (2025-01-06) + +**Finding:** The ivory.pill file has structure `["ivory" ARVO_CORE]` where: +- Tag: The atom/string "ivory" +- Tail: **A CELL containing the complete Arvo core** (NOT atom 0!) + +**Verified by:** `test/examine_ivory.ml` which loads and analyzes ivory.pill: +``` +Tag: ivory +Tail type: CELL +Tail is a CELL +Head type: cell +Tail type: cell +✓ Has slot 2 and 3 (it's a cell with head and tail) +``` + +**This means:** +1. The lifecycle formula `[2 [0 3] [0 2]]` operates on the **Arvo core** (a cell), not on atom 0 +2. The formula extracts slot 3 (tail of core) and slot 2 (head of core), then nocks them together +3. This is why the formula doesn't fail - it's working on a valid cell structure! + +**Boot sequence clarification:** +- `_cv_lite()` extracts `tal` from `["ivory" tal]` → `tal` is the **Arvo core** +- `u3v_life(tal)` runs the lifecycle formula **on the Arvo core itself** +- The result is the updated/initialized Arvo kernel + +**Mystery resolved:** +The confusing C Vere log showing "eve=null" must refer to a DIFFERENT usage context (possibly for solid pills or after the ivory is bootstrapped). The ivory pill tail is definitely a CELL, not null! + +**NEW PROBLEM DISCOVERED:** +When attempting to run the lifecycle formula on the ivory.pill tail: +- Step 1 succeeds: `*[arvo_core [0 3]]` → extracts slot 3 (a cell) +- Step 2 succeeds: `*[arvo_core [0 2]]` → extracts slot 2 (a cell) +- Step 3 **FAILS**: `*[slot3 slot2]` → Nock Exit! + +This means the ivory.pill file's Arvo core **cannot be executed** by the lifecycle formula! + +**HYPOTHESIS:** +The embedded ivory pill in C Vere (from ivory.c) might be DIFFERENT from the ivory.pill FILE. The embedded version might actually be `["ivory" 0]` or some other structure that works with the lifecycle formula. + +**NEXT STEP:** +Need to check what C Vere actually does when you boot with `-B solid.pill`. Does it: +1. Load embedded ivory first? OR +2. Skip ivory entirely and boot directly from solid pill? + ```c diff --git a/ocaml/FINDINGS.md b/ocaml/FINDINGS.md new file mode 100644 index 0000000..397924c --- /dev/null +++ b/ocaml/FINDINGS.md @@ -0,0 +1,113 @@ +# Critical Boot System Findings (2025-01-06) + +## Summary +We discovered that the ivory.pill file structure is `["ivory" ARVO_CORE]` where the tail is a CELL containing the complete Arvo core, NOT atom 0. However, the lifecycle formula `[2 [0 3] [0 2]]` FAILS when executed on this Arvo core. + +## Detailed Findings + +### 1. Ivory Pill Structure +**Verified by:** `test/examine_ivory.ml` + +``` +Tag: ivory +Tail type: CELL + Head type: cell + Tail type: cell +✓ Has slot 2 and 3 +``` + +The ivory.pill file contains: +- Tag: The atom "ivory" +- Tail: **A complete Arvo core (CELL)** - NOT null/atom 0! + +### 2. Lifecycle Formula Execution Test +**Tested by:** `test/test_two_stage_boot.ml` + +Running `[2 [0 3] [0 2]]` on the Arvo core: +- ✓ Step 1: `*[core [0 3]]` succeeds → returns cell +- ✓ Step 2: `*[core [0 2]]` succeeds → returns cell +- ✗ Step 3: `*[slot3 slot2]` **FAILS with Nock Exit** + +### 3. What This Means + +The ivory.pill file's Arvo core **cannot be bootstrapped** using the lifecycle formula in our implementation! This leads to two possibilities: + +**Possibility A:** The embedded ivory in C Vere is DIFFERENT from ivory.pill +- Embedded might be `["ivory" 0]` or some simpler structure +- ivory.pill file might be for a different use case + +**Possibility B:** C Vere's `-B solid.pill` path doesn't use ivory at all +- Your log showed `u3v_life: eve=null` during solid pill boot +- Maybe solid pill boot skips the ivory pill entirely? +- The `u3v_boot_lite()` code in mars.c was COMMENTED OUT! + +## Questions to Answer + +1. **Does `-B solid.pill` load ivory.pill at all?** + - Need to trace mars.c boot path for `-B` flag + - Check if embedded ivory is even used + +2. **What is eve=null in your C Vere log?** + - If eve is null (atom 0), how does `[2 [0 3] [0 2]]` work on it? + - Our test proves it CANNOT work on atom 0! + +3. **Is ivory.pill the right file to use?** + - Maybe there's a different pill for bootstrapping? + - Or maybe solid.pill contains everything needed? + +## C Vere Test Results + +**Test Created**: `vere/pkg/noun/life_test.c` +**Built with**: `zig build life-test` + +**Result**: +``` +Testing lifecycle formula [2 [0 3] [0 2]] on null + +Formula: [2 [0 3] [0 2]] +Subject: 0 (null) + +✗ FAILED! +Error: : %exit + +This confirms the formula CANNOT work on atom 0! +``` + +**PROVEN**: The lifecycle formula `[2 [0 3] [0 2]]` **FAILS** on atom 0 in C Vere! + +## The Contradiction + +Your boot log showed: +``` +u3v_boot: processing 10 events +u3v_life: eve=null (atom=yes cell=no) +u3v_life: completed successfully +``` + +But our C test PROVES this is impossible! The lifecycle formula cannot succeed on null! + +## Possible Explanations + +1. **"eve=null" doesn't mean the lifecycle formula is called on null** + - Maybe it's just logging what the original `eve` was before processing? + - The actual u3v_life call might receive something else? + +2. **The log is from a DIFFERENT u3v_life call** + - Maybe there are TWO separate calls to u3v_life? + - One with ivory pill's core (succeeds) + - One that's never actually executed (logged as null)? + +3. **There's special case handling we're missing** + - Maybe C Vere checks for null and skips u3v_life entirely? + - The log might be misleading? + +## Next Steps + +1. Add MORE detailed logging to C Vere's u3v_life to see: + - Exact eve structure being passed + - Whether formula actually executes + - What the result is + +2. Trace where u3v_life is called from during `-B solid.pill` boot + +3. Check if there's special handling for null in u3v_boot or mars.c diff --git a/ocaml/lib/boot.ml b/ocaml/lib/boot.ml index 630da3b..ce30f2f 100644 --- a/ocaml/lib/boot.ml +++ b/ocaml/lib/boot.ml @@ -148,12 +148,6 @@ let boot_fake state = *) let life eve = try - (* Build lifecycle formula: [2 [0 3] [0 2]] *) - let lyf = Noun.cell (Noun.atom 2) - (Noun.cell - (Noun.cell (Noun.atom 0) (Noun.atom 3)) - (Noun.cell (Noun.atom 0) (Noun.atom 2))) in - Printf.printf "[Boot] Running lifecycle formula [2 [0 3] [0 2]]...\n%!"; (* Check if eve is null (for ivory pill boot) *) @@ -177,9 +171,27 @@ let life eve = end; (* Run lifecycle formula *) + Printf.printf "[Boot] About to execute: *[eve [2 [0 3] [0 2]]]\n%!"; + Printf.printf "[Boot] This expands to: *[*[eve [0 3]] *[eve [0 2]]]\n%!"; + + (* First, manually compute the two parts to see where it fails *) let gat = try - Nock.nock_on eve lyf + (* Step 1: Compute *[eve [0 3]] = slot 3 of eve *) + Printf.printf "[Boot] Step 1: Computing *[eve [0 3]] (slot 3 of subject)...\n%!"; + let slot3_result = Nock.nock_on eve (Noun.cell (Noun.atom 0) (Noun.atom 3)) in + Printf.printf "[Boot] ✓ Slot 3 computed: %s\n%!" + (if Noun.is_cell slot3_result then "cell" else "atom"); + + (* Step 2: Compute *[eve [0 2]] = slot 2 of eve *) + Printf.printf "[Boot] Step 2: Computing *[eve [0 2]] (slot 2 of subject)...\n%!"; + let slot2_result = Nock.nock_on eve (Noun.cell (Noun.atom 0) (Noun.atom 2)) in + Printf.printf "[Boot] ✓ Slot 2 computed: %s\n%!" + (if Noun.is_cell slot2_result then "cell" else "atom"); + + (* Step 3: Compute *[slot3_result slot2_result] *) + Printf.printf "[Boot] Step 3: Computing *[slot3 slot2] (nock slot-2 formula on slot-3 subject)...\n%!"; + Nock.nock_on slot3_result slot2_result with e -> Printf.printf "[Boot] ✗ Nock failed during lifecycle: %s\n%!" (Printexc.to_string e); @@ -237,56 +249,205 @@ let boot state eve_list = with e -> Error ("Boot failed: " ^ Printexc.to_string e) -(* Boot from ivory pill - the lightweight boot sequence +(* Parse solid pill structure: [%boot [%pill %solid [bot mod use]]] + * + * Following C Vere mars.c:1730 _mars_sift_pill + *) +let parse_solid_pill pil = + (* Extract [%boot com] *) + if not (Noun.is_cell pil) then + Error "Pill must be a cell" + else + let tag = Noun.head pil in + let com = Noun.tail pil in + + (* Check for %boot tag *) + let boot_tag = Z.of_string "1953654151028" in (* "boot" *) + + match tag with + | Noun.Atom z when Z.equal z boot_tag -> + (* Now parse com structure *) + if not (Noun.is_cell com) then + Error "Pill com must be a cell" + else + (* com is [[pill typ] [bot mod use]] *) + let fst = Noun.head com in + let snd = Noun.tail com in + + if not (Noun.is_cell fst) then + Error "Pill fst must be a cell" + else + let pill_tag = Noun.head fst in + let _typ = Noun.tail fst in + + (* Check for %pill tag *) + let pill_atom = Z.of_string "1819633778" in (* "pill" *) + + match pill_tag with + | Noun.Atom z when Z.equal z pill_atom -> + (* Extract [bot mod use] from snd *) + if not (Noun.is_cell snd) then + Error "Events structure must be a cell" + else + let bot = Noun.head snd in + let rest = Noun.tail snd in + + if not (Noun.is_cell rest) then + Error "Mod/use structure must be a cell" + else + let mod_ = Noun.head rest in + let use = Noun.tail (Noun.head (Noun.tail rest)) in + + Ok (bot, mod_, use) + | _ -> + Error "Expected %pill tag" + | _ -> + Error "Expected %boot tag" + +(* Build event list following C Vere mars.c:1814-1836 * - * Ivory pills have structure: ["ivory" core] - * The core contains a lifecycle formula that must be executed + * Key: Bot events are NOT timestamped (bare atoms/cells) + * Mod/use events ARE timestamped as [timestamp event] *) -let boot_ivory ~fs state pill_path = - Printf.printf "[Boot] Booting from ivory pill...\n%!"; +let build_event_list bot mod_ use_ = + (* Count events *) + let rec count_list noun = + match noun with + | Noun.Atom z when Z.equal z Z.zero -> 0 + | Noun.Cell (_, rest) -> 1 + count_list rest + | _ -> 0 + in - match load_pill ~fs pill_path with - | Error err -> - let msg = match err with - | FileNotFound s -> "File not found: " ^ s - | InvalidPill s -> "Invalid pill: " ^ s - | BootFailed s -> "Boot failed: " ^ s - in - Printf.printf "[Boot] Error: %s\n%!" msg; + let bot_c = count_list bot in + let mod_c = count_list mod_ in + let use_c = count_list use_ in + + Printf.printf "[Boot] Building event list:\n%!"; + Printf.printf " Bot events: %d (NO timestamp)\n%!" bot_c; + Printf.printf " Mod events: %d (WITH timestamp)\n%!" mod_c; + Printf.printf " Use events: %d (WITH timestamp)\n%!" use_c; + Printf.printf " Total: %d events\n%!" (bot_c + mod_c + use_c); + + (* Get current time in Urbit format (128-bit @da timestamp) *) + let now_timeval = Unix.gettimeofday () in + (* Convert to microseconds since Unix epoch *) + let now_us = Int64.of_float (now_timeval *. 1_000_000.0) in + (* Urbit epoch is ~292 billion years before Unix epoch + For now, use simplified timestamp *) + let now = Noun.Atom (Z.of_int64 now_us) in + + (* 1/2^16 seconds increment *) + let bit = Noun.Atom (Z.shift_left Z.one 48) in + + (* Helper: flip a list *) + let rec flip acc noun = + match noun with + | Noun.Atom z when Z.equal z Z.zero -> acc + | Noun.Cell (h, t) -> flip (Noun.Cell (h, acc)) t + | _ -> acc + in + + (* Start with flipped bot events (NO timestamp) *) + let eve = flip (Noun.Atom Z.zero) bot in + + (* Weld mod and use lists *) + let rec weld l1 l2 = + match l1 with + | Noun.Atom z when Z.equal z Z.zero -> l2 + | Noun.Cell (h, t) -> Noun.Cell (h, weld t l2) + | _ -> l2 + in + + let lit = weld mod_ use_ in + + (* Add timestamped events *) + let rec add_timestamped acc now_ref noun = + match noun with + | Noun.Atom z when Z.equal z Z.zero -> acc + | Noun.Cell (event, rest) -> + (* Increment timestamp *) + let new_now = match !now_ref, bit with + | Noun.Atom n, Noun.Atom b -> Noun.Atom (Z.add n b) + | _ -> !now_ref + in + now_ref := new_now; + + (* Create [timestamp event] pair *) + let stamped = Noun.Cell (new_now, event) in + + (* Cons onto accumulator *) + let new_acc = Noun.Cell (stamped, acc) in + + add_timestamped new_acc now_ref rest + | _ -> acc + in + + let now_ref = ref now in + let eve_with_stamped = add_timestamped eve now_ref lit in + + (* Flip final list *) + let ova = flip (Noun.Atom Z.zero) eve_with_stamped in + + Printf.printf "[Boot] ✓ Event list built: %d events\n%!" (count_list ova); + ova + +(* Boot from solid pill - following C Vere -B flag logic + * + * This follows the exact flow from BOOT_FLOW.md: + * 1. Load pill bytes from file + * 2. Cue to get [%boot com] structure + * 3. Parse into bot/mod/use events + * 4. Timestamp mod/use events (bot stays bare) + * 5. Boot with event list + * + * Skipping disk persistence for now (steps 4-5 in C flow) + *) +let boot_solid ~fs state pill_path = + Printf.printf "\n%!"; + Printf.printf "═══════════════════════════════════════════════════\n%!"; + Printf.printf " Solid Pill Boot (Following C Vere -B Logic)\n%!"; + Printf.printf "═══════════════════════════════════════════════════\n\n%!"; + + (* Step 1: Load pill file *) + Printf.printf "[1] Loading %s...\n%!" pill_path; + + let file_path = Eio.Path.(fs / pill_path) in + let pill_bytes = Eio.Path.load file_path |> Bytes.of_string in + + Printf.printf " ✓ Loaded %d bytes\n\n%!" (Bytes.length pill_bytes); + + (* Step 2: Cue the pill *) + Printf.printf "[2] Cuing pill...\n%!"; + let pil = Serial.cue pill_bytes in + Printf.printf " ✓ Cued successfully\n\n%!"; + + (* Step 3: Parse pill structure *) + Printf.printf "[3] Parsing pill structure...\n%!"; + match parse_solid_pill pil with + | Error msg -> + Printf.printf " ✗ Parse failed: %s\n%!" msg; Error msg - | Ok pill -> - (* Check if pill has ivory tag *) - if not (Noun.is_cell pill.kernel) then - Error "Ivory pill must be a cell" - else begin - let hed = Noun.head pill.kernel in - let tal = Noun.tail pill.kernel in - - (* Check for "ivory" tag *) - (* "ivory" as cord (little-endian): 0x79726f7669 = 521610950249 *) - let ivory_tag = Z.of_string "521610950249" in - - match hed with - | Noun.Atom z when Z.equal z ivory_tag -> - Printf.printf "[Boot] ✓ Found ivory tag\n%!"; - Printf.printf "[Boot] Running lifecycle formula...\n%!"; - - (try - let start = Unix.gettimeofday () in - let core = life tal in - let elapsed = Unix.gettimeofday () -. start in - - Printf.printf "[Boot] ✓ Lifecycle completed in %.4fs\n%!" elapsed; - Printf.printf "[Boot] Setting Arvo core...\n%!"; - - State.boot state core; - Printf.printf "[Boot] ✓ Ivory pill booted!\n%!"; - Ok () - with e -> - Error ("Lifecycle failed: " ^ Printexc.to_string e)) - - | _ -> - Printf.printf "[Boot] Warning: No ivory tag found, trying regular boot...\n%!"; - boot_from_pill state pill - end + | Ok (bot, mod_, use_) -> + Printf.printf " ✓ Extracted bot/mod/use events\n\n%!"; + + (* Step 4: Build event list (C Vere style) *) + Printf.printf "[4] Building event list (C Vere style)...\n%!"; + let ova = build_event_list bot mod_ use_ in + Printf.printf "\n%!"; + + (* Step 5: Boot with event list *) + Printf.printf "[5] Calling u3v_boot with event list...\n%!"; + Printf.printf " (Booting Arvo kernel from events)\n\n%!"; + + match boot state ova with + | Error msg -> + Printf.printf " ✗ BOOT FAILED: %s\n%!" msg; + Error msg + | Ok () -> + Printf.printf " ✓ BOOT SUCCEEDED!\n%!"; + Printf.printf "\n%!"; + Printf.printf "═══════════════════════════════════════════════════\n%!"; + Printf.printf " ✓ SOLID PILL BOOT COMPLETE!\n%!"; + Printf.printf "═══════════════════════════════════════════════════\n\n%!"; + Ok () diff --git a/ocaml/test/dune b/ocaml/test/dune index 17e84b8..c7cf6da 100644 --- a/ocaml/test/dune +++ b/ocaml/test/dune @@ -271,3 +271,13 @@ (name test_two_stage_boot) (modules test_two_stage_boot) (libraries nock_lib eio_main unix)) + +(executable + (name test_life_formula) + (modules test_life_formula) + (libraries nock_lib)) + +(executable + (name examine_ivory) + (modules examine_ivory) + (libraries nock_lib eio_main)) diff --git a/ocaml/test/examine_ivory.ml b/ocaml/test/examine_ivory.ml new file mode 100644 index 0000000..34b5fed --- /dev/null +++ b/ocaml/test/examine_ivory.ml @@ -0,0 +1,84 @@ +(* Examine ivory.pill structure *) + +open Nock_lib + +let main env = + Printf.printf "\n═══════════════════════════════════════\n"; + Printf.printf " Examining ivory.pill Structure\n"; + Printf.printf "═══════════════════════════════════════\n\n"; + + (* Load ivory pill *) + Printf.printf "[1] Loading ivory.pill...\\n%!"; + let fs = Eio.Stdenv.fs env in + let pill_bytes = Eio.Path.(load (fs / "ivory.pill")) |> Bytes.of_string in + Printf.printf " Size: %d bytes\n%!" (Bytes.length pill_bytes); + + (* Cue it *) + Printf.printf "[2] Cuing ivory pill...\n%!"; + let pill = Serial.cue pill_bytes in + Printf.printf " ✓ Cued\n\n"; + + (* Check structure *) + Printf.printf "[3] Structure analysis:\n"; + match pill with + | Noun.Cell (tag, tail) -> + (* Print tag *) + let tag_str = match tag with + | Noun.Atom z -> + let bytes = Z.to_bits z in + if String.length bytes <= 10 then bytes else Printf.sprintf "" (Z.numbits z) + | Noun.Cell _ -> "" + in + Printf.printf " Tag: %s\n" tag_str; + + (* Analyze tail *) + Printf.printf " Tail type: %s\n" (if Noun.is_cell tail then "CELL" else "ATOM"); + + (match tail with + | Noun.Atom z when Z.equal z Z.zero -> + Printf.printf " Tail value: 0 (NULL!)\n"; + Printf.printf "\n"; + Printf.printf " ✓ CONFIRMED: Embedded ivory has structure [\"ivory\" 0]\n"; + Printf.printf " This means u3v_life() is called with atom 0!\n" + + | Noun.Atom z -> + Printf.printf " Tail value: atom with %d bits\n" (Z.numbits z); + Printf.printf " Tail decimal: %s\n" (Z.to_string z) + + | Noun.Cell (h, t) -> + Printf.printf " Tail is a CELL\n"; + Printf.printf " Head type: %s\n" (if Noun.is_cell h then "cell" else "atom"); + Printf.printf " Tail type: %s\n" (if Noun.is_cell t then "cell" else "atom"); + + (* Check if it's the Arvo core structure *) + Printf.printf "\n Checking if tail is Arvo core...\n"; + begin try + let _slot2 = Noun.slot (Z.of_int 2) tail in + let _slot3 = Noun.slot (Z.of_int 3) tail in + Printf.printf " ✓ Has slot 2 and 3 (it's a cell with head and tail)\n"; + + (* Check for lifecycle formula at slot 2 *) + begin try + let slot2 = Noun.slot (Z.of_int 2) tail in + Printf.printf " Slot 2 type: %s\n" (if Noun.is_cell slot2 then "cell" else "atom"); + + (* The lifecycle formula should be [2 [0 3] [0 2]] *) + match slot2 with + | Noun.Cell (Noun.Atom op, _rest) when Z.equal op (Z.of_int 2) -> + Printf.printf " Slot 2 starts with opcode 2 - could be lifecycle formula!\n"; + Printf.printf "\n ✓ Tail appears to BE the Arvo core itself!\n"; + Printf.printf " This means the lifecycle formula operates on the CORE, not null!\n" + | _ -> + Printf.printf " Slot 2 doesn't match expected lifecycle formula pattern\n" + with _ -> + Printf.printf " Could not analyze slot 2\n" + end + with Noun.Exit -> + Printf.printf " ✗ Cannot access slots 2/3 - not a valid cell structure\n" + end + ) + + | Noun.Atom _ -> + Printf.printf " ✗ Pill is an atom (unexpected)\n" + +let () = Eio_main.run main diff --git a/ocaml/test/test_life_formula.ml b/ocaml/test/test_life_formula.ml new file mode 100644 index 0000000..722154b --- /dev/null +++ b/ocaml/test/test_life_formula.ml @@ -0,0 +1,48 @@ +(* Test lifecycle formula on atom 0 *) + +open Nock_lib + +let () = + Printf.printf "Testing lifecycle formula [2 [0 3] [0 2]] on atom 0\n\n%!"; + + (* Build the lifecycle formula *) + let lyf = Noun.cell (Noun.atom 2) + (Noun.cell + (Noun.cell (Noun.atom 0) (Noun.atom 3)) + (Noun.cell (Noun.atom 0) (Noun.atom 2))) in + + Printf.printf "Formula: [2 [0 3] [0 2]]\n%!"; + Printf.printf "Subject: 0 (null)\n\n%!"; + + (* Try running it *) + begin try + let result = Nock.nock_on (Noun.atom 0) lyf in + Printf.printf "✓ SUCCESS! Result: %s\n%!" (match result with + | Noun.Atom z -> Z.to_string z + | Noun.Cell _ -> "[cell]") + with + | Noun.Exit -> + Printf.printf "✗ FAILED with Nock Exit\n%!"; + + (* Let's trace through the formula step by step *) + Printf.printf "\nStep-by-step trace:\n%!"; + Printf.printf "Formula: *[0 [2 [0 3] [0 2]]]\n%!"; + Printf.printf "Opcode 2: *[a [2 b c]] = *[*[a b] *[a c]]\n%!"; + Printf.printf " b = [0 3]\n%!"; + Printf.printf " c = [0 2]\n%!"; + Printf.printf "\n*[a b] = *[0 [0 3]] = slot 3 of atom 0\n%!"; + + (* Try slot 3 on atom 0 *) + begin try + let s3 = Noun.slot (Z.of_int 3) (Noun.atom 0) in + Printf.printf " slot 3 of 0 = %s (unexpected!)\n%!" (match s3 with + | Noun.Atom z -> Z.to_string z + | Noun.Cell _ -> "[cell]") + with Noun.Exit -> + Printf.printf " slot 3 of 0 = ERROR (as expected)\n%!" + end; + + Printf.printf "\nThis proves the formula CANNOT work on atom 0!\n%!" + | e -> + Printf.printf "✗ FAILED with: %s\n%!" (Printexc.to_string e) + end diff --git a/ocaml/test/test_two_stage_boot.ml b/ocaml/test/test_two_stage_boot.ml index 090dd50..f8311b5 100644 --- a/ocaml/test/test_two_stage_boot.ml +++ b/ocaml/test/test_two_stage_boot.ml @@ -40,16 +40,18 @@ let stage1_ivory_boot env = Printf.printf " Tag: '%s'\n" tag_str; Printf.printf " Core: %s\n\n" (if Noun.is_cell core then "cell" else "atom"); - (* Now boot with the ivory core as eve *) - Printf.printf "[4] Running u3v_life() on ivory core...\n%!"; - Printf.printf " Formula: [2 [0 3] [0 2]]\n"; - Printf.printf " Subject: ivory pill core\n\n%!"; + (* KEY DISCOVERY: The ivory pill tail IS the Arvo core! *) + Printf.printf "[4] Using ivory pill tail (Arvo core) for bootstrap...\n%!"; + Printf.printf " Ivory structure: [\"ivory\" ARVO_CORE]\n"; + Printf.printf " The tail is a CELL, not null!\n\n"; - let eve_core = core in (* Use the ivory core, not null! *) + Printf.printf "[5] Running u3v_life() on Arvo core...\n%!"; + Printf.printf " Formula: [2 [0 3] [0 2]]\n"; + Printf.printf " Subject: Arvo core (cell)\n%!"; begin try let start = Unix.gettimeofday () in - let kernel = Boot.life eve_core in + let kernel = Boot.life core in let elapsed = Unix.gettimeofday () -. start in Printf.printf " ✓ SUCCESS! Kernel built in %.4fs\n\n" elapsed; @@ -186,18 +188,7 @@ let stage2_solid_boot env _ivory_kernel = with | Noun.Exit -> Printf.printf " ✗ FAILED: Nock Exit during lifecycle\n\n"; - - (* Debug: try with null like C Vere seems to do *) - Printf.printf "[DEBUG] Trying with null (like C Vere)...\n%!"; - begin try - let _kernel = Boot.life (Noun.atom 0) in - Printf.printf " ✓ Null works! (same as ivory)\n"; - Printf.printf " This means solid pill events might be processed differently\n\n"; - false - with _ -> - Printf.printf " ✗ Null also fails\n\n"; - false - end + false | e -> Printf.printf " ✗ FAILED: %s\n\n" (Printexc.to_string e); diff --git a/vere/build.zig b/vere/build.zig index 66318a0..707ca2b 100644 --- a/vere/build.zig +++ b/vere/build.zig @@ -616,6 +616,11 @@ fn buildBinary( .file = "pkg/noun/serial_tests.c", .deps = noun_test_deps, }, + .{ + .name = "life-test", + .file = "pkg/noun/life_test.c", + .deps = noun_test_deps, + }, // pkg_vere .{ .name = "ames-test", @@ -627,6 +632,11 @@ fn buildBinary( .file = "pkg/vere/boot_tests.c", .deps = vere_test_deps, }, + .{ + .name = "solid-boot-test", + .file = "pkg/vere/solid_boot_test.c", + .deps = vere_test_deps, + }, .{ .name = "newt-test", .file = "pkg/vere/newt_tests.c", diff --git a/vere/pkg/noun/life_test.c b/vere/pkg/noun/life_test.c new file mode 100644 index 0000000..cffe97b --- /dev/null +++ b/vere/pkg/noun/life_test.c @@ -0,0 +1,96 @@ +/// @file +/// Test lifecycle formula on different subjects + +#include "noun.h" + +/* _setup(): prepare for tests. +*/ +static void +_setup(void) +{ + u3m_boot_lite(1 << 28); // 256MB loom +} + +/* Helper to run nock with subject+formula in a cell for u3m_soft */ +static u3_noun +_nock_pair(u3_noun sub_fol) +{ + u3_noun sub, fol; + u3x_cell(sub_fol, &sub, &fol); + return u3n_nock_on(u3k(sub), u3k(fol)); +} + +/* _test_life_on_null(): test lifecycle formula on atom 0 +*/ +static c3_i +_test_life_on_null(void) +{ + fprintf(stderr, "\n=================================================\n"); + fprintf(stderr, "Testing lifecycle formula [2 [0 3] [0 2]] on null\n"); + fprintf(stderr, "=================================================\n\n"); + + /* Build lifecycle formula: [2 [0 3] [0 2]] */ + u3_noun lyf = u3nt(2, u3nc(0, 3), u3nc(0, 2)); + + fprintf(stderr, "Formula: [2 [0 3] [0 2]]\n"); + fprintf(stderr, "Subject: 0 (null)\n"); + fprintf(stderr, "Formula mug: %x\n\n", u3r_mug(lyf)); + + /* Test on null (atom 0) */ + u3_noun eve = 0; /* u3_nul is defined as 0 */ + + fprintf(stderr, "Testing: *[0 [2 [0 3] [0 2]]]\n\n"); + + /* Try running it - need to pass [subject formula] as single argument */ + u3_noun pair = u3nc(eve, lyf); + u3_noun pro = u3m_soft(0, _nock_pair, pair); + + if ( u3_blip != u3h(pro) ) { + fprintf(stderr, "✗ FAILED!\n"); + fprintf(stderr, "Error: "); + u3m_p("", u3h(pro)); + fprintf(stderr, "\n"); + + /* Print trace if available */ + if ( u3du(pro) ) { + fprintf(stderr, "\nTrace:\n"); + u3m_p("trace", u3t(pro)); + fprintf(stderr, "\n"); + } + + fprintf(stderr, "\nThis confirms the formula CANNOT work on atom 0!\n"); + u3z(pro); + return 0; + } + + fprintf(stderr, "✓ SUCCESS!\n"); + fprintf(stderr, "Result mug: %x\n", u3r_mug(u3t(pro))); + fprintf(stderr, "\nResult structure:\n"); + u3m_p("result", u3t(pro)); + fprintf(stderr, "\n"); + + fprintf(stderr, "\nThis is UNEXPECTED! The formula somehow works on atom 0 in C!\n"); + + u3z(pro); + + return 1; +} + +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_life_on_null() ) { + fprintf(stderr, "test life on null: failed (as expected)\r\n"); + fprintf(stderr, "This is actually the CORRECT behavior - lifecycle formula cannot work on null.\r\n"); + return 0; // Return success since failure is expected + } + + // GC + // + u3m_grab(u3_none); + + fprintf(stderr, "test life on null: unexpected success!\r\n"); + return 0; +} diff --git a/vere/pkg/noun/vortex.c b/vere/pkg/noun/vortex.c index 0d6d1cf..63b4fc2 100644 --- a/vere/pkg/noun/vortex.c +++ b/vere/pkg/noun/vortex.c @@ -25,14 +25,17 @@ u3v_home* u3v_Home; u3_noun u3v_life(u3_noun eve) { - c3_o is_null = u3r_sing(u3_nul, eve); - c3_o is_atom = u3a_is_atom(eve); - c3_o is_cell = u3du(eve); + u3l_log("u3f_life()"); + - u3l_log("u3v_life: eve=%s (atom=%s cell=%s)", - is_null ? "null" : (is_cell ? "cell" : "atom"), - is_atom ? "yes" : "no", - is_cell ? "yes" : "no"); + c3_o is_atom = u3a_is_atom(eve); + c3_d len_d; + { + u3_noun len = u3qb_lent(eve); + u3_assert( c3y == u3r_safe_chub(len, &len_d) ); + u3z(len); + } + u3l_log("u3v_life: processing %llu events", (unsigned long long)len_d); u3_noun lyf = u3nt(2, u3nc(0, 3), u3nc(0, 2)); u3_noun gat = u3n_nock_on(eve, lyf); @@ -48,6 +51,7 @@ u3v_life(u3_noun eve) c3_o u3v_boot(u3_noun eve) { + c3_d len_d; { u3_noun len = u3qb_lent(eve); @@ -105,8 +109,18 @@ _cv_lite(u3_noun pil) c3_o u3v_boot_lite(u3_noun pil) { + // ensure zero-initialized kernel // + c3_d len_d; + { + u3_noun len = u3qb_lent(pil); + u3_assert( c3y == u3r_safe_chub(len, &len_d) ); + u3z(len); + } + + u3l_log("u3v_boot_lite: processing %llu events", (unsigned long long)len_d); + u3A->roc = 0; { diff --git a/vere/pkg/vere/boot_tests.c b/vere/pkg/vere/boot_tests.c index d9728d8..c90c538 100644 --- a/vere/pkg/vere/boot_tests.c +++ b/vere/pkg/vere/boot_tests.c @@ -17,11 +17,59 @@ _setup(void) u3C.wag_w |= u3o_hashless; u3m_boot_lite(1 << 26); + // this follows king.c sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); if ( u3_none == (pil = u3s_cue_xeno_with(sil_u, len_d, byt_y)) ) { printf("*** fail _setup 1\n"); exit(1); } + + u3l_log("embed_pil_is_atom %u", u3a_is_atom(pil)); + u3_noun local_pil = u3m_file("/home/y/code/urbit/vere/ocaml/ivory.pill"); + u3_noun cued_pil = u3ke_cue(local_pil); + + u3l_log("local_pil_is_atom %u", u3a_is_atom(local_pil)); + u3l_log("cued_pil_is_atom %u", u3a_is_atom(cued_pil)); + + c3_d len_pp; + { + u3_noun len = u3qb_lent(pil); + u3_assert( c3y == u3r_safe_chub(len, &len_pp) ); + u3z(len); + } + u3l_log("embedded pill length %llu", (unsigned long long)len_pp); + c3_d len_pp2; + { + u3_noun len = u3qb_lent(cued_pil); + u3_assert( c3y == u3r_safe_chub(len, &len_pp2) ); + u3z(len); + } + u3l_log("file_pill_length %llu", (unsigned long long)len_pp2); + + // 1. Direct equality check + c3_o match = u3r_sing(pil, cued_pil); + u3l_log("pills equal: %u", match); + + // 2. Compare mugs (32-bit hashes) + u3l_log("embedded mug: %x", u3r_mug(pil)); + u3l_log("file mug: %x", u3r_mug(cued_pil)); + + // 3. If they're cells, compare heads + if ( c3y == u3a_is_cell(pil) && c3y == u3a_is_cell(cued_pil) ) { + u3l_log("head mug embedded: %x", u3r_mug(u3h(pil))); + u3l_log("head mug file: %x", u3r_mug(u3h(cued_pil))); + } + + // 4. Jam both and compare sizes + u3_noun jam1 = u3qe_jam(pil); + u3_noun jam2 = u3qe_jam(cued_pil); + u3l_log("jammed embedded: %u met", u3r_met(3, jam1)); + u3l_log("jammed file: %u met", u3r_met(3, jam2)); + u3l_log("jams equal: %u", u3r_sing(jam1, jam2)); + u3z(jam1); u3z(jam2); + + + // u3s_cue_xeno_done(sil_u); if ( c3n == u3v_boot_lite(pil) ) { printf("*** fail _setup 2\n"); diff --git a/vere/pkg/vere/king.c b/vere/pkg/vere/king.c index 0a2aef7..dd4711a 100644 --- a/vere/pkg/vere/king.c +++ b/vere/pkg/vere/king.c @@ -616,7 +616,7 @@ _boothack_pill(void) c3_c url_c[2048]; if ( (c3y == u3_Host.ops_u.git) && - (0 != u3_Host.ops_u.arv_c) ) + (0 != u3_Host.ops_u.arv_c) ) { _git_pill_url(url_c, u3_Host.ops_u.arv_c); } @@ -714,9 +714,11 @@ static u3_noun _boothack_doom(void) { u3_noun pax = u3i_string(u3_Host.dir_c); + u3m_p("pax boothack_doom", pax); u3_noun bot; if ( c3n == u3_Host.ops_u.nuu ) { + u3l_log("u3_Host.ops.u.nuu"); return u3nt(c3__pier, u3_nul, pax); } else if ( 0 != u3_Host.ops_u.fak_c ) { @@ -961,6 +963,7 @@ _king_loop_exit() static void _king_boot_ivory(void) { + u3l_log("king boot ivory"); c3_d len_d; c3_y* byt_y; @@ -1007,6 +1010,8 @@ _king_boot_ivory(void) void u3_king_commence() { + u3l_log("king commence"); + u3_Host.lup_u = uv_default_loop(); // initialize top-level timer diff --git a/vere/pkg/vere/main.c b/vere/pkg/vere/main.c index a547e23..db19f77 100644 --- a/vere/pkg/vere/main.c +++ b/vere/pkg/vere/main.c @@ -1293,6 +1293,8 @@ _cw_eval(c3_i argc, c3_c* argv[]) u3_cue_xeno* sil_u; u3_weak pil; + u3l_log("initialize loom and load ivory main.c"); + u3C.wag_w |= u3o_hashless; u3m_boot_lite((size_t)1 << u3_Host.ops_u.lom_y); sil_u = u3s_cue_xeno_init_with(ur_fib27, ur_fib28); diff --git a/vere/pkg/vere/mars.c b/vere/pkg/vere/mars.c index 5f9eb68..7b1ed03 100644 --- a/vere/pkg/vere/mars.c +++ b/vere/pkg/vere/mars.c @@ -1153,10 +1153,28 @@ _mars_do_boot(u3_disk* log_u, c3_d eve_d, u3_noun cax) u3l_log("--------------- bootstrap starting ----------------"); - u3l_log("boot: 1-%u", u3qb_lent(eve)); + c3_d eve_count = u3qb_lent(eve); + u3l_log("boot: 1-%llu", (unsigned long long)eve_count); + u3l_log("_mars_do_boot: eve list has %llu events", (unsigned long long)eve_count); + + // Check structure of first event + if ( u3_nul != eve ) { + u3_noun first = u3h(eve); + c3_o is_atom = u3a_is_atom(first); + c3_o is_cell = u3a_is_cell(first); + u3l_log("_mars_do_boot: first event is %s", is_cell ? "cell" : (is_atom ? "atom" : "unknown")); + + if ( is_cell ) { + u3_noun fst_h = u3h(first); + u3_noun fst_t = u3t(first); + u3l_log(" first event head: %s", u3a_is_atom(fst_h) ? "atom (timestamp?)" : "cell"); + u3l_log(" first event tail: %s", u3a_is_atom(fst_t) ? "atom" : "cell"); + } + } // XX check mug if available // + u3l_log("_mars_do_boot: calling u3v_boot(eve)..."); if ( c3n == u3v_boot(eve) ) { return c3n; } @@ -1814,10 +1832,21 @@ _mars_boot_make(u3_boot_opts* inp_u, // timestamp events, cons list // { + c3_d bot_c = u3qb_lent(bot); + c3_d mod_c = u3qb_lent(mod); + c3_d use_c = u3qb_lent(use); + + u3l_log("_mars_boot_make: assembling events"); + u3l_log(" bot (lifecycle): %llu events (NO timestamp)", (unsigned long long)bot_c); + u3l_log(" mod (vanes): %llu events (WITH timestamp)", (unsigned long long)mod_c); + u3l_log(" use (userspace): %llu events (WITH timestamp)", (unsigned long long)use_c); + u3_noun now = u3_time_in_tv(&inp_u->tim_u); u3_noun bit = u3qc_bex(48); // 1/2^16 seconds u3_noun eve = u3kb_flop(bot); + u3l_log(" starting with bot events (untimestamped)"); + { u3_noun lit = u3kb_weld(mod, use); u3_noun i, t = lit; @@ -1832,6 +1861,7 @@ _mars_boot_make(u3_boot_opts* inp_u, } *ova = u3kb_flop(eve); + u3l_log(" final event list: %llu events", (unsigned long long)u3qb_lent(*ova)); u3z(now); u3z(bit); } @@ -1907,6 +1937,8 @@ u3_mars_boot(u3_mars* mar_u, c3_d len_d, c3_y* hun_y) u3_meta met_u; u3_noun com, ova, cax; + u3l_log("u3_mars_boot()"); + inp_u.veb_o = __( u3C.wag_w & u3o_verbose ); inp_u.lit_o = c3n; // unimplemented in arvo diff --git a/vere/pkg/vere/solid_boot_test.c b/vere/pkg/vere/solid_boot_test.c new file mode 100644 index 0000000..b0d5200 --- /dev/null +++ b/vere/pkg/vere/solid_boot_test.c @@ -0,0 +1,178 @@ +/// @file +/// Test solid pill boot flow - exactly as mars.c does it + +#include "vere.h" + +static void +_setup(void) +{ + u3m_boot_lite(1 << 28); // 256MB loom +} + +/* Helper wrapper for u3v_boot to use with u3m_soft */ +static u3_noun +_boot_wrapper(u3_noun ova) +{ + if ( c3n == u3v_boot(ova) ) { + return u3nc(c3__exit, u3_nul); + } + return u3nc(u3_blip, u3_nul); +} + +/* _test_solid_boot(): boot from solid.pill following exact mars.c flow +*/ +static c3_i +_test_solid_boot(void) +{ + fprintf(stderr, "\n"); + fprintf(stderr, "═══════════════════════════════════════════════════\n"); + fprintf(stderr, " Solid Pill Boot Test (Exact C Vere Flow)\n"); + fprintf(stderr, "═══════════════════════════════════════════════════\n\n"); + + /* Step 1: Load solid.pill (like king.c:611) */ + fprintf(stderr, "[1] Loading solid.pill (u3m_file like king.c)...\n"); + u3_noun pil_p = u3m_file("solid.pill"); + // u3_noun pil_p = u3m_file("/home/y/code/urbit/vere/ocaml/solid.pill"); + u3_noun arv = u3_nul; + c3_o arv_atom = u3a_is_atom(arv); + c3_o atom2 = u3a_is_atom(42); + c3_o atom3 = u3a_is_atom(u3nc(1, 5)); + u3l_log("arv_atom %u", arv_atom); + u3l_log("atoms ? %u - %u", atom2, atom3); + u3l_log("c3y %u", c3y); + u3l_log("c3n %u", c3n); + u3_noun pil2 = u3nc(pil_p, arv); + + fprintf(stderr, " ✓ Loaded pill as atom\n\n"); + + /* Step 2: Cue the pill atom (like _mars_sift_pill:1597) */ + fprintf(stderr, "[2] Cuing pill atom (like _mars_sift_pill)...\n"); + u3_noun pro = u3m_soft(0, u3ke_cue, u3k(pil_p)); + u3_noun mot, tag, dat; + + if ( (c3n == u3r_trel(pro, &mot, &tag, &dat)) + || (u3_blip != mot) ) + { + fprintf(stderr, " ✗ Failed to cue pill\n"); + u3z(pro); + u3z(pil_p); + return 0; + } + + /* Check for %pill tag */ + if ( c3__pill != tag ) { + fprintf(stderr, " ✗ Not a pill (expected %%pill tag)\n"); + u3z(pro); + u3z(pil_p); + return 0; + } + + fprintf(stderr, " ✓ Cued successfully, got %%pill\n\n"); + + /* Step 3: Parse pill structure [%solid [bot mod use]] */ + fprintf(stderr, "[3] Parsing pill structure...\n"); + + u3_noun sol_tag, events; + if ( c3n == u3r_cell(dat, &sol_tag, &events) ) { + fprintf(stderr, " ✗ Invalid pill data structure\n"); + u3z(pro); + u3z(pil_p); + return 0; + } + + /* Extract bot, mod, use */ + u3_noun bot, mod, use; + if ( c3n == u3r_trel(events, &bot, &mod, &use) ) { + fprintf(stderr, " ✗ Cannot extract bot/mod/use\n"); + u3z(pro); + u3z(pil_p); + return 0; + } + + u3k(bot); u3k(mod); u3k(use); + u3z(pro); + u3z(pil_p); + + c3_d bot_c = u3qb_lent(bot); + c3_d mod_c = u3qb_lent(mod); + c3_d use_c = u3qb_lent(use); + + fprintf(stderr, " Bot events: %llu\n", (unsigned long long)bot_c); + fprintf(stderr, " Mod events: %llu\n", (unsigned long long)mod_c); + fprintf(stderr, " Use events: %llu\n", (unsigned long long)use_c); + fprintf(stderr, " Total: %llu events\n\n", + (unsigned long long)(bot_c + mod_c + use_c)); + + /* Step 4: Build event list (like _mars_boot_make lines 1814-1836) */ + fprintf(stderr, "[4] Building event list (C Vere style)...\n"); + fprintf(stderr, " Bot events: NOT timestamped\n"); + fprintf(stderr, " Mod/use events: timestamped\n\n"); + + struct timeval tim_u; + gettimeofday(&tim_u, 0); + u3_noun now = u3_time_in_tv(&tim_u); + u3_noun bit = u3qc_bex(48); // 1/2^16 seconds + u3_noun eve = u3kb_flop(u3k(bot)); // Bot events WITHOUT timestamp + + { + u3_noun lit = u3kb_weld(u3k(mod), u3k(use)); + u3_noun i, t = lit; + + while ( u3_nul != t ) { + u3x_cell(t, &i, &t); + now = u3ka_add(now, u3k(bit)); + eve = u3nc(u3nc(u3k(now), u3k(i)), eve); // WITH timestamp + } + + u3z(lit); + } + + u3_noun ova = u3kb_flop(eve); + u3z(now); u3z(bit); + u3z(bot); u3z(mod); u3z(use); + + c3_d eve_count = u3qb_lent(ova); + fprintf(stderr, " ✓ Event list built: %llu events\n\n", (unsigned long long)eve_count); + + /* Step 5: Call u3v_boot (like _mars_do_boot line 1160) */ + fprintf(stderr, "[5] Calling u3v_boot with event list...\n"); + fprintf(stderr, " (This is what actually happens in C Vere!)\n\n"); + + u3_noun boot_pro = u3m_soft(0, _boot_wrapper, ova); + + if ( u3_blip != u3h(boot_pro) ) { + fprintf(stderr, " ✗ BOOT FAILED!\n"); + fprintf(stderr, " Error: "); + u3m_p("", u3h(boot_pro)); + fprintf(stderr, "\n"); + u3z(boot_pro); + return 0; + } + + fprintf(stderr, " ✓ BOOT SUCCEEDED!\n"); + fprintf(stderr, " Kernel mug: %x\n", u3r_mug(u3A->roc)); + fprintf(stderr, "\n"); + + fprintf(stderr, "═══════════════════════════════════════════════════\n"); + fprintf(stderr, " ✓ SOLID PILL BOOT TEST PASSED!\n"); + fprintf(stderr, "═══════════════════════════════════════════════════\n\n"); + + u3z(boot_pro); + + return 1; +} + +int +main(int argc, char* argv[]) +{ + _setup(); + + if ( !_test_solid_boot() ) { + fprintf(stderr, "test solid boot: FAILED\r\n"); + return 1; + } + + u3m_grab(u3_none); + fprintf(stderr, "test solid boot: OK\r\n"); + return 0; +} diff --git a/zod/.urb/log/0i0/data.mdb b/zod/.urb/log/0i0/data.mdb index 3576929..aac7bed 100644 Binary files a/zod/.urb/log/0i0/data.mdb and b/zod/.urb/log/0i0/data.mdb differ diff --git a/zod/.urb/log/0i0/lock.mdb b/zod/.urb/log/0i0/lock.mdb index 83e959d..cf0169c 100644 Binary files a/zod/.urb/log/0i0/lock.mdb and b/zod/.urb/log/0i0/lock.mdb differ diff --git a/zod/.urb/log/0i0/vere.txt b/zod/.urb/log/0i0/vere.txt index 7c6e483..0455ac0 100644 --- a/zod/.urb/log/0i0/vere.txt +++ b/zod/.urb/log/0i0/vere.txt @@ -1 +1 @@ -4.0-0395f1ef05 \ No newline at end of file +4.0-437df069b5 \ No newline at end of file diff --git a/zod/.vere.lock b/zod/.vere.lock index f2694d9..d3bf1bd 100644 --- a/zod/.vere.lock +++ b/zod/.vere.lock @@ -1 +1 @@ -502068 +589155 -- cgit v1.2.3