nx_skills_emit.nx source
↩ module page · 154 lines · 8412 B
1// nx_skills_emit.nx -- MAIN: seed the skill layer for a dish and render its skills surface.
2//
3// Idempotent (rule 10): every seed is a value-compare put. Separate organ from nx_meal_emit so the recipe page
4// and the skills page can each be re-rendered without touching the other's stores.
5//
6// The seeded levels are DELIBERATELY incomplete: this household has been assessed on the knife and the pan but
7// has NEVER braised. That is the common real case, and it exercises the disclosure rather than hiding it --
8// the cook-from-scratch option becomes unrankable, the page says exactly why, and the recommendation falls to
9// something we can actually compare.
10//
11// argv[1] = output html path (default /tmp/kitchen-skills.html)
12// license_tier: ORIGINAL No hw writes (Rule 26).
13import "_hdl_build/nx_meal_skills_page.nx"
14import "_hdl_build/nx_meal_cost.nx"
15import "_hdl_build/nx_meal_effort.nx"
16import "_hdl_build/nx_skill_video.nx"
17import "_hdl_build/nx_meal_plan.nx"
18import "nx_syscalls.nx"
19const SE_MAGIC_2500: i64 = 2500
20const SE_MAGIC_1800: i64 = 1800
21const SE_MAGIC_2600: i64 = 2600
22const SE_MAGIC_2900: i64 = 2900
23const SE_MAGIC_3600: i64 = 3600
24
25const SE_PAGE: i64 = 262144
26const SE_WARC: i64 = 4194304
27const SE_MODE: i64 = 420
28const SE_SALE_FLOOR: i64 = 50
29const SE_INTAKE_PORT: i64 = 8033
30const SE_RATE: i64 = 2500 // $25.00/hour -- this household's own stated value for an hour
31
32func se_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
33func se_n(v: i64) -> i64 {
34 let b: *u8 = sys_mmap(32)
35 let t: *u8 = sys_mmap(32)
36 var m: i64 = v
37 var k: i64 = 0
38 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
39 if m == 0 { t[0] = 48 as u8; k = 1 }
40 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
41 var i: i64 = 0
42 while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
43 sys_write(1, b, k)
44 return 0
45}
46func se_port_open(port: i64) -> i64 {
47 let fd: i64 = sys_socket(2, 1, 0)
48 if fd < 0 { return 0 }
49 let addr: *u8 = sys_mmap(16)
50 var i: i64 = 0
51 while i < 16 { addr[i] = 0 as u8; i = i + 1 }
52 addr[0] = 2 as u8
53 addr[2] = ((port >> 8) & 255) as u8
54 addr[3] = (port & 255) as u8
55 addr[4] = 127 as u8
56 addr[7] = 1 as u8
57 let r: i64 = sys_connect(fd, addr, 16)
58 sys_close(fd)
59 if r < 0 { return 0 }
60 return 1
61}
62func se_write_file(path: *u8, buf: *u8, n: i64) -> i64 {
63 let fd: i64 = sys_openat_wr(path, SE_MODE)
64 if fd < 0 { return 0 - 1 }
65 sys_write(fd, buf, n)
66 sys_close(fd)
67 return n
68}
69
70func main(argc: i64, argv: *i64) -> i64 {
71 let meal: *u8 = "knowledge/store/meal-" as *u8
72 let inv: *u8 = "knowledge/store/inv-" as *u8
73 let price: *u8 = "knowledge/store/price-" as *u8
74 let vp: *u8 = "knowledge/store/skillvid-" as *u8
75 let curr: *u8 = "knowledge/store/coach-curriculum-" as *u8
76 let warcpath: *u8 = "knowledge/store/meal.warc" as *u8
77 let rid: *u8 = "beefstew" as *u8
78 let unit: *u8 = "wests" as *u8
79
80 var outpath: *u8 = "/tmp/kitchen-skills.html" as *u8
81 if argc > 1 { outpath = argv[1] as *u8 }
82
83 // ---------------- the skill tree: broad -> specific ----------------
84 ef_add_skill(meal, "knife" as *u8, "Knife skills" as *u8, ef_empty(), "Everything done with a blade on a board" as *u8)
85 ef_add_skill(meal, "dicing" as *u8, "Dicing" as *u8, "knife" as *u8, "Even cubes, consistent size" as *u8)
86 ef_add_skill(meal, "dice-onion" as *u8, "Dice an onion" as *u8, "dicing" as *u8, "Root-on, horizontal then vertical, claw grip" as *u8)
87 ef_add_skill(meal, "chop-veg" as *u8, "Rough-chop vegetables" as *u8, "knife" as *u8, "Carrot and celery to even pieces" as *u8)
88 ef_add_skill(meal, "heat" as *u8, "Heat control" as *u8, ef_empty(), "Reading a pan and adjusting" as *u8)
89 ef_add_skill(meal, "sear" as *u8, "Searing" as *u8, "heat" as *u8, "Dry surface, hot pan, do not crowd" as *u8)
90 ef_add_skill(meal, "braise" as *u8, "Braising" as *u8, "heat" as *u8, "Bare tremble, lid on, low and long" as *u8)
91
92 // ---------------- the dish as ACTIVE steps ----------------
93 ef_add_step(meal, rid, 0, "Dice the onion" as *u8, "dice-onion" as *u8, 300)
94 ef_add_step(meal, rid, 1, "Chop the carrot and celery" as *u8, "chop-veg" as *u8, 300)
95 ef_add_step(meal, rid, 2, "Brown the chuck in batches" as *u8, "sear" as *u8, 600)
96 ef_add_step(meal, rid, 3, "Build and set the braise" as *u8, "braise" as *u8, 300)
97
98 // ---------------- pace multipliers as DATA (base = a competent cook, level 2) ----------------
99 ef_set_tmul(meal, 0, SE_MAGIC_2500)
100 ef_set_tmul(meal, 1, SE_MAGIC_1800)
101 ef_set_tmul(meal, 2, 1000)
102 ef_set_tmul(meal, 3, 850)
103 ef_set_tmul(meal, 4, 700)
104
105 // ---------------- this household: assessed on the knife and the pan, NEVER on a braise ----------------
106 ef_set_level(meal, unit, "dice-onion" as *u8, 1)
107 ef_set_level(meal, unit, "chop-veg" as *u8, 2)
108 ef_set_level(meal, unit, "sear" as *u8, 2)
109 ef_set_timevalue(meal, unit, SE_RATE)
110
111 // ---------------- what it would cost to skip the cooking ----------------
112 ef_add_alt(meal, rid, "prepped" as *u8, SE_MAGIC_2600, 12, "store deli counter" as *u8, "2026-08-05" as *u8)
113 ef_add_alt(meal, rid, "frozen" as *u8, SE_MAGIC_2900, 10, "freezer aisle" as *u8, "2026-08-04" as *u8)
114 ef_add_alt(meal, rid, "restaurant" as *u8, SE_MAGIC_3600, 0, "neighbourhood bistro" as *u8, "2026-08-06" as *u8)
115
116 // ---------------- who you can learn from ----------------
117 sv_add_chef(vp, "kenji" as *u8, "J. Kenji Lopez-Alt" as *u8, "@kenji" as *u8, "https://www.seriouseats.com/" as *u8)
118 sv_add_chef(vp, "julia" as *u8, "Julia Child" as *u8, "@juliachild" as *u8, "https://www.pbs.org/food/chefs/julia-child/" as *u8)
119
120 sv_add_video(vp, "kd1" as *u8, "dice-onion" as *u8, "Knife Skills: how to dice an onion" as *u8, "Serious Eats" as *u8, "pro" as *u8, "https://www.seriouseats.com/knife-skills-how-to-dice-an-onion" as *u8, "publisher terms" as *u8, 420, "kenji" as *u8)
121 sv_add_video(vp, "ad1" as *u8, "dice-onion" as *u8, "Dicing onions in a normal kitchen" as *u8, "a home cook" as *u8, "amateur" as *u8, "https://commons.wikimedia.org/wiki/Category:Onion_cutting" as *u8, "CC BY-SA" as *u8, 240, sv_empty())
122 sv_add_video(vp, "cv1" as *u8, "chop-veg" as *u8, "Rough-chopping mirepoix" as *u8, "Wikibooks Cookbook" as *u8, "pro" as *u8, "https://en.wikibooks.org/wiki/Cookbook:Mirepoix" as *u8, "CC BY-SA 3.0" as *u8, 180, sv_empty())
123 sv_add_video(vp, "sr1" as *u8, "sear" as *u8, "Why you should not crowd the pan" as *u8, "Serious Eats" as *u8, "pro" as *u8, "https://www.seriouseats.com/the-maillard-reaction" as *u8, "publisher terms" as *u8, 360, "kenji" as *u8)
124 sv_add_video(vp, "br1" as *u8, "braise" as *u8, "Braising, the bare tremble" as *u8, "Wikibooks Cookbook" as *u8, "pro" as *u8, "https://en.wikibooks.org/wiki/Cookbook:Braising" as *u8, "CC BY-SA 3.0" as *u8, 300, sv_empty())
125
126 se_p(" seed: skills, steps, levels, alternatives, chefs and sources\n" as *u8)
127
128 // ---------------- the shopping total, from the SAME engine the recipe page uses ----------------
129 let items: *i64 = sys_mmap(8 * 64) as *i64
130 let ni: i64 = mp_items(meal, rid, items)
131 let sum: *i64 = sys_mmap(8 * MC_SLOTS) as *i64
132 mc_meal(inv, "wests" as *u8, price, "seattle" as *u8, items, ni, SE_SALE_FLOOR, sum)
133 let complete: i64 = mc_total_is_complete(sum)
134 se_p(" cost: scratch shopping = " as *u8); se_n(sum[MC_BUY_CENTS]); se_p(" cents, complete=" as *u8); se_n(complete); se_p("\n" as *u8)
135
136 let warc: *u8 = sys_mmap(SE_WARC)
137 var wl: i64 = wa_load(warcpath, warc, SE_WARC)
138 if wl < 0 { wl = 0 }
139
140 let live: i64 = se_port_open(SE_INTAKE_PORT)
141 if live == 1 { se_p(" intake: :8033 answering -- the request form will render\n" as *u8) } else { se_p(" intake: :8033 NOT listening -- request form SUPPRESSED\n" as *u8) }
142
143 let page: *u8 = sys_mmap(SE_PAGE)
144 let n: i64 = msp_render(page, meal, vp, curr, unit, rid, warc, wl, sum[MC_BUY_CENTS], complete, live, "/kitchen.html" as *u8)
145 if se_write_file(outpath, page, n) < 0 {
146 se_p("NX-SKILLS-EMIT FAIL cannot write " as *u8); se_p(outpath); se_p("\n" as *u8)
147 sys_exit(1)
148 return 1
149 }
150 se_p("NX-SKILLS-EMIT OK bytes=" as *u8); se_n(n)
151 se_p(" path=" as *u8); se_p(outpath); se_p("\n" as *u8)
152 sys_exit(0)
153 return 0
154}