code wiki / (root) / nx_jobfollow_parse.nx

nx_jobfollow_parse.nx source

↩ module page · 157 lines · 8600 B

1// nx_jobfollow_parse.nx -- THE PURE HALF of the job-pointer follower: parsing and buffer arithmetic, 2// with NO transport dependency at all. 3// 4// WHY IT IS A SEPARATE FILE. The follower has to live in TWO places: nx_jobfollow_lib (which an 5// explicit caller composes) and nx_https_post_lib (so that EVERY caller of hp_post_json inherits it 6// without editing 81 organs). But nx_jobfollow_lib imports nx_https_post_lib to do its polling, so 7// putting the follow INTO the post lib would close an import cycle. Splitting the pure half out is the 8// standard break: this file imports only nx_syscalls, so both layers above can share ONE implementation 9// and there is still exactly one job-id parser in the estate. 10// 11// AND THE PURE HALF IS THE HALF WORTH GATING. Everything here is buffer arithmetic over inputs a test 12// can construct, so a gate walks it without opening a socket -- the same reason the TLS fragmentation 13// split was pulled out of its loop on the same day. 14// 15// THE ANCHORED PARSE IS THE POINT. jf_job_id matches the whole literal `JOB-STARTED id=`, never a bare 16// `id=`. MEASURED 2026-09-04: a client scanning unanchored read the JOB id as the ORGAN id -- they are 17// both epoch-derived, so 1788537161 looked like a plausible prefix of the real 1788537161795845 -- and 18// then reported a receipt that never existed. 19// license_tier: ORIGINAL No hw writes (Rule 26). 20import "nx_syscalls.nx" 21 22const JF_PATHCAP: i64 = 256 23const JF_REQCAP: i64 = 4096 24const JF_QUOTE: i64 = 34 25const JF_BACKSLASH: i64 = 92 26const JF_SPACE: i64 = 32 27const JF_DEL: i64 = 127 28// ---- THE KEYED RE-ISSUE (dataio DI4, client half, 2026-09-05) ------------------------------------------------ 29// The edge answers an unsafe call whose backend ACCEPTED the request but produced no reply inside the edge window 30// with a problem+json carrying `"stage":"read-after-accept"` ("Outcome Unknown"). Re-posting blind double-applies; 31// not re-posting loses a receipt the server already wrote. The tools/call transport now reads params._idem and 32// answers a repeated key with `NX-IDEM REPLAY ... job=<id>` (the FIRST outcome, never a second execution) or 33// `NX-IDEM INFLIGHT` (the first is still running). So a re-post is safe BY CONSTRUCTION exactly when the request 34// carries `_idem`, and never otherwise. MEASURED 2026-09-05: nx_content_put_client posted a begin for a SOURCE 35// destination (the receiver hashes the 43 KB incumbent before answering), the edge answered Outcome Unknown, the 36// client printed `CP-BEGIN id= chunk_raw=` and exited 5 -- while the receiver had already accepted the transfer. 37const JF_UNKNOWN: *u8 = "\x22stage\x22:\x22read-after-accept\x22" as *u8 38const JF_KEYED: *u8 = "\x22_idem\x22" as *u8 39const JF_REPLAY: *u8 = "NX-IDEM REPLAY" as *u8 40const JF_INFLIGHT: *u8 = "NX-IDEM IN-FLIGHT" as *u8 // the transport's literal (nx_tools_api ta_mcp_call), hyphenated -- verified by grep, not recalled 41 42func jf_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 43func jf_eo(s: *u8) -> i64 { sys_write(2, s, jf_slen(s)); return 0 } 44func jf_enum(v: i64) -> i64 { 45 let b: *u8 = sys_mmap(32) 46 var m: i64 = v 47 var i: i64 = 31 48 if m == 0 { i = i - 1; b[i] = 48 as u8 } 49 while m > 0 { i = i - 1; b[i] = (48 + (m % 10)) as u8; m = m / 10 } 50 sys_write(2, (b as i64 + i) as *u8, 31 - i) 51 return 0 52} 53// index just past needle, or -1. Exits on a FLAG, never by clobbering the cursor -- the loop-exit 54// sentinel defect this estate has recorded four times in one day. 55func jf_find(buf: *u8, n: i64, needle: *u8) -> i64 { 56 let m: i64 = jf_slen(needle) 57 if m == 0 { return 0 - 1 } 58 var i: i64 = 0 59 var hit: i64 = 0 - 1 60 while i + m <= n { 61 var j: i64 = 0 62 var same: i64 = 1 63 while j < m { if buf[i + j] != needle[j] { same = 0; j = m } else { j = j + 1 } } 64 if same == 1 { if hit < 0 { hit = i + m } } 65 i = i + 1 66 } 67 return hit 68} 69func jf_has(buf: *u8, n: i64, needle: *u8) -> i64 { if jf_find(buf, n, needle) >= 0 { return 1 } return 0 } 70// THE ANCHORED job-pointer read. Matches the whole report token, never a bare `id=`. 71func jf_job_id(buf: *u8, n: i64) -> i64 { 72 var p: i64 = jf_find(buf, n, "JOB-STARTED id=" as *u8) 73 if p < 0 { 74 // the transport's REPLAY of a keyed call names the FIRST execution's job: `NX-IDEM REPLAY key=... job=<id>`; 75 // anchored on the report literal and then on its own ` job=` field, never a bare `id=` 76 let r: i64 = jf_find(buf, n, JF_REPLAY) 77 if r < 0 { return 0 - 1 } 78 let q: i64 = jf_find(((buf as i64) + r) as *u8, n - r, " job=" as *u8) 79 if q < 0 { return 0 - 1 } 80 p = r + q 81 } 82 var i: i64 = p 83 var v: i64 = 0 84 var got: i64 = 0 85 while i < n { 86 let c: i64 = buf[i] as i64 87 if c < 48 { i = n } else { if c > 57 { i = n } else { v = v * 10 + (c - 48); got = 1; i = i + 1 } } 88 } 89 if got == 0 { return 0 - 1 } 90 return v 91} 92func jf_append(out: *u8, o: i64, s: *u8) -> i64 { 93 var p: i64 = o 94 var i: i64 = 0 95 let n: i64 = jf_slen(s) 96 while i < n { out[p] = s[i]; p = p + 1; i = i + 1 } 97 return p 98} 99func jf_append_num(out: *u8, o: i64, v: i64) -> i64 { 100 if v == 0 { out[o] = 48 as u8; return o + 1 } 101 let tmp: *u8 = sys_mmap(32) 102 var m: i64 = v 103 var i: i64 = 0 104 while m > 0 { tmp[i] = (48 + (m % 10)) as u8; m = m / 10; i = i + 1 } 105 var p: i64 = o 106 var j: i64 = 0 107 while j < i { out[p] = tmp[i - 1 - j]; p = p + 1; j = j + 1 } 108 return p 109} 110// REFUSE RATHER THAN ESCAPE, on the sibling clients' precedent: a capability token comes from a 111// known-safe alphabet, so a byte needing JSON escaping means the input is wrong, not that an escaper 112// is owed. A hand-rolled escaper fails silently and yields a request rejected for the wrong reason. 113func jf_json_safe(s: *u8, n: i64) -> i64 { 114 var i: i64 = 0 115 while i < n { 116 let c: i64 = s[i] as i64 117 if c == JF_QUOTE { return 0 } 118 if c == JF_BACKSLASH { return 0 } 119 if c < JF_SPACE { return 0 } 120 if c == JF_DEL { return 0 } 121 i = i + 1 122 } 123 return 1 124} 125// Is the artifact readable yet? nx_fs answers ABSENT before the job writes and EMPTY while it is still 126// zero-length, so readiness is the ABSENCE of both -- a positive test on a body whose shape we do not 127// yet know would pass on the error envelope itself. 128func jf_artifact_ready(buf: *u8, n: i64) -> i64 { 129 if n <= 0 { return 0 } 130 if jf_has(buf, n, "NX-FS DENIED" as *u8) == 1 { return 0 - 1 } 131 if jf_has(buf, n, "NX-FS ABSENT" as *u8) == 1 { return 0 } 132 if jf_has(buf, n, "NX-FS EMPTY" as *u8) == 1 { return 0 } 133 return 1 134} 135// 1 iff the reply is the edge's outcome-unknown envelope (503 read-after-accept) 136func jf_outcome_unknown(buf: *u8, n: i64) -> i64 { if n <= 0 { return 0 } return jf_has(buf, n, JF_UNKNOWN) } 137// 1 iff the REQUEST carries an idempotency key -- the only condition under which a re-post is safe 138func jf_req_keyed(req: *u8, n: i64) -> i64 { if n <= 0 { return 0 } return jf_has(req, n, JF_KEYED) } 139// 1 iff the transport says the keyed call's first execution is still running: wait one interval, ask again 140func jf_inflight(buf: *u8, n: i64) -> i64 { if n <= 0 { return 0 } return jf_has(buf, n, JF_INFLIGHT) } 141// THE DECISION, pure and gate-walkable: re-post iff (outcome unknown OR in-flight) AND the request is keyed. 142// An unkeyed request is NEVER re-posted, whatever the reply says: its 503 is returned as the reply, honestly. 143func jf_should_reissue(buf: *u8, n: i64, req: *u8, reqlen: i64) -> i64 { 144 if jf_req_keyed(req, reqlen) == 0 { return 0 } 145 // NO REPLY AT ALL is the same uncertainty as Outcome Unknown, and the key is what makes re-posting safe -- MEASURED 146 // 2026-09-05: under a load1 of 19 the FIRST post of a run failed at the transport (`CC-BEGIN: post failed`) on 147 // five of eleven transfers while every later post of the same run succeeded; the earlier rule ("an empty reply is a 148 // transport error, not an accepted call") was true and beside the point for a keyed request. 149 if n <= 0 { return 1 } 150 if jf_outcome_unknown(buf, n) == 1 { return 1 } 151 if jf_inflight(buf, n) == 1 { return 1 } 152 return 0 153} 154// POST, and if the edge answered with a job pointer, wait for the artifact and return THAT as the 155// receipt. Returns the receipt length in `out`, or 0. `readcap` may be zero length: then a promotion is 156// reported as UNFOLLOWABLE rather than silently mis-parsed -- naming the missing input is the whole 157// point, since without it the caller would otherwise read the job id as the organ's id.