code wiki / _hdl_build / nx_cms_comments.nx

nx_cms_comments.nx source

↩ module page · 70 lines · 3744 B

1// nx_cms_comments.nx -- CMS COMMENT MODERATION (sovereign, offline, integer-deterministic). 2// The WordPress comments+Akismet class, made Nishi-native: spam scoring is a REPRODUCIBLE integer 3// heuristic computed ON-BOX (comments NEVER leave the machine for a cloud anti-spam service = 4// privacy-native, the exceed angle over Akismet), and the moderation state machine is EXACT. A 5// comment is innocent until a real moderation transition; public render shows ONLY approved comments 6// (pending/spam/trash are withheld) so spam NEVER auto-publishes. Legit comments are not stripped 7// (rule 25): a single weak signal stays below threshold and lands in the queue, not the spam bin. 8// Weights/threshold are the data-driven seam (production reads svc-config; rule 11). Composes the 9// nx_cms_store record format. license_tier: ORIGINAL 10import "nx_syscalls.nx" 11 12// moderation states 13const NX_CMT_PENDING: i64 = 0 14const NX_CMT_APPROVED: i64 = 1 15const NX_CMT_SPAM: i64 = 2 16const NX_CMT_TRASH: i64 = 3 17 18// sovereign spam-score weights/threshold (the data-driven seam; prod = svc-config, rule 11) 19const NX_CMT_W_LINK: i64 = 3 // per embedded link (http / https token) 20const NX_CMT_W_BANNED: i64 = 5 // per banned-token hit 21const NX_CMT_SPAM_THRESHOLD: i64 = 6 // score >= threshold -> auto-spam (needs 2+ signals; one weak hit stays PENDING) 22 23func cmt_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 24 25// count non-overlapping occurrences of NUL-terminated pat in buf[0..n) 26func cmt_count(buf: *u8, n: i64, pat: *u8) -> i64 { 27 let pl: i64 = cmt_slen(pat) 28 if pl == 0 { return 0 } 29 var c: i64 = 0 30 var i: i64 = 0 31 while i + pl <= n { 32 var j: i64 = 0 33 var ok: i64 = 1 34 while j < pl { if (buf[i+j] as i64) != (pat[j] as i64) { ok = 0; j = pl } else { j = j + 1 } } 35 if ok == 1 { c = c + 1; i = i + pl } else { i = i + 1 } 36 } 37 return c 38} 39 40// integer spam score for a comment body buf[0..n): links*W_LINK + banned*W_BANNED. Deterministic: 41// same bytes in -> same score out, every time, with no external call. 42func cmt_score(buf: *u8, n: i64) -> i64 { 43 let links: i64 = cmt_count(buf, n, "http" as *u8) 44 var banned: i64 = 0 45 banned = banned + cmt_count(buf, n, "casino" as *u8) 46 banned = banned + cmt_count(buf, n, "viagra" as *u8) 47 banned = banned + cmt_count(buf, n, "loan" as *u8) 48 return links * NX_CMT_W_LINK + banned * NX_CMT_W_BANNED 49} 50 51// classify a freshly-submitted comment from its score: SPAM if at/over threshold, else PENDING. 52// NEVER auto-APPROVED -- the moderation queue is the default and legit comments are not stripped. 53func cmt_classify(score: i64) -> i64 { 54 if score >= NX_CMT_SPAM_THRESHOLD { return NX_CMT_SPAM } 55 return NX_CMT_PENDING 56} 57 58// is a moderation transition from->to allowed? (exact state machine; no skipping a queue, and 59// NEVER spam->approved or trash->approved directly -- recovery routes back through pending first) 60func cmt_can_moderate(from: i64, to: i64) -> i64 { 61 if from == to { return 1 } // idempotent re-set 62 if from == NX_CMT_PENDING { if to == NX_CMT_APPROVED { return 1 } if to == NX_CMT_SPAM { return 1 } if to == NX_CMT_TRASH { return 1 } } 63 if from == NX_CMT_APPROVED { if to == NX_CMT_PENDING { return 1 } if to == NX_CMT_TRASH { return 1 } } 64 if from == NX_CMT_SPAM { if to == NX_CMT_PENDING { return 1 } if to == NX_CMT_TRASH { return 1 } } 65 // TRASH is terminal here (a restore must go back through PENDING out of band) 66 return 0 67} 68 69// only APPROVED comments are publicly visible (spam/pending/trash are withheld) 70func cmt_visible_public(status: i64) -> i64 { if status == NX_CMT_APPROVED { return 1 } return 0 }