nx_ledger_gate.nx source
↩ module page · 186 lines · 8862 B
1// nx_ledger_gate.nx -- F981 INDEPENDENT GATE for the sovereign double-entry ledger.
2// Imports the lib and proves its contract by BEHAVIOUR on a live seg-store plane.
3//
4// ★NON-VACUITY NOTE (stated plainly rather than dressed up): conservation is STRUCTURAL here --
5// one record carries BOTH legs (dr and cr), so a one-sided entry is INEXPRESSIBLE and a global
6// "drift == 0" assertion would be a TAUTOLOGY. Asserting it alone would be fake rigor. So the
7// measured tests are the ones that CAN fail:
8// * per-account balances summed across every account must total 0 -- this cross-checks the
9// per-account FILTER against global conservation; a broken match would break it.
10// * exact expected deltas (not merely non-zero) -- a sign flip or a wrong field would fail.
11// * every refusal path must refuse AND leave ZERO state change.
12// All assertions are DELTAS against a pre-read baseline, so the gate is re-runnable on a plane
13// that already holds history (append-only = prior runs persist by design).
14// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
15
16import "nx_ledger_lib.nx"
17
18const LG_PFX: i64 = 0
19
20func lg_puts(s: *u8) -> i64 {
21 var n: i64 = 0
22 while s[n] != (0 as u8) { n = n + 1 }
23 sys_write(1, s, n)
24 return 0
25}
26func lg_putn(v: i64) -> i64 {
27 let t: *u8 = sys_mmap(32)
28 var o: i64 = 0
29 var m: i64 = v
30 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m }
31 let d: *u8 = sys_mmap(32)
32 var k: i64 = 0
33 if m == 0 { d[0] = 48 as u8; k = 1 }
34 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
35 var i: i64 = 0
36 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 }
37 sys_write(1, t, o)
38 return 0
39}
40// cnt[0]=pass cnt[1]=fail -- counters live in an mmap'd slot (no module-level mutable globals)
41func lg_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 {
42 if got == want {
43 cnt[0] = cnt[0] + 1
44 lg_puts(" PASS " as *u8); lg_puts(name); lg_puts(" = " as *u8); lg_putn(got); lg_puts("\n" as *u8)
45 return 1
46 }
47 cnt[1] = cnt[1] + 1
48 lg_puts(" FAIL " as *u8); lg_puts(name); lg_puts(" got " as *u8); lg_putn(got)
49 lg_puts(" want " as *u8); lg_putn(want); lg_puts("\n" as *u8)
50 return 0
51}
52
53// build a run-unique id: <tag><nonce>
54func lg_id(tag: *u8, nonce: i64, out: *u8) -> i64 {
55 var o: i64 = mt_catcopy(out, 0, tag)
56 o = mt_catn(out, o, nonce)
57 out[o] = 0 as u8
58 return o
59}
60
61func main(argc: i64, argv: *i64) -> i64 {
62 // FIXTURE MOVED OUT OF THE SWEPT STORE (2026-08-07). knowledge/store/ is walked every 600s by the
63 // nx_segguard beat, which has folded THIS gate's fixture 17 times -- more than any other gate in
64 // the corpus. A fold landing mid-run rewrites the manifest under the code being measured, so a RED
65 // here could not be attributed to the ledger logic at all. Proven on the sibling defect: the SAME
66 // code went RED on a knowledge/store fixture and GREEN 24/24 on a /tmp one.
67 // The run-unique account names below were the earlier mitigation -- they keep the DELTAS clean but
68 // leave the plane accumulating in production, which is precisely what let it grow past the fold
69 // threshold. ★MAKING THE DATA UNIQUE IS NOT THE SAME AS MAKING THE LOCATION ISOLATED.
70 // Created at SETUP, not teardown: a teardown does not run when a run crashes.
71 sys_mkdir("/tmp/ledgergate\x00" as *u8, 0x1ed)
72 let pfx: *u8 = "/tmp/ledgergate/ledgergate-" as *u8
73 let nonce: i64 = sys_now_us()
74 let cnt: *i64 = sys_mmap(16) as *i64
75 cnt[0] = 0
76 cnt[1] = 0
77
78 // run-unique account names so deltas are clean even though the plane is append-only
79 let A: *u8 = sys_mmap(64)
80 let B: *u8 = sys_mmap(64)
81 let C: *u8 = sys_mmap(64)
82 lg_id("acctA" as *u8, nonce, A)
83 lg_id("acctB" as *u8, nonce, B)
84 lg_id("acctC" as *u8, nonce, C)
85
86 let i1: *u8 = sys_mmap(64)
87 let i2: *u8 = sys_mmap(64)
88 let i3: *u8 = sys_mmap(64)
89 let i4: *u8 = sys_mmap(64)
90 let i5: *u8 = sys_mmap(64)
91 lg_id("t1_" as *u8, nonce, i1)
92 lg_id("t2_" as *u8, nonce, i2)
93 lg_id("t3_" as *u8, nonce, i3)
94 lg_id("t4_" as *u8, nonce, i4)
95 lg_id("t5_" as *u8, nonce, i5)
96
97 lg_puts("NISHI-LEDGER-GATE (F981 double-entry, integer minor units)\n" as *u8)
98
99 // ---- T1/T2: a posted transfer moves EXACTLY the amount, both directions ----
100 led_xfer(pfx, i1, A, B, 10000, "posted" as *u8)
101 lg_ck(cnt, "T1 debit side bal(A) after A->B $100.00" as *u8, led_balance(pfx, A), 0 - 10000)
102 lg_ck(cnt, "T2 credit side bal(B) after A->B $100.00" as *u8, led_balance(pfx, B), 10000)
103
104 // ---- T3: second transfer, exact cumulative deltas (a sign flip or wrong field fails here) ----
105 led_xfer(pfx, i2, B, C, 2500, "posted" as *u8)
106 lg_ck(cnt, "T3 bal(B) after B->C $25.00" as *u8, led_balance(pfx, B), 7500)
107
108 // ---- T4: THE CROSS-CHECK -- per-account balances must sum to ZERO ----
109 // NOT structural: this validates the per-account filter against global conservation.
110 let sum3: i64 = led_balance(pfx, A) + led_balance(pfx, B) + led_balance(pfx, C)
111 lg_ck(cnt, "T4 sum of per-account balances (conservation)" as *u8, sum3, 0)
112
113 // ---- T5/T6: refusals must refuse AND write nothing ----
114 let bA: i64 = led_balance(pfx, A)
115 lg_ck(cnt, "T5 negative amount REFUSED" as *u8, led_xfer(pfx, i3, A, B, 0 - 500, "posted" as *u8), 0 - 1)
116 lg_ck(cnt, "T5b refusal left bal(A) untouched" as *u8, led_balance(pfx, A), bA)
117 lg_ck(cnt, "T6 self-transfer REFUSED" as *u8, led_xfer(pfx, i3, A, A, 500, "posted" as *u8), 0 - 2)
118 lg_ck(cnt, "T6b refusal left bal(A) untouched" as *u8, led_balance(pfx, A), bA)
119
120 // ---- T7/T8: two-phase pending reserves without moving posted money ----
121 let bB: i64 = led_balance(pfx, B)
122 let avB: i64 = led_available(pfx, B)
123 led_xfer(pfx, i3, B, C, 1000, "pending" as *u8)
124 lg_ck(cnt, "T7 pending does NOT move posted bal(B)" as *u8, led_balance(pfx, B), bB)
125 lg_ck(cnt, "T8 pending DOES reduce available(B) by $10.00" as *u8, led_available(pfx, B), avB - 1000)
126
127 // ---- T9: post the pending -> money moves, available unchanged from the reserved state ----
128 led_resolve(pfx, i3, "post" as *u8)
129 lg_ck(cnt, "T9 after post, bal(B) moved by the pending amount" as *u8, led_balance(pfx, B), bB - 1000)
130
131 // ---- T10/T11: a VOIDED pending must restore available and never touch posted ----
132 let bB2: i64 = led_balance(pfx, B)
133 let avB2: i64 = led_available(pfx, B)
134 led_xfer(pfx, i4, B, C, 3000, "pending" as *u8)
135 led_resolve(pfx, i4, "void" as *u8)
136 lg_ck(cnt, "T10 voided pending left posted bal(B) unchanged" as *u8, led_balance(pfx, B), bB2)
137 lg_ck(cnt, "T11 voided pending RESTORED available(B)" as *u8, led_available(pfx, B), avB2)
138
139 // ---- T12/T13: linked chain atomicity -- underfunded chain writes NOTHING ----
140 let ids: *i64 = sys_mmap(8 * 2) as *i64
141 let drs: *i64 = sys_mmap(8 * 2) as *i64
142 let crs: *i64 = sys_mmap(8 * 2) as *i64
143 let amts: *i64 = sys_mmap(8 * 2) as *i64
144 let c1: *u8 = sys_mmap(64)
145 let c2: *u8 = sys_mmap(64)
146 lg_id("c1_" as *u8, nonce, c1)
147 lg_id("c2_" as *u8, nonce, c2)
148 ids[0] = c1 as i64
149 ids[1] = c2 as i64
150 drs[0] = C as i64
151 drs[1] = C as i64
152 crs[0] = A as i64
153 crs[1] = B as i64
154 amts[0] = 500000
155 amts[1] = 500000
156 let bC: i64 = led_balance(pfx, C)
157 let bA2: i64 = led_balance(pfx, A)
158 lg_ck(cnt, "T12 underfunded chain REFUSED" as *u8, led_chain(pfx, ids, drs, crs, amts, 2, C), 0 - 3)
159 lg_ck(cnt, "T12b refused chain left bal(C) untouched (zero partial state)" as *u8, led_balance(pfx, C), bC)
160 lg_ck(cnt, "T12c refused chain left bal(A) untouched" as *u8, led_balance(pfx, A), bA2)
161
162 // ---- T13: a funded chain commits EVERY leg, conservation still holds ----
163 amts[0] = 100
164 amts[1] = 100
165 lg_ck(cnt, "T13 funded chain committed both legs" as *u8, led_chain(pfx, ids, drs, crs, amts, 2, "" as *u8), 2)
166 let sum4: i64 = led_balance(pfx, A) + led_balance(pfx, B) + led_balance(pfx, C)
167 lg_ck(cnt, "T13b conservation holds after the chain" as *u8, sum4, 0)
168
169 // ---- T14: chain leg validation refuses the WHOLE chain on one bad leg ----
170 amts[0] = 100
171 amts[1] = 0 - 5
172 let bC2: i64 = led_balance(pfx, C)
173 lg_ck(cnt, "T14 one bad leg REFUSES the whole chain" as *u8, led_chain(pfx, ids, drs, crs, amts, 2, "" as *u8), 0 - 1)
174 lg_ck(cnt, "T14b bad-leg refusal wrote NOTHING" as *u8, led_balance(pfx, C), bC2)
175
176 lg_puts("nx_ledger_gate: pass=" as *u8); lg_putn(cnt[0])
177 lg_puts(" fail=" as *u8); lg_putn(cnt[1]); lg_puts("\n" as *u8)
178 if cnt[1] == 0 {
179 lg_puts("F981 nx_ledger: VERDICT=GREEN (conservation cross-checked, refusals leave zero state)\n" as *u8)
180 sys_exit(0)
181 return 0
182 }
183 lg_puts("F981 nx_ledger: VERDICT=RED\n" as *u8)
184 sys_exit(1)
185 return 1
186}