nx_bprov_chain.nx source
↩ module page · 100 lines · 3524 B
1// nx_bprov_chain.nx -- ergonomic wrappers over nx_bit_provenance.
2//
3// Cardinal: feedback-bit-provenance-systemic-auto-injection.
4//
5// The bit-provenance ledger primitive (nx_bit_provenance.nx) exposes
6// alloc / emit / emit3 / join. Used directly, each producer site
7// needs 2-3 lines of boilerplate:
8//
9// let id: i64 = nx_bprov_alloc()
10// nx_bprov_emit(id, src_a, src_b, layer, tag)
11//
12// This wrapper collapses that into a single chain-call:
13//
14// let id: i64 = nx_bprov_chain2(layer, tag, src_a, src_b)
15//
16// Or for 3 sources:
17// let id: i64 = nx_bprov_chain3(layer, tag, src_a, src_b, src_c)
18//
19// Or 0 sources (silicon-born input):
20// let id: i64 = nx_bprov_chain0(layer, tag)
21//
22// These are the "born into what we build" half of the systemic
23// answer. New substrate primitives use these in their main paths.
24// The other half (retroactive injection on existing primitives) is
25// the self-host IR pass per docs/NISHI_BPROV_AUTO_INJECTION_DESIGN.md.
26
27import "nx_bit_provenance.nx"
28
29// Silicon-born / no upstream: just allocate + record.
30func nx_bprov_chain0(layer: i64, tag: i64) -> i64 {
31 let id: i64 = nx_bprov_alloc()
32 nx_bprov_emit(id, 0, 0, layer, tag)
33 return id
34}
35
36// One upstream source.
37func nx_bprov_chain1(layer: i64, tag: i64, src_a: i64) -> i64 {
38 let id: i64 = nx_bprov_alloc()
39 nx_bprov_emit(id, src_a, 0, layer, tag)
40 return id
41}
42
43// Two upstream sources (most common).
44func nx_bprov_chain2(layer: i64, tag: i64, src_a: i64, src_b: i64) -> i64 {
45 let id: i64 = nx_bprov_alloc()
46 nx_bprov_emit(id, src_a, src_b, layer, tag)
47 return id
48}
49
50// Three upstream sources (matmul-cell-class).
51func nx_bprov_chain3(layer: i64, tag: i64,
52 src_a: i64, src_b: i64, src_c: i64) -> i64 {
53 let id: i64 = nx_bprov_alloc()
54 nx_bprov_emit3(id, src_a, src_b, src_c, layer, tag)
55 return id
56}
57
58// Consumer-side helper -- alias for nx_bprov_join with a friendlier
59// name in caller context.
60func nx_bprov_consume(in_bit_id: i64, layer: i64, tag: i64) -> i64 {
61 return nx_bprov_join(in_bit_id, layer, tag)
62}
63
64// ---- self-test ---------------------------------------------------
65// expect_exit: 0
66
67func main() -> i64 {
68 if nx_bprov_init() != 0 { return 1 }
69
70 // Birth 2 silicon bits.
71 let b_a: i64 = nx_bprov_chain0(NX_BPROV_L_NEG_1, 0xC0DE0001)
72 let b_b: i64 = nx_bprov_chain0(NX_BPROV_L_NEG_1, 0xC0DE0002)
73
74 // Compose at L3.
75 let b_x: i64 = nx_bprov_chain2(NX_BPROV_L_3, 0xC0DE0003, b_a, b_b)
76
77 // Compose at L3.5 with 3 sources (last is silicon-immutable 0).
78 let b_y: i64 = nx_bprov_chain3(NX_BPROV_L_35, 0xC0DE0004, b_a, b_b, b_x)
79
80 // Single-source chain at L4.
81 let b_z: i64 = nx_bprov_chain1(NX_BPROV_L_4, 0xC0DE0005, b_y)
82
83 // Pre-consume audit: 5 zombies (b_a/b_b/b_x/b_y/b_z all unjoined).
84 if nx_bprov_audit_zombies() != 5 { return 10 }
85
86 // Consume the leaf at L7 (browser death).
87 if nx_bprov_consume(b_z, NX_BPROV_L_7, 0xC0DE0006) != 0 { return 20 }
88
89 // Join intermediates at their actual consumer layers.
90 if nx_bprov_consume(b_a, NX_BPROV_L_3, 0xC0DE0003) != 0 { return 21 }
91 if nx_bprov_consume(b_b, NX_BPROV_L_3, 0xC0DE0003) != 0 { return 22 }
92 if nx_bprov_consume(b_x, NX_BPROV_L_35, 0xC0DE0004) != 0 { return 23 }
93 if nx_bprov_consume(b_y, NX_BPROV_L_4, 0xC0DE0005) != 0 { return 24 }
94
95 // Final audit: zombies=0, all 5 bits silicon-to-death traced.
96 if nx_bprov_audit_zombies() != 0 { return 30 }
97 if nx_bprov_n_records() != 5 { return 40 }
98
99 return 0
100}