code wiki / _hdl_build / nx_reorder_gate.nx
nx_reorder_gate.nx source
↩ module page · 139 lines · 8661 B
1// nx_reorder_gate.nx -- GATE: R-REORDER. The supply-chain management layer that closes the loop: par levels ->
2// low-stock detection -> a shopping list generated from what a meal plan consumed. Proves: T1 par set/get,
3// T2 low-stock detection (qty<par, with correct buy quantity), T3 meal-plan integration (consuming ingredients
4// drops them below par -> onto the list), T4 sovereign shopping-list render, T5 SHIPPED via publisher.
5// license_tier: ORIGINAL
6import "nx_shopping.nx"
7import "nx_pantry.nx"
8import "nx_inventory.nx"
9import "nx_food_science.nx"
10import "nx_publisher.nx"
11import "nx_syscalls.nx"
12
13const RO_FOOD: *u8 = "knowledge/store/food-"
14const RO_INV: *u8 = "knowledge/store/inv-"
15const RO_DOM: *u8 = "home"
16const RO_Q: *u8 = "knowledge/publish/shop-queue.tsv"
17const RO_LED: *u8 = "knowledge/publish/shop-ledger.tsv"
18const RO_STG: *u8 = "knowledge/publish/shop-stage"
19const RO_LIVE: *u8 = "knowledge/publish/shop-live"
20const RO_STAGE_FILE: *u8 = "knowledge/staging/shop/list.html"
21const RO_LIVE_FILE: *u8 = "knowledge/publish/shop-live/shopping-list.html"
22
23func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
24func g_i(v: i64) -> i64 {
25 let bb: *u8 = sys_mmap(28); var m: i64 = v
26 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
27 let t: *u8 = sys_mmap(28); var k: i64 = 0
28 if m == 0 { t[0] = 48 as u8; k = 1 }
29 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
30 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
31}
32func g_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 }
33func g_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
34// need for a given id in (ids,need)[0..n); -1 if absent
35func g_need(ids: *i64, need: *i64, n: i64, target: *u8) -> i64 { var i: i64 = 0; while i < n { if g_streq(ids[i] as *u8, target) == 1 { return need[i] } i = i + 1 } return 0 - 1 }
36
37// stock a stir-fry ingredient with par == qty (so cooking one drops it below par)
38func ro_stock(id: *u8, name: *u8, cat: *u8, qty: i64, unit: *u8) -> i64 {
39 iv_add(RO_INV, RO_DOM, id, name, cat, qty, unit, "kitchen" as *u8, 0, 0, "-" as *u8)
40 iv_set_par(RO_INV, RO_DOM, id, qty)
41 return 0
42}
43
44func main() -> i64 {
45 g_p("=== nx_reorder_gate (R-REORDER: par -> low-stock -> shopping list from a meal plan) ===\n" as *u8)
46 fd_seed(RO_FOOD)
47
48 // stir-fry ingredients (par = qty)
49 ro_stock("chicken" as *u8, "Chicken" as *u8, "protein" as *u8, 2, "lb" as *u8)
50 ro_stock("tofu" as *u8, "Tofu" as *u8, "protein" as *u8, 2, "block" as *u8)
51 ro_stock("broccoli" as *u8, "Broccoli" as *u8, "produce" as *u8, 2, "head" as *u8)
52 ro_stock("onion" as *u8, "Onion" as *u8, "produce" as *u8, 3, "ea" as *u8)
53 ro_stock("snowpea" as *u8, "Snow Peas" as *u8, "produce" as *u8, 2, "bag" as *u8)
54 ro_stock("garlic" as *u8, "Garlic" as *u8, "produce" as *u8, 2, "bulb" as *u8)
55 ro_stock("ginger" as *u8, "Ginger" as *u8, "produce" as *u8, 2, "knob" as *u8)
56 ro_stock("soy" as *u8, "Soy Sauce" as *u8, "condiment" as *u8, 2, "bottle" as *u8)
57 ro_stock("oyster" as *u8, "Oyster Sauce" as *u8, "condiment" as *u8, 2, "bottle" as *u8)
58 ro_stock("rice" as *u8, "Rice" as *u8, "grain" as *u8, 2, "bag" as *u8)
59 // household staples already low (test detection independent of cooking)
60 iv_add(RO_INV, RO_DOM, "eggs" as *u8, "Eggs" as *u8, "dairy" as *u8, 1, "dozen" as *u8, "fridge" as *u8, 0, 0, "-" as *u8); iv_set_par(RO_INV, RO_DOM, "eggs" as *u8, 3)
61 iv_add(RO_INV, RO_DOM, "milk" as *u8, "Milk" as *u8, "dairy" as *u8, 0, "carton" as *u8, "fridge" as *u8, 0, 0, "-" as *u8); iv_set_par(RO_INV, RO_DOM, "milk" as *u8, 2)
62 iv_add(RO_INV, RO_DOM, "flour" as *u8, "Flour" as *u8, "baking" as *u8, 5, "bag" as *u8, "pantry" as *u8, 0, 0, "-" as *u8); iv_set_par(RO_INV, RO_DOM, "flour" as *u8, 2)
63
64 let world: *i64 = fd_world_open(RO_FOOD)
65 let names: *i64 = world[4] as *i64
66
67 var pass: i64 = 0
68 var tot: i64 = 0
69
70 // T1 par set/get
71 tot = tot + 1
72 var ok1: i64 = 1
73 if iv_get_par(RO_INV, RO_DOM, "eggs" as *u8) != 3 { ok1 = 0 }
74 if iv_get_par(RO_INV, RO_DOM, "chicken" as *u8) != 2 { ok1 = 0 }
75 if iv_get_par(RO_INV, RO_DOM, "nope" as *u8) != 0 { ok1 = 0 } // untracked -> 0
76 if ok1 == 1 { pass = pass + 1; g_p("PASS T1 par levels set/get\n" as *u8) } else { g_p("FAIL T1\n" as *u8) }
77
78 // T2 low-stock BEFORE cooking (only the already-low staples)
79 let lid: *i64 = sys_mmap(8 * 256) as *i64
80 let lneed: *i64 = sys_mmap(8 * 256) as *i64
81 let nlo0: i64 = iv_low_stock(RO_INV, RO_DOM, lid, lneed)
82 g_p("low before cooking=" as *u8); g_i(nlo0); g_p(" (eggs need " as *u8); g_i(g_need(lid, lneed, nlo0, "eggs" as *u8)); g_p(", milk need " as *u8); g_i(g_need(lid, lneed, nlo0, "milk" as *u8)); g_p(")\n" as *u8)
83 tot = tot + 1
84 var ok2: i64 = 1
85 if nlo0 != 2 { ok2 = 0 }
86 if g_need(lid, lneed, nlo0, "eggs" as *u8) != 2 { ok2 = 0 } // par3 - qty1
87 if g_need(lid, lneed, nlo0, "milk" as *u8) != 2 { ok2 = 0 } // par2 - qty0
88 if g_need(lid, lneed, nlo0, "flour" as *u8) != (0 - 1) { ok2 = 0 } // well-stocked -> not listed
89 if ok2 == 1 { pass = pass + 1; g_p("PASS T2 low-stock detection (eggs+milk to buy, flour not)\n" as *u8) } else { g_p("FAIL T2\n" as *u8) }
90
91 // T3 cook a meal from the pantry -> consumed ingredients drop below par -> onto the reorder list
92 let avail: *i64 = sys_mmap(8 * 64) as *i64
93 fp_pantry_avail(world, RO_INV, RO_DOM, avail)
94 let b1: *i64 = sys_mmap(8 * 16) as *i64; let r1: *i64 = sys_mmap(8 * 16) as *i64
95 let nb1: i64 = fp_choose(RO_FOOD, world, avail, b1, r1)
96 g_p("cooked: " as *u8)
97 var si: i64 = 0; while si < nb1 { if si > 0 { g_p(" | " as *u8) } g_p(names[b1[si]] as *u8); si = si + 1 } g_p("\n" as *u8)
98 fp_consume_build(RO_INV, RO_DOM, world, b1, nb1)
99 let nlo1: i64 = iv_low_stock(RO_INV, RO_DOM, lid, lneed)
100 g_p("low after cooking=" as *u8); g_i(nlo1); g_p("\n" as *u8)
101 let widx: *i64 = world[1] as *i64
102 let protein_id: *u8 = widx[b1[0]] as *u8
103 g_p(" cooked protein id=" as *u8); g_p(protein_id); g_p(" need=" as *u8); g_i(g_need(lid, lneed, nlo1, protein_id)); g_p("\n" as *u8)
104 tot = tot + 1
105 var ok3: i64 = 1
106 if nb1 != 5 { ok3 = 0 }
107 if nlo1 != 7 { ok3 = 0 } // 2 staples + 5 cooked ingredients
108 if g_need(lid, lneed, nlo1, protein_id) != 1 { ok3 = 0 } // cooked protein now short by 1
109 if ok3 == 1 { pass = pass + 1; g_p("PASS T3 meal -> reorder: cooking dropped 5 ingredients below par (low 2 -> 7)\n" as *u8) } else { g_p("FAIL T3 nlo1=" as *u8); g_i(nlo1); g_p("\n" as *u8) }
110
111 // T4 render the shopping list (sovereign, lists low items + buy quantities)
112 let page: *u8 = sys_mmap(65536)
113 let np: i64 = sh_render_list(RO_INV, RO_DOM, "Your shopping list" as *u8, page)
114 tot = tot + 1
115 var ok4: i64 = 1
116 if as_has_thirdparty_js(page, np) != 0 { ok4 = 0 }
117 if as_contains(page, np, "Milk" as *u8) != 1 { ok4 = 0 }
118 if as_contains(page, np, names[b1[0]] as *u8) != 1 { ok4 = 0 } // cooked protein on the list
119 if as_contains(page, np, "Buy 7 item" as *u8) != 1 { ok4 = 0 }
120 if ok4 == 1 { pass = pass + 1; g_p("PASS T4 sovereign shopping list (" as *u8); g_i(np); g_p(" bytes, 7 items, 0 JS)\n" as *u8) } else { g_p("FAIL T4\n" as *u8) }
121
122 // T5 ship via the publisher
123 sys_mkdir("knowledge/staging" as *u8, 0x1ed)
124 sys_mkdir("knowledge/staging/shop" as *u8, 0x1ed)
125 let sfd: i64 = sys_openat_wr(RO_STAGE_FILE, 420); if sfd >= 0 { sys_write(sfd, page, np); sys_close(sfd) }
126 pub_init()
127 sys_mkdir(RO_STG, 0x1ed)
128 sys_mkdir(RO_LIVE, 0x1ed)
129 pub_submit_to(RO_Q, RO_STAGE_FILE, "shopping-list.html" as *u8, "nishifamily" as *u8, "nishi-home" as *u8, "internal" as *u8)
130 let pubd: i64 = pub_run_full(RO_Q, RO_LED, RO_STG, RO_LIVE, "publish:shop" as *u8)
131 g_p(" pub_run_full -> published_this_pass=" as *u8); g_i(pubd); g_p("\n" as *u8)
132 tot = tot + 1
133 if g_exists(RO_LIVE_FILE) == 1 { pass = pass + 1; g_p("PASS T5 SHIPPED the shopping list to liveroot\n" as *u8) } else { g_p("FAIL T5\n" as *u8) }
134
135 g_p("nx_reorder_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot)
136 if pass == tot { g_p(" verdict=GREEN (supply-chain loop CLOSED: consume -> low-stock -> shopping list -> shipped)\n" as *u8); return 0 }
137 g_p(" verdict=RED\n" as *u8)
138 return 1
139}