code wiki / (root) / nx_arxiv_census.nx

nx_arxiv_census.nx source

↩ module page · 132 lines · 6371 B

1// nx_arxiv_census.nx -- COMPLETE-POPULATION CENSUS of an arXiv date window. Turns "I read the current 2// month" from a seat's assertion into a MECHANICAL verdict, which is what the sotabar/barscan law needs. 3// 4// COMPOSES the incumbents, deliberately does not duplicate them: 5// se_fetch (nx_search_extern) -- polite sovereign-TLS fetch, the ONE arXiv fetcher 6// em_int_after (nx_search_emerge) -- opensearch:totalResults reader 7// em_collect_yms (nx_search_emerge) -- <published> year-month extractor 8// em_maxym (nx_search_emerge) -- newest YYYY-MM, which IS the barscan newest= field 9// ac_reason/ac_verdict (nx_arxiv_census_lib) -- the ONE decision, shared with the gate in-process 10// 11// The ONE question neither incumbent asks: does opensearch:totalResults RECONCILE against the number of 12// entries actually delivered? Equal means the window is a POPULATION and an absence claim over it is sound; 13// fewer means a SAMPLE wearing a population's clothes and absence over it is UNPROVEN. 14// 15// nx_search_emerge is NOT defective and this organ does not replace it: it samples 12 on purpose for a cheap 16// daily velocity signal and HONESTLY prints "sampled hits" beside "total volume". That is a different 17// question (is this field moving) from this one (what did this window actually contain). Its em_collect_yms 18// cap is silent at the FUNCTION level for any future composer, which is filed as dataio rung DI19. 19// license_tier: ORIGINAL 20import "nx_search_extern.nx" 21import "nx_search_emerge.nx" 22import "nx_arxiv_census_lib.nx" 23import "nx_syscalls.nx" 24import "nx_x509_trust_store.nx" 25import "nx_trust_store_load_from_certdata.nx" 26 27const AC_BUFCAP: i64 = 4194304 28const AC_URLCAP: i64 = 1024 29const AC_MAXD: i64 = 4096 // date slots. nd==AC_MAXD is ANNOUNCED as a local cap, never silent. 30const AC_YMSLOT: i64 = 8 31const AC_TRUST_HINT: i64 = 512 32const AC_DEFAULT_MAX: i64 = 300 33const AC_MINARGC: i64 = 4 34const AC_ASCII_ZERO: i64 = 48 35const AC_ASCII_NINE: i64 = 57 36const AC_NUMBUF: i64 = 28 37 38func acp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 39func acn(v: i64) -> i64 { 40 if v==0 { sys_write(1,"0" as *u8,1); return 0 } 41 var m: i64=v 42 if m<0 { sys_write(1,"-" as *u8,1); m=0-m } 43 let t: *u8=sys_mmap(AC_NUMBUF); var k: i64=0 44 while m>0 { t[k]=(AC_ASCII_ZERO+(m%10)) as u8; m=m/10; k=k+1 } 45 while k>0 { k=k-1; sys_write(1,(((t as i64)+k) as *u8),1) } 46 return 0 47} 48func ac_numto(dst: *u8, off: i64, v: i64) -> i64 { 49 var o: i64=off 50 if v==0 { dst[o]=AC_ASCII_ZERO as u8; return o+1 } 51 var m: i64=v 52 let t: *u8=sys_mmap(AC_NUMBUF); var k: i64=0 53 while m>0 { t[k]=(AC_ASCII_ZERO+(m%10)) as u8; m=m/10; k=k+1 } 54 while k>0 { k=k-1; dst[o]=t[k]; o=o+1 } 55 return o 56} 57func ac_atoi(s: *u8) -> i64 { 58 var v: i64=0; var i: i64=0; var seen: i64=0 59 while s[i]!=(0 as u8) { 60 let c: i64=s[i] as i64 61 if c>=AC_ASCII_ZERO { if c<=AC_ASCII_NINE { v=v*10+(c-AC_ASCII_ZERO); seen=1 } } 62 i=i+1 63 } 64 if seen==0 { return 0-1 } 65 return v 66} 67 68// the trust store lives at data/ from the estate root and ../data/ from buildroot; a CWD must not decide a verdict 69func ac_trust() -> i64 { 70 let a: i64=nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, AC_TRUST_HINT, AC_BUFCAP) 71 if a>0 { return a } 72 return nx_trust_store_load_from_certdata("../data/mozilla_certdata.txt" as *u8, AC_TRUST_HINT, AC_BUFCAP) 73} 74 75func ac_usage() -> i64 { 76 acp("usage: nx_arxiv_census <category> <YYYYMMDD-from> <YYYYMMDD-to> [max_results]\n" as *u8) 77 acp(" e.g. nx_arxiv_census cs.SE 20260901 20260907\n" as *u8) 78 acp(" exit 0 COMPLETE (delivered==totalResults) | 1 CAPPED | 2 usage | 3 UNREADABLE\n" as *u8) 79 return 0 80} 81 82func main(argc: i64, argv: *i64) -> i64 { 83 if argc<AC_MINARGC { ac_usage(); sys_exit(ACV_USAGE); return ACV_USAGE } 84 let cat: *u8=argv[1] as *u8 85 let dfrom: *u8=argv[2] as *u8 86 let dto: *u8=argv[3] as *u8 87 var maxr: i64=AC_DEFAULT_MAX 88 if argc>AC_MINARGC { let m: i64=ac_atoi(argv[AC_MINARGC] as *u8); if m>0 { maxr=m } } 89 90 let tr: i64=ac_trust() 91 if tr<=0 { acp("AC-REASON trust store load FAILED from data/ and ../data/\n" as *u8); acp("verdict=UNREADABLE\n" as *u8); sys_exit(ACV_UNREADABLE); return ACV_UNREADABLE } 92 let store: *TrustStore=tr as *TrustStore 93 94 let url: *u8=sys_mmap(AC_URLCAP); var o: i64=0 95 o=se_app(url,o,"https://export.arxiv.org/api/query?search_query=cat:" as *u8) 96 o=se_app(url,o,cat) 97 o=se_app(url,o,"+AND+submittedDate:[" as *u8) 98 o=se_app(url,o,dfrom); o=se_app(url,o,"0000+TO+" as *u8); o=se_app(url,o,dto); o=se_app(url,o,"0000]" as *u8) 99 o=se_app(url,o,"&sortBy=submittedDate&sortOrder=descending&max_results=" as *u8) 100 o=ac_numto(url,o,maxr) 101 url[o]=0 as u8 102 103 acp("AC-QUERY " as *u8); sys_write(1,url,o); acp("\n" as *u8) 104 105 let buf: *u8=sys_mmap(AC_BUFCAP) 106 let n: i64=se_fetch(store, url, buf, AC_BUFCAP, "arXiv" as *u8) 107 if n<=0 { acp("AC-REASON fetch returned no body\n" as *u8); acp("verdict=UNREADABLE\n" as *u8); sys_exit(ACV_UNREADABLE); return ACV_UNREADABLE } 108 109 let total: i64=em_int_after(buf, n, "opensearch:totalResults>" as *u8) 110 let flat: *u8=sys_mmap(AC_MAXD*AC_YMSLOT) 111 let nd: i64=em_collect_yms(buf, n, "<published>" as *u8, flat, AC_MAXD) 112 let newest: *u8=sys_mmap(AC_YMSLOT) 113 em_maxym(flat, nd, newest) 114 let recent: i64=em_count_eq(flat, nd, newest) 115 116 let reason: i64=ac_reason(total, nd, AC_MAXD) 117 let verdict: i64=ac_verdict_of_reason(reason) 118 119 acp("category=" as *u8); acp(cat); acp(" from=" as *u8); acp(dfrom); acp(" to=" as *u8); acp(dto); acp("\n" as *u8) 120 acp("body_bytes=" as *u8); acn(n); acp("\n" as *u8) 121 acp("max_results=" as *u8); acn(maxr); acp("\n" as *u8) 122 acp("totalResults=" as *u8); acn(total); acp("\n" as *u8) 123 acp("delivered=" as *u8); acn(nd); acp("\n" as *u8) 124 acp("newest_ym=" as *u8); acp(newest); acp("\n" as *u8) 125 acp("newest_ym_count=" as *u8); acn(recent); acp("\n" as *u8) 126 acp("local_slot_cap=" as *u8); acn(AC_MAXD); acp("\n" as *u8) 127 acp("reason_code=" as *u8); acn(reason); acp("\n" as *u8) 128 acp("AC-REASON " as *u8); acp(ac_reason_text(reason)); acp("\n" as *u8) 129 acp("verdict=" as *u8); acp(ac_verdict_text(verdict)); acp("\n" as *u8) 130 sys_exit(verdict) 131 return verdict 132}