code wiki / _hdl_build / nx_hr_bot_behavior.nx
nx_hr_bot_behavior.nx source
↩ module page · 55 lines · 4585 B
1// nx_hr_bot_behavior.nx -- NISHI HR, visitor module REDESIGNED for PRIVACY + sophistication (operator 2026-06-20:
2// "we are NOT going to log visitors / we don't want IP / we don't want anything; evaluate bots by BEHAVIOR even
3// if they are sophisticated"). SUPERSEDES the UA/IP approach (nx_hr_visitor list-match + nx_hr_visitor_log IP-log),
4// which sophisticated bots defeat (UA spoof + residential-IP rotation) AND which logs PII. This evaluates a visitor
5// purely from EPHEMERAL per-session BEHAVIOR signals -- ZERO IP / UA / identity inputs by construction (privacy by
6// design: nothing about the visitor is stored). Researcher-grounded (sovereign fetch, cited):
7// knowledge/fetched/botbehavior_scraping.raw -- web-scraping countermeasures: CAPTCHA/challenge, fingerprinting,
8// bot-detection, HONEYPOTS (invisible traps humans never touch). [en.wikipedia.org/wiki/Web_scraping]
9// knowledge/fetched/botbehavior_fingerprint.raw -- passive/behavioral fingerprinting signals. [.../Device_fingerprint]
10// knowledge/fetched/botbehavior_bot.raw -- bot taxonomy/threat. [.../Internet_bot]
11// DESIGN: no single signal (a sophisticated bot fakes any one); LAYER them + impose a cost (proof-of-work/JS
12// challenge) -- a bot can spoof a UA but cannot cheaply manufacture real human interaction entropy AND solve a
13// per-session challenge AND stay consistent. Signals are 0..100 (or 0/1), computed live by the front-end and
14// DISCARDED after the verdict. license_tier: ORIGINAL
15import "nx_syscalls.nx"
16
17const HB_ALLOW: i64 = 0
18const HB_CHALLENGE: i64 = 1 // ambiguous -> raise a cost (proof-of-work / interactive challenge), don't block a human
19const HB_BLOCK: i64 = 2
20
21// thresholds (data-driven, CLAUDE.md #11): score >= BLOCK -> block; >= CHALLENGE -> challenge; else allow.
22const HB_BLOCK_THRESH: i64 = 60
23const HB_CHALLENGE_THRESH: i64 = 30
24
25// BOT-LIKELIHOOD SCORE from ephemeral behavior signals (higher = more bot-like). NO identity inputs.
26// interaction_entropy 0..100 : richness/irregularity of mouse+scroll+timing (0 = none/linear = bot, 100 = human)
27// timing_regularity 0..100 : how machine-regular the request cadence is (100 = metronome = bot)
28// challenge_solved 0/1 : passed the per-session proof-of-work / JS challenge (0 = failed = strong bot signal)
29// sequence_anomaly 0..100 : how rigid/anomalous the navigation sequence is (100 = scripted path = bot)
30// honeypot_hit 0/1 : touched an invisible trap a human never sees (1 = near-certain bot)
31// env_consistent 0/1 : runtime behaves as the declared environment should (0 = spoof mismatch = bot)
32func hb_bot_score(interaction_entropy: i64, timing_regularity: i64, challenge_solved: i64, sequence_anomaly: i64, honeypot_hit: i64, env_consistent: i64) -> i64 {
33 var s: i64 = 0
34 if honeypot_hit == 1 { s = s + 60 } // strongest single tell (cited: honeypots)
35 if challenge_solved == 0 { s = s + 50 } // failed the cost-imposing challenge
36 var ie: i64 = interaction_entropy; if ie < 0 { ie = 0 } if ie > 100 { ie = 100 }
37 s = s + ((100 - ie) * 30) / 100 // low interaction entropy -> up to +30
38 var tr: i64 = timing_regularity; if tr < 0 { tr = 0 } if tr > 100 { tr = 100 }
39 s = s + (tr * 20) / 100 // metronomic cadence -> up to +20
40 var sa: i64 = sequence_anomaly; if sa < 0 { sa = 0 } if sa > 100 { sa = 100 }
41 s = s + (sa * 20) / 100 // scripted navigation -> up to +20
42 if env_consistent == 0 { s = s + 30 } // declared-env mismatch -> +30
43 return s
44}
45// THE VERDICT from the score (layered; CHALLENGE the ambiguous so a real human is never hard-blocked).
46func hb_verdict(score: i64) -> i64 {
47 if score >= HB_BLOCK_THRESH { return HB_BLOCK }
48 if score >= HB_CHALLENGE_THRESH { return HB_CHALLENGE }
49 return HB_ALLOW
50}
51// convenience: signals -> verdict in one call (the front desk's whole decision; stores nothing).
52func hb_evaluate(interaction_entropy: i64, timing_regularity: i64, challenge_solved: i64, sequence_anomaly: i64, honeypot_hit: i64, env_consistent: i64) -> i64 {
53 return hb_verdict(hb_bot_score(interaction_entropy, timing_regularity, challenge_solved, sequence_anomaly, honeypot_hit, env_consistent))
54}
55func hb_verdict_name(v: i64) -> *u8 { if v == HB_BLOCK { return "BLOCK" as *u8 } if v == HB_CHALLENGE { return "CHALLENGE" as *u8 } return "ALLOW" as *u8 }