nx_analyst_infer.nx
buildroot/runtime/nx_analyst_infer.nx
about
nx_analyst_infer.nx -- STATISTICAL INFERENCE for the general Nishi analyst: the "is it actually real?"
layer that every SOTA analyst tool (pandas/scipy, R, DuckDB+stats) reports and ours did not.
THE GAP THIS CLOSES (measured 2026-07-23, ws=analyst-sota): nx_analyst_multi computes Pearson r and
nx_analyst_report NAMES A KEY DRIVER from it -- with NO significance guard whatsoever. The driver was a
bare argmax over |r|, so the report named one at ANY sample size. Its capstone gate happens to run at
n=300 where its r=-172 IS real, so no live finding was false -- but nothing in the code said so, and the
same call at n=8 returns the same confident sentence about pure noise (this organ's T2/T4 teeth show the
flip). Naming a driver that cannot be distinguished from noise is the liar-kill law applied to statistics.
The ecosystem ALREADY had sovereign inference (nx_survey_stats: chi-square vs a data-driven critical
table, fail-closed past the table, 95% proportion margin) but it was locked inside the SURVEY vertical
and consumed se_ballots. This organ is the general, dataset-agnostic extraction (rule 15 DRY): it takes
a bare r and n, so ANY caller -- dataframe, store, timeseries, survey -- can ask "is it real?".
METHOD: Student-t test on a correlation coefficient. t = r*sqrt(n-2)/sqrt(1-r^2), df = n-2, compared to
a two-tailed alpha=.05 critical value. Both sides are SQUARED so the whole test is INTEGER-EXACT -- no
sqrt, no float, bit-reproducible (the ecosystem's integer-exact-analytics EXCEED holds through inference):
t^2 > tc^2 <=> rp^2 * (n-2) > ceil( tcp^2 * (SCALE_SQ - rp^2) / SCALE_SQ )
with rp = r*1000 and tcp = t_crit*1000. The RHS division rounds UP so truncation can only make the test
STRICTER -- an integer-rounding artifact can never manufacture a false "significant".
FAIL-CLOSED BY CONSTRUCTION (mirrors nx_survey_stats' own adversary guard):
- n < 3 -> df < 1 -> CANNOT TEST (-1), never silently "not significant"
- df not tabulated -> use the largest tabulated df <= query. t_crit DECREASES in df, so a lower-df row
is a LARGER threshold = conservative. No usable row at all -> tcrit 0 -> NOT significant.
license_tier: ORIGINAL No hardware writes (Rule 26).
dependencies 2 imports · 5 importers
imports: nx_syscalls.nxnx_analyst_multi.nx
imported by: nx_analyst_causal.nxnx_analyst_dashboard.nxnx_analyst_infer_gate.nxnx_analyst_insight.nxnx_analyst_report.nx
structs
| none |
consts
| 31 | const AI_SCALE: i64 = 1000 // permille fixed point: r and t are both carried x1000 |
| 32 | const AI_SCALE_SQ: i64 = 1000000 // AI_SCALE * AI_SCALE |
| 33 | const AI_TBL_MAX: i64 = 64 // max critical-table rows held |
| 34 | const AI_CONF_CAP: i64 = 8192 // critical-table conf read window |
| 35 | const AI_MINN_CAP: i64 = 1000000 // give up searching for a min-n beyond this many pairs |
| 36 | const AI_MIN_PAIRS: i64 = 3 // df = n-2 >= 1 requires n >= 3 |
| 37 | const AI_TAB: i64 = 9 |
| 38 | const AI_HASH: i64 = 35 |
| 39 | const AI_NL: i64 = 10 |
| 40 | const AI_CR: i64 = 13 |
| 41 | const AI_ZERO: i64 = 48 |
| 42 | const AI_TBL_ALL: i64 = 512 // rows held when loading EVERY alpha (audit / Bonferroni lookup) |
| 43 | const AI_ALPHA_05: i64 = 50 // permille; the classic .05 two-tailed level, and a legacy line's default |
| 273 | const AI_MICRO: i64 = 1000000 |
| 274 | const AI_LN2_MICRO: i64 = 693147 // ln 2 in micro |
| 275 | const AI_EXP_TERMS: i64 = 16 // Taylor terms after range reduction (reduced arg < ln2, so ample) |
| 276 | const AI_EXP_KMAX: i64 = 40 // refuse absurd exponents rather than overflow the doubling loop |
| 277 | const AI_Z_ASYMPTOTE_DF: i64 = 10000 // the conf row carrying the normal quantile |
functions
| 50 | func ai_atoi_rng(buf: *u8, a: i64, b: i64) -> i64 called by 1: ai_tcrit_parse |
| 71 | func ai_tcrit_parse(alphas: *i64, dfs: *i64, tcs: *i64, maxn: i64, want_alpha: i64) -> i64 |
| 121 | func ai_tcrit_load(dfs: *i64, tcs: *i64, maxn: i64) -> i64 { return ai_tcrit_parse(0 as *i64, dfs, tcs, maxn, AI_ALPHA_05) } |
| 127 | func ai_tcrit_audit() -> i64 |
| 150 | func ai_alpha_for_m(m: i64) -> i64 |
| 167 | func ai_tcrit_from(dfs: *i64, tcs: *i64, cnt: i64, df: i64) -> i64 |
| 179 | func ai_r_sig_from(dfs: *i64, tcs: *i64, cnt: i64, rp: i64, n: i64) -> i64 |
| 201 | func ai_r_significant(rp: i64, n: i64) -> i64 called by 6: db_relrowai_r_verdictmainar_analyzeaz_sigaz_report calls 3: sys_mmapai_tcrit_loadai_r_sig_from |
| 207 | func ai_tcrit(df: i64) -> i64 |
| 213 | func ai_tcrit_alpha(alpha_permil: i64, df: i64) -> i64 |
| 220 | func ai_r_sig_alpha(rp: i64, n: i64, alpha_permil: i64) -> i64 |
| 232 | func ai_r_sig_bonferroni(rp: i64, n: i64, m: i64) -> i64 |
| 242 | func ai_rank2_into(x: *i64, n: i64, out: *i64) -> i64 |
| 280 | func ai_exp_micro(w: i64) -> i64 |
| 302 | func ai_r_ci(rp: i64, n: i64, alpha_permil: i64, lo: *i64, hi: *i64) -> i64 |
| 337 | func ai_r_undef() -> i64 { return 0 - 2000 } called by 1: ai_partial_milli |
| 338 | func ai_partial_milli(r_xy: i64, r_xz: i64, r_yz: i64) -> i64 |
| 363 | func ai_confound_scan(target: *i64, cands: *i64, ncand: i64, n: i64, ci: i64, out_z: *i64, out_partial: *i64) -> i64 |
| 395 | func ai_spearman_milli(x: *i64, y: *i64, n: i64) -> i64 |
| 407 | func ai_min_n(rp: i64) -> i64 |
| 423 | func ai_itoa(v: i64, out: *u8, at: i64) -> i64 |
| 434 | func ai_cat(out: *u8, at: i64, s: *u8) -> i64 called by 1: ai_r_verdict |
| 440 | func ai_r_verdict(rp: i64, n: i64, out: *u8) -> i64 |
| 472 | func ai_key_driver_guarded(rs: *i64, ncol: i64, n: i64) -> i64 |