code wiki / _hdl_build / nx_card_compile.nx

nx_card_compile.nx

buildroot/runtime/_hdl_build/nx_card_compile.nx

30986 B607 linesdepth 4pulls 5 transitivereach 0 importersview sourcekind tooltopic card
docsdependenciesstructsconstsfunctions

about

nx_card_compile.nx -- CompanionCard COMPILER (F917 rung-1, "first byte up"): elara_card.json (the character sheet SSOT) compiles DOWNWARD into elara_persona.txt, which the live gen daemon re-reads per request = the card becomes the byte-one source of who she is, no daemon deploy needed. Fail-closed: age < 18 REFUSES (adult-companion invariant enforced at the compiler, not by convention). Rule-13: the pre-card persona is banked ONCE to elara_persona.txt.bak-precard. Write is ATOMIC (tmp + rename; the daemon never sees a torn file). Composition keeps the battle-tested persona laws VERBATIM (never-AI, sends pics, EN-lock, first person, no stage directions) -- the card supplies the variable identity/personality half. usage: nx_card_compile [dir] (dir default /volume1/ai/gen; reads elara_card.json, writes elara_persona.txt) nx_card_compile import <card.png> [age=N] [dir] (CC2: a Tavern V2 PNG card -> the SSOT, then compile) nx_card_compile export <dir> <out.json> (CC2: the imported V2 source back out, byte-identical) CC2 COMMUNITY CARD IMPORT (companionchat, 2026-08-30): a Tavern V2 card is base64 JSON in a tEXt chunk keyed `chara` (nx_png_chunks walks it, base64.nx decodes it). Every V2 field is MAPPED into the SSOT or REFUSED BY NAME in a printed ledger -- never silently dropped; the decoded JSON is kept VERBATIM as elara_card.v2.json so `export` round-trips byte-stable by construction; the age gate stays fail-closed -- a V2 card carries no age field, so import REFUSES unless the card declares one or the operator passes age=N, and N < 18 refuses exactly as the native compiler does. An imported card composes from its own description/personality/scenario and NEVER inherits the native defaults (hair, eyes, relationship) -- those are Elara's, not the imported character's. license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0

dependencies 3 imports · 0 importers

nx_syscalls.nx nx_png_chunks.nx base64.nx nx_card_compile.nx

imports: nx_syscalls.nxnx_png_chunks.nxbase64.nx

imported by: nobody (leaf or entry point)

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main ccm_eq ccm_puts sys_write ccm_len sys_exit ccm_parse_age_arg ccm_len ↻ ccm_card_import sys_mmap nxa_die sys_write ↻ sys_exit ↻ nxa_lock_take nxa_lock_addr sys_write ↻ nxa_lock_give nxa_lock_addr ↻ nxa_report_overrun sys_write ↻ nxa_dump_printable sys_write ↻ nxa_dump_sizes sys_write ↻ sys_read_file sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_munmap sys_close ccm_puts ↻ png_find_text png_is png_len png_be32 png_type_is b64_decode b64_grab b64_dec_char

structs

none

consts

22const CC_MAGIC_1024: i64 = 1024
24const CC_OUTCAP: i64 = 65536
25const CC_STRCAP: i64 = 2048
26const CC_PATHCAP: i64 = 512
27const CC_MODE: i64 = 420
28const CC_MIN_AGE: i64 = 18
29const CC_NONE: i64 = 0 - 1
31const CC_V2CAP: i64 = 16384
32const CC_V2_FIELDS: i64 = 12
33const CC_LEDGER_CAP: i64 = 4096
34const CC_EXIT_USAGE: i64 = 2
35const CC_EXIT_REFUSED: i64 = 3
36const CC_EXIT_IO: i64 = 4
37const CC_CH_QUOTE: i64 = 34
38const CC_CH_BSLASH: i64 = 92
39const CC_CH_SPACE: i64 = 32
40const CC_CH_NL: i64 = 10
41const CC_CH_COMMA: i64 = 44
42const CC_CH_0: i64 = 48
43const CC_CH_9: i64 = 57
44const CC_DEC_BASE: i64 = 10
45const CC_AGE_ARG: *u8 = "age=" as *u8
46const CC_V2_SPEC: *u8 = "chara_card_v2" as *u8
47const CC_V2_KEYWORD: *u8 = "chara" as *u8
48const CC_SSOT: *u8 = "elara_card.json" as *u8
49const CC_SSOT_BAK: *u8 = "elara_card.json.bak-preimport" as *u8
50const CC_V2_SRC: *u8 = "elara_card.v2.json" as *u8
262const CC_CH_DOT: i64 = 46
263const CC_CH_BANG: i64 = 33
264const CC_CH_QMARK: i64 = 63

functions

52func ccm_cat(dst: *u8, off: i64, s: *u8) -> i64 { var o: i64 = off; var i: i64 = 0; while s[i] != (0 as u8) { dst[o] = s[i]; o = o + 1; i = i + 1 } return o }
53func ccm_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
54func ccm_catn(d: *u8, o: i64, v: i64) -> i64 { let t: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { d[o] = 45 as u8; o = o + 1; m = 0 - m } var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 } while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } var i: i64 = 0; while i < k { d[o] = t[k-1-i]; o = o + 1; i = i + 1 } return o }
55func ccm_puts(s: *u8) -> i64 { sys_write(1, s, ccm_len(s)); return 0 }
56func ccm_eq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] == b[i] { if a[i] == (0 as u8) { return 1 } i = i + 1 } return 0 }
58func ccm_pathjoin(dst: *u8, dir: *u8, name: *u8) -> i64
68func ccm_find(b: *u8, n: i64, pat: *u8) -> i64
called by 1: ccm_key_at calls 1: ccm_len
84func ccm_key_at(b: *u8, n: i64, key: *u8) -> i64
96func ccm_json_str(b: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64
126func ccm_json_int(b: *u8, n: i64, key: *u8) -> i64
148func ccm_json_arr(b: *u8, n: i64, key: *u8, out: *u8, cap: i64) -> i64
186func ccm_first_seg(s: *u8, out: *u8, cap: i64) -> i64
called by 1: ccm_compile
199func ccm_age_words(age: i64, d: *u8, off: i64) -> i64
called by 1: ccm_compile calls 2: ccm_catccm_catn
212func ccm_emit_jstr(dst: *u8, off: i64, s: *u8) -> i64
229func ccm_write_atomic(path: *u8, body: *u8, n: i64) -> i64
242func ccm_bank_once(dir: *u8, name: *u8, bakname: *u8) -> i64
265func ccm_cat_prose(dst: *u8, off: i64, s: *u8) -> i64
called by 1: ccm_compile calls 1: ccm_cat
278func ccm_compile(dir: *u8) -> i64
396func ccm_ledger(verdict: *u8, field: *u8, note: *u8) -> i64
407func ccm_map_str(json: *u8, jn: i64, key: *u8, dst: *u8, off: i64, present: *i64) -> i64
420func ccm_refuse_field(json: *u8, jn: i64, key: *u8, why: *u8, refused: *i64) -> i64
429func ccm_card_import(png_path: *u8, age_arg: i64, dir: *u8) -> i64
546func ccm_card_export(dir: *u8, out_path: *u8) -> i64
563func ccm_parse_age_arg(s: *u8) -> i64
called by 1: main calls 1: ccm_len
578func main(argc: i64, argv: *i64) -> i64