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 }