nx_module_registry.nx source
↩ module page · 279 lines · 11156 B
1// nx_module_registry.nx -- modular stdlib backbone.
2//
3// module: nishi-core.install.module_registry
4// depends: nishi-core.io.csv, nishi-core.io.syscalls
5// disk_kb: 8
6// capability: CORE_SYSCALLS
7//
8// license_tier: PUBLIC_NISHI_SUBSTRATE
9// genealogy_id: debian_apt_package_dependency_resolution +
10// rust_cargo_feature_flags +
11// python_pep_440_optional_dependencies +
12// freebsd_pkg_sets +
13// nishi_modular_stdlib_opt_in_cardinal_2026
14//
15// Per cardinal [[feedback-modular-stdlib-opt-in-at-install-time]]:
16// Nishi family substrate is NOT a monolithic stdlib. Each `.nx`
17// file declares MODULE METADATA at the top of the file (the header
18// comment block above this one is the canonical shape). This
19// primitive READS the module manifest, resolves capability-tag
20// selections + transitive dependencies, and reports the disk-
21// footprint of any install configuration.
22//
23// User experience:
24//
25// $ nishi install --capability greenhouse,iot
26// Resolving 47 modules + 12 transitive deps.
27// Total disk: 14.2 MB (3.1 MB compressed).
28// Confirm? [y/N]:
29//
30// ===== Module manifest record shape ===============================
31//
32// Each module is one record in nishi-core/modules/manifest.jsonl:
33//
34// { "module": "nishi-greenhouse.crop.potato",
35// "path": "nishi-greenhouse/runtime/nx_crop_potato.nx",
36// "version": "0.1.0",
37// "capabilities": ["GREENHOUSE"],
38// "depends": [
39// "nishi-core.math.q10",
40// "nishi-core.math.exp",
41// "nishi-greenhouse.eq.potato_aero_tower"
42// ],
43// "disk_bytes": 12288,
44// "license_tier": "PUBLIC_NISHI_SUBSTRATE",
45// "genealogy_id": "stoner_1983_nasa_celss_aeroponic_potato",
46// "stability": "BETA" // ALPHA | BETA | STABLE | DEPRECATED
47// }
48//
49// nishi-library generates the manifest via `nishi-library/scripts/
50// build_module_manifest.py` which scans every `.nx` file's header
51// comment block + computes disk_bytes from filesystem.
52
53// nx_safety_envelope:
54// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
55// sil_target: SIL1
56// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
57// verdict: NOT_YET_EVALUATED
58
59import "nx_syscalls.nx"
60
61// ===== ModuleCapability sealed enum ===============================
62
63const NX_CAP_KERNEL: i64 = 1
64const NX_CAP_BROWSER: i64 = 2
65const NX_CAP_COMMS: i64 = 3
66const NX_CAP_IOT: i64 = 4
67const NX_CAP_GREENHOUSE: i64 = 5
68const NX_CAP_SEEDBANK: i64 = 6
69const NX_CAP_GAME_ENGINE: i64 = 7
70const NX_CAP_MARKETPLACE: i64 = 8
71const NX_CAP_STORAGE: i64 = 9
72const NX_CAP_CRYPTO: i64 = 10
73const NX_CAP_ML: i64 = 11
74const NX_CAP_COMPILER: i64 = 12
75const NX_CAP_BENCH: i64 = 13
76const NX_CAP_CORE_MATH: i64 = 14
77const NX_CAP_CORE_NET: i64 = 15
78const NX_CAP_CORE_SYSCALLS: i64 = 16
79const NX_CAP_CORE_IO: i64 = 17
80const NX_CAP_CURRICULUM: i64 = 18 // game-curriculum modules (Pillar replenisher)
81const NX_CAP_REGULATORY: i64 = 19 // state-law + tax + KYC routers
82const NX_CAP_PROCGEN: i64 = 20 // causal-growth + biome + procgen substrate
83
84func nx_cap_name(c: i64) -> *u8 {
85 if c == NX_CAP_KERNEL { return "KERNEL" }
86 if c == NX_CAP_BROWSER { return "BROWSER" }
87 if c == NX_CAP_COMMS { return "COMMS" }
88 if c == NX_CAP_IOT { return "IOT" }
89 if c == NX_CAP_GREENHOUSE { return "GREENHOUSE" }
90 if c == NX_CAP_SEEDBANK { return "SEEDBANK" }
91 if c == NX_CAP_GAME_ENGINE { return "GAME_ENGINE" }
92 if c == NX_CAP_MARKETPLACE { return "MARKETPLACE" }
93 if c == NX_CAP_STORAGE { return "STORAGE" }
94 if c == NX_CAP_CRYPTO { return "CRYPTO" }
95 if c == NX_CAP_ML { return "ML" }
96 if c == NX_CAP_COMPILER { return "COMPILER" }
97 if c == NX_CAP_BENCH { return "BENCH" }
98 if c == NX_CAP_CORE_MATH { return "CORE_MATH" }
99 if c == NX_CAP_CORE_NET { return "CORE_NET" }
100 if c == NX_CAP_CORE_SYSCALLS { return "CORE_SYSCALLS" }
101 if c == NX_CAP_CORE_IO { return "CORE_IO" }
102 if c == NX_CAP_CURRICULUM { return "CURRICULUM" }
103 if c == NX_CAP_REGULATORY { return "REGULATORY" }
104 if c == NX_CAP_PROCGEN { return "PROCGEN" }
105 return "UNKNOWN"
106}
107
108// ===== Stability tier sealed enum =================================
109
110const NX_STABILITY_ALPHA: i64 = 1 // unstable; may change/disappear
111const NX_STABILITY_BETA: i64 = 2 // mostly stable; minor breaks possible
112const NX_STABILITY_STABLE: i64 = 3 // API frozen per Cardinal 19
113const NX_STABILITY_DEPRECATED: i64 = 4 // scheduled for removal; alternative exists
114
115func nx_stability_name(s: i64) -> *u8 {
116 if s == NX_STABILITY_ALPHA { return "ALPHA" }
117 if s == NX_STABILITY_BETA { return "BETA" }
118 if s == NX_STABILITY_STABLE { return "STABLE" }
119 if s == NX_STABILITY_DEPRECATED { return "DEPRECATED" }
120 return "UNKNOWN"
121}
122
123// ===== Module record struct =======================================
124//
125// One row per installable module. Read from manifest.jsonl at
126// startup. Maximum module-name string length is 128 bytes.
127
128struct ModuleRecord {
129 module_hk: i64,
130 module_name_ptr: *u8, // e.g. "nishi-greenhouse.crop.potato"
131 path_ptr: *u8, // relative file path
132 version_major: i64,
133 version_minor: i64,
134 version_patch: i64,
135 capability_bitmask: i64, // bits 1..20 = NX_CAP_*
136 depends_count: i64,
137 depends_ptr: *u8, // pointer to flat-buffer of dep names
138 disk_bytes: i64,
139 stability: i64,
140 license_tier_id: i64,
141 is_installed: i64,
142}
143
144const NX_MODULE_RECORD_BYTES: i64 = 96 // 12 fields * 8 bytes
145
146// ===== Capability-bitmask helpers =================================
147
148func nx_cap_bitmask_has(bitmask: i64, capability: i64) -> i64 {
149 let bit: i64 = 1 << (capability - 1)
150 if (bitmask & bit) != 0 { return 1 }
151 return 0
152}
153
154func nx_cap_bitmask_set(bitmask: i64, capability: i64) -> i64 {
155 let bit: i64 = 1 << (capability - 1)
156 return bitmask | bit
157}
158
159// ===== Install-resolution verdict =================================
160
161const NX_INSTALL_OK: i64 = 1
162const NX_INSTALL_MISSING_DEPENDENCY: i64 = 2 // user excluded a transitive dep
163const NX_INSTALL_CIRCULAR_DEPENDENCY: i64 = 3 // manifest data error
164const NX_INSTALL_UNKNOWN_CAPABILITY: i64 = 4 // typo'd capability flag
165const NX_INSTALL_DISK_BUDGET_EXCEEDED: i64 = 5 // user --max-disk-mb set
166
167func nx_install_verdict_name(v: i64) -> *u8 {
168 if v == NX_INSTALL_OK { return "OK" }
169 if v == NX_INSTALL_MISSING_DEPENDENCY { return "MISSING_DEPENDENCY" }
170 if v == NX_INSTALL_CIRCULAR_DEPENDENCY { return "CIRCULAR_DEPENDENCY" }
171 if v == NX_INSTALL_UNKNOWN_CAPABILITY { return "UNKNOWN_CAPABILITY" }
172 if v == NX_INSTALL_DISK_BUDGET_EXCEEDED { return "DISK_BUDGET_EXCEEDED" }
173 return "UNKNOWN"
174}
175
176// ===== InstallPlan struct =========================================
177
178struct InstallPlan {
179 plan_hk: i64,
180 requested_capabilities: i64, // bitmask of NX_CAP_*
181 selected_module_count: i64,
182 transitive_dep_count: i64,
183 total_disk_bytes: i64,
184 verdict: i64, // NX_INSTALL_*
185 missing_dep_name_ptr: *u8, // first missing dep if any
186}
187
188const NX_INSTALL_PLAN_BYTES: i64 = 56 // 7 fields * 8 bytes
189
190func nx_install_plan_new(requested_capabilities: i64) -> *InstallPlan {
191 let raw: *u8 = sys_mmap(NX_INSTALL_PLAN_BYTES)
192 let p: *InstallPlan = raw as *InstallPlan
193 p.plan_hk = 0
194 p.requested_capabilities = requested_capabilities
195 p.selected_module_count = 0
196 p.transitive_dep_count = 0
197 p.total_disk_bytes = 0
198 p.verdict = 0
199 p.missing_dep_name_ptr = 0 as *u8
200 return p
201}
202
203// ===== Per-module install decision ================================
204//
205// Given a module record + the user's requested capability bitmask,
206// return 1 if the module is INCLUDED in the install, 0 if not.
207// Inclusion criteria:
208// - Module has at least one capability matching the requested mask, OR
209// - Module is a transitive dependency of an included module
210// (transitive-dep walk is the caller's job; this primitive answers
211// the "direct match" question)
212
213func nx_module_direct_match(record: *ModuleRecord, requested_capabilities: i64) -> i64 {
214 if (record.capability_bitmask & requested_capabilities) != 0 { return 1 }
215 return 0
216}
217
218// ===== Disk-budget aggregator =====================================
219//
220// Walks an array of selected modules + sums disk_bytes. Bounded
221// per [[feedback-bounded-loop-discipline-jpl-rule-2]].
222
223const NX_MODULE_MAX_PER_INSTALL: i64 = 4096
224
225func nx_install_sum_disk_bytes(modules: **ModuleRecord, n_modules: i64) -> i64 {
226 if n_modules <= 0 { return 0 }
227 if n_modules > NX_MODULE_MAX_PER_INSTALL { return -1 }
228 var total: i64 = 0
229 var i: i64 = 0
230 var iter: i64 = 0
231 var verdict: i64 = 0
232 while verdict == 0 && iter < NX_MODULE_MAX_PER_INSTALL {
233 if i >= n_modules { verdict = 1 }
234 if verdict == 0 {
235 let m: *ModuleRecord = modules[i]
236 total = total + m.disk_bytes
237 i = i + 1
238 }
239 iter = iter + 1
240 }
241 return total
242}
243
244// ===== Capability-tag parsing =====================================
245//
246// CLI argument "greenhouse,iot,seedbank" -> bitmask. Caller passes
247// each capability ID separately after parsing the CSV string.
248
249func nx_capability_string_to_id(name: *u8) -> i64 {
250 // Caller compares against the known names; substrate doesn't ship
251 // a string-table here because nx_string equality is a separate
252 // primitive (substrate composes nx_string against this).
253 // v1 returns 0 (unknown); the install CLI does the string match
254 // and passes the resolved ID. Future v1.1: integrate nx_string
255 // table directly when it's stable.
256 return 0
257}
258
259// ===== Sovereign distribution metadata ============================
260//
261// Per [[nishi-stack-is-bits-up-sovereign-always-no-third-party]]:
262// no apt / npm / pip — modules are distributed via Nishi-sovereign
263// channels. Default channel: HTTPS over Nishi sovereign DNS.
264// Alternative: BitTorrent magnet, IPFS CID, local NAS rsync.
265
266const NX_DIST_CHANNEL_HTTPS: i64 = 1
267const NX_DIST_CHANNEL_BITTORRENT: i64 = 2
268const NX_DIST_CHANNEL_IPFS: i64 = 3
269const NX_DIST_CHANNEL_LOCAL_RSYNC: i64 = 4
270const NX_DIST_CHANNEL_USB_OFFLINE: i64 = 5 // air-gapped install
271
272func nx_dist_channel_name(c: i64) -> *u8 {
273 if c == NX_DIST_CHANNEL_HTTPS { return "HTTPS" }
274 if c == NX_DIST_CHANNEL_BITTORRENT { return "BITTORRENT" }
275 if c == NX_DIST_CHANNEL_IPFS { return "IPFS" }
276 if c == NX_DIST_CHANNEL_LOCAL_RSYNC { return "LOCAL_RSYNC" }
277 if c == NX_DIST_CHANNEL_USB_OFFLINE { return "USB_OFFLINE" }
278 return "UNKNOWN"
279}