nx_pathway.nx source
↩ module page · 275 lines · 10421 B
1// nx_pathway.nx -- cell-graph manifest.
2//
3// Biological analogue: a signaling pathway is a sequence of molecular
4// events where signal transduction passes through ordered cells via
5// vesicles. Nishi pathway is the substrate-level declarative
6// composition format: a typed directed graph of cells with vesicle
7// edges between them. Same .nx pathway runs local-only, split across
8// laptop+NAS+peer GPU, or all-cloud -- the operator changes the per-
9// cell tropism, not the graph.
10//
11// Per [[feedback-pathway-tropism-block-composition-location-agnostic]]:
12// the structural EXCEED-axis vs ComfyUI / Langflow / Airflow DAG /
13// K8s Argo / Ray Serve / Step Functions ASL / Temporal: those bind
14// the location of work at graph-definition time. nx_pathway lets the
15// SAME manifest run differently per cell's nx_tropism resolution.
16//
17// Composes:
18// nx_budget -- each cell has a budget pointer; pathway
19// aggregates for whole-pathway forecasting
20// nx_attention_class -- each cell declares its class
21// nx_tropism -- each cell declares preferred location
22// nx_ribosome -- each cell declares ribosome target
23// nx_metabolism -- pathway-level hot-site list informs replan
24// nx_homeostasis -- migration signals at the cell level may
25// trigger pathway-wide topology re-resolve
26//
27// V1 ships a fixed-capacity graph with cells + edges. Sub-graph
28// composition (pathway-of-pathways) is queued; parallel sub-graphs
29// are representable but the scheduler that exploits them is V2.
30//
31// Gap list (V1 honest perf verdict):
32// - no typed payload validation between cells (caller's job)
33// - no cycle detection (caller must build DAG-correct)
34// - no per-edge bandwidth budget (queued for distributed scheduler)
35// - no live re-routing (pathway is rebuilt, not patched, on
36// migration signal)
37// - no NxCellSpec field count is bumping the parser's 16-field
38// ceiling -- stay strict to that contract per
39// [[feedback-nishilang-16-arg-function-limit]]
40//
41// genealogy_id: nishi_cardinal_2026-05-17_pathway_tropism + biology_signal_transduction
42// lineage_id: substrate_pathway_v1
43//
44// nx_safety_envelope:
45// intended_use: "Declarative cell-graph manifest enabling
46// same-source local/NAS/peer/cloud execution"
47// sil_target: SIL2
48// asil_target: QM
49// evidence: [bounded_capacity, deterministic_topology,
50// per_cell_tropism_separation]
51// verdict: NOT_YET_EVALUATED
52
53import "nx_syscalls.nx"
54import "nx_tier.nx"
55import "nx_budget.nx"
56import "nx_attention_class.nx"
57import "nx_tropism.nx"
58import "nx_ribosome.nx"
59
60// ===== Sealed enum: NxPathwayVerdict ==============================
61
62const NX_PW_OK: nx_int = 0
63const NX_PW_ERR_FULL: nx_int = 1
64const NX_PW_ERR_BAD_CELL: nx_int = 2
65const NX_PW_ERR_BAD_EDGE: nx_int = 3
66const NX_PW_ERR_CELL_NOT_FOUND: nx_int = 4
67
68// ===== Struct: NxCellSpec ========================================
69//
70// One row per cell in the pathway. Bundles the cell's identity, its
71// declared resource ceilings (via *NxBudget pointer to keep this
72// struct under the 16-field limit), and its placement preferences.
73
74struct NxCellSpec {
75 cell_id: nx_int,
76 attention_class: nx_int,
77 tropism_prefer: nx_int,
78 ribosome_target: nx_int,
79 budget: *NxBudget,
80 site_id_hint: nx_int,
81 initial_tier: nx_int,
82}
83
84// ===== Struct: NxEdge ============================================
85//
86// Vesicle: directed edge carrying typed payload from one cell to
87// another. payload_kind is caller-defined (e.g. an enum for image
88// bytes, tensor, logits, audio); pathway does not validate it.
89
90struct NxEdge {
91 from_cell_id: nx_int,
92 to_cell_id: nx_int,
93 payload_kind: nx_int,
94}
95
96// ===== Struct: NxPathway =========================================
97//
98// Top-level container. Cells + edges in fixed-capacity arenas. Two
99// counts (n_cells, n_edges) advance monotonically as add_cell /
100// add_edge calls succeed.
101
102struct NxPathway {
103 cells: *NxCellSpec,
104 cell_capacity: nx_size,
105 n_cells: nx_size,
106 edges: *NxEdge,
107 edge_capacity: nx_size,
108 n_edges: nx_size,
109}
110
111// Each NxCellSpec is 7 nx_int fields + 1 pointer = 64 bytes
112const NX_PW_CELLSPEC_BYTES: nx_size = 64
113// Each NxEdge is 3 nx_int fields = 24 bytes
114const NX_PW_EDGE_BYTES: nx_size = 24
115
116// ===== Constructor ===============================================
117
118func nx_pathway_new(cell_capacity: nx_size, edge_capacity: nx_size) -> *NxPathway {
119 let p: *NxPathway = (sys_mmap(56)) as *NxPathway
120 let cell_bytes: nx_size = cell_capacity * NX_PW_CELLSPEC_BYTES
121 let edge_bytes: nx_size = edge_capacity * NX_PW_EDGE_BYTES
122 p.cells = (sys_mmap(cell_bytes)) as *NxCellSpec
123 p.cell_capacity = cell_capacity
124 p.n_cells = 0
125 p.edges = (sys_mmap(edge_bytes)) as *NxEdge
126 p.edge_capacity = edge_capacity
127 p.n_edges = 0
128 return p
129}
130
131// ===== _pathway_cell_at ==========================================
132
133func _pathway_cell_at(p: *NxPathway, idx: nx_size) -> *NxCellSpec {
134 return (p.cells as i64 + (idx as i64) * NX_PW_CELLSPEC_BYTES) as *NxCellSpec
135}
136
137// ===== _pathway_edge_at ==========================================
138
139func _pathway_edge_at(p: *NxPathway, idx: nx_size) -> *NxEdge {
140 return (p.edges as i64 + (idx as i64) * NX_PW_EDGE_BYTES) as *NxEdge
141}
142
143// ===== nx_pathway_add_cell =======================================
144//
145// Append one cell. Caller has already populated the spec; this is a
146// shallow copy. Returns OK or FULL. Per Cardinal 12 (defensive at
147// boundaries), the attention_class / tropism / ribosome_target are
148// validated here rather than each downstream call.
149
150func nx_pathway_add_cell(p: *NxPathway, spec: *NxCellSpec) -> nx_int {
151 if p.n_cells >= p.cell_capacity { return NX_PW_ERR_FULL }
152 if nx_ac_is_valid(spec.attention_class) == 0 { return NX_PW_ERR_BAD_CELL }
153 if nx_tropism_is_valid(spec.tropism_prefer) == 0 { return NX_PW_ERR_BAD_CELL }
154 if nx_rbt_is_valid(spec.ribosome_target) == 0 { return NX_PW_ERR_BAD_CELL }
155 let dst: *NxCellSpec = _pathway_cell_at(p, p.n_cells)
156 dst.cell_id = spec.cell_id
157 dst.attention_class = spec.attention_class
158 dst.tropism_prefer = spec.tropism_prefer
159 dst.ribosome_target = spec.ribosome_target
160 dst.budget = spec.budget
161 dst.site_id_hint = spec.site_id_hint
162 dst.initial_tier = spec.initial_tier
163 p.n_cells = p.n_cells + 1
164 return NX_PW_OK
165}
166
167// ===== _pathway_find_cell_idx ====================================
168
169func _pathway_find_cell_idx(p: *NxPathway, cell_id: nx_int) -> nx_int {
170 var i: nx_size = 0
171 while i < p.n_cells {
172 let c: *NxCellSpec = _pathway_cell_at(p, i)
173 if c.cell_id == cell_id { return i as i64 }
174 i = i + 1
175 }
176 return -1
177}
178
179// ===== nx_pathway_add_edge =======================================
180//
181// Append one vesicle edge. Both endpoints must exist (validated here
182// at the boundary). Returns OK / FULL / CELL_NOT_FOUND.
183
184func nx_pathway_add_edge(p: *NxPathway,
185 from_cell_id: nx_int,
186 to_cell_id: nx_int,
187 payload_kind: nx_int) -> nx_int {
188 if p.n_edges >= p.edge_capacity { return NX_PW_ERR_FULL }
189 if _pathway_find_cell_idx(p, from_cell_id) < 0 { return NX_PW_ERR_CELL_NOT_FOUND }
190 if _pathway_find_cell_idx(p, to_cell_id) < 0 { return NX_PW_ERR_CELL_NOT_FOUND }
191 let e: *NxEdge = _pathway_edge_at(p, p.n_edges)
192 e.from_cell_id = from_cell_id
193 e.to_cell_id = to_cell_id
194 e.payload_kind = payload_kind
195 p.n_edges = p.n_edges + 1
196 return NX_PW_OK
197}
198
199// ===== nx_pathway_get_cell =======================================
200
201func nx_pathway_get_cell(p: *NxPathway, cell_id: nx_int) -> *NxCellSpec {
202 let idx: nx_int = _pathway_find_cell_idx(p, cell_id)
203 if idx < 0 { return (0 as i64) as *NxCellSpec }
204 return _pathway_cell_at(p, idx as nx_size)
205}
206
207// ===== nx_pathway_resolve_target =================================
208//
209// For one cell, resolve its concrete ribosome target given:
210// - the cell's declared initial_tier
211// - a metabolism profile (optional, may be NULL)
212//
213// This is the pathway-level entry into nx_ribosome_pick. Useful when
214// the operator wants to dry-run "what would this cell compile to?"
215// before committing the pathway.
216
217func nx_pathway_resolve_target(p: *NxPathway,
218 cell_id: nx_int,
219 m: *NxMetabolism) -> nx_int {
220 let c: *NxCellSpec = nx_pathway_get_cell(p, cell_id)
221 if (c as i64) == 0 { return NX_RBT_X86_64 }
222 return nx_ribosome_pick(c.initial_tier, m, c.site_id_hint, c.ribosome_target)
223}
224
225// ===== nx_pathway_aggregate_ram_max ===============================
226//
227// Sum the declared RAM ceilings across all cells. Returns the
228// pathway-wide RAM floor needed for ALL cells to coexist locally;
229// the host's actual physical RAM must exceed this if tropism is
230// LOCAL_*-only across the whole graph.
231
232func nx_pathway_aggregate_ram_max(p: *NxPathway) -> nx_size {
233 var total: nx_size = 0
234 var i: nx_size = 0
235 while i < p.n_cells {
236 let c: *NxCellSpec = _pathway_cell_at(p, i)
237 if (c.budget as i64) != 0 {
238 total = total + c.budget.ram_max
239 }
240 i = i + 1
241 }
242 return total
243}
244
245// ===== nx_pathway_aggregate_vram_max ==============================
246
247func nx_pathway_aggregate_vram_max(p: *NxPathway) -> nx_size {
248 var total: nx_size = 0
249 var i: nx_size = 0
250 while i < p.n_cells {
251 let c: *NxCellSpec = _pathway_cell_at(p, i)
252 if (c.budget as i64) != 0 {
253 total = total + c.budget.vram_max
254 }
255 i = i + 1
256 }
257 return total
258}
259
260// ===== nx_pathway_count_remote_cells ==============================
261//
262// Number of cells whose tropism is a remote target. Useful to flag
263// pathways that REQUIRE peer-mesh discovery to run; if this is > 0
264// and peer-mesh is offline, the operator knows to fall back.
265
266func nx_pathway_count_remote_cells(p: *NxPathway) -> nx_size {
267 var hits: nx_size = 0
268 var i: nx_size = 0
269 while i < p.n_cells {
270 let c: *NxCellSpec = _pathway_cell_at(p, i)
271 if nx_tropism_is_remote(c.tropism_prefer) == 1 { hits = hits + 1 }
272 i = i + 1
273 }
274 return hits
275}