nx_crawl_sufficiency.nx
buildroot/runtime/nx_crawl_sufficiency.nx
about
nx_crawl_sufficiency.nx -- ADAPTIVE STOP: "do we know enough to stop fetching?" -- the /compare/webscraping
R5 contract (symbol cs_confidence). Concept source: crawl4ai's AdaptiveCrawler (docs/core/adaptive-crawling.md,
StatisticalStrategy in adaptive_crawler.py): confidence = coverage + consistency + saturation, stop at a bar.
Sovereign form, integer permil, no floats, no LLM, no embeddings:
COVERAGE for each query term t: doc_cov = df_t * 1000 / docs; freq = ilog2(1+tf_t) / ilog2(1+max_tf);
term = doc_cov * (1000 + freq_boost * freq / 1000) / 1000, capped at 1000; coverage = mean over terms.
CONSISTENCY permil of counted docs that are ON TOPIC: hold at least relevant_permil of the query terms (min 1).
(The source uses mean pairwise Jaccard of term sets, which REWARDS redundancy -- five copies of one
page score as perfectly consistent. Ours cannot be inflated by copies: see the dedup below.)
SATURATION 1000 - new_terms(last window) * 1000 / new_terms(first window): diminishing discovery of NEW
vocabulary. UNOBSERVABLE (not 0, not 1000) until two windows exist or when the term set is full.
confidence = (w_cov * coverage + w_con * consistency + w_sat * saturation) / (w_cov + w_con + w_sat)
EXCEED over the source: a doc whose simhash lands within simhash_ham of an already-counted doc is a NEAR-DUPLICATE
and is not counted anywhere (not df, not tf, not the new-term history) -- it is tallied as a dup so the partition
docs_added == counted + dups always sums. A crawl that keeps fetching copies therefore cannot talk itself into
confidence, which is exactly the failure the source's Jaccard consistency has.
THIRD STATE: cs_should_stop returns CONTINUE / CONFIDENT / SATURATED, and saturation carries its own
sat_observed flag: when the term set fills, saturation is UNOBSERVABLE and counts as 0 in confidence (it can
only make the verdict more conservative, never acquit) and the report names it.
EVERY NUMBER IS A CONF ROW: knowledge/crawl_sufficiency.conf (nx_lane_conf semantics), bootstrap defaults
below cite their source. Consumers: nx_web_crawl_step (query-scoped crawl), the research fetch, the CLI.
license_tier: ORIGINAL module: nishi-core.search.sufficiency No hw writes (Rule 26).
dependencies 5 imports · 3 importers
imports: nx_syscalls.nxnx_lane_conf.nxnx_search_inverted.nxnx_intlog.nxnx_simhash.nx
imported by: nx_crawl_sufficiency_cli.nxnx_crawl_sufficiency_gate.nxnx_web_crawl_step.nx
structs
| none |
consts
| 29 | const CS_CONF: *u8 = "knowledge/crawl_sufficiency.conf" |
| 31 | const CS_DEF_W_COVERAGE: i64 = 400 // crawl4ai StatisticalStrategy.calculate_confidence: 0.4 * coverage |
| 32 | const CS_DEF_W_CONSISTENCY: i64 = 300 // 0.3 * consistency |
| 33 | const CS_DEF_W_SATURATION: i64 = 300 // 0.3 * saturation |
| 34 | const CS_DEF_CONFIDENCE_STOP: i64 = 700 // AdaptiveConfig.confidence_threshold = 0.7 |
| 35 | const CS_DEF_SATURATION_STOP: i64 = 800 // AdaptiveConfig.saturation_threshold = 0.8 |
| 36 | const CS_DEF_FREQ_BOOST: i64 = 500 // term_score = doc_coverage * (1 + 0.5 * freq_signal) |
| 37 | const CS_DEF_RELEVANT_PERMIL: i64 = 500 // ours: on topic = holds at least half the query terms (min 1); the source has no per-doc topic test |
| 38 | const CS_DEF_WINDOW: i64 = 1 // the source compares the FIRST and the LATEST new-term count; a wider window smooths |
| 39 | const CS_DEF_SIMHASH_HAM: i64 = 4 // WC_SIMHASH_HAM: the crawler's own near-duplicate bar (Manku 2007 uses 3), one estate value |
| 40 | const CS_DEF_TERMSET_CAP: i64 = 65536 // distinct term hashes tracked for saturation; full -> saturation UNOBSERVABLE, announced |
| 41 | const CS_DEF_HIST_CAP: i64 = 4096 // counted docs tracked (fingerprints + new-term history); full -> refuses further docs, announced |
| 42 | const CS_DEF_REQUIRE_SAT_OBSERVED: i64 = 1 // OURS: CONFIDENT needs an OBSERVED saturation. MEASURED 2026-08-24: one Wikipedia page holding |
| 45 | const CS_QMAX: i64 = 64 // query terms held; excess is REFUSED and counted in dropped_terms, never silently ignored |
| 46 | const CS_PERMIL: i64 = 1000 |
| 47 | const CS_HDR: i64 = 64 // i64 slots in the state header |
| 50 | const CS_S_QN: i64 = 0 |
| 51 | const CS_S_DOCS: i64 = 1 |
| 52 | const CS_S_DUPS: i64 = 2 |
| 53 | const CS_S_RELEVANT: i64 = 3 |
| 54 | const CS_S_TERMSET_CAP: i64 = 4 |
| 55 | const CS_S_TERMSET_USED: i64 = 5 |
| 56 | const CS_S_TERMSET_FULL: i64 = 6 |
| 57 | const CS_S_HIST_CAP: i64 = 7 |
| 58 | const CS_S_HIST_N: i64 = 8 |
| 59 | const CS_S_HIST_FULL: i64 = 9 |
| 60 | const CS_S_CONFIDENCE: i64 = 10 |
| 61 | const CS_S_COVERAGE: i64 = 11 |
| 62 | const CS_S_CONSISTENCY: i64 = 12 |
| 63 | const CS_S_SATURATION: i64 = 13 |
| 64 | const CS_S_SAT_OBSERVED: i64 = 14 |
| 65 | const CS_S_STOP: i64 = 15 |
| 66 | const CS_S_MAXTF: i64 = 16 |
| 67 | const CS_S_DROPPED_TERMS: i64 = 17 |
| 68 | const CS_S_CONF_SRC: i64 = 18 |
| 69 | const CS_S_FIRST_NEW: i64 = 19 |
| 70 | const CS_S_LAST_NEW: i64 = 20 |
| 71 | const CS_S_W_COV: i64 = 21 |
| 72 | const CS_S_W_CON: i64 = 22 |
| 73 | const CS_S_W_SAT: i64 = 23 |
| 74 | const CS_S_CONF_STOP: i64 = 24 |
| 75 | const CS_S_SAT_STOP: i64 = 25 |
| 76 | const CS_S_FREQ_BOOST: i64 = 26 |
| 77 | const CS_S_RELEVANT_PERMIL: i64 = 27 |
| 78 | const CS_S_WINDOW: i64 = 28 |
| 79 | const CS_S_HAM: i64 = 29 |
| 80 | const CS_S_P_QHASH: i64 = 30 |
| 81 | const CS_S_P_QTF: i64 = 31 |
| 82 | const CS_S_P_QDF: i64 = 32 |
| 83 | const CS_S_P_TERMSET: i64 = 33 |
| 84 | const CS_S_P_HIST: i64 = 34 |
| 85 | const CS_S_P_FPS: i64 = 35 |
| 86 | const CS_S_P_SEEN: i64 = 36 |
| 87 | const CS_S_REQUIRE_SAT: i64 = 37 |
| 89 | const CS_CONTINUE: i64 = 0 |
| 90 | const CS_CONFIDENT: i64 = 1 |
| 91 | const CS_SATURATED: i64 = 2 |
functions
| 94 | func cs_conf_one(key: *u8, dflt: i64) -> i64 |
| 103 | func cs_tokens(text: *u8, n: i64, out: *i64, cap: i64) -> i64 |
| 122 | func cs_new_t(query: *u8, qlen: i64, termset_cap: i64, hist_cap: i64) -> *i64 |
| 180 | func cs_new(query: *u8, qlen: i64) -> *i64 |
| 186 | func cs_free(st: *i64) -> i64 |
| 199 | func cs_termset_add(st: *i64, h0: i64) -> i64 called by 1: cs_add_doc |
| 219 | func cs_add_doc(st: *i64, text: *u8, n: i64) -> i64 |
| 266 | func cs_coverage(st: *i64) -> i64 |
| 290 | func cs_consistency(st: *i64) -> i64 called by 1: cs_confidence |
| 295 | func cs_saturation(st: *i64) -> i64 called by 1: cs_confidence |
| 318 | func cs_confidence(st: *i64) -> i64 |
| 337 | func cs_should_stop(st: *i64) -> i64 calls 1: cs_confidence |
| 343 | func cs_r_num(out: *u8, cap: i64, o: i64, v: i64) -> i64 |
| 355 | func cs_r_str(out: *u8, cap: i64, o: i64, s: *u8) -> i64 called by 1: cs_report |
| 361 | func cs_report(st: *i64, out: *u8, cap: i64) -> i64 |