summaryrefslogtreecommitdiff
path: root/ocaml/BOOT_FLOW.md
blob: 7f9d4171604995b34cb4fbf5abd68f851602dd36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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!