nx_seed_bank.nx source
↩ module page · 256 lines · 9349 B
1// nx_seed_bank.nx -- multi-genotype cold-storage backup substrate.
2//
3// Biology: a seed bank (Svalbard Global Seed Vault, Millennium Seed Bank,
4// indigenous community seed banks) preserves GENETIC DIVERSITY in dormant
5// form across decades-to-centuries. Each accession is content-addressed,
6// labeled with provenance, and can be retrieved + germinated when needed
7// to restore a lost cultivar / population. Diversity is the load-bearing
8// property: a monoculture seed bank is a single point of failure.
9//
10// In Nishi: persistent cold storage of substrate genotype snapshots
11// (config + schema + seed primitives) so a damaged installation can be
12// restored to known-green from a chosen accession. Composes with
13// [[nx_seed]] (the seed primitive is what gets stored), [[nx_prune]] +
14// [[nx_regenerate]] (prune-rebuild reads from seed bank), [[feedback-
15// thymus-sovereignty-audit-soma-germline]] (only germline accessions
16// preserved; soma is regenerable from germline), [[feedback-end-to-end-
17// bit-traceability-architecture]] (every accession is content-addressed +
18// provenance-stamped).
19//
20// V1 ships sealed accession-kind enum + provenance-stamped record +
21// retrieval + diversity audit (HHI-style monoculture detector).
22
23import "nx_syscalls.nx"
24import "nx_tier.nx"
25const NX_MAGIC_1024: i64 = 1024
26
27// ===== Sealed enum: NxAccessionKind ===============================
28
29const NX_SB_KIND_FULL_GENOTYPE: nx_int = 0 // complete germline snapshot
30const NX_SB_KIND_CONFIG_ONLY: nx_int = 1 // operator preferences
31const NX_SB_KIND_SCHEMA_ONLY: nx_int = 2 // data layout
32const NX_SB_KIND_KEY_MATERIAL: nx_int = 3 // sovereign keys (encrypted)
33const NX_SB_KIND_FAMILY_CORPUS: nx_int = 4 // family-generated content
34const NX_SB_KIND_TEK_ARCHIVE: nx_int = 5 // traditional knowledge
35const NX_SB_KIND_HEIRLOOM_CULTIVAR: nx_int = 6 // cultural/family heritage data
36const NX_SB_KIND_N: nx_int = 7
37
38// ===== Sealed enum: NxAccessionStatus =============================
39
40const NX_SB_STATUS_DORMANT: nx_int = 0
41const NX_SB_STATUS_VERIFIED: nx_int = 1 // hash + signature checked
42const NX_SB_STATUS_RETRIEVED: nx_int = 2
43const NX_SB_STATUS_CORRUPTED: nx_int = 3 // hash mismatch on verify
44const NX_SB_STATUS_N: nx_int = 4
45
46// ===== Sealed enum: NxSeedBankVerdict =============================
47
48const NX_SB_V_OK: nx_int = 0
49const NX_SB_V_OK_HEALTHY_DIVERSITY: nx_int = 1
50const NX_SB_V_MONOCULTURE_WARNING: nx_int = 2 // HHI too concentrated
51const NX_SB_V_CORRUPTION_DETECTED: nx_int = 3
52const NX_SB_V_INVALID: nx_int = 4
53const NX_SB_V_NULL: nx_int = 5
54const NX_SB_V_N: nx_int = 6
55
56// ===== Struct: NxAccession ========================================
57
58struct NxAccession {
59 accession_id: nx_int,
60 kind: nx_int,
61 content_hash: nx_size,
62 provenance_hash: nx_size, // signer chain
63 stored_at_us: nx_size,
64 last_verified_us: nx_size,
65 bytes_stored: nx_size,
66 status: nx_int,
67}
68
69const NX_SB_A_BYTES: nx_int = 64
70
71struct NxSeedBank {
72 accessions: *u8,
73 n_accessions: nx_int,
74 capacity: nx_int,
75 next_accession_id: nx_int,
76 monoculture_threshold_q10: nx_int, // HHI Q10 threshold for warning
77 formed_at_us: nx_size,
78}
79
80const NX_SB_BYTES: nx_int = 48
81
82// ===== Validators =================================================
83
84func nx_sb_kind_is_valid(k: nx_int) -> nx_int {
85 if k < 0 { return 0 }
86 if k >= NX_SB_KIND_N { return 0 }
87 return 1
88}
89
90func nx_sb_status_is_valid(s: nx_int) -> nx_int {
91 if s < 0 { return 0 }
92 if s >= NX_SB_STATUS_N { return 0 }
93 return 1
94}
95
96func nx_sb_v_is_valid(v: nx_int) -> nx_int {
97 if v < 0 { return 0 }
98 if v >= NX_SB_V_N { return 0 }
99 return 1
100}
101
102// ===== Constructor ================================================
103
104func nx_sb_new(capacity: nx_int,
105 monoculture_threshold_q10: nx_int,
106 now_us: nx_size) -> *NxSeedBank {
107 if capacity <= 0 { return 0 as *NxSeedBank }
108 if monoculture_threshold_q10 <= 0 { return 0 as *NxSeedBank }
109 if monoculture_threshold_q10 > NX_MAGIC_1024 { return 0 as *NxSeedBank }
110 let raw: *u8 = sys_mmap(NX_SB_BYTES)
111 let b: *NxSeedBank = raw as *NxSeedBank
112 b.accessions = sys_mmap(capacity * NX_SB_A_BYTES)
113 b.n_accessions = 0
114 b.capacity = capacity
115 b.next_accession_id = 1
116 b.monoculture_threshold_q10 = monoculture_threshold_q10
117 b.formed_at_us = now_us
118 return b
119}
120
121func _sb_acc_at(b: *NxSeedBank, idx: nx_int) -> *NxAccession {
122 if idx < 0 { return 0 as *NxAccession }
123 if idx >= b.n_accessions { return 0 as *NxAccession }
124 let off: nx_int = idx * NX_SB_A_BYTES
125 return (b.accessions + off) as *NxAccession
126}
127
128// ===== Store accession ============================================
129
130func nx_sb_store(b: *NxSeedBank,
131 kind: nx_int,
132 content_hash: nx_size,
133 provenance_hash: nx_size,
134 bytes_stored: nx_size,
135 now_us: nx_size) -> nx_int {
136 if (b as i64) == 0 { return 0 }
137 if nx_sb_kind_is_valid(kind) == 0 { return 0 }
138 if b.n_accessions >= b.capacity { return 0 }
139 if content_hash == 0 { return 0 }
140 let off: nx_int = b.n_accessions * NX_SB_A_BYTES
141 let a: *NxAccession = (b.accessions + off) as *NxAccession
142 a.accession_id = b.next_accession_id
143 a.kind = kind
144 a.content_hash = content_hash
145 a.provenance_hash = provenance_hash
146 a.stored_at_us = now_us
147 a.last_verified_us = now_us
148 a.bytes_stored = bytes_stored
149 a.status = NX_SB_STATUS_VERIFIED
150 b.n_accessions = b.n_accessions + 1
151 b.next_accession_id = b.next_accession_id + 1
152 return a.accession_id
153}
154
155func nx_sb_find(b: *NxSeedBank, accession_id: nx_int) -> *NxAccession {
156 if (b as i64) == 0 { return 0 as *NxAccession }
157 var i: nx_int = 0
158 while i < b.n_accessions {
159 let a: *NxAccession = _sb_acc_at(b, i)
160 if a.accession_id == accession_id { return a }
161 i = i + 1
162 }
163 return 0 as *NxAccession
164}
165
166// ===== Verify integrity ===========================================
167
168func nx_sb_verify(b: *NxSeedBank,
169 accession_id: nx_int,
170 observed_hash: nx_size,
171 now_us: nx_size) -> nx_int {
172 if (b as i64) == 0 { return NX_SB_V_NULL }
173 let a: *NxAccession = nx_sb_find(b, accession_id)
174 if (a as i64) == 0 { return NX_SB_V_INVALID }
175 if a.content_hash != observed_hash {
176 a.status = NX_SB_STATUS_CORRUPTED
177 return NX_SB_V_CORRUPTION_DETECTED
178 }
179 a.status = NX_SB_STATUS_VERIFIED
180 a.last_verified_us = now_us
181 return NX_SB_V_OK
182}
183
184// ===== Retrieve ===================================================
185
186func nx_sb_retrieve(b: *NxSeedBank,
187 accession_id: nx_int,
188 now_us: nx_size) -> nx_size {
189 if (b as i64) == 0 { return 0 }
190 let a: *NxAccession = nx_sb_find(b, accession_id)
191 if (a as i64) == 0 { return 0 }
192 if a.status == NX_SB_STATUS_CORRUPTED { return 0 }
193 a.status = NX_SB_STATUS_RETRIEVED
194 return a.content_hash
195}
196
197// ===== Aggregations + diversity audit =============================
198
199func nx_sb_count_by_kind(b: *NxSeedBank, kind: nx_int) -> nx_int {
200 if (b as i64) == 0 { return 0 }
201 var count: nx_int = 0
202 var i: nx_int = 0
203 while i < b.n_accessions {
204 let a: *NxAccession = _sb_acc_at(b, i)
205 if a.kind == kind { count = count + 1 }
206 i = i + 1
207 }
208 return count
209}
210
211func nx_sb_count_by_status(b: *NxSeedBank, status: nx_int) -> nx_int {
212 if (b as i64) == 0 { return 0 }
213 var count: nx_int = 0
214 var i: nx_int = 0
215 while i < b.n_accessions {
216 let a: *NxAccession = _sb_acc_at(b, i)
217 if a.status == status { count = count + 1 }
218 i = i + 1
219 }
220 return count
221}
222
223// HHI-style concentration: returns Q10 of dominant kind's share. When
224// share >= monoculture_threshold_q10, the bank is too concentrated --
225// diversity warning fires per the seed-bank discipline that a bank with
226// only one cultivar is a single point of failure.
227func nx_sb_audit_diversity(b: *NxSeedBank) -> nx_int {
228 if (b as i64) == 0 { return NX_SB_V_NULL }
229 if b.n_accessions == 0 { return NX_SB_V_OK_HEALTHY_DIVERSITY }
230 var max_count: nx_int = 0
231 var k: nx_int = 0
232 while k < NX_SB_KIND_N {
233 let cnt: nx_int = nx_sb_count_by_kind(b, k)
234 if cnt > max_count { max_count = cnt }
235 k = k + 1
236 }
237 let dominant_share_q10: nx_int = (max_count * NX_MAGIC_1024) / b.n_accessions
238 if dominant_share_q10 >= b.monoculture_threshold_q10 {
239 return NX_SB_V_MONOCULTURE_WARNING
240 }
241 let corrupted: nx_int = nx_sb_count_by_status(b, NX_SB_STATUS_CORRUPTED)
242 if corrupted > 0 { return NX_SB_V_CORRUPTION_DETECTED }
243 return NX_SB_V_OK_HEALTHY_DIVERSITY
244}
245
246func nx_sb_total_bytes(b: *NxSeedBank) -> nx_size {
247 if (b as i64) == 0 { return 0 }
248 var sum: nx_size = 0
249 var i: nx_int = 0
250 while i < b.n_accessions {
251 let a: *NxAccession = _sb_acc_at(b, i)
252 sum = sum + a.bytes_stored
253 i = i + 1
254 }
255 return sum
256}