# Scoring model, gates and fix priority

score-audit turns the filled checklist into a verdict, a score, an evidence coverage figure and a fix order. The weights below are quoted from the constants at the top of [../scripts/score-audit.mjs](../scripts/score-audit.mjs). Change both together, then rerun the worked example and update its expected output.

## Statuses and points

- PASS: evidence seen and correct. Earns the check's full weight.
- WARN: a plausible defect needing a decision or confirmation, or a minor deviation. Earns half the weight.
- FAIL: evidence seen and wrong. Earns zero.
- NOT_CHECKED: applicable but not verified. Lowers coverage, never health. Needs a reason.
- NA: not applicable to this site. Removed from health and coverage. Needs a reason.
- Each check carries one status: the worst result across every capture, run, region, route and read that tested it ([checks.md](checks.md#statuses)).

## Weights

- Severity weights: critical 8, high 4, medium 2, low 1.
- Domain weights: CNV 20, CON 15, EVT 12, CID 12, SST 10, INV 8, XDS 8, PII 7, CFG 5, GOV 3 (total 100).
- Domain weights follow consequence: conversions feed bidding and revenue reporting, consent is the legal exposure, events and click IDs decide whether outcomes can be attributed at all. PII has a lower domain weight because its checks are mostly critical and because the privacy gate below overrides the score anyway.

## Formulas

- Domain health = points earned (PASS full weight, WARN half) divided by the summed weight of checks rated PASS, WARN or FAIL, times 100.
- Domain coverage = summed weight of checked checks (PASS, WARN, FAIL) divided by the summed weight of applicable checks (everything except NA), times 100.
- Overall score = the domain-weighted average of domain health over domains with at least one checked check. When a domain has none, the remaining weights renormalise.
- Overall coverage = checked weight divided by applicable weight across all checks, times 100.

## Coverage rules

- 80 percent or more: graded.
- 60 to 79.9 percent: provisional. Score and grade are shown with the word provisional.
- Under 60 percent: insufficient evidence. Score and grade are withheld and findings are reported by domain only. An L1-only audit usually lands here, which is the honest result for public evidence alone.

## Gates

- Any open S1 FAIL: verdict "Fail: privacy" and grade F, whatever the score. The score is still shown for trend tracking unless coverage withholds it.
- Any open S2 FAIL: grade capped at D, verdict "Grade capped at D: bidding integrity", with "(provisional)" added when coverage is provisional.
- Gates apply even when coverage is provisional or insufficient. With insufficient coverage the grade is withheld, so an open S2 FAIL shows as "Insufficient evidence; bidding gate open".
- A finding may raise its gate with a reason in notes (an undisclosed vendor in INV-01 becomes S1). Only the privacy owner lowers an S1; score-audit refuses a lowered S1 gate unless notes name the privacy owner, and any other lowered gate without a reason.

## Grade bands

- A 90 to 100, B 80 to 89.9, C 70 to 79.9, D 60 to 69.9, F under 60.
- Bands are for triage and for comparing the same site before and after fixes. They are not a certification and should not be compared across sites with different scope or access levels.

## Fix priority

- P1: open S1 FAILs, and S1 WARNs confirmed by reproduction (write "confirmed" in notes).
- P2: open S2 FAILs.
- P3: open S3 FAILs, S2 WARNs, and unconfirmed S1 WARNs (confirm them first, then they move to P1).
- P4: everything else: S4 FAILs, S3 and S4 WARNs.
- Within a class: severity weight descending, then impact, then effort ascending.
- Impact: high when the defect touches 10 percent or more of a tier-1 conversion's volume or revenue, or any conversion used for bidding; medium for 1 to 10 percent; low under 1 percent. Unknown counts as medium until measured.
- Effort: S is a setting or one tag change; M is one release of site code or container work with tests; L is a cross-team or architecture change (a server route, the CRM model).

## Worked math: the Acme checklist

From [../assets/example-acme-checklist.csv](../assets/example-acme-checklist.csv): 71 checks, 37 PASS, 13 WARN, 16 FAIL, 4 NOT_CHECKED, 1 NA.

- CON: CON-01, CON-04, CON-05 and CON-06 PASS (8 + 4 + 4 + 4 = 20 points); CON-02 and CON-03 FAIL (critical, 0 of 16); CON-07 (critical) and CON-08 (medium) NOT_CHECKED. Health = 20 / 36 = 55.6. Coverage = 36 / 46 = 78.3 percent.
- CID: CID-02 and CID-03 PASS (4 + 2); CID-08 WARN (half of 2) and CID-09 WARN (half of 1); CID-01, CID-04, CID-05 and CID-06 FAIL (0 of 16); CID-07 NOT_CHECKED. Health = 7.5 / 25 = 30.0. Coverage = 25 / 27 = 92.6 percent.
- Domain health: INV 75.0, CON 55.6, EVT 78.1, CNV 71.7, XDS 61.9, SST 55.0, CID 30.0, PII 33.3, CFG 64.3, GOV 62.5.
- Overall score = (8 x 75.0 + 15 x 55.6 + 12 x 78.1 + 20 x 71.7 + 8 x 61.9 + 10 x 55.0 + 12 x 30.0 + 7 x 33.3 + 5 x 64.3 + 3 x 62.5) / 100 = 59.5, computed on unrounded values.
- Overall coverage: 94.4 percent, so the result is graded.
- Gates: open S1 FAILs CON-02, CON-03, PII-01 and PII-02 make the verdict "Fail: privacy", grade F. Open S2 FAILs CNV-04, CNV-06 and SST-02 would cap the grade at D on their own.
- After the four P1 fixes alone the score rises to 70.9 (a C), but the open S2 FAILs cap the grade at D until FX-3 to FX-5 ship. That is the point of the gates: privacy and bidding defects dominate the verdict however good the rest looks.

## Beside the other audits

The four audits in this family score different things, so their numbers never add up or compare.

- Status words: this checklist writes NOT_CHECKED and NA. ga4-audit, gtm-container-audit and tracking-plan-audit write NOT CHECKED, and ga4-audit N/A. score-audit reads either spelling.
- Headline: A to F here, a label from decision-grade to not decision-grade in ga4-audit, RED, AMBER or GREEN in gtm-container-audit, and no score at all in tracking-plan-audit, whose rules report coverage one by one.
- FAIL means evidence seen and wrong in all four. Where the evidence differs, so can the result: a container can pass gtm-container-audit while this audit fails the same consent case at runtime, because a tag outside the container fired.
- P1 to P4: all four put privacy first, double counting and bidding next, attribution and lost data after that, hygiene last, but the lines differ. Data that is lost for good is P1 in ga4-audit, a lost conversion is P2 in gtm-container-audit, and an S3 data loss FAIL is P3 here. Keep each finding's priority from its own skill and order a combined fix list by what the finding does to data, permission first.

## Why not an unweighted pass rate

- An unweighted ratio counts a missing page title the same as a purchase counted twice, so a site can look 90 percent healthy while bidding on duplicates.
- Rubrics with points per category but no evidence rule invite invented points: an unverified check silently becomes a pass.
- This model weights by consequence, keeps health and coverage apart so missing access never looks like good health, and lets privacy and bidding defects decide the verdict.
