nx_hypha.nx source
↩ module page · 375 lines · 15732 B
1// nx_hypha.nx -- bidirectional peer share + receive (point-to-point
2// mycelium / wood-wide-web).
3//
4// Per META-CARDINAL feedback-forest-meta-vision-drift-lifecycle: every
5// EXCHANGE_* mode has a paired RECEIVE_* mode at the same peer. Pure
6// consumers are throttled per [[feedback-west-industrial-build-
7// replenish-not-buy-consume]]. A new node gets a "starter quota" of
8// EXCHANGE_* capability proportional to its niche -- no node arrives
9// with literally nothing to offer.
10//
11// Distinct from nx_fruiting (queued): nx_hypha is POINT-TO-POINT peer
12// share between two specific Nishi nodes. nx_fruiting is MANY-TO-MANY
13// content-addressed broadcast (mushroom spore release). Both compose
14// to give the complete underground-mycelium-plus-fruiting-body
15// distribution architecture.
16//
17// V1 ships sealed enum of exchange modes + reciprocity discipline
18// predicate + niche-aware capability gating + per-peer trust state.
19//
20// Composes:
21// nx_methyl -- peer-attestation Ed25519 chain (caller-supplied)
22// nx_niche -- niche gates which EXCHANGE_* modes a peer can offer
23// nx_attest_silicon -- silicon-trust gates sovereignty-critical exchanges
24// nx_immune -- runtime defense composes on suspicious-peer signal
25//
26// Gap list (V1 honest perf verdict):
27// - actual byte transport is caller-supplied (V2 wires nx_chromatin
28// content-addressed blocks + nx_http3 / libp2p-class re-derived
29// transport)
30// - reciprocity ratio thresholds are operator-tuneable per niche
31// (V2 makes data-driven)
32// - "starter quota" for new peer is the niche-default + first 100
33// interactions; V1 marks the quota; V2 enforces decay
34//
35// genealogy_id: nishi_metacardinal_2026-05-19_forest_drift_lifecycle
36// lineage_id: substrate_hypha_v1
37//
38// nx_safety_envelope:
39// intended_use: "Bidirectional point-to-point peer exchange
40// with reciprocity discipline + niche-aware
41// gating; refuses free-rider configuration"
42// sil_target: SIL2
43// evidence: [enum_sealed, reciprocity_required,
44// niche_gating_explicit, starter_quota_documented]
45// verdict: NOT_YET_EVALUATED
46
47import "nx_syscalls.nx"
48import "nx_tier.nx"
49
50// ===== Sealed enum: NxExchangeMode ================================
51//
52// Eight canonical exchange modes shipped V1. Each mode has both a
53// SHARE direction (this node giving) and RECEIVE direction (this node
54// taking). Reciprocity discipline enforced at the substrate level:
55// a peer that only RECEIVEs and never SHAREs is throttled.
56
57const NX_EM_COMPUTE: nx_int = 0 // VRAM / cores / NPU borrow
58const NX_EM_STORAGE: nx_int = 1 // content-addressed blocks
59const NX_EM_SIGNAL: nx_int = 2 // telemetry / alerts / niche-correction
60const NX_EM_CHROMATIN: nx_int = 3 // organelle updates + audit-labels
61const NX_EM_PATHWAY: nx_int = 4 // cooperative sub-graph execution
62const NX_EM_LABEL: nx_int = 5 // triangulated audit-consensus
63const NX_EM_KNOWLEDGE: nx_int = 6 // federated-averaged small-model weights
64const NX_EM_INGEST: nx_int = 7 // one-directional consume from foreign substrate
65const NX_EM_N_MODES: nx_int = 8
66
67// ===== Sealed enum: NxExchangeDirection ===========================
68
69const NX_EM_DIR_SHARE: nx_int = 0
70const NX_EM_DIR_RECEIVE: nx_int = 1
71const NX_EM_DIR_N_DIRS: nx_int = 2
72
73// ===== Sealed enum: NxHyphaVerdict ================================
74
75const NX_HY_OK: nx_int = 0
76const NX_HY_ERR_INVALID_MODE: nx_int = 1
77const NX_HY_ERR_INVALID_DIRECTION: nx_int = 2
78const NX_HY_ERR_RECIPROCITY_VIOLATION: nx_int = 3 // pure consumer; throttled
79const NX_HY_ERR_NICHE_INCAPABLE: nx_int = 4 // this niche can't offer this mode
80const NX_HY_ERR_TRUST_INSUFFICIENT: nx_int = 5 // silicon trust below requirement
81const NX_HY_ERR_NULL_INPUT: nx_int = 6
82const NX_HY_N_VERDICTS: nx_int = 7
83
84// ===== Struct: NxPeerExchangeState ================================
85//
86// Per-peer state tracking what THIS local node has SHAREd + RECEIVEd
87// from the remote peer over time. Reciprocity verdict computed from
88// share_count vs receive_count.
89
90struct NxPeerExchangeState {
91 peer_id: nx_int,
92 peer_niche: nx_int,
93 peer_silicon_trust: nx_int,
94 share_counts: *u8, // array[NX_EM_N_MODES] of i64
95 receive_counts: *u8, // array[NX_EM_N_MODES] of i64
96 last_exchange_us: nx_size,
97 starter_quota_remaining: nx_int, // per-niche starter; decrements on receive
98}
99
100const NX_HY_PEER_BYTES: nx_int = 56
101const NX_HY_PER_MODE_BYTES: nx_int = 8
102const NX_HY_STARTER_QUOTA_DEFAULT: nx_int = 100
103
104// ===== nx_em_mode_is_valid ========================================
105
106func nx_em_mode_is_valid(m: nx_int) -> nx_int {
107 if m < 0 { return 0 }
108 if m >= NX_EM_N_MODES { return 0 }
109 return 1
110}
111
112// ===== nx_em_dir_is_valid =========================================
113
114func nx_em_dir_is_valid(d: nx_int) -> nx_int {
115 if d < 0 { return 0 }
116 if d >= NX_EM_DIR_N_DIRS { return 0 }
117 return 1
118}
119
120// ===== nx_hy_verdict_is_valid =====================================
121
122func nx_hy_verdict_is_valid(v: nx_int) -> nx_int {
123 if v < 0 { return 0 }
124 if v >= NX_HY_N_VERDICTS { return 0 }
125 return 1
126}
127
128// ===== nx_em_niche_can_offer ======================================
129//
130// Predicate: does this niche typically have the capacity to OFFER
131// the given exchange mode? E.g. a phone can offer SIGNAL + LABEL +
132// KNOWLEDGE but can't realistically offer COMPUTE (no spare cycles)
133// or STORAGE (limited capacity). A NAS can offer STORAGE + CHROMATIN
134// + SIGNAL but limited COMPUTE.
135//
136// niche values match NX_NICHE_* from nx_niche.nx by-value.
137
138func nx_em_niche_can_offer(niche: nx_int, mode: nx_int) -> nx_int {
139 if nx_em_mode_is_valid(mode) == 0 { return 0 }
140 // GAMING_WORKSTATION (0) / DEV_WORKSTATION (1) -- can offer all
141 if niche == 0 { return 1 }
142 if niche == 1 { return 1 }
143 // LAPTOP (2) -- can offer most; limited COMPUTE under battery
144 if niche == 2 {
145 if mode == NX_EM_PATHWAY { return 0 } // pathway needs sustained compute
146 return 1
147 }
148 // HOME_NAS (3) -- excellent STORAGE + CHROMATIN; limited COMPUTE
149 if niche == 3 {
150 if mode == NX_EM_COMPUTE { return 0 }
151 if mode == NX_EM_PATHWAY { return 0 }
152 return 1
153 }
154 // SMARTPHONE (5) -- SIGNAL / LABEL / KNOWLEDGE / INGEST only
155 if niche == 5 {
156 if mode == NX_EM_SIGNAL { return 1 }
157 if mode == NX_EM_LABEL { return 1 }
158 if mode == NX_EM_KNOWLEDGE { return 1 }
159 if mode == NX_EM_INGEST { return 1 }
160 return 0
161 }
162 // EMBEDDED_SENSOR (40) / FARM_SOIL_MONITOR (41) -- SIGNAL only
163 if niche == 40 { if mode == NX_EM_SIGNAL { return 1 } else { return 0 } }
164 if niche == 41 { if mode == NX_EM_SIGNAL { return 1 } else { return 0 } }
165 // HOME_IOT_HUB (42) -- SIGNAL + LABEL
166 if niche == 42 {
167 if mode == NX_EM_SIGNAL { return 1 }
168 if mode == NX_EM_LABEL { return 1 }
169 return 0
170 }
171 // INDUSTRIAL_* (10-13) / MEDICAL (20-21) / AUTOMOTIVE (30) --
172 // SIGNAL + restricted others
173 if niche >= 10 {
174 if niche <= 13 {
175 if mode == NX_EM_SIGNAL { return 1 }
176 if mode == NX_EM_LABEL { return 1 }
177 return 0
178 }
179 }
180 if niche == 20 { if mode == NX_EM_SIGNAL { return 1 } else { return 0 } }
181 if niche == 21 { if mode == NX_EM_SIGNAL { return 1 } else { return 0 } }
182 if niche == 30 { if mode == NX_EM_SIGNAL { return 1 } else { return 0 } }
183 // Refused niches (50-53) -- none
184 if niche >= 50 {
185 if niche <= 53 { return 0 }
186 }
187 return 0 // unknown niche -- conservative
188}
189
190// ===== nx_hy_peer_state_new =======================================
191
192func nx_hy_peer_state_new(peer_id: nx_int,
193 peer_niche: nx_int,
194 peer_silicon_trust: nx_int) -> *NxPeerExchangeState {
195 let raw: *u8 = sys_mmap(NX_HY_PEER_BYTES)
196 let p: *NxPeerExchangeState = raw as *NxPeerExchangeState
197 p.peer_id = peer_id
198 p.peer_niche = peer_niche
199 p.peer_silicon_trust = peer_silicon_trust
200 p.share_counts = sys_mmap(NX_EM_N_MODES * NX_HY_PER_MODE_BYTES)
201 p.receive_counts = sys_mmap(NX_EM_N_MODES * NX_HY_PER_MODE_BYTES)
202 var i: nx_int = 0
203 while i < NX_EM_N_MODES {
204 let off: nx_int = i * NX_HY_PER_MODE_BYTES
205 let s: *i64 = (p.share_counts + off) as *i64
206 let r: *i64 = (p.receive_counts + off) as *i64
207 s[0] = 0
208 r[0] = 0
209 i = i + 1
210 }
211 p.last_exchange_us = 0
212 p.starter_quota_remaining = NX_HY_STARTER_QUOTA_DEFAULT
213 return p
214}
215
216// ===== nx_hy_record_exchange ======================================
217//
218// Record an exchange event with this peer. direction = SHARE means
219// local node gave; RECEIVE means local node took. Updates counts +
220// starter quota. Reciprocity verdict computed in separate predicate.
221
222func nx_hy_record_exchange(p: *NxPeerExchangeState,
223 mode: nx_int,
224 direction: nx_int,
225 now_us: nx_size) -> nx_int {
226 if (p as i64) == 0 { return NX_HY_ERR_NULL_INPUT }
227 if nx_em_mode_is_valid(mode) == 0 { return NX_HY_ERR_INVALID_MODE }
228 if nx_em_dir_is_valid(direction) == 0 { return NX_HY_ERR_INVALID_DIRECTION }
229 let off: nx_int = mode * NX_HY_PER_MODE_BYTES
230 if direction == NX_EM_DIR_SHARE {
231 let s: *i64 = (p.share_counts + off) as *i64
232 s[0] = s[0] + 1
233 } else {
234 let r: *i64 = (p.receive_counts + off) as *i64
235 r[0] = r[0] + 1
236 // Decrement starter quota when receiving
237 if p.starter_quota_remaining > 0 {
238 p.starter_quota_remaining = p.starter_quota_remaining - 1
239 }
240 }
241 p.last_exchange_us = now_us
242 return NX_HY_OK
243}
244
245// ===== nx_hy_share_count ==========================================
246
247func nx_hy_share_count(p: *NxPeerExchangeState, mode: nx_int) -> nx_int {
248 if (p as i64) == 0 { return 0 }
249 if nx_em_mode_is_valid(mode) == 0 { return 0 }
250 let off: nx_int = mode * NX_HY_PER_MODE_BYTES
251 let s: *i64 = (p.share_counts + off) as *i64
252 return s[0] as nx_int
253}
254
255// ===== nx_hy_receive_count ========================================
256
257func nx_hy_receive_count(p: *NxPeerExchangeState, mode: nx_int) -> nx_int {
258 if (p as i64) == 0 { return 0 }
259 if nx_em_mode_is_valid(mode) == 0 { return 0 }
260 let off: nx_int = mode * NX_HY_PER_MODE_BYTES
261 let r: *i64 = (p.receive_counts + off) as *i64
262 return r[0] as nx_int
263}
264
265// ===== nx_hy_total_shared =========================================
266
267func nx_hy_total_shared(p: *NxPeerExchangeState) -> nx_int {
268 if (p as i64) == 0 { return 0 }
269 var sum: nx_int = 0
270 var i: nx_int = 0
271 while i < NX_EM_N_MODES {
272 sum = sum + nx_hy_share_count(p, i)
273 i = i + 1
274 }
275 return sum
276}
277
278// ===== nx_hy_total_received =======================================
279
280func nx_hy_total_received(p: *NxPeerExchangeState) -> nx_int {
281 if (p as i64) == 0 { return 0 }
282 var sum: nx_int = 0
283 var i: nx_int = 0
284 while i < NX_EM_N_MODES {
285 sum = sum + nx_hy_receive_count(p, i)
286 i = i + 1
287 }
288 return sum
289}
290
291// ===== nx_hy_reciprocity_verdict ==================================
292//
293// Returns OK if peer's exchange profile meets reciprocity discipline:
294// - starter_quota_remaining > 0 -> OK (new peer; grace period)
295// - share/(share+receive) >= 0.3 -> OK (at least 30% share ratio)
296// - else -> RECIPROCITY_VIOLATION (throttle)
297//
298// Per [[feedback-west-industrial-build-replenish-not-buy-consume]] --
299// pure consumers are throttled.
300
301func nx_hy_reciprocity_verdict(p: *NxPeerExchangeState) -> nx_int {
302 if (p as i64) == 0 { return NX_HY_ERR_NULL_INPUT }
303 if p.starter_quota_remaining > 0 { return NX_HY_OK }
304 let shared: nx_int = nx_hy_total_shared(p)
305 let received: nx_int = nx_hy_total_received(p)
306 let total: nx_int = shared + received
307 if total == 0 { return NX_HY_OK } // no exchanges yet
308 // 30% threshold: shared * 10 >= total * 3
309 if (shared * 10) >= (total * 3) { return NX_HY_OK }
310 return NX_HY_ERR_RECIPROCITY_VIOLATION
311}
312
313// ===== nx_hy_reciprocity_verdict_units ============================
314//
315// DEFECT FOUND 2026-08-06: nx_hy_reciprocity_verdict above counts EVENTS, not MAGNITUDES. Share one
316// byte, receive one terabyte, and the counts are 1:1 -> 50% -> comfortably past the 30% floor -> OK.
317// Anyone who can make their giving granular and their taking bulky walks straight through it, and
318// that is precisely the skimmer's move: many tiny rendered services, few enormous extractions.
319//
320// A COUNT IS NOT A QUANTITY. A reciprocity floor denominated in events measures politeness,
321// not reciprocity.
322//
323// ADDITIVE by law 19: the count-based verdict keeps its exact contract for every existing caller and
324// is NOT touched. New callers take this one. nx_commons_units_gate holds BOTH and asserts they
325// DISAGREE on a magnitude-skewed peer, so the discrimination this term buys stays visible and cannot
326// quietly regress to the blind form.
327//
328// Overflow-safe BY CONSTRUCTION: the 30% floor divides the total DOWN and never multiplies the
329// shared side UP. Multiplying up is exactly the nx_mycorrhiza defect fixed in the same session --
330// the same lesson learned twice in two organs is a lesson the codebase never learned, so it is
331// written into the arithmetic here rather than into a comment.
332func nx_hy_reciprocity_verdict_units(p: *NxPeerExchangeState,
333 shared_units: nx_int,
334 received_units: nx_int) -> nx_int {
335 if (p as i64) == 0 { return NX_HY_ERR_NULL_INPUT }
336 if p.starter_quota_remaining > 0 { return NX_HY_OK }
337 var s: nx_int = shared_units
338 if s < 0 { s = 0 }
339 var r: nx_int = received_units
340 if r < 0 { r = 0 }
341 let total: nx_int = s + r
342 if total == 0 { return NX_HY_OK }
343 let floor_units: nx_int = (total / 10) * 3 + ((total % 10) * 3) / 10
344 if s >= floor_units { return NX_HY_OK }
345 return NX_HY_ERR_RECIPROCITY_VIOLATION
346}
347
348// ===== nx_hy_can_initiate_share ===================================
349//
350// Predicate: should this local node initiate a SHARE of `mode` to peer?
351// Composes:
352// - peer must be capable of offering reciprocal mode (niche check)
353// - peer reciprocity verdict OK
354// - peer trust level acceptable for mode
355
356func nx_hy_can_initiate_share(p: *NxPeerExchangeState,
357 mode: nx_int) -> nx_int {
358 if (p as i64) == 0 { return NX_HY_ERR_NULL_INPUT }
359 if nx_em_mode_is_valid(mode) == 0 { return NX_HY_ERR_INVALID_MODE }
360 let v: nx_int = nx_hy_reciprocity_verdict(p)
361 if v != NX_HY_OK { return v }
362 // Caller-supplied silicon-trust gate: sovereignty-critical modes
363 // (KNOWLEDGE, PATHWAY) require higher trust than opportunistic
364 // (SIGNAL, LABEL, INGEST). We encode a simple threshold: any
365 // commodity-class trust (>=4 per nx_attest_silicon NxSiliconTrustLevel)
366 // accepts opportunistic; sovereignty-critical requires <=3 (SBC_RPI
367 // or better).
368 if mode == NX_EM_KNOWLEDGE {
369 if p.peer_silicon_trust > 3 { return NX_HY_ERR_TRUST_INSUFFICIENT }
370 }
371 if mode == NX_EM_PATHWAY {
372 if p.peer_silicon_trust > 4 { return NX_HY_ERR_TRUST_INSUFFICIENT }
373 }
374 return NX_HY_OK
375}