nx_xform_gate.nx source
↩ module page · 115 lines · 6239 B
1// nx_xform_gate.nx -- proves the transform-DAG engine: topological ordering, CYCLE refusal, the three
2// data-test operators, whole-token dep matching (the subtle bug: "avg" must NOT match "avg_price"), and
3// end-to-end DESCENDANT-ONLY fail-closed skipping over the real conf + azdemo store. D001 verdict via
4// nx_gate_verdict. expect_exit: 0 license_tier: ORIGINAL
5import "nx_gate_verdict.nx"
6import "nx_xform.nx"
7
8func xg_eq(a: i64, b: i64) -> i64 { if a == b { return 1 } return 0 }
9func xg_has(hay: *u8, needle: *u8) -> i64 {
10 var hn: i64 = 0
11 while hay[hn] != (0 as u8) { hn = hn + 1 }
12 var nl: i64 = 0
13 while needle[nl] != (0 as u8) { nl = nl + 1 }
14 var i: i64 = 0
15 while i + nl <= hn {
16 var j: i64 = 0
17 var eq: i64 = 1
18 while j < nl { if hay[i+j] != needle[j] { eq = 0 } j = j + 1 }
19 if eq == 1 { return 1 }
20 i = i + 1
21 }
22 return 0
23}
24// index of id in order[] (position); -1 if absent
25func xg_pos(order: *i64, n: i64, ids: *i64, name: *u8) -> i64 {
26 var i: i64 = 0
27 while i < n { if xf_streq(ids[order[i]] as *u8, name) == 1 { return i } i = i + 1 }
28 return 0 - 1
29}
30
31func main() -> i64 {
32 let ctr: *i64 = gv_ctr()
33 gv_head("nx_xform_gate -- models as data, topo-ordered, fail-closed data-tests" as *u8)
34
35 // ---- whole-token dep matching: the subtle correctness point --------------------------------
36 gv_check("T1 csv_has finds a whole element" as *u8, xg_eq(xf_csv_has("avg_price,max_size" as *u8, "max_size" as *u8), 1), ctr)
37 gv_check("T2 csv_has does NOT match a PREFIX (avg is not avg_price)" as *u8, xg_eq(xf_csv_has("avg_price" as *u8, "avg" as *u8), 0), ctr)
38 gv_check("T3 csv_has does NOT match a SUFFIX (price is not avg_price)" as *u8, xg_eq(xf_csv_has("avg_price" as *u8, "price" as *u8), 0), ctr)
39 gv_check("T4 a lone dash means no deps" as *u8, xg_eq(xf_csv_has("-" as *u8, "anything" as *u8), 0), ctr)
40
41 // ---- topological order on hand-built graphs -------------------------------------------------
42 // chain: c depends on b depends on a => order must be a,b,c
43 let ids: *i64 = sys_mmap(8 * 8) as *i64
44 let deps: *i64 = sys_mmap(8 * 8) as *i64
45 ids[0] = "c" as *u8 as i64
46 deps[0] = "b" as *u8 as i64
47 ids[1] = "a" as *u8 as i64
48 deps[1] = "-" as *u8 as i64
49 ids[2] = "b" as *u8 as i64
50 deps[2] = "a" as *u8 as i64
51 let order: *i64 = sys_mmap(8 * 8) as *i64
52 let em: i64 = xf_topo(ids, deps, 3, order)
53 var t5: i64 = 0
54 if em == 3 { if xg_pos(order, 3, ids, "a" as *u8) < xg_pos(order, 3, ids, "b" as *u8) { if xg_pos(order, 3, ids, "b" as *u8) < xg_pos(order, 3, ids, "c" as *u8) { t5 = 1 } } }
55 gv_check("T5 a<-b<-c chain topo-sorts to a,b,c regardless of file order" as *u8, t5, ctr)
56
57 // diamond: d deps b,c ; b deps a ; c deps a => a first, d last
58 let id2: *i64 = sys_mmap(8 * 8) as *i64
59 let dp2: *i64 = sys_mmap(8 * 8) as *i64
60 id2[0] = "d" as *u8 as i64
61 dp2[0] = "b,c" as *u8 as i64
62 id2[1] = "b" as *u8 as i64
63 dp2[1] = "a" as *u8 as i64
64 id2[2] = "c" as *u8 as i64
65 dp2[2] = "a" as *u8 as i64
66 id2[3] = "a" as *u8 as i64
67 dp2[3] = "-" as *u8 as i64
68 let ord2: *i64 = sys_mmap(8 * 8) as *i64
69 let em2: i64 = xf_topo(id2, dp2, 4, ord2)
70 var t6: i64 = 0
71 if em2 == 4 { if xg_pos(ord2, 4, id2, "a" as *u8) == 0 { if xg_pos(ord2, 4, id2, "d" as *u8) == 3 { t6 = 1 } } }
72 gv_check("T6 a diamond (d<-b,c<-a) puts a first and d last" as *u8, t6, ctr)
73
74 // CYCLE: a<-b, b<-a => emitted < m, engine refuses
75 let id3: *i64 = sys_mmap(8 * 8) as *i64
76 let dp3: *i64 = sys_mmap(8 * 8) as *i64
77 id3[0] = "a" as *u8 as i64
78 dp3[0] = "b" as *u8 as i64
79 id3[1] = "b" as *u8 as i64
80 dp3[1] = "a" as *u8 as i64
81 let ord3: *i64 = sys_mmap(8 * 8) as *i64
82 let em3: i64 = xf_topo(id3, dp3, 2, ord3)
83 gv_check("T7 a 2-cycle emits FEWER than all models -> detected as a non-DAG" as *u8, xg_eq(em3, 0), ctr)
84
85 // ---- data-test operators (known answers) ----------------------------------------------------
86 gv_check("T8a gt: 590 gt 400 passes" as *u8, xg_eq(xf_test(590, "gt" as *u8, 400), 1), ctr)
87 gv_check("T8b gt: 100 gt 400 fails" as *u8, xg_eq(xf_test(100, "gt" as *u8, 400), 0), ctr)
88 gv_check("T8c lt: 3 lt 10 passes" as *u8, xg_eq(xf_test(3, "lt" as *u8, 10), 1), ctr)
89 gv_check("T8d nonzero: 0 fails, 5 passes" as *u8, xg_eq(xf_test(0, "nonzero" as *u8, 0) + xf_test(5, "nonzero" as *u8, 0), 1), ctr)
90
91 // ---- END TO END over the real conf + azdemo store ------------------------------------------
92 let out: *u8 = sys_mmap(XF_OUT)
93 xf_order_json(out)
94 gv_puts(out)
95 gv_puts("\n" as *u8)
96 gv_check("T9 order verb resolves a DAG (ok:true) over the seeded conf" as *u8, xg_has(out, "\"ok\":true" as *u8), ctr)
97 // avg_price and max_size have no deps; summary depends on both -> summary must come AFTER both
98 var t10: i64 = 0
99 if xg_has(out, "\"order\":[\"avg_price\",\"max_size\"" as *u8) == 1 { t10 = 1 }
100 gv_check("T10 the no-dep models order before the dependent summary" as *u8, t10, ctr)
101
102 xf_run_json(out)
103 gv_puts(out)
104 gv_puts("\n---\n" as *u8)
105 gv_check("T11 run computes each model metric and tests it" as *u8, xg_has(out, "\"id\":\"avg_price\",\"deps\":\"-\",\"op\":\"mean\",\"result\":" as *u8), ctr)
106 gv_check("T12 the deliberately-failing bad_check model reports pass:false" as *u8, xg_has(out, "\"id\":\"bad_check\"" as *u8), ctr)
107 gv_check("T13 its dependent is SKIPPED (descendant-only fail-closed), not silently built" as *u8, xg_has(out, "SKIPPED (a dependency failed" as *u8), ctr)
108 // the UNRELATED summary must still build -- fail-closed skips DESCENDANTS, not the whole run
109 gv_check("T14 an UNRELATED model still builds despite the failure elsewhere (not global halt)" as *u8, xg_has(out, "\"id\":\"summary\",\"deps\":\"avg_price,max_size\",\"op\":\"count\"" as *u8), ctr)
110 gv_check("T15 the pipeline is honestly marked NOT passing (a test failed)" as *u8, xg_has(out, "\"pipeline_pass\":false" as *u8), ctr)
111
112 let rc: i64 = gv_verdict("XFORM-GATE" as *u8, ctr, "transform-DAG: models as data, topo-ordered, cycle-refusing, descendant-only fail-closed tests" as *u8)
113 sys_exit(rc)
114 return rc
115}