nx_coa_gate.nx source
↩ module page · 163 lines · 7605 B
1// nx_coa_gate.nx -- F982 INDEPENDENT GATE: chart of accounts + period close.
2// Proves the sign convention actually inverts per account KIND, that the type->side map is genuinely
3// data-driven (a NEW kind invented at runtime works with no code change), that unknown types
4// FAIL CLOSED instead of guessing a side, and that a closed period refuses postings.
5// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
6
7import "nx_coa_lib.nx"
8
9func cg_puts(s: *u8) -> i64 {
10 var n: i64 = 0
11 while s[n] != (0 as u8) { n = n + 1 }
12 sys_write(1, s, n)
13 return 0
14}
15func cg_putn(v: i64) -> i64 {
16 let t: *u8 = sys_mmap(32)
17 var o: i64 = 0
18 var m: i64 = v
19 if m < 0 { t[o] = 45 as u8; o = o + 1; m = 0 - m }
20 let d: *u8 = sys_mmap(32)
21 var k: i64 = 0
22 if m == 0 { d[0] = 48 as u8; k = 1 }
23 while m > 0 { d[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
24 var i: i64 = 0
25 while i < k { t[o] = d[k - 1 - i]; o = o + 1; i = i + 1 }
26 sys_write(1, t, o)
27 return 0
28}
29func cg_ck(cnt: *i64, name: *u8, got: i64, want: i64) -> i64 {
30 if got == want {
31 cnt[0] = cnt[0] + 1
32 cg_puts(" PASS " as *u8); cg_puts(name); cg_puts(" = " as *u8); cg_putn(got); cg_puts("\n" as *u8)
33 return 1
34 }
35 cnt[1] = cnt[1] + 1
36 cg_puts(" FAIL " as *u8); cg_puts(name); cg_puts(" got " as *u8); cg_putn(got)
37 cg_puts(" want " as *u8); cg_putn(want); cg_puts("\n" as *u8)
38 return 0
39}
40func cg_id(tag: *u8, nonce: i64, out: *u8) -> i64 {
41 var o: i64 = mt_catcopy(out, 0, tag)
42 o = mt_catn(out, o, nonce)
43 out[o] = 0 as u8
44 return o
45}
46
47func main(argc: i64, argv: *i64) -> i64 {
48 // FIXTURE MOVED OUT OF THE SWEPT STORE (2026-08-07). knowledge/store/ is walked every 600s by
49 // the nx_segguard beat; this gate's fixture is one of TEN measured as actually folded by it. A
50 // fold landing mid-run rewrites the manifest under the code being measured, so a RED could not
51 // be attributed. Proven on the sibling defect: the SAME code went RED on a knowledge/store
52 // fixture and GREEN 24/24 on a /tmp one -- the RED tracked the FIXTURE, not the code.
53 // Created at SETUP, not teardown: a teardown does not run when a run crashes.
54 sys_mkdir("/tmp/coagate\x00" as *u8, 0x1ed)
55 let lp: *u8 = "/tmp/coagate/coagate-led-" as *u8
56 let cp: *u8 = "/tmp/coagate/coagate-coa-" as *u8
57 let nonce: i64 = sys_now_us()
58 let cnt: *i64 = sys_mmap(16) as *i64
59 cnt[0] = 0
60 cnt[1] = 0
61
62 let cash: *u8 = sys_mmap(64)
63 let loan: *u8 = sys_mmap(64)
64 let ghost: *u8 = sys_mmap(64)
65 let weird: *u8 = sys_mmap(64)
66 // ★NONCE THE KIND TOO (2026-07-31). Every ACCOUNT here is nonced per run, but the KIND was the
67 // hardcoded literal "unobtainium" -- and C6 REGISTERS a side for it in a PERSISTENT plane
68 // (the coagate-coa- plane). So C5, which requires that kind to have NO registered side,
69 // passed only on a virgin store and failed on every run afterwards: the gate poisoned its own
70 // fixture and violated rule 10 (safe to run twice). Nonce it and the C5->C6 pair stays intact
71 // and idempotent, with no fixture deletion needed.
72 let wkind: *u8 = sys_mmap(64)
73 cg_id("cash_" as *u8, nonce, cash)
74 cg_id("loan_" as *u8, nonce, loan)
75 cg_id("ghost_" as *u8, nonce, ghost)
76 cg_id("weird_" as *u8, nonce, weird)
77 cg_id("unobtainium_" as *u8, nonce, wkind)
78
79 let x1: *u8 = sys_mmap(64)
80 let x2: *u8 = sys_mmap(64)
81 cg_id("cx1_" as *u8, nonce, x1)
82 cg_id("cx2_" as *u8, nonce, x2)
83
84 let per: *u8 = sys_mmap(64)
85 let per2: *u8 = sys_mmap(64)
86 cg_id("2026-07_" as *u8, nonce, per)
87 cg_id("2026-08_" as *u8, nonce, per2)
88
89 let out: *i64 = sys_mmap(16) as *i64
90
91 cg_puts("NISHI-COA-GATE (F982 chart of accounts + period close)\n" as *u8)
92
93 // data-driven side map
94 coa_type_put(cp, "asset" as *u8, "debit" as *u8)
95 coa_type_put(cp, "liability" as *u8, "credit" as *u8)
96 coa_put(cp, cash, "asset" as *u8)
97 coa_put(cp, loan, "liability" as *u8)
98
99 // fund cash $1000.00 from the loan: debits cash, credits loan
100 led_xfer(lp, x1, cash, loan, 100000, "posted" as *u8)
101
102 // ---- C1: the RAW ledger balance is credits-debits, so cash reads NEGATIVE ----
103 cg_ck(cnt, "C1 raw led_balance(cash) is credits-debits" as *u8, led_balance(lp, cash), 0 - 100000)
104
105 // ---- C2: the CHART inverts it -- an asset reads its natural POSITIVE balance ----
106 cg_ck(cnt, "C2 coa_natural(cash) resolved (1=ok)" as *u8, coa_natural(lp, cp, cash, out), 1)
107 cg_ck(cnt, "C2a asset natural balance is POSITIVE $1000.00" as *u8, out[0], 100000)
108
109 // ---- C3: a liability is credit-normal, so it also reads positive ----
110 cg_ck(cnt, "C3 coa_natural(loan) resolved" as *u8, coa_natural(lp, cp, loan, out), 1)
111 cg_ck(cnt, "C3a liability natural balance is POSITIVE $1000.00" as *u8, out[0], 100000)
112
113 // ---- C4: FAIL-CLOSED -- an account with no registered type must NOT guess a side ----
114 out[0] = 424242
115 cg_ck(cnt, "C4 unregistered account FAILS CLOSED (0)" as *u8, coa_natural(lp, cp, ghost, out), 0)
116 cg_ck(cnt, "C4a fail-closed wrote NOTHING to out" as *u8, out[0], 424242)
117
118 // ---- C5: FAIL-CLOSED -- a known account whose KIND has no registered side ----
119 coa_put(cp, weird, wkind)
120 out[0] = 777777
121 cg_ck(cnt, "C5 unknown account KIND FAILS CLOSED (0)" as *u8, coa_natural(lp, cp, weird, out), 0)
122 cg_ck(cnt, "C5a fail-closed wrote NOTHING to out" as *u8, out[0], 777777)
123
124 // ---- C6: DATA-DRIVEN PROOF -- register the new kind's side at RUNTIME, no code change ----
125 coa_type_put(cp, wkind, "credit" as *u8)
126 cg_ck(cnt, "C6 new account KIND works after a DATA write alone" as *u8,
127 coa_natural(lp, cp, weird, out), 1)
128 cg_ck(cnt, "C6a and it resolves to a real balance" as *u8, out[0], 0)
129
130 // ---- C7/C8: period close is a fail-closed posting guard ----
131 cg_ck(cnt, "C7 open period ALLOWS posting" as *u8, coa_post_ok(cp, per), 1)
132 // C7a: the gate must PROVE its own setup landed. reg_put returns <0 on failure and
133 // coa_period_close returns it verbatim; discarding it made a FAILED CLOSE indistinguishable
134 // from a successful one, so the flake surfaced as whichever assertion read the store next
135 // (C8 in some runs, C2 in others -- a MOVING tooth is the signature of unchecked setup).
136 let cl1: i64 = coa_period_close(cp, per)
137 var cl1ok: i64 = 0
138 if cl1 >= 0 { cl1ok = 1 }
139 cg_ck(cnt, "C7a period close SUCCEEDS (setup proven, never assumed)" as *u8, cl1ok, 1)
140 cg_ck(cnt, "C8 closed period REFUSES posting" as *u8, coa_post_ok(cp, per), 0)
141 cg_ck(cnt, "C8a and reports itself closed" as *u8, coa_period_closed(cp, per), 1)
142
143 // ---- C9: closing is IDEMPOTENT (rule 10) ----
144 let cl2: i64 = coa_period_close(cp, per)
145 var cl2ok: i64 = 0
146 if cl2 >= 0 { cl2ok = 1 }
147 cg_ck(cnt, "C9a re-close also SUCCEEDS (idempotent path is a write too)" as *u8, cl2ok, 1)
148 cg_ck(cnt, "C9 re-closing is idempotent, still closed" as *u8, coa_period_closed(cp, per), 1)
149
150 // ---- C10: closing ONE period must not lock the next ----
151 cg_ck(cnt, "C10 the NEXT period is still open" as *u8, coa_post_ok(cp, per2), 1)
152
153 cg_puts("nx_coa_gate: pass=" as *u8); cg_putn(cnt[0])
154 cg_puts(" fail=" as *u8); cg_putn(cnt[1]); cg_puts("\n" as *u8)
155 if cnt[1] == 0 {
156 cg_puts("F982 nx_coa: VERDICT=GREEN (sign per kind, data-driven side map, fail-closed on unknown, period lock)\n" as *u8)
157 sys_exit(0)
158 return 0
159 }
160 cg_puts("F982 nx_coa: VERDICT=RED\n" as *u8)
161 sys_exit(1)
162 return 1
163}