{
  "schemaVersion": 1,
  "slug": "lucky-number-calculator",
  "category": "fun",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "bdca75cdfc074ea10e4e6fc50a419cfd74095dc12cd9ffa5cff99abfdd05d629",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/lucky-number-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(n) = Σᵢ dᵢ, n = Σᵢ dᵢ × 10ⁱ, dᵢ ∈ {0,…,9}; r(n) = {n, n ≤ 9; r(s(n)), n > 9}; S = Σⱼ eⱼ; lucky = r(S); combined = r(lucky + r(T))",
    "vars": [
      [
        "S",
        "sum of birth-date digits"
      ],
      [
        "T",
        "digit sum of favourite number"
      ],
      [
        "r",
        "repeated digit-sum reduction"
      ],
      [
        "lucky",
        "lucky number"
      ],
      [
        "combined",
        "combined number"
      ],
      [
        "s",
        "digit sum, s(n) = Σᵢ dᵢ"
      ],
      [
        "d",
        "digit of n, dᵢ ∈ {0,…,9}"
      ],
      [
        "e",
        "digit occurring in the birth date, eⱼ"
      ]
    ],
    "note": "The birth-date digit sum is reduced to 1–9; unreduced sums of exactly 11, 22 or 33 are flagged separately as master numbers. The flag does not change the single-digit result."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const red = (n, keepMaster) => { n = Math.abs(Math.round(n)); while (n > 9) { if (keepMaster && (n === 11 || n === 22 || n === 33)) break; n = String(n).split('').reduce((a, b) => a + Number(b), 0); } return n; }; const bd = new Date(birthDate + 'T00:00:00Z'); const validDate = /^\\d{4}-\\d{2}-\\d{2}$/.test(String(birthDate)) && !Number.isNaN(bd.getTime()) && bd.toISOString().slice(0,10) === birthDate; if (!validDate) return { luckyNumber: null, digitSum: null, masterNumber: null, combined: null, meaning: null, __error: 'inputError' }; const digits = Number.isNaN(bd.getTime()) ? 0 : birthDate.replace(/[^0-9]/g, '').split('').reduce((a, b) => a + Number(b), 0); const lucky = Number.isNaN(bd.getTime()) ? 0 : red(digits, false); const meanings = { 1: 'Leadership and new starts', 2: 'Balance and partnership', 3: 'Creativity and joy', 4: 'Stability and order', 5: 'Change and travel', 6: 'Family and care', 7: 'Insight and study', 8: 'Wealth and achievement', 9: 'Generosity and endings' }; const sumFav = red(String(favouriteNumber).split('').reduce((a, b) => a + Number(b), 0), false); return { luckyNumber: lucky, digitSum: digits, masterNumber: digits === 11 || digits === 22 || digits === 33 ? digits : null, combined: red(lucky + sumFav, false), meaning: meanings[lucky] || 'Unknown' };",
    "inputs": [
      {
        "name": "birthDate",
        "type": "date",
        "default": "1990-01-01",
        "step": 1
      },
      {
        "name": "favouriteNumber",
        "type": "number",
        "default": 7,
        "min": 0,
        "max": 100000000,
        "step": 1
      }
    ],
    "outputs": [
      {
        "name": "luckyNumber",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "digitSum",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "masterNumber",
        "precision": 0,
        "unit": "",
        "optional": true
      },
      {
        "name": "combined",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "meaning",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
