nx_beauty_score.nx source
↩ module page · 147 lines · 5806 B
1// nx_beauty_score.nx -- S-class composite proportion scorer.
2//
3// Given a measurement bundle (flat-array of (axis_id, measured_px)
4// pairs) and a built canon table, score how close each canon entry
5// is matched and emit a composite verdict.
6//
7// Output: flat-array result layout (no struct pointer return — avoids
8// nxc2 codegen bug).
9// result[0] = composite_score_q10 (0..1024)
10// result[1] = verdict_kind (NX_BEAUTY_*)
11// result[2] = matched_count (number of canon entries whose axes were both measured)
12// result[3] = perfect_count (entries scoring within tight tolerance)
13// result[4] = phi_family_score_q10 (avg across phi-family entries only)
14// result[5] = loomis_family_score_q10
15// result[6] = vitruvian_family_score_q10
16// result[7] = linear_family_score_q10
17// result[8 + i] = per-entry score_q10 for canon entry i (0..NX_CANON_ENTRY_COUNT-1)
18
19// nx_safety_envelope:
20// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
21// sil_target: SIL1
22// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
23// verdict: NOT_YET_EVALUATED
24
25import "nx_syscalls.nx"
26import "nx_phi.nx"
27import "nx_canon_proportions.nx"
28
29// Sealed beauty verdict.
30const NX_BEAUTY_UNKNOWN: i64 = 0
31const NX_BEAUTY_S_CLASS: i64 = 1 // avg >= 819 (0.80)
32const NX_BEAUTY_A_CLASS: i64 = 2 // avg >= 614 (0.60)
33const NX_BEAUTY_B_CLASS: i64 = 3 // avg >= 410 (0.40)
34const NX_BEAUTY_OFF_CANON: i64 = 4 // avg < 410
35
36// Thresholds in Q10.
37const NX_BEAUTY_THRESH_S: i64 = 819
38const NX_BEAUTY_THRESH_A: i64 = 614
39const NX_BEAUTY_THRESH_B: i64 = 410
40
41// Result fixed offsets.
42const NX_RES_COMPOSITE: i64 = 0
43const NX_RES_VERDICT: i64 = 1
44const NX_RES_MATCHED: i64 = 2
45const NX_RES_PERFECT: i64 = 3
46const NX_RES_PHI_AVG: i64 = 4
47const NX_RES_LOOMIS_AVG: i64 = 5
48const NX_RES_VITRUV_AVG: i64 = 6
49const NX_RES_LINEAR_AVG: i64 = 7
50const NX_RES_PER_ENTRY_BASE: i64 = 8
51
52// Measurement bundle layout: 2 i64 per entry (axis_id, measured_px).
53const NX_MEAS_FIELDS: i64 = 2
54
55// Find measured value for axis_id; returns -1 if not measured.
56func nx_meas_find(meas: *i64, count: i64, axis_id: i64) -> i64 {
57 var i: i64 = 0
58 while i < count {
59 let a: i64 = meas[i * NX_MEAS_FIELDS]
60 if a == axis_id { return meas[i * NX_MEAS_FIELDS + 1] }
61 i = i + 1
62 }
63 return -1
64}
65
66// Score one canon entry. Returns score_q10 0..1024 or -1 if axes missing.
67func nx_score_entry(canon: *i64, idx: i64, meas: *i64, m_count: i64) -> i64 {
68 let num_axis: i64 = nx_canon_get(canon, idx, NX_CANON_FIELD_NUM_AXIS)
69 let den_axis: i64 = nx_canon_get(canon, idx, NX_CANON_FIELD_DEN_AXIS)
70 if num_axis == 0 { return -1 }
71 let num_val: i64 = nx_meas_find(meas, m_count, num_axis)
72 let den_val: i64 = nx_meas_find(meas, m_count, den_axis)
73 if num_val < 0 { return -1 }
74 if den_val <= 0 { return -1 }
75 let target: i64 = nx_canon_get(canon, idx, NX_CANON_FIELD_TARGET_Q10)
76 let tol: i64 = nx_canon_get(canon, idx, NX_CANON_FIELD_TOL_Q10)
77 let measured_ratio: i64 = nx_ratio_q10(num_val, den_val)
78 return nx_proportion_score_q10(measured_ratio, target, tol)
79}
80
81// Run full S-class scoring. Caller pre-allocs result of size
82// (NX_RES_PER_ENTRY_BASE + NX_CANON_ENTRY_COUNT) * 8 bytes.
83func nx_beauty_score(canon: *i64, meas: *i64, m_count: i64, result: *i64) -> i64 {
84 // Zero-init headers.
85 result[NX_RES_COMPOSITE] = 0
86 result[NX_RES_VERDICT] = NX_BEAUTY_UNKNOWN
87 result[NX_RES_MATCHED] = 0
88 result[NX_RES_PERFECT] = 0
89 result[NX_RES_PHI_AVG] = 0
90 result[NX_RES_LOOMIS_AVG] = 0
91 result[NX_RES_VITRUV_AVG] = 0
92 result[NX_RES_LINEAR_AVG] = 0
93
94 var total_sum: i64 = 0
95 var total_n: i64 = 0
96 var perfect: i64 = 0
97 var phi_sum: i64 = 0
98 var phi_n: i64 = 0
99 var loom_sum: i64 = 0
100 var loom_n: i64 = 0
101 var vit_sum: i64 = 0
102 var vit_n: i64 = 0
103 var lin_sum: i64 = 0
104 var lin_n: i64 = 0
105
106 var i: i64 = 0
107 while i < NX_CANON_ENTRY_COUNT {
108 let s: i64 = nx_score_entry(canon, i, meas, m_count)
109 if s < 0 {
110 result[NX_RES_PER_ENTRY_BASE + i] = -1
111 } else {
112 result[NX_RES_PER_ENTRY_BASE + i] = s
113 total_sum = total_sum + s
114 total_n = total_n + 1
115 if s >= 921 { perfect = perfect + 1 } // >=0.90 = perfect
116
117 let fam: i64 = nx_canon_get(canon, i, NX_CANON_FIELD_FAMILY)
118 if fam == NX_FAMILY_PHI { phi_sum = phi_sum + s; phi_n = phi_n + 1 }
119 if fam == NX_FAMILY_LOOMIS { loom_sum = loom_sum + s; loom_n = loom_n + 1 }
120 if fam == NX_FAMILY_VITRUVIAN { vit_sum = vit_sum + s; vit_n = vit_n + 1 }
121 if fam == NX_FAMILY_LINEAR { lin_sum = lin_sum + s; lin_n = lin_n + 1 }
122 }
123 i = i + 1
124 }
125
126 var composite: i64 = 0
127 if total_n > 0 { composite = total_sum / total_n }
128 result[NX_RES_COMPOSITE] = composite
129 result[NX_RES_MATCHED] = total_n
130 result[NX_RES_PERFECT] = perfect
131 if phi_n > 0 { result[NX_RES_PHI_AVG] = phi_sum / phi_n }
132 if loom_n > 0 { result[NX_RES_LOOMIS_AVG] = loom_sum / loom_n }
133 if vit_n > 0 { result[NX_RES_VITRUV_AVG] = vit_sum / vit_n }
134 if lin_n > 0 { result[NX_RES_LINEAR_AVG] = lin_sum / lin_n }
135
136 var verdict: i64 = NX_BEAUTY_OFF_CANON
137 if composite >= NX_BEAUTY_THRESH_S { verdict = NX_BEAUTY_S_CLASS }
138 if verdict == NX_BEAUTY_OFF_CANON {
139 if composite >= NX_BEAUTY_THRESH_A { verdict = NX_BEAUTY_A_CLASS }
140 }
141 if verdict == NX_BEAUTY_OFF_CANON {
142 if composite >= NX_BEAUTY_THRESH_B { verdict = NX_BEAUTY_B_CLASS }
143 }
144 if total_n == 0 { verdict = NX_BEAUTY_UNKNOWN }
145 result[NX_RES_VERDICT] = verdict
146 return composite
147}