code wiki / (root) / nx_symbiote.nx

nx_symbiote.nx source

↩ module page · 280 lines · 11395 B

1// nx_symbiote.nx -- foreign-process virtual cell. 2// 3// Biological analogue: a symbiote is a non-self organism living 4// cooperatively with the host -- mitochondria are the classic example 5// (originally free-living bacteria, now permanent residents). Nishi 6// symbiote wraps a non-Nishi process (Steam-hosted NMS, Chrome, OBS, 7// VS Code, a CUDA training run) and projects it into the same resource- 8// arbitration substrate as Nishi-native cells. 9// 10// THIS IS THE PARTNERSHIP INTERFACE. Per user 2026-05-19 NMS-via-Steam 11// scenario: "where can we build from the silicon up to get the best 12// experience on the nishi ecosystem and then as it moves off our 13// ecosystem into steam partnering with steam to improve things like 14// vram usage, disk space usage." The user runs NMS via Steam; we 15// can't make Steam speak Nishi grammar, but we can OBSERVE the Steam- 16// hosted process and NEGOTIATE through a treaty (see nx_treaty). 17// 18// CRITICAL HONESTY (per [[feedback-honest-perf-verdict-no-aspirational- 19// claims]]): symbiote resource numbers are AS-OBSERVED, not AS-PROMISED. 20// A native nx_cell honors its budget contractually -- the substrate 21// enforces it. A symbiote may consume MORE than declared at any moment 22// because it has no contractual obligation. Symbiote's job is to 23// MEASURE the reality, not GUARANTEE the limit. 24// 25// Composes: 26// nx_budget -- virtual_budget records the symbiote's 27// DECLARED resource ceiling (caller-supplied; 28// honest baseline for treaty negotiation) 29// nx_attention_class -- foreground game symbiote (NMS) gets 30// foreground priority just like native cells 31// nx_evict_journal -- throttle/pause/terminate events logged 32// nx_treaty -- bilateral resource agreement between 33// organism and symbiote 34// nx_organism -- the container that arbitrates across all 35// symbiotes + native pathways 36// 37// V1 ships an in-memory descriptor with caller-supplied observation 38// updates. Real OS probes (Linux /proc/<pid>/status + /proc/<pid>/ 39// io, Windows Job Object + GetProcessMemoryInfo + nvidia-smi pmon) 40// are queued -- the integration layer between nx_symbiote and the 41// host OS lives outside this primitive. 42// 43// Gap list (V1 honest perf verdict): 44// - no actual OS probe (caller calls nx_symbiote_update with 45// externally-obtained numbers) 46// - throttle/pause/terminate are intent verbs; actual enforcement 47// is the integration layer's job (SIGSTOP/SetSuspendThread/etc) 48// - no GPU-specific VRAM probe (nvidia-smi binding queued) 49// - no per-process disk-bandwidth probe 50// - no cross-PID grouping (Steam spawns many PIDs; symbiote is 51// 1:1 with PID, treaty layer handles process trees) 52// 53// genealogy_id: biology_symbiosis + cardinal_2026-05-19_ecosystem_wide 54// lineage_id: substrate_symbiote_v1 55// 56// nx_safety_envelope: 57// intended_use: "Foreign-process virtual cell for ecosystem- 58// wide arbitration; OBSERVES, does not contract" 59// sil_target: SIL2 60// evidence: [observation_not_contract_explicit, 61// enforcement_intent_separate_from_observation] 62// hazard_register: [bug-tape-symbiote-pid-reuse-after-exit, 63// bug-tape-symbiote-stale-observation] 64// verdict: NOT_YET_EVALUATED 65 66import "nx_syscalls.nx" 67import "nx_tier.nx" 68import "nx_budget.nx" 69import "nx_attention_class.nx" 70import "nx_evict_journal.nx" 71const NX_MAGIC_1024: i64 = 1024 72 73// ===== Sealed enum: NxSymbioteState =============================== 74 75const NX_SYM_RUNNING: nx_int = 0 76const NX_SYM_THROTTLED: nx_int = 1 77const NX_SYM_PAUSED: nx_int = 2 78const NX_SYM_TERMINATED: nx_int = 3 79const NX_SYM_GONE: nx_int = 4 // process exited on its own 80const NX_SYM_N_STATES: nx_int = 5 81 82// ===== Sealed enum: NxSymbioteVerdict ============================= 83 84const NX_SYM_OK: nx_int = 0 85const NX_SYM_ERR_BAD_STATE: nx_int = 1 86const NX_SYM_ERR_BAD_PID: nx_int = 2 87const NX_SYM_ERR_ALREADY_GONE: nx_int = 3 88 89// ===== Struct: NxSymbiote ========================================= 90// 91// pid is the host OS process id (Linux pid_t / Windows DWORD). name 92// is a caller-supplied byte buffer (e.g. "steam-nms"). attention_class 93// is the priority the substrate gives it -- NMS gameplay would be 94// FOREGROUND_GAME, a background training run BACKGROUND_INFERENCE. 95// 96// virtual_budget is the DECLARED ceiling (used in treaty negotiation 97// and organism aggregate forecasts). observed_* fields hold the 98// last-probe ACTUAL consumption -- the truth, not the promise. 99 100struct NxSymbiote { 101 pid: nx_int, 102 name: *u8, 103 attention_class: nx_int, 104 state: nx_int, 105 virtual_budget: *NxBudget, 106 observed_ram_bytes: nx_size, 107 observed_vram_bytes: nx_size, 108 observed_cpu_us: nx_size, 109 observed_disk_bytes: nx_size, 110 last_observe_us: nx_size, 111 cooperative: nx_int, // 1 if it speaks treaty, 0 otherwise 112} 113 114// ===== nx_sym_state_is_valid ===================================== 115 116func nx_sym_state_is_valid(s: nx_int) -> nx_int { 117 if s < 0 { return 0 } 118 if s >= NX_SYM_N_STATES { return 0 } 119 return 1 120} 121 122// ===== Constructor =============================================== 123 124func nx_symbiote_new(pid: nx_int, 125 name: *u8, 126 attention_class: nx_int, 127 virtual_budget: *NxBudget, 128 cooperative: nx_int) -> *NxSymbiote { 129 let s: *NxSymbiote = (sys_mmap(88)) as *NxSymbiote 130 s.pid = pid 131 s.name = name 132 s.attention_class = attention_class 133 s.state = NX_SYM_RUNNING 134 s.virtual_budget = virtual_budget 135 s.observed_ram_bytes = 0 136 s.observed_vram_bytes = 0 137 s.observed_cpu_us = 0 138 s.observed_disk_bytes = 0 139 s.last_observe_us = 0 140 s.cooperative = cooperative 141 return s 142} 143 144// ===== nx_symbiote_update ======================================== 145// 146// Caller refreshes the observed_* fields with fresh OS-probe numbers. 147// V1 takes them all as arguments (caller pulls from /proc + nvidia-smi); 148// V2 will internalize a probe-source callback. 149 150func nx_symbiote_update(s: *NxSymbiote, 151 ram_bytes: nx_size, 152 vram_bytes: nx_size, 153 cpu_us: nx_size, 154 disk_bytes: nx_size, 155 now_us: nx_size) -> nx_int { 156 s.observed_ram_bytes = ram_bytes 157 s.observed_vram_bytes = vram_bytes 158 s.observed_cpu_us = cpu_us 159 s.observed_disk_bytes = disk_bytes 160 s.last_observe_us = now_us 161 return NX_SYM_OK 162} 163 164// ===== nx_symbiote_overshoot_q10 ================================= 165// 166// Q10 ratio of observed/declared for one resource. > 1024 means the 167// symbiote is consuming MORE than its declared virtual_budget allows. 168// Treaty layer uses this to detect breach. 169 170func nx_symbiote_overshoot_q10(s: *NxSymbiote, kind: nx_int) -> nx_int { 171 if (s.virtual_budget as i64) == 0 { return 0 } 172 var max: nx_size = 0 173 var obs: nx_size = 0 174 if kind == NX_RES_RAM { max = s.virtual_budget.ram_max; obs = s.observed_ram_bytes } 175 if kind == NX_RES_VRAM { max = s.virtual_budget.vram_max; obs = s.observed_vram_bytes } 176 if kind == NX_RES_CPU { max = s.virtual_budget.cpu_us_max; obs = s.observed_cpu_us } 177 if kind == NX_RES_DISK { max = s.virtual_budget.disk_max; obs = s.observed_disk_bytes } 178 if max <= 0 { return 0 } 179 return ((obs as i64) * NX_MAGIC_1024) / (max as i64) 180} 181 182// ===== nx_symbiote_throttle ====================================== 183// 184// Intent verb: caller wants the symbiote slowed (renice, CPU affinity 185// drop, JobObject CPU rate cap, etc). V1 just transitions state and 186// logs -- actual OS enforcement is the integration layer's job. 187 188func nx_symbiote_throttle(s: *NxSymbiote, 189 j: *NxEvictJournal, 190 now_us: nx_size, 191 displaced_by: nx_int) -> nx_int { 192 if s.state == NX_SYM_TERMINATED { return NX_SYM_ERR_ALREADY_GONE } 193 if s.state == NX_SYM_GONE { return NX_SYM_ERR_ALREADY_GONE } 194 s.state = NX_SYM_THROTTLED 195 if (j as i64) != 0 { 196 nx_evict_log(j, now_us, s.pid, 197 NX_EVR_YIELD_THROTTLED, NX_RES_CPU, 198 s.attention_class, displaced_by) 199 } 200 return NX_SYM_OK 201} 202 203// ===== nx_symbiote_pause ========================================= 204// 205// Intent verb: caller wants the symbiote suspended (SIGSTOP / Sus- 206// pendThread). Stronger than throttle; useful when a foreground cell 207// needs immediate VRAM and the symbiote can wait. 208 209func nx_symbiote_pause(s: *NxSymbiote, 210 j: *NxEvictJournal, 211 now_us: nx_size, 212 displaced_by: nx_int) -> nx_int { 213 if s.state == NX_SYM_TERMINATED { return NX_SYM_ERR_ALREADY_GONE } 214 if s.state == NX_SYM_GONE { return NX_SYM_ERR_ALREADY_GONE } 215 s.state = NX_SYM_PAUSED 216 if (j as i64) != 0 { 217 nx_evict_log(j, now_us, s.pid, 218 NX_EVR_YIELD_DEMOTED, NX_RES_CPU, 219 s.attention_class, displaced_by) 220 } 221 return NX_SYM_OK 222} 223 224// ===== nx_symbiote_resume ======================================== 225// 226// Wakes a throttled or paused symbiote. Cannot revive a terminated 227// or gone symbiote -- caller must re-spawn the process and create a 228// new nx_symbiote. 229 230func nx_symbiote_resume(s: *NxSymbiote) -> nx_int { 231 if s.state == NX_SYM_TERMINATED { return NX_SYM_ERR_ALREADY_GONE } 232 if s.state == NX_SYM_GONE { return NX_SYM_ERR_ALREADY_GONE } 233 s.state = NX_SYM_RUNNING 234 return NX_SYM_OK 235} 236 237// ===== nx_symbiote_terminate ===================================== 238// 239// Intent verb: caller wants the symbiote killed (SIGKILL / Terminate- 240// Process). Logged loudly to the eviction journal -- terminating a 241// foreign process is a heavy action and should never be silent. 242 243func nx_symbiote_terminate(s: *NxSymbiote, 244 j: *NxEvictJournal, 245 now_us: nx_size, 246 displaced_by: nx_int) -> nx_int { 247 if s.state == NX_SYM_TERMINATED { return NX_SYM_ERR_ALREADY_GONE } 248 s.state = NX_SYM_TERMINATED 249 if (j as i64) != 0 { 250 nx_evict_log(j, now_us, s.pid, 251 NX_EVR_TERMINATED, NX_RES_CPU, 252 s.attention_class, displaced_by) 253 } 254 return NX_SYM_OK 255} 256 257// ===== nx_symbiote_is_responsive ================================= 258// 259// Returns 1 if the symbiote is in a state that can do work 260// (RUNNING). Throttled/paused/terminated/gone all return 0. 261 262func nx_symbiote_is_responsive(s: *NxSymbiote) -> nx_int { 263 if s.state == NX_SYM_RUNNING { return 1 } 264 return 0 265} 266 267// ===== nx_symbiote_stale_observation ============================= 268// 269// Returns 1 if the last observation is older than max_age_us, meaning 270// our resource numbers may not reflect reality. Used by treaty layer 271// to refuse renegotiation on stale data. 272 273func nx_symbiote_stale_observation(s: *NxSymbiote, 274 now_us: nx_size, 275 max_age_us: nx_size) -> nx_int { 276 if s.last_observe_us == 0 { return 1 } 277 let age: nx_size = now_us - s.last_observe_us 278 if age > max_age_us { return 1 } 279 return 0 280}