code wiki / (root) / nx_chat_store.nx

nx_chat_store.nx

buildroot/runtime/nx_chat_store.nx

45147 B1025 linesdepth 5pulls 8 transitivereach 0 importersview sourcekind tooltopic chat
docsdependenciesstructsconstsfunctions

about

nx_chat_store.nx -- C1 of the comms lane: durable STORE-AND-FORWARD chat history on the sovereign seg-store plane. Contract symbol cs_store_forward == the /compare/comms C1 watch contract. DONE-RULE (pre-declared in comms.plan before this organ existed): a message sent to an offline member is delivered on reconnect byte-identical and in order; history survives room close; the store is additive-only with soft-delete and REFUSES loudly at its conf-named size budget instead of silently dropping. REFEREE: nx_chat_store_gate (the flip is the receipt, the gate is the proof). WHY: the live room chat is nx_chat_ring -- bounded, in-memory, gone when the room closes. Its own header declares persistence as pluggable (disk / memory / future MLS-encrypted); this organ is the disk layer, pure COMPOSITION of incumbents, no second ruler: nx_store_seed_lib sts_lock/sts_unlock (the shared <prefix>plock domain) + sts_seed (explicit room creation ONLY) + sts_atoi/sts_rowkey/sts_mm nx_seg_store ss_open_cached + ss_hget (the amplification-safe read path, seq356) + ss_begin_cap/ss_add/ss_commit_cas (O(1) append; CAS turns a lost update into a loud CHAT-RETRY -- backpressure, never corruption) nx_chatmsg cm_advance -- the monotonic receipt ladder; a delivery cursor NEVER regresses MODEL: one plane per room at <store_root>chat_<room>- . q:<i> message row m|<seq>|<epoch_ms>|<kind>|<sender>|<hexbody> (seq == i+1, ASSERTED at read) q:n row count (the store's own counter -- two counters of one population, free audit) meta:bytes cumulative DECODED body bytes (the budget ruler: cumulative, not a ring) cur:<member> per-member delivery cursor (store-and-forward: reconnect = fetch since cursor) del:<seq> soft-delete tombstone (additive-only, rule 13; history is never rewritten) BODIES ARE HEX-ARMORED: plane rows are newline-framed text and chat bodies are arbitrary bytes (tomorrow: MLS ciphertext), so rows carry lowercase hex and the BUDGET COUNTS DECODED BYTES -- the armor never distorts the policy. Byte-identity round-trip is a gate tooth, not a promise. KINDS are nx_chat_ring's SEALED wire constants, validated as the range 1..6 BY CITATION: a cross-import is refused by the import graph (the ring pins nx_syscalls_x86_64, the seg-store pins nx_syscalls; importing both duplicates the syscall layer and the duplicate guard fails the build). If the ring grows a kind, NX_CHAT_KIND_N moves and CS_KIND_MAX here must follow. EVERY POLICY NUMBER LIVES IN THE CONF (rule 11): knowledge/comms/chatstore.conf rows store_root| room_bytes_cliff| room_msgs_cliff| body_bytes_max| A missing conf row REFUSES BY NAME -- no silent code default. FAIL-CLOSED: appending to an unopened room is REFUSED (a typo must not conjure a plane -- the nx_plane_append law); open of an existing room is REFUSED (create-only, idempotent-safe, rule 10); every refusal ANNOUNCES its reason and writes NOTHING. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 5 imports · 0 importers

nx_syscalls.nx nx_itoa_lib.nx nx_store_seed_lib.nx nx_seg_store.nx nx_chatmsg.nx nx_chat_store.nx

imports: nx_syscalls.nxnx_itoa_lib.nxnx_store_seed_lib.nxnx_seg_store.nxnx_chatmsg.nx

imported by: nobody (leaf or entry point)

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

main cs_usage cs_w sys_write sys_exit cs_eq cs_open cs_tok_ok cs_w ↻ sts_mm 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 ↻ sts_werr sys_write ↻ sys_exit ↻ cs_prefix cs_tok_ok ↻ cs_confs sts_mm ↻ sys_read_file sys_openat_rd sys_lseek sys_mmap ↻ sys_read sys_munmap sys_close cs_len

structs

none

consts

46const CS_EXIT_OK: i64 = 0
47const CS_EXIT_USAGE: i64 = 2
48const CS_EXIT_REFUSED: i64 = 3
49const CS_EXIT_RETRY: i64 = 4
50const CS_EXIT_CORRUPT: i64 = 5
52const CS_NAME_MAX: i64 = 64 // room/member/sender token cap; keeps cur:<member> inside key caps
53const CS_PFX_CAP: i64 = 256 // store_root + chat_ + room + - + NUL
54const CS_ROW_OVH: i64 = 128 // row framing around the hex body
55const CS_WSLACK: i64 = 65536 // writer slack, same margin the seed lib uses (STS_WSLACK)
56const CS_CONF_CAP: i64 = 192 // one conf value
57const CS_KIND_MIN: i64 = 1 // NX_CHAT_KIND_TEXT (nx_chat_ring sealed kinds, by citation)
58const CS_KIND_MAX: i64 = 6 // NX_CHAT_KIND_HANDRAISE (== NX_CHAT_KIND_N - 1)
59const CS_KIND_SYS: i64 = 4 // NX_CHAT_KIND_SYS -- the room-open system row
60const CS_NL: i64 = 10
61const CS_PIPE: i64 = 124
62const CS_LOW_M: i64 = 109 // ASCII m -- the row marker

functions

64func cs_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
65func cs_wn(s: *u8, n: i64) -> i64 { sys_write(1, s, n); return 0 }
called by 1: cs_fetch calls 1: sys_write
66func cs_n(v: i64) -> i64 { nxi_out(v); return 0 }
67func cs_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
68func cs_eq(a: *u8, b: *u8) -> i64
called by 2: cs_purgemain
75func cs_tok_ok(s: *u8) -> i64
92func cs_hexe(src: *u8, n: i64, dst: *u8) -> i64
called by 1: cs_rowbuild
104func cs_hexv(c: i64) -> i64
called by 1: cs_hexd
111func cs_hexd(src: *u8, n: i64, dst: *u8) -> i64
called by 1: main calls 1: cs_hexv
126func cs_confs(confpath: *u8, key: *u8, out: *u8, cap: i64) -> i64
161func cs_confn(confpath: *u8, key: *u8) -> i64
167func cs_refuse_conf(key: *u8, confpath: *u8) -> i64
176func cs_prefix(confpath: *u8, room: *u8, out: *u8) -> i64
188func cs_put_key(prefix: *u8, key: *u8, val: *u8, vlen: i64) -> i64
194func cs_curkey(member: *u8, out: *u8) -> i64
called by 2: cs_cursorcs_ack calls 1: ss_cat
200func cs_delkey(seq: i64, out: *u8) -> i64
207func cs_rowseq(p: *u8, l: i64) -> i64
called by 1: cs_fetch
226func cs_rowbuild(seq: i64, kind: i64, sender: *u8, body: *u8, blen: i64, out: *u8) -> i64
242func cs_open(room: *u8, opener: *u8, confpath: *u8) -> i64
295func cs_store_forward(room: *u8, sender: *u8, kind: i64, body: *u8, blen: i64, confpath: *u8) -> i64
402func cs_fetch(room: *u8, since: i64, maxn: i64, confpath: *u8) -> i64
477func cs_cursor(room: *u8, member: *u8, confpath: *u8) -> i64
502func cs_ack(room: *u8, member: *u8, seq: i64, confpath: *u8) -> i64
550func cs_del(room: *u8, seq: i64, actor: *u8, confpath: *u8) -> i64
587func cs_status(room: *u8, confpath: *u8) -> i64
644func cs_setretention(room: *u8, ms: i64, actor: *u8, confpath: *u8) -> i64
680func cs_retention(room: *u8, confpath: *u8) -> i64
780func cs_rowhead(p: *u8, l: i64) -> i64
called by 1: cs_purge
799func cs_purge(room: *u8, actor: *u8, confirm: *u8, confpath: *u8) -> i64
932func cs_usage() -> i64
called by 1: main calls 1: cs_w
936func cs_confpick(argc: i64, argv: *i64, idx: i64) -> *u8
called by 1: main
940func cs_argn(argv: *i64, idx: i64) -> i64
called by 1: main calls 2: sts_atoics_len
945func main(argc: i64, argv: *i64) -> i64