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}