nx_tropism.nx source
↩ module page · 188 lines · 7733 B
1// nx_tropism.nx -- location-policy resolver.
2//
3// Biological analogue: tropism is a directional growth response to a
4// stimulus gradient (phototropism toward light, geotropism toward
5// gravity, chemotropism toward nutrient). Nishi tropism resolves a
6// homeostasis migration signal into a concrete destination by
7// consulting the cell's declared preference list against current
8// conditions. Same .nx pathway runs local/NAS/peer/cloud transparently
9// per [[feedback-pathway-tropism-block-composition-location-agnostic]].
10//
11// The structural EXCEED-axis vs K8s scheduler / Nomad / Argo: those
12// resolve placement at submission time and re-schedule on failure;
13// nx_tropism resolves PER MIGRATION SIGNAL, mid-pathway, with cell
14// memory intact via the existing nx_chromatin replication.
15//
16// Composes:
17// nx_homeostasis -- supplies the migration signal
18// nx_attention_class -- foreground prefers LOCAL_*; idle accepts CLOUD
19// nx_budget -- destination must have headroom for the cell
20// nx_pathway -- pathway declares per-cell tropism preference
21//
22// V1 ships a sealed enum of 10 location targets + a resolver that
23// picks based on signal + attention class. Cost / bandwidth / latency
24// estimation per peer is queued (requires peer-mesh discovery layer).
25//
26// Gap list (V1 honest perf verdict):
27// - no actual peer discovery (returns symbolic target, not address)
28// - no cost estimation (CHEAPEST returns same as LOCAL_DISK)
29// - no FOLLOW_INPUT/FOLLOW_DEST cross-cell resolution (returns
30// LOCAL_CPU placeholder)
31// - no failed-migration retry policy (caller's responsibility)
32//
33// genealogy_id: nishi_cardinal_2026-05-17_pathway_tropism + biology_directional_growth
34// lineage_id: substrate_tropism_v1
35//
36// nx_safety_envelope:
37// intended_use: "Resolve homeostasis migration signal into a
38// concrete location target per cell preference"
39// sil_target: SIL1
40// evidence: [enum_sealed, deterministic_resolution,
41// attention_class_honored]
42// verdict: NOT_YET_EVALUATED
43
44import "nx_syscalls.nx"
45import "nx_tier.nx"
46import "nx_attention_class.nx"
47import "nx_homeostasis.nx"
48const NX_MAGIC_1024: i64 = 1024
49
50// ===== Sealed enum: NxTropism =====================================
51//
52// Order is preference rank within a cell's declared list -- LOCAL_*
53// is cheapest+lowest-latency, CLOUD is expensive+highest-latency.
54
55const NX_TROP_LOCAL_CPU: nx_int = 0
56const NX_TROP_LOCAL_GPU: nx_int = 1
57const NX_TROP_LOCAL_GPU_MAX_VRAM: nx_int = 2
58const NX_TROP_LOCAL_DISK: nx_int = 3
59const NX_TROP_NAS: nx_int = 4
60const NX_TROP_PEER: nx_int = 5
61const NX_TROP_CLOUD: nx_int = 6
62const NX_TROP_FOLLOW_INPUT: nx_int = 7 // co-locate with upstream cell
63const NX_TROP_CHEAPEST: nx_int = 8 // pick by cost (V2)
64const NX_TROP_USER_ATTENTION: nx_int = 9 // pick by where user is looking
65const NX_TROP_N_TARGETS: nx_int = 10
66
67// ===== Sealed enum: NxTropismVerdict ==============================
68
69const NX_TROP_OK: nx_int = 0
70const NX_TROP_ERR_BAD_TARGET: nx_int = 1
71const NX_TROP_ERR_NO_HEADROOM: nx_int = 2 // resolved target full
72
73// ===== nx_tropism_is_valid =======================================
74
75func nx_tropism_is_valid(t: nx_int) -> nx_int {
76 if t < 0 { return 0 }
77 if t >= NX_TROP_N_TARGETS { return 0 }
78 return 1
79}
80
81// ===== nx_tropism_is_local =======================================
82//
83// Local targets (CPU/GPU/disk) keep cell memory in same address space;
84// migration is cheap. Remote targets (NAS/PEER/CLOUD) require
85// chromatin serialization + transport.
86
87func nx_tropism_is_local(t: nx_int) -> nx_int {
88 if t == NX_TROP_LOCAL_CPU { return 1 }
89 if t == NX_TROP_LOCAL_GPU { return 1 }
90 if t == NX_TROP_LOCAL_GPU_MAX_VRAM { return 1 }
91 if t == NX_TROP_LOCAL_DISK { return 1 }
92 return 0
93}
94
95// ===== nx_tropism_is_remote ======================================
96
97func nx_tropism_is_remote(t: nx_int) -> nx_int {
98 if t == NX_TROP_NAS { return 1 }
99 if t == NX_TROP_PEER { return 1 }
100 if t == NX_TROP_CLOUD { return 1 }
101 return 0
102}
103
104// ===== nx_tropism_resolve ========================================
105//
106// Pick the destination for the given migration signal. Foreground
107// classes refuse CLOUD (latency floor unacceptable); background
108// classes accept it. Returns NX_TROP_LOCAL_CPU when signal is STEADY
109// (no migration needed); returns the cell's declared `prefer` when
110// it is locally viable, otherwise next viable option.
111//
112// signal -- one of NX_HOMEO_* from nx_homeostasis
113// current -- the cell's current location (NX_TROP_*)
114// attention_class -- one of NX_AC_*
115// prefer -- cell's declared first-choice tropism
116
117func nx_tropism_resolve(signal: nx_int,
118 current: nx_int,
119 attention_class: nx_int,
120 prefer: nx_int) -> nx_int {
121 if signal == NX_HOMEO_STEADY { return current }
122 if nx_tropism_is_valid(prefer) == 0 { return NX_TROP_LOCAL_CPU }
123
124 // Foreground class refuses CLOUD outright (latency floor).
125 let fg: nx_int = nx_ac_is_foreground(attention_class)
126 if fg == 1 {
127 if prefer == NX_TROP_CLOUD { return NX_TROP_NAS }
128 }
129
130 // Migration signals route by resource pressure type.
131 if signal == NX_HOMEO_MIGRATE_VRAM {
132 // VRAM pressure: prefer the local GPU with most VRAM, then
133 // peer with GPU, then CPU fallback for foreground / CLOUD
134 // for background. Do not return current (would no-op).
135 if current != NX_TROP_LOCAL_GPU_MAX_VRAM { return NX_TROP_LOCAL_GPU_MAX_VRAM }
136 if fg == 1 { return NX_TROP_LOCAL_CPU }
137 return NX_TROP_PEER
138 }
139 if signal == NX_HOMEO_MIGRATE_RAM {
140 // RAM pressure: spill to NAS for background, prefer local CPU
141 // re-balance (zero-copy via shared arena) for foreground.
142 if fg == 1 { return NX_TROP_LOCAL_CPU }
143 return NX_TROP_NAS
144 }
145 if signal == NX_HOMEO_MIGRATE_DISK {
146 // Disk pressure: archive to NAS regardless of class.
147 return NX_TROP_NAS
148 }
149 if signal == NX_HOMEO_MIGRATE_THERMAL {
150 // Thermal pressure: offload compute. Foreground stays local
151 // GPU (less hot than CPU); background goes peer.
152 if fg == 1 { return NX_TROP_LOCAL_GPU }
153 return NX_TROP_PEER
154 }
155 if signal == NX_HOMEO_EVICTION_STORM {
156 // The cell is being displaced repeatedly -- relocate to a
157 // larger venue where headroom is more abundant.
158 if fg == 1 { return NX_TROP_LOCAL_GPU_MAX_VRAM }
159 return NX_TROP_PEER
160 }
161 if signal == NX_HOMEO_PROMOTE_TIER {
162 // Metabolism says this site is hot enough for higher tier.
163 if fg == 1 { return NX_TROP_LOCAL_GPU_MAX_VRAM }
164 return NX_TROP_CLOUD
165 }
166 if signal == NX_HOMEO_DEMOTE_TIER {
167 return NX_TROP_LOCAL_CPU
168 }
169 return current
170}
171
172// ===== nx_tropism_cost_q10 ======================================
173//
174// Coarse Q10 estimate of migration cost for the given target.
175// LOCAL_CPU = 0 (no migration); LOCAL_GPU = 64 (cache invalidate);
176// LOCAL_DISK = 256 (mmap reload); NAS = 512 (network copy);
177// PEER = 768 (network + handshake); CLOUD = 1024 (TLS + region hop).
178
179func nx_tropism_cost_q10(t: nx_int) -> nx_int {
180 if t == NX_TROP_LOCAL_CPU { return 0 }
181 if t == NX_TROP_LOCAL_GPU { return 64 }
182 if t == NX_TROP_LOCAL_GPU_MAX_VRAM { return 96 }
183 if t == NX_TROP_LOCAL_DISK { return 256 }
184 if t == NX_TROP_NAS { return 512 }
185 if t == NX_TROP_PEER { return 768 }
186 if t == NX_TROP_CLOUD { return NX_MAGIC_1024 }
187 return 0
188}