166 lines
7.2 KiB
Markdown
166 lines
7.2 KiB
Markdown
# Audit Engine Findings → Canonical Business Record Mapping
|
|
|
|
**Date:** 2026-08-14
|
|
**Status:** Draft
|
|
**Owner:** Tony / VeriPath
|
|
**Scope:** Architecture
|
|
|
|
Contract between `audit_engine.py` output (findings) and `canonical-business-record-v0.1.1.md` field states.
|
|
|
|
---
|
|
|
|
## 1. Direct Field Mappings
|
|
|
|
Each audit finding maps to one or more CBR domains. The finding's evidence drives the field's `status`, `evidence_tier`, and `action_risk`.
|
|
|
|
| Finding ID | CBR Domain | CBR Field(s) Updated |
|
|
|------------|-----------|----------------------|
|
|
| `nap_phone_mismatch` | Contact | `phone` |
|
|
| `nap_address_mismatch` | Location | `street_address` |
|
|
| `nap_website_mismatch` | Contact | `website` |
|
|
| `hours_mismatch` | Hours | `regular_hours` |
|
|
| `rating_delta_high` | Proof & Reputation | `review_count`, `review_sources` |
|
|
| `rating_below_threshold` | Proof & Reputation | `review_count`, `review_sources` |
|
|
| `review_count_delta` | Proof & Reputation | `review_count`, `review_sources` |
|
|
| `reviews_stale` | Proof & Reputation | `review_sources` |
|
|
| `reviews_low_specificity` | Proof & Reputation | `review_sources`, `differentiators` |
|
|
| `category_fragmentation` | Identity | `industry` |
|
|
| `gbp_permanently_closed` | Identity | `industry` (closed status flag) |
|
|
| `gbp_temporarily_closed` | Identity | `industry` (closed status flag) |
|
|
| `no_description` | Proof & Reputation | (description field — not yet in CBR) |
|
|
| `no_price_level` | Services and Pricing | `price_point` |
|
|
| `no_photos` | Proof & Reputation | (photos field — not yet in CBR) |
|
|
| `low_photos` | Proof & Reputation | (photos field — not yet in CBR) |
|
|
| `missing_jsonld_schema` | Identity | (schema field — not yet in CBR) |
|
|
| `schema_wrong_type` | Identity | (schema field — not yet in CBR) |
|
|
| `missing_canonical` | Identity | (schema field — not yet in CBR) |
|
|
| `missing_og_tags` | Identity | (schema field — not yet in CBR) |
|
|
| `website_unreachable` | Contact | `website` |
|
|
| `no_gmaps_url` | Location | `geo_coordinates` (GBP claim URL) |
|
|
| `low_coordinate_precision` | Location | `geo_coordinates` |
|
|
|
|
---
|
|
|
|
## 2. Provenance Rules
|
|
|
|
### Status Assignment
|
|
|
|
| Engine Finding Severity | CBR Field `status` | When |
|
|
|------------------------|-------------------|------|
|
|
| Finding detected, 1 source | `observed` | Single surface has data but no corroboration |
|
|
| Finding detected, 2+ independent sources agree | `verified` | GBP + Apple Maps match, or website + GBP match |
|
|
| Finding detected, sources contradict | `disputed` | GBP says one thing, Apple says another |
|
|
| Previous audit had value, window expired | `stale` | Freshness policy exceeded without re-check |
|
|
|
|
### Evidence Tier Assignment
|
|
|
|
| Source Combination | `evidence_tier` | `source_independence` |
|
|
|--------------------|----------------|-----------------------|
|
|
| GBP only | `tier_3` | `unknown` |
|
|
| Apple Maps only | `tier_3` | `unknown` |
|
|
| Bing Places only | `tier_3` | `unknown` |
|
|
| GBP + Apple Maps | `tier_2` | `independent` (different data pipelines) |
|
|
| GBP + Bing Places | `tier_2` | `independent` |
|
|
| Apple Maps + Bing Places | `tier_2` | `independent` |
|
|
| GBP + Apple + Bing | `tier_2` | `independent` |
|
|
| Website schema + GBP | `tier_2` | `independent` |
|
|
| Owner confirmation | `tier_1` | `independent` |
|
|
| Website footer + website schema | `tier_3` | `same_origin` |
|
|
|
|
**Rule:** Multiple extractions from the same website (footer text, JSON-LD, meta tags) count as `same_origin`, not independent. Only cross-platform matches upgrade tier.
|
|
|
|
### Freshness Policy Alignment
|
|
|
|
Each field inherits the freshness window from `evidence-freshness-policy-v0.1.md`:
|
|
|
|
| CBR Domain | Freshness Window | `fresh_until` calculation |
|
|
|-----------|------------------|--------------------------|
|
|
| Hours | 7 days | `audit_timestamp + 7d` |
|
|
| Services/Pricing | 14 days | `audit_timestamp + 14d` |
|
|
| Booking | 7 days | `audit_timestamp + 7d` |
|
|
| All other fields | 30 days | `audit_timestamp + 30d` |
|
|
|
|
If a finding detects a mismatch on a field whose freshness has expired, set `fresh_until` to the audit timestamp + that domain's window.
|
|
|
|
---
|
|
|
|
## 3. Severity → action_risk Translation
|
|
|
|
| Engine Severity | CBR `action_risk` | Rationale |
|
|
|----------------|------------------|-----------|
|
|
| `immediate` | `high` | Data is actively harmful (wrong address, closed status, phone mismatch). Downstream agents must not act on stale values without re-check. |
|
|
| `high` | `high` | Significant credibility signal loss (no photos, rating below 4.0, no website). Display only; block transactions. |
|
|
| `medium` | `medium` | Optimization gap (category misalignment, low review specificity, missing price level). Display with timestamp and recheck notice. |
|
|
| `enhancement` | `low` | Nice-to-have (OG tags, additional photos). Informational display. |
|
|
|
|
---
|
|
|
|
## 4. Gaps and Open Questions
|
|
|
|
The following audit findings have **no clean home** in the current CBR v0.1.1 schema:
|
|
|
|
| Finding | Gap | Proposed Resolution |
|
|
|---------|-----|-------------------|
|
|
| `no_photos` / `low_photos` | No `photos` field in CBR | Add `photos: { count, sources, last_updated }` to Proof & Reputation |
|
|
| `no_description` | No `description` field in CBR | Add `description` to Identity domain |
|
|
| `missing_jsonld_schema` / `schema_wrong_type` / `missing_canonical` / `missing_og_tags` | No technical schema fields in CBR | Add `technical_seo: { jsonld, canonical, og_tags }` as metadata domain |
|
|
| `website_unreachable` | Website status is boolean but CBR only stores URL | Add `website: { url, reachable, last_checked }` sub-object |
|
|
| `reviews_low_specificity` | CBR has `differentiators` but no structured review quality score | Add `review_quality: { specific_ratio, sample_size }` to Proof & Reputation |
|
|
|
|
**Decision needed:** Do we extend CBR v0.1.2 to include these fields, or keep the engine findings separate from the canonical record until v1.0?
|
|
|
|
---
|
|
|
|
## 5. Example: Phoenix Salon+Spa Address Mismatch
|
|
|
|
**Finding:**
|
|
```json
|
|
{
|
|
"id": "nap_address_mismatch",
|
|
"severity": "immediate",
|
|
"title": "Address inconsistent across 2 surface(s)",
|
|
"sub_score": "Digital Identity",
|
|
"evidence": {
|
|
"google": "1234 Main St, Ste 4, Los Angeles, CA 90012",
|
|
"apple": "1234 Main St, Los Angeles, CA 90012"
|
|
},
|
|
"recommendation": "Standardize exact address format. GBP address is authoritative."
|
|
}
|
|
```
|
|
|
|
**Resulting CBR field state:**
|
|
```json
|
|
{
|
|
"street_address": {
|
|
"value": "1234 Main St, Ste 4, Los Angeles, CA 90012",
|
|
"status": "disputed",
|
|
"evidence_tier": "tier_2",
|
|
"observed_at": "2026-08-14T00:00:00Z",
|
|
"verified_at": null,
|
|
"fresh_until": "2026-09-13T00:00:00Z",
|
|
"source_independence": "independent",
|
|
"sources": ["google_business_profile", "apple_maps"],
|
|
"action_risk": "high",
|
|
"conflict_detail": {
|
|
"google": "1234 Main St, Ste 4, Los Angeles, CA 90012",
|
|
"apple": "1234 Main St, Los Angeles, CA 90012"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Decision logic:**
|
|
- GBP is authoritative → GBP value is the canonical `value`
|
|
- Apple disagrees → `status` is `disputed`, not `verified`
|
|
- Two independent sources → `evidence_tier` is `tier_2`
|
|
- Severity `immediate` → `action_risk` is `high`
|
|
- Domain is Location (regular field) → `fresh_until` is `audit + 30d`
|
|
|
|
---
|
|
|
|
## Related Documents
|
|
|
|
- `docs/architecture/canonical-business-record-v0.1.1.md`
|
|
- `docs/architecture/evidence-freshness-policy-v0.1.md`
|
|
- `implementation/auditing/audit_engine.py`
|