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
//! The loop's ops rows (VISION §5 V4 item 2, DESIGN §4.2): **every spawn and
//! every reap, and nothing else.**
//!
//! One `ops.jsonl` line per action the loop completes, in the shape §4.2
//! already defines, with no field added to the schema — the same discipline
//! `["yog-step",…]`, `["yog-drift",…]` and `["yog-monitor",…]` follow:
//!
//! ```text
//! argv[0] yog-fleet the pseudo-binary naming a loop row
//! argv[1] spawn|reap
//! argv[2] the ball id the action was about
//! argv[3] what it produced: the conversation a spawn minted, or the
//! claimant name a reap released the ball from
//! cwd the armed workspace
//! stdout a reap's COMPARISON; empty for a spawn
//! exit 0 — the loop writes a row for what it DID
//! ```
//!
//! **A reap reason is the comparison itself** (V4 item 2, verbatim: *"Reap
//! reasons are the comparisons themselves ('lease expired 14m ago'), never
//! diagnoses"*). [`reaped`] takes an already-formed comparison and stores it
//! verbatim; there is deliberately no way to hand this module a judgement. The
//! loop spawns and reaps; it never diagnoses (§4.3).
//!
//! **A failed action writes nothing here.** Every executor the loop composes —
//! the start flow's `bl` steps, the §3.5 ceiling gate, `bl unclaim` — already
//! leaves its own §4.2 failure row, and the loop is level-triggered, so the
//! next tick simply re-fires against whatever it finds. A second row saying
//! "and the loop wanted that" would double every failure on the trail and, at
//! one tick per full sweep, would do it forever.
use crate;
use Path;
/// `argv[0]` of a loop row — the pseudo-binary, beside `yog-step`, `yog-drift`
/// and `yog-monitor`. No process is involved: the loop's own decision is what
/// the row records, the verbs it drove having logged themselves.
pub const YOG_FLEET: &str = "yog-fleet";
/// `argv[1]` — what the loop did. Two words, because the loop does two things.
pub const SPAWN: &str = "spawn";
pub const REAP: &str = "reap";
/// One row, read back. The render side's value and the tests' assertion.
/// The row a completed **spawn** appends: the ball it took and the conversation
/// it minted on it.
/// The row a completed **reap** appends: the ball it released, the claimant it
/// released it from, and the comparison that decided it — never a diagnosis.
/// Read one durable line as a loop act, or `None` when it is not one. Forgiving
/// like every other `ops.jsonl` read: a row from a future yog with more fields,
/// or a hand-mangled one, simply is not an act.
/// The acts in a published snapshot's ops tail, oldest first. [`OpRow`] joins
/// `argv` for display and every field a loop row puts there is space-free by
/// construction (a word, a ball id, a conversation or claimant name), so the
/// split is lossless.
/// When this workspace's loop last **did** something — the newest act's stamp,
/// or `None` when it has never acted. The board's "last tick" fact: a
/// level-triggered loop's quiet tick leaves no trace by design, so the last
/// tick yog can name is the last one that changed the world.