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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
# Boot Process: Vere vs Our OCaml Implementation
## ✅ FIXED! Now using lifecycle formula correctly!
### What Vere Actually Does
**From vere/pkg/vere/mars.c and vere/pkg/noun/vortex.c:**
```c
// 1. Build event list from solid pill (mars.c:1700-1835)
u3_noun bot, mod, use;
_mars_sift_pill(pil, &bot, &mod, &use, &cax);
// Add 4 system events to mod (wack, whom, verb, wyrd)
mod = u3nc(wack_event, u3nc(whom_event, u3nc(verb_event, u3nc(wyrd_event, mod))));
// Add boot event to use
use = u3nc(boot_event, use);
// Timestamp mod+use events (bot is NOT timestamped!)
u3_noun eve = u3kb_flop(bot); // Start with bot events
u3_noun lit = u3kb_weld(mod, use);
while (lit) {
now = add_increment(now);
eve = u3nc(u3nc(now, event), eve); // Prepend [timestamp event]
}
// 2. Write events to disk
u3_disk_plan_list(log_u, ova);
u3_disk_sync(log_u);
// 3. Read events back from disk
eve = u3_disk_read_list(log_u, 1, eve_d, &mug_l);
// 4. Boot by running lifecycle formula on ENTIRE event list
u3v_boot(eve);
→ u3v_life(eve);
→ u3_noun lyf = [2 [0 3] [0 2]];
→ u3_noun gat = u3n_nock_on(eve, lyf); // Run formula on FULL LIST!
→ return slot_7(gat);
```
**Key insight:** The lifecycle formula `[2 [0 3] [0 2]]` processes the **entire event list at once**, NOT event-by-event.
### What We're Doing (WRONG)
**From ocaml/lib/boot.ml:**
```ocaml
(* 1. Build event list from solid pill *)
let bot_list = parse_bot_events()
let mod_list = parse_mod_events()
let use_list = parse_use_events()
(* Add system events to mod *)
let mod_list = wack :: whom :: verb :: wyrd :: mod_list
(* Add boot event to use *)
let use_list = boot_event :: use_list
(* Timestamp ALL events *)
let all_events = bot_list @ mod_list @ use_list
let timestamped_events = timestamp_all all_events
(* 2. Poke each event individually - THIS IS WRONG! *)
List.iter (fun event ->
ignore (State.poke state event) (* Returns [effects new_core] *)
) timestamped_events
```
**Problem:** We're using `State.poke` which is for **runtime event processing**, not boot!
## The Lifecycle Formula Explained
```
[2 [0 3] [0 2]]
Breaking it down:
- [0 2] = slot 2 of subject = head of event list = FIRST EVENT (should be a formula!)
- [0 3] = slot 3 of subject = tail of event list = REST OF EVENTS
- [2 formula subject] = nock(subject, formula)
So: nock(rest_of_events, first_event)
```
The **first event must be a formula** that knows how to process all the remaining events and build the Arvo kernel!
## Event List Structure
**From mars.c:1820-1829:**
```
Final event list passed to u3v_boot():
[
bot_event_1 // NO timestamp
bot_event_2 // NO timestamp
bot_event_3 // NO timestamp
[timestamp mod_event_1] // WITH timestamp
[timestamp mod_event_2] // WITH timestamp
[timestamp mod_event_3] // WITH timestamp
[timestamp mod_event_4] // WITH timestamp
[timestamp use_event_1] // WITH timestamp
[timestamp use_event_2] // WITH timestamp
...
]
```
**MIXED structure:** Bot events are bare, mod/use events are timestamped pairs!
## State.poke vs u3v_life
### State.poke (for runtime events)
```ocaml
let poke state event =
let formula = slot 23 kernel in (* Get poke formula *)
let gate = nock_on kernel formula in (* Compute poke gate *)
let result = slam_on gate event in (* Apply to single event *)
match result with
| Cell (effects, new_core) ->
state.roc <- new_core;
effects
```
**Used for:** Processing events AFTER boot, one at a time
### u3v_life (for boot)
```c
u3_noun u3v_life(u3_noun eve) {
u3_noun lyf = [2 [0 3] [0 2]]; // Lifecycle formula
u3_noun gat = u3n_nock_on(eve, lyf); // Process ALL events at once
u3_noun cor = slot_7(gat); // Extract kernel
return cor;
}
```
**Used for:** Initial boot, processes entire event list as batch
## What We Need To Fix
### Option 1: Implement u3v_life properly
```ocaml
(* lib/boot.ml *)
let lifecycle_formula =
(* [2 [0 3] [0 2]] *)
cell (atom_int 2)
(cell (cell (atom_int 0) (atom_int 3))
(cell (atom_int 0) (atom_int 2)))
let run_lifecycle events =
let result = nock_on events lifecycle_formula in
slot (Z.of_int 7) result
let boot_solid state path =
(* ... parse pill ... *)
let all_events = construct_event_list bot mod use in
let kernel = run_lifecycle all_events in
state.roc <- kernel;
state.eve <- Int64.of_int (count_events all_events)
```
**Problem:** This requires the first bot event to be a valid formula. Do we have that?
### Option 2: Use ivory boot first, then events
```ocaml
(* 1. Boot ivory pill to get initial kernel *)
let boot_ivory state ivory_path =
let pill = cue_file ivory_path in
match pill with
| Cell (tag, core) when tag = "ivory" ->
(* Run lifecycle on ivory's event list *)
let kernel = run_lifecycle core in
state.roc <- kernel
(* 2. Then process solid events differently? *)
(* But how? Vere uses u3v_life for solid too... *)
```
**Problem:** Need to understand what the bot events actually contain.
## Critical Questions
1. **What do bot events contain?**
- Are they formulas or data?
- Is bot[0] the lifecycle processor?
2. **Why does poke return 0 effects during boot?**
- Is our poke implementation wrong?
- Or are boot events genuinely side-effect-free?
3. **Should we use poke at all for boot?**
- Vere uses u3v_life for boot
- Vere uses u3v_poke for runtime
- We're conflating them!
## Next Steps
1. ✅ Document the actual Vere boot flow (this file)
2. ⏳ Examine bot events from solid pill - are they formulas or data?
3. ⏳ Try running lifecycle formula on our event list
4. ⏳ Compare with what Sword does (Rust implementation)
5. ⏳ Test if u3v_life approach produces correct kernel mug
## ✅ SOLUTION IMPLEMENTED
We now have `boot_solid_lifecycle` in `lib/boot.ml` that:
1. ✅ Parses solid pill correctly
2. ✅ Adds 4 system events to mod list (wack, whom, verb, wyrd)
3. ✅ Adds boot event to use list
4. ✅ Builds mixed event list (bot bare, mod/use timestamped)
5. ✅ Runs lifecycle formula `[2 [0 3] [0 2]]` on full list
6. ✅ Extracts kernel from slot 7
7. ✅ Stores kernel in state with correct event count
**Tested and working!** See `scripts/test_lifecycle_boot.ml`
The key insight: **Boot is a batch operation via lifecycle formula, not incremental pokes**.
## References
- `vere/pkg/vere/mars.c:1700-1965` - Boot preparation and execution
- `vere/pkg/noun/vortex.c:23-63` - Lifecycle formula and u3v_boot
- `ocaml-old/BOOT_PROCESS.md` - Previous investigation
- `ocaml-old/SOLID_BOOT_FLOW.md` - Event structure findings
- `ocaml/scripts/test_lifecycle_boot.ml` - Working implementation test
|