code wiki / (root) / nx_meal_emit.nx

nx_meal_emit.nx source

↩ module page · 187 lines · 11035 B

1// nx_meal_emit.nx -- MAIN: SEED the meal stores and RENDER the page. Idempotent end to end (rule 10): every 2// seed is a value-compare put that writes nothing when unchanged, and the render simply overwrites its 3// artifact. Run it twice, get the same estate. 4// 5// IT OWNS STORES AND MARKUP, AND NOTHING ELSE. Preserving the origin page is nx_meal_capture's job, in its own 6// organ, because the decompressor it needs drags nx_runtime/nx_tier/nx_deflate/nx_crc32 in behind it and that 7// destabilised the seg-store seeding here -- untouched code that had been green minutes before. Splitting on 8// the job boundary (rule 9) was the fix, not a workaround: this organ reads the finished WARC and never 9// decodes anything. 10// 11// It writes the page to a FILE and stops. Publishing is a separate deliberate act through nx_site_publish -- 12// a renderer that also deploys is a renderer you cannot safely run just to look at the output. 13// 14// argv[1] = output html path (default /tmp/kitchen.html) 15// license_tier: ORIGINAL No hw writes (Rule 26). 16import "_hdl_build/nx_meal_page.nx" 17import "_hdl_build/nx_meal_source.nx" 18import "_hdl_build/nx_meal_cost.nx" 19import "_hdl_build/nx_meal_plan.nx" 20import "_hdl_build/nx_adnet_slot.nx" 21import "nx_syscalls.nx" 22const ME_MAGIC_1099: i64 = 1099 23const ME_MAGIC_1249: i64 = 1249 24 25const ME_PAGE: i64 = 262144 26const ME_WARC: i64 = 4194304 27const ME_MODE: i64 = 420 28const ME_DAY: i64 = 20671 29 30// CONFIG SEAM (rule 11): the floor a price must clear BELOW the area median before the page calls it a 31// bargain. One named constant rather than a literal buried in a comparison; belongs in svc-config the moment 32// a second surface needs it. 33const ME_SALE_FLOOR_CENTS: i64 = 50 34 35// the loopback port nx_site_intake_serve binds (proxied by the edge row `nishifamily.com /intake 8033`) 36const ME_INTAKE_PORT: i64 = 8033 37 38func me_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 39func me_n(v: i64) -> i64 { 40 let b: *u8 = sys_mmap(32) 41 let t: *u8 = sys_mmap(32) 42 var m: i64 = v 43 var k: i64 = 0 44 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 45 if m == 0 { t[0] = 48 as u8; k = 1 } 46 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 47 var i: i64 = 0 48 while i < k { b[i] = t[k - 1 - i]; i = i + 1 } 49 sys_write(1, b, k) 50 return 0 51} 52 53// Is anything actually LISTENING for the contact forms? A TCP connect is a MEASUREMENT; a config flag is a 54// belief. The page renders a form only when this returns 1, so a dead form can never ship by accident. 55func me_port_open(port: i64) -> i64 { 56 let fd: i64 = sys_socket(2, 1, 0) 57 if fd < 0 { return 0 } 58 let addr: *u8 = sys_mmap(16) 59 var i: i64 = 0 60 while i < 16 { addr[i] = 0 as u8; i = i + 1 } 61 addr[0] = 2 as u8 62 addr[2] = ((port >> 8) & 255) as u8 63 addr[3] = (port & 255) as u8 64 addr[4] = 127 as u8 65 addr[7] = 1 as u8 66 let r: i64 = sys_connect(fd, addr, 16) 67 sys_close(fd) 68 if r < 0 { return 0 } 69 return 1 70} 71 72func me_write_file(path: *u8, buf: *u8, n: i64) -> i64 { 73 let fd: i64 = sys_openat_wr(path, ME_MODE) 74 if fd < 0 { return 0 - 1 } 75 sys_write(fd, buf, n) 76 sys_close(fd) 77 return n 78} 79 80func main(argc: i64, argv: *i64) -> i64 { 81 let meal: *u8 = "knowledge/store/meal-" as *u8 82 let inv: *u8 = "knowledge/store/inv-" as *u8 83 let price: *u8 = "knowledge/store/price-" as *u8 84 let warcpath: *u8 = "knowledge/store/meal.warc" as *u8 85 let adconf: *u8 = "meal_ad_inventory.conf" as *u8 86 let host: *u8 = "nishifamily.com" as *u8 87 let url: *u8 = "https://en.wikibooks.org/wiki/Cookbook:Beef_Stew" as *u8 88 89 var outpath: *u8 = "/tmp/kitchen.html" as *u8 90 if argc > 1 { outpath = argv[1] as *u8 } 91 92 // ---------------- SEED: recipes ---------------- 93 mp_add_recipe(meal, "beefstew" as *u8, "Classic Beef Stew" as *u8, "Chuck browned hard, then three hours at a bare tremble until the connective tissue gives up and the broth turns glossy." as *u8, 6, "beef onion carrot potato celery garlic thyme stock redwine" as *u8) 94 mp_add_recipe(meal, "potroast" as *u8, "Sunday Pot Roast" as *u8, "The same braise, left whole and carved at the table." as *u8, 6, "beef onion carrot potato celery garlic stock" as *u8) 95 mp_add_recipe(meal, "veggiesoup" as *u8, "Garden Vegetable Soup" as *u8, "Everything the stew uses except the beef and the wine." as *u8, 4, "onion carrot celery garlic thyme stock potato" as *u8) 96 mp_add_recipe(meal, "aromaticstock" as *u8, "Aromatic Stock" as *u8, "The base every braise on this page is built from." as *u8, 8, "onion carrot celery garlic thyme stock" as *u8) 97 mp_add_recipe(meal, "steakfrites" as *u8, "Steak Frites" as *u8, "Same beef, same potato, thirty minutes instead of three hours." as *u8, 2, "beef potato garlic thyme" as *u8) 98 99 // ---------------- SEED: the ingredient catalogue ---------------- 100 // Ids are join keys shared by pantry rows, price observations and recipe lists, so they stay terse and 101 // lowercase. Their human names live HERE, not in the pantry -- otherwise an ingredient this kitchen does 102 // not happen to stock would have no name at all and the page would print a raw key at a reader. 103 mp_add_ingredient(meal, "beef" as *u8, "Beef chuck" as *u8) 104 mp_add_ingredient(meal, "onion" as *u8, "Yellow onion" as *u8) 105 mp_add_ingredient(meal, "carrot" as *u8, "Carrot" as *u8) 106 mp_add_ingredient(meal, "potato" as *u8, "Waxy potato" as *u8) 107 mp_add_ingredient(meal, "celery" as *u8, "Celery" as *u8) 108 mp_add_ingredient(meal, "garlic" as *u8, "Garlic" as *u8) 109 mp_add_ingredient(meal, "thyme" as *u8, "Thyme" as *u8) 110 mp_add_ingredient(meal, "stock" as *u8, "Beef stock" as *u8) 111 mp_add_ingredient(meal, "redwine" as *u8, "Dry red wine" as *u8) 112 113 // ---------------- SEED: units (family / person / restaurant, one engine) ---------------- 114 mp_add_unit(meal, "wests" as *u8, "The West Family" as *u8, "family" as *u8, "wests" as *u8, "seattle" as *u8) 115 mp_add_unit(meal, "ana" as *u8, "Ana" as *u8, "person" as *u8, "ana" as *u8, "seattle" as *u8) 116 mp_add_unit(meal, "spicehouse" as *u8, "Sichuan Spice House" as *u8, "restaurant" as *u8, "spicehouse" as *u8, "portland" as *u8) 117 118 // ---------------- SEED: the family's pantry ---------------- 119 iv_add(inv, "wests" as *u8, "onion" as *u8, "Yellow onion" as *u8, "produce" as *u8, 4, "each" as *u8, "pantry" as *u8, 90, 0, ed_empty()) 120 iv_add(inv, "wests" as *u8, "carrot" as *u8, "Carrot" as *u8, "produce" as *u8, 6, "each" as *u8, "crisper" as *u8, 140, 0, ed_empty()) 121 iv_add(inv, "wests" as *u8, "celery" as *u8, "Celery" as *u8, "produce" as *u8, 1, "bunch" as *u8, "crisper" as *u8, 180, 0, ed_empty()) 122 iv_add(inv, "wests" as *u8, "garlic" as *u8, "Garlic" as *u8, "produce" as *u8, 3, "bulb" as *u8, "pantry" as *u8, 90, 0, ed_empty()) 123 iv_add(inv, "wests" as *u8, "thyme" as *u8, "Thyme" as *u8, "herb" as *u8, 1, "bunch" as *u8, "fridge door" as *u8, 240, 0, ed_empty()) 124 iv_add(inv, "wests" as *u8, "stock" as *u8, "Beef stock" as *u8, "pantry" as *u8, 2, "quart" as *u8, "pantry" as *u8, 380, 0, ed_empty()) 125 126 // ---------------- SEED: area stores + dated price observations ---------------- 127 pr_add_store(price, "bigmart" as *u8, "BigMart Rainier" as *u8, "BigMart" as *u8, "seattle" as *u8, "WA" as *u8, "weekly circular, 2026-08-04" as *u8) 128 pr_add_store(price, "corner" as *u8, "Corner Market" as *u8, "independent" as *u8, "seattle" as *u8, "WA" as *u8, "shelf tag" as *u8) 129 pr_add_store(price, "pikeplace" as *u8, "Pike Place Butcher" as *u8, "independent" as *u8, "seattle" as *u8, "WA" as *u8, "counter board" as *u8) 130 131 pr_set_price(price, "bigmart" as *u8, "beef" as *u8, ME_MAGIC_1099, "2026-08-04" as *u8, "lb" as *u8, "weekly circular" as *u8) 132 pr_set_price(price, "bigmart" as *u8, "potato" as *u8, 349, "2026-08-04" as *u8, "5 lb bag" as *u8, "weekly circular" as *u8) 133 pr_set_price(price, "bigmart" as *u8, "redwine" as *u8, 899, "2026-08-04" as *u8, "750 ml" as *u8, "weekly circular" as *u8) 134 pr_set_price(price, "corner" as *u8, "beef" as *u8, ME_MAGIC_1249, "2026-08-05" as *u8, "lb" as *u8, "shelf tag" as *u8) 135 pr_set_price(price, "corner" as *u8, "potato" as *u8, 279, "2026-08-05" as *u8, "5 lb bag" as *u8, "shelf tag" as *u8) 136 pr_set_price(price, "corner" as *u8, "redwine" as *u8, ME_MAGIC_1099, "2026-08-05" as *u8, "750 ml" as *u8, "shelf tag" as *u8) 137 // Pike Place has the CHEAPEST beef and wine in the area -- and no potatoes at all. The coverage guard is 138 // what stops it winning a basket it cannot fill. 139 pr_set_price(price, "pikeplace" as *u8, "beef" as *u8, 899, "2026-08-06" as *u8, "lb" as *u8, "counter board" as *u8) 140 pr_set_price(price, "pikeplace" as *u8, "redwine" as *u8, 799, "2026-08-06" as *u8, "750 ml" as *u8, "counter board" as *u8) 141 142 // ---------------- SEED: provenance ---------------- 143 ms_record(meal, "beefstew" as *u8, "Classic Beef Stew" as *u8, "Wikibooks Cookbook" as *u8, url, "CC BY-SA 3.0" as *u8, ME_DAY, 0) 144 me_p(" seed: complete\n" as *u8) 145 146 // ---------------- the preserved archive (written by nx_meal_capture; read-only here) ---------------- 147 let warc: *u8 = sys_mmap(ME_WARC) 148 var wl: i64 = wa_load(warcpath, warc, ME_WARC) 149 if wl < 0 { wl = 0 } 150 if ms_is_archived(warc, wl, url) == 1 { 151 me_p(" archive: source preserved, " as *u8); me_n(ms_archive_bytes(warc, wl, url)); me_p(" bytes retrievable\n" as *u8) 152 } else { 153 me_p(" archive: source NOT preserved -- the page will say the link can rot\n" as *u8) 154 } 155 156 // ---------------- the sponsor inventory, host-gated exactly as the ad slot demands ---------------- 157 let box: *i64 = sys_mmap(16) as *i64 158 box[0] = 0 159 let adinv: *u8 = sys_read_file(adconf, box) 160 var adlen: i64 = box[0] 161 if adlen > 0 { 162 if aslot_host_ok(adinv, adlen, host) == 0 { 163 adlen = 0 164 me_p(" sponsor: no @host row for this vhost -- slot omitted (fail-closed)\n" as *u8) 165 } 166 } 167 168 // ---------------- RENDER ---------------- 169 let page: *u8 = sys_mmap(ME_PAGE) 170 let intake_live: i64 = me_port_open(ME_INTAKE_PORT) 171 if intake_live == 1 { 172 me_p(" intake: :8033 is answering -- the contact forms will render\n" as *u8) 173 } else { 174 me_p(" intake: :8033 NOT listening -- forms SUPPRESSED, the page will say so rather than post into the void\n" as *u8) 175 } 176 let n: i64 = mpg_render(page, meal, inv, price, "beefstew" as *u8, "wests" as *u8, warc, wl, adinv, adlen, sys_now_realtime_sec(), ME_SALE_FLOOR_CENTS, "kitchen" as *u8, "/kitchen/beef-stew" as *u8, intake_live) 177 if me_write_file(outpath, page, n) < 0 { 178 me_p("NX-MEAL-EMIT FAIL cannot write " as *u8); me_p(outpath); me_p("\n" as *u8) 179 sys_exit(1) 180 return 1 181 } 182 me_p("NX-MEAL-EMIT OK bytes=" as *u8); me_n(n) 183 me_p(" warc=" as *u8); me_n(wl) 184 me_p(" path=" as *u8); me_p(outpath); me_p("\n" as *u8) 185 sys_exit(0) 186 return 0 187}