sketch_buglog.nx source
↩ module page · 331 lines · 11259 B
1// sketch_buglog.nx -- 5W+H+GLP provenance ledger primitive.
2//
3// NOT JUST FOR BUGS. This is the general provenance-emit primitive every
4// tool / sketch / capability uses to declare itself. The "bug log" is just
5// one filtered view (kind=BUG) of a broader ledger that also holds:
6//
7// kind = CAPABILITY -- primitive declares what it does
8// kind = BUG -- something failed; root-cause + fix
9// kind = IMPROVEMENT_OPP -- lineage step exists but unshipped (e.g.,
10// heule_bias_table is on sketch_hll's
11// lineage but the table isn't in code yet)
12// kind = CROSS_REF -- primitive A composes against B
13//
14// G (Genealogy) and L (Lineage) are stored as arrays of SHORT IDs that
15// reference docs/genealogy.md and docs/lineage.md. Lightweight entries,
16// full provenance, joinable for tree views.
17//
18// SCHEMA (10 fields):
19// kind entry type (sealed enum below)
20// W Who primitive name
21// W What workload / scenario / capability description
22// W When ISO timestamp + commit hash
23// W Where sealed axis enum (accuracy/memory/time/capability/usability)
24// W Why root cause (for bugs) / motivation (for capabilities)
25// H How repro + fix (bugs) / usage example (capabilities)
26// G genealogy_ids IDs into docs/genealogy.md
27// L lineage_ids IDs into docs/lineage.md (TODO items here = improvement
28// opportunities a human or AI
29// can pick up directly)
30// P performance JSON object of measured metrics
31//
32// All callers append to _offc/provenance.jsonl (one JSON line per entry).
33// Bug-table is just `grep '"kind":"BUG"' _offc/provenance.jsonl`.
34
35import "syscalls.nx"
36import "sketch_types.nx"
37
38const NX_PROV_KIND_BUG: i64 = 0
39const NX_PROV_KIND_CAPABILITY: i64 = 1
40const NX_PROV_KIND_IMPROVEMENT_OPP: i64 = 2
41const NX_PROV_KIND_CROSS_REF: i64 = 3
42
43const NX_BUG_AXIS_ACCURACY: i64 = 0
44const NX_BUG_AXIS_MEMORY: i64 = 1
45const NX_BUG_AXIS_TIME: i64 = 2
46const NX_BUG_AXIS_CAPABILITY: i64 = 3
47const NX_BUG_AXIS_USABILITY: i64 = 4
48
49const NX_BUG_MAX_GENEALOGY: i64 = 64
50const NX_BUG_MAX_LINEAGE: i64 = 64
51
52struct StrSlice {
53 s: *u8,
54 len: i64,
55}
56
57struct BugLog {
58 kind: i64,
59 who: *u8,
60 who_len: i64,
61 what: *u8,
62 what_len: i64,
63 when_iso: *u8,
64 when_iso_len: i64,
65 where_axis: i64,
66 why: *u8,
67 why_len: i64,
68 how: *u8,
69 how_len: i64,
70 genealogy: *StrSlice,
71 n_genealogy: i64,
72 lineage: *StrSlice,
73 n_lineage: i64,
74 performance: *u8,
75 performance_len: i64,
76}
77
78func nx_buglog_slen(s: *u8) -> i64 {
79 var i: i64 = 0
80 while s[i] != 0 { i = i + 1 }
81 return i
82}
83
84func nx_buglog_alloc() -> *BugLog {
85 let raw: *u8 = sys_mmap(192)
86 let e: *BugLog = raw as *BugLog
87 let empty: *u8 = sys_mmap(1)
88 empty[0] = 0
89 e.kind = NX_PROV_KIND_BUG
90 e.who = empty
91 e.who_len = 0
92 e.what = empty
93 e.what_len = 0
94 e.when_iso = empty
95 e.when_iso_len = 0
96 e.where_axis = NX_BUG_AXIS_ACCURACY
97 e.why = empty
98 e.why_len = 0
99 e.how = empty
100 e.how_len = 0
101 let gen_raw: *u8 = sys_mmap(NX_BUG_MAX_GENEALOGY * 16)
102 e.genealogy = gen_raw as *StrSlice
103 e.n_genealogy = 0
104 let lin_raw: *u8 = sys_mmap(NX_BUG_MAX_LINEAGE * 16)
105 e.lineage = lin_raw as *StrSlice
106 e.n_lineage = 0
107 e.performance = empty
108 e.performance_len = 0
109 return e
110}
111
112func nx_buglog_slice_at(arr: *StrSlice, i: i64) -> *StrSlice {
113 return (arr as i64 + i * 16) as *StrSlice
114}
115
116// === base setters (must precede _z wrappers per forward-decl rule) ===
117
118func nx_buglog_set_kind(e: *BugLog, kind: i64) -> i64 {
119 if kind < 0 { return -1 }
120 if kind > NX_PROV_KIND_CROSS_REF { return -1 }
121 e.kind = kind
122 return 0
123}
124
125func nx_buglog_kind_str(kind: i64) -> *u8 {
126 if kind == NX_PROV_KIND_BUG { return "BUG" }
127 if kind == NX_PROV_KIND_CAPABILITY { return "CAPABILITY" }
128 if kind == NX_PROV_KIND_IMPROVEMENT_OPP { return "IMPROVEMENT_OPP" }
129 if kind == NX_PROV_KIND_CROSS_REF { return "CROSS_REF" }
130 return "UNKNOWN"
131}
132
133func nx_buglog_kind_strlen(kind: i64) -> i64 {
134 if kind == NX_PROV_KIND_BUG { return 3 }
135 if kind == NX_PROV_KIND_CAPABILITY { return 10 }
136 if kind == NX_PROV_KIND_IMPROVEMENT_OPP { return 15 }
137 if kind == NX_PROV_KIND_CROSS_REF { return 9 }
138 return 7
139}
140
141func nx_buglog_set_who(e: *BugLog, s: *u8, len: i64) -> i64 {
142 e.who = s
143 e.who_len = len
144 return 0
145}
146
147func nx_buglog_set_what(e: *BugLog, s: *u8, len: i64) -> i64 {
148 e.what = s
149 e.what_len = len
150 return 0
151}
152
153func nx_buglog_set_when(e: *BugLog, s: *u8, len: i64) -> i64 {
154 e.when_iso = s
155 e.when_iso_len = len
156 return 0
157}
158
159func nx_buglog_set_axis(e: *BugLog, axis: i64) -> i64 {
160 if axis < 0 { return -1 }
161 if axis > NX_BUG_AXIS_USABILITY { return -1 }
162 e.where_axis = axis
163 return 0
164}
165
166func nx_buglog_set_why(e: *BugLog, s: *u8, len: i64) -> i64 {
167 e.why = s
168 e.why_len = len
169 return 0
170}
171
172func nx_buglog_set_how(e: *BugLog, s: *u8, len: i64) -> i64 {
173 e.how = s
174 e.how_len = len
175 return 0
176}
177
178func nx_buglog_set_performance(e: *BugLog, s: *u8, len: i64) -> i64 {
179 e.performance = s
180 e.performance_len = len
181 return 0
182}
183
184func nx_buglog_add_genealogy(e: *BugLog, s: *u8, len: i64) -> i64 {
185 if e.n_genealogy >= NX_BUG_MAX_GENEALOGY { return -1 }
186 let slot: *StrSlice = nx_buglog_slice_at(e.genealogy, e.n_genealogy)
187 slot.s = s
188 slot.len = len
189 e.n_genealogy = e.n_genealogy + 1
190 return 0
191}
192
193func nx_buglog_add_lineage(e: *BugLog, s: *u8, len: i64) -> i64 {
194 if e.n_lineage >= NX_BUG_MAX_LINEAGE { return -1 }
195 let slot: *StrSlice = nx_buglog_slice_at(e.lineage, e.n_lineage)
196 slot.s = s
197 slot.len = len
198 e.n_lineage = e.n_lineage + 1
199 return 0
200}
201
202// === _z wrappers (defined AFTER base setters) ====================
203
204func nx_buglog_set_who_z(e: *BugLog, s: *u8) -> i64 {
205 return nx_buglog_set_who(e, s, nx_buglog_slen(s))
206}
207func nx_buglog_set_what_z(e: *BugLog, s: *u8) -> i64 {
208 return nx_buglog_set_what(e, s, nx_buglog_slen(s))
209}
210func nx_buglog_set_when_z(e: *BugLog, s: *u8) -> i64 {
211 return nx_buglog_set_when(e, s, nx_buglog_slen(s))
212}
213func nx_buglog_set_why_z(e: *BugLog, s: *u8) -> i64 {
214 return nx_buglog_set_why(e, s, nx_buglog_slen(s))
215}
216func nx_buglog_set_how_z(e: *BugLog, s: *u8) -> i64 {
217 return nx_buglog_set_how(e, s, nx_buglog_slen(s))
218}
219func nx_buglog_set_performance_z(e: *BugLog, s: *u8) -> i64 {
220 return nx_buglog_set_performance(e, s, nx_buglog_slen(s))
221}
222func nx_buglog_add_genealogy_z(e: *BugLog, s: *u8) -> i64 {
223 return nx_buglog_add_genealogy(e, s, nx_buglog_slen(s))
224}
225func nx_buglog_add_lineage_z(e: *BugLog, s: *u8) -> i64 {
226 return nx_buglog_add_lineage(e, s, nx_buglog_slen(s))
227}
228
229// === axis -> string ==============================================
230
231func nx_buglog_axis_str(axis: i64) -> *u8 {
232 if axis == NX_BUG_AXIS_ACCURACY { return "accuracy" }
233 if axis == NX_BUG_AXIS_MEMORY { return "memory" }
234 if axis == NX_BUG_AXIS_TIME { return "time" }
235 if axis == NX_BUG_AXIS_CAPABILITY { return "capability" }
236 if axis == NX_BUG_AXIS_USABILITY { return "usability" }
237 return "unknown"
238}
239
240func nx_buglog_axis_strlen(axis: i64) -> i64 {
241 if axis == NX_BUG_AXIS_ACCURACY { return 8 }
242 if axis == NX_BUG_AXIS_MEMORY { return 6 }
243 if axis == NX_BUG_AXIS_TIME { return 4 }
244 if axis == NX_BUG_AXIS_CAPABILITY { return 10 }
245 if axis == NX_BUG_AXIS_USABILITY { return 9 }
246 return 7
247}
248
249// === JSON emit ===================================================
250
251func nx_buglog_w(s: *u8, len: i64) -> i64 {
252 sys_write(1, s, len)
253 return 0
254}
255
256func nx_buglog_emit_field(name: *u8, name_len: i64,
257 value: *u8, value_len: i64,
258 trailing_comma: i64) -> i64 {
259 nx_buglog_w("\"", 1)
260 nx_buglog_w(name, name_len)
261 nx_buglog_w("\":\"", 3)
262 nx_buglog_w(value, value_len)
263 nx_buglog_w("\"", 1)
264 if trailing_comma == 1 { nx_buglog_w(",", 1) }
265 return 0
266}
267
268func nx_buglog_emit_id_array(name: *u8, name_len: i64,
269 arr: *StrSlice, n: i64,
270 trailing_comma: i64) -> i64 {
271 nx_buglog_w("\"", 1)
272 nx_buglog_w(name, name_len)
273 nx_buglog_w("\":[", 3)
274 var i: i64 = 0
275 while i < n {
276 let slot: *StrSlice = nx_buglog_slice_at(arr, i)
277 nx_buglog_w("\"", 1)
278 nx_buglog_w(slot.s, slot.len)
279 nx_buglog_w("\"", 1)
280 if i < n - 1 { nx_buglog_w(",", 1) }
281 i = i + 1
282 }
283 nx_buglog_w("]", 1)
284 if trailing_comma == 1 { nx_buglog_w(",", 1) }
285 return 0
286}
287
288func nx_buglog_emit_raw_json(name: *u8, name_len: i64,
289 value: *u8, value_len: i64,
290 trailing_comma: i64) -> i64 {
291 nx_buglog_w("\"", 1)
292 nx_buglog_w(name, name_len)
293 nx_buglog_w("\":", 2)
294 if value_len == 0 { nx_buglog_w("null", 4) }
295 if value_len > 0 { nx_buglog_w(value, value_len) }
296 if trailing_comma == 1 { nx_buglog_w(",", 1) }
297 return 0
298}
299
300func nx_buglog_emit(e: *BugLog) -> i64 {
301 nx_buglog_w("{", 1)
302 let kind_s: *u8 = nx_buglog_kind_str(e.kind)
303 let kind_l: i64 = nx_buglog_kind_strlen(e.kind)
304 nx_buglog_emit_field("kind", 4, kind_s, kind_l, 1)
305 nx_buglog_emit_field("who", 3, e.who, e.who_len, 1)
306 nx_buglog_emit_field("what", 4, e.what, e.what_len, 1)
307 nx_buglog_emit_field("when", 4, e.when_iso, e.when_iso_len, 1)
308 let axis_s: *u8 = nx_buglog_axis_str(e.where_axis)
309 let axis_l: i64 = nx_buglog_axis_strlen(e.where_axis)
310 nx_buglog_emit_field("where", 5, axis_s, axis_l, 1)
311 nx_buglog_emit_field("why", 3, e.why, e.why_len, 1)
312 nx_buglog_emit_field("how", 3, e.how, e.how_len, 1)
313 nx_buglog_emit_id_array("genealogy_ids", 13, e.genealogy, e.n_genealogy, 1)
314 nx_buglog_emit_id_array("lineage_ids", 11, e.lineage, e.n_lineage, 1)
315 nx_buglog_emit_raw_json("performance", 11, e.performance, e.performance_len, 0)
316 nx_buglog_w("}\n", 2)
317 return 0
318}
319
320func nx_buglog_query(e: *BugLog) -> *ApproxI64 {
321 return nx_approx_new(e.where_axis, NX_ENV_ABS, 0, 1000000000,
322 NX_MATURITY_PRODUCTION,
323 NX_ADV_HONEST)
324}
325
326func nx_buglog_n_genealogy(e: *BugLog) -> i64 { return e.n_genealogy }
327func nx_buglog_n_lineage(e: *BugLog) -> i64 { return e.n_lineage }
328
329func nx_buglog_memory_bytes(e: *BugLog) -> i64 {
330 return 192 + NX_BUG_MAX_GENEALOGY * 16 + NX_BUG_MAX_LINEAGE * 16
331}