code wiki / (root) / nx_clm_lib.nx

nx_clm_lib.nx source

↩ module page · 120 lines · 5433 B

1// nx_clm_lib.nx -- F996: CONTRACT LIFECYCLE -- obligation tracking + auto-renewal-trap detection. 2// 3// The expensive, silent contract failure is the EVERGREEN AUTO-RENEWAL TRAP: a contract renews for 4// another (often costly) term unless you give written notice N days before expiry. Miss that window by 5// a day and you are locked in. Legal teams miss it constantly because nothing computes the deadline and 6// nothing flags the day it passes. This organ does both, and it is FAIL-CLOSED: a contract whose expiry 7// or notice period is unknown is flagged FOR REVIEW, never silently reported safe -- because "no action 8// needed" on a contract you could not evaluate is exactly how you get trapped. 9// 10// Dates are integer DAY-NUMBERS (deterministic, no float). Converting a YYYYMMDD to a day-number is the 11// docketing engine's job (nx_docket); this takes day-numbers so the lifecycle math is exact and testable. 12// 13// SCALE ENVELOPE (declared): clm_overdue scans the obligation index for a contract's key-prefix (the 14// proven per-key scan). DRY: composes nx_matter_lib (reg_*/mt_*/canon_encode). license_tier: ORIGINAL LIB. 15 16import "nx_matter_lib.nx" 17 18const CLM_OPEN: i64 = 0 // notice window still open -- you can still cancel 19const CLM_MISSED: i64 = 1 // past the notice deadline, before expiry -- it WILL auto-renew 20const CLM_RENEWED: i64 = 2 // past expiry -- already auto-renewed into a new term 21const CLM_UNKNOWN: i64 = 0 - 1 // insufficient data -- FLAG FOR REVIEW (fail-closed), never "safe" 22const CLM_COLON: i64 = 58 23 24// the LAST day on which cancellation notice may be given. 25func clm_notice_deadline(expiry_day: i64, notice_days: i64) -> i64 { 26 return expiry_day - notice_days 27} 28 29// ★evaluate the auto-renewal trap as of `today_day`. 30// FAIL-CLOSED: an unknown expiry (<=0) or negative notice period -> CLM_UNKNOWN, not OPEN. 31func clm_renewal_state(expiry_day: i64, notice_days: i64, today_day: i64) -> i64 { 32 if expiry_day <= 0 { return CLM_UNKNOWN } 33 if notice_days < 0 { return CLM_UNKNOWN } 34 let deadline: i64 = expiry_day - notice_days 35 if today_day <= deadline { return CLM_OPEN } 36 if today_day <= expiry_day { return CLM_MISSED } 37 return CLM_RENEWED 38} 39 40// days remaining to give notice; NEGATIVE means the window is already missed. 41func clm_days_to_act(expiry_day: i64, notice_days: i64, today_day: i64) -> i64 { 42 return (expiry_day - notice_days) - today_day 43} 44 45// 1 only if it is still SAFE (window open). Missed, renewed, AND unknown all return 0. 46func clm_is_safe(expiry_day: i64, notice_days: i64, today_day: i64) -> i64 { 47 if clm_renewal_state(expiry_day, notice_days, today_day) == CLM_OPEN { return 1 } 48 return 0 49} 50 51// record a contract obligation with its due day. key = "<contract>:<obl>". 52func clm_obligation_put(prefix: *u8, contract_id: *u8, obl_id: *u8, due_day: i64, otype: *u8) -> i64 { 53 let id: *u8 = sys_mmap(256) 54 var o: i64 = mt_catcopy(id, 0, contract_id) 55 id[o] = CLM_COLON as u8 56 o = o + 1 57 o = mt_catcopy(id, o, obl_id) 58 id[o] = 0 as u8 59 let db: *u8 = sys_mmap(32) 60 var doo: i64 = mt_catn(db, 0, due_day) 61 db[doo] = 0 as u8 62 let k: *i64 = sys_mmap(8 * 2) as *i64 63 let v: *i64 = sys_mmap(8 * 2) as *i64 64 k[0] = ("due" as *u8) as i64 65 v[0] = db as i64 66 k[1] = ("type" as *u8) as i64 67 v[1] = otype as i64 68 let rec: *u8 = sys_mmap(512) 69 let rl: i64 = canon_encode(k, v, 2, rec) 70 return reg_put(prefix, "clm:" as *u8, "clm:__idx__" as *u8, id, rec, rl) 71} 72 73// count a contract's obligations that are OVERDUE as of today_day (due_day < today_day). 74func clm_overdue(prefix: *u8, contract_id: *u8, today_day: i64) -> i64 { 75 // SIZE-TO-NEED: buffer derived from the index itself. The pair this replaces 76 // returned -1 once the contract index passed 1 MiB, and -1 skips the walk 77 // below -- an overdue check would have reported NOTHING OVERDUE. 78 let idxbox: *i64 = sys_mmap(16) as *i64 79 let ilen: i64 = reg_index_read(prefix, "clm:__idx__" as *u8, idxbox) 80 let idx: *u8 = idxbox[0] as *u8 81 let cp: *u8 = sys_mmap(256) 82 var cpl: i64 = mt_catcopy(cp, 0, contract_id) 83 cp[cpl] = CLM_COLON as u8 84 cpl = cpl + 1 85 cp[cpl] = 0 as u8 86 let idb: *u8 = sys_mmap(256) 87 let po: *i64 = sys_mmap(16) as *i64 88 let lo: *i64 = sys_mmap(16) as *i64 89 let df: *u8 = sys_mmap(32) 90 var overdue: i64 = 0 91 var ls: i64 = 0 92 var i: i64 = 0 93 while i <= ilen { 94 var eol: i64 = 0 95 if i == ilen { eol = 1 } 96 if i < ilen { if idx[i] == 10 as u8 { eol = 1 } } 97 if eol == 1 { 98 if i > ls { 99 var c: i64 = 0 100 while ls + c < i { idb[c] = idx[ls + c]; c = c + 1 } 101 idb[c] = 0 as u8 102 var mtch: i64 = 1 103 var x: i64 = 0 104 while cp[x] != (0 as u8) { if idb[x] != cp[x] { mtch = 0 } x = x + 1 } 105 if mtch == 1 { 106 if reg_get(prefix, "clm:" as *u8, idb, po, lo) == 1 { 107 mt_field(po[0] as *u8, lo[0], "due" as *u8, 3, df) 108 var due: i64 = 0 109 var y: i64 = 0 110 while df[y] != (0 as u8) { due = due * 10 + (df[y] - 48); y = y + 1 } 111 if due < today_day { overdue = overdue + 1 } 112 } 113 } 114 } 115 ls = i + 1 116 } 117 i = i + 1 118 } 119 return overdue 120}