code wiki / _hdl_build / nx_swap_gate.nx
nx_swap_gate.nx source
↩ module page · 165 lines · 11245 B
1// nx_swap_gate.nx -- GATE: gamified community swap + sovereign ads. T1 species catalog + gardeners + empty dex.
2// T2 ask/give matching + AREA isolation (find offers near me, not across the country). T3 THE SWAP exchange
3// (claim an offer -> get the plant by swapping, not buying; dex grows). T4 gamification (XP -> LEVEL up). T5
4// SETS + BADGES ("gotta grow 'em all"; incomplete gardener gets no badge). T6 the sovereign board renders with
5// a CONTEXTUAL ad slot (selected by topic, labelled Sponsored, no tracking / no third-party JS) + ships.
6// license_tier: ORIGINAL
7import "nx_swap.nx"
8import "nx_ads.nx"
9import "nx_publisher.nx"
10import "nx_seg_store.nx"
11import "nx_syscalls.nx"
12import "nx_gate_verdict.nx"
13
14const SG_SWAP: *u8 = "knowledge/store/swap-"
15const SG_ADS: *u8 = "knowledge/store/ads-"
16const SG_STAGE_FILE: *u8 = "knowledge/staging/swap/board.html"
17const SG_LIVE_FILE: *u8 = "knowledge/publish/swap-live/board.html"
18
19func g_p(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
20func g_i(v: i64) -> i64 {
21 let bb: *u8 = sys_mmap(28); var m: i64 = v
22 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
23 let t: *u8 = sys_mmap(28); var k: i64 = 0
24 if m == 0 { t[0] = 48 as u8; k = 1 }
25 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
26 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
27}
28func g_exists(path: *u8) -> i64 { let fd: i64 = sys_openat_rd(path); if fd < 0 { return 0 } sys_close(fd); return 1 }
29
30func main() -> i64 {
31 g_p("=== nx_swap_gate (gamified community swap + sovereign ads) ===\n" as *u8)
32 sw_seed_config(SG_SWAP)
33
34 // species catalog (our own "creatures" = real plants)
35 sw_add_species(SG_SWAP, "basil" as *u8, "Basil" as *u8, "herb" as *u8, "common" as *u8)
36 sw_add_species(SG_SWAP, "rosemary" as *u8, "Rosemary" as *u8, "herb" as *u8, "common" as *u8)
37 sw_add_species(SG_SWAP, "thyme" as *u8, "Thyme" as *u8, "herb" as *u8, "common" as *u8)
38 sw_add_species(SG_SWAP, "oregano" as *u8, "Oregano" as *u8, "herb" as *u8, "common" as *u8)
39 sw_add_species(SG_SWAP, "sage" as *u8, "Sage" as *u8, "herb" as *u8, "common" as *u8)
40 sw_add_species(SG_SWAP, "saffron" as *u8, "Saffron Crocus" as *u8, "herb" as *u8, "rare" as *u8)
41 sw_add_set(SG_SWAP, "medherbs" as *u8, "Mediterranean Herbs\tbasil\trosemary\tthyme\toregano\tsage" as *u8)
42
43 // gardeners
44 sw_add_gardener(SG_SWAP, "alice" as *u8, "Alice" as *u8, "TX-Austin" as *u8)
45 sw_add_gardener(SG_SWAP, "bob" as *u8, "Bob" as *u8, "TX-Austin" as *u8)
46 sw_add_gardener(SG_SWAP, "cara" as *u8, "Cara" as *u8, "TX-Austin" as *u8)
47 sw_add_gardener(SG_SWAP, "dan" as *u8, "Dan" as *u8, "CA-LA" as *u8)
48
49 // alice grows the full Mediterranean herb garden and offers all 5 (TX-Austin)
50 sw_post_offer(SG_SWAP, "a_basil" as *u8, "alice" as *u8, "basil" as *u8, "cutting" as *u8, 3, "TX-Austin" as *u8, "fresh" as *u8)
51 sw_post_offer(SG_SWAP, "a_rose" as *u8, "alice" as *u8, "rosemary" as *u8, "cutting" as *u8, 3, "TX-Austin" as *u8, "-" as *u8)
52 sw_post_offer(SG_SWAP, "a_thyme" as *u8, "alice" as *u8, "thyme" as *u8, "seed" as *u8, 50, "TX-Austin" as *u8, "-" as *u8)
53 sw_post_offer(SG_SWAP, "a_oreg" as *u8, "alice" as *u8, "oregano" as *u8, "seed" as *u8, 50, "TX-Austin" as *u8, "-" as *u8)
54 sw_post_offer(SG_SWAP, "a_sage" as *u8, "alice" as *u8, "sage" as *u8, "cutting" as *u8, 2, "TX-Austin" as *u8, "-" as *u8)
55 // cara also offers basil in Austin; dan offers basil in LA (for area isolation)
56 sw_post_offer(SG_SWAP, "c_basil" as *u8, "cara" as *u8, "basil" as *u8, "seed" as *u8, 20, "TX-Austin" as *u8, "-" as *u8)
57 sw_post_offer(SG_SWAP, "d_basil" as *u8, "dan" as *u8, "basil" as *u8, "seed" as *u8, 20, "CA-LA" as *u8, "-" as *u8)
58 // bob asks for basil
59 sw_post_request(SG_SWAP, "b_req1" as *u8, "bob" as *u8, "basil" as *u8, "TX-Austin" as *u8)
60
61 // a contextual ad (indexed under the "herbs" topic, not under any viewer)
62 ads_add(SG_ADS, "seedlib" as *u8, "Nishi heirloom herb seeds" as *u8, "Start your own Mediterranean herb patch with open-pollinated, swap-friendly seed." as *u8, "Nishi Seed Library" as *u8, "herbs" as *u8)
63 ads_add(SG_ADS, "tomatoad" as *u8, "Brandywine tomato starts" as *u8, "-" as *u8, "Nishi Market" as *u8, "tomato" as *u8)
64
65 var pass: i64 = 0
66 var tot: i64 = 0
67
68 // T1 catalog + empty dex
69 let bn: *u8 = sys_mmap(48); sw_species_field(SG_SWAP, "basil" as *u8, 0, bn)
70 let bobdex0: i64 = sw_dex_count(SG_SWAP, "bob" as *u8)
71 g_p("species basil=" as *u8); g_p(bn); g_p(" bob dex=" as *u8); g_i(bobdex0); g_p("\n" as *u8)
72 tot = tot + 1
73 var ok1: i64 = 1
74 if fd_streq(bn, "Basil" as *u8) != 1 { ok1 = 0 }
75 if bobdex0 != 0 { ok1 = 0 }
76 if ok1 == 1 { pass = pass + 1; g_p("PASS T1 species catalog + gardeners; new gardener starts with an empty garden-dex\n" as *u8) } else { g_p("FAIL T1\n" as *u8) }
77
78 // T2 matching + area isolation
79 let m_atx: *i64 = sys_mmap(8 * 64) as *i64
80 let m_la: *i64 = sys_mmap(8 * 64) as *i64
81 let n_atx: i64 = sw_find_offers(SG_SWAP, "basil" as *u8, "TX-Austin" as *u8, m_atx)
82 let n_la: i64 = sw_find_offers(SG_SWAP, "basil" as *u8, "CA-LA" as *u8, m_la)
83 g_p("basil offers: Austin=" as *u8); g_i(n_atx); g_p(" LA=" as *u8); g_i(n_la); g_p("\n" as *u8)
84 tot = tot + 1
85 if n_atx == 2 { if n_la == 1 { pass = pass + 1; g_p("PASS T2 ask/give match + AREA isolation (Austin basil=2: Alice+Cara; LA basil=1: Dan, not mixed)\n" as *u8) } else { g_p("FAIL T2 la\n" as *u8) } } else { g_p("FAIL T2 atx=" as *u8); g_i(n_atx); g_p("\n" as *u8) }
86
87 // T3 THE SWAP: bob claims alice's 5 offers -> gets the plants by swapping
88 let c1: i64 = sw_claim_offer(SG_SWAP, "a_basil" as *u8, "bob" as *u8)
89 sw_claim_offer(SG_SWAP, "a_rose" as *u8, "bob" as *u8)
90 sw_claim_offer(SG_SWAP, "a_thyme" as *u8, "bob" as *u8)
91 sw_claim_offer(SG_SWAP, "a_oreg" as *u8, "bob" as *u8)
92 sw_claim_offer(SG_SWAP, "a_sage" as *u8, "bob" as *u8)
93 let bobdex: i64 = sw_dex_count(SG_SWAP, "bob" as *u8)
94 g_p("after swaps: bob dex=" as *u8); g_i(bobdex); g_p(" has rosemary=" as *u8); g_i(sw_dex_has(SG_SWAP, "bob" as *u8, "rosemary" as *u8)); g_p(" a_basil still open=" as *u8); g_i(sw_offer_open(SG_SWAP, "a_basil" as *u8)); g_p("\n" as *u8)
95 tot = tot + 1
96 var ok3: i64 = 1
97 if c1 != 1 { ok3 = 0 }
98 if bobdex != 5 { ok3 = 0 }
99 if sw_dex_has(SG_SWAP, "bob" as *u8, "rosemary" as *u8) != 1 { ok3 = 0 }
100 if sw_offer_open(SG_SWAP, "a_basil" as *u8) != 0 { ok3 = 0 } // claimed offer is no longer open
101 if ok3 == 1 { pass = pass + 1; g_p("PASS T3 the swap: Bob got 5 herbs incl rosemary by SWAPPING (not buying); offers marked claimed\n" as *u8) } else { g_p("FAIL T3\n" as *u8) }
102
103 // T4 gamification: XP -> level up
104 let bxp: i64 = sw_xp(SG_SWAP, "bob" as *u8)
105 let blv: i64 = sw_level(SG_SWAP, "bob" as *u8)
106 let alv: i64 = sw_level(SG_SWAP, "alice" as *u8)
107 g_p("bob xp=" as *u8); g_i(bxp); g_p(" level=" as *u8); g_i(blv); g_p(" | alice (gave 5) level=" as *u8); g_i(alv); g_p("\n" as *u8)
108 tot = tot + 1
109 var ok4: i64 = 1
110 if bxp != 175 { ok4 = 0 } // 5 x (receive 10 + new-species 25)
111 if blv != 4 { ok4 = 0 } // 1 + 175/50
112 if alv <= 1 { ok4 = 0 } // alice leveled up from giving
113 if ok4 == 1 { pass = pass + 1; g_p("PASS T4 gamification: Bob earned 175 XP -> Level 4; Alice leveled up from giving\n" as *u8) } else { g_p("FAIL T4\n" as *u8) }
114
115 // T5 sets + badges
116 let bcomplete: i64 = sw_set_complete(SG_SWAP, "bob" as *u8, "medherbs" as *u8)
117 let awarded: i64 = sw_award_badge(SG_SWAP, "bob" as *u8, "medherbs" as *u8)
118 let ccomplete: i64 = sw_set_complete(SG_SWAP, "cara" as *u8, "medherbs" as *u8)
119 let cawarded: i64 = sw_award_badge(SG_SWAP, "cara" as *u8, "medherbs" as *u8)
120 g_p("bob set-complete=" as *u8); g_i(bcomplete); g_p(" badge=" as *u8); g_i(sw_has_badge(SG_SWAP, "bob" as *u8, "medherbs" as *u8)); g_p(" | cara complete=" as *u8); g_i(ccomplete); g_p(" badge=" as *u8); g_i(cawarded); g_p("\n" as *u8)
121 tot = tot + 1
122 var ok5: i64 = 1
123 if bcomplete != 1 { ok5 = 0 }
124 if awarded != 1 { ok5 = 0 }
125 if sw_has_badge(SG_SWAP, "bob" as *u8, "medherbs" as *u8) != 1 { ok5 = 0 }
126 if ccomplete != 0 { ok5 = 0 } // cara only has basil
127 if cawarded != 0 { ok5 = 0 }
128 if ok5 == 1 { pass = pass + 1; g_p("PASS T5 set complete -> Bob earns the Mediterranean Herbs badge; Cara (1/5) earns nothing\n" as *u8) } else { g_p("FAIL T5\n" as *u8) }
129
130 // T6 sovereign board + contextual ad + ship
131 let page: *u8 = sys_mmap(65536)
132 let np: i64 = sw_render_board(SG_SWAP, SG_ADS, "TX-Austin" as *u8, "bob" as *u8, "medherbs" as *u8, page)
133 g_p("board = " as *u8); g_i(np); g_p(" bytes\n" as *u8)
134 tot = tot + 1
135 var ok6: i64 = 1
136 if as_has_thirdparty_js(page, np) != 0 { ok6 = 0 }
137 if as_contains(page, np, "Level " as *u8) != 1 { ok6 = 0 }
138 if as_contains(page, np, "5 / 5" as *u8) != 1 { ok6 = 0 } // set progress
139 if as_contains(page, np, "Sponsored" as *u8) != 1 { ok6 = 0 } // ad slot present
140 if as_contains(page, np, "Nishi heirloom herb seeds" as *u8) != 1 { ok6 = 0 } // contextual ad (herbs)
141 if as_contains(page, np, "not who you are" as *u8) != 1 { ok6 = 0 } // privacy stance shown
142 if as_contains(page, np, "from Cara" as *u8) != 1 { ok6 = 0 } // local open offer shown
143 if as_contains(page, np, "from Dan" as *u8) != 0 { ok6 = 0 } // LA offer NOT shown (area)
144 sys_mkdir("knowledge/staging" as *u8, 0x1ed)
145 sys_mkdir("knowledge/staging/swap" as *u8, 0x1ed)
146 let sfd: i64 = sys_openat_wr(SG_STAGE_FILE, 420); if sfd >= 0 { sys_write(sfd, page, np); sys_close(sfd) }
147 pub_init()
148 sys_mkdir("knowledge/publish/swap-stage" as *u8, 0x1ed)
149 sys_mkdir("knowledge/publish/swap-live" as *u8, 0x1ed)
150 pub_submit_to("knowledge/publish/swap-queue.tsv" as *u8, SG_STAGE_FILE, "board.html" as *u8, "nishifoodfamily" as *u8, "nishi-swap" as *u8, "internal" as *u8)
151 pub_run_full("knowledge/publish/swap-queue.tsv" as *u8, "knowledge/publish/swap-ledger.tsv" as *u8, "knowledge/publish/swap-stage" as *u8, "knowledge/publish/swap-live" as *u8, "publish:swap" as *u8)
152 if g_exists(SG_LIVE_FILE) != 1 { ok6 = 0 }
153 if ok6 == 1 { pass = pass + 1; g_p("PASS T6 sovereign gamified board + contextual ad (no tracking, no third-party JS), shipped\n" as *u8) } else { g_p("FAIL T6\n" as *u8) }
154
155 g_p("nx_swap_gate pass=" as *u8); g_i(pass); g_p("/" as *u8); g_i(tot)
156 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
157 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
158 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
159 let ctr__dry: *i64 = gv_ctr()
160 ctr__dry[0] = pass
161 ctr__dry[1] = tot
162 let rc__dry: i64 = gv_verdict("SWAP-GATE" as *u8, ctr__dry, "ask + give plants, gamified + fun, sovereign ads, our own IP, gift economy)" as *u8)
163 sys_exit(rc__dry)
164 return rc__dry
165}