Files
veripath/docs/architecture/findings-to-cbr-mapping.md
T

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`