nx_load_test_harness.nx source
↩ module page · 186 lines · 8898 B
1// nx_load_test_harness.nx -- N-concurrent-user capacity probe.
2//
3// module: nishi-core.perception.load_test_harness
4// depends: nishi-core.perception.profile + nishi-core.perception.external_reach_probe +
5// nishi-core.perception.perceptual_dataset + nishi-core.net.socket + nishi-core.io.syscalls
6// disk_kb: 5
7// capability: PERCEPTION
8// wired_status: PARTIAL_WIRED
9//
10// MISSING_CAPABILITIES:
11// - CONCURRENT_CONNECT_DISPATCH (issue N parallel TCP+TLS+HTTP connects via
12// nx_socket + nx_tls13_client + nx_https_client; all FULLY_WIRED;
13// wire the call site through a scheduler that respects
14// nx_cooperative_resource_arbitration budgets)
15// - LATENCY_PERCENTILE_AGGREGATION (p50 / p95 / p99 / pmax + error rate
16// in single pass without buffering all responses)
17// - WS_LOAD_DISPATCH (WebSocket-frames-per-second sustain test for the
18// /video chat substrate specifically)
19// - WEBRTC_PEER_LOAD (simulate N peer mesh connections with SRTP-like
20// payload; gates the family-chat capacity claim)
21//
22// license_tier: PUBLIC_NISHI_SUBSTRATE
23// genealogy_id: feedback-substrate-does-heavy-lifting-user-is-partner-not-gate_2026 +
24// feedback-substrate-primitives-meta-not-one-off_2026 +
25// feedback-real-playtest-loop-not-just-logs +
26// nx_realism_score +
27// NISHIFAMILY_VIDEO_HARDENING_2026-05-20 +
28// wrk_2012_http_benchmarking +
29// vegeta_2013_http_load_testing
30//
31// User directive 2026-05-20: "real heavy heavy testing... how many users
32// can interact well, if it does message spam, all that bullshit."
33//
34// THIS primitive issues N concurrent virtual users against ANY endpoint
35// (HTTP/HTTPS landing page, WebSocket chat frames, simulated WebRTC peer
36// mesh) and reports latency percentiles + error rate + sustained
37// throughput. Distinct from nx_external_reach_probe (which is one
38// probe at a time): this is sustained concurrent load to find the
39// capacity knee.
40//
41// First measurements 2026-05-20 against nishifamily.com/video from INSIDE
42// the NAS via curl-based bench (companion shell script):
43// N=10 parallel: p50=0.95s p99=0.98s 10/10 OK
44// N=50 parallel: p50=3.41s p99=4.57s 50/50 OK (DEGRADED)
45// N=200 parallel: p50=15.07s p99=18.38s 198/200 OK (2 errors, BROKEN)
46//
47// Reuse set:
48// - nishifamily.com/video capacity ceiling (PRIMARY for today)
49// - Prey-spec dog toy production-line load test (N toys reporting in
50// simultaneously when staff swap power)
51// - Livestock acoustic welfare gateway N-sensor sustain (farm with
52// 100 cattle each with a sensor)
53// - Conservation recorder bulk-upload (overnight bulk push from
54// N field recorders to a central ingest)
55// - Vet-clinic stethoscope concurrent-N-room (clinic with N exam rooms)
56// - Beekeeping hive-sensor swarm (apiary with N hives reporting)
57// - Generic any-endpoint sustain stress test for substrate
58
59import "nx_syscalls.nx"
60import "nx_perceptual_profile.nx"
61import "nx_external_reach_probe.nx"
62import "nx_perceptual_dataset.nx"
63
64// ===== Load profile sealed enum ==================================
65
66const NX_LT_PROFILE_HTTP_GET: i64 = 1 // simple GET
67const NX_LT_PROFILE_HTTP_POST: i64 = 2 // form submit / API
68const NX_LT_PROFILE_WS_CHAT_BURST: i64 = 3 // N message frames/sec
69const NX_LT_PROFILE_WS_LONG_LIVED: i64 = 4 // N connections held open
70const NX_LT_PROFILE_WEBRTC_PEER_MESH: i64 = 5 // mesh with N participants
71const NX_LT_PROFILE_FILE_DOWNLOAD: i64 = 6 // N parallel large downloads
72const NX_LT_PROFILE_DNS_QUERY_FLOOD: i64 = 7 // DNS amplification
73 // resistance test
74const NX_LT_PROFILE_TLS_HANDSHAKE_STORM: i64 = 8 // N TLS handshakes in
75 // burst (handshake-only)
76
77func nx_lt_profile_name(p: i64) -> *u8 {
78 if p == NX_LT_PROFILE_HTTP_GET { return "HTTP_GET" }
79 if p == NX_LT_PROFILE_HTTP_POST { return "HTTP_POST" }
80 if p == NX_LT_PROFILE_WS_CHAT_BURST { return "WS_CHAT_BURST" }
81 if p == NX_LT_PROFILE_WS_LONG_LIVED { return "WS_LONG_LIVED" }
82 if p == NX_LT_PROFILE_WEBRTC_PEER_MESH { return "WEBRTC_PEER_MESH" }
83 if p == NX_LT_PROFILE_FILE_DOWNLOAD { return "FILE_DOWNLOAD" }
84 if p == NX_LT_PROFILE_DNS_QUERY_FLOOD { return "DNS_QUERY_FLOOD" }
85 if p == NX_LT_PROFILE_TLS_HANDSHAKE_STORM { return "TLS_HANDSHAKE_STORM" }
86 return "UNKNOWN_PROFILE"
87}
88
89// ===== Verdicts ===================================================
90//
91// Capacity is grade-discretized so substrate can name "still S-class up
92// to N=10, drops to A at N=50, F at N=200" without ambiguity.
93
94const NX_LT_VERDICT_S_CLASS: i64 = 5 // p99 <= 100 ms, 100% success
95const NX_LT_VERDICT_A_CLASS: i64 = 4 // p99 <= 500 ms
96const NX_LT_VERDICT_B_CLASS: i64 = 3 // p99 <= 2 s
97const NX_LT_VERDICT_C_CLASS: i64 = 2 // p99 <= 5 s
98const NX_LT_VERDICT_D_CLASS: i64 = 1 // p99 <= 30 s
99const NX_LT_VERDICT_F_BROKEN: i64 = 0 // any errors OR p99 > 30s
100const NX_LT_VERDICT_DEPENDENCY_MISSING: i64 = -1 // PARTIAL_WIRED default
101
102func nx_lt_verdict_name(v: i64) -> *u8 {
103 if v == NX_LT_VERDICT_S_CLASS { return "S_CLASS" }
104 if v == NX_LT_VERDICT_A_CLASS { return "A_CLASS" }
105 if v == NX_LT_VERDICT_B_CLASS { return "B_CLASS" }
106 if v == NX_LT_VERDICT_C_CLASS { return "C_CLASS" }
107 if v == NX_LT_VERDICT_D_CLASS { return "D_CLASS" }
108 if v == NX_LT_VERDICT_F_BROKEN { return "F_BROKEN" }
109 if v == NX_LT_VERDICT_DEPENDENCY_MISSING { return "DEPENDENCY_MISSING" }
110 return "UNKNOWN_LT_VERDICT"
111}
112
113// ===== Load test config + result structs ==========================
114
115struct NxLoadTestConfig {
116 endpoint_url_ptr: *u8
117 endpoint_url_len: i64
118 profile: i64 // NX_LT_PROFILE_*
119 concurrency_n: i64 // virtual-user count
120 duration_seconds: i64 // for sustained tests
121 requests_per_user: i64 // for finite-burst tests
122 ramp_up_seconds: i64 // 0 = thundering-herd; >0 = staggered
123 per_request_timeout_ms: i64
124 payload_size_bytes: i64 // POST / WS / RTP-like simulation
125 target_profile: i64 // optional: which species perceptual
126 // envelope to gate "acceptable latency"
127 // against
128}
129
130struct NxLoadTestResult {
131 config_hash_ptr: *u8
132 config_hash_len: i64
133 timestamp_unix_ms: i64
134 overall_verdict: i64 // NX_LT_VERDICT_*
135 requests_attempted: i64
136 requests_succeeded: i64
137 requests_errored: i64
138 p50_latency_ms: i64
139 p95_latency_ms: i64
140 p99_latency_ms: i64
141 pmax_latency_ms: i64
142 sustained_rps: i64 // requests/sec achieved
143 bytes_throughput_per_s: i64
144}
145
146// ===== Top-level entry stubs ======================================
147
148// nx_load_test_run -- execute the configured load profile once.
149
150func nx_load_test_run(config_ptr: *NxLoadTestConfig,
151 result_out_ptr: *NxLoadTestResult) -> i64 {
152 if config_ptr == 0 as *NxLoadTestConfig { return NX_LT_VERDICT_F_BROKEN }
153 // PARTIAL_WIRED: concurrent dispatch + percentile aggregation queued.
154 return NX_LT_VERDICT_DEPENDENCY_MISSING
155}
156
157// nx_load_test_find_capacity_knee -- sweep concurrency from 1 to N_max,
158// binary-search the point where verdict drops from B-or-better to C-or-worse.
159// "What's the capacity ceiling for acceptable latency?" answered directly.
160
161func nx_load_test_find_capacity_knee(endpoint_url_ptr: *u8, endpoint_url_len: i64,
162 profile: i64,
163 n_min: i64, n_max: i64,
164 acceptable_verdict_floor: i64) -> i64 {
165 if endpoint_url_len <= 0 { return 0 }
166 if profile < NX_LT_PROFILE_HTTP_GET { return 0 }
167 if profile > NX_LT_PROFILE_TLS_HANDSHAKE_STORM { return 0 }
168 if n_min < 1 { return 0 }
169 if n_max < n_min { return 0 }
170 if acceptable_verdict_floor < NX_LT_VERDICT_F_BROKEN { return 0 }
171 return 0
172}
173
174// nx_load_test_persist_to_dataset -- record the result in
175// nx_perceptual_dataset as a VALIDATION entry so the capacity curve is
176// preserved over time + regression-detectable.
177
178func nx_load_test_persist_to_dataset(result_ptr: *NxLoadTestResult) -> i64 {
179 return 0
180}
181
182// nx_load_test_get_last_verdict -- inspector.
183
184func nx_load_test_get_last_verdict() -> i64 {
185 return NX_LT_VERDICT_DEPENDENCY_MISSING
186}