nx_code_quality.nx source
↩ module page · 389 lines · 14479 B
1// nx_code_quality.nx -- qualitative + quantitative code refactor verdict.
2//
3// Six measurable axes -> Q10 score per axis + sealed-enum CodeQualityVerdict.
4// Operates on a source-text byte buffer (any language whose lexical
5// substrate uses { } ( ) [ ] for nesting + // for comments -- which covers
6// NishiLang, C, Rust, Go, Java, JavaScript, TypeScript, C++).
7//
8// Refactor triggers (each maps to a Q10 axis):
9//
10// 1. NULL_PTR_HAZARD count of `0 as *` patterns (NULL sentinel)
11// normalized by source length
12// 2. HARDCODING_SCORE count of `* 8`, `* 4` literals not in
13// comments (cardinal-violation signal:
14// should be NX_SIZEOF_NX_INT etc.)
15// 3. NESTING_HAZARD maximum bracket nesting depth (cyclomatic
16// proxy; deep nesting -> refactor)
17// 4. REPETITION_HAZARD line-length-diversity proxy (very uniform
18// line lengths -> repetition; very long
19// single lines -> readability issue)
20// 5. COMMENT_DEFICIT comment density below threshold ->
21// documentation gap
22// 6. TIER_COMPLIANCE bare `i64 ` occurrences (should use
23// nx_int / nx_size / nx_idx aliases)
24//
25// Composite_q10 = inverse-weighted sum across axes (low hazard count
26// + good comment density + nx_tier compliance = high composite).
27//
28// Sealed-enum verdict:
29// NX_CQ_REFACTOR_HOT composite < 300 immediate refactor
30// NX_CQ_REFACTOR_RECOMMENDED 300 <= comp < 600
31// NX_CQ_ACCEPTABLE 600 <= comp < 800
32// NX_CQ_EXCELLENT comp >= 800
33//
34// Cross-language: same primitive over any text-source byte stream
35// (NishiLang .nx, C .c, Rust .rs, prose .txt -- though the cardinal-
36// violation axes 1, 2, 6 are NishiLang-specific; they read as
37// no-op on other languages where those patterns don't appear).
38//
39// "Competitive coding best practices" reading per dual-reading
40// cardinal: the qualitative verdict names WHICH refactor is most
41// urgent (deepest nesting? most duplication? most hardcoding?);
42// the quantitative axes give the operator the numbers behind it.
43//
44// genealogy_id: mccabe_1976_cyclomatic + halstead_1977_metrics +
45// fenton_2014_software_metrics + lloyd_1986_practical
46// lineage_id: code_quality_composite_q10
47
48// nx_safety_envelope:
49// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
50// sil_target: SIL1
51// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
52// verdict: NOT_YET_EVALUATED
53
54import "nx_syscalls.nx"
55import "nx_tier.nx"
56
57const NX_CQ_Q: nx_int = 1024
58const NX_CQ_MAX_NESTING_OK: nx_int = 5
59
60const NX_CQ_REFACTOR_HOT: nx_int = 0
61const NX_CQ_REFACTOR_RECOMMENDED: nx_int = 1
62const NX_CQ_ACCEPTABLE: nx_int = 2
63const NX_CQ_EXCELLENT: nx_int = 3
64const NX_CQ_N_VERDICTS: nx_int = 4
65
66const NX_CQ_AXIS_NULL_PTR: nx_int = 0
67const NX_CQ_AXIS_HARDCODING: nx_int = 1
68const NX_CQ_AXIS_NESTING: nx_int = 2
69const NX_CQ_AXIS_REPETITION: nx_int = 3
70const NX_CQ_AXIS_COMMENT: nx_int = 4
71const NX_CQ_AXIS_TIER: nx_int = 5
72const NX_CQ_N_AXES: nx_int = 6
73
74struct CodeQualityReport {
75 line_count: nx_int,
76 null_ptr_count: nx_int,
77 hardcoded_size_count: nx_int,
78 bare_i64_count: nx_int,
79 comment_line_count: nx_int,
80 max_nesting: nx_int,
81 null_ptr_q10: nx_int, // 0 = many nulls (bad); Q10 = none (good)
82 hardcoding_q10: nx_int, // same convention -- HIGH = clean
83 nesting_q10: nx_int, // HIGH = shallow (good)
84 repetition_q10: nx_int,
85 comment_q10: nx_int, // HIGH = well-documented
86 tier_q10: nx_int,
87 composite_q10: nx_int,
88 verdict: nx_int, // NX_CQ_* sealed enum
89 worst_axis: nx_int, // NX_CQ_AXIS_* of the lowest-scoring axis
90}
91
92// ===== Helpers =========================================================
93
94// Check if buffer[i..i+n] equals literal byte string.
95func _cq_match_at(buf: *u8, len: nx_int, pos: nx_int, lit: *u8, n: nx_int) -> nx_int {
96 if pos + n > len { return 0 }
97 var k: nx_int = 0
98 while k < n {
99 if buf[pos + k] != lit[k] { return 0 }
100 k = k + 1
101 }
102 return 1
103}
104
105// Is position inside a // line comment? Cheap heuristic: scan back
106// from pos to start-of-line and check for // before any non-whitespace.
107// For NishiLang/C-style. Returns 1 if in comment, 0 if not.
108func _cq_in_comment(buf: *u8, pos: nx_int) -> nx_int {
109 var p: nx_int = pos
110 while p > 0 {
111 let c: u8 = buf[p - 1]
112 if c == 10 { return 0 } // hit start-of-line without seeing //
113 if p >= 2 {
114 if buf[p - 2] == 47 { // '/'
115 if buf[p - 1] == 47 { return 1 }
116 }
117 }
118 p = p - 1
119 }
120 return 0
121}
122
123// ===== Primary scanner ================================================
124//
125// Single pass over the buffer, accumulating all axis counters.
126
127func nx_code_quality_scan(buf: *u8, len: nx_int, report: *CodeQualityReport) -> nx_int {
128 report.line_count = 0
129 report.null_ptr_count = 0
130 report.hardcoded_size_count = 0
131 report.bare_i64_count = 0
132 report.comment_line_count = 0
133 report.max_nesting = 0
134
135 // Literals to search for. Allocate small const-string buffers
136 // (NishiLang doesn't yet have string-literal pool, so we use
137 // byte-array allocations).
138 let lit_null: *u8 = sys_mmap(4)
139 lit_null[0] = 48 // '0'
140 lit_null[1] = 32 // ' '
141 lit_null[2] = 97 // 'a'
142 lit_null[3] = 115 // 's'
143
144 let lit_star8: *u8 = sys_mmap(3)
145 lit_star8[0] = 42 // '*'
146 lit_star8[1] = 32 // ' '
147 lit_star8[2] = 56 // '8'
148
149 let lit_i64: *u8 = sys_mmap(4)
150 lit_i64[0] = 105 // 'i'
151 lit_i64[1] = 54 // '6'
152 lit_i64[2] = 52 // '4'
153 lit_i64[3] = 32 // ' ' (trailing space prevents 'i640' false positive)
154
155 var nest: nx_int = 0
156 var max_nest: nx_int = 0
157 var at_line_start: nx_int = 1
158 var leading_ws: nx_int = 1
159 var line_has_comment: nx_int = 0
160
161 var i: nx_int = 0
162 while i < len {
163 let c: u8 = buf[i]
164
165 // Newline: count line, reset line state.
166 if c == 10 {
167 report.line_count = report.line_count + 1
168 if line_has_comment == 1 {
169 report.comment_line_count = report.comment_line_count + 1
170 }
171 at_line_start = 1
172 leading_ws = 1
173 line_has_comment = 0
174 i = i + 1
175 // continue
176 } else {
177 // Comment detection: '//' on a line.
178 if c == 47 { // '/'
179 if i + 1 < len {
180 if buf[i + 1] == 47 {
181 line_has_comment = 1
182 }
183 }
184 }
185
186 // Bracket nesting.
187 if c == 123 { // '{'
188 if _cq_in_comment(buf, i) == 0 {
189 nest = nest + 1
190 if nest > max_nest { max_nest = nest }
191 }
192 }
193 if c == 125 { // '}'
194 if _cq_in_comment(buf, i) == 0 {
195 nest = nest - 1
196 if nest < 0 { nest = 0 }
197 }
198 }
199
200 // Pattern matches at this position (skip if in comment).
201 if _cq_in_comment(buf, i) == 0 {
202 if _cq_match_at(buf, len, i, lit_null, 4) == 1 {
203 // Followed by '*' to confirm '0 as *T' shape?
204 if i + 4 < len {
205 if buf[i + 4] == 42 { // '*'
206 report.null_ptr_count = report.null_ptr_count + 1
207 }
208 }
209 }
210 if _cq_match_at(buf, len, i, lit_star8, 3) == 1 {
211 // Confirm boundary: prev char is not letter/digit
212 var prev_ok: nx_int = 1
213 if i > 0 {
214 let pc: u8 = buf[i - 1]
215 if pc >= 48 {
216 if pc <= 57 { prev_ok = 0 }
217 }
218 if pc >= 65 {
219 if pc <= 90 { prev_ok = 0 }
220 }
221 if pc >= 97 {
222 if pc <= 122 { prev_ok = 0 }
223 }
224 }
225 if prev_ok == 1 {
226 // Confirm next char is whitespace/newline/end (not '8'-of-a-bigger-number)
227 var next_ok: nx_int = 1
228 if i + 3 < len {
229 let nc: u8 = buf[i + 3]
230 if nc >= 48 {
231 if nc <= 57 { next_ok = 0 }
232 }
233 }
234 if next_ok == 1 {
235 report.hardcoded_size_count = report.hardcoded_size_count + 1
236 }
237 }
238 }
239 if _cq_match_at(buf, len, i, lit_i64, 4) == 1 {
240 // Confirm boundary on the LEFT: prev is whitespace/colon/comma
241 var pok: nx_int = 1
242 if i > 0 {
243 let pc: u8 = buf[i - 1]
244 if pc >= 65 {
245 if pc <= 90 { pok = 0 }
246 }
247 if pc >= 97 {
248 if pc <= 122 { pok = 0 }
249 }
250 }
251 if pok == 1 {
252 report.bare_i64_count = report.bare_i64_count + 1
253 }
254 }
255 }
256
257 i = i + 1
258 }
259 }
260 // Tail line without trailing newline.
261 if len > 0 {
262 if buf[len - 1] != 10 {
263 report.line_count = report.line_count + 1
264 if line_has_comment == 1 {
265 report.comment_line_count = report.comment_line_count + 1
266 }
267 }
268 }
269 report.max_nesting = max_nest
270 return 0
271}
272
273// ===== Axis Q10 scoring + composite + verdict =========================
274//
275// All scores are HIGH = GOOD convention. Each axis maps the relevant
276// count + a tolerance into a Q10 [0, 1024] band:
277// null_ptr_q10 = max(0, Q - 4 * null_count) clamped
278// hardcoding_q10 = max(0, Q - 64 * hardcoded_count / line_count_norm)
279// nesting_q10 = max(0, Q - 200 * (max_nesting - NX_CQ_MAX_NESTING_OK))
280// repetition_q10 = derived from line-density distribution (placeholder
281// for the shingling-based repetition detector --
282// today fixed at Q/2 = 512 ('unmeasured').
283// comment_q10 = comment_lines / total_lines * Q (clamped)
284// tier_q10 = max(0, Q - 32 * bare_i64_density_q10)
285
286func nx_code_quality_score(report: *CodeQualityReport) -> nx_int {
287 let lc: nx_int = report.line_count
288 let lc_safe: nx_int = lc
289 var lc_div: nx_int = lc_safe
290 if lc_div < 1 { lc_div = 1 }
291
292 // null_ptr_q10: 0 nulls = Q10 (perfect); each null subtracts ~64.
293 var ng: nx_int = NX_CQ_Q - report.null_ptr_count * 64
294 if ng < 0 { ng = 0 }
295 report.null_ptr_q10 = ng
296
297 // hardcoding_q10: each hardcoded literal subtracts ~256.
298 var hc: nx_int = NX_CQ_Q - report.hardcoded_size_count * 256
299 if hc < 0 { hc = 0 }
300 report.hardcoding_q10 = hc
301
302 // nesting_q10: every level beyond NX_CQ_MAX_NESTING_OK subtracts 200.
303 var ns: nx_int = NX_CQ_Q
304 let over: nx_int = report.max_nesting - NX_CQ_MAX_NESTING_OK
305 if over > 0 { ns = NX_CQ_Q - over * 200 }
306 if ns < 0 { ns = 0 }
307 report.nesting_q10 = ns
308
309 // repetition_q10: placeholder pending shingling pass.
310 report.repetition_q10 = NX_CQ_Q / 2
311
312 // comment_q10: comment density.
313 let cd: nx_int = (report.comment_line_count * NX_CQ_Q) / lc_div
314 var cd_clamped: nx_int = cd
315 if cd_clamped > NX_CQ_Q { cd_clamped = NX_CQ_Q }
316 report.comment_q10 = cd_clamped
317
318 // tier_q10: bare i64 occurrences scaled.
319 let bd: nx_int = (report.bare_i64_count * NX_CQ_Q) / lc_div
320 var tg: nx_int = NX_CQ_Q - bd * 4
321 if tg < 0 { tg = 0 }
322 report.tier_q10 = tg
323
324 // Composite = simple average across the 6 axes.
325 let comp: nx_int = (
326 report.null_ptr_q10 +
327 report.hardcoding_q10 +
328 report.nesting_q10 +
329 report.repetition_q10 +
330 report.comment_q10 +
331 report.tier_q10
332 ) / 6
333 report.composite_q10 = comp
334
335 // Verdict band.
336 if comp < 300 { report.verdict = NX_CQ_REFACTOR_HOT }
337 if comp >= 300 { report.verdict = NX_CQ_REFACTOR_RECOMMENDED }
338 if comp >= 600 { report.verdict = NX_CQ_ACCEPTABLE }
339 if comp >= 800 { report.verdict = NX_CQ_EXCELLENT }
340
341 // Worst axis: the lowest-scoring of the 6 -- this is what the
342 // operator should refactor first.
343 var worst_axis: nx_int = NX_CQ_AXIS_NULL_PTR
344 var worst_score: nx_int = report.null_ptr_q10
345 if report.hardcoding_q10 < worst_score {
346 worst_score = report.hardcoding_q10
347 worst_axis = NX_CQ_AXIS_HARDCODING
348 }
349 if report.nesting_q10 < worst_score {
350 worst_score = report.nesting_q10
351 worst_axis = NX_CQ_AXIS_NESTING
352 }
353 if report.repetition_q10 < worst_score {
354 worst_score = report.repetition_q10
355 worst_axis = NX_CQ_AXIS_REPETITION
356 }
357 if report.comment_q10 < worst_score {
358 worst_score = report.comment_q10
359 worst_axis = NX_CQ_AXIS_COMMENT
360 }
361 if report.tier_q10 < worst_score {
362 worst_score = report.tier_q10
363 worst_axis = NX_CQ_AXIS_TIER
364 }
365 report.worst_axis = worst_axis
366
367 return 0
368}
369
370// Sealed-enum validity check.
371func nx_code_quality_verdict_is_valid(v: nx_int) -> nx_int {
372 if v < 0 { return 0 }
373 if v >= NX_CQ_N_VERDICTS { return 0 }
374 return 1
375}
376
377func nx_code_quality_axis_is_valid(a: nx_int) -> nx_int {
378 if a < 0 { return 0 }
379 if a >= NX_CQ_N_AXES { return 0 }
380 return 1
381}
382
383// One-shot composite: allocate report, scan, score. Caller frees
384// (we don't have explicit free in the substrate yet).
385func nx_code_quality_compute(buf: *u8, len: nx_int, report: *CodeQualityReport) -> nx_int {
386 nx_code_quality_scan(buf, len, report)
387 nx_code_quality_score(report)
388 return 0
389}