nx_layer_verdict.nx source
↩ module page · 349 lines · 15222 B
1// nx_layer_verdict.nx -- polymorphic per-layer grader verdict.
2//
3// Per user 2026-05-16: "i also again want our proc gen to always
4// layer by layer and overall meta have a god is this good and it
5// should do that based on the math like we were building in the
6// elder ai for images and video and sound"
7//
8// This primitive is the SHARED DATA STRUCTURE that every per-layer
9// grader emits. Composes with nx_meta_verdict.nx (the META
10// aggregator that produces the "God saw it was good" overall grade).
11//
12// Mathematical posture (matches Elder AI's image/video/sound grader
13// design):
14// - Every layer has 1-12 axes, each scored Q14 [0, Q].
15// - Axis verdicts: WIN (>= 0.6Q), MARGINAL (>= 0.4Q), LOSS (else).
16// - Layer grade is computed from axis verdict counts (4-axis-wins,
17// etc.); same rubric as nx_quality_grade.nx for inter-grader
18// consistency.
19// - REFINE_HINT names the weakest axis to direct iterative
20// improvement.
21//
22// LAYER_VERDICT layout (16 i64, all Q14 except sealed-enums):
23// v[0] layer_kind sealed enum NX_LAYER_KIND_*
24// v[1] grade F=0..S=5
25// v[2] n_axes_used 1..12 (number of axes actually scored)
26// v[3] refine_hint sealed enum NX_LAYER_REFINE_*
27// v[4..15] axis_scores[12] Q14 [0, Q] per axis; unused axes = 0
28//
29// The 12-axis ceiling is a hard cap; if a grader needs more axes,
30// either split into multiple LAYER_VERDICT records or pre-aggregate.
31//
32// genealogy_id: elder_ai_image_grader + elder_ai_sound_grader_canon +
33// nx_quality_grade_sclass_canon
34// lineage_id: nx_layer_verdict_polymorphic_v1
35
36// nx_safety_envelope:
37// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
38// sil_target: SIL1
39// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
40// verdict: NOT_YET_EVALUATED
41
42import "nx_syscalls.nx"
43import "nx_tier.nx"
44
45// ===== Q14 ==========================================================
46const NX_LV_Q: nx_int = 16384
47
48// ===== LAYER_VERDICT layout =========================================
49const NX_LV_STRIDE: nx_int = 16
50
51const NX_LV_OFF_KIND: nx_int = 0
52const NX_LV_OFF_GRADE: nx_int = 1
53const NX_LV_OFF_N_AXES: nx_int = 2
54const NX_LV_OFF_REFINE_HINT: nx_int = 3
55const NX_LV_OFF_AXIS_0: nx_int = 4
56const NX_LV_OFF_AXIS_LAST: nx_int = 15
57
58const NX_LV_MAX_AXES: nx_int = 12
59
60// ===== Layer-kind sealed enum =======================================
61// Each procgen layer in the substrate gets a unique kind ID. Add new
62// kinds at the END additively per cardinal rule 13.
63const NX_LAYER_KIND_HEIGHTMAP: nx_int = 0 // nx_terrestrial_surface / nx_world_quality_grader
64const NX_LAYER_KIND_BIOME: nx_int = 1 // nx_biome_classifier output
65const NX_LAYER_KIND_FOREST: nx_int = 2 // nx_forest_layout placement
66const NX_LAYER_KIND_RIVER: nx_int = 3 // nx_river_carve path quality
67const NX_LAYER_KIND_TOWN: nx_int = 4 // nx_town_layout coherence
68const NX_LAYER_KIND_CRATER: nx_int = 5 // nx_crater_field density
69const NX_LAYER_KIND_WEATHER: nx_int = 6 // nx_weather_pattern coherence
70const NX_LAYER_KIND_ATMOSPHERE: nx_int = 7 // sky/fog/scattering quality
71const NX_LAYER_KIND_AUDIO: nx_int = 8 // sound design grader (Elder AI parallel)
72const NX_LAYER_KIND_COLOR: nx_int = 9 // color palette / contrast / vibrancy
73const NX_LAYER_KIND_READABILITY: nx_int = 10 // overall visual readability
74const NX_LAYER_KIND_HAMMERED: nx_int = 11 // nx_hammered_zone variety
75const NX_LAYER_KIND_CASTLE: nx_int = 12 // nx_castle_layout / architectural
76const NX_LAYER_KIND_WATER_EROSION: nx_int = 13 // nx_water_erosion convergence
77const NX_LAYER_KIND_ORE_DEPOSIT: nx_int = 14 // nx_ore_deposit distribution
78
79const NX_LAYER_KIND_COUNT: nx_int = 15
80
81func nx_layer_kind_is_valid(k: nx_int) -> nx_int {
82 if k >= 0 { if k < NX_LAYER_KIND_COUNT { return 1 } }
83 return 0
84}
85
86// ===== Grade sealed enum (matches nx_quality_grade.nx) =============
87const NX_LV_GRADE_F: nx_int = 0
88const NX_LV_GRADE_D: nx_int = 1
89const NX_LV_GRADE_C: nx_int = 2
90const NX_LV_GRADE_B: nx_int = 3
91const NX_LV_GRADE_A: nx_int = 4
92const NX_LV_GRADE_S: nx_int = 5
93
94const NX_LV_GRADE_COUNT: nx_int = 6
95
96func nx_lv_grade_is_valid(g: nx_int) -> nx_int {
97 if g >= NX_LV_GRADE_F { if g <= NX_LV_GRADE_S { return 1 } }
98 return 0
99}
100
101// ===== Refine-hint sealed enum =====================================
102// Generic refinement directions; per-layer graders can use these or
103// add layer-specific extensions via the meta field (queued).
104const NX_LAYER_REFINE_NONE: nx_int = 0
105const NX_LAYER_REFINE_MORE_RELIEF: nx_int = 1
106const NX_LAYER_REFINE_MORE_FEATURES: nx_int = 2
107const NX_LAYER_REFINE_LESS_FLATNESS: nx_int = 3
108const NX_LAYER_REFINE_ADD_DETAIL: nx_int = 4
109const NX_LAYER_REFINE_SMOOTH_NOISE: nx_int = 5
110const NX_LAYER_REFINE_FIX_FRACTAL: nx_int = 6
111const NX_LAYER_REFINE_FIX_BIOMES: nx_int = 7
112const NX_LAYER_REFINE_MORE_VARIETY: nx_int = 8
113const NX_LAYER_REFINE_IMPROVE_READ: nx_int = 9
114const NX_LAYER_REFINE_FIX_COHERENCE: nx_int = 10
115const NX_LAYER_REFINE_REPLACE_LAYER: nx_int = 11 // layer is hopeless; regenerate
116
117const NX_LAYER_REFINE_COUNT: nx_int = 12
118
119func nx_layer_refine_is_valid(r: nx_int) -> nx_int {
120 if r >= 0 { if r < NX_LAYER_REFINE_COUNT { return 1 } }
121 return 0
122}
123
124// ===== Axis verdict thresholds ======================================
125const NX_LV_AXIS_WIN_FLOOR: nx_int = 9830 // 0.6Q
126const NX_LV_AXIS_MARGINAL_FLOOR: nx_int = 6553 // 0.4Q
127
128// Axis verdict: 1 = WIN, 0 = MARGINAL, -1 = LOSS.
129func nx_lv_axis_verdict(score: nx_int) -> nx_int {
130 if score >= NX_LV_AXIS_WIN_FLOOR { return 1 }
131 if score >= NX_LV_AXIS_MARGINAL_FLOOR { return 0 }
132 return 0 - 1
133}
134
135// ===== Grade calculator from axis verdicts =========================
136// Sums axis verdicts (WIN=1, MARG=0, LOSS=-1) and applies a consistent
137// rubric (matches nx_world_quality_grader's _wqg_grade_from_8 for
138// 8 axes, and degrades smoothly for other axis counts).
139//
140// Rule (n axes used, w wins, l losses):
141// w == n -> S
142// w == n - 1 -> A
143// w >= n * 3 / 4 -> B if losses <= 1 else C
144// w >= n / 2 -> C if losses <= 1 else D
145// losses >= n / 2 -> F
146// otherwise -> D
147func nx_layer_grade_from_axes(
148 axis_scores: *i64, n_axes: nx_int
149) -> nx_int {
150 if n_axes <= 0 { return NX_LV_GRADE_F }
151 if n_axes > NX_LV_MAX_AXES { return NX_LV_GRADE_F }
152 var wins: nx_int = 0
153 var losses: nx_int = 0
154 var i: nx_int = 0
155 while i < n_axes {
156 let v: nx_int = nx_lv_axis_verdict(axis_scores[i])
157 if v == 1 { wins = wins + 1 }
158 if v == 0 - 1 { losses = losses + 1 }
159 i = i + 1
160 }
161 if losses * 2 >= n_axes { return NX_LV_GRADE_F }
162 if wins == n_axes { return NX_LV_GRADE_S }
163 if wins == n_axes - 1 { return NX_LV_GRADE_A }
164 let three_quarter_n: nx_int = (n_axes * 3) / 4
165 let half_n: nx_int = n_axes / 2
166 if wins >= three_quarter_n {
167 if losses <= 1 { return NX_LV_GRADE_B }
168 return NX_LV_GRADE_C
169 }
170 if wins >= half_n {
171 if losses <= 1 { return NX_LV_GRADE_C }
172 return NX_LV_GRADE_D
173 }
174 return NX_LV_GRADE_D
175}
176
177// ===== Writer (convenience) =========================================
178// Initialises a LAYER_VERDICT record: zero-fills axes 0..12, sets the
179// supplied kind / n_axes / refine_hint, leaves grade as F. Caller
180// fills axis_scores via direct writes, then calls nx_layer_verdict_finalize.
181func nx_layer_verdict_init(
182 v: *i64,
183 layer_kind: nx_int,
184 n_axes: nx_int,
185 refine_hint: nx_int
186) {
187 var i: nx_int = 0
188 while i < NX_LV_STRIDE { v[i] = 0; i = i + 1 }
189 v[NX_LV_OFF_KIND] = layer_kind
190 v[NX_LV_OFF_GRADE] = NX_LV_GRADE_F
191 v[NX_LV_OFF_N_AXES] = n_axes
192 v[NX_LV_OFF_REFINE_HINT] = refine_hint
193}
194
195// ===== Finalizer ====================================================
196// Computes the grade from axis scores and writes it into v[GRADE].
197// Caller should write all axis scores before calling this.
198func nx_layer_verdict_finalize(v: *i64) {
199 let n: nx_int = v[NX_LV_OFF_N_AXES]
200 let axes: *i64 = (v as i64 + NX_LV_OFF_AXIS_0 * NX_SIZEOF_NX_INT) as *i64
201 let grade: nx_int = nx_layer_grade_from_axes(axes, n)
202 v[NX_LV_OFF_GRADE] = grade
203}
204
205// ===== Accessor: axis_score_q14 ====================================
206func nx_layer_verdict_axis(v: *i64, axis_idx: nx_int) -> nx_int {
207 if axis_idx < 0 { return 0 }
208 if axis_idx >= NX_LV_MAX_AXES { return 0 }
209 return v[NX_LV_OFF_AXIS_0 + axis_idx]
210}
211
212// ===== Bulk writer (caller pre-fills 12 axes) ======================
213func nx_layer_verdict_write(
214 v: *i64,
215 layer_kind: nx_int,
216 n_axes: nx_int,
217 refine_hint: nx_int,
218 axis_scores: *i64
219) {
220 nx_layer_verdict_init(v, layer_kind, n_axes, refine_hint)
221 var i: nx_int = 0
222 while i < n_axes {
223 if i < NX_LV_MAX_AXES {
224 v[NX_LV_OFF_AXIS_0 + i] = axis_scores[i]
225 }
226 i = i + 1
227 }
228 nx_layer_verdict_finalize(v)
229}
230
231// ===== Adapter: nx_world_quality_grader output -> LAYER_VERDICT ====
232// nx_world_quality_grader writes 12 i64s with grade + 8 axis scores +
233// refine_axis + min/max heights. We copy the 8 axes into LAYER_VERDICT
234// axis slots 0..7, set kind=HEIGHTMAP, set refine_hint from refine_axis.
235//
236// wqg layout (per nx_world_quality_grader.nx NX_WQG_OFF_*):
237// 0=grade, 1=diversity, 2=local_var, 3=extremes, 4=flatness,
238// 5=fractal, 6=biome, 7=variety, 8=readability, 9=refine_axis,
239// 10=min, 11=max
240func nx_layer_verdict_from_wqg(
241 wqg_output: *i64, out: *i64
242) {
243 let refine: nx_int = wqg_output[9]
244 nx_layer_verdict_init(out, NX_LAYER_KIND_HEIGHTMAP, 8, refine)
245 out[NX_LV_OFF_AXIS_0 ] = wqg_output[1] // diversity
246 out[NX_LV_OFF_AXIS_0 + 1] = wqg_output[2] // local_variation
247 out[NX_LV_OFF_AXIS_0 + 2] = wqg_output[3] // extremes
248 // FLATNESS is inverted (lower = better); convert to a score where
249 // higher = better.
250 let q: nx_int = NX_LV_Q
251 let flat_inv: nx_int = q - wqg_output[4]
252 var clamped_flat: nx_int = flat_inv
253 if clamped_flat < 0 { clamped_flat = 0 }
254 if clamped_flat > q { clamped_flat = q }
255 out[NX_LV_OFF_AXIS_0 + 3] = clamped_flat
256 out[NX_LV_OFF_AXIS_0 + 4] = wqg_output[5] // fractal_dim
257 out[NX_LV_OFF_AXIS_0 + 5] = wqg_output[6] // biome_coherence
258 out[NX_LV_OFF_AXIS_0 + 6] = wqg_output[7] // feature_variety
259 out[NX_LV_OFF_AXIS_0 + 7] = wqg_output[8] // readability
260 nx_layer_verdict_finalize(out)
261}
262
263// ===== Self-test ====================================================
264func main() -> i64 {
265 let q: nx_int = NX_LV_Q
266
267 // T1: Validity predicates.
268 if nx_layer_kind_is_valid(NX_LAYER_KIND_HEIGHTMAP) != 1 { return __syscall(93, 1, 0, 0, 0, 0, 0) }
269 if nx_layer_kind_is_valid(NX_LAYER_KIND_AUDIO) != 1 { return __syscall(93, 2, 0, 0, 0, 0, 0) }
270 if nx_layer_kind_is_valid(99) != 0 { return __syscall(93, 3, 0, 0, 0, 0, 0) }
271 if nx_lv_grade_is_valid(NX_LV_GRADE_S) != 1 { return __syscall(93, 4, 0, 0, 0, 0, 0) }
272 if nx_lv_grade_is_valid(99) != 0 { return __syscall(93, 5, 0, 0, 0, 0, 0) }
273 if nx_layer_refine_is_valid(NX_LAYER_REFINE_NONE) != 1 { return __syscall(93, 6, 0, 0, 0, 0, 0) }
274 if nx_layer_refine_is_valid(99) != 0 { return __syscall(93, 7, 0, 0, 0, 0, 0) }
275
276 // T2: Axis verdict bands.
277 if nx_lv_axis_verdict(q) != 1 { return __syscall(93, 10, 0, 0, 0, 0, 0) } // full-WIN
278 if nx_lv_axis_verdict(q * 7 / 10) != 1 { return __syscall(93, 11, 0, 0, 0, 0, 0) } // WIN
279 if nx_lv_axis_verdict(q / 2) != 0 { return __syscall(93, 12, 0, 0, 0, 0, 0) } // MARGINAL
280 if nx_lv_axis_verdict(q / 5) != 0 - 1 { return __syscall(93, 13, 0, 0, 0, 0, 0) } // LOSS
281
282 // T3: Grade from axes.
283 let axes: *i64 = (sys_mmap(NX_LV_MAX_AXES * NX_SIZEOF_NX_INT)) as *i64
284 var i: nx_int = 0
285 while i < NX_LV_MAX_AXES { axes[i] = 0; i = i + 1 }
286
287 // All 8 axes at full WIN -> S.
288 var j: nx_int = 0
289 while j < 8 { axes[j] = q; j = j + 1 }
290 if nx_layer_grade_from_axes(axes, 8) != NX_LV_GRADE_S { return __syscall(93, 20, 0, 0, 0, 0, 0) }
291
292 // 7 WIN + 1 MARGINAL -> A.
293 axes[7] = q / 2
294 if nx_layer_grade_from_axes(axes, 8) != NX_LV_GRADE_A { return __syscall(93, 21, 0, 0, 0, 0, 0) }
295
296 // 6 WIN + 2 MARGINAL (no losses) -> B.
297 axes[6] = q / 2
298 if nx_layer_grade_from_axes(axes, 8) != NX_LV_GRADE_B { return __syscall(93, 22, 0, 0, 0, 0, 0) }
299
300 // All 8 at LOSS -> F.
301 var k: nx_int = 0
302 while k < 8 { axes[k] = q / 10; k = k + 1 }
303 if nx_layer_grade_from_axes(axes, 8) != NX_LV_GRADE_F { return __syscall(93, 23, 0, 0, 0, 0, 0) }
304
305 // T4: Writer + finalizer pipeline.
306 let v: *i64 = (sys_mmap(NX_LV_STRIDE * NX_SIZEOF_NX_INT)) as *i64
307 var w: nx_int = 0
308 while w < 5 { axes[w] = q; w = w + 1 }
309 while w < 8 { axes[w] = q / 2; w = w + 1 }
310 nx_layer_verdict_write(v, NX_LAYER_KIND_FOREST, 8, NX_LAYER_REFINE_NONE, axes)
311 if v[NX_LV_OFF_KIND] != NX_LAYER_KIND_FOREST { return __syscall(93, 30, 0, 0, 0, 0, 0) }
312 if v[NX_LV_OFF_N_AXES] != 8 { return __syscall(93, 31, 0, 0, 0, 0, 0) }
313 // 5 WIN + 3 MARGINAL = wins=5, losses=0. half_n=4, three_quarter=6.
314 // wins >= half_n=4, losses<=1 -> C.
315 if v[NX_LV_OFF_GRADE] != NX_LV_GRADE_C { return __syscall(93, 32, 0, 0, 0, 0, 0) }
316
317 // T5: Accessor reads back axis scores.
318 if nx_layer_verdict_axis(v, 0) != q { return __syscall(93, 40, 0, 0, 0, 0, 0) }
319 if nx_layer_verdict_axis(v, 5) != q / 2 { return __syscall(93, 41, 0, 0, 0, 0, 0) }
320 if nx_layer_verdict_axis(v, 99) != 0 { return __syscall(93, 42, 0, 0, 0, 0, 0) }
321
322 // T6: WQG-to-LayerVerdict adapter.
323 // Build a fake wqg output: grade=A, 8 axes all 0.7Q, refine=0.
324 let wqg: *i64 = (sys_mmap(12 * NX_SIZEOF_NX_INT)) as *i64
325 wqg[0] = NX_LV_GRADE_A
326 wqg[1] = q * 7 / 10 // diversity
327 wqg[2] = q * 7 / 10 // local_var
328 wqg[3] = q * 7 / 10 // extremes
329 wqg[4] = q * 3 / 10 // flatness (lower = better; inverted to 0.7Q in axis)
330 wqg[5] = q * 7 / 10 // fractal
331 wqg[6] = q * 7 / 10 // biome
332 wqg[7] = q * 7 / 10 // variety
333 wqg[8] = q * 7 / 10 // readability
334 wqg[9] = NX_LAYER_REFINE_NONE
335 wqg[10] = 0
336 wqg[11] = 1000
337 let v2: *i64 = (sys_mmap(NX_LV_STRIDE * NX_SIZEOF_NX_INT)) as *i64
338 nx_layer_verdict_from_wqg(wqg, v2)
339 if v2[NX_LV_OFF_KIND] != NX_LAYER_KIND_HEIGHTMAP { return __syscall(93, 50, 0, 0, 0, 0, 0) }
340 if v2[NX_LV_OFF_N_AXES] != 8 { return __syscall(93, 51, 0, 0, 0, 0, 0) }
341 // axis[3] = q - 0.3Q = 0.7Q.
342 let inv_flat: nx_int = nx_layer_verdict_axis(v2, 3)
343 if inv_flat < q * 6 / 10 { return __syscall(93, 52, 0, 0, 0, 0, 0) }
344 if inv_flat > q * 8 / 10 { return __syscall(93, 53, 0, 0, 0, 0, 0) }
345 // 8 axes all at 0.7Q -> 8 wins -> S.
346 if v2[NX_LV_OFF_GRADE] != NX_LV_GRADE_S { return __syscall(93, 54, 0, 0, 0, 0, 0) }
347
348 return 0
349}