diff options
Diffstat (limited to 'ocaml')
-rw-r--r-- | ocaml/BOOT_FLOW.md | 172 | ||||
-rw-r--r-- | ocaml/BOOT_PROCESS.md | 47 | ||||
-rw-r--r-- | ocaml/FINDINGS.md | 113 | ||||
-rw-r--r-- | ocaml/lib/boot.ml | 271 | ||||
-rw-r--r-- | ocaml/test/dune | 10 | ||||
-rw-r--r-- | ocaml/test/examine_ivory.ml | 84 | ||||
-rw-r--r-- | ocaml/test/test_life_formula.ml | 48 | ||||
-rw-r--r-- | ocaml/test/test_two_stage_boot.ml | 27 |
8 files changed, 699 insertions, 73 deletions
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 "<atom %d bits>" (Z.numbits z) + | Noun.Cell _ -> "<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); |