code wiki / (root) / nx_group_composite.nx

nx_group_composite.nx source

↩ module page · 106 lines · 4284 B

1// nx_group_composite.nx -- aggregate N character verdicts + pair scores into one outcome. 2// 3// For multi-character scenes the substrate produces: 4// - N per-character verdicts (canon score, mannequin index, eroticism rank, etc.) 5// - N*(N-1)/2 pair-synchrony scores between every pair 6// 7// This composite aggregates all of them into ONE scene-quality verdict 8// so the auto_fix loop has a single decision criterion. 9// 10// Per-character contribution: average composite (sum / N). 11// Pair contribution: average pair-synchrony (sum / pair_count). 12// Group composite = weighted average (75% character + 25% pair). 13// 14// Sealed verdict ladder: 15// GROUP_FAILED composite < 410 scene has multiple severe failures 16// GROUP_PARTIAL 410-614 some characters/pairs ok 17// GROUP_COHERENT 614-819 scene reads well 18// GROUP_S_CLASS >= 819 every character + every pair S-class 19 20// nx_safety_envelope: 21// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 22// sil_target: SIL1 23// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 24// verdict: NOT_YET_EVALUATED 25 26import "nx_syscalls.nx" 27const NX_MAGIC_1024: i64 = 1024 28 29const NX_GRP_RES_N_CHARS: i64 = 0 30const NX_GRP_RES_N_PAIRS: i64 = 1 31const NX_GRP_RES_CHAR_AVG: i64 = 2 32const NX_GRP_RES_PAIR_AVG: i64 = 3 33const NX_GRP_RES_WORST_CHAR_SCORE: i64 = 4 34const NX_GRP_RES_WORST_PAIR_SCORE: i64 = 5 35const NX_GRP_RES_COMPOSITE_Q10: i64 = 6 36const NX_GRP_RES_VERDICT: i64 = 7 37const NX_GRP_RES_FIELDS: i64 = 8 38 39const NX_GRP_FAILED: i64 = 0 40const NX_GRP_PARTIAL: i64 = 1 41const NX_GRP_COHERENT: i64 = 2 42const NX_GRP_S_CLASS: i64 = 3 43 44const NX_GRP_WEIGHT_CHARS_PCT: i64 = 75 45const NX_GRP_WEIGHT_PAIRS_PCT: i64 = 25 46 47// Aggregate per-character and per-pair scores. 48// char_scores: i64 array of length n_chars, each entry 0..1024 49// pair_scores: i64 array of length n_pairs (= n_chars*(n_chars-1)/2), each 0..1024 50// result: pre-allocated NX_GRP_RES_FIELDS i64 array 51func nx_group_composite(char_scores: *i64, n_chars: i64, 52 pair_scores: *i64, n_pairs: i64, 53 result: *i64) -> i64 { 54 var i: i64 = 0 55 while i < NX_GRP_RES_FIELDS { result[i] = 0; i = i + 1 } 56 if n_chars <= 0 { return 1 } 57 58 result[NX_GRP_RES_N_CHARS] = n_chars 59 result[NX_GRP_RES_N_PAIRS] = n_pairs 60 61 var char_sum: i64 = 0 62 var worst_char: i64 = NX_MAGIC_1024 63 var ci: i64 = 0 64 while ci < n_chars { 65 let s: i64 = char_scores[ci] 66 char_sum = char_sum + s 67 if s < worst_char { worst_char = s } 68 ci = ci + 1 69 } 70 let char_avg: i64 = char_sum / n_chars 71 result[NX_GRP_RES_CHAR_AVG] = char_avg 72 result[NX_GRP_RES_WORST_CHAR_SCORE] = worst_char 73 74 var pair_avg: i64 = NX_MAGIC_1024 // default to perfect when no pairs (solo scene) 75 var worst_pair: i64 = NX_MAGIC_1024 76 if n_pairs > 0 { 77 var pair_sum: i64 = 0 78 var pi: i64 = 0 79 while pi < n_pairs { 80 let s: i64 = pair_scores[pi] 81 pair_sum = pair_sum + s 82 if s < worst_pair { worst_pair = s } 83 pi = pi + 1 84 } 85 pair_avg = pair_sum / n_pairs 86 } 87 result[NX_GRP_RES_PAIR_AVG] = pair_avg 88 result[NX_GRP_RES_WORST_PAIR_SCORE] = worst_pair 89 90 // Weighted composite: 75% characters + 25% pairs. 91 let composite: i64 = (char_avg * NX_GRP_WEIGHT_CHARS_PCT + pair_avg * NX_GRP_WEIGHT_PAIRS_PCT) / 100 92 result[NX_GRP_RES_COMPOSITE_Q10] = composite 93 94 // Sealed verdict ladder. 95 var verdict: i64 = NX_GRP_FAILED 96 if composite >= 410 { verdict = NX_GRP_PARTIAL } 97 if composite >= 614 { verdict = NX_GRP_COHERENT } 98 if composite >= 819 { verdict = NX_GRP_S_CLASS } 99 // Downgrade if ANY character or pair is severely below threshold. 100 // Even if average is high, one ruined character drags the verdict. 101 if worst_char < 256 { if verdict == NX_GRP_S_CLASS { verdict = NX_GRP_COHERENT } } 102 if worst_char < 256 { if verdict == NX_GRP_COHERENT { verdict = NX_GRP_PARTIAL } } 103 if worst_pair < 256 { if verdict == NX_GRP_S_CLASS { verdict = NX_GRP_COHERENT } } 104 result[NX_GRP_RES_VERDICT] = verdict 105 return 0 106}