code wiki / _hdl_build / nx_ad_intake.nx
nx_ad_intake.nx source
↩ module page · 144 lines · 5929 B
1// nx_ad_intake.nx -- LIB: advertiser SELF-SERVE SIGNUP / campaign creation for the "Brought to you
2// by" ad engine (the "businesses sign up to advertise" face). A business picks a goal, sets a flat
3// fee, and submits creative copy; we VALIDATE at the boundary (rule 12), then persist a campaign
4// record ADDITIVELY to the sovereign store (rule 13, append-only versioned). Idempotent (rule 10):
5// re-creating an unchanged campaign is a no-op.
6//
7// PRIVACY LAW (feedback-no-server-side-visitor-identity): this is an ADVERTISER B2B ACCOUNT -- a
8// business deliberately identifying itself as a paying customer. The campaign record holds ONLY
9// advertiser-supplied business data (name, goal, fee, banner, status). It has NO parameter and NO
10// field for any SITE-VISITOR identity -- signup can never become visitor tracking by construction.
11//
12// Record (store key adcamp:<id>): business<tab>goal<tab>fee<tab>banner<tab>status. Creative text is
13// stored RAW and HTML-ESCAPED at emission by nx_ad_serve (the proven boundary), so a "<script>" name
14// is safe on the page. Goals are DATA-DRIVEN (rule 11): a goal is valid iff adgoal:<goal> exists in
15// the store, so adding a goal needs no code change. license_tier: ORIGINAL
16import "nx_ad_serve.nx"
17import "nx_ad_store.nx"
18import "nx_seg_store.nx"
19import "nx_syscalls.nx"
20
21const IN_OK: i64 = 0
22const IN_BAD_GOAL: i64 = 0 - 1
23const IN_BAD_FEE: i64 = 0 - 2
24const IN_BAD_CREA: i64 = 0 - 3
25const IN_COMMIT_ERR: i64 = 0 - 4
26
27// append a non-negative int as decimal into dst at off; return new offset.
28func in_appn(dst: *u8, off: i64, v: i64) -> i64 {
29 if v == 0 { dst[off] = 48 as u8; return off + 1 }
30 var m: i64 = v
31 var o: i64 = off
32 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m }
33 let t: *u8 = sys_mmap(28)
34 var k: i64 = 0
35 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
36 var i: i64 = k - 1
37 while i >= 0 { dst[o] = t[i]; o = o + 1; i = i - 1 }
38 return o
39}
40
41// store key for a campaign id: "adcamp:" + id (NUL-terminated). out must hold id length + 8.
42func in_campaign_key(id: *u8, out: *u8) -> i64 {
43 var o: i64 = as_append(out, 0, "adcamp:" as *u8)
44 o = as_append(out, o, id)
45 out[o] = 0 as u8
46 return o
47}
48
49// build the campaign record bytes into out; returns byte length. Advertiser data ONLY.
50func in_build_record(business: *u8, goal: *u8, fee: i64, banner: *u8, status: *u8, out: *u8) -> i64 {
51 var o: i64 = as_append(out, 0, business)
52 out[o] = 9 as u8; o = o + 1
53 o = as_append(out, o, goal)
54 out[o] = 9 as u8; o = o + 1
55 o = in_appn(out, o, fee)
56 out[o] = 9 as u8; o = o + 1
57 o = as_append(out, o, banner)
58 out[o] = 9 as u8; o = o + 1
59 o = as_append(out, o, status)
60 out[o] = 0 as u8
61 return o
62}
63
64// data-driven goal validation: 1 iff adgoal:<goalname> exists in the store (rule 11).
65func in_goal_known(goalname: *u8) -> i64 {
66 let key: *u8 = sys_mmap(128)
67 var o: i64 = as_append(key, 0, "adgoal:" as *u8)
68 o = as_append(key, o, goalname)
69 key[o] = 0 as u8
70 let pq: *i64 = sys_mmap(16) as *i64
71 let lq: *i64 = sys_mmap(16) as *i64
72 if ads_get(key, pq, lq) == 1 { return 1 }
73 return 0
74}
75
76// the max flat fee we accept (config-hierarchy, rule 17): store adcfg:fee_max wins; absent -> the
77// bootstrap default (lowest tier). Guards against fat-finger / abuse at the boundary.
78func in_fee_max() -> i64 {
79 let pq: *i64 = sys_mmap(16) as *i64
80 let lq: *i64 = sys_mmap(16) as *i64
81 if ads_get("adcfg:fee_max" as *u8, pq, lq) != 1 { return 100000 }
82 let b: *u8 = pq[0] as *u8
83 let n: i64 = lq[0]
84 var v: i64 = 0
85 var i: i64 = 0
86 var go: i64 = 1
87 while go == 1 {
88 if i >= n { go = 0 } else {
89 let c: i64 = b[i] as i64
90 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); i = i + 1 } else { go = 0 } } else { go = 0 }
91 }
92 }
93 if v <= 0 { return 100000 }
94 return v
95}
96
97// creative bounds (boundary defense): business name + banner present and length-bounded. Bootstrap
98// bounds (move to store config later if needed). Escaping happens at emit (nx_ad_serve), not here.
99func in_creative_ok(business: *u8, banner: *u8) -> i64 {
100 let bl: i64 = as_len(business)
101 let tl: i64 = as_len(banner)
102 if bl < 1 { return 0 }
103 if bl > 80 { return 0 }
104 if tl < 1 { return 0 }
105 if tl > 200 { return 0 }
106 return 1
107}
108
109// 1 if the store's value for key byte-equals val[0..vlen]. Idempotent skip + read-back helper.
110func in_streq_store(key: *u8, val: *u8, vlen: i64) -> i64 {
111 let pq: *i64 = sys_mmap(16) as *i64
112 let lq: *i64 = sys_mmap(16) as *i64
113 if ads_get(key, pq, lq) != 1 { return 0 }
114 let b: *u8 = pq[0] as *u8
115 let n: i64 = lq[0]
116 if n != vlen { return 0 }
117 var i: i64 = 0
118 while i < n { if b[i] != val[i] { return 0 } i = i + 1 }
119 return 1
120}
121
122// CREATE a campaign. Validates goal (data-driven) -> fee (>=0, <=max) -> creative (present, bounded),
123// FAIL-CLOSED with a distinct code before any write. On success persists adcamp:<id> additively and
124// returns IN_OK (idempotent: unchanged -> no-op). No visitor identity touches this path.
125func in_create_campaign(id: *u8, business: *u8, goal: *u8, fee: i64, banner: *u8) -> i64 {
126 if in_goal_known(goal) != 1 { return IN_BAD_GOAL }
127 if fee < 0 { return IN_BAD_FEE }
128 if fee > in_fee_max() { return IN_BAD_FEE }
129 if in_creative_ok(business, banner) != 1 { return IN_BAD_CREA }
130
131 let rec: *u8 = sys_mmap(4096)
132 let rlen: i64 = in_build_record(business, goal, fee, banner, "staging" as *u8, rec)
133 let key: *u8 = sys_mmap(256)
134 in_campaign_key(id, key)
135
136 if in_streq_store(key, rec, rlen) == 1 { return IN_OK } // idempotent: already created unchanged
137
138 let w: *i64 = ss_begin()
139 ss_add(w, 1, key, rec, rlen)
140 let segid: i64 = ads_seg_next()
141 let rc: i64 = ss_commit(ADS_PREFIX, w, segid)
142 if rc != 0 { return IN_COMMIT_ERR }
143 return IN_OK
144}