code wiki / _hdl_build / nx_pantry_meal_gate.nx
nx_pantry_meal_gate.nx source
↩ module page · 132 lines · 8015 B
1// nx_pantry_meal_gate.nx -- GATE: the pantry -> food-engine integration (the operator's chain: pantry ->
2// what's expiring -> what can I make -> meal planning). Proves: T1 "what can I make" builds a complete
3// stir-fry from ONLY in-stock ingredients, T2 "cook what's expiring first" forces an expiring protein
4// (Chicken/Tofu) over a fresh one (Beef), T3 a sovereign no-JS "Your Kitchen" page renders from the pantry,
5// T4 a 2-meal plan CONSUMES inventory (stock drops by exactly 2 meals x 5 ingredients). license_tier: ORIGINAL
6import "nx_pantry.nx"
7import "nx_food_site.nx"
8import "nx_inventory.nx"
9import "nx_syscalls.nx"
10import "nx_gate_verdict.nx"
11
12const PM_FOOD: *u8 = "knowledge/store/food-"
13const PM_INV: *u8 = "knowledge/store/inv-"
14const PM_DOM: *u8 = "kitchen"
15const PM_CAT: *u8 = "knowledge/registry/nishi_builder.tsv"
16
17func 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 }
18func g_i(v: i64) -> i64 {
19 let bb: *u8 = sys_mmap(28); var m: i64 = v
20 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
21 let t: *u8 = sys_mmap(28); var k: i64 = 0
22 if m == 0 { t[0] = 48 as u8; k = 1 }
23 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
24 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
25}
26func g_show(world: *i64, build: *i64, nb: i64) -> i64 {
27 let names: *i64 = world[4] as *i64
28 var i: i64 = 0
29 while i < nb { if i > 0 { g_p(" | " as *u8) } g_p(names[build[i]] as *u8); i = i + 1 }
30 g_p("\n" as *u8); return 0
31}
32
33func main() -> i64 {
34 g_p("=== nx_pantry_meal_gate (pantry -> what's expiring -> what can I make -> meal plan) ===\n" as *u8)
35 fd_seed(PM_FOOD)
36 fs_teach(PM_CAT)
37
38 // stock the kitchen (today = day 0; chicken/tofu expiring, beef fresh)
39 iv_add(PM_INV, PM_DOM, "beef" as *u8, "Beef" as *u8, "protein" as *u8, 1, "lb" as *u8, "fridge" as *u8, 0, 30, "" as *u8)
40 iv_add(PM_INV, PM_DOM, "chicken" as *u8, "Chicken" as *u8, "protein" as *u8, 2, "lb" as *u8, "fridge" as *u8, 0, 3, "" as *u8)
41 iv_add(PM_INV, PM_DOM, "tofu" as *u8, "Tofu" as *u8, "protein" as *u8, 1, "block" as *u8, "fridge" as *u8, 0, 2, "" as *u8)
42 iv_add(PM_INV, PM_DOM, "broccoli" as *u8, "Broccoli" as *u8, "veg" as *u8, 2, "head" as *u8, "fridge" as *u8, 0, 5, "" as *u8)
43 iv_add(PM_INV, PM_DOM, "onion" as *u8, "Onion" as *u8, "veg" as *u8, 3, "ea" as *u8, "pantry" as *u8, 0, 20, "" as *u8)
44 iv_add(PM_INV, PM_DOM, "snowpea" as *u8, "Snow Peas" as *u8, "veg" as *u8, 2, "bag" as *u8, "fridge" as *u8, 0, 6, "" as *u8)
45 iv_add(PM_INV, PM_DOM, "garlic" as *u8, "Garlic" as *u8, "aromatic" as *u8, 2, "bulb" as *u8, "pantry" as *u8, 0, 60, "" as *u8)
46 iv_add(PM_INV, PM_DOM, "ginger" as *u8, "Ginger" as *u8, "aromatic" as *u8, 2, "knob" as *u8, "fridge" as *u8, 0, 14, "" as *u8)
47 iv_add(PM_INV, PM_DOM, "soy" as *u8, "Soy Sauce" as *u8, "sauce" as *u8, 2, "bottle" as *u8, "pantry" as *u8, 0, 365, "" as *u8)
48 iv_add(PM_INV, PM_DOM, "oyster" as *u8, "Oyster Sauce" as *u8, "sauce" as *u8, 1, "bottle" as *u8, "pantry" as *u8, 0, 200, "" as *u8)
49 iv_add(PM_INV, PM_DOM, "rice" as *u8, "Rice" as *u8, "starch" as *u8, 2, "bag" as *u8, "pantry" as *u8, 0, 0, "" as *u8)
50
51 let world: *i64 = fd_world_open(PM_FOOD)
52 let n: i64 = world[0]
53 let ids: *i64 = world[1] as *i64
54 let names: *i64 = world[4] as *i64
55
56 var pass: i64 = 0
57 var tot: i64 = 0
58
59 // T1 "what can I make" from in-stock ingredients only
60 let avail: *i64 = sys_mmap(8 * 64) as *i64
61 let nav: i64 = fp_pantry_avail(world, PM_INV, PM_DOM, avail)
62 let b1: *i64 = sys_mmap(8 * 16) as *i64; let r1: *i64 = sys_mmap(8 * 16) as *i64
63 let nb1: i64 = fp_choose(PM_FOOD, world, avail, b1, r1)
64 g_p("in-stock ingredients=" as *u8); g_i(nav); g_p(" -> tonight: " as *u8); g_show(world, b1, nb1)
65 tot = tot + 1
66 var ok1: i64 = 1
67 if nb1 != 5 { ok1 = 0 }
68 var t1i: i64 = 0
69 while t1i < nb1 { if iv_qty(PM_INV, PM_DOM, ids[b1[t1i]] as *u8) <= 0 { ok1 = 0 } t1i = t1i + 1 }
70 if ok1 == 1 { pass = pass + 1; g_p("PASS T1 what-can-I-make: a complete stir-fry from only what's in stock\n" as *u8) } else { g_p("FAIL T1\n" as *u8) }
71
72 // T2 cook-what's-expiring-first: forces an expiring protein over fresh Beef
73 let avexp: *i64 = sys_mmap(8 * 64) as *i64
74 fp_expiring_first(world, PM_INV, PM_DOM, PM_FOOD, 0, 3, avail, avexp)
75 let be: *i64 = sys_mmap(8 * 16) as *i64; let re: *i64 = sys_mmap(8 * 16) as *i64
76 let nbe: i64 = fp_choose(PM_FOOD, world, avexp, be, re)
77 g_p("normal protein=" as *u8); g_p(names[b1[0]] as *u8); g_p(" expiring-first protein=" as *u8); g_p(names[be[0]] as *u8); g_p("\n" as *u8)
78 tot = tot + 1
79 var ok2: i64 = 1
80 if nbe != 5 { ok2 = 0 }
81 if fp_is_expiring(PM_INV, PM_DOM, ids[be[0]] as *u8, 0, 3) != 1 { ok2 = 0 }
82 if ok2 == 1 { pass = pass + 1; g_p("PASS T2 expiring-first: the meal uses a soon-to-expire protein (cut waste)\n" as *u8) } else { g_p("FAIL T2\n" as *u8) }
83
84 // T3 sovereign "Your Kitchen" page from the pantry
85 let avoid: *i64 = sys_mmap(8 * 64) as *i64
86 let prefw: *i64 = sys_mmap(8 * 8) as *i64
87 fd_set_all(avoid, n, 0)
88 var z: i64 = 0; while z < FOOD_NAX { prefw[z] = 0; z = z + 1 }
89 let page: *u8 = sys_mmap(65536)
90 let np: i64 = fs_render_avail(PM_FOOD, PM_CAT, "Your Kitchen" as *u8, avail, avoid, prefw, page)
91 tot = tot + 1
92 var ok3: i64 = 1
93 if as_has_thirdparty_js(page, np) != 0 { ok3 = 0 }
94 if as_contains(page, np, names[b1[0]] as *u8) != 1 { ok3 = 0 }
95 if ok3 == 1 { pass = pass + 1; g_p("PASS T3 sovereign 'Your Kitchen' page rendered from the pantry (" as *u8); g_i(np); g_p(" bytes, 0 JS)\n" as *u8) } else { g_p("FAIL T3\n" as *u8) }
96
97 // T4 meal plan: 2 meals, consuming inventory
98 let q0: i64 = fp_total_qty(PM_INV, PM_DOM)
99 // meal 1
100 let m1: *i64 = sys_mmap(8 * 64) as *i64; fp_pantry_avail(world, PM_INV, PM_DOM, m1)
101 let m1e: *i64 = sys_mmap(8 * 64) as *i64; fp_expiring_first(world, PM_INV, PM_DOM, PM_FOOD, 0, 3, m1, m1e)
102 let mb1: *i64 = sys_mmap(8 * 16) as *i64; let mr1: *i64 = sys_mmap(8 * 16) as *i64
103 let nm1: i64 = fp_choose(PM_FOOD, world, m1e, mb1, mr1)
104 g_p(" meal 1: " as *u8); g_show(world, mb1, nm1)
105 fp_consume_build(PM_INV, PM_DOM, world, mb1, nm1)
106 // meal 2 (pantry now depleted)
107 let m2: *i64 = sys_mmap(8 * 64) as *i64; fp_pantry_avail(world, PM_INV, PM_DOM, m2)
108 let m2e: *i64 = sys_mmap(8 * 64) as *i64; fp_expiring_first(world, PM_INV, PM_DOM, PM_FOOD, 0, 3, m2, m2e)
109 let mb2: *i64 = sys_mmap(8 * 16) as *i64; let mr2: *i64 = sys_mmap(8 * 16) as *i64
110 let nm2: i64 = fp_choose(PM_FOOD, world, m2e, mb2, mr2)
111 g_p(" meal 2: " as *u8); g_show(world, mb2, nm2)
112 fp_consume_build(PM_INV, PM_DOM, world, mb2, nm2)
113 let q2: i64 = fp_total_qty(PM_INV, PM_DOM)
114 g_p(" pantry stock: " as *u8); g_i(q0); g_p(" -> " as *u8); g_i(q2); g_p(" units after 2 meals\n" as *u8)
115 tot = tot + 1
116 var ok4: i64 = 1
117 if nm1 != 5 { ok4 = 0 }
118 if nm2 != 5 { ok4 = 0 }
119 if q0 - q2 != 10 { ok4 = 0 }
120 if ok4 == 1 { pass = pass + 1; g_p("PASS T4 meal plan: 2 meals cooked, inventory consumed (10 units depleted)\n" as *u8) } else { g_p("FAIL T4 (q0=" as *u8); g_i(q0); g_p(" q2=" as *u8); g_i(q2); g_p(" nm1=" as *u8); g_i(nm1); g_p(" nm2=" as *u8); g_i(nm2); g_p(")\n" as *u8) }
121
122 g_p("nx_pantry_meal_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot)
123 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
124 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
125 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
126 let ctr__dry: *i64 = gv_ctr()
127 ctr__dry[0] = pass
128 ctr__dry[1] = tot
129 let rc__dry: i64 = gv_verdict("PANTRY-MEAL-GATE" as *u8, ctr__dry, "pantry -> expiry -> what can I make -> meal plan, inventory consumed)" as *u8)
130 sys_exit(rc__dry)
131 return rc__dry
132}