nx_fruiting.nx source
↩ module page · 334 lines · 13121 B
1// nx_fruiting.nx -- content-addressed many-to-many broadcast (mushroom
2// fruiting body releasing spores).
3//
4// Per user 2026-05-19: *"not just peer but we should also have torrent
5// aka the fruiting or whatever"* -- the underground mycelium (nx_hypha)
6// is point-to-point peer share; the ABOVE-GROUND fruiting body is the
7// many-to-many broadcast layer. Mushrooms release spores that disperse
8// via wind / water / animal / ballistospory; spores find new substrate
9// and germinate. Substrate equivalent: content-addressed fragment
10// dispersal where any peer holding fragment-N can serve it to any
11// receiver requesting fragment-N (BitTorrent-class but biology-named).
12//
13// Per [[feedback-naming-discipline-no-industry-competitor-overlap]]:
14// "torrent" is a tech-product name we avoid. "Fruiting" is biology-
15// precise + unowned in tech-product space.
16//
17// V1 ships sealed enum of dispersal modes + content-addressed fragment-
18// hash chain + per-fragment provenance + per-fruiting-body dispersal
19// budget (refuses amplification attacks).
20//
21// Distinct from nx_hypha: hypha is RECIPROCITY-REQUIRED point-to-point
22// peer exchange; fruiting is one-to-many broadcast where receivers do
23// NOT need to share back (they may, but it's not required for
24// reception). Together they're the complete fungal-network
25// distribution architecture.
26//
27// Composes:
28// nx_methyl -- each fragment carries Ed25519-signed methyl
29// marker; receiver verifies before germinating
30// nx_chromatin -- content-addressed block storage; fragments are
31// chromatin block hashes
32// nx_provenance_chain -- dispersal event chain-logged
33// nx_hypha -- peers can re-share fruiting fragments via hypha
34// point-to-point if desired (composes)
35//
36// V1 ships state-machine + classification primitives. Actual byte-
37// transport for fragment delivery is caller-supplied (V2 wires
38// content-addressed BLAKE3 fragment chain + chromatin block fetch).
39//
40// Gap list (V1 honest perf verdict):
41// - per-fragment hash chain is operator-supplied (V2 inlines
42// BLAKE3-Merkle-tree construction)
43// - dispersal-budget thresholds research-derived (V2 makes per-niche
44// policy)
45// - rare-fragment-priority (BitTorrent rarest-first) is a future
46// optimization
47//
48// genealogy_id: nishi_metacardinal_2026-05-19_forest_drift_lifecycle
49// lineage_id: substrate_fruiting_v1
50//
51// nx_safety_envelope:
52// intended_use: "Many-to-many content-addressed broadcast for
53// substrate dispersal; biology-named torrent
54// with per-fragment provenance + amplification-
55// budget gate"
56// sil_target: SIL2
57// evidence: [enum_sealed, content_addressed,
58// per_fragment_provenance, amplification_budgeted]
59// verdict: NOT_YET_EVALUATED
60
61import "nx_syscalls.nx"
62import "nx_tier.nx"
63
64// ===== Sealed enum: NxDispersalMode ===============================
65//
66// Biological spore-dispersal mechanisms mapped to substrate transport:
67// ANEMOPHILY = wind dispersal (broadcast UDP-class; any-to-any)
68// HYDROPHILY = water dispersal (sequential downstream; mesh-flow)
69// ZOOCHORY = animal dispersal (carried by a peer; targeted
70// delivery to specific endpoint)
71// BALLISTOSPORY = active shooting (push delivery; sender initiates)
72// AUTOCHORY = self-dispersal (sender stores locally + signals
73// availability; pull delivery)
74
75const NX_FR_ANEMOPHILY: nx_int = 0 // wind: broadcast many-to-many
76const NX_FR_HYDROPHILY: nx_int = 1 // water: sequential flow
77const NX_FR_ZOOCHORY: nx_int = 2 // animal: carry-and-deliver
78const NX_FR_BALLISTOSPORY: nx_int = 3 // active push
79const NX_FR_AUTOCHORY: nx_int = 4 // local store + pull-available
80const NX_FR_N_MODES: nx_int = 5
81
82// ===== Sealed enum: NxFruitingBodyState ===========================
83
84const NX_FB_DEVELOPING: nx_int = 0 // gathering fragments
85const NX_FB_READY_TO_DISPERSE: nx_int = 1 // complete + verified
86const NX_FB_DISPERSING: nx_int = 2 // actively serving fragments
87const NX_FB_QUIESCENT: nx_int = 3 // dispersal-budget exhausted
88const NX_FB_FAILED: nx_int = 4 // refused/invalid
89const NX_FB_N_STATES: nx_int = 5
90
91// ===== Sealed enum: NxFruitingVerdict =============================
92
93const NX_FR_OK: nx_int = 0
94const NX_FR_ERR_INVALID_MODE: nx_int = 1
95const NX_FR_ERR_INVALID_STATE: nx_int = 2
96const NX_FR_ERR_BUDGET_EXHAUSTED: nx_int = 3
97const NX_FR_ERR_FRAGMENT_OUT_OF_RANGE: nx_int = 4
98const NX_FR_ERR_NULL_INPUT: nx_int = 5
99const NX_FR_ERR_INVALID_TRANSITION: nx_int = 6
100const NX_FR_N_VERDICTS: nx_int = 7
101
102// ===== Struct: NxFruitingBody =====================================
103//
104// One content-addressed broadcast artifact (e.g., a Nishi-stack
105// release, a published audit-attestation, a peer-mesh-distributable
106// dataset). total_fragments = number of BLAKE3 content-addressed
107// blocks composing the artifact. served_count = fragments served
108// so far (for amplification-budget accounting).
109
110struct NxFruitingBody {
111 body_id: nx_int,
112 dispersal_mode: nx_int,
113 state: nx_int,
114 total_fragments: nx_int,
115 fragments_complete: nx_int, // for DEVELOPING state; reaches total
116 served_count: nx_int, // dispersal accounting
117 dispersal_budget: nx_int, // max fragments to serve before QUIESCENT
118 root_methyl_id: nx_int, // composes nx_methyl
119 created_at_us: nx_size,
120 last_served_us: nx_size,
121}
122
123const NX_FB_BYTES: nx_int = 80
124const NX_FB_DEFAULT_BUDGET_MULTIPLIER: nx_int = 100
125
126// ===== nx_fr_mode_is_valid ========================================
127
128func nx_fr_mode_is_valid(m: nx_int) -> nx_int {
129 if m < 0 { return 0 }
130 if m >= NX_FR_N_MODES { return 0 }
131 return 1
132}
133
134// ===== nx_fb_state_is_valid =======================================
135
136func nx_fb_state_is_valid(s: nx_int) -> nx_int {
137 if s < 0 { return 0 }
138 if s >= NX_FB_N_STATES { return 0 }
139 return 1
140}
141
142// ===== nx_fr_verdict_is_valid =====================================
143
144func nx_fr_verdict_is_valid(v: nx_int) -> nx_int {
145 if v < 0 { return 0 }
146 if v >= NX_FR_N_VERDICTS { return 0 }
147 return 1
148}
149
150// ===== nx_fr_mode_is_broadcast ====================================
151//
152// Predicate: returns 1 for true broadcast modes (ANEMOPHILY = wind /
153// HYDROPHILY = water-flow downstream). ZOOCHORY (single carrier),
154// BALLISTOSPORY (active push to one target), AUTOCHORY (local store)
155// are targeted/sequential.
156
157func nx_fr_mode_is_broadcast(m: nx_int) -> nx_int {
158 if m == NX_FR_ANEMOPHILY { return 1 }
159 if m == NX_FR_HYDROPHILY { return 1 }
160 return 0
161}
162
163// ===== nx_fr_mode_requires_active_sender ==========================
164//
165// Predicate: BALLISTOSPORY requires the sender to actively push to
166// a designated recipient (vs. waiting to be pulled).
167
168func nx_fr_mode_requires_active_sender(m: nx_int) -> nx_int {
169 if m == NX_FR_BALLISTOSPORY { return 1 }
170 return 0
171}
172
173// ===== nx_fb_state_is_serving =====================================
174
175func nx_fb_state_is_serving(s: nx_int) -> nx_int {
176 if s == NX_FB_DISPERSING { return 1 }
177 return 0
178}
179
180// ===== nx_fb_state_is_terminal ====================================
181
182func nx_fb_state_is_terminal(s: nx_int) -> nx_int {
183 if s == NX_FB_QUIESCENT { return 1 }
184 if s == NX_FB_FAILED { return 1 }
185 return 0
186}
187
188// ===== _fb_transition_allowed =====================================
189//
190// DEVELOPING -> READY_TO_DISPERSE -> DISPERSING -> QUIESCENT
191// Any non-terminal state can transition to FAILED.
192
193func _fb_transition_allowed(from: nx_int, to: nx_int) -> nx_int {
194 if to == NX_FB_FAILED {
195 if nx_fb_state_is_terminal(from) == 1 { return 0 }
196 if nx_fb_state_is_valid(from) == 1 { return 1 }
197 return 0
198 }
199 if from == NX_FB_DEVELOPING {
200 if to == NX_FB_READY_TO_DISPERSE { return 1 }
201 return 0
202 }
203 if from == NX_FB_READY_TO_DISPERSE {
204 if to == NX_FB_DISPERSING { return 1 }
205 return 0
206 }
207 if from == NX_FB_DISPERSING {
208 if to == NX_FB_QUIESCENT { return 1 }
209 return 0
210 }
211 return 0
212}
213
214// ===== nx_fb_new ==================================================
215
216func nx_fb_new(body_id: nx_int,
217 dispersal_mode: nx_int,
218 total_fragments: nx_int,
219 root_methyl_id: nx_int,
220 created_at_us: nx_size) -> *NxFruitingBody {
221 if total_fragments <= 0 { return 0 as *NxFruitingBody }
222 let raw: *u8 = sys_mmap(NX_FB_BYTES)
223 let b: *NxFruitingBody = raw as *NxFruitingBody
224 b.body_id = body_id
225 b.dispersal_mode = dispersal_mode
226 b.state = NX_FB_DEVELOPING
227 b.total_fragments = total_fragments
228 b.fragments_complete = 0
229 b.served_count = 0
230 // Default budget: serve each fragment up to 100 times before quiesce
231 b.dispersal_budget = total_fragments * NX_FB_DEFAULT_BUDGET_MULTIPLIER
232 b.root_methyl_id = root_methyl_id
233 b.created_at_us = created_at_us
234 b.last_served_us = 0
235 return b
236}
237
238// ===== nx_fb_record_fragment_complete =============================
239//
240// Caller signals that fragment N has been verified + added to the
241// body. When fragments_complete == total_fragments, state advances
242// to READY_TO_DISPERSE (caller must explicitly transition).
243
244func nx_fb_record_fragment_complete(b: *NxFruitingBody) -> nx_int {
245 if (b as i64) == 0 { return NX_FR_ERR_NULL_INPUT }
246 if b.state != NX_FB_DEVELOPING { return NX_FR_ERR_INVALID_STATE }
247 if b.fragments_complete >= b.total_fragments {
248 return NX_FR_ERR_FRAGMENT_OUT_OF_RANGE
249 }
250 b.fragments_complete = b.fragments_complete + 1
251 return NX_FR_OK
252}
253
254// ===== nx_fb_is_complete ==========================================
255
256func nx_fb_is_complete(b: *NxFruitingBody) -> nx_int {
257 if (b as i64) == 0 { return 0 }
258 if b.fragments_complete >= b.total_fragments { return 1 }
259 return 0
260}
261
262// ===== nx_fb_transition ===========================================
263
264func nx_fb_transition(b: *NxFruitingBody, to: nx_int) -> nx_int {
265 if (b as i64) == 0 { return NX_FR_ERR_NULL_INPUT }
266 if nx_fb_state_is_valid(to) == 0 { return NX_FR_ERR_INVALID_TRANSITION }
267 if _fb_transition_allowed(b.state, to) == 0 {
268 return NX_FR_ERR_INVALID_TRANSITION
269 }
270 if to == NX_FB_READY_TO_DISPERSE {
271 if b.fragments_complete < b.total_fragments {
272 return NX_FR_ERR_FRAGMENT_OUT_OF_RANGE
273 }
274 }
275 b.state = to
276 return NX_FR_OK
277}
278
279// ===== nx_fb_serve_fragment =======================================
280//
281// Caller records that fragment was served to a requesting peer.
282// Increments served_count + checks against dispersal_budget. When
283// budget exhausted, state auto-transitions to QUIESCENT (refuses
284// amplification attacks).
285//
286// fragment_index is for caller's accounting + provenance (not
287// validated here; substrate trusts caller's BLAKE3 verification).
288
289func nx_fb_serve_fragment(b: *NxFruitingBody,
290 fragment_index: nx_int,
291 now_us: nx_size) -> nx_int {
292 if (b as i64) == 0 { return NX_FR_ERR_NULL_INPUT }
293 if b.state != NX_FB_DISPERSING { return NX_FR_ERR_INVALID_STATE }
294 if fragment_index < 0 { return NX_FR_ERR_FRAGMENT_OUT_OF_RANGE }
295 if fragment_index >= b.total_fragments {
296 return NX_FR_ERR_FRAGMENT_OUT_OF_RANGE
297 }
298 if b.served_count >= b.dispersal_budget {
299 // Auto-quiesce on budget exhaustion
300 b.state = NX_FB_QUIESCENT
301 return NX_FR_ERR_BUDGET_EXHAUSTED
302 }
303 b.served_count = b.served_count + 1
304 b.last_served_us = now_us
305 if b.served_count >= b.dispersal_budget {
306 b.state = NX_FB_QUIESCENT
307 }
308 return NX_FR_OK
309}
310
311// ===== nx_fb_remaining_budget =====================================
312
313func nx_fb_remaining_budget(b: *NxFruitingBody) -> nx_int {
314 if (b as i64) == 0 { return 0 }
315 let r: nx_int = b.dispersal_budget - b.served_count
316 if r < 0 { return 0 }
317 return r
318}
319
320// ===== nx_fb_set_dispersal_budget =================================
321//
322// Operator override of default budget (e.g., for known-high-demand
323// release, raise the budget; for sensitive release, lower it).
324// Cannot be raised once DISPERSING (additive-only-style discipline).
325
326func nx_fb_set_dispersal_budget(b: *NxFruitingBody,
327 new_budget: nx_int) -> nx_int {
328 if (b as i64) == 0 { return NX_FR_ERR_NULL_INPUT }
329 if new_budget < 0 { return NX_FR_ERR_INVALID_STATE }
330 if b.state == NX_FB_DISPERSING { return NX_FR_ERR_INVALID_STATE }
331 if b.state == NX_FB_QUIESCENT { return NX_FR_ERR_INVALID_STATE }
332 b.dispersal_budget = new_budget
333 return NX_FR_OK
334}