code wiki / (root) / nx_homeostasis.nx

nx_homeostasis.nx source

↩ module page · 144 lines · 6411 B

1// nx_homeostasis.nx -- steady-state monitor that triggers migration. 2// 3// Biological analogue: homeostasis is the body's set-point control -- 4// when blood glucose / pH / temperature drift past tolerance bands, 5// counter-regulatory signals fire. Nishi homeostasis watches each 6// cell's budget pressure, eviction history, and metabolism heat; when 7// any drifts past its set-point, it emits a migration signal that 8// nx_tropism resolves into a concrete relocation target. 9// 10// This is the structural EXCEED-axis vs the kernel OOM-killer: the 11// kernel waits until the host is OUT of memory and then kills the 12// biggest offender after the fact. Homeostasis fires PROACTIVELY at 13// 90% pressure (Q10 921), giving the substrate slack to relocate the 14// cell cleanly before any user-visible disruption. 15// 16// Composes: 17// nx_budget -- pressure_q10 per resource 18// nx_evict_journal -- count_for_cell to spot eviction storms 19// nx_metabolism -- hot sites are migration candidates 20// nx_attention_class -- foreground cells prefer local migration; 21// idle cells are offload-OK to peer/cloud 22// nx_tropism -- consumes the migration signal to pick target 23// 24// V1 ships per-cell snapshot polling. Continuous monitoring (an 25// integrator that fires on sustained pressure rather than instantaneous) 26// is queued; today the caller drives polling at its preferred cadence 27// (a 100ms tick is the canonical default). 28// 29// Gap list (V1 honest perf verdict): 30// - no integrator / leaky-bucket dampening (transient spikes can 31// fire migration signals) 32// - no cross-cell pressure (only per-cell, not host-aggregate) 33// - no de-bounce on repeated MIGRATE signals from same cell 34// - no return-to-set-point hysteresis (cell re-evaluated each tick) 35// 36// genealogy_id: nishi_cardinal_2026-05-17_cooperative_resource_arbitration + cardinal-21 37// lineage_id: substrate_homeostasis_v1 38// 39// nx_safety_envelope: 40// intended_use: "Proactive migration trigger before host OOM; 41// composes budget+evict+metabolism into one 42// decision signal" 43// sil_target: SIL2 44// evidence: [proactive_not_reactive, named_thresholds, 45// decision_observable_via_signal_enum] 46// hazard_register: [bug-tape-homeostasis-thrash-on-edge-pressure] 47// verdict: NOT_YET_EVALUATED 48 49import "nx_syscalls.nx" 50import "nx_tier.nx" 51import "nx_budget.nx" 52import "nx_evict_journal.nx" 53import "nx_metabolism.nx" 54import "nx_attention_class.nx" 55 56// ===== Sealed enum: NxHomeoSignal ================================= 57 58const NX_HOMEO_STEADY: nx_int = 0 // within bands, no action 59const NX_HOMEO_MIGRATE_RAM: nx_int = 1 // RAM pressure -> move 60const NX_HOMEO_MIGRATE_VRAM: nx_int = 2 // VRAM pressure -> move 61const NX_HOMEO_MIGRATE_DISK: nx_int = 3 // disk pressure -> archive 62const NX_HOMEO_MIGRATE_THERMAL: nx_int = 4 // CPU pressure -> offload 63const NX_HOMEO_DEMOTE_TIER: nx_int = 5 // metabolism says step down 64const NX_HOMEO_PROMOTE_TIER: nx_int = 6 // metabolism says step up 65const NX_HOMEO_EVICTION_STORM: nx_int = 7 // displaced too often 66const NX_HOMEO_N_SIGNALS: nx_int = 8 67 68// ===== Set-points ================================================ 69// 70// Migration fires at 90% (Q10 921); demotion fires at 95% (Q10 972). 71// Eviction-storm threshold: 5 events in the journal window for this 72// cell. Per Cardinal 11 these are named constants for one-line tuning. 73 74const NX_HOMEO_MIGRATE_PRESSURE_Q10: nx_int = 921 75const NX_HOMEO_DEMOTE_PRESSURE_Q10: nx_int = 972 76const NX_HOMEO_EVICTION_STORM_AT: nx_int = 5 77 78// ===== nx_homeo_check ============================================= 79// 80// Single-cell snapshot. Returns the first signal that crosses its 81// set-point; caller is expected to handle that signal then re-check. 82// Ordering: thermal first (most user-visible), then RAM, VRAM, disk, 83// then eviction-storm, then metabolism-driven tier signals. 84// 85// budget may be NULL when the cell has no budget assigned (e.g., 86// initialization phase); homeostasis returns STEADY in that case 87// rather than spuriously firing migration on uninitialized state. 88 89func nx_homeo_check(b: *NxBudget, 90 j: *NxEvictJournal, 91 m: *NxMetabolism, 92 cell_id: nx_int, 93 site_id: nx_int) -> nx_int { 94 if (b as i64) == 0 { return NX_HOMEO_STEADY } 95 96 let cpu_q: nx_int = nx_budget_pressure_q10(b, NX_RES_CPU) 97 if cpu_q >= NX_HOMEO_MIGRATE_PRESSURE_Q10 { return NX_HOMEO_MIGRATE_THERMAL } 98 99 let ram_q: nx_int = nx_budget_pressure_q10(b, NX_RES_RAM) 100 if ram_q >= NX_HOMEO_MIGRATE_PRESSURE_Q10 { return NX_HOMEO_MIGRATE_RAM } 101 102 let vram_q: nx_int = nx_budget_pressure_q10(b, NX_RES_VRAM) 103 if vram_q >= NX_HOMEO_MIGRATE_PRESSURE_Q10 { return NX_HOMEO_MIGRATE_VRAM } 104 105 let disk_q: nx_int = nx_budget_pressure_q10(b, NX_RES_DISK) 106 if disk_q >= NX_HOMEO_MIGRATE_PRESSURE_Q10 { return NX_HOMEO_MIGRATE_DISK } 107 108 if (j as i64) != 0 { 109 let storms: nx_int = nx_evict_count_for_cell(j, cell_id) 110 if storms >= NX_HOMEO_EVICTION_STORM_AT { return NX_HOMEO_EVICTION_STORM } 111 } 112 113 if (m as i64) != 0 { 114 let suggested: nx_int = nx_metab_suggest_target(m, site_id) 115 // current tier is held in nx_budget metadata in the future; 116 // V1 assumes NX_TIER_WORKSTATION baseline and signals when 117 // metabolism suggests a different tier. 118 if suggested > NX_TIER_WORKSTATION { return NX_HOMEO_PROMOTE_TIER } 119 if suggested < NX_TIER_FAMILY_DEVICE { return NX_HOMEO_DEMOTE_TIER } 120 } 121 122 return NX_HOMEO_STEADY 123} 124 125// ===== nx_homeo_signal_is_migration =============================== 126// 127// Convenience predicate for callers that only care whether ANY 128// migration is indicated (any of RAM/VRAM/DISK/THERMAL). 129 130func nx_homeo_signal_is_migration(sig: nx_int) -> nx_int { 131 if sig == NX_HOMEO_MIGRATE_RAM { return 1 } 132 if sig == NX_HOMEO_MIGRATE_VRAM { return 1 } 133 if sig == NX_HOMEO_MIGRATE_DISK { return 1 } 134 if sig == NX_HOMEO_MIGRATE_THERMAL { return 1 } 135 return 0 136} 137 138// ===== nx_homeo_signal_is_valid =================================== 139 140func nx_homeo_signal_is_valid(sig: nx_int) -> nx_int { 141 if sig < 0 { return 0 } 142 if sig >= NX_HOMEO_N_SIGNALS { return 0 } 143 return 1 144}