nx_coa_gate.nx source
↩ module page · 156 lines · 7000 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 let lp: *u8 = "knowledge/store/coagate-led-" as *u8
49 let cp: *u8 = "knowledge/store/coagate-coa-" as *u8
50 let nonce: i64 = sys_now_us()
51 let cnt: *i64 = sys_mmap(16) as *i64
52 cnt[0] = 0
53 cnt[1] = 0
54
55 let cash: *u8 = sys_mmap(64)
56 let loan: *u8 = sys_mmap(64)
57 let ghost: *u8 = sys_mmap(64)
58 let weird: *u8 = sys_mmap(64)
59 // ★NONCE THE KIND TOO (2026-07-31). Every ACCOUNT here is nonced per run, but the KIND was the
60 // hardcoded literal "unobtainium" -- and C6 REGISTERS a side for it in a PERSISTENT plane
61 // (knowledge/store/coagate-coa-). So C5, which requires that kind to have NO registered side,
62 // passed only on a virgin store and failed on every run afterwards: the gate poisoned its own
63 // fixture and violated rule 10 (safe to run twice). Nonce it and the C5->C6 pair stays intact
64 // and idempotent, with no fixture deletion needed.
65 let wkind: *u8 = sys_mmap(64)
66 cg_id("cash_" as *u8, nonce, cash)
67 cg_id("loan_" as *u8, nonce, loan)
68 cg_id("ghost_" as *u8, nonce, ghost)
69 cg_id("weird_" as *u8, nonce, weird)
70 cg_id("unobtainium_" as *u8, nonce, wkind)
71
72 let x1: *u8 = sys_mmap(64)
73 let x2: *u8 = sys_mmap(64)
74 cg_id("cx1_" as *u8, nonce, x1)
75 cg_id("cx2_" as *u8, nonce, x2)
76
77 let per: *u8 = sys_mmap(64)
78 let per2: *u8 = sys_mmap(64)
79 cg_id("2026-07_" as *u8, nonce, per)
80 cg_id("2026-08_" as *u8, nonce, per2)
81
82 let out: *i64 = sys_mmap(16) as *i64
83
84 cg_puts("NISHI-COA-GATE (F982 chart of accounts + period close)\n" as *u8)
85
86 // data-driven side map
87 coa_type_put(cp, "asset" as *u8, "debit" as *u8)
88 coa_type_put(cp, "liability" as *u8, "credit" as *u8)
89 coa_put(cp, cash, "asset" as *u8)
90 coa_put(cp, loan, "liability" as *u8)
91
92 // fund cash $1000.00 from the loan: debits cash, credits loan
93 led_xfer(lp, x1, cash, loan, 100000, "posted" as *u8)
94
95 // ---- C1: the RAW ledger balance is credits-debits, so cash reads NEGATIVE ----
96 cg_ck(cnt, "C1 raw led_balance(cash) is credits-debits" as *u8, led_balance(lp, cash), 0 - 100000)
97
98 // ---- C2: the CHART inverts it -- an asset reads its natural POSITIVE balance ----
99 cg_ck(cnt, "C2 coa_natural(cash) resolved (1=ok)" as *u8, coa_natural(lp, cp, cash, out), 1)
100 cg_ck(cnt, "C2a asset natural balance is POSITIVE $1000.00" as *u8, out[0], 100000)
101
102 // ---- C3: a liability is credit-normal, so it also reads positive ----
103 cg_ck(cnt, "C3 coa_natural(loan) resolved" as *u8, coa_natural(lp, cp, loan, out), 1)
104 cg_ck(cnt, "C3a liability natural balance is POSITIVE $1000.00" as *u8, out[0], 100000)
105
106 // ---- C4: FAIL-CLOSED -- an account with no registered type must NOT guess a side ----
107 out[0] = 424242
108 cg_ck(cnt, "C4 unregistered account FAILS CLOSED (0)" as *u8, coa_natural(lp, cp, ghost, out), 0)
109 cg_ck(cnt, "C4a fail-closed wrote NOTHING to out" as *u8, out[0], 424242)
110
111 // ---- C5: FAIL-CLOSED -- a known account whose KIND has no registered side ----
112 coa_put(cp, weird, wkind)
113 out[0] = 777777
114 cg_ck(cnt, "C5 unknown account KIND FAILS CLOSED (0)" as *u8, coa_natural(lp, cp, weird, out), 0)
115 cg_ck(cnt, "C5a fail-closed wrote NOTHING to out" as *u8, out[0], 777777)
116
117 // ---- C6: DATA-DRIVEN PROOF -- register the new kind's side at RUNTIME, no code change ----
118 coa_type_put(cp, wkind, "credit" as *u8)
119 cg_ck(cnt, "C6 new account KIND works after a DATA write alone" as *u8,
120 coa_natural(lp, cp, weird, out), 1)
121 cg_ck(cnt, "C6a and it resolves to a real balance" as *u8, out[0], 0)
122
123 // ---- C7/C8: period close is a fail-closed posting guard ----
124 cg_ck(cnt, "C7 open period ALLOWS posting" as *u8, coa_post_ok(cp, per), 1)
125 // C7a: the gate must PROVE its own setup landed. reg_put returns <0 on failure and
126 // coa_period_close returns it verbatim; discarding it made a FAILED CLOSE indistinguishable
127 // from a successful one, so the flake surfaced as whichever assertion read the store next
128 // (C8 in some runs, C2 in others -- a MOVING tooth is the signature of unchecked setup).
129 let cl1: i64 = coa_period_close(cp, per)
130 var cl1ok: i64 = 0
131 if cl1 >= 0 { cl1ok = 1 }
132 cg_ck(cnt, "C7a period close SUCCEEDS (setup proven, never assumed)" as *u8, cl1ok, 1)
133 cg_ck(cnt, "C8 closed period REFUSES posting" as *u8, coa_post_ok(cp, per), 0)
134 cg_ck(cnt, "C8a and reports itself closed" as *u8, coa_period_closed(cp, per), 1)
135
136 // ---- C9: closing is IDEMPOTENT (rule 10) ----
137 let cl2: i64 = coa_period_close(cp, per)
138 var cl2ok: i64 = 0
139 if cl2 >= 0 { cl2ok = 1 }
140 cg_ck(cnt, "C9a re-close also SUCCEEDS (idempotent path is a write too)" as *u8, cl2ok, 1)
141 cg_ck(cnt, "C9 re-closing is idempotent, still closed" as *u8, coa_period_closed(cp, per), 1)
142
143 // ---- C10: closing ONE period must not lock the next ----
144 cg_ck(cnt, "C10 the NEXT period is still open" as *u8, coa_post_ok(cp, per2), 1)
145
146 cg_puts("nx_coa_gate: pass=" as *u8); cg_putn(cnt[0])
147 cg_puts(" fail=" as *u8); cg_putn(cnt[1]); cg_puts("\n" as *u8)
148 if cnt[1] == 0 {
149 cg_puts("F982 nx_coa: VERDICT=GREEN (sign per kind, data-driven side map, fail-closed on unknown, period lock)\n" as *u8)
150 sys_exit(0)
151 return 0
152 }
153 cg_puts("F982 nx_coa: VERDICT=RED\n" as *u8)
154 sys_exit(1)
155 return 1
156}