Discovery Contract — jlr (us)
The vetting gate between discovery and coding. This file is the human narrative + probe evidence; the authoritative gate state lives in the sidecar
discovery-contract.gate.json, whichpublic-api-implementchecks viacheck_contract_gate.py. Keep this table in sync with the sidecar.
- OEM / market:
jlr/us(Land Rover + Jaguar) - Discovered:
2026-06-12 - Gate status: 🟢 PASS — all hard gates green; identity_key inventory→models OVERRIDE user-approved (2026-06-12)
Gate summary
| # | Gate | Entity / param | Status | Evidence |
|---|---|---|---|---|
| 1 | Pagination contract | inventory | ✅ PASS | total=289, perPage=20, page2∩page1=0 VINs |
| 2 | Enumerator (model/nameplate) | models | ✅ PASS | base URL 302→version; no-view lists bodystyles; 7 nameplates live |
| 3 | Enumerator (dealer) | dealers | ✅ PASS | 20-zip sweep → 181 unique ciCodes |
| 4 | Multi-value filter | inventory | ⬜ N/A | per-dealer scrape, no combined filter |
| 5 | Body shape / bot-block | inventory | ✅ PASS | curl_cffi chrome clears Cloudflare; search API 200 JSON |
| 6 | Body shape / bot-block | features (configurator) | ✅ PASS | JSONP rcjson(...), 200, strips cleanly |
| 7 | Data quality / plausibility | inventory | ✅ PASS | valid unique VINs, real prices $52-53k, mmc populated |
| 8 | Data quality / plausibility | dealers | ✅ PASS | real NYC coords (not 0.0), ciCode+name 100% |
| 9 | Data quality / plausibility | models | ✅ PASS | PRODUCT A-S-P300-110 @ $63,500 w/ 5000Code |
| 10 | Data quality / plausibility | features | ✅ PASS | 124 priced/described leaf features |
| 11 | Cross-source identity key | inventory→dealers | ✅ PASS | ccid→ciCode; dealer.location name match |
| 12 | Cross-source identity key | inventory→models | 🟢 OVERRIDE (approved 2026-06-12) | no shared code; fuzzy (model,trim,year), 95.1% FK |
| 13 | Cross-source identity key | features→models | ✅ PASS | shared SCS response, FK programme_code L663 |
| 14 | Real fixture (no synthetic) | inventory | ✅ PASS | jlr_carscommerce_search_sample.json |
| 15 | Real fixture (no synthetic) | dealers | ✅ PASS | jlr_retailerlocator_sample.json |
| 16 | Real fixture (no synthetic) | models | ✅ PASS | jlr_scs_sample.json (LIVE) |
| 17 | Real fixture (no synthetic) | features | ✅ PASS | jlr_scs_sample.json (LIVE) |
| 18 | Postman record | inventory | ✅ PASS | Collection uid 53897914-9cdbecc6-...a5e1 |
| 19 | Postman record | dealers | ✅ PASS | same collection |
| 20 | Postman record | models | ✅ PASS | same collection |
| 21 | Postman record | features | ✅ PASS | same collection |
Per-entity endpoints
| Entity | Endpoint (method + URL) | Auth / protocol | Fixture | Notes |
|---|---|---|---|---|
| dealers | GET https://retailerlocator.jaguarlandrover.com/dealers?postCode=&requestMarketLocale=en_us&brand=Land Rover&filter=dealer&radius=500&unitOfMeasure=Miles&country=us | Public; needs Origin/Referer = Land Rover US | tests/data/jlr_retailerlocator_sample.json | Real capture — Land Rover Manhattan etc. Key = ciCode. |
| models | GET https://rules.config.landrover.com/rc/lr/en_us/{nameplate}_{my}/{ver}/{bodystyle}/.jsonp?view=summary | Public JSONP | tests/data/jlr_scs_sample.json | Real LIVE capture l663_k26. PRODUCT features = models. |
| features | (same SCS configurator response) | Public JSONP | tests/data/jlr_scs_sample.json | Non-PRODUCT feature-list categories = features. |
| inventory | POST https://websites-search.api.carscommerce.inc/api/v1/listings/{ccid}/search | x-api-key + Origin/Referer; Cloudflare on dealer page (curl_cffi chrome clears) | jlr_carscommerce_search_sample.json | CURRENT endpoint. ccid+x-api-key scraped from dealer page. Old admin-ajax.php is OBSOLETE (400). |
Cross-source identity / FK alignment (HARD)
| FK | Referencing entity.field | Target entity.field | Example value | Verified |
|---|---|---|---|---|
| inventory→dealers | inventory.dealer_id (= dealer ciCode passed through) | dealers.dealer_id (ciCode) | R0627 | ⬜ |
| inventory→models | inventory (model, trim, year) (fuzzy) | models (model_name, trim, model_year) | Discovery Sport / Landmark / 2026 | 🟢 (no shared code — OVERRIDE approved, 95.1% FK) |
| features→models | programme_code | programme_code | L663 | ✅ |
Probe evidence
1. Pagination contract — inventory
paste pagination_probe block
2–3. Enumerators (model / dealer)
paste enumerator_probe blocks
4. Multi-value filter — inventory
N/A — inventory is scraped per dealer; no combined multi-value filter endpoint.
5–6. Body shape / bot-block
paste body_shape_probe blocks
7–10. Data quality / plausibility
paste data_quality_probe blocks per entity
11–13. Cross-source identity keys
paste value-match evidence for every FK listed in the sidecar requirements
14–17. Real fixtures
list every fixture path and the live request it came from
18–21. Postman records
list the Postman request/folder URL for every discovered endpoint
Probe results (verified 2026-06-12)
- Pagination (inventory):
POST websites-search.api.carscommerce.inc/api/v1/listings/6035416/search→ HTTP 200,data.total_vehicle_count=289, 20 rows/page; page 2 VIN set has 0 overlap with page 1. Minimal body returns 400 — the fullsort+facetsarrays are required. - Enumerator (model): base nameplate
/rc/lr/en_us/l663_k26/.jsonp→ 302 →/4cvli.jsonp; version-level no-view response lists BODYSTYLE[A-SV-110, A-90, A-110, A-130]. All 7 nameplates resolve live. - Enumerator (dealer): 20-metro locator sweep, radius 250mi, dedupe by
ciCode→ 181 unique US dealers (151 withnewVehicleInventoryLink). - Body shape (inventory): plain curl → 403 Cloudflare; curl_cffi
impersonate=chrome→ 200 (493KB page, nonce/ccid/api-key extractable), search API → 200 JSON. ~42% of dealers are behind Akamai "Access Denied" that blocks even real Chrome (chrome-devtools also got 403). - Body shape (configurator): JSONP
rcjson(...), HTTP 200, 112KB, strips to JSON. No bot block. - Data quality: dealers real NYC coords (not 0.0); inventory 4 valid unique VINs, prices $52,756-$53,706; models PRODUCT @ $63,500; features 124 priced leaves.
Overrides
| Gate | OVERRIDE reason | Approved by |
|---|---|---|
| identity_key:inventory→models | Cars Commerce inventory exposes manufacturer_model_code (e.g. HQ550/353BT) which shares no token with the SCS catalog's 5000Code / DerivativePackCode / programme_code. The only available join is fuzzy normalized (model_name, trim, model_year). This is a genuine API limitation (two independent feeds), not a discovery miss. | User-approved 2026-06-12 (measured 95.1% FK resolution) |