nx_bright_rewrite_gate.nx source
↩ module page · 239 lines · 17955 B
1// nx_bright_rewrite_gate.nx -- the referee for nx_bright_rewrite_lib (search R0l, 2026-09-16): the remote engine
2// door, the idempotent re-run, the per-split lease and the split verdict, driven IN-PROCESS on a /tmp fixture
3// tree (no model, no network peer: the engine under test is 127.0.0.1:1, a port nothing listens on, so the
4// ENGINE-DOWN path is reached for real and never a passthrough row is manufactured from it).
5// Scratch lives in /tmp/nx_bright_rewrite_gate/ (fixture-ratchet law), created at setup, and every fixture file
6// is truncate-written or unlinked first so the gate is idempotent run after run.
7// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
8import "nx_bright_rewrite_lib.nx"
9import "nx_gate_verdict.nx"
10
11const BG_DIR: *u8 = "/tmp/nx_bright_rewrite_gate" as *u8
12const BG_ROOT: *u8 = "/tmp/nx_bright_rewrite_gate/root" as *u8
13const BG_LEASE_ROOT: *u8 = "/tmp/nx_bright_rewrite_gate/lease/" as *u8
14const BG_OUT: *u8 = "gatefix" as *u8
15const BG_MODE_DIR: i64 = 493
16const BG_CAP: i64 = 65536
17const BG_ENGINE_DEAD: *u8 = "127.0.0.1:1" as *u8
18const BG_TTL: i64 = 60 // a crashed gate run frees its own fixture lease within a minute
19// the canned oracle reply's declared numbers (the reply text spells them; the teeth compare against these names)
20const BG_ORACLE_TOK_PRED: i64 = 301
21const BG_ORACLE_PRED_MS: i64 = 2210
22const BG_PERMIL_ONE: i64 = 1000
23const BG_PERMIL_ZERO: i64 = 0
24
25func bg_mkdir(p: *u8) -> i64 { return sys_mkdir(p, BG_MODE_DIR) }
26func bg_write(p: *u8, s: *u8) -> i64 {
27 let fd: i64 = sys_openat_wr(p, BR_FILE_MODE)
28 if fd < 0 { return 0 - 1 }
29 br_write_all(fd, s, br_slen(s))
30 sys_close(fd)
31 return 0
32}
33func bg_exists(p: *u8) -> i64 { let fd: i64 = sys_openat_rd(p); if fd < 0 { return 0 } sys_close(fd); return 1 }
34func bg_rm(p: *u8) -> i64 { return sys_unlinkat(p) }
35// a canned HTTP reply with an honest Content-Length
36func bg_crlf(dst: *u8, o: i64) -> i64 { dst[o] = 13 as u8; dst[o + 1] = 10 as u8; return o + 2 }
37func bg_http(dst: *u8, code: i64, body: *u8) -> i64 {
38 var o: i64 = br_cat(dst, 0, "HTTP/1.1 " as *u8); o = br_catn(dst, o, code)
39 o = br_cat(dst, o, " X" as *u8); o = bg_crlf(dst, o)
40 o = br_cat(dst, o, "Content-Type: application/json" as *u8); o = bg_crlf(dst, o)
41 o = br_cat(dst, o, "Content-Length: " as *u8); o = br_catn(dst, o, br_slen(body)); o = bg_crlf(dst, o)
42 o = bg_crlf(dst, o)
43 o = br_cat(dst, o, body)
44 return o
45}
46func bg_split_path(dst: *u8, split: *u8, tail: *u8) -> i64 { return br_path(dst, BG_ROOT, split, tail) }
47
48func main(argc: i64, argv: *i64) -> i64 {
49 let ctr: *i64 = gv_ctr()
50 gv_head("nx_bright_rewrite_gate -- the remote engine door, the idempotent re-run, the split lease and the split verdict" as *u8)
51 // ---- setup: the fixture tree, idempotent ----
52 bg_mkdir(BG_DIR); bg_mkdir(BG_ROOT); bg_mkdir(BG_LEASE_ROOT)
53 let pb: *u8 = sys_mmap(BR_PATH_CAP)
54 bg_split_path(pb, "biology" as *u8, "" as *u8); bg_mkdir(pb)
55 bg_split_path(pb, "earth_science" as *u8, "" as *u8); bg_mkdir(pb)
56 bg_split_path(pb, "economics" as *u8, "" as *u8); bg_mkdir(pb)
57 let qtsv: *u8 = "q1\tWhat is the essential problem?\nq2\tWhy does the second query exist?\n" as *u8
58 bg_split_path(pb, "biology" as *u8, "queries.tsv" as *u8); bg_write(pb, qtsv)
59 bg_split_path(pb, "earth_science" as *u8, "queries.tsv" as *u8); bg_write(pb, qtsv)
60 bg_split_path(pb, "economics" as *u8, "queries.tsv" as *u8); bg_write(pb, qtsv)
61 bg_split_path(pb, "biology" as *u8, "queries.gatefix.tsv.part" as *u8); bg_rm(pb)
62 bg_split_path(pb, "earth_science" as *u8, "queries.gatefix.tsv.part" as *u8); bg_rm(pb)
63 bg_split_path(pb, "earth_science" as *u8, "queries.gatefix.tsv" as *u8); bg_rm(pb)
64 bg_split_path(pb, "economics" as *u8, "queries.gatefix.tsv.part" as *u8); bg_rm(pb)
65 bg_split_path(pb, "economics" as *u8, "queries.gatefix.tsv" as *u8); bg_rm(pb)
66 bg_split_path(pb, "biology" as *u8, "queries.gatefix.tsv" as *u8); bg_write(pb, "q1\tdone one\nq2\tdone two\n" as *u8)
67
68 // ---- T1/T2 the engine address parser ----
69 let eng: *i64 = br_eng_alloc()
70 let p1: i64 = br_engine_parse("192.168.8.193:8034" as *u8, eng)
71 gv_check("T1 engine=a.b.c.d:port parses" as *u8, p1, ctr)
72 gv_check_eq("T1a octet a" as *u8, eng[0], 192, ctr)
73 gv_check_eq("T1b octet d" as *u8, eng[3], 193, ctr)
74 gv_check_eq("T1c port" as *u8, eng[4], 8034, ctr)
75 let e2: *i64 = br_eng_alloc()
76 gv_check("T2 neg-control a hostname is refused (no fabricated address)" as *u8, (br_engine_parse("laptop:8034" as *u8, e2) == 0) as i64, ctr)
77 gv_check("T2a neg-control a port of 0 is refused" as *u8, (br_engine_parse("10.0.0.1:0" as *u8, e2) == 0) as i64, ctr)
78 gv_check("T2b neg-control an octet above 255 is refused" as *u8, (br_engine_parse("10.0.0.300:80" as *u8, e2) == 0) as i64, ctr)
79 gv_check("T2c neg-control three octets are refused" as *u8, (br_engine_parse("10.0.1:80" as *u8, e2) == 0) as i64, ctr)
80 gv_check_eq("T2d the reply budget derives from max_new (512 tokens at the bound + setup)" as *u8, br_engine_timeout_s(512), 1084, ctr)
81
82 // ---- T3 the /gen body carries the whole sampling contract and an ESCAPED prompt ----
83 let body: *u8 = sys_mmap(BG_CAP)
84 let prompt: *u8 = "Query: a \"quoted\" line\nsecond line" as *u8
85 let bn: i64 = br_engine_body(body, BG_CAP, prompt, br_slen(prompt), 512, 700, 800, 64, 1)
86 gv_check("T3 body built" as *u8, (bn > 0) as i64, ctr)
87 gv_check("T3a max_new" as *u8, (br_find(body, bn, "\"max_new\":512" as *u8) >= 0) as i64, ctr)
88 gv_check("T3b mode i8" as *u8, (br_find(body, bn, "\"mode\":\"i8\"" as *u8) >= 0) as i64, ctr)
89 gv_check("T3c temp" as *u8, (br_find(body, bn, "\"temp\":700" as *u8) >= 0) as i64, ctr)
90 gv_check("T3d top_p" as *u8, (br_find(body, bn, "\"top_p\":800" as *u8) >= 0) as i64, ctr)
91 gv_check("T3e top_k" as *u8, (br_find(body, bn, "\"top_k\":64" as *u8) >= 0) as i64, ctr)
92 gv_check("T3f seed" as *u8, (br_find(body, bn, "\"seed\":1" as *u8) >= 0) as i64, ctr)
93 gv_check("T3g chat wrap declared" as *u8, (br_find(body, bn, "\"chat\":1" as *u8) >= 0) as i64, ctr)
94 // the needle is BUILT from bytes (92 34) rather than spelled with lexer escapes, so the test cannot depend on
95 // how this dialect reads a backslash inside a literal
96 let nd: *u8 = sys_mmap(64)
97 var no: i64 = br_cat(nd, 0, "a " as *u8); nd[no] = 92 as u8; no = no + 1; nd[no] = 34 as u8; no = no + 1
98 no = br_cat(nd, no, "quoted" as *u8); nd[no] = 92 as u8; no = no + 1; nd[no] = 34 as u8; no = no + 1
99 no = br_cat(nd, no, " line" as *u8)
100 gv_check("T3h the prompt's quote is escaped" as *u8, (br_find(body, bn, nd) >= 0) as i64, ctr)
101 gv_check("T3i the prompt's newline is escaped (no raw NL inside the body)" as *u8, (br_find(body, bn, "line\nsecond" as *u8) < 0) as i64, ctr)
102 gv_check("T3j neg-control an over-cap prompt is refused, never truncated" as *u8, (br_engine_body(body, 64, prompt, br_slen(prompt), 512, 700, 800, 64, 1) < 0) as i64, ctr)
103
104 // ---- T4..T7 the reply classifier on canned replies ----
105 let meta: *i64 = sys_mmap(BR_META_SLOTS * BR_I64) as *i64
106 let outb: *u8 = sys_mmap(BG_CAP)
107 let raw: *u8 = "Hello\nworld \"q\" done" as *u8
108 let jb: *u8 = sys_mmap(BG_CAP)
109 var jo: i64 = nsv_cat(jb, 0, "{\"ok\":1,\"mode\":\"i8\",\"prompt_tokens\":88,\"gen_tokens\":57,\"ms_total\":9100,\"ms_per_token\":159,\"eos\":1,\"temp\":700,\"seed\":1,\"text\":\"" as *u8)
110 jo = nsv_jesc(jb, jo, raw, br_slen(raw))
111 jo = nsv_cat(jb, jo, "\"}" as *u8)
112 jb[jo] = 0 as u8
113 let resp: *u8 = sys_mmap(BG_CAP)
114 let rn: i64 = bg_http(resp, 200, jb)
115 let tl: i64 = br_engine_parse_resp(resp, rn, outb, BG_CAP, meta)
116 gv_check_eq("T4 a 200 reply yields the unescaped text length" as *u8, tl, br_slen(raw), ctr)
117 var same: i64 = 0
118 if tl == br_slen(raw) { same = 1; var k: i64 = 0; while k < tl { if outb[k] != raw[k] { same = 0 } k = k + 1 } }
119 gv_check("T4a the text round-trips byte for byte through the serve's own escaper" as *u8, same, ctr)
120 gv_check_eq("T4b gen_tokens" as *u8, meta[1], 57, ctr)
121 gv_check_eq("T4c ms_total" as *u8, meta[2], 9100, ctr)
122 gv_check_eq("T4d eos" as *u8, meta[4], 1, ctr)
123 gv_check_eq("T4e http status recorded" as *u8, meta[3], 200, ctr)
124 gv_check_eq("T4f no engine err on success" as *u8, meta[5], 0, ctr)
125 let rn5: i64 = bg_http(resp, 400, "{\"ok\":0,\"err\":7}" as *u8)
126 let r5: i64 = br_engine_parse_resp(resp, rn5, outb, BG_CAP, meta)
127 gv_check_eq("T5 a 400 with an engine err is a per-prompt REFUSAL (passthrough row)" as *u8, r5, BR_ENG_REFUSED, ctr)
128 gv_check_eq("T5a the engine's err travels in meta" as *u8, meta[5], 7, ctr)
129 let rn6: i64 = bg_http(resp, 400, "{\"ok\":0,\"err\":1}" as *u8)
130 gv_check_eq("T6 neg-control err=1 (a malformed request) ABORTS, it is never a passthrough" as *u8, br_engine_parse_resp(resp, rn6, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
131 let rn7: i64 = bg_http(resp, 503, "{\"ok\":0}" as *u8)
132 gv_check_eq("T7 neg-control a 503 ABORTS" as *u8, br_engine_parse_resp(resp, rn7, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
133 let rn7b: i64 = bg_http(resp, 200, "{\"ok\":0,\"text\":\"x\"}" as *u8)
134 gv_check_eq("T7a neg-control a 200 without ok:1 ABORTS" as *u8, br_engine_parse_resp(resp, rn7b, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
135 gv_check_eq("T7b neg-control garbage bytes ABORT" as *u8, br_engine_parse_resp("not http at all" as *u8, 15, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
136 gv_check_eq("T7c neg-control an empty reply ABORTS" as *u8, br_engine_parse_resp(resp, 0, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
137
138 // ---- T8 idempotent re-run: a finished split is skipped without touching the engine ----
139 let cfg: *i64 = sys_mmap(BR_CFG_SLOTS * BR_I64) as *i64
140 cfg[0] = 0; cfg[1] = 512; cfg[2] = 0; cfg[3] = 700; cfg[4] = 800; cfg[5] = 64; cfg[6] = 1; cfg[7] = BG_TTL
141 cfg[8] = BG_LEASE_ROOT as i64
142 let dead: *i64 = br_eng_alloc()
143 br_engine_parse(BG_ENGINE_DEAD, dead)
144 dead[5] = 2
145 let progress: *u8 = "/tmp/nx_bright_rewrite_gate/gatefix.progress" as *u8
146 let st: *i64 = sys_mmap(BR_ST_SLOTS * BR_I64) as *i64
147 let r8: i64 = br_run_split(BG_ROOT, "biology" as *u8, BG_OUT, cfg, dead, progress, st)
148 gv_check_eq("T8 a split whose final file exists returns 0" as *u8, r8, 0, ctr)
149 gv_check_eq("T8a state COMPLETE-EXISTING" as *u8, st[8], BR_STATE_EXISTING, ctr)
150 bg_split_path(pb, "biology" as *u8, "queries.gatefix.tsv.part" as *u8)
151 gv_check("T8b no part file was opened for a finished split" as *u8, (bg_exists(pb) == 0) as i64, ctr)
152
153 // ---- T9 the lease: a split held elsewhere is skipped; released, the same call reaches the engine ----
154 let lname: *u8 = sys_mmap(BR_PATH_CAP)
155 br_lease_name(lname, BG_OUT, "economics" as *u8)
156 let hb: *u8 = sys_mmap(BR_PATH_CAP)
157 ls_release_root(BG_LEASE_ROOT, lname, "other-runner" as *u8)
158 let la: i64 = ls_acquire_root(BG_LEASE_ROOT, lname, "other-runner" as *u8, BG_TTL, hb)
159 gv_check_eq("T9 fixture: another runner holds the economics lease" as *u8, la, 0, ctr)
160 let r9: i64 = br_run_split(BG_ROOT, "economics" as *u8, BG_OUT, cfg, dead, progress, st)
161 gv_check_eq("T9a a leased split is skipped (returns 0)" as *u8, r9, 0, ctr)
162 gv_check_eq("T9b state LEASED-ELSEWHERE" as *u8, st[8], BR_STATE_LEASED, ctr)
163 gv_check_eq("T9c nothing written under another runner's lease" as *u8, st[1], 0, ctr)
164 ls_release_root(BG_LEASE_ROOT, lname, "other-runner" as *u8)
165 let r9d: i64 = br_run_split(BG_ROOT, "economics" as *u8, BG_OUT, cfg, dead, progress, st)
166 gv_check_eq("T9d neg-control: released, the same call proceeds past the lease to the engine" as *u8, st[8], BR_STATE_ENGINE_DOWN, ctr)
167 let lb: i64 = ls_acquire_root(BG_LEASE_ROOT, lname, "after-run" as *u8, BG_TTL, hb)
168 gv_check_eq("T9e the run released its own lease on exit" as *u8, lb, 0, ctr)
169 ls_release_root(BG_LEASE_ROOT, lname, "after-run" as *u8)
170
171 // ---- T10 a dead engine ABORTS the split with the rows untouched ----
172 let r10: i64 = br_run_split(BG_ROOT, "earth_science" as *u8, BG_OUT, cfg, dead, progress, st)
173 gv_check_eq("T10 the split ran (returns 0)" as *u8, r10, 0, ctr)
174 gv_check_eq("T10a state ENGINE-DOWN" as *u8, st[8], BR_STATE_ENGINE_DOWN, ctr)
175 gv_check_eq("T10b zero rows written: an unreachable engine never becomes a passthrough row" as *u8, st[1], 0, ctr)
176 gv_check_eq("T10c zero passthrough counted" as *u8, st[2], 0, ctr)
177 gv_check_eq("T10d the engine rc is UNREACHABLE" as *u8, st[9], BR_ENG_UNREACHABLE, ctr)
178 gv_check_eq("T10e the fixture reached the condition: 2 queries were in the split" as *u8, st[0], 2, ctr)
179 bg_split_path(pb, "earth_science" as *u8, "queries.gatefix.tsv" as *u8)
180 gv_check("T10f no final file for an aborted split" as *u8, (bg_exists(pb) == 0) as i64, ctr)
181
182 // ---- T11 the split verdict (pure) ----
183 gv_check_eq("T11 all rows written and none passthrough -> COMPLETE" as *u8, br_split_verdict(3, 3, 3, 1, 0), BR_STATE_COMPLETE, ctr)
184 gv_check_eq("T11a every row this run a passthrough -> ALL-PASSTHROUGH (never renamed)" as *u8, br_split_verdict(3, 3, 3, 3, 0), BR_STATE_ALL_PASSTHROUGH, ctr)
185 gv_check_eq("T11b a confirmed full part file with nothing new written -> COMPLETE" as *u8, br_split_verdict(3, 3, 0, 0, 0), BR_STATE_COMPLETE, ctr)
186 gv_check_eq("T11c rows missing -> PARTIAL" as *u8, br_split_verdict(3, 2, 2, 0, 0), BR_STATE_PARTIAL, ctr)
187 gv_check_eq("T11d a limit run -> SMOKE even when every row landed" as *u8, br_split_verdict(3, 3, 3, 0, 2), BR_STATE_SMOKE, ctr)
188 gv_check_eq("T11e neg-control an empty split never completes from nothing" as *u8, br_split_verdict(0, 0, 0, 0, 0), BR_STATE_PARTIAL, ctr)
189
190 // ---- T13..T15 the oracle dialect: same question, its own wire, its own refusal shape ----
191 let lb: *u8 = sys_mmap(BG_CAP)
192 let ln: i64 = br_engine_body_llamacpp(lb, BG_CAP, prompt, br_slen(prompt), 512, 700, 800, 64, 1)
193 gv_check("T13 llamacpp body built" as *u8, (ln > 0) as i64, ctr)
194 gv_check("T13a the prompt is wrapped in the sovereign ChatML shape (user open)" as *u8, (br_find(lb, ln, "<|im_start|>user" as *u8) >= 0) as i64, ctr)
195 gv_check("T13b ... and the assistant open closes it" as *u8, (br_find(lb, ln, "<|im_start|>assistant" as *u8) >= 0) as i64, ctr)
196 gv_check("T13c n_predict" as *u8, (br_find(lb, ln, "\"n_predict\":512" as *u8) >= 0) as i64, ctr)
197 gv_check("T13d temperature as a decimal" as *u8, (br_find(lb, ln, "\"temperature\":0.700" as *u8) >= 0) as i64, ctr)
198 gv_check("T13e top_p as a decimal" as *u8, (br_find(lb, ln, "\"top_p\":0.800" as *u8) >= 0) as i64, ctr)
199 gv_check("T13f seed" as *u8, (br_find(lb, ln, "\"seed\":1" as *u8) >= 0) as i64, ctr)
200 gv_check("T13g prompt cache off" as *u8, (br_find(lb, ln, "\"cache_prompt\":false" as *u8) >= 0) as i64, ctr)
201 let pm: *u8 = sys_mmap(32)
202 br_cat_permil(pm, 0, BG_PERMIL_ONE)
203 gv_check("T13h permil 1000 prints 1.000" as *u8, br_streq(pm, "1.000" as *u8), ctr)
204 br_cat_permil(pm, 0, BG_PERMIL_ZERO)
205 gv_check("T13i permil 0 prints 0.000 (greedy)" as *u8, br_streq(pm, "0.000" as *u8), ctr)
206 let lj: *u8 = sys_mmap(BG_CAP)
207 var ljo: i64 = nsv_cat(lj, 0, "{\"index\":0,\"content\":\"" as *u8)
208 ljo = nsv_jesc(lj, ljo, raw, br_slen(raw))
209 ljo = nsv_cat(lj, ljo, "\",\"tokens_predicted\":301,\"tokens_evaluated\":88,\"stop_type\":\"limit\",\"timings\":{\"prompt_ms\":40.5,\"predicted_ms\":2210.7}}" as *u8)
210 lj[ljo] = 0 as u8
211 let lrn: i64 = bg_http(resp, 200, lj)
212 let ltl: i64 = br_engine_parse_resp_llamacpp(resp, lrn, outb, BG_CAP, meta)
213 gv_check_eq("T14 a llama.cpp 200 yields the unescaped content length" as *u8, ltl, br_slen(raw), ctr)
214 var lsame: i64 = 0
215 if ltl == br_slen(raw) { lsame = 1; var lk: i64 = 0; while lk < ltl { if outb[lk] != raw[lk] { lsame = 0 } lk = lk + 1 } }
216 gv_check("T14a the content round-trips byte for byte" as *u8, lsame, ctr)
217 gv_check_eq("T14b tokens_predicted" as *u8, meta[1], BG_ORACLE_TOK_PRED, ctr)
218 gv_check_eq("T14c predicted_ms (integer part)" as *u8, meta[2], BG_ORACLE_PRED_MS, ctr)
219 let lrn5: i64 = bg_http(resp, 400, "{\"error\":{\"code\":400,\"message\":\"the request exceeds the available context size\",\"type\":\"invalid_request_error\"}}" as *u8)
220 gv_check_eq("T15 a 400 naming the context window is a per-prompt REFUSAL" as *u8, br_engine_parse_resp_llamacpp(resp, lrn5, outb, BG_CAP, meta), BR_ENG_REFUSED, ctr)
221 let lrn6: i64 = bg_http(resp, 400, "{\"error\":{\"code\":400,\"message\":\"invalid json\",\"type\":\"invalid_request_error\"}}" as *u8)
222 gv_check_eq("T15a neg-control any other 400 ABORTS" as *u8, br_engine_parse_resp_llamacpp(resp, lrn6, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
223 let lrn7: i64 = bg_http(resp, 200, "{\"index\":0,\"stop_type\":\"limit\"}" as *u8)
224 gv_check_eq("T15b neg-control a 200 without content ABORTS" as *u8, br_engine_parse_resp_llamacpp(resp, lrn7, outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
225 gv_check_eq("T15c neg-control a 503 ABORTS" as *u8, br_engine_parse_resp_llamacpp(resp, bg_http(resp, 503, "{\"error\":\"loading\"}" as *u8), outb, BG_CAP, meta), BR_ENG_ABORT, ctr)
226
227 // ---- T12 the progress path hangs off the bright root, not the CWD ----
228 let pp: *u8 = sys_mmap(BR_PATH_CAP)
229 br_progress_path(pp, "knowledge/beir/bright" as *u8, "tsqrsov0916" as *u8)
230 gv_check("T12 progress path derived from root=" as *u8, br_streq(pp, "knowledge/beir/bright/../../status/bright_rewrite.tsqrsov0916.progress" as *u8), ctr)
231
232 gv_kv("body_bytes" as *u8, bn)
233 gv_kv("t4_text_len" as *u8, tl)
234 gv_kv("t10_rows" as *u8, st[0])
235 gv_kv("t10_written" as *u8, st[1])
236 let rc: i64 = gv_verdict("BRIGHT-REWRITE-GATE" as *u8, ctr, "the remote door refuses to invent rows, the re-run is idempotent, the lease partitions runners, the verdict names ALL-PASSTHROUGH" as *u8)
237 sys_exit(rc)
238 return rc
239}