""" Re-scores a Business Strength Archetype submission on the server, so what we store never depends on numbers the browser sent. Mirrors lib/bsa/score.ts; the question bank comes from questions.json, built by scripts/bsa/build_content.py. """ import json import math from pathlib import Path _DATA = json.loads((Path(__file__).resolve().parent / "questions.json").read_text(encoding="utf-8")) ORDER: list[str] = _DATA["order"] STAGES: list[str] = _DATA["stages"] AGES: list[str] = _DATA["ages"] QUESTIONS: dict[int, dict] = {q["id"]: q for q in _DATA["questions"]} def percentages(raw: dict[str, int]) -> dict[str, int]: """Whole percentages that add up to 100 (largest remainder method).""" total = sum(raw.values()) or 1 exact = [raw[d] / total * 100 for d in ORDER] pct = [math.floor(e) for e in exact] order = sorted(range(len(ORDER)), key=lambda i: (-(exact[i] - pct[i]), i)) for i in order[: 100 - sum(pct)]: pct[i] += 1 return dict(zip(ORDER, pct)) def score(answers: dict[int, str]) -> dict: """answers: question id → strength picked. Raises ValueError if any answer is impossible.""" if set(answers) != set(QUESTIONS): raise ValueError(f"Expected answers to all {len(QUESTIONS)} questions.") raw = {d: 0 for d in ORDER} fit = {d: 0 for d in ORDER} for qid, dim in answers.items(): q = QUESTIONS[qid] if dim not in q["dims"]: raise ValueError(f"Question {qid} has no option for {dim}.") raw[dim] += 1 if dim == q["naturalFit"]: fit[dim] += 1 ranked = sorted(ORDER, key=lambda d: (-raw[d], -fit[d], ORDER.index(d))) primary, secondary = ranked[0], ranked[1] pair = sorted([primary, secondary], key=ORDER.index) return { "raw": raw, "pct": percentages(raw), "primary": primary, "secondary": secondary, "lowest": [ranked[6], ranked[5]], "blendKey": f"{pair[0]}-{pair[1]}", }