Functional Weave
Code in TypeScript

legal.conflict-name-match@1.0.1

README.md

4,454 bytes · view raw

# legal.conflict-name-match

Before a firm takes on a client it checks the client and the other parties
against everyone it has acted for or against. Exact matching misses "Smith,
John" against "John Smith", "Acme Holdings Ltd" against "ACME HOLDINGS
LIMITED" and a transposed "Marhta"; this returns every candidate whose name is
similar enough, best first, so a person can review them.

## How a name is compared

1. **Normalise** with text.normalise-name (trim, collapse Unicode whitespace),
   then lower-case each character (one-to-one case mappings only, as
   text.normalise-name does, so all three languages agree).
2. **Punctuation.** Apostrophes (' and ’) and full stops are removed, so
   "O'Neill" is "oneill" and "J.P." is "jp"; "&" becomes the word "and"; every
   other ASCII punctuation character becomes a space. Letters outside ASCII are
   kept as they are: "José" and "Jose" are close, not equal.
3. **Company forms** are dropped as whole words: ltd, limited, plc, llp, llc,
   inc. "Acme Ltd" and "Acme Limited" are the same key, "acme".
4. **Token sort.** The words are sorted (by code point) and joined with single
   spaces, so word order does not matter: "Smith, John" and "John Smith" are
   both "john smith". This is the "token sort" idea of fuzzy matching.

The result for each candidate carries this `matchKey`, so a reviewer can see
why two names matched.

## The score

Jaro-Winkler similarity of the two keys, over Unicode code points, as defined
by Winkler (W. E. Winkler, "String Comparator Metrics and Enhanced Decision
Rules in the Fellegi-Sunter Model of Record Linkage", Proceedings of the
Section on Survey Research Methods, American Statistical Association, 1990,
pp. 354-359; the definition as set out at
https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance):

- matching characters are equal characters no further apart than
  floor(max(|s1|, |s2|) / 2) - 1, each used once, scanning s1 left to right;
- t is half the number of matched characters that are out of order;
- Jaro = (m/|s1| + m/|s2| + (m - t)/m) / 3, or 0 when m is 0;
- Winkler adds l x 0.1 x (1 - Jaro) for a common prefix of l characters (at
  most 4), **only when Jaro is above 0.7**, Winkler's boost threshold.

It is computed exactly as a fraction of integers and rounded half-up once to
basis points (10000 = identical), so the three languages give the same score
and a threshold means the same thing everywhere. The standard examples:
MARTHA/MARHTA 9611, DWAYNE/DUANE 8400, DIXON/DICKSONX 8133.

Results are the candidates scoring at least `thresholdBasisPoints`, highest
score first, and in input order among equal scores, so the output is
deterministic. A candidate that normalises to nothing (an empty string, "Ltd")
scores 0. A query that normalises to nothing is an error, and so is a key over
500 characters (the exact arithmetic is bounded).

## Limits

A similarity score is a screen, not a decision: it will miss a name that
changed on marriage, a trading name, a transliteration ("Mohammed" and
"Muhammad" score well; "Ivanov" and "Иванов" do not), and it will flag common
surnames. Choosing the threshold is a risk decision for the firm; set it low
enough that a person reviews near misses. The company-form list is short and
English; "Co", "Company", "Group" and "The" are kept on purpose, because
dropping them joins genuinely different names.

## Before you rely on this

**Not professional advice.** This capability calculates legal figures from published rules. It is a software component for developers, not legal advice. Rules change and every rate here has an effective date. Check that the dates cover your case. Verify results against the official sources listed above, and have a solicitor review how you use it, before anyone relies on the output. Provided "as is" under its licence, without warranty.

**Unreviewed.** This capability's implementations agree in every language and pass its published test vectors, which were worked out from the official sources cited. But no qualified solicitor has yet checked those vectors, or confirmed that the capability covers the cases it claims. Treat it as a draft. Do not use it for real people, money or decisions without your own expert review. Once a qualified reviewer signs off, this notice is replaced with their name, qualification and the date. Each new version needs fresh sign-off.

1.0.1 marks it unreviewed. The code and the tests are unchanged.