nx_corolla.nx source
↩ module page · 244 lines · 9047 B
1// nx_corolla.nx -- joy + beauty as primary first-class metric.
2//
3// Biology: the corolla is the colored petal whorl that signals reproductive
4// vitality to pollinators -- beauty as HONEST signal of fitness. In Nishi,
5// it is the substrate's commitment that aesthetic outcomes (joy, beauty,
6// playability, awe) are FIRST-CLASS observables, not afterthoughts measured
7// only at end of integration.
8//
9// Per CARDINAL feedback-real-playtest-loop-not-just-logs: quantitative
10// telemetry (FPS, frame correctness) is NECESSARY but NEVER SUFFICIENT.
11// nx_corolla holds the qualitative axes alongside the quantitative.
12//
13// Resolves the earlier nx_bloom name collision per [[feedback-naming-
14// discipline-no-industry-competitor-overlap]] -- corolla is unowned in
15// software-infra trademark space.
16
17import "nx_syscalls.nx"
18import "nx_tier.nx"
19const NX_MAGIC_1024: i64 = 1024
20
21// ===== Sealed enum: NxAestheticAxis ===============================
22
23const NX_CO_AXIS_JOY: nx_int = 0 // user-reported delight
24const NX_CO_AXIS_BEAUTY: nx_int = 1 // visual / acoustic harmony
25const NX_CO_AXIS_AWE: nx_int = 2 // scale / unexpectedness
26const NX_CO_AXIS_PLAYABILITY: nx_int = 3 // game-feel correctness
27const NX_CO_AXIS_LIVENESS: nx_int = 4 // organic / alive feel
28const NX_CO_AXIS_COHERENCE: nx_int = 5 // parts feel-of-a-piece
29const NX_CO_AXIS_SURPRISE: nx_int = 6 // novelty within coherence
30const NX_CO_AXIS_PEACE: nx_int = 7 // calm / restorative
31const NX_CO_AXIS_N: nx_int = 8
32
33// ===== Sealed enum: NxCorollaSource ===============================
34//
35// Per CARDINAL feedback-real-playtest-loop-not-just-logs: never claim
36// substrate produces joy without HUMAN observation. Source enum makes
37// provenance of every score auditable.
38
39const NX_CO_SRC_AUTOMATED_PROXY: nx_int = 0 // smoke / heuristic (LOW WEIGHT)
40const NX_CO_SRC_OPERATOR: nx_int = 1 // operator playtest
41const NX_CO_SRC_FAMILY: nx_int = 2 // family member playtest
42const NX_CO_SRC_TRUSTED_REVIEWER: nx_int = 3 // formal review
43const NX_CO_SRC_COMMUNITY: nx_int = 4 // aggregated community
44const NX_CO_SRC_N: nx_int = 5
45
46// ===== Sealed verdict =============================================
47
48const NX_CO_V_OK: nx_int = 0
49const NX_CO_V_THIN_EVIDENCE: nx_int = 1 // only automated proxies
50const NX_CO_V_BELOW_THRESHOLD: nx_int = 2
51const NX_CO_V_DIVERGENT: nx_int = 3 // quant green, qual low
52const NX_CO_V_NULL: nx_int = 4
53const NX_CO_V_INVALID: nx_int = 5
54const NX_CO_V_N: nx_int = 6
55
56// ===== Struct: NxCorollaReading ==================================
57
58struct NxCorollaReading {
59 axis: nx_int,
60 score_q10: nx_int, // 0..NX_MAGIC_1024
61 source: nx_int,
62 observer_id: nx_int,
63 observed_at_us: nx_size,
64 duration_us: nx_size, // observation window
65}
66
67const NX_CO_R_BYTES: nx_int = 40
68
69struct NxCorolla {
70 target_id: nx_int,
71 readings: *u8,
72 n_readings: nx_int,
73 capacity: nx_int,
74 threshold_q10: nx_int, // minimum acceptable mean score
75 minimum_human_readings: nx_int,
76 created_at_us: nx_size,
77}
78
79const NX_CO_BYTES: nx_int = 48
80
81// ===== Validators =================================================
82
83func nx_co_axis_is_valid(a: nx_int) -> nx_int {
84 if a < 0 { return 0 }
85 if a >= NX_CO_AXIS_N { return 0 }
86 return 1
87}
88
89func nx_co_src_is_valid(s: nx_int) -> nx_int {
90 if s < 0 { return 0 }
91 if s >= NX_CO_SRC_N { return 0 }
92 return 1
93}
94
95func nx_co_v_is_valid(v: nx_int) -> nx_int {
96 if v < 0 { return 0 }
97 if v >= NX_CO_V_N { return 0 }
98 return 1
99}
100
101func nx_co_src_is_human(s: nx_int) -> nx_int {
102 if s == NX_CO_SRC_OPERATOR { return 1 }
103 if s == NX_CO_SRC_FAMILY { return 1 }
104 if s == NX_CO_SRC_TRUSTED_REVIEWER { return 1 }
105 if s == NX_CO_SRC_COMMUNITY { return 1 }
106 return 0
107}
108
109// ===== Constructor ================================================
110
111func nx_co_new(target_id: nx_int,
112 capacity: nx_int,
113 threshold_q10: nx_int,
114 minimum_human_readings: nx_int,
115 now_us: nx_size) -> *NxCorolla {
116 if capacity <= 0 { return 0 as *NxCorolla }
117 if threshold_q10 < 0 { return 0 as *NxCorolla }
118 if threshold_q10 > NX_MAGIC_1024 { return 0 as *NxCorolla }
119 if minimum_human_readings < 0 { return 0 as *NxCorolla }
120 let raw: *u8 = sys_mmap(NX_CO_BYTES)
121 let c: *NxCorolla = raw as *NxCorolla
122 c.target_id = target_id
123 c.readings = sys_mmap(capacity * NX_CO_R_BYTES)
124 c.n_readings = 0
125 c.capacity = capacity
126 c.threshold_q10 = threshold_q10
127 c.minimum_human_readings = minimum_human_readings
128 c.created_at_us = now_us
129 return c
130}
131
132func _co_reading_at(c: *NxCorolla, idx: nx_int) -> *NxCorollaReading {
133 if idx < 0 { return 0 as *NxCorollaReading }
134 if idx >= c.n_readings { return 0 as *NxCorollaReading }
135 let off: nx_int = idx * NX_CO_R_BYTES
136 return (c.readings + off) as *NxCorollaReading
137}
138
139// ===== Record reading =============================================
140
141func nx_co_record(c: *NxCorolla,
142 axis: nx_int,
143 score_q10: nx_int,
144 source: nx_int,
145 observer_id: nx_int,
146 duration_us: nx_size,
147 now_us: nx_size) -> nx_int {
148 if (c as i64) == 0 { return NX_CO_V_NULL }
149 if nx_co_axis_is_valid(axis) == 0 { return NX_CO_V_INVALID }
150 if nx_co_src_is_valid(source) == 0 { return NX_CO_V_INVALID }
151 if score_q10 < 0 { return NX_CO_V_INVALID }
152 if score_q10 > NX_MAGIC_1024 { return NX_CO_V_INVALID }
153 if c.n_readings >= c.capacity { return NX_CO_V_INVALID }
154 let off: nx_int = c.n_readings * NX_CO_R_BYTES
155 let r: *NxCorollaReading = (c.readings + off) as *NxCorollaReading
156 r.axis = axis
157 r.score_q10 = score_q10
158 r.source = source
159 r.observer_id = observer_id
160 r.observed_at_us = now_us
161 r.duration_us = duration_us
162 c.n_readings = c.n_readings + 1
163 return NX_CO_V_OK
164}
165
166// ===== Aggregations ===============================================
167
168func nx_co_mean_q10_by_axis(c: *NxCorolla, axis: nx_int) -> nx_int {
169 if (c as i64) == 0 { return 0 }
170 var sum: nx_int = 0
171 var count: nx_int = 0
172 var i: nx_int = 0
173 while i < c.n_readings {
174 let r: *NxCorollaReading = _co_reading_at(c, i)
175 if r.axis == axis {
176 sum = sum + r.score_q10
177 count = count + 1
178 }
179 i = i + 1
180 }
181 if count == 0 { return 0 }
182 return sum / count
183}
184
185func nx_co_human_reading_count(c: *NxCorolla) -> nx_int {
186 if (c as i64) == 0 { return 0 }
187 var count: nx_int = 0
188 var i: nx_int = 0
189 while i < c.n_readings {
190 let r: *NxCorollaReading = _co_reading_at(c, i)
191 if nx_co_src_is_human(r.source) == 1 { count = count + 1 }
192 i = i + 1
193 }
194 return count
195}
196
197func nx_co_mean_q10_human_only(c: *NxCorolla, axis: nx_int) -> nx_int {
198 if (c as i64) == 0 { return 0 }
199 var sum: nx_int = 0
200 var count: nx_int = 0
201 var i: nx_int = 0
202 while i < c.n_readings {
203 let r: *NxCorollaReading = _co_reading_at(c, i)
204 if r.axis == axis {
205 if nx_co_src_is_human(r.source) == 1 {
206 sum = sum + r.score_q10
207 count = count + 1
208 }
209 }
210 i = i + 1
211 }
212 if count == 0 { return 0 }
213 return sum / count
214}
215
216// ===== Classify ===================================================
217//
218// Verdict logic per CARDINAL feedback-real-playtest-loop-not-just-logs:
219// - Insufficient human readings -> THIN_EVIDENCE (refuse to claim joy
220// from automated proxies alone)
221// - Human mean below threshold -> BELOW_THRESHOLD
222// - Automated mean OK but human mean low -> DIVERGENT (the dangerous
223// passing-smokes-while-broken-UX case)
224// - Otherwise OK
225
226func nx_co_classify(c: *NxCorolla, axis: nx_int) -> nx_int {
227 if (c as i64) == 0 { return NX_CO_V_NULL }
228 if nx_co_axis_is_valid(axis) == 0 { return NX_CO_V_INVALID }
229 let human_count: nx_int = nx_co_human_reading_count(c)
230 if human_count < c.minimum_human_readings { return NX_CO_V_THIN_EVIDENCE }
231 let human_mean: nx_int = nx_co_mean_q10_human_only(c, axis)
232 if human_mean < c.threshold_q10 { return NX_CO_V_BELOW_THRESHOLD }
233 let overall_mean: nx_int = nx_co_mean_q10_by_axis(c, axis)
234 // DIVERGENT: automated alone would have passed but human is significantly
235 // lower (delta >= 200/1024 ~ 20%). This is the "smokes green, UX broken"
236 // class CARDINAL feedback-real-playtest-loop-not-just-logs catches.
237 var delta: nx_int = 0
238 delta = overall_mean - human_mean
239 if delta < 0 { delta = 0 - delta }
240 if delta >= 200 {
241 if human_mean < (c.threshold_q10 + 100) { return NX_CO_V_DIVERGENT }
242 }
243 return NX_CO_V_OK
244}