Scoring
Four separate outputs: readiness, coverage, confidence and assessment scope. Inferred, agent and experimental observations never enter readiness.
Definitions
For each scored rule r with weight w(r) ∈ {1, 2, 3}, applicable subjects are partitioned (after removing not-applicable ones) into direct passes, direct fails, inferred, and unassessed (not_evaluated or error). Each site-level rule contributes one site subject.
p(r) = |D_f(r)| / |D(r)| for r with direct evidence
Readiness = 100 · Σ w(r)·(1 − p(r)) / Σ w(r) over rules with direct evidence
Coverage = 100 · Σ w(r)·|D|/(|D|+|I|+|U|) / Σ w(r) over applicable rules
Confidence = 100 · Σ w(r)·|D|/(|D|+|I|) / Σ w(r) over rules with direct or inferred evidence- Readiness is null with no direct evidence; coverage is 0 with no applicable rules; confidence is null with nothing evaluated.
- Unrounded throughout; display rounds half away from zero, once.
- Sub-checks. A fail on any evaluated sub-check fails the subject. All evaluated sub-checks passing while one applicable sub-check could not run is
not_evaluated(incomplete_subchecks). A rule never passes on part of its own checks. - Blocker cap. Readiness is capped at 40 when direct evidence shows robots.txt answering 5xx, a search crawler blocked site-wide against declared policy, or every route noindex. The uncapped value and the reason are kept.
- Display. Coverage ≥ 80% shows readiness; 50–80% shows it as provisional; below 50% (or no readiness) shows “insufficient evidence” and no number.
The score range
Every report also gives each rule one result: Clear, Problem, Can’t tell or Not applicable. From those, the CLI and the agent plugins calculate one score with one formula, shown as a range. The low end assumes every Can’t tell rule is a problem, and the high end assumes every one is clear. The CLI puts this in the report’s summary. Readiness below stays stricter: a rule never passes on part of its checks.
If bot protection or a firewall answers instead of the site, the report says it was blocked, sets blocked, and passes or fails nothing about the site.
Worked examples
These are executable fixtures in packages/geopilot/test/fixtures/scoring. The test suite recomputes every number below from them on every change, and this page reads the same files, so the prose cannot drift from the engine.
Example A — Static site without a renderer
Three route groups (/, /about, /contact). GEO-016 is evaluated from raw HTML: without a renderer the raw response is the server HTML, so a plain <a href> in it is server-link evidence. GEO-003 and GEO-002 need a renderer and are not evaluated. GEO-004 and GEO-101 are not applicable by fixture precondition: no JSON-LD and the web profile.
| Readiness | Coverage | Confidence | Cap |
|---|---|---|---|
| 96 | 83% | 100% | — |
Readiness = 100 × (19 − 2 × 1/3) / 19 = 96.49 → 96; Coverage = 100 × 19 / 23 = 82.6% → 83%; Confidence = 100%Example B-APP — Example B with the app profile
As example B, with the app profile on and GEO-101 passing (weight 2).
| Readiness | Coverage | Confidence | Cap |
|---|---|---|---|
| 40 | 100% | 100% | GEO-013: robots.txt answered 5xx |
Uncapped = 100 × (27 − 3.5) / 27 = 87.04; capped at 40Example B — Next.js, four groups, robots.txt 503 and one canonical issue
All web-profile rules are evaluated directly (this fixture assumes a renderer and was collected with --ignore-robots for a named target, because a 5xx robots.txt otherwise stops GEO fetching pages). GEO-013 fails site-wide with a 5xx, which caps readiness at 40. GEO-015 fails on one of four groups. GEO-101 is not applicable in the web profile.
| Readiness | Coverage | Confidence | Cap |
|---|---|---|---|
| 40 | 100% | 100% | GEO-013: robots.txt answered 5xx |
Uncapped = 100 × (25 − 3 − 2 × 1/4) / 25 = 86; capped at 40; Coverage and Confidence 100%Example C — Unreachable target
Every applicable evaluation errors. Readiness is null, coverage 0%, confidence null; the assessment is incomplete and the display is “insufficient evidence”. Without --fail-on-incomplete the scan still exits 0, but never with “passed” wording.
| Readiness | Coverage | Confidence | Cap |
|---|---|---|---|
| insufficient evidence | 0% | n/a | — |
No direct evidence: Readiness null, Coverage 0%, Confidence nullExample D — Repository only, recomputed under the sub-check rule
Next.js repository, four groups, no --url, web profile. GEO-009 and GEO-017 are fully evaluable from source and pass. GEO-012 fails on one group. GEO-003 is inferred. GEO-013, GEO-014, GEO-015 and GEO-011 pass their static sub-checks but cannot run their HTTP sub-checks, so they are not_evaluated (incomplete_subchecks). GEO-016 and GEO-002 need a URL. The same numbers are produced end-to-end by test/fixtures/example-d.
| Readiness | Coverage | Confidence | Cap |
|---|---|---|---|
| insufficient evidence | 30% | 70% | — |
Readiness = 100 × (7 − 0.5) / 7 = 92.86 (hidden); Coverage = 100 × 7 / 23 = 30.4% → 30%: below 50%, so “insufficient evidence”; Confidence = 100 × 7 / (7 + 3) = 70%Example E — Mixed evidence (URL + repository)
GEO-014 (weight 3): three direct subjects, two pass and one fail, plus one inferred. GEO-012 (weight 2): four direct passes. All sub-checks are available because a URL was supplied.
| Readiness | Coverage | Confidence | Cap |
|---|---|---|---|
| 80 | 85% | 85% | — |
Readiness = 100 × (3 × 2/3 + 2) / 5 = 80; Coverage = Confidence = 100 × (3 × 3/4 + 2) / 5 = 85%Comparing runs
- A numeric readiness delta is shown only when the scoring version, ruleset major.minor and the set of direct (rule, subject) pairs are identical. Otherwise the comparison says “assessment scope changed” and lists what entered and left.
- A finding that moves from
failtonot_evaluatedorerroris not resolved. - Cross-site scores are not rankings. Even with an identical scope it is a technical readiness comparison, not AI performance.
Eleven properties are checked on 10,000 generated cases each: bounds, null-iff-no-direct-evidence, fail→pass monotonicity, unassessed evidence never improving coverage or readiness, inferred evidence never moving readiness, order and sample invariance, cap invariance, and the comparability rules above.