code wiki / _hdl_build / nx_auction_proxybid.nx
nx_auction_proxybid.nx source
↩ module page · 188 lines · 9637 B
1// nx_auction_proxybid.nx -- MANHEIM-BUILD-L1: PROXY BIDDING ("set your max" / automatic bidding, the
2// OVE + Manheim Timed-Sales convenience primitive), COMPOSED on the shared nx_auction_core engine.
3// Sovereign (nx_cc->nxasm, no gcc), pure integer-exact + deterministic.
4//
5// MODEL: each dealer submits a standing MAX (a proxy). proxy_resolve settles the eBay-style second-price
6// outcome: the WINNER is the highest valid max (ties -> earliest submission), and pays the MINIMUM needed
7// to beat the runner-up = min(top1_max, top2_max + increment), floored to the opening, and JUMPED to the
8// reserve when the winner's max covers it. A max below the opening is REJECTED.
9// valid iff start <= t <= end AND max >= opening.
10// out[]: [winner, price, status(1=SOLD/0=NOSALE), accepted, rejected, runnerup_bidder, runnerup_max]
11//
12// EXCEED axis (honest, not yet benched): (1) proxy bidding is SNIPE-IMMUNE BY CONSTRUCTION -- maxes are
13// pre-committed, so there is no last-tick advantage to extend against (the timed channel needs anti-snipe;
14// the proxy channel eliminates the attack); (2) the winner provably pays the minimum to beat the runner-up
15// (Vickrey-fair, auditable, no shill ambiguity).
16//
17// COMPOSITION PROOF: the gate also expands the proxy outcome into the implied concrete 2-bid stream
18// (runner-up @ their max, winner @ the settling price) and feeds it to the SHARED core at_resolve --
19// asserting the core settles to the SAME winner+price. One settlement engine, two channels.
20//
21// GATE (self-validating): A normal 3-proxy sale (cross-checked vs core), B no-sale (top max < reserve),
22// C neg-control (a below-opening max REJECTED + the reserve-jump when the winner is uncontested). A broken
23// rule diverges a checked value -> verdict=RED. Evidence -> knowledge/status/auction_proxybid.log.
24// license_tier: ORIGINAL
25import "nx_syscalls.nx"
26import "nx_auction_core.nx"
27const PX_MAGIC_1100000: i64 = 1100000
28const PX_MAGIC_1050000: i64 = 1050000
29const PX_MAGIC_950000: i64 = 950000
30const PX_MAGIC_900000: i64 = 900000
31const PX_MAGIC_25000: i64 = 25000
32const PX_MAGIC_1000000: i64 = 1000000
33const PX_MAGIC_925000: i64 = 925000
34const PX_MAGIC_800000: i64 = 800000
35const PX_MAGIC_1075000: i64 = 1075000
36
37const PX_LOG: *u8 = "knowledge/status/auction_proxybid.log"
38
39func px_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
40func px_wn(fd: i64, v: i64) -> i64 { let bb: *u8 = sys_mmap(28); var m: i64=v; if m<0 {m=0-m; sys_write(fd,"-" as *u8,1)}; let t: *u8 = sys_mmap(28); var k: i64=0; if m==0 {t[0]=48;k=1}; while m>0 {t[k]=(48+(m%10)) as u8; m=m/10; k=k+1}; var i: i64=0; while i<k {bb[i]=t[k-1-i]; i=i+1}; sys_write(fd, bb, k); return 0 }
41
42// resolve a proxy (max-bid) auction. writes 7 results into out (see header).
43func proxy_resolve(opening: i64, increment: i64, reserve: i64, start: i64, end: i64, bidder: *i64, maxamt: *i64, time: *i64, n: i64, out: *i64) -> i64 {
44 var top1b: i64 = 0
45 var top1m: i64 = 0
46 var top1t: i64 = 0
47 var top2b: i64 = 0
48 var top2m: i64 = 0
49 var accepted: i64 = 0
50 var rejected: i64 = 0
51 var i: i64 = 0
52 while i < n {
53 let b: i64 = bidder[i]
54 let m: i64 = maxamt[i]
55 let t: i64 = time[i]
56 var valid: i64 = 1
57 if t < start { valid = 0 }
58 if t > end { valid = 0 }
59 if m < opening { valid = 0 }
60 if valid == 1 {
61 accepted = accepted + 1
62 // takes the lead iff a strictly higher max, or an equal max submitted EARLIER (tie -> earlier)
63 var take: i64 = 0
64 if m > top1m { take = 1 }
65 if m == top1m { if t < top1t { take = 1 } }
66 if take == 1 {
67 top2b = top1b; top2m = top1m // demote old leader to runner-up
68 top1b = b; top1m = m; top1t = t
69 } else {
70 if m > top2m { top2b = b; top2m = m }
71 }
72 } else {
73 rejected = rejected + 1
74 }
75 i = i + 1
76 }
77 var price: i64 = opening
78 if top2m > 0 {
79 let p2: i64 = top2m + increment
80 if p2 < top1m { price = p2 } else { price = top1m }
81 if price < opening { price = opening }
82 }
83 var status: i64 = AT_NOSALE
84 var winner: i64 = 0
85 if top1m >= reserve {
86 status = AT_SOLD
87 winner = top1b
88 if price < reserve { price = reserve } // reserve jump: winner's max covers it
89 } else {
90 price = 0
91 }
92 out[0] = winner
93 out[1] = price
94 out[2] = status
95 out[3] = accepted
96 out[4] = rejected
97 out[5] = top2b
98 out[6] = top2m
99 return 0
100}
101
102func main() -> i64 {
103 let bidder: *i64 = sys_mmap(8 * 16) as *i64
104 let maxamt: *i64 = sys_mmap(8 * 16) as *i64
105 let time: *i64 = sys_mmap(8 * 16) as *i64
106 let out: *i64 = sys_mmap(8 * 8) as *i64
107 // cross-check scratch (feeds the shared core)
108 let cb: *i64 = sys_mmap(8 * 4) as *i64
109 let ca: *i64 = sys_mmap(8 * 4) as *i64
110 let ct: *i64 = sys_mmap(8 * 4) as *i64
111 let o2: *i64 = sys_mmap(8 * 8) as *i64
112
113 // --- Scenario A: 3 proxies, second-price settlement (opening 900000, incr 25000, reserve 1000000) ---
114 bidder[0]=1; maxamt[0]=PX_MAGIC_1100000; time[0]=110
115 bidder[1]=2; maxamt[1]=PX_MAGIC_1050000; time[1]=120
116 bidder[2]=3; maxamt[2]=PX_MAGIC_950000; time[2]=130
117 proxy_resolve(PX_MAGIC_900000, PX_MAGIC_25000, PX_MAGIC_1000000, 100, 200, bidder, maxamt, time, 3, out)
118 let aw: i64 = out[0]; let ap: i64 = out[1]; let as_: i64 = out[2]; let aacc: i64 = out[3]; let arej: i64 = out[4]
119 let arub: i64 = out[5]; let arum: i64 = out[6]
120
121 // COMPOSITION PROOF: expand A to the implied concrete stream + settle via the SHARED core engine.
122 cb[0]=arub; ca[0]=arum; ct[0]=150 // runner-up bids their max
123 cb[1]=aw; ca[1]=ap; ct[1]=151 // winner bids the settling price
124 at_resolve(PX_MAGIC_900000, PX_MAGIC_25000, PX_MAGIC_1000000, 100, 200, 0, 0, cb, ca, ct, 2, o2)
125 let xw: i64 = o2[0]; let xp: i64 = o2[1]; let xs: i64 = o2[2]
126
127 // --- Scenario B: no-sale (every max below reserve) ---
128 bidder[0]=1; maxamt[0]=PX_MAGIC_950000; time[0]=110
129 bidder[1]=2; maxamt[1]=PX_MAGIC_925000; time[1]=120
130 proxy_resolve(PX_MAGIC_900000, PX_MAGIC_25000, PX_MAGIC_1000000, 100, 200, bidder, maxamt, time, 2, out)
131 let bw: i64 = out[0]; let bs: i64 = out[2]; let bacc: i64 = out[3]
132
133 // --- Control C: a below-opening max REJECTED + reserve-jump for the uncontested winner ---
134 bidder[0]=1; maxamt[0]=PX_MAGIC_1100000; time[0]=110
135 bidder[1]=2; maxamt[1]=PX_MAGIC_800000; time[1]=120 // PX_MAGIC_800000 < opening PX_MAGIC_900000 -> rejected
136 proxy_resolve(PX_MAGIC_900000, PX_MAGIC_25000, PX_MAGIC_1000000, 100, 200, bidder, maxamt, time, 2, out)
137 let cw: i64 = out[0]; let cp: i64 = out[1]; let cs: i64 = out[2]; let cacc: i64 = out[3]; let crej: i64 = out[4]
138
139 // --- assertions (tight, hand-computed) ---
140 var ok: i64 = 1
141 // A: SOLD to bidder 1 at runner-up(1050000)+increment(25000)=1075000, 3 accepted / 0 rejected
142 if aw != 1 { ok = 0 }
143 if ap != PX_MAGIC_1075000 { ok = 0 }
144 if as_ != AT_SOLD { ok = 0 }
145 if aacc != 3 { ok = 0 }
146 if arej != 0 { ok = 0 }
147 // A composition: the shared core settles the expanded stream to the SAME winner+price+status
148 if xw != aw { ok = 0 }
149 if xp != ap { ok = 0 }
150 if xs != as_ { ok = 0 }
151 // B: NO-SALE (top max 950000 < reserve 1000000), 2 accepted
152 if bw != 0 { ok = 0 }
153 if bs != AT_NOSALE { ok = 0 }
154 if bacc != 2 { ok = 0 }
155 // C: below-opening REJECTED -> 1 accepted / 1 rejected; uncontested winner reserve-JUMPS to 1000000
156 if cw != 1 { ok = 0 }
157 if cp != PX_MAGIC_1000000 { ok = 0 }
158 if cs != AT_SOLD { ok = 0 }
159 if cacc != 1 { ok = 0 }
160 if crej != 1 { ok = 0 }
161 if cp == PX_MAGIC_900000 { ok = 0 } // reserve jump MUST have moved price off the opening (rule-sensitivity)
162
163 px_w(1, "PROXYGATE engine=nx_auction_proxybid A{winner=" as *u8); px_wn(1, aw)
164 px_w(1, " price=" as *u8); px_wn(1, ap); px_w(1, " status=" as *u8); px_wn(1, as_)
165 px_w(1, " acc=" as *u8); px_wn(1, aacc); px_w(1, " rej=" as *u8); px_wn(1, arej)
166 px_w(1, "} core-crosscheck{winner=" as *u8); px_wn(1, xw); px_w(1, " price=" as *u8); px_wn(1, xp)
167 px_w(1, " agree=" as *u8); if xw == aw { if xp == ap { px_wn(1, 1) } else { px_wn(1, 0) } } else { px_wn(1, 0) }
168 px_w(1, "} B{winner=" as *u8); px_wn(1, bw); px_w(1, " status=" as *u8); px_wn(1, bs)
169 px_w(1, "} C{winner=" as *u8); px_wn(1, cw); px_w(1, " price=" as *u8); px_wn(1, cp)
170 px_w(1, " rej=" as *u8); px_wn(1, crej); px_w(1, "}" as *u8)
171 if ok == 1 { px_w(1, " verdict=GREEN\n" as *u8) } else { px_w(1, " verdict=RED\n" as *u8) }
172
173 let lf: i64 = sys_openat_append(PX_LOG, 420)
174 if lf >= 0 {
175 px_w(lf, "PROXYGATE engine=nx_auction_proxybid A{winner=" as *u8); px_wn(lf, aw)
176 px_w(lf, " price=" as *u8); px_wn(lf, ap); px_w(lf, " acc=" as *u8); px_wn(lf, aacc)
177 px_w(lf, " rej=" as *u8); px_wn(lf, arej); px_w(lf, "} core-agree=" as *u8)
178 if xw == aw { if xp == ap { px_wn(lf, 1) } else { px_wn(lf, 0) } } else { px_wn(lf, 0) }
179 px_w(lf, " B{winner=" as *u8); px_wn(lf, bw); px_w(lf, " status=" as *u8); px_wn(lf, bs)
180 px_w(lf, "} C{winner=" as *u8); px_wn(lf, cw); px_w(lf, " price=" as *u8); px_wn(lf, cp)
181 px_w(lf, " rej=" as *u8); px_wn(lf, crej); px_w(lf, "}" as *u8)
182 if ok == 1 { px_w(lf, " verdict=GREEN\n" as *u8) } else { px_w(lf, " verdict=RED\n" as *u8) }
183 sys_close(lf)
184 }
185
186 if ok == 1 { return 0 }
187 return 1
188}