Skip to content

Architecture

GBP Scorecard keeps collection, judgment, scoring, rendering, and verification separate. Each stage is independently runnable.

COLLECT
public observations + source metadata
        ↓
REVIEW
human or model fills only what needs judgment
        ↓
SCORE
validate · applicability · normalization · caps
        ↓
RENDER
one-page + full report
        ↓
VERIFY
invariants · cross-artifact checks · mutation tests

Stage 1 — Collect

collect.mjs writes a pending worksheet to .audit/<slug>/<run-id>/:

  • audit.json — observations, sources, and 49 unscored check placeholders,
  • run.json — manifest with audit mode, source mode, versions, and non-destructive flag.

Public Mode prefers supported APIs over brittle scraping. It uses the Google Places API (New) for publicly available place data and a non-destructive HTTP inspector for the destination. It never posts, replies, books, calls, texts, submits a form, creates an account, or changes a profile.

The collector does not pretend the Places API exposes the complete profile. Services, attributes, owner responses, posts, and some action types are left for public profile review with explicit notes. A missing field is not scored zero.

Fixture mode reads synthetic observations and performs no network access or credential lookup.

Stage 2 — Review

A reviewer fills every applicable check in audit.filled.json:

  • score from the allowed anchors,
  • evidence strings,
  • source references,
  • confidence state,
  • cap facts that restate structured observations.

Only judgment checks should use a model. Facts such as rating, review count, link resolution, and hours are deterministic. A model proposal is merged with apply_judgment.mjs, which accepts only model-judgment checks and requires evidence references. The reviewer must not invent unavailable data.

Stage 3 — Score

score.py validates the filled audit, removes N/A checks, normalizes category weights to 100, applies deterministic category and overall caps, and writes scores.json.

The scorer never contacts the business. It is file-based and deterministic.

Stage 4 — Render

render.mjs combines scores.json with reviewer-written content.json. The renderer owns:

  • score strings,
  • category and journey tables,
  • check rows,
  • fix point limits,
  • confidence labels,
  • synthetic label,
  • provenance table.

The model owns prose: verdict, findings, strengths, next steps, limitations. It cannot invent check IDs, owner-data IDs, or points.

Stage 5 — Verify

verify.mjs independently recomputes the math and checks:

  • check IDs and category weights,
  • applicability and structural N/A,
  • score bounds, evidence, confidence, source references,
  • fact consistency and cap triggers,
  • category and total math,
  • owner-data exclusion,
  • report score and category rows,
  • full-report finding rows,
  • synthetic labels,
  • top-finding linkage,
  • fix point claims,
  • required sections,
  • local report links,
  • no placeholders,
  • no credential-like material.

It runs a mutation suite that intentionally breaks totals, category scores, confidence, evidence, caps, labels, report linkage, and owner-data exclusion. If a mutation survives, verification fails.

Why the stages stay separate

A monolith is hard to audit. Separating files makes it possible to:

  • inspect raw observations without re-running collection,
  • change a report without changing a score,
  • reproduce a historical score,
  • test a cap in isolation,
  • replace the judgment layer with fixtures,
  • run CI with no credentials and no network.

npm run audit is a wrapper that prints the next commands. It is not an opaque scoring engine.

Audit modes

Public Mode is the only implemented mode. Connected Mode is a future, authorized read-only mode. Each run records audit_mode. The public score is never silently rewritten with connected performance data; connected diagnostics will be reported separately.

Non-destructive boundary

The collector and destination inspector:

  • use GET/search requests only,
  • do not submit forms,
  • do not create bookings,
  • do not place calls or send messages,
  • do not create accounts,
  • do not enter payments,
  • do not mutate a profile,
  • use explicit timeouts, bounded retries, and bounded response reads.

Repository layout

.opencode/skills/home-service-gbp-audit/
  SKILL.md
  references/
    rubric.json
    rubric.md
    coverage-matrix.json
    portable-checklist.md
    fix-library.md
    templates
    schema/
  scripts/
    collect.mjs
    score.py
    render.mjs
    verify.mjs
    eval.mjs
    generators and tests
examples/acme-plumbing/
docs/
scripts/

See Development for commands and test structure.