{
  "schemaVersion": 1,
  "slug": "name-compatibility-calculator",
  "category": "party",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "6c9241370f15db434d353fedc8e9f4082ffecfaa5c597768b930402205276b4b",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/name-compatibility-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "S = round((9 − min(g, 9−g))/9 × 100); g = |d(N₁) − d(N₂)|",
    "vars": [
      [
        "S",
        "compatibility score, %"
      ],
      [
        "g",
        "gap between name numbers"
      ],
      [
        "N₁",
        "number of first name"
      ],
      [
        "N₂",
        "number of second name"
      ],
      [
        "d",
        "digital reduction"
      ]
    ],
    "note": "Letters carry Pythagorean values a–i = 1–9, repeating over j–r and s–z; values are summed and the digits re-added until ≤ 9; verdict thresholds: ≥85 highly compatible, ≥65 compatible, ≥45 workable."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const validName=s=>/^[A-Za-z][A-Za-z\\s'’-]*$/.test(String(s).trim());if(!validName(name1)||!validName(name2))return{__error:'inputError'};const PV = { a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9,j:1,k:2,l:3,m:4,n:5,o:6,p:7,q:8,r:9,s:1,t:2,u:3,v:4,w:5,x:6,y:7,z:8 }; const red = (s2) => { let n = 0; for (const ch of String(s2).toLowerCase()) if (PV[ch]) n += PV[ch]; while (n > 9) n = String(n).split('').reduce((a, b) => a + Number(b), 0); return n; }; const a = red(name1); const b = red(name2); const gap = Math.abs(a - b); const cyclic = Math.min(gap, 9 - gap); const score = Math.round((9 - cyclic)/9*100); return { nameNumber1: a, nameNumber2: b, score: score, difference: gap, verdict: score >= 85 ? 'Highly compatible' : score >= 65 ? 'Compatible' : score >= 45 ? 'Workable' : 'Opposites' };",
    "inputs": [
      {
        "name": "name1",
        "type": "text",
        "default": "Alex",
        "step": 1,
        "preserveEmpty": true
      },
      {
        "name": "name2",
        "type": "text",
        "default": "Jordan",
        "step": 1,
        "preserveEmpty": true
      }
    ],
    "outputs": [
      {
        "name": "score",
        "precision": 0,
        "unit": "%",
        "trimTrailingZeros": true
      },
      {
        "name": "nameNumber1",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "nameNumber2",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "difference",
        "precision": 0,
        "unit": "",
        "trimTrailingZeros": true
      },
      {
        "name": "verdict",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
