code wiki / (root) / nx_dashboard.nx

nx_dashboard.nx source

↩ module page · 195 lines · 7242 B

1// nx_dashboard.nx -- end-to-end batch-audit dashboard renderer. 2// 3// The capstone tying the sovereign-log roadmap into one consumable 4// artifact: takes a CBOR span buffer (any source), extracts every 5// BATCH_CLOSE rollup via nx_trace_query, renders an HTML page via 6// nx_html_emit, writes to fd. 7// 8// Per the user's "live fire testing + see how its testing, 9// innovating, improving" directive: this is what produces the page 10// they actually look at. Pure NishiLang from binary up; no 11// SQLite / Python / template engine. 12// 13// Caller flow: 14// 1. Compile nx_dashboard via nxc2 -> nx_dashboard.elf 15// 2. Pipe a CBOR span stream into stdin (or load from log file) 16// 3. Run nx_dashboard --fd=1 > batch_audit.html 17// 4. Open batch_audit.html in any browser 18// 19// The smoke test below constructs a synthetic 2-batch stream in 20// memory so we can exercise the end-to-end render without a live 21// batch. Production usage swaps the in-memory stream for an 22// actual log-bytes read. 23// 24// genealogy_id: cqrs_projection + grafana_dashboard_pattern 25// lineage_id: sovereign_substrate_dashboard_v1 26 27// nx_safety_envelope: 28// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 29// sil_target: SIL1 30// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 31// verdict: NOT_YET_EVALUATED 32 33import "nx_syscalls.nx" 34import "nx_runtime.nx" 35import "nx_tier.nx" 36import "nx_cbor.nx" 37import "nx_trace_emit.nx" 38import "nx_trace_query.nx" 39import "nx_html_emit.nx" 40import "nx_batch_audit_sidecar.nx" 41 42// ===== Map utilization band -> HTML badge class =================== 43// 44// SEVERE_BIAS or BROKEN -> red badge. MILD_BIAS or DRIFT -> yellow. 45// UNIFORM / GOOD -> green. EMPTY / UNKNOWN -> neutral. 46 47func _dash_util_badge_kind(util_band: nx_int) -> nx_int { 48 if util_band == NX_UTIL_UNIFORM { return NX_HTML_BADGE_GOOD } 49 if util_band == NX_UTIL_MILD_BIAS { return NX_HTML_BADGE_DRIFT } 50 if util_band == NX_UTIL_SEVERE_BIAS { return NX_HTML_BADGE_BROKEN } 51 return NX_HTML_BADGE_NEUTRAL 52} 53 54func _dash_util_badge_label(util_band: nx_int) -> *u8 { 55 if util_band == NX_UTIL_UNIFORM { return "UNIFORM" as *u8 } 56 if util_band == NX_UTIL_MILD_BIAS { return "MILD_BIAS" as *u8 } 57 if util_band == NX_UTIL_SEVERE_BIAS { return "SEVERE_BIAS" as *u8 } 58 return "EMPTY" as *u8 59} 60 61// ===== Lookup an attr value in a summary slot ===================== 62// 63// summary_slot is the [trace, n_attrs, k0, v0, k1, v1, ...] layout 64// from nx_tq_extract_batch_summaries. Returns the value matching 65// key_hash, or default_val if absent. 66 67func _dash_lookup_attr(slot: *i64, key_hash: nx_int, default_val: nx_int) -> nx_int { 68 let n_attrs: nx_int = slot[1] 69 var i: nx_int = 0 70 while i < n_attrs { 71 if slot[NX_TQ_SUMMARY_HDR_FIELDS + 2 * i] == key_hash { 72 return slot[NX_TQ_SUMMARY_HDR_FIELDS + 2 * i + 1] 73 } 74 i = i + 1 75 } 76 return default_val 77} 78 79// ===== Attribute-key hashes ======================================== 80// 81// Must match the hashes nx_batch_audit_sidecar uses when emitting 82// BATCH_CLOSE attrs. Documented here so the dashboard reads what 83// the sidecar wrote, with no string-table round-trip. 84 85const NX_DASH_KEY_N_SCENES: nx_int = 0x5C01 86const NX_DASH_KEY_N_VIOLATIONS: nx_int = 0xCC07 87const NX_DASH_KEY_OUTFIT_BAND: nx_int = 0x0FBA 88const NX_DASH_KEY_OUTFIT_DISTINCT: nx_int = 0xFBD1 89const NX_DASH_KEY_POSE_BAND: nx_int = 0xB05E 90const NX_DASH_KEY_POSE_DISTINCT: nx_int = 0xBD15 91 92// ===== Render one batch row ======================================== 93 94func nx_dashboard_render_row(fd: nx_int, slot: *i64) -> nx_int { 95 let trace_id: nx_int = slot[0] 96 let n_scenes: nx_int = _dash_lookup_attr(slot, NX_DASH_KEY_N_SCENES, 0) 97 let n_violations: nx_int = _dash_lookup_attr(slot, NX_DASH_KEY_N_VIOLATIONS, 0) 98 let outfit_band: nx_int = _dash_lookup_attr(slot, NX_DASH_KEY_OUTFIT_BAND, 0) 99 let outfit_distinct: nx_int = _dash_lookup_attr(slot, NX_DASH_KEY_OUTFIT_DISTINCT, 0) 100 let pose_band: nx_int = _dash_lookup_attr(slot, NX_DASH_KEY_POSE_BAND, 0) 101 let pose_distinct: nx_int = _dash_lookup_attr(slot, NX_DASH_KEY_POSE_DISTINCT, 0) 102 103 nx_html_tr_open(fd) 104 nx_html_td_int(fd, trace_id) 105 nx_html_td_int(fd, n_scenes) 106 nx_html_td_int(fd, n_violations) 107 nx_html_td_int(fd, outfit_distinct) 108 109 // Outfit-band cell with badge 110 _html_write_z(fd, "<td>" as *u8) 111 nx_html_badge(fd, 112 _dash_util_badge_kind(outfit_band), 113 _dash_util_badge_label(outfit_band)) 114 _html_write_z(fd, "</td>" as *u8) 115 116 nx_html_td_int(fd, pose_distinct) 117 _html_write_z(fd, "<td>" as *u8) 118 nx_html_badge(fd, 119 _dash_util_badge_kind(pose_band), 120 _dash_util_badge_label(pose_band)) 121 _html_write_z(fd, "</td>" as *u8) 122 123 nx_html_tr_close(fd) 124 return 0 125} 126 127// ===== Top-level render ============================================ 128// 129// Walks the CBOR buffer, extracts all BATCH_CLOSE rollups, emits a 130// full HTML page to fd. cap is the max batches we'll render in 131// one page (caller-sized). 132 133func nx_dashboard_render(fd: nx_int, title: *u8, 134 buf: *u8, n_bytes: nx_int, 135 cap: nx_int) -> nx_int { 136 // Extract summaries 137 let summaries_bytes: nx_int = cap * NX_TQ_SUMMARY_STRIDE * 8 138 let summaries: *i64 = (sys_mmap(summaries_bytes)) as *i64 139 let n_sums: nx_int = nx_tq_extract_batch_summaries(buf, n_bytes, 140 summaries, cap) 141 142 // Compute per-page totals 143 let counts: *i64 = (sys_mmap(NX_SPAN_N_KINDS * 8)) as *i64 144 let n_total_spans: nx_int = nx_tq_count_kinds(buf, n_bytes, counts) 145 146 // ===== Header ============================================== 147 nx_html_doc_open(fd, title) 148 nx_html_h1(fd, "Sovereign substrate -- batch audit") 149 150 nx_html_p(fd, "Each row is one BATCH_CLOSE span the substrate emitted. Bands routed via nx_dashboard.nx integration.") 151 152 // ===== Summary stats ======================================= 153 nx_html_h2(fd, "Stream stats") 154 nx_html_table_open(fd) 155 nx_html_thead_open(fd) 156 nx_html_th(fd, "metric") 157 nx_html_th(fd, "value") 158 nx_html_thead_close(fd) 159 160 nx_html_tr_open(fd) 161 nx_html_td_text(fd, "total spans") 162 nx_html_td_int(fd, n_total_spans) 163 nx_html_tr_close(fd) 164 165 nx_html_tr_open(fd) 166 nx_html_td_text(fd, "batches found") 167 nx_html_td_int(fd, n_sums) 168 nx_html_tr_close(fd) 169 170 nx_html_table_close(fd) 171 172 // ===== Per-batch table ===================================== 173 nx_html_h2(fd, "Batches") 174 nx_html_table_open(fd) 175 nx_html_thead_open(fd) 176 nx_html_th(fd, "trace") 177 nx_html_th(fd, "scenes") 178 nx_html_th(fd, "violations") 179 nx_html_th(fd, "outfit_distinct") 180 nx_html_th(fd, "outfit_band") 181 nx_html_th(fd, "pose_distinct") 182 nx_html_th(fd, "pose_band") 183 nx_html_thead_close(fd) 184 185 var i: nx_int = 0 186 while i < n_sums { 187 let slot: *i64 = ((summaries as nx_int) + i * NX_TQ_SUMMARY_STRIDE * 8) as *i64 188 nx_dashboard_render_row(fd, slot) 189 i = i + 1 190 } 191 192 nx_html_table_close(fd) 193 nx_html_doc_close(fd) 194 return n_sums 195}