nx_clause_lib.nx
buildroot/runtime/nx_clause_lib.nx
about
nx_clause_lib.nx -- CONTRACT TEXT REASONING: clause retrieval, redline deviation, playbook risk.
u2605THIS IS THE QUALITATIVE GAP. Every other legal organ here computes over facts a caller supplies.
This one READS THE DOCUMENT: it locates a clause in raw contract text, RETRIEVES the closest standard
clause from a playbook corpus, measures how far the draft has drifted, and scores the risk. That is
the deterministic core of what Ironclad's Jurist and DocuSign's IAM agents do during negotiation.
u2605TWO DIRECTIONS OF DRIFT, MEASURED SEPARATELY -- because they are different problems and a single
"similarity" number hides both:
RETAINED : how much of the STANDARD clause survives in the draft. Low retention = protections were
DELETED. This is what silently strips an indemnity or a limitation of liability.
NOVEL : how much of the DRAFT is language the standard never had. High novelty = terms were
INSERTED -- an added carve-out, an uncapped obligation, a new termination right.
A redline can score 900 on one and 100 on the other. Averaging them into one figure is how a
dangerous edit passes review looking "95% similar".
u2605RETRIEVAL IS BY MEASUREMENT, NOT BY LABEL. cl_best_match scans the playbook and returns the clause
with the highest retention against the draft. It never trusts a heading: a paragraph titled
"Limitation of Liability" that actually reads like an indemnity will match the indemnity standard,
which is exactly the mislabel a human reviewer skims past.
u2605FAIL-CLOSED: an empty draft, an empty playbook, or a clause that matches NOTHING above the floor
returns CL_NO_MATCH -- never "matches the first entry". An unmatched clause is escalated, not guessed.
Thresholds are DATA (rule 11) as named constants in per mille, never literals in branches.
STRUCTURE: pure text functions, no storage, no I/O. license_tier: ORIGINAL LIB.
dependencies 1 imports · 5 importers
imports: nx_matter_lib.nx
imported by: nx_bm25_lib.nxnx_clause_gate.nxnx_cuad_lib.nxnx_legal_svc.nxnx_legalsem_lib.nx
structs
| none |
consts
| 29 | const CL_NO_MATCH: i64 = 0 - 1 |
| 31 | const CL_RISK_NONE: i64 = 0 |
| 32 | const CL_RISK_LOW: i64 = 1 |
| 33 | const CL_RISK_MEDIUM: i64 = 2 |
| 34 | const CL_RISK_HIGH: i64 = 3 |
| 35 | const CL_RISK_BLOCK: i64 = 4 |
| 37 | const CL_MATCH_FLOOR: i64 = 300 |
| 38 | const CL_DEV_LOW: i64 = 100 |
| 39 | const CL_DEV_MEDIUM: i64 = 250 |
| 40 | const CL_DEV_HIGH: i64 = 500 |
| 41 | const CL_NOVEL_ALERT: i64 = 400 |
| 43 | const CL_WORDBUF: i64 = 256 |
functions
| 47 | func cl_lower(c: i64) -> i64 called by 1: cl_word_at |
| 55 | func cl_is_word(c: i64) -> i64 called by 1: cl_word_at |
| 70 | func cl_word_at(s: *u8, i: i64, out: *u8) -> i64 called by 7: bm_tfbm_score_millicl_word_countcl_has_wordcl_retained_permillecl_novel_permille+1 calls 2: cl_is_wordcl_lower |
| 89 | func cl_word_count(s: *u8) -> i64 |
| 104 | func cl_has_word(hay: *u8, word: *u8) -> i64 called by 6: bm_dfmaincl_retained_permillecl_novel_permillecuad_cue_hitsem_negated calls 2: cl_word_atmt_streq |
| 120 | func cl_retained_permille(standard: *u8, draft: *u8) -> i64 |
| 138 | func cl_novel_permille(standard: *u8, draft: *u8) -> i64 |
| 155 | func cl_deviation_permille(standard: *u8, draft: *u8) -> i64 |
| 163 | func cl_best_match(draft: *u8, lib: *i64, n: i64) -> i64 |
| 180 | func cl_best_score(draft: *u8, lib: *i64, n: i64) -> i64 |
| 190 | func cl_risk_pure(deviation: i64, novel: i64, criticality: i64) -> i64 |
| 212 | func cl_auto_approve_pure(risk: i64) -> i64 |
| 218 | func cl_unmatched_risk_pure(match_idx: i64) -> i64 called by 1: main |
| 223 | func cl_risk_label(r: i64, out: *u8) -> i64 |