nx_crm_store.nx source
↩ module page · 280 lines · 12420 B
1// nx_crm_store.nx -- PERSISTENCE for deals + giving (the DEPTH rung after full-presence 1000): the pipeline and
2// the church statements survive across runs on the sovereign APPEND-ONLY seg_store (additive, tombstone-not-delete,
3// content-addressed = tamper-evident, on YOUR hardware -- the CRM exceed made concrete for the money records).
4// Records: key "dea:"+cid {kind=dea,name,account,amount,stage} ยท key "giv:"+cid {kind=giv,donor,fund,amount,gtype}.
5// THE DEPTH PROOF: the weighted forecast and the household giving statement are recomputed FROM THE STORE and must
6// equal the in-memory oracles of nx_crm/nx_org ($122,500 forecast; $1,350 received) -- two independent paths, one
7// truth. Saves VALIDATE (unknown stage / bad gift type = LOUD -1, nothing committed). Additivity proven: a second
8// commit adds a deal and the recomputed forecast moves exactly (+Lead 40000 -> +4000 weighted).
9// Composes the nx_crm pure core (stage_prob/stage_open/gift vocab lives beside) + canon_cid + seg_store.
10// Argless = selftest gate. license_tier: ORIGINAL expect_exit: 0
11import "nx_crm.nx"
12import "nx_canon_cid.nx"
13import "nx_seg_store.nx"
14const K_MAGIC_2048: i64 = 2048
15const K_MAGIC_50000: i64 = 50000
16const K_MAGIC_120000: i64 = 120000
17const K_MAGIC_30000: i64 = 30000
18const K_MAGIC_20000: i64 = 20000
19const K_MAGIC_200000: i64 = 200000
20const K_MAGIC_122500: i64 = 122500
21const K_MAGIC_1350: i64 = 1350
22const K_MAGIC_40000: i64 = 40000
23const K_MAGIC_240000: i64 = 240000
24const K_MAGIC_126500: i64 = 126500
25
26func cs_kmemeq(b: *u8, off: i64, n: i64, s: *u8) -> i64 {
27 if slen(s) != n { return 0 }
28 var i: i64 = 0
29 while i < n { if b[off + i] != s[i] { return 0 } i = i + 1 }
30 return 1
31}
32func cs_iskind(b: *u8, koff: i64, kl: i64, pfx: *u8) -> i64 {
33 if kl <= 4 { return 0 }
34 return cs_kmemeq(b, koff, 4, pfx)
35}
36func cs_field(rec: *u8, rl: i64, want: *u8, out: *u8, cap: i64) -> i64 {
37 if rl < 8 { return 0 }
38 let nf: i64 = ss_r32(rec, 4)
39 var off: i64 = 8
40 var fi: i64 = 0
41 while fi < nf {
42 if off + 8 > rl { return 0 }
43 let kl: i64 = ss_r32(rec, off)
44 let koff: i64 = off + 4
45 let vl: i64 = ss_r32(rec, koff + kl)
46 let voff: i64 = koff + kl + 4
47 if cs_kmemeq(rec, koff, kl, want) == 1 {
48 var t: i64 = 0
49 while t < vl { if t < cap - 1 { out[t] = rec[voff + t] } t = t + 1 }
50 if t > cap - 1 { t = cap - 1 }
51 out[t] = 0 as u8
52 return 1
53 }
54 off = voff + vl
55 fi = fi + 1
56 }
57 return 0
58}
59func cs_atoi(s: *u8) -> i64 {
60 var v: i64 = 0
61 var i: i64 = 0
62 while s[i] != (0 as u8) {
63 let d: i64 = (s[i] as i64) - 48
64 if d >= 0 { if d <= 9 { v = v * 10 + d } }
65 i = i + 1
66 }
67 return v
68}
69func cs_gift_ok(t: *u8) -> i64 {
70 if seq(t, "donation" as *u8) == 1 { return 1 }
71 if seq(t, "recurring" as *u8) == 1 { return 1 }
72 if seq(t, "pledge-payment" as *u8) == 1 { return 1 }
73 if seq(t, "in-kind" as *u8) == 1 { return 1 }
74 if seq(t, "soft-credit" as *u8) == 1 { return 1 }
75 return 0
76}
77// save one deal (VALIDATED: unknown stage = -1, nothing added)
78func cs_save_deal(w: *i64, name: *u8, account: *u8, amount: i64, stage: *u8) -> i64 {
79 if stage_valid(stage) == 0 { p("CRM-STORE save_deal unknown stage -- fail loud\n" as *u8); return 0 - 1 }
80 if amount < 0 { return 0 - 1 }
81 let ab: *u8 = sys_mmap(32)
82 var ao: i64 = 0
83 ao = ss_catn(ab, ao, amount)
84 ab[ao] = 0 as u8
85 let keys: *i64 = sys_mmap(8 * 8) as *i64
86 let vals: *i64 = sys_mmap(8 * 8) as *i64
87 keys[0]="kind" as *u8 as i64; keys[1]="name" as *u8 as i64; keys[2]="account" as *u8 as i64; keys[3]="amount" as *u8 as i64; keys[4]="stage" as *u8 as i64
88 vals[0]="dea" as *u8 as i64; vals[1]=name as i64; vals[2]=account as i64; vals[3]=ab as i64; vals[4]=stage as i64
89 let enc: *u8 = sys_mmap(K_MAGIC_2048)
90 let el: i64 = canon_encode(keys, vals, 5, enc)
91 let cid: *u8 = sys_mmap(96)
92 cid_of(enc, el, cid)
93 let key: *u8 = sys_mmap(128)
94 var ko: i64 = 0
95 ko = ss_cat(key, ko, "dea:" as *u8)
96 ko = ss_cat(key, ko, cid)
97 key[ko] = 0 as u8
98 return ss_add(w, 1, key, enc, el)
99}
100// save one gift (VALIDATED type)
101func cs_save_gift(w: *i64, donor: *u8, fund: *u8, amount: i64, gtype: *u8) -> i64 {
102 if cs_gift_ok(gtype) == 0 { p("CRM-STORE save_gift unknown type -- fail loud\n" as *u8); return 0 - 1 }
103 if amount < 0 { return 0 - 1 }
104 let ab: *u8 = sys_mmap(32)
105 var ao: i64 = 0
106 ao = ss_catn(ab, ao, amount)
107 ab[ao] = 0 as u8
108 let keys: *i64 = sys_mmap(8 * 8) as *i64
109 let vals: *i64 = sys_mmap(8 * 8) as *i64
110 keys[0]="kind" as *u8 as i64; keys[1]="donor" as *u8 as i64; keys[2]="fund" as *u8 as i64; keys[3]="amount" as *u8 as i64; keys[4]="gtype" as *u8 as i64
111 vals[0]="giv" as *u8 as i64; vals[1]=donor as i64; vals[2]=fund as i64; vals[3]=ab as i64; vals[4]=gtype as i64
112 let enc: *u8 = sys_mmap(K_MAGIC_2048)
113 let el: i64 = canon_encode(keys, vals, 5, enc)
114 let cid: *u8 = sys_mmap(96)
115 cid_of(enc, el, cid)
116 let key: *u8 = sys_mmap(128)
117 var ko: i64 = 0
118 ko = ss_cat(key, ko, "giv:" as *u8)
119 ko = ss_cat(key, ko, cid)
120 key[ko] = 0 as u8
121 return ss_add(w, 1, key, enc, el)
122}
123// recompute the pipeline FROM THE STORE: out[0]=open total, out[1]=weighted forecast, out[2]=won; returns deal count
124func cs_forecast(prefix: *u8, out: *i64) -> i64 {
125 out[0] = 0
126 out[1] = 0
127 out[2] = 0
128 let segp: *i64 = sys_mmap(16) as *i64
129 let ns: i64 = ss_manifest_dyn(prefix, segp) // uncapped: sees the WHOLE store, not the first legacy-cap segs
130 let segs: *i64 = segp[0] as *i64
131 let fa: *u8 = sys_mmap(64)
132 let fs: *u8 = sys_mmap(128)
133 var cnt: i64 = 0
134 var s: i64 = 0
135 while s < ns {
136 let path: *u8 = sys_mmap(512)
137 var po: i64 = 0
138 po = ss_cat(path, po, prefix)
139 po = ss_cat(path, po, segs[s] as *u8)
140 po = ss_cat(path, po, ".docs" as *u8)
141 path[po] = 0 as u8
142 let szp: *i64 = sys_mmap(16) as *i64
143 let b: *u8 = ss_readall(path, szp)
144 let sz: i64 = szp[0]
145 var j: i64 = 0
146 while j + 9 <= sz {
147 let kl: i64 = ss_r32(b, j + 1)
148 let koff: i64 = j + 5
149 let vl: i64 = ss_r32(b, koff + kl)
150 let voff: i64 = koff + kl + 4
151 if b[j] == 1 {
152 if cs_iskind(b, koff, kl, "dea:" as *u8) == 1 {
153 let rec: *u8 = (b as i64 + voff) as *u8
154 cs_field(rec, vl, "amount" as *u8, fa, 64)
155 cs_field(rec, vl, "stage" as *u8, fs, 128)
156 let amt: i64 = cs_atoi(fa)
157 if stage_open(fs) == 1 {
158 out[0] = out[0] + amt
159 out[1] = out[1] + (amt * stage_prob(fs)) / 100
160 }
161 if seq(fs, "ClosedWon" as *u8) == 1 { out[2] = out[2] + amt }
162 cnt = cnt + 1
163 }
164 }
165 j = voff + vl
166 }
167 s = s + 1
168 }
169 return cnt
170}
171// recompute giving FROM THE STORE: returns total; out[0]=count, out[1]=total for fundfilter (or all if filter[0]==0)
172func cs_giving(prefix: *u8, fundfilter: *u8, out: *i64) -> i64 {
173 out[0] = 0
174 out[1] = 0
175 let segp: *i64 = sys_mmap(16) as *i64
176 let ns: i64 = ss_manifest_dyn(prefix, segp) // uncapped: sees the WHOLE store
177 let segs: *i64 = segp[0] as *i64
178 let fa: *u8 = sys_mmap(64)
179 let ff: *u8 = sys_mmap(128)
180 var total: i64 = 0
181 var s: i64 = 0
182 while s < ns {
183 let path: *u8 = sys_mmap(512)
184 var po: i64 = 0
185 po = ss_cat(path, po, prefix)
186 po = ss_cat(path, po, segs[s] as *u8)
187 po = ss_cat(path, po, ".docs" as *u8)
188 path[po] = 0 as u8
189 let szp: *i64 = sys_mmap(16) as *i64
190 let b: *u8 = ss_readall(path, szp)
191 let sz: i64 = szp[0]
192 var j: i64 = 0
193 while j + 9 <= sz {
194 let kl: i64 = ss_r32(b, j + 1)
195 let koff: i64 = j + 5
196 let vl: i64 = ss_r32(b, koff + kl)
197 let voff: i64 = koff + kl + 4
198 if b[j] == 1 {
199 if cs_iskind(b, koff, kl, "giv:" as *u8) == 1 {
200 let rec: *u8 = (b as i64 + voff) as *u8
201 cs_field(rec, vl, "amount" as *u8, fa, 64)
202 cs_field(rec, vl, "fund" as *u8, ff, 128)
203 let amt: i64 = cs_atoi(fa)
204 total = total + amt
205 out[0] = out[0] + 1
206 if fundfilter[0] != (0 as u8) { if seq(ff, fundfilter) == 1 { out[1] = out[1] + amt } }
207 }
208 }
209 j = voff + vl
210 }
211 s = s + 1
212 }
213 return total
214}
215
216func main() -> i64 {
217 p("=== NX-CRM-STORE SELFTEST (deals + giving persisted; forecast + statement recomputed FROM THE STORE) ===\n" as *u8)
218 var ok: i64 = 1
219 let mt: *u8 = sys_mmap(4)
220 mt[0] = 0 as u8
221 let prefix: *u8 = sys_mmap(128)
222 var po: i64 = 0
223 po = ss_cat(prefix, po, "/tmp/crmstore_" as *u8)
224 po = ss_catn(prefix, po, sys_now_us())
225 po = ss_cat(prefix, po, "_" as *u8)
226 prefix[po] = 0 as u8
227
228 // commit 1: the exact nx_crm dashboard pipeline + the exact nx_org household gifts
229 let w: *i64 = ss_begin()
230 cs_save_deal(w, "Westfield Renovation" as *u8, "Westfield Group" as *u8, K_MAGIC_50000, "Proposal" as *u8)
231 cs_save_deal(w, "Riverside Contract" as *u8, "Riverside LLC" as *u8, K_MAGIC_120000, "Negotiation" as *u8)
232 cs_save_deal(w, "Downtown Lease" as *u8, "Downtown Co" as *u8, K_MAGIC_30000, "Qualified" as *u8)
233 cs_save_deal(w, "Old Bid" as *u8, "Old Co" as *u8, K_MAGIC_20000, "ClosedLost" as *u8)
234 cs_save_gift(w, "Rose" as *u8, "Tithing" as *u8, 500, "donation" as *u8)
235 cs_save_gift(w, "Rose" as *u8, "Missionary" as *u8, 100, "donation" as *u8)
236 cs_save_gift(w, "Ken" as *u8, "Tithing" as *u8, 300, "donation" as *u8)
237 cs_save_gift(w, "Rose" as *u8, "Humanitarian" as *u8, 50, "recurring" as *u8)
238 cs_save_gift(w, "Ken" as *u8, "Building" as *u8, 400, "pledge-payment" as *u8)
239 if ss_commit(prefix, w, sys_now_us()) != 0 { p("commit1 FAILED -- fail loud\n" as *u8); return 1 }
240
241 // recompute FROM THE STORE -- must equal the in-memory oracles (two independent paths, one truth)
242 let fo: *i64 = sys_mmap(8 * 4) as *i64
243 let d1: i64 = cs_forecast(prefix, fo)
244 p(" from-store: deals=" as *u8); pn(d1); p(" open=" as *u8); pn(fo[0]); p(" weighted=" as *u8); pn(fo[1]); p(" won=" as *u8); pn(fo[2]); p("\n" as *u8)
245 if d1 != 4 { ok = 0 }
246 if fo[0] != K_MAGIC_200000 { ok = 0 }
247 if fo[1] != K_MAGIC_122500 { ok = 0 }
248 if fo[2] != 0 { ok = 0 }
249 let go: *i64 = sys_mmap(8 * 4) as *i64
250 let gt: i64 = cs_giving(prefix, "Tithing" as *u8, go)
251 p(" from-store: gifts=" as *u8); pn(go[0]); p(" received=" as *u8); pn(gt); p(" tithing=" as *u8); pn(go[1]); p("\n" as *u8)
252 if go[0] != 5 { ok = 0 }
253 if gt != K_MAGIC_1350 { ok = 0 }
254 if go[1] != 800 { ok = 0 }
255
256 // additivity: a second commit adds one Lead deal -> the recomputed forecast moves EXACTLY
257 let w2: *i64 = ss_begin()
258 cs_save_deal(w2, "New Lead" as *u8, "Fresh Co" as *u8, K_MAGIC_40000, "Lead" as *u8)
259 if ss_commit(prefix, w2, sys_now_us()) != 0 { p("commit2 FAILED -- fail loud\n" as *u8); return 1 }
260 let d2: i64 = cs_forecast(prefix, fo)
261 p(" additive: deals=" as *u8); pn(d2); p(" open=" as *u8); pn(fo[0]); p(" weighted=" as *u8); pn(fo[1]); p("\n" as *u8)
262 if d2 != 5 { ok = 0 }
263 if fo[0] != K_MAGIC_240000 { ok = 0 }
264 if fo[1] != K_MAGIC_126500 { ok = 0 }
265
266 // validation: bad stage / bad gift type refuse LOUD and change nothing
267 let w3: *i64 = ss_begin()
268 let bd: i64 = cs_save_deal(w3, "Bad" as *u8, "X" as *u8, 1000, "Vibes" as *u8)
269 let bg: i64 = cs_save_gift(w3, "X" as *u8, "F" as *u8, 10, "bitcoin-rug" as *u8)
270 if bd != (0 - 1) { ok = 0 }
271 if bg != (0 - 1) { ok = 0 }
272 let d3: i64 = cs_forecast(prefix, fo)
273 if d3 != 5 { ok = 0 }
274 p(" validation: bad-stage=" as *u8); pn(bd); p(" bad-gift=" as *u8); pn(bg); p(" store-unchanged deals=" as *u8); pn(d3); p("\n" as *u8)
275
276 p("NX-CRM-STORE-SELFTEST prefix=" as *u8); p(prefix); p(" " as *u8)
277 if ok == 1 { p("verdict=GREEN (money records persisted, recomputed from store == in-memory oracles, additive)\n" as *u8); return 0 }
278 p("verdict=RED\n" as *u8)
279 return 1
280}