nx_legalsem_lib.nx
buildroot/runtime/nx_legalsem_lib.nx
about
nx_legalsem_lib.nx -- SEMANTIC clause matching: legal concept normalisation + POLARITY.
nx_clause matches WORDS. Two clauses can say the same thing in different words -- "indemnify and hold
harmless" versus "defend against claims" -- and word overlap scores them as unrelated. This layer
matches at the CONCEPT level, so paraphrase works: surface terms normalise to a legal concept and
clauses are compared on the concepts they invoke, not the vocabulary they happen to use.
u2605u2605THE REASON THIS IS NOT JUST A THESAURUS -- POLARITY. "Supplier shall indemnify Customer" and
"Supplier shall NOT indemnify Customer" invoke IDENTICAL concepts. Every similarity measure that works
on concept overlap alone -- including dense vector embeddings, which are notoriously weak on negation --
scores those two as near-identical. They are opposites, and it is the single most dangerous redline in
contracting: the obligation survives the concept check while its direction has been inverted.
So equivalence here requires BOTH concept overlap AND matching polarity, and the specific case of
"same concepts, opposite polarity" gets its own predicate -- sem_reversal -- because that is not a
weak match, it is an ALARM. A reversal must never be reported as a low similarity score; it must be
reported as a reversal.
u2605FAIL-CLOSED: text invoking NO known concept yields zero overlap and is never "equivalent" by
vacuous agreement. Two clauses that both mention nothing recognisable are not the same clause.
The ontology is an explicit, greppable table (extend it by adding rows, not by retraining anything) --
a deliberate trade: narrower than an embedder, but auditable, deterministic, and incapable of
hallucinating a match. license_tier: ORIGINAL LIB.
dependencies 1 imports · 1 importers
imports: nx_clause_lib.nx
imported by: nx_legalsem_gate.nx
structs
| none |
consts
| 27 | const SEM_NONE: i64 = 0 |
| 28 | const SEM_INDEMNITY: i64 = 1 |
| 29 | const SEM_CONFIDENTIALITY: i64 = 2 |
| 30 | const SEM_TERMINATION: i64 = 3 |
| 31 | const SEM_LIABILITY: i64 = 4 |
| 32 | const SEM_UNCAPPED: i64 = 5 |
| 33 | const SEM_WARRANTY: i64 = 6 |
| 34 | const SEM_ASSIGNMENT: i64 = 7 |
| 35 | const SEM_PAYMENT: i64 = 8 |
| 36 | const SEM_MAXC: i64 = 9 |
| 38 | const SEM_EQUIV_FLOOR: i64 = 600 |
functions
| 41 | func sem_concept_of(w: *u8) -> i64 |
| 87 | func sem_has_concept(text: *u8, concept: i64) -> i64 |
| 100 | func sem_concept_count(text: *u8) -> i64 |
| 112 | func sem_overlap_permille(a: *u8, b: *u8) -> i64 |
| 131 | func sem_negated(text: *u8) -> i64 |
| 143 | func sem_equivalent(a: *u8, b: *u8) -> i64 |
| 151 | func sem_reversal(a: *u8, b: *u8) -> i64 |
| 159 | func sem_verdict(standard: *u8, draft: *u8) -> i64 |
| 165 | func sem_verdict_label(v: i64, out: *u8) -> i64 calls 1: mt_catcopy |