nx_lbclimb_lib.nx source
↩ module page · 320 lines · 15276 B
1// nx_lbclimb_lib.nx -- THE ONE climb ruler (search R0d, ecosystem EC62, 2026-09-17): does a board's DECLARED ladder
2// reach the leader of the public leaderboard it names, and which rank does each declared gate reach?
3//
4// WHY. The operator asked "what ladder do we need to climb to beat rank 1" and a seat answered by hand, staging the
5// rungs with accept numbers NO rung had pre-declared. The estate already held every input as DATA -- the leaderboard
6// rows (<dom>.leaderboard, nx_leaderboard_lib) and the dated targets and rung roles (<dom>.plan, nx_ladder_lib) -- and
7// lacked only the JOIN and one datum: the score each contender rung must reach on the board. This lib is that join.
8// climbboard|<board>|<sotatarget id>|<note> which leaderboard board measures which target
9// climbgate|<rung>|<board>|<floor>|<basis> the rung's accept floor on that board: a score (22.9), a single
10// dash (declared UNMEASURED) or the word leader (strictly above the
11// leader of the day, so the gate moves when the public board does)
12// The floor is never the last field, so a CRLF-terminated row parses (the trailing CR lands in the prose).
13// POPULATION: the rungs whose rungrole row says contender toward the board's target. PARTITION (the CLI prints it):
14// contenders = gated + ungated + nogate + badfloor. A climbgate row naming a rung outside that population is a STRAY:
15// counted, never voting (a gate planted on a substrate rung cannot make a ladder reach).
16// VERDICT: REACHES when at least one gated contender's floor is strictly above the leader; SHORT when numeric gates
17// exist and none clears the leader; NOGATES when no contender carries a numeric gate; NOBOARD when the leaderboard
18// holds no rival row for the board; BADTARGET when the climbboard row names no declared sotatarget. SHORT is the
19// forcing verdict: the declared ladder cannot reach the target whatever ships, so the board owes a rung whose gate does.
20// Pure over two buffers (plan, leaderboard): the gate drives it in-process; the CLI, the goal mapper and the emitter
21// compose it and never re-derive it.
22// license_tier: ORIGINAL. No hw writes (Rule 26).
23import "nx_syscalls.nx"
24import "nx_barfresh_lib.nx"
25import "nx_ladder_lib.nx"
26import "nx_leaderboard_lib.nx"
27
28const LBC_BOARD_TAG: *u8 = "climbboard|"
29const LBC_GATE_TAG: *u8 = "climbgate|"
30const LBC_F_B_BOARD: i64 = 1
31const LBC_F_B_TARGET: i64 = 2
32const LBC_F_G_RUNG: i64 = 1
33const LBC_F_G_BOARD: i64 = 2
34const LBC_F_G_FLOOR: i64 = 3
35const LBC_F_G_BASIS: i64 = 4
36const LBC_FLOOR_UNGATED: *u8 = "-"
37const LBC_FLOOR_LEADER: *u8 = "leader"
38const LBC_LEADER_STEP: i64 = 1 // one tenth of a point above the leader, in the x10 scale the boards print
39// per-contender states
40const LBC_S_GATED: i64 = 0
41const LBC_S_UNGATED: i64 = 1 // a climbgate row whose floor is the dash: declared unmeasured
42const LBC_S_NOGATE: i64 = 2 // no climbgate row for this board at all
43const LBC_S_BADFLOOR: i64 = 3 // a floor that is neither a score, the dash nor the word leader
44// verdicts
45const LBC_V_REACHES: i64 = 0
46const LBC_V_SHORT: i64 = 1
47const LBC_V_NOGATES: i64 = 3
48const LBC_V_NOBOARD: i64 = 4
49const LBC_V_BADTARGET: i64 = 5
50// exits the CLI maps the verdicts onto
51const LBC_EXIT_REACHES: i64 = 0
52const LBC_EXIT_SHORT: i64 = 1
53const LBC_EXIT_ABSTAIN: i64 = 3
54// the per-contender record handed back to the caller (stride LBC_KF)
55const LBC_KF: i64 = 5
56const LBC_K_ROFF: i64 = 0 // line start of the rung row
57const LBC_K_STATE: i64 = 1
58const LBC_K_FLOOR: i64 = 2 // floor x10, LBC_NONE when not gated
59const LBC_K_REACH: i64 = 3 // the rank the floor reaches, LBC_NONE when not gated
60const LBC_K_GATE: i64 = 4 // line start of the deciding climbgate row, LBC_NONE when there is none
61// the per-board record of lbc_boards (stride LBC_BF)
62const LBC_BF: i64 = 5
63const LBC_B_LINE: i64 = 0
64const LBC_B_NAMEOFF: i64 = 1
65const LBC_B_NAMELEN: i64 = 2
66const LBC_B_TGTOFF: i64 = 3
67const LBC_B_TGTLEN: i64 = 4
68// census slots
69const LBC_N_CONTENDERS: i64 = 0
70const LBC_N_GATED: i64 = 1
71const LBC_N_UNGATED: i64 = 2
72const LBC_N_NOGATE: i64 = 3
73const LBC_N_BADFLOOR: i64 = 4
74const LBC_N_STRAY: i64 = 5 // climbgate rows for this board naming a rung outside the contender population
75const LBC_N_DUPGATE: i64 = 6 // further climbgate rows for a (rung, board) pair an earlier row already gated
76const LBC_N_LEADER_X10: i64 = 7
77const LBC_N_ESTATE_X10: i64 = 8
78const LBC_N_ESTATE_RANK: i64 = 9
79const LBC_N_RIVALS: i64 = 10
80const LBC_N_BEST_FLOOR_X10: i64 = 11
81const LBC_N_BEST_REACH: i64 = 12
82const LBC_N_REACHERS: i64 = 13 // gated contenders whose floor is strictly above the leader
83const LBC_N_MOVERS: i64 = 14 // gated contenders whose floor reaches a better rank than the estate holds
84const LBC_N_DYNAMIC: i64 = 15 // gates spelled with the word leader
85const LBC_N_COUNT: i64 = 16
86const LBC_NONE: i64 = 0 - 1
87const LBC_I64: i64 = 8
88const LBC_NAME_CAP: i64 = 128
89
90// copy a span into a NUL-terminated name buffer (the leaderboard lib takes the board as a C string)
91func lbc_span_z(buf: *u8, off: i64, len: i64, dst: *u8) -> i64 {
92 var n: i64 = len
93 if n < 0 { n = 0 }
94 if n > LBC_NAME_CAP - 1 { n = LBC_NAME_CAP - 1 }
95 var i: i64 = 0
96 while i < n { dst[i] = buf[off + i]; i = i + 1 }
97 dst[n] = 0 as u8
98 return n
99}
100
101// the climbboard rows of a plan, in file order: records of stride LBC_BF; returns how many were written (at most cap)
102func lbc_boards(pbuf: *u8, pn: i64, b: *i64, cap: i64) -> i64 {
103 let fo: *i64 = sys_mmap(LBC_I64) as *i64
104 var nb: i64 = 0
105 var p: i64 = 0
106 while p < pn {
107 let e: i64 = bf_line_end(pbuf, pn, p)
108 if bf_line_starts(pbuf, p, e, LBC_BOARD_TAG) == 1 {
109 if nb < cap {
110 let nl: i64 = bf_field(pbuf, p, e, LBC_F_B_BOARD, fo)
111 let no: i64 = fo[0]
112 let tl: i64 = bf_field(pbuf, p, e, LBC_F_B_TARGET, fo)
113 let to: i64 = fo[0]
114 if nl > 0 {
115 b[nb * LBC_BF + LBC_B_LINE] = p
116 b[nb * LBC_BF + LBC_B_NAMEOFF] = no
117 b[nb * LBC_BF + LBC_B_NAMELEN] = nl
118 b[nb * LBC_BF + LBC_B_TGTOFF] = to
119 b[nb * LBC_BF + LBC_B_TGTLEN] = tl
120 nb = nb + 1
121 }
122 }
123 }
124 p = e + 1
125 }
126 return nb
127}
128
129// the FIRST climbgate row for this board that names the rung whose id is the span [ridoff, ridoff+ridlen) of the plan;
130// returns its line start or LBC_NONE; dups[0] receives how many FURTHER rows name the same pair (they never vote)
131func lbc_gate_find(pbuf: *u8, pn: i64, board: *u8, ridoff: i64, ridlen: i64, dups: *i64) -> i64 {
132 let fo: *i64 = sys_mmap(LBC_I64) as *i64
133 var found: i64 = LBC_NONE
134 dups[0] = 0
135 var p: i64 = 0
136 while p < pn {
137 let e: i64 = bf_line_end(pbuf, pn, p)
138 if bf_line_starts(pbuf, p, e, LBC_GATE_TAG) == 1 {
139 let bl: i64 = bf_field(pbuf, p, e, LBC_F_G_BOARD, fo)
140 var mine: i64 = 0
141 if bl > 0 { mine = ld_span_is(pbuf, fo[0], bl, board) }
142 if mine == 1 {
143 let rl: i64 = bf_field(pbuf, p, e, LBC_F_G_RUNG, fo)
144 if rl > 0 { if bf_span_eq(pbuf, fo[0], rl, ridoff, ridlen) == 1 {
145 if found == LBC_NONE { found = p } else { dups[0] = dups[0] + 1 }
146 } }
147 }
148 }
149 p = e + 1
150 }
151 return found
152}
153
154// THE JOIN. k receives one record per contender (stride LBC_KF, in plan order; the caller sizes it from the plan's rung
155// row count), c the census. Returns the verdict.
156func lbc_climb(pbuf: *u8, pn: i64, lbuf: *u8, ln: i64, board: *u8, tgtoff: i64, tgtlen: i64, k: *i64, c: *i64) -> i64 {
157 var z: i64 = 0
158 while z < LBC_N_COUNT { c[z] = 0; z = z + 1 }
159 c[LBC_N_LEADER_X10] = LBC_NONE
160 c[LBC_N_ESTATE_X10] = LBC_NONE
161 c[LBC_N_ESTATE_RANK] = LBC_NONE
162 c[LBC_N_BEST_FLOOR_X10] = LBC_NONE
163 c[LBC_N_BEST_REACH] = LBC_NONE
164 let nt: i64 = bf_count_rows(pbuf, pn, LD_TARGET_TAG)
165 let nrmax: i64 = bf_count_rows(pbuf, pn, LD_RUNG_TAG)
166 let toff: *i64 = sys_mmap((nt + 1) * LBC_I64) as *i64
167 let tcls: *i64 = sys_mmap((nt + 1) * LBC_I64) as *i64
168 let tst: *i64 = sys_mmap((nt + 1) * LBC_I64) as *i64
169 let roff: *i64 = sys_mmap((nrmax + 1) * LBC_I64) as *i64
170 let rrole: *i64 = sys_mmap((nrmax + 1) * LBC_I64) as *i64
171 let rtgt: *i64 = sys_mmap((nrmax + 1) * LBC_I64) as *i64
172 let rst: *i64 = sys_mmap((nrmax + 1) * LBC_I64) as *i64
173 let ldc: *i64 = sys_mmap(LD_N_COUNT * LBC_I64) as *i64
174 let nr: i64 = ld_classify(pbuf, pn, toff, tcls, tst, roff, rrole, rtgt, rst, ldc)
175 let fo: *i64 = sys_mmap(LBC_I64) as *i64
176 // the board's target, by id
177 var ti: i64 = LBC_NONE
178 var t: i64 = 0
179 while t < nt {
180 let te: i64 = bf_line_end(pbuf, pn, toff[t])
181 let il: i64 = bf_field(pbuf, toff[t], te, LD_F_T_ID, fo)
182 if il > 0 { if ti == LBC_NONE { if tgtlen > 0 { if bf_span_eq(pbuf, fo[0], il, tgtoff, tgtlen) == 1 { ti = t } } } }
183 t = t + 1
184 }
185 if ti == LBC_NONE { return LBC_V_BADTARGET }
186 // the public board: rivals, leader, the estate's own latest row and the rank it holds
187 let heads: *i64 = sys_mmap(LBC_I64) as *i64
188 let rivals: *i64 = sys_mmap(LBC_I64) as *i64
189 let est: *i64 = sys_mmap(LBC_I64) as *i64
190 heads[0] = 0
191 rivals[0] = 0
192 est[0] = 0
193 lb_count(lbuf, ln, board, heads, rivals, est)
194 c[LBC_N_RIVALS] = rivals[0]
195 if rivals[0] <= 0 { return LBC_V_NOBOARD }
196 let leader: i64 = lb_leader(lbuf, ln, board)
197 c[LBC_N_LEADER_X10] = leader
198 let ero: *i64 = sys_mmap(LBC_I64) as *i64
199 let erl: *i64 = sys_mmap(LBC_I64) as *i64
200 let estate: i64 = lb_estate_latest(lbuf, ln, board, ero, erl)
201 c[LBC_N_ESTATE_X10] = estate
202 var erank: i64 = rivals[0] + 1
203 if estate != LB_NONE { erank = lb_rank_of(lbuf, ln, board, estate) }
204 c[LBC_N_ESTATE_RANK] = erank
205 // the contenders toward the target, each with the first gate that names it on this board
206 let dups: *i64 = sys_mmap(LBC_I64) as *i64
207 var nk: i64 = 0
208 var i: i64 = 0
209 while i < nr {
210 var isc: i64 = 0
211 if rrole[i] == LD_R_CONTENDER { if rtgt[i] == ti { isc = 1 } }
212 if isc == 1 {
213 let re: i64 = bf_line_end(pbuf, pn, roff[i])
214 let idl: i64 = bf_field(pbuf, roff[i], re, LD_F_R_ID, fo)
215 let ido: i64 = fo[0]
216 var st: i64 = LBC_S_NOGATE
217 var fl: i64 = LBC_NONE
218 var rc: i64 = LBC_NONE
219 var gp: i64 = LBC_NONE
220 if idl > 0 {
221 gp = lbc_gate_find(pbuf, pn, board, ido, idl, dups)
222 c[LBC_N_DUPGATE] = c[LBC_N_DUPGATE] + dups[0]
223 }
224 if gp != LBC_NONE {
225 let ge: i64 = bf_line_end(pbuf, pn, gp)
226 let fll: i64 = bf_field(pbuf, gp, ge, LBC_F_G_FLOOR, fo)
227 st = LBC_S_BADFLOOR
228 if fll > 0 {
229 if ld_span_is(pbuf, fo[0], fll, LBC_FLOOR_UNGATED) == 1 { st = LBC_S_UNGATED } else {
230 if ld_span_is(pbuf, fo[0], fll, LBC_FLOOR_LEADER) == 1 {
231 st = LBC_S_GATED
232 fl = leader + LBC_LEADER_STEP
233 c[LBC_N_DYNAMIC] = c[LBC_N_DYNAMIC] + 1
234 } else {
235 let sv: i64 = lb_score_x10((pbuf as i64 + fo[0]) as *u8, fll)
236 if sv != LB_NONE { st = LBC_S_GATED; fl = sv }
237 }
238 }
239 }
240 }
241 if st == LBC_S_GATED {
242 rc = lb_rank_of(lbuf, ln, board, fl)
243 c[LBC_N_GATED] = c[LBC_N_GATED] + 1
244 if fl > leader { c[LBC_N_REACHERS] = c[LBC_N_REACHERS] + 1 }
245 if rc < erank { c[LBC_N_MOVERS] = c[LBC_N_MOVERS] + 1 }
246 if fl > c[LBC_N_BEST_FLOOR_X10] { c[LBC_N_BEST_FLOOR_X10] = fl; c[LBC_N_BEST_REACH] = rc }
247 }
248 if st == LBC_S_UNGATED { c[LBC_N_UNGATED] = c[LBC_N_UNGATED] + 1 }
249 if st == LBC_S_NOGATE { c[LBC_N_NOGATE] = c[LBC_N_NOGATE] + 1 }
250 if st == LBC_S_BADFLOOR { c[LBC_N_BADFLOOR] = c[LBC_N_BADFLOOR] + 1 }
251 k[nk * LBC_KF + LBC_K_ROFF] = roff[i]
252 k[nk * LBC_KF + LBC_K_STATE] = st
253 k[nk * LBC_KF + LBC_K_FLOOR] = fl
254 k[nk * LBC_KF + LBC_K_REACH] = rc
255 k[nk * LBC_KF + LBC_K_GATE] = gp
256 nk = nk + 1
257 }
258 i = i + 1
259 }
260 c[LBC_N_CONTENDERS] = nk
261 // strays: climbgate rows for this board whose rung is not one of the contenders above
262 var p: i64 = 0
263 while p < pn {
264 let e: i64 = bf_line_end(pbuf, pn, p)
265 if bf_line_starts(pbuf, p, e, LBC_GATE_TAG) == 1 {
266 let bl: i64 = bf_field(pbuf, p, e, LBC_F_G_BOARD, fo)
267 var mine: i64 = 0
268 if bl > 0 { mine = ld_span_is(pbuf, fo[0], bl, board) }
269 if mine == 1 {
270 let rl: i64 = bf_field(pbuf, p, e, LBC_F_G_RUNG, fo)
271 let ro: i64 = fo[0]
272 var hit: i64 = 0
273 var q: i64 = 0
274 while q < nk {
275 let kro: i64 = k[q * LBC_KF + LBC_K_ROFF]
276 let kre: i64 = bf_line_end(pbuf, pn, kro)
277 let kil: i64 = bf_field(pbuf, kro, kre, LD_F_R_ID, fo)
278 if kil > 0 { if rl > 0 { if bf_span_eq(pbuf, fo[0], kil, ro, rl) == 1 { hit = 1 } } }
279 q = q + 1
280 }
281 if hit == 0 { c[LBC_N_STRAY] = c[LBC_N_STRAY] + 1 }
282 }
283 }
284 p = e + 1
285 }
286 if c[LBC_N_GATED] == 0 { return LBC_V_NOGATES }
287 if c[LBC_N_REACHERS] > 0 { return LBC_V_REACHES }
288 return LBC_V_SHORT
289}
290
291// the partition the CLI prints beside the population: it must equal c[LBC_N_CONTENDERS]
292func lbc_partition_sum(c: *i64) -> i64 {
293 return c[LBC_N_GATED] + c[LBC_N_UNGATED] + c[LBC_N_NOGATE] + c[LBC_N_BADFLOOR]
294}
295
296func lbc_verdict_name(v: i64) -> *u8 {
297 if v == LBC_V_REACHES { return "REACHES" as *u8 }
298 if v == LBC_V_SHORT { return "SHORT" as *u8 }
299 if v == LBC_V_NOGATES { return "NOGATES" as *u8 }
300 if v == LBC_V_NOBOARD { return "NOBOARD" as *u8 }
301 if v == LBC_V_BADTARGET { return "BADTARGET" as *u8 }
302 return "UNKNOWN" as *u8
303}
304
305func lbc_state_name(s: i64) -> *u8 {
306 if s == LBC_S_GATED { return "GATED" as *u8 }
307 if s == LBC_S_UNGATED { return "UNGATED" as *u8 }
308 if s == LBC_S_NOGATE { return "NOGATE" as *u8 }
309 if s == LBC_S_BADFLOOR { return "BADFLOOR" as *u8 }
310 return "UNKNOWN" as *u8
311}
312
313// the exit a verdict maps onto: REACHES 0; SHORT and BADTARGET 1 (declared and unable, or declared and broken);
314// NOGATES and NOBOARD 3 (the ruler could not judge -- it abstains, it never acquits)
315func lbc_exit_of(v: i64) -> i64 {
316 if v == LBC_V_REACHES { return LBC_EXIT_REACHES }
317 if v == LBC_V_SHORT { return LBC_EXIT_SHORT }
318 if v == LBC_V_BADTARGET { return LBC_EXIT_SHORT }
319 return LBC_EXIT_ABSTAIN
320}