pa.gf.cx contractors — canonical-record architecture
Date: 2026-05-21 · Status: Phase 1 shipped (section live, 2 pending-vetting records + property cross-section), Phase 2 parked (BBB automation, reviews distill)
The architectural answer to Dan’s question
“Do these references live inside the car record (likely yes) but they live at the Contractor level, then become applied to sub-categories, right?”
Yes — contractor records are canonical, asset records reference them. Same exact pattern as the existing equipment-vendor relationship (N&J General Repair, Newtown Homeware) — lifted into its own first-class section because vetting + reviews + multi-asset reference patterns deserve a dedicated home.
Topology — where records live + how they reference each other
pa.gf.cx/contractors/ ← canonical truth
─────────────────────
│
┌──────────────┬──┴───────────┬────────────────┐
│ │ │ │
▼ ▼ ▼ ▼
Apple Earl's Newtown Homeware N&J General
Graphics Sealcoating (to migrate) Repair
(wraps, (driveway) (to migrate)
tint,
signage)
Asset records reference contractors via link, never embed:
──────────────────────────────────────────────────────────
pa/vehicles/bmw-2013 ──→ /contractors/apple-graphics
(window tinting)
pa/vehicles/ford-f250-2007 ──→ /contractors/apple-graphics
(full vehicle wrap)
pa/property/front-gate ──→ /contractors/<gate-firm>
(replace/automate) (pending shortlist)
pa/household/miele-c3 ──→ /contractors/newtown-homeware
(service) (currently inline; to migrate)
pa/equipment/john-deere ──→ /contractors/n-and-j-repair
(annual service) (currently inline; to migrate)
Key property: the link is unidirectional — asset records point at contractor records, never the other direction. The contractor record’s history log captures the reverse (which assets it’s been used on) as service-log entries get added.
Status taxonomy — vetting lifecycle
┌───────────────┐ BBB ok + ┌──────────────────┐
│ PENDING │ reviews ok + │ SHORTLISTED │
│ vetting │ ──first call──▶ │ not yet hired │
└───────┬───────┘ positive └────────┬─────────┘
│ │
│ BBB bad OR │ estimate signed +
│ reviews bad OR │ first job booked
│ wrong service area │
▼ ▼
┌───────────────┐ ┌──────────────────┐
│ REJECTED │ │ ENGAGED │
│ (notes WHY) │ │ has service │
└───────────────┘ │ log entries │
└──────────────────┘
Each state is captured in the contractor record’s Status field. REJECTED records stay in the directory (not deleted) so the “why we ruled them out” reasoning persists — prevents re-evaluating the same firm twice.
Record schema (per contractor)
�STASH3�
What shipped 2026-05-21 (Phase 1)
�STASH4�
What’s parked for Phase 2
Migration of existing inline vendors into canonical records:
�STASH5�
The migration is mechanical: extract the vendor identity + service log entries from the asset records, lift into /contractors/<vendor-slug>.html, replace the inline mentions with <a href="../contractors/..."> links. ~10 min per vendor.
BBB lookup automation: a ~/bin/contractor_bbb_lookup.py that takes a contractor name + state and pulls the BBB profile via their public search → fills in the vetting fields. Similar shape to reddit_distill.py. ~1.5 hr to build well.
Reviews distillation: lift reddit_distill.py to also work against Google reviews + Yelp + Angi. Each is a different scraper, but the 5-things-digest pattern travels. Pull into the vetting checklist as it completes.
Diagram: how a new contractor enters + exits the system
Roadside sign / referral / online search
│
▼
┌─────────────────────────────────┐
│ Photo + 2-line note captured │ ← Dan
│ ("spotted Earl's yard sign") │
└────────────────┬────────────────┘
│
▼
┌─────────────────────────────────┐
│ Render contractor record │ ← Claude / script
│ (PENDING vetting status) │
│ + HEAD-check website │
│ + cross-link from any asset │
│ record that already needs it │
└────────────────┬────────────────┘
│
▼
┌──── vetting steps ────┐
│ BBB + reviews + │
│ first phone call │
└────────────┬──────────┘
│
┌──────────┴───────────┐
│ │
passes ▼ ▼ fails
┌──────────────────┐ ┌──────────────────┐
│ SHORTLISTED │ │ REJECTED │
│ (ready to hire) │ │ (notes in │
└────────┬─────────┘ │ record · stays │
│ │ for history) │
▼ └──────────────────┘
┌──────────────────┐
│ ENGAGED │
│ + service log │
│ entries start │
└──────────────────┘
Why this pattern compounds
Three forces make the contractors directory pay back over time:
-
Multi-asset contractors collapse vetting cost. Apple Graphics covers F-250 wrap + BMW tint + future LR4 tint. One vetting pass = 2-3 potential engagements. The shortlist gets denser the more multi-service firms enter it.
-
REJECTED records compound knowledge. Every “why we ruled X out” is a future-Dan time-saver — six months from now when X’s truck appears again, the record says “checked 2026-05-21, rejected because
.” No re-evaluation cost. -
Cross-asset queries unlock. Once 5+ contractors exist, “find me a vendor that does both wraps and signage” becomes a directory query, not a search. As the directory grows, the search space inverts from “find a firm” to “filter the directory.”
Sibling memories
feedback_clean_sweep_retrofit_scripts.md— Phase-2 migration of inline vendors is the canonical clean-sweep script use-casefeedback_reddit_as_knowledge_substrate.md— extends naturally to BBB / Google reviews scraping for vetting evidenceuser_pa_gfcx_as_country_house_operating_system.md— the strategic frame this rolls up intoproject_pa_claim_cockpit.md— adjacent canonical-record pattern (claims, not contractors)
Resume conditions for Phase 2
Build Phase 2 (vendor migration + BBB automation + reviews distill) when ANY:
- Third inline vendor reference appears in a new asset record (would be the 4th total — Newtown, N&J, plus 2 more — making the manual inline pattern feel obviously sub-optimal)
- Dan starts comparing contractors for a single service (e.g., 3 sealcoating quotes side-by-side — directory needs the comparison view)
- The “I keep re-checking the same BBB profile” friction crosses the discipline threshold — automate it
- A vetting failure costs money — engaging an un-vetted contractor and getting burned. Failure-driven build.
The aphorism
A contractor exists once. Their work exists everywhere. Build the directory like that — one canonical record per firm, many asset references pointing in. The directory is the truth; the assets are the consumers.