code wiki / _hdl_build / nx_lineage_deep.nx
nx_lineage_deep.nx source
↩ module page · 189 lines · 10330 B
1// nx_lineage_deep.nx -- LIB: DEEPER provenance (R-DEEP). Two real-world traceability gaps closed:
2// (1) MULTI-PARENT CROSSES -- a hybrid traces to BOTH parents (parent_a x parent_b), and a cross is detected
3// as such. nx_lineage stored parent_b but only walked parent_a; this reads both.
4// (2) HARVEST-LOT SPLITTING -- one harvest is a LOT that splits into many child lots (sauce, fresh, seed,
5// jars, plates), each linked to its parent lot. ANY leaf (a jar on the table) traces back through the
6// split chain to the harvest -> the plant -> its full seed-to-feed lineage + genetics. "One harvest ->
7// many plates, each individually traceable to the exact plant and its seed." Conservation: a lot can't
8// be split beyond what remains. Additive (rule 13). Same bio- store as nx_lineage. license_tier: ORIGINAL
9import "nx_lineage.nx"
10import "nx_seg_store.nx"
11import "nx_syscalls.nx"
12
13func ld_put(prefix: *u8, key: *u8, val: *u8) -> i64 {
14 let vl: i64 = as_len(val)
15 if fd_streq_store(prefix, key, val, vl) == 1 { return 0 }
16 let w: *i64 = ss_begin()
17 ss_add(w, 1, key, val, vl)
18 let seg: i64 = fd_seg_next(prefix)
19 ss_commit(prefix, w, seg)
20 return 1
21}
22
23// ---- (1) multi-parent crosses ----
24func ld_parents(prefix: *u8, id: *u8, out_a: *u8, out_b: *u8) -> i64 {
25 ln_field_str(prefix, id, 4, out_a)
26 ln_field_str(prefix, id, 5, out_b)
27 return 0
28}
29// 1 if `id` is a hybrid cross: two distinct, present parents.
30func ld_is_cross(prefix: *u8, id: *u8) -> i64 {
31 let a: *u8 = sys_mmap(64); let b: *u8 = sys_mmap(64)
32 ld_parents(prefix, id, a, b)
33 if a[0] == (0 as u8) { return 0 }
34 if b[0] == (0 as u8) { return 0 }
35 if fd_streq(a, "-" as *u8) == 1 { return 0 }
36 if fd_streq(b, "-" as *u8) == 1 { return 0 }
37 if fd_streq(a, b) == 1 { return 0 }
38 return 1
39}
40// "<name> = <parentA name> x <parentB name>" for a cross; just "<name>" otherwise. NUL-terminated.
41func ld_cross_label(prefix: *u8, id: *u8, out: *u8) -> i64 {
42 let nm: *u8 = sys_mmap(96); ln_field_str(prefix, id, 0, nm)
43 var o: i64 = 0
44 o = as_append(out, o, nm)
45 if ld_is_cross(prefix, id) == 1 {
46 let a: *u8 = sys_mmap(64); let b: *u8 = sys_mmap(64)
47 ld_parents(prefix, id, a, b)
48 let an: *u8 = sys_mmap(96); ln_field_str(prefix, a, 0, an)
49 let bn: *u8 = sys_mmap(96); ln_field_str(prefix, b, 0, bn)
50 o = as_append(out, o, " = " as *u8)
51 o = as_append(out, o, an)
52 o = as_append(out, o, " x " as *u8)
53 o = as_append(out, o, bn)
54 }
55 out[o] = 0 as u8
56 return o
57}
58
59// ---- (2) harvest-lot splitting ----
60// lot:<lotid> -> org_id <t> parent_lot <t> quantity <t> unit <t> purpose <t> day (org_id "-" on splits; "-" parent_lot = root)
61func ld_lot_key(lotid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "lot:" as *u8); o = as_append(out, o, lotid); out[o] = 0 as u8; return o }
62func ld_alloc_key(lotid: *u8, out: *u8) -> i64 { var o: i64 = 0; o = as_append(out, o, "lot:alloc:" as *u8); o = as_append(out, o, lotid); out[o] = 0 as u8; return o }
63
64func ld_lot_str(prefix: *u8, lotid: *u8, f: i64, out: *u8) -> i64 {
65 let key: *u8 = sys_mmap(96); ld_lot_key(lotid, key)
66 let pq: *i64 = sys_mmap(16) as *i64
67 let lq: *i64 = sys_mmap(16) as *i64
68 if ss_get(prefix, key, pq, lq) != 1 { out[0] = 0 as u8; return 0 }
69 return fd_field(pq[0] as *u8, lq[0], f, out)
70}
71func ld_lot_int(prefix: *u8, lotid: *u8, f: i64) -> i64 {
72 let fb: *u8 = sys_mmap(24)
73 let fl: i64 = ld_lot_str(prefix, lotid, f, fb)
74 if fl == 0 { return 0 }
75 return fd_atoi(fb, fl)
76}
77func ld_lot_exists(prefix: *u8, lotid: *u8) -> i64 {
78 let key: *u8 = sys_mmap(96); ld_lot_key(lotid, key)
79 let pq: *i64 = sys_mmap(16) as *i64
80 let lq: *i64 = sys_mmap(16) as *i64
81 if ss_get(prefix, key, pq, lq) != 1 { return 0 }
82 return 1
83}
84// a root harvest lot from an org's harvest.
85func ld_create_lot(prefix: *u8, lotid: *u8, org_id: *u8, quantity: i64, unit: *u8, day: i64) -> i64 {
86 let key: *u8 = sys_mmap(96); ld_lot_key(lotid, key)
87 let val: *u8 = sys_mmap(256); var v: i64 = 0
88 v = as_append(val, v, org_id); val[v] = 9 as u8; v = v + 1
89 val[v] = 45 as u8; v = v + 1; val[v] = 9 as u8; v = v + 1 // parent_lot "-" (root)
90 v = fd_apnum(val, v, quantity); val[v] = 9 as u8; v = v + 1
91 v = as_append(val, v, unit); val[v] = 9 as u8; v = v + 1
92 v = as_append(val, v, "harvest" as *u8); val[v] = 9 as u8; v = v + 1
93 v = fd_apnum(val, v, day); val[v] = 0 as u8
94 return ld_put(prefix, key, val)
95}
96func ld_alloc(prefix: *u8, lotid: *u8) -> i64 {
97 let key: *u8 = sys_mmap(96); ld_alloc_key(lotid, key)
98 let pq: *i64 = sys_mmap(16) as *i64
99 let lq: *i64 = sys_mmap(16) as *i64
100 if ss_get(prefix, key, pq, lq) != 1 { return 0 }
101 return fd_atoi(pq[0] as *u8, lq[0])
102}
103func ld_lot_remaining(prefix: *u8, lotid: *u8) -> i64 { return ld_lot_int(prefix, lotid, 2) - ld_alloc(prefix, lotid) }
104// split a child lot off a parent. Refuses (0) if it would exceed what remains (conservation). Returns 1 on success.
105func ld_split_lot(prefix: *u8, parent_lotid: *u8, child_lotid: *u8, quantity: i64, unit: *u8, purpose: *u8, day: i64) -> i64 {
106 if quantity <= 0 { return 0 }
107 if ld_lot_exists(prefix, parent_lotid) == 0 { return 0 }
108 if ld_lot_remaining(prefix, parent_lotid) < quantity { return 0 }
109 let key: *u8 = sys_mmap(96); ld_lot_key(child_lotid, key)
110 let val: *u8 = sys_mmap(256); var v: i64 = 0
111 val[v] = 45 as u8; v = v + 1; val[v] = 9 as u8; v = v + 1 // org_id "-" (inherit via the chain)
112 v = as_append(val, v, parent_lotid); val[v] = 9 as u8; v = v + 1
113 v = fd_apnum(val, v, quantity); val[v] = 9 as u8; v = v + 1
114 v = as_append(val, v, unit); val[v] = 9 as u8; v = v + 1
115 v = as_append(val, v, purpose); val[v] = 9 as u8; v = v + 1
116 v = fd_apnum(val, v, day); val[v] = 0 as u8
117 ld_put(prefix, key, val)
118 let ak: *u8 = sys_mmap(96); ld_alloc_key(parent_lotid, ak)
119 let nv: *u8 = sys_mmap(16); var no: i64 = fd_apnum(nv, 0, ld_alloc(prefix, parent_lotid) + quantity); nv[no] = 0 as u8
120 ld_put(prefix, ak, nv)
121 return 1
122}
123// trace a lot back to its root harvest: "lotid <- parent <- ... <- root"; returns hop count.
124func ld_lot_trace(prefix: *u8, lotid: *u8, out: *u8) -> i64 {
125 var o: i64 = 0
126 let cur: *u8 = sys_mmap(64)
127 var t: i64 = 0
128 while lotid[t] != (0 as u8) { cur[t] = lotid[t]; t = t + 1 } cur[t] = 0 as u8
129 var hops: i64 = 0
130 var guard: i64 = 0
131 var go: i64 = 1
132 while go == 1 {
133 if guard >= 64 { go = 0 } else {
134 o = as_append(out, o, cur)
135 let p: *u8 = sys_mmap(64); ld_lot_str(prefix, cur, 1, p)
136 if p[0] == (0 as u8) { go = 0 } else {
137 if fd_streq(p, "-" as *u8) == 1 { go = 0 } else {
138 o = as_append(out, o, " <- " as *u8)
139 var u: i64 = 0; while p[u] != (0 as u8) { cur[u] = p[u]; u = u + 1 } cur[u] = 0 as u8
140 hops = hops + 1
141 }
142 }
143 guard = guard + 1
144 }
145 }
146 out[o] = 0 as u8
147 return hops
148}
149// the origin organism of any lot: walk parent_lot to the root, return the root's org_id. ""/empty if broken.
150func ld_lot_origin_org(prefix: *u8, lotid: *u8, out: *u8) -> i64 {
151 let cur: *u8 = sys_mmap(64)
152 var t: i64 = 0
153 while lotid[t] != (0 as u8) { cur[t] = lotid[t]; t = t + 1 } cur[t] = 0 as u8
154 var guard: i64 = 0
155 while guard < 64 {
156 let p: *u8 = sys_mmap(64); ld_lot_str(prefix, cur, 1, p)
157 if p[0] == (0 as u8) { ld_lot_str(prefix, cur, 0, out); return 1 }
158 if fd_streq(p, "-" as *u8) == 1 { ld_lot_str(prefix, cur, 0, out); return 1 }
159 var u: i64 = 0; while p[u] != (0 as u8) { cur[u] = p[u]; u = u + 1 } cur[u] = 0 as u8
160 guard = guard + 1
161 }
162 out[0] = 0 as u8
163 return 0
164}
165
166// render a lot's provenance: the split chain -> the plant -> its lineage + genetics. Sovereign no-JS.
167func ld_render_lot(prefix: *u8, lotid: *u8, out: *u8) -> i64 {
168 let org: *u8 = sys_mmap(64); ld_lot_origin_org(prefix, lotid, org)
169 let orgnm: *u8 = sys_mmap(96); ln_field_str(prefix, org, 0, orgnm)
170 let variety: *u8 = sys_mmap(96); ln_field_str(prefix, org, 2, variety)
171 var o: i64 = 0
172 o = as_append(out, o, "<!doctype html><html lang='en'><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'><title>Lot provenance</title><style>body{margin:0;font-family:system-ui,sans-serif;color:#22301d;background:#f3f7ee;line-height:1.5}header{background:#3a5a2a;color:#fff;padding:22px}header h1{margin:0;font-size:1.4rem}main{max-width:680px;margin:0 auto;padding:16px}section{background:#fff;border-radius:12px;padding:16px 18px;margin-top:14px;box-shadow:0 1px 0 #e2e8d6}h2{font-size:1.05rem;margin:0 0 8px;color:#3a5a2a}.chain{font-family:ui-monospace,monospace;background:#eef3e6;padding:8px 10px;border-radius:8px}.good{color:#2c6b1f;font-weight:700}.muted{color:#54614a;font-size:.88rem}</style></head><body><header><h1>This lot — where it came from</h1></header><main>" as *u8)
173 o = as_append(out, o, "<section><h2>Split chain back to the harvest</h2><p class='chain'>" as *u8)
174 let chain: *u8 = sys_mmap(512); ld_lot_trace(prefix, lotid, chain)
175 o = as_append_escaped(out, o, chain, as_len(chain))
176 o = as_append(out, o, "</p></section><section><h2>The plant it grew on</h2><p><b>" as *u8)
177 o = as_append_escaped(out, o, orgnm, as_len(orgnm))
178 o = as_append(out, o, "</b> — " as *u8)
179 o = as_append_escaped(out, o, variety, as_len(variety))
180 o = as_append(out, o, "<br>Genetic quality: <b>" as *u8); o = fd_apnum(out, o, ln_quality_score(prefix, org)); o = as_append(out, o, "/100</b> " as *u8)
181 if ln_is_superior(prefix, org) == 1 { o = as_append(out, o, "<span class='good'>(superior strain)</span>" as *u8) }
182 if ld_is_cross(prefix, org) == 1 {
183 let cl: *u8 = sys_mmap(256); ld_cross_label(prefix, org, cl)
184 o = as_append(out, o, "<br>Cross: " as *u8); o = as_append_escaped(out, o, cl, as_len(cl))
185 }
186 o = as_append(out, o, "</p></section><p class='muted'>Every plate traces to the exact plant and its seed — one harvest, many plates, all accounted for.</p></main></body></html>" as *u8)
187 out[o] = 0 as u8
188 return o
189}