code wiki / _hdl_build / nx_connect_lds_reconnect_lib.nx
nx_connect_lds_reconnect_lib.nx source
↩ module page · 110 lines · 5205 B
1// nx_connect_lds_reconnect_lib.nx -- the MEMBER <-> MISSIONARY RECONNECTION model, extracted as a shared
2// library so the verifying gate (nx_connect_lds_reconnect) and the LIVE app (nx_connect_serve) bind ONE
3// implementation of the law instead of two that can drift. This is the split the gate's own DRY note named:
4// "the small primitives are re-stated to keep the gate self-contained; production extracts them to a shared
5// library organ". No main, no syscalls, no allocation -- records are caller-supplied buffers -- so any
6// consumer can import it, including one that never pulls in the syscall layer.
7//
8// THE LAW (unchanged, integer-only, no floats): two people could have KNOWN each other only if they were in
9// the SAME MISSION, share an AREA, and their time windows OVERLAP. All three are NECESSARY, so a later
10// missionary in the same area does not surface (time is load-bearing) and a same-mission person in a
11// different area does not surface (area is load-bearing). A mutually-confirmed "I remember you" edge
12// outranks inferred overlap. Discovery is CONSENT-GATED both ways (GDPR Art.9-style): a member who has not
13// opted in is never surfaced, however real the overlap. The DATE lane is UNREACHABLE when a minor is
14// involved, in both directions -- a returned missionary and a youth they taught are community, never romance.
15//
16// RECORD LAYOUT (8 slots): p[0]=age_band p[1]=mission p[2]=areas-bitmask p[3]=start_month p[4]=end_month
17// p[5]=reconnect_optin p[6]=self_token p[7]=confirmed_tokens
18// license_tier: ORIGINAL
19
20const RC_LANE_FRIEND: i64 = 1
21const RC_LANE_COMMUNITY: i64 = 2
22const RC_LANE_DATE: i64 = 3
23const RC_BAND_MINOR: i64 = 0
24const RC_BAND_ADULT: i64 = 1
25const RC_EXCLUDED: i64 = 0-1
26const RC_REC_SLOTS: i64 = 8
27
28// number of bits set in BOTH masks (shared-area count), arithmetic only -- no bitwise ops.
29func rc_inter_popc(a: i64, b: i64) -> i64 {
30 var c: i64 = 0
31 var x: i64 = a
32 var y: i64 = b
33 while x > 0 {
34 let ax: i64 = x - (x / 2) * 2
35 let by: i64 = y - (y / 2) * 2
36 if ax == 1 { if by == 1 { c = c + 1 } }
37 x = x / 2
38 y = y / 2
39 }
40 return c
41}
42func rc_clamp100(v: i64) -> i64 { if v > 100 { return 100 } return v }
43func rc_imax(a: i64, b: i64) -> i64 { if a > b { return a } return b }
44func rc_imin(a: i64, b: i64) -> i64 { if a < b { return a } return b }
45func rc_has_bit(mask: i64, bit: i64) -> i64 { if rc_inter_popc(mask, bit) > 0 { return 1 } return 0 }
46
47// months both were present; 0 when disjoint (they were never there at the same time).
48func rc_time_overlap(a_s: i64, a_e: i64, b_s: i64, b_e: i64) -> i64 {
49 let lo: i64 = rc_imax(a_s, b_s)
50 let hi: i64 = rc_imin(a_e, b_e)
51 if hi > lo { return hi - lo }
52 return 0
53}
54
55// fill a CALLER-SUPPLIED 8-slot record (no allocation -> no syscall dependency).
56func rc_mk(p: *i64, band: i64, mission: i64, areas: i64, s: i64, e: i64, optin: i64, token: i64, conf: i64) -> i64 {
57 p[0] = band
58 p[1] = mission
59 p[2] = areas
60 p[3] = s
61 p[4] = e
62 p[5] = optin
63 p[6] = token
64 p[7] = conf
65 return 0
66}
67
68// a reciprocal "I remember you": each lists the other's token. One-sided claims do not count (anti-forgery).
69func rc_mutually_confirmed(a: *i64, b: *i64) -> i64 {
70 if rc_has_bit(a[7], b[6]) == 1 { if rc_has_bit(b[7], a[6]) == 1 { return 1 } }
71 return 0
72}
73
74// raw strength 0..100, consent-BLIND. Internal only -- also the base the consent NEG-CONTROL compares against.
75func rc_raw(a: *i64, b: *i64) -> i64 {
76 if a[1] == 0 { return 0 } // no mission recorded
77 if a[1] != b[1] { return 0 } // different mission -> not the pair
78 let ao: i64 = rc_inter_popc(a[2], b[2])
79 if ao == 0 { return 0 } // NECESSARY: must have shared an area
80 let to: i64 = rc_time_overlap(a[3], a[4], b[3], b[4])
81 if to == 0 { return 0 } // NECESSARY: must have overlapped in time
82 let area_sc: i64 = rc_clamp100(ao * 50) // 1 shared area -> 50, 2+ -> 100
83 let time_sc: i64 = rc_clamp100(to * 20) // 5+ months overlap -> 100
84 var base: i64 = (area_sc * 60 + time_sc * 40) / 100
85 if rc_mutually_confirmed(a, b) == 1 { base = rc_clamp100(base + 40) }
86 return base
87}
88
89// consent-gated discovery: BOTH parties must have opted in or nothing is surfaced.
90func rc_score(a: *i64, b: *i64) -> i64 {
91 if a[5] == 0 { return 0 }
92 if b[5] == 0 { return 0 }
93 return rc_raw(a, b)
94}
95
96// lane-aware + safety-gated: reconnection lives in friendship/community; DATE is unreachable when either
97// party is a minor, in both directions.
98func rc_lane(a: *i64, b: *i64, lane: i64) -> i64 {
99 if lane == RC_LANE_DATE { if a[0] == RC_BAND_MINOR { return RC_EXCLUDED } }
100 if lane == RC_LANE_DATE { if b[0] == RC_BAND_MINOR { return RC_EXCLUDED } }
101 return rc_score(a, b)
102}
103
104// NEG-CONTROL twin: the naive "same mission = match" matcher that ignores area AND time. Kept in the library
105// so the gate measures the real alternative, not a re-typed approximation of it.
106func rc_mission_only(a: *i64, b: *i64) -> i64 {
107 if a[1] == 0 { return 0 }
108 if a[1] == b[1] { return 100 }
109 return 0
110}