code wiki / _hdl_build / nx_nofloat_arch_config_gate.nx
nx_nofloat_arch_config_gate.nx source
↩ module page · 153 lines · 11388 B
1// nx_nofloat_arch_config_gate.nx -- proves ARCH-CONFIGURABLE inference: read the model's dims from GGUF
2// METADATA (nac_read_config) instead of hardcoding, then run the REAL no-float forward with those read dims
3// and confirm it STILL generates ' Paris' (id 12095). This is the keystone that lets our inference run ANY
4// Qwen2/Llama-schema gguf -- the real 0.5B AND a small from-scratch model -> closes the sovereign train->serve
5// loop (our f32 trainer -> gguf writer -> THIS inference). expect_exit: 0 license_tier: ORIGINAL
6//
7// D001 MIGRATION 2026-08-25. This gate hand-rolled its verdict: a pass/total pair, inline PASS/FAIL prints and
8// a prose "verdict=" line, with main returning a bare 0 or 1. A gate whose EXIT CODE does not carry its verdict
9// can print FAIL and still exit 0, silently blessing every failure it finds -- so it now inherits
10// nx_gate_verdict. gv_ctr makes declared and executed tooth counts ONE number (a tooth that stops running can
11// no longer read GREEN), gv_check names every tooth, and gv_verdict owns the exit code: 0 GREEN / 1 RED / 3 SKIP.
12//
13// THE MODEL FILE IS A PRECONDITION, NOT A SUBJECT. If the fixture gguf is absent this gate proves NOTHING about
14// arch-configurable inference; it used to return 1, which reports its own environment in the same word it
15// reports a regression. It now SKIPs. SKIP is not a pass -- it blocks any claim that this works.
16//
17// The old single compound T1 (seven dims nested in one if) is decomposed into one tooth per dimension. The
18// predicate set is unchanged; what changes is that a failure now NAMES the dim that drifted instead of saying
19// "config mismatch" and leaving the reader to guess which of the seven conjuncts fired.
20import "nx_syscalls.nx"
21import "nx_gate_verdict.nx"
22import "nx_tier.nx"
23import "nx_le.nx"
24import "nx_tensor.nx"
25import "nx_gguf.nx"
26import "nx_gguf_load.nx"
27import "nx_gguf_meta.nx"
28import "nx_nofloat_llm.nx"
29import "nx_nofloat_tok.nx"
30import "nx_nofloat_arch.nx"
31
32// The dims the fixture must REPORT. Named for the schema slot each one pins, never for its value: the whole
33// point of this gate is that these arrive from the gguf METADATA rather than from the inference code.
34const ACG_EXPECT_EMBED_DIM: i64 = 896
35const ACG_EXPECT_LAYERS: i64 = 24
36const ACG_EXPECT_HEADS: i64 = 14
37const ACG_EXPECT_KV_HEADS: i64 = 2
38const ACG_EXPECT_HEAD_DIM: i64 = 64
39const ACG_EXPECT_FFN_DIM: i64 = 4864
40const ACG_EXPECT_ROPE_SCALE_Q16: i64 = 8192
41// vocab is read from a TENSOR SHAPE, not a metadata key, so it is bounded rather than pinned: any Qwen2.5
42// tokenizer build lands in this window and a wrong tensor lands nowhere near it.
43const ACG_VOCAB_LO: i64 = 151000
44const ACG_VOCAB_HI: i64 = 152500
45// the argmax the real 0.5B must still produce for "The capital of France is" -- the no-regression anchor.
46const ACG_EXPECT_NEXT_TOKEN_ID: i64 = 12095
47// prompt slots the scratch buffers are sized for (the prompt is short; this bounds every MAXT-scaled arena).
48const ACG_PROMPT_SLOTS: i64 = 8
49
50func acg_eq(got: i64, want: i64) -> i64 { if got == want { return 1 } return 0 }
51func acg_in(v: i64, lo: i64, hi: i64) -> i64 { if v < lo { return 0 } if v > hi { return 0 } return 1 }
52func aslen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
53
54func main() -> i64 {
55 let ctr: *i64 = gv_ctr()
56 gv_head("nx_nofloat_arch_config_gate -- the no-float forward takes its dims from GGUF metadata (nac_read_config) and still generates correctly on the real Qwen2.5-0.5B" as *u8)
57 let note: *u8 = "the forward's dims came out of the gguf metadata, and the real 0.5B still argmaxes ' Paris' from them" as *u8
58
59 let path: *u8 = "/home/elderwesto/nx_stage/nx_real_model.gguf\x00" as *u8
60 let len_out: *i64 = sys_mmap(8) as *i64; len_out[0]=0
61 let buf: *u8 = sys_read_file(path, len_out)
62 var have_model: i64 = 0
63 if buf != (0 as *u8) { have_model = 1 }
64 if gv_need("the fixture model /home/elderwesto/nx_stage/nx_real_model.gguf" as *u8, have_model, ctr) == 0 {
65 let rc_absent: i64 = gv_verdict("NOFLOAT-ARCH-CONFIG" as *u8, ctr, note)
66 sys_exit(rc_absent)
67 return rc_absent
68 }
69
70 let hdr: *NxGgufHeader = sys_mmap(NX_GGUF_HDR_BYTES) as *NxGgufHeader
71 var parsed: i64 = 0
72 if nx_gguf_parse(buf, len_out[0], hdr) == NX_GGUF_OK { parsed = 1 }
73 if gv_check("T0 the fixture gguf parses -- nx_gguf_parse returns NX_GGUF_OK" as *u8, parsed, ctr) == 0 {
74 let rc_parse: i64 = gv_verdict("NOFLOAT-ARCH-CONFIG" as *u8, ctr, note)
75 sys_exit(rc_parse)
76 return rc_parse
77 }
78
79 // ---- READ CONFIG FROM METADATA (the capability under test) ----
80 let cfg: *i64 = sys_mmap(16*8) as *i64
81 let arch: *u8 = sys_mmap(64)
82 var cfg_ok: i64 = 0
83 if nac_read_config(buf, len_out[0], hdr, cfg, arch) == 0 { cfg_ok = 1 }
84 if gv_check("T0b nac_read_config returns 0 -- every arch metadata key it needs is present and readable" as *u8, cfg_ok, ctr) == 0 {
85 let rc_cfg: i64 = gv_verdict("NOFLOAT-ARCH-CONFIG" as *u8, ctr, note)
86 sys_exit(rc_cfg)
87 return rc_cfg
88 }
89 let ne: i64=cfg[0]; let NL: i64=cfg[1]; let NH: i64=cfg[2]; let NKV: i64=cfg[3]; let hd: i64=cfg[4]; let qd: i64=cfg[5]; let kvd: i64=cfg[6]; let fd: i64=cfg[7]; let scale: i64=cfg[8]
90 gv_puts(" metadata arch='" as *u8); gv_puts(arch); gv_puts("' -> D=" as *u8); gv_num(ne); gv_puts(" layers=" as *u8); gv_num(NL); gv_puts(" heads=" as *u8); gv_num(NH); gv_puts(" kv=" as *u8); gv_num(NKV); gv_puts(" head_dim=" as *u8); gv_num(hd); gv_puts(" ffn=" as *u8); gv_num(fd); gv_puts(" scale_q16=" as *u8); gv_num(scale); gv_puts("\n" as *u8)
91
92 // vocab from output.weight dim_1 (arch-derived, not hardcoded)
93 let no: *u8="output.weight\x00" as *u8; let ti_o: nx_int=nx_gguf_find_tensor(hdr, no, 13)
94 let oh: *NxGgufTensorInfo=nx_gguf_tensor_at(hdr, ti_o); let oh_base: i64=hdr.data_off+oh.offset; let oh_ty: i64=oh.ggml_type; let vocab: i64=oh.dim_1
95 gv_puts(" vocab from output.weight dim_1 = " as *u8); gv_num(vocab); gv_puts("\n" as *u8)
96
97 // T1: the config READ FROM METADATA must be the known Qwen2.5-0.5B geometry -- one tooth per dim, so a
98 // drift names the dim instead of collapsing seven conjuncts into one unreadable FAIL.
99 gv_check("T1a metadata embedding dim D == 896" as *u8, acg_eq(ne, ACG_EXPECT_EMBED_DIM), ctr)
100 gv_check("T1b metadata block count == 24 layers" as *u8, acg_eq(NL, ACG_EXPECT_LAYERS), ctr)
101 gv_check("T1c metadata attention head count == 14" as *u8, acg_eq(NH, ACG_EXPECT_HEADS), ctr)
102 gv_check("T1d metadata kv head count == 2 (grouped-query)" as *u8, acg_eq(NKV, ACG_EXPECT_KV_HEADS), ctr)
103 gv_check("T1e metadata head_dim == 64" as *u8, acg_eq(hd, ACG_EXPECT_HEAD_DIM), ctr)
104 gv_check("T1f metadata ffn dim == 4864" as *u8, acg_eq(fd, ACG_EXPECT_FFN_DIM), ctr)
105 gv_check("T1g metadata rope scale q16 == 8192" as *u8, acg_eq(scale, ACG_EXPECT_ROPE_SCALE_Q16), ctr)
106
107 // T2: vocab comes off the output.weight tensor SHAPE, so it is bounded, not pinned.
108 gv_check("T2 vocab read from the output.weight dim_1 shape lands in the Qwen2.5 window 151000..152500" as *u8, acg_in(vocab, ACG_VOCAB_LO, ACG_VOCAB_HI), ctr)
109
110 // ---- T3: run the forward with the METADATA-READ dims -> must still argmax ' Paris' (12095) ----
111 let voff: *i64=sys_mmap(8) as *i64; let vty: *i64=sys_mmap(8) as *i64
112 var mfirst: i64=0; var nm_c: i64=0; var vfirst: i64=0
113 let km: *u8="tokenizer.ggml.merges\x00" as *u8; let kt: *u8="tokenizer.ggml.tokens\x00" as *u8
114 if nx_gguf_meta_find(buf, len_out[0], hdr, km, aslen(km), voff, vty)==NX_GMETA_OK { nm_c=nx_gguf_meta_array_count(buf, voff[0]); mfirst=nx_gguf_meta_array_first_elt_off(buf, voff[0]) }
115 if nx_gguf_meta_find(buf, len_out[0], hdr, kt, aslen(kt), voff, vty)==NX_GMETA_OK { vfirst=nx_gguf_meta_array_first_elt_off(buf, voff[0]) }
116 let nt: *u8="token_embd.weight\x00" as *u8; let nn: *u8="output_norm.weight\x00" as *u8
117 let ti_e: nx_int=nx_gguf_find_tensor(hdr, nt, 17); let te: *NxGgufTensorInfo=nx_gguf_tensor_at(hdr, ti_e); let te_base: i64=hdr.data_off+te.offset; let te_ty: i64=te.ggml_type
118 let gout: *i64=sys_mmap(ne*8) as *i64; load_named_q16(buf, hdr, nn, 18, gout, ne)
119 let MAXT: i64=ACG_PROMPT_SLOTS
120 let wb: *i64=sys_mmap(12*8) as *i64
121 wb[0]=sys_mmap(ne*8) as i64; wb[1]=sys_mmap(qd*ne*8) as i64; wb[2]=sys_mmap(kvd*ne*8) as i64; wb[3]=sys_mmap(kvd*ne*8) as i64; wb[4]=sys_mmap(ne*qd*8) as i64
122 wb[5]=sys_mmap(ne*8) as i64; wb[6]=sys_mmap(ne*fd*8) as i64; wb[7]=sys_mmap(ne*fd*8) as i64; wb[8]=sys_mmap(fd*ne*8) as i64
123 wb[9]=sys_mmap(qd*8) as i64; wb[10]=sys_mmap(kvd*8) as i64; wb[11]=sys_mmap(kvd*8) as i64
124 let sb: *i64=sys_mmap(14*8) as *i64
125 sb[0]=sys_mmap(MAXT*ne*8) as i64; sb[1]=sys_mmap(MAXT*qd*8) as i64; sb[2]=sys_mmap(MAXT*kvd*8) as i64; sb[3]=sys_mmap(MAXT*kvd*8) as i64; sb[4]=sys_mmap(MAXT*qd*8) as i64
126 sb[5]=sys_mmap(MAXT*8) as i64; sb[6]=sys_mmap(MAXT*8) as i64; sb[7]=sys_mmap(MAXT*ne*8) as i64; sb[8]=sys_mmap(MAXT*fd*8) as i64; sb[9]=sys_mmap(MAXT*fd*8) as i64
127 sb[10]=sys_mmap(MAXT*fd*8) as i64; sb[11]=sys_mmap(MAXT*ne*8) as i64; sb[12]=sys_mmap(MAXT*ne*8) as i64; sb[13]=sys_mmap(MAXT*ne*8) as i64
128 let nm: *u8=sys_mmap(64); let freqs: *i64=sys_mmap(32*8) as *i64; rope_freqs(freqs, hd)
129 let tmp: *i64=sys_mmap(64*256*8) as *i64
130 let ids: *i64=sys_mmap(MAXT*8) as *i64; let tokp: *i64=sys_mmap(MAXT*8) as *i64; let tokl: *i64=sys_mmap(MAXT*8) as *i64
131 let input: *u8="The capital of France is\x00" as *u8
132 let nprompt: i64=tk_bpe_encode(buf, mfirst, nm_c, vfirst, vocab, input, aslen(input), tokp, tokl, ids)
133 // cfgA/cfgF built ENTIRELY from the metadata-read config
134 let cfgA: *i64=sys_mmap(8*8) as *i64; cfgA[0]=nprompt; cfgA[1]=ne; cfgA[2]=NH; cfgA[3]=NKV; cfgA[4]=hd; cfgA[5]=qd; cfgA[6]=kvd; cfgA[7]=scale
135 let cfgF: *i64=sys_mmap(4*8) as *i64; cfgF[0]=nprompt; cfgF[1]=ne; cfgF[2]=fd
136 let x: *i64=sys_mmap(MAXT*ne*8) as *i64; let hout: *i64=sys_mmap(MAXT*ne*8) as *i64
137 var ei: i64=0; while ei<nprompt { dequant_row(buf, te_base, te_ty, ids[ei], ne, ((x as i64)+ei*ne*8) as *i64, tmp); ei=ei+1 }
138 run_stack(buf, hdr, x, hout, wb, sb, nm, freqs, cfgA, cfgF, NL, 0)
139 let normed: *i64=sys_mmap(ne*8) as *i64; rmsnorm_gamma_row_q24(hout, gout, (nprompt-1)*ne, ne, normed, 0)
140 let idout: *i64=sys_mmap(8) as *i64; let lgout: *i64=sys_mmap(8) as *i64
141 let hp: *i64=sys_mmap(8*8) as *i64; hp[0]=buf as i64; hp[1]=oh_base; hp[2]=oh_ty; hp[3]=normed as i64; hp[4]=vocab; hp[5]=ne; hp[6]=idout as i64; hp[7]=lgout as i64
142 let nextid: i64=head_argmax_pool(hp)
143 gv_puts(" forward('The capital of France is') with METADATA-READ config -> next id=" as *u8); gv_num(nextid); gv_puts("\n" as *u8)
144 gv_check("T3 no-regression: the arch-config forward argmaxes 12095 (the ' Paris' token) from metadata-read dims" as *u8, acg_eq(nextid, ACG_EXPECT_NEXT_TOKEN_ID), ctr)
145
146 gv_puts("\n ARCH-CONFIGURABLE INFERENCE: the no-float forward now takes its dims from GGUF metadata, so ANY Qwen2/Llama-\n" as *u8)
147 gv_puts(" schema model runs -- the real 0.5B AND a small from-scratch one. This is the keystone that lets OUR f32-trained\n" as *u8)
148 gv_puts(" model (-> gguf writer ->) generate on OUR inference: the fully-sovereign train->serve loop.\n" as *u8)
149
150 let rc: i64 = gv_verdict("NOFLOAT-ARCH-CONFIG" as *u8, ctr, note)
151 sys_exit(rc)
152 return rc
153}