code wiki / _hdl_build / nx_worldgen_tuner_test.nx
nx_worldgen_tuner_test.nx source
↩ module page · 124 lines · 5765 B
1// nx_worldgen_tuner_test.nx -- KATs for the verdict-targeted tuner
2// machinery (nx_worldgen_tunelib). Gate module: /tmp-only side effects
3// (the real tuner's durable banking is exercised by its live runs, not
4// here -- a gate beat must never mutate team state).
5// Exit 0 = all pass; first failing KAT's number is the exit code.
6//
7// KAT 1 conf parse: ints, negatives, missing-key fallback.
8// KAT 2 refine-axis string parse (the banked verdict's form).
9// KAT 3 axis mapping: every refine axis -> a verdict offset; FLATNESS
10// value inverted (lower flat = higher score).
11// KAT 4 score is lexicographic: one grade step beats any axis value.
12// KAT 5 eval determinism: same (preset, density, knobs) -> identical
13// 12-slot verdicts.
14// KAT 6 the knob does its job: detail_amp 140 raises LOCAL_VARIATION
15// vs detail_amp 0 (same preset/density -- the ADD_DETAIL claim
16// at tuner level).
17// KAT 7 knob banking round-trip: write a /tmp conf, tl_load_knobs reads
18// it back exactly; missing file falls back to preset defaults.
19// license_tier: ORIGINAL
20import "nx_syscalls.nx"
21import "nx_tier.nx"
22import "nx_worldgen_tunelib.nx"
23
24func main() -> i64 {
25 // ---- KAT 1: conf int parse ----
26 let cb: *u8 = "preset=3\ndensity_q10=1024\nriver_depth=-7\n" as *u8
27 var cn: i64 = 0
28 while cb[cn] != (0 as u8) { cn = cn + 1 }
29 if tl_conf_get(cb, cn, "preset" as *u8, 99) != 3 { return 1 }
30 if tl_conf_get(cb, cn, "density_q10" as *u8, 99) != 1024 { return 1 }
31 if tl_conf_get(cb, cn, "river_depth" as *u8, 99) != 0 - 7 { return 1 }
32 if tl_conf_get(cb, cn, "absent" as *u8, 42) != 42 { return 1 }
33
34 // ---- KAT 2: refine-axis string parse ----
35 let rb: *u8 = "grade=C\nrefine_axis=MORE_FEATURES\n" as *u8
36 var rn: i64 = 0
37 while rb[rn] != (0 as u8) { rn = rn + 1 }
38 if tl_conf_get_refine(rb, rn, NX_WQG_REFINE_NONE) != NX_WQG_REFINE_MORE_FEATURES { return 2 }
39 let rb2: *u8 = "refine_axis=ADD_DETAIL\n" as *u8
40 var rn2: i64 = 0
41 while rb2[rn2] != (0 as u8) { rn2 = rn2 + 1 }
42 if tl_conf_get_refine(rb2, rn2, NX_WQG_REFINE_NONE) != NX_WQG_REFINE_ADD_DETAIL { return 2 }
43 if tl_conf_get_refine(cb, cn, NX_WQG_REFINE_IMPROVE_READ) != NX_WQG_REFINE_IMPROVE_READ { return 2 }
44
45 // ---- KAT 3: axis mapping + flatness inversion ----
46 if tl_axis_offset(NX_WQG_REFINE_MORE_FEATURES) != NX_WQG_OFF_EXTREMES { return 3 }
47 if tl_axis_offset(NX_WQG_REFINE_ADD_DETAIL) != NX_WQG_OFF_LOCAL_VAR { return 3 }
48 let v12: *i64 = sys_mmap(8 * 12) as *i64
49 var z: i64 = 0
50 while z < 12 { v12[z] = 0; z = z + 1 }
51 v12[NX_WQG_OFF_FLATNESS_PENALTY] = 4000
52 if tl_axis_value(v12, NX_WQG_REFINE_LESS_FLATNESS) != NX_WQG_Q - 4000 { return 3 }
53 v12[NX_WQG_OFF_EXTREMES] = 7000
54 if tl_axis_value(v12, NX_WQG_REFINE_MORE_FEATURES) != 7000 { return 3 }
55
56 // ---- KAT 4: lexicographic score ----
57 let a12: *i64 = sys_mmap(8 * 12) as *i64
58 var z2: i64 = 0
59 while z2 < 12 { a12[z2] = 0; z2 = z2 + 1 }
60 a12[NX_WQG_OFF_EXTREMES] = NX_WQG_Q // max axis value, lower grade
61 v12[NX_WQG_OFF_EXTREMES] = 0 // min axis value, higher grade
62 let lo_grade_hi_axis: i64 = tl_score(NX_GRADE_C, a12, NX_WQG_REFINE_MORE_FEATURES)
63 let hi_grade_lo_axis: i64 = tl_score(NX_GRADE_B, v12, NX_WQG_REFINE_MORE_FEATURES)
64 if hi_grade_lo_axis <= lo_grade_hi_axis { return 4 }
65
66 // ---- KAT 5: eval determinism ----
67 let knobs: *i64 = sys_mmap(TL_K_COUNT * 8) as *i64
68 knobs[TL_K_RIVER_DEPTH] = 120
69 knobs[TL_K_RILL_DEPTH] = 45
70 knobs[TL_K_RILL_RADIUS] = 4
71 knobs[TL_K_DETAIL_AMP] = 0
72 let e1: *i64 = sys_mmap(8 * 12) as *i64
73 let e2: *i64 = sys_mmap(8 * 12) as *i64
74 let g1: i64 = tl_eval(4, 1024, knobs, e1)
75 let g2: i64 = tl_eval(4, 1024, knobs, e2)
76 if g1 != g2 { return 5 }
77 var c: i64 = 0
78 while c < 12 {
79 if e1[c] != e2[c] { return 5 }
80 c = c + 1
81 }
82
83 // ---- KAT 6: detail_amp raises LOCAL_VARIATION ----
84 knobs[TL_K_DETAIL_AMP] = 140
85 tl_eval(4, 1024, knobs, e2)
86 if e2[NX_WQG_OFF_LOCAL_VAR] <= e1[NX_WQG_OFF_LOCAL_VAR] { return 6 }
87
88 // ---- KAT 7: knob banking round-trip + fallback ----
89 let kp: *u8 = "/tmp/nishi_worldgen_knobs.kat.conf" as *u8
90 let wfd: i64 = sys_openat_wr(kp, 0x1a4)
91 if wfd < 0 { return 7 }
92 let kc: *u8 = "river_depth=150\nrill_depth=30\nrill_radius=6\ndetail_amp=100\npeaks_extra=2\namp_boost=1228\n" as *u8
93 var kn: i64 = 0
94 while kc[kn] != (0 as u8) { kn = kn + 1 }
95 sys_write(wfd, kc, kn)
96 sys_close(wfd)
97 let lk: *i64 = sys_mmap(TL_K_COUNT * 8) as *i64
98 tl_load_knobs(kp, 4, lk)
99 if lk[TL_K_RIVER_DEPTH] != 150 { return 7 }
100 if lk[TL_K_RILL_DEPTH] != 30 { return 7 }
101 if lk[TL_K_RILL_RADIUS] != 6 { return 7 }
102 if lk[TL_K_DETAIL_AMP] != 100 { return 7 }
103 if lk[TL_K_PEAKS_EXTRA] != 2 { return 7 }
104 if lk[TL_K_AMP_BOOST] != 1228 { return 7 }
105 tl_load_knobs("/tmp/nishi_worldgen_knobs.kat.absent" as *u8, 4, lk)
106 if lk[TL_K_RIVER_DEPTH] != nx_water_default_river_depth(4) { return 7 }
107 if lk[TL_K_RILL_DEPTH] != nx_water_default_rill_depth() { return 7 }
108 if lk[TL_K_DETAIL_AMP] != 0 { return 7 }
109 if lk[TL_K_PEAKS_EXTRA] != 0 { return 7 }
110 if lk[TL_K_AMP_BOOST] != 1024 { return 7 }
111
112 // ---- KAT 8: landmark knobs move EXTREMES (the structural handle) ----
113 let k8: *i64 = sys_mmap(TL_K_COUNT * 8) as *i64
114 tl_load_knobs("/tmp/nishi_worldgen_knobs.kat.absent" as *u8, 4, k8)
115 let b1: *i64 = sys_mmap(8 * 12) as *i64
116 let b2: *i64 = sys_mmap(8 * 12) as *i64
117 tl_eval(4, 1024, k8, b1)
118 k8[TL_K_PEAKS_EXTRA] = 2
119 k8[TL_K_AMP_BOOST] = 1433
120 tl_eval(4, 1024, k8, b2)
121 if b2[NX_WQG_OFF_EXTREMES] <= b1[NX_WQG_OFF_EXTREMES] { return 8 }
122
123 return 0
124}