[object Object]

← back to Rentv Ad Engine

Full REview reconciliation: producer-page harvest maps 20/22 episodes (16 with official sponsors + real air dates); reconcile-review.py cross-verifies 7 advertisers vs RENTV official record + stamps 15 episode air dates; UI shows REview-verified badge + air dates

c3eae5f2011f45a98a0c3234b4273ead0d0ab945 · 2026-08-07 09:51:18 -0700 · Steve Abrams

Transcript extraction agrees with RENTV official on all 7 recurring sponsors (Rockefeller/Provident exact); ours slightly higher (also catches panels + 4 unparsed episodes).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit c3eae5f2011f45a98a0c3234b4273ead0d0ab945
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Aug 7 09:51:18 2026 -0700

    Full REview reconciliation: producer-page harvest maps 20/22 episodes (16 with official sponsors + real air dates); reconcile-review.py cross-verifies 7 advertisers vs RENTV official record + stamps 15 episode air dates; UI shows REview-verified badge + air dates
    
    Transcript extraction agrees with RENTV official on all 7 recurring sponsors (Rockefeller/Provident exact); ours slightly higher (also catches panels + 4 unparsed episodes).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 data/advertisers.json          | 104 ++++++++++++-----
 data/manifest.json             |  45 ++++---
 data/rentvreview.json          | 259 ++++++++++++++++++++++++++++++++++-------
 public/index.html              |   5 +-
 scripts/harvest-rentvreview.py | 133 ++++++++++-----------
 scripts/reconcile-review.py    |  73 ++++++++++++
 6 files changed, 456 insertions(+), 163 deletions(-)

diff --git a/data/advertisers.json b/data/advertisers.json
index b73330e..31f6b6b 100644
--- a/data/advertisers.json
+++ b/data/advertisers.json
@@ -121,7 +121,10 @@
    "address_status": "found_web",
    "addresses": [
     "2550 Honolulu Ave, Ste 101, Montrose, CA 91020"
-   ]
+   ],
+   "review_verified": true,
+   "review_appearances": 13,
+   "review_official_name": "Commercial Real Estate Inspectors"
   },
   {
    "name": "Fidelity Mortgage Lenders",
@@ -231,7 +234,10 @@
    "address_status": "found_web",
    "addresses": [
     "11952 Wilshire Boulevard, Los Angeles, CA 90025-6608"
-   ]
+   ],
+   "review_verified": true,
+   "review_appearances": 13,
+   "review_official_name": "Fidelity Mortgage Lenders"
   },
   {
    "name": "Paramount Property Tax Appeal",
@@ -317,7 +323,10 @@
    "address_status": "found_web",
    "addresses": [
     "14251 Danielson Street, Poway, CA 92064"
-   ]
+   ],
+   "review_verified": true,
+   "review_appearances": 9,
+   "review_official_name": "Paramount Property Tax Appeal"
   },
   {
    "name": "Chase Partners",
@@ -390,7 +399,10 @@
    "addresses": [
     "Chase Partners Ltd., P.O Box 3944, Glendale, CA 91221"
    ],
-   "address_status": "found"
+   "address_status": "found",
+   "review_verified": true,
+   "review_appearances": 7,
+   "review_official_name": "Chase Partners"
   },
   {
    "name": "Redwood Mortgage",
@@ -444,7 +456,10 @@
    "addresses": [
     "155 Bovet Road, Suite 302 San Mateo, CA 94402"
    ],
-   "address_status": "found"
+   "address_status": "found",
+   "review_verified": true,
+   "review_appearances": 3,
+   "review_official_name": "Redwood Mortgage"
   },
   {
    "name": "Provident Savings Bank",
@@ -484,7 +499,10 @@
    "addresses": [
     "3756 Central Avenue, Riverside, CA 92506"
    ],
-   "address_status": "found"
+   "address_status": "found",
+   "review_verified": true,
+   "review_appearances": 3,
+   "review_official_name": "Provident Savings Bank"
   },
   {
    "name": "Rockefeller Group",
@@ -518,7 +536,10 @@
    "addresses": [
     "2325 East Camelback Road, Suite 400, Phoenix, AZ 85016"
    ],
-   "address_status": "found"
+   "address_status": "found",
+   "review_verified": true,
+   "review_appearances": 3,
+   "review_official_name": "Rockefeller Group"
   },
   {
    "name": "The Bascom Group",
@@ -549,7 +570,8 @@
    "address_status": "found_web",
    "addresses": [
     "7 Corporate Park, Suite 100, Irvine, CA 92606"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Advanced Real Estate Services",
@@ -573,7 +595,8 @@
    "address_status": "found_web",
    "addresses": [
     "15320 Barranca Parkway, Suite 150, Irvine, CA 92618"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Advanced Real Estate The Firm",
@@ -597,7 +620,8 @@
    "address_status": "found_web",
    "addresses": [
     "15320 Barranca Parkway, Suite 150, Irvine, CA 92618"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Axo Bank",
@@ -621,7 +645,8 @@
    "address_status": "found_web",
    "addresses": [
     "4350 La Jolla Village Drive, Suite 140, San Diego, CA 92122"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Axos Bank",
@@ -645,7 +670,8 @@
    "address_status": "found_web",
    "addresses": [
     "4350 La Jolla Village Drive, Suite 140, San Diego, CA 92122"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "CBRE",
@@ -669,7 +695,8 @@
    "address_status": "found_web",
    "addresses": [
     "400 S Hope Street, 25th Floor, Los Angeles, CA 90071"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "CBRE's National Retail Partners West Team",
@@ -695,7 +722,8 @@
    "address_status": "found_web",
    "addresses": [
     "400 S Hope Street, 25th Floor, Los Angeles, CA 90071"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "City of Ontario",
@@ -716,7 +744,8 @@
      "url": "https://vimeo.com/830276773"
     }
    ],
-   "address_status": "needs_web_search"
+   "address_status": "needs_web_search",
+   "review_verified": false
   },
   {
    "name": "First",
@@ -735,7 +764,8 @@
      "url": "https://vimeo.com/1039101858"
     }
    ],
-   "address_status": "needs_web_search"
+   "address_status": "needs_web_search",
+   "review_verified": false
   },
   {
    "name": "Jones Lang LaSalle (JLL)",
@@ -761,7 +791,8 @@
    "address_status": "found_web",
    "addresses": [
     "515 S Flower Street, Floor 13, Los Angeles, CA 90071"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "MG R Real Estate",
@@ -787,7 +818,8 @@
    "address_status": "found_web",
    "addresses": [
     "3800 E Concours St, Suite 350, Ontario, CA 91764"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "MGR Real Estate Services",
@@ -813,7 +845,8 @@
    "address_status": "found_web",
    "addresses": [
     "3800 E Concours St, Suite 350, Ontario, CA 91764"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Ms. Rahi TE Bank",
@@ -832,7 +865,8 @@
      "url": "https://vimeo.com/862593366"
     }
    ],
-   "address_status": "needs_web_search"
+   "address_status": "needs_web_search",
+   "review_verified": false
   },
   {
    "name": "Newmark Merrill Companies",
@@ -860,7 +894,8 @@
    "address_status": "found_web",
    "addresses": [
     "24025 Park Sorrento, Suite 300, Calabasas, CA 91302"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Pacific Southwest Realty Services",
@@ -886,7 +921,8 @@
    "address_status": "found_web",
    "addresses": [
     "7675 Dagget Street, Suite 330, San Diego, CA 92111"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Paragon Commercial Group",
@@ -914,7 +950,8 @@
    "address_status": "found_web",
    "addresses": [
     "133 Penn Street, El Segundo, CA 90245"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Provident Bank",
@@ -938,7 +975,8 @@
    "address_status": "found_web",
    "addresses": [
     "111 Wood Avenue South, Suite 200, Iselin, NJ 08830"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "rent TV",
@@ -957,7 +995,8 @@
      "url": "https://vimeo.com/721184140"
     }
    ],
-   "address_status": "needs_web_search"
+   "address_status": "needs_web_search",
+   "review_verified": false
   },
   {
    "name": "Say What's Properties",
@@ -976,7 +1015,8 @@
      "url": "https://vimeo.com/739081927"
     }
    ],
-   "address_status": "needs_web_search"
+   "address_status": "needs_web_search",
+   "review_verified": false
   },
   {
    "name": "Torrey Pines Bank",
@@ -1002,7 +1042,8 @@
    "address_status": "found_web",
    "addresses": [
     "12220 El Camino Real, Suite 110, San Diego, CA 92130"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Universe Holdings",
@@ -1026,7 +1067,8 @@
    "address_status": "found_web",
    "addresses": [
     "1875 Century Park E, Suite 1800, Los Angeles, CA 90067"
-   ]
+   ],
+   "review_verified": false
   },
   {
    "name": "Walker and Dunlop",
@@ -1050,7 +1092,9 @@
    "address_status": "found_web",
    "addresses": [
     "7272 Wisconsin Avenue, Suite 1300, Bethesda, MD 20814"
-   ]
+   ],
+   "review_verified": false
   }
- ]
+ ],
+ "reconciled_at": "2026-08-07 09:50:33"
 }
\ No newline at end of file
diff --git a/data/manifest.json b/data/manifest.json
index 5466570..9cce4a8 100644
--- a/data/manifest.json
+++ b/data/manifest.json
@@ -19,7 +19,8 @@
    "url": "https://vimeo.com/1199114985",
    "duration": 4051,
    "caption_chars": 58625,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "June 04, 2026"
   },
   {
    "id": 1178561985,
@@ -59,7 +60,8 @@
    "url": "https://vimeo.com/1106281388",
    "duration": 4122,
    "caption_chars": 74419,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "July 31, 2025"
   },
   {
    "id": 1083190047,
@@ -107,7 +109,8 @@
    "url": "https://vimeo.com/1079649123",
    "duration": 3750,
    "caption_chars": 57666,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "April 25, 2025"
   },
   {
    "id": 1059913595,
@@ -123,7 +126,8 @@
    "url": "https://vimeo.com/1056513923",
    "duration": 3012,
    "caption_chars": 48067,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "February 12, 2025"
   },
   {
    "id": 1039101858,
@@ -131,7 +135,8 @@
    "url": "https://vimeo.com/1039101858",
    "duration": 4613,
    "caption_chars": 71555,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "December 13, 2024"
   },
   {
    "id": 1012976399,
@@ -139,7 +144,8 @@
    "url": "https://vimeo.com/1012976399",
    "duration": 3050,
    "caption_chars": 51652,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "September 19, 2024"
   },
   {
    "id": 989909369,
@@ -163,7 +169,8 @@
    "url": "https://vimeo.com/953281926",
    "duration": 3656,
    "caption_chars": 60628,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "June 03, 2024"
   },
   {
    "id": 931863337,
@@ -171,7 +178,8 @@
    "url": "https://vimeo.com/931863337",
    "duration": 3678,
    "caption_chars": 57234,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "March 21, 2024"
   },
   {
    "id": 911412212,
@@ -179,7 +187,8 @@
    "url": "https://vimeo.com/911412212",
    "duration": 4139,
    "caption_chars": 62340,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "February 09, 2024"
   },
   {
    "id": 906276616,
@@ -187,7 +196,8 @@
    "url": "https://vimeo.com/906276616",
    "duration": 3601,
    "caption_chars": 54030,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "January 19, 2024"
   },
   {
    "id": 886025667,
@@ -195,7 +205,8 @@
    "url": "https://vimeo.com/886025667",
    "duration": 3521,
    "caption_chars": 48930,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "November 17, 2023"
   },
   {
    "id": 868849453,
@@ -203,7 +214,8 @@
    "url": "https://vimeo.com/868849453",
    "duration": 3690,
    "caption_chars": 66741,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "September 21, 2023"
   },
   {
    "id": 865035925,
@@ -227,7 +239,8 @@
    "url": "https://vimeo.com/852462696",
    "duration": 3910,
    "caption_chars": 56811,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "August 09, 2023"
   },
   {
    "id": 831673533,
@@ -283,7 +296,8 @@
    "url": "https://vimeo.com/795355693",
    "duration": 2883,
    "caption_chars": 45629,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "January 30, 2023"
   },
   {
    "id": 771348410,
@@ -291,7 +305,8 @@
    "url": "https://vimeo.com/771348410",
    "duration": 3065,
    "caption_chars": 45097,
-   "has_captions": true
+   "has_captions": true,
+   "air_date": "November 14, 2022"
   },
   {
    "id": 763447786,
diff --git a/data/rentvreview.json b/data/rentvreview.json
index 92e303a..3532e40 100644
--- a/data/rentvreview.json
+++ b/data/rentvreview.json
@@ -1,78 +1,249 @@
 {
- "771348410": {
-  "rv_id": "1909",
-  "url": "https://www.rentvreview.com/Videos/View/1909",
-  "vimeo": "771348410",
-  "title": "Commercial Real Estate Talk, Episode #1 - Bill Shopoff 9677 views Video added by Commercia",
-  "sponsors": [],
-  "date": "November 14, 2022",
-  "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, which is celebrating its 30th Anniversar"
+ "1200839794": {
+  "rv_id": "3255",
+  "url": "https://www.rentvreview.com/Videos/View/3255",
+  "title": "CRE Talk Episode #22 with Bill Shopoff In this episode of Commercial Real Estate Talk with",
+  "ep": 22,
+  "sponsors": [
+   "Rockefeller Group",
+   "Chase Partners",
+   "Provident Savings Bank",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "",
+  "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, a very active developer of major long-te"
  },
- "795355693": {
-  "rv_id": "1910",
-  "url": "https://www.rentvreview.com/Videos/View/1910",
-  "vimeo": "795355693",
-  "title": "Commercial Real Estate Talk, Episode #2 - Sandy Sigal 7118 views Video added by Commercial",
+ "1199114985": {
+  "rv_id": "3254",
+  "url": "https://www.rentvreview.com/Videos/View/3254",
+  "title": "CRE Talk Episode #21 - Daniel Weiss In this episode of Commercial Real Estate Talk with St",
+  "ep": 21,
+  "sponsors": [
+   "Rockefeller Group",
+   "Chase Partners",
+   "Provident Savings Bank",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "June 04, 2026",
+  "guest_note": "Daniel Weiss \u2014 President of Strauss Investments, an extremely active investor in commercial properties a"
+ },
+ "1178561985": {
+  "rv_id": "3158",
+  "url": "https://www.rentvreview.com/Videos/View/3158",
+  "title": "CRE Talk Episode #20 - Colton Sudberry In this episode of Commercial Real Estate Talk with",
+  "ep": 20,
+  "sponsors": [
+   "Rockefeller Group",
+   "Chase Partners",
+   "Provident Savings Bank",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "",
+  "guest_note": "Colton Sudberry \u2014 President & CEO of Sudberry Properties, an extremely active developer of large, master-pl"
+ },
+ "1138312637": {
+  "rv_id": "3065",
+  "url": "https://www.rentvreview.com/Videos/View/3065",
+  "title": "CRE Talk Episode #19 - Chris Tourtellotte In this episode of Commercial Real Estate Talk w",
+  "ep": 19,
   "sponsors": [],
-  "date": "January 30, 2023",
-  "guest_note": "Sandy SIgal \u2014 President and CEO of NewMark Merrill Companies"
+  "date": "",
+  "guest_note": "Chris Tourtellotte \u2014 Managing Director with LaTerra Development, one of the most prolific multifamily develop"
  },
- "953281926": {
-  "rv_id": "2493",
-  "url": "https://www.rentvreview.com/Videos/View/2493",
-  "vimeo": "953281926",
-  "title": "RENTV CRE Talk Episode #11 - Michael Rademaker 9942 views Video added by Commercial Real E",
+ "1115700624": {
+  "rv_id": "2909",
+  "url": "https://www.rentvreview.com/Videos/View/2909",
+  "title": "RENTV CRE Talk Episode #18 - Terry Tallen In this episode of Commercial Real Estate Talk w",
+  "ep": 18,
   "sponsors": [
-   "Paramount Property Tax Appeal",
+   "Chase Partners",
    "Commercial Real Estate Inspectors",
    "Fidelity Mortgage Lenders"
   ],
-  "date": "June 03, 2024",
-  "guest_note": "Michael Rademaker \u2014 Founder and CEO of MGR Real Estate, his Ontario-based company the has a residential and"
+  "date": "",
+  "guest_note": ""
  },
- "1039101858": {
-  "rv_id": "2642",
-  "url": "https://www.rentvreview.com/Videos/View/2642",
-  "vimeo": "1039101858",
-  "title": "RENTV CRE Talk Episode #13 - Ethan Penner 4876 views Video added by Commercial Real Estate",
+ "1106281388": {
+  "rv_id": "2810",
+  "url": "https://www.rentvreview.com/Videos/View/2810",
+  "title": "RENTV CRE Talk Episode #17 - Christopher Rising In this episode of Commercial Real Estate ",
+  "ep": 17,
   "sponsors": [
    "Chase Partners",
    "Commercial Real Estate Inspectors",
    "Fidelity Mortgage Lenders"
   ],
-  "date": "December 13, 2024",
-  "guest_note": "Ethan Penner \u2014 Founder & CEO of Mosaic Real Estate Investors, an iconic figure in the real estate fina"
+  "date": "July 31, 2025",
+  "guest_note": ""
+ },
+ "1079649123": {
+  "rv_id": "2746",
+  "url": "https://www.rentvreview.com/Videos/View/2746",
+  "title": "RENTV CRE Talk Episode #16 - Alex Zikakis In this episode of Commercial Real Estate Talk w",
+  "ep": 16,
+  "sponsors": [
+   "Chase Partners",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "April 25, 2025",
+  "guest_note": "Alex Zikakis \u2014 President of Capstone Advisors, the San Diego-based owner and operator of retail properti"
+ },
+ "1059913595": {
+  "rv_id": "2727",
+  "url": "https://www.rentvreview.com/Videos/View/2727",
+  "title": "RENTV CRE Talk Episode #15 - Marc Brutten In this episode of Commercial Real Estate Talk w",
+  "ep": 15,
+  "sponsors": [],
+  "date": "",
+  "guest_note": "Marc Brutten \u2014 CEO of Brutten Global, headquartered in San Diego"
  },
  "1056513923": {
   "rv_id": "2726",
   "url": "https://www.rentvreview.com/Videos/View/2726",
-  "vimeo": "1056513923",
-  "title": "RENTV CRE Talk Episode #14 - John McNellis 3573 views Video added by Commercial Real Estat",
+  "title": "RENTV CRE Talk Episode #14 - John McNellis In this episode of Commercial Real Estate Talk,",
+  "ep": 14,
   "sponsors": [],
   "date": "February 12, 2025",
   "guest_note": "John McNellis \u2014 Partner at McNellis Partners, an owner, investor and developer of shopping centers, mai"
  },
- "1200839794": {
-  "rv_id": "3255",
-  "url": "https://www.rentvreview.com/Videos/View/3255",
-  "vimeo": "1200839794",
-  "title": "CRE Talk Episode #22 with Bill Shopoff 2034 views Video added by Commercial Real Estate Ta",
+ "1039101858": {
+  "rv_id": "2642",
+  "url": "https://www.rentvreview.com/Videos/View/2642",
+  "title": "RENTV CRE Talk Episode #13 - Ethan Penner In this episode of Commercial Real Estate Talk w",
+  "ep": 13,
   "sponsors": [
-   "Rockefeller Group",
    "Chase Partners",
-   "Provident Savings Bank",
+   "Commercial Real Estate Inspectors",
    "Fidelity Mortgage Lenders"
   ],
-  "date": "June 10, 2026",
-  "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, a very active developer of major long-te"
+  "date": "December 13, 2024",
+  "guest_note": "Ethan Penner \u2014 Founder & CEO of Mosaic Real Estate Investors, an iconic figure in the real estate fina"
+ },
+ "1012976399": {
+  "rv_id": "2601",
+  "url": "https://www.rentvreview.com/Videos/View/2601",
+  "title": "RENTV CRE Talk Episode #12 - Kaitlin Arduino In this episode of Commercial Real Estate Tal",
+  "ep": 12,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "September 19, 2024",
+  "guest_note": "Kaitlin Arduino \u2014 President of Murphy Development, the family-owned company now in its fourth decade that i"
+ },
+ "953281926": {
+  "rv_id": "2493",
+  "url": "https://www.rentvreview.com/Videos/View/2493",
+  "title": "RENTV CRE Talk Episode #11 - Michael Rademaker In this episode of Commercial Real Estate T",
+  "ep": 11,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "June 03, 2024",
+  "guest_note": "Michael Rademaker \u2014 Founder and CEO of MGR Real Estate, his Ontario-based company the has a residential and"
+ },
+ "931863337": {
+  "rv_id": "2447",
+  "url": "https://www.rentvreview.com/Videos/View/2447",
+  "title": "RENTV CRE Talk Episode #10 Henry Manoucheri In this episode of Commercial Real Estate Talk",
+  "ep": 10,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "March 21, 2024",
+  "guest_note": "Henry Manoucheri \u2014 Chairman and CEO of Universe Holdings, the multifamily real estate investment firm that"
+ },
+ "911412212": {
+  "rv_id": "2392",
+  "url": "https://www.rentvreview.com/Videos/View/2392",
+  "title": "RENTV CRE Talk Episode #9 Eddie Ring In this episode of Commercial Real Estate Talk with S",
+  "ep": 9,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "February 09, 2024",
+  "guest_note": "Eddie Ring \u2014 Founder and CEO of New Standard Equities, the multifamily real estate investment firm t"
+ },
+ "906276616": {
+  "rv_id": "2346",
+  "url": "https://www.rentvreview.com/Videos/View/2346",
+  "title": "RENTV CRE Talk Episode #8 Erwin Bucy In this episode of Commercial Real Estate Talk with S",
+  "ep": 8,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "January 19, 2024",
+  "guest_note": ""
+ },
+ "886025667": {
+  "rv_id": "2122",
+  "url": "https://www.rentvreview.com/Videos/View/2122",
+  "title": "RENTV CRE Talk Episode #7 Chuck Hershson In this episode of Commercial Real Estate Talk wi",
+  "ep": 7,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Fidelity Mortgage Lenders"
+  ],
+  "date": "November 17, 2023",
+  "guest_note": ""
+ },
+ "868849453": {
+  "rv_id": "2107",
+  "url": "https://www.rentvreview.com/Videos/View/2107",
+  "title": "RENTV CRE Talk Episode #6 Barry Saywitz In this episode of Commercial Real Estate Talk wit",
+  "ep": 6,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Redwood Mortgage"
+  ],
+  "date": "September 21, 2023",
+  "guest_note": "Barry Saywitz \u2014 President & Founder of The Saywitz Company, the commercial real estate brokerage firm, an"
  },
  "852462696": {
   "rv_id": "2033",
   "url": "https://www.rentvreview.com/Videos/View/2033",
-  "vimeo": "852462696",
-  "title": "RENTV CRE Talk Episode #5 Barry DiRaimondo 14679 views Video added by Commercial Real Esta",
-  "sponsors": [],
+  "title": "RENTV CRE Talk Episode #5 Barry DiRaimondo In this episode of Commercial Real Estate Talk ",
+  "ep": 5,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Redwood Mortgage"
+  ],
   "date": "August 09, 2023",
   "guest_note": ""
+ },
+ "795355693": {
+  "rv_id": "1910",
+  "url": "https://www.rentvreview.com/Videos/View/1910",
+  "title": "Commercial Real Estate Talk, Episode #2 - Sandy Sigal In this episode of Commercial Real E",
+  "ep": 2,
+  "sponsors": [],
+  "date": "January 30, 2023",
+  "guest_note": "Sandy SIgal \u2014 President and CEO of NewMark Merrill Companies"
+ },
+ "771348410": {
+  "rv_id": "1909",
+  "url": "https://www.rentvreview.com/Videos/View/1909",
+  "title": "Commercial Real Estate Talk, Episode #1 - Bill Shopoff In this first episode of Commercial",
+  "ep": 1,
+  "sponsors": [
+   "Paramount Property Tax Appeal",
+   "Commercial Real Estate Inspectors",
+   "Redwood Mortgage"
+  ],
+  "date": "November 14, 2022",
+  "guest_note": "Bill Shopoff \u2014 President and CEO of Shopoff Realty Investments, which is celebrating its 30th Anniversar"
  }
 }
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 4d1e23d..f0bc12f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -183,7 +183,8 @@ function renderCards(main,L){
     const c=el("div","card");
     c.innerHTML=`<h3 onclick='openAdv(${JSON.stringify(a.name)})'>${esc(a.name)}</h3>
       <div class="row"><span class="badge cat">${esc(a.category||"other")}</span>
-        <span class="appear" onclick='openAdv(${JSON.stringify(a.name)})'>${a.appearances} run${a.appearances>1?"s":""}</span></div>
+        <span class="appear" onclick='openAdv(${JSON.stringify(a.name)})'>${a.appearances} run${a.appearances>1?"s":""}</span>
+        ${a.review_verified?`<span class="badge" style="color:var(--gold);border-color:#3a3320" title="Confirmed by RENTV's official sponsor list on The REview (${a.review_appearances} episodes)">✓ REview</span>`:""}</div>
       <div class="pitch">${esc(a.pitch||"")}</div>
       ${(a.websites||[]).map(w=>`<div class="kv">🌐 <a href="${siteURL(esc(w))}" target="_blank" rel="noopener">${esc(w)}</a></div>`).join("")}
       ${(a.phones||[]).map(p=>`<div class="kv">📞 <a href="${telURL(p)}">${esc(p)}</a></div>`).join("")}
@@ -230,7 +231,7 @@ function renderCards(main,L){
     const c=el("div","card"); const fr=FRAMES[v.id];
     c.innerHTML=`${fr&&fr.poster?`<img src="${esc(fr.poster)}" loading="lazy" onclick="openEpisode(${v.id})" style="width:100%;border-radius:8px;cursor:pointer;border:1px solid var(--line)">`:""}
       <h3 onclick="openEpisode(${v.id})" style="font-size:14px">${esc(v.title)}</h3>
-      <div class="kv">⏱ ${(v.duration/60).toFixed(0)} min · 📝 ${(v.caption_chars/1000).toFixed(1)}k chars</div>
+      <div class="kv">${v.air_date?"📅 "+esc(v.air_date)+" · ":""}⏱ ${(v.duration/60).toFixed(0)} min · 📝 ${(v.caption_chars/1000).toFixed(1)}k chars</div>
       ${fr&&fr.logos&&fr.logos.length?`<div class="row"><span class="kv">on-screen:</span>${fr.logos.map(l=>`<span class="chip">${esc(l)}</span>`).join("")}</div>`:""}
       <div class="row"><span class="badge">${v.has_captions?"transcribed":"no captions"}</span>
         <span class="chip ep" onclick="openEpisode(${v.id})">▶ open dossier</span></div>`;
diff --git a/scripts/harvest-rentvreview.py b/scripts/harvest-rentvreview.py
index b17990c..5a1982e 100644
--- a/scripts/harvest-rentvreview.py
+++ b/scripts/harvest-rentvreview.py
@@ -1,95 +1,84 @@
 #!/usr/bin/env python3
-"""Harvest AUTHORITATIVE episode data from rentvreview.com ("The REview").
+"""Harvest AUTHORITATIVE episode data from rentvreview.com "The REview".
 
-Each /Videos/View/<id> page is server-rendered and carries, in plain HTML:
-  - data-video-external-id="<vimeoId>"  (maps REview episode -> our Vimeo video)
-  - "... Sponsored by: A; B; and C. To be a part ..."  (authoritative sponsor list)
-  - the guest/synopsis prose + "Date Created: <date>"
-This is cleaner than transcript inference and covers episodes predating the Vimeo feed.
+The CRE Talk producer page /Producers/View/618 lists EVERY episode inline with its
+title, "Sponsored by:" list, air date, and guest prose — one server-rendered fetch,
+free, no API/DRM. We parse it into per-episode records and join to our Vimeo library
+by episode number (both title sets carry "Episode #N").
 
-We BFS from known CRE Talk pages, following the 6 related-video links per page, keeping
-pages whose Vimeo id matches our library OR whose title is a CRE Talk episode. Free,
-bounded (MAX_FETCH), no API/DRM.
-
-Output: data/rentvreview.json  { "<vimeoId>": {rv_id,url,sponsors[],guest_note,date,title} }
-Env: MAX_FETCH (default 120), SEEDS (comma ids)
+Output: data/rentvreview.json  { "<vimeoId>": {rv_id,url,title,ep,sponsors[],date,guest_note} }
+Env: PRODUCER (default 618)
 """
-import json, os, re, time, urllib.request, html as _html
-from collections import deque
+import json, os, re, urllib.request, html as _html
 
 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 MANIFEST = os.path.join(ROOT, "data", "manifest.json")
 OUT = os.path.join(ROOT, "data", "rentvreview.json")
 UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1"
-MAX_FETCH = int(os.environ.get("MAX_FETCH", "120"))
-SEEDS = [s for s in os.environ.get("SEEDS", "1909,1910,2493,2642,2726,3255,1034,1650,2033,2298,2898,3273").split(",") if s]
+PRODUCER = os.environ.get("PRODUCER", "618")
 
-VIMEO_IDS = {str(v["id"]) for v in json.load(open(MANIFEST))["videos"]}
+STOP = re.compile(r"(To be a part|If you have|Thank you|please email|\bhere\b)", re.I)
 
 
-def fetch(rv_id):
-    try:
-        return urllib.request.urlopen(urllib.request.Request(
-            f"https://www.rentvreview.com/Videos/View/{rv_id}", headers={"User-Agent": UA}), timeout=20
-        ).read().decode("utf-8", "ignore")
-    except Exception:
-        return ""
+def epnum(title):
+    m = re.search(r"Episode\s*#?\s*(\d+)", title or "", re.I)
+    return int(m.group(1)) if m else None
 
 
-def parse(h):
-    ext = re.search(r'data-video-external-id="(\d+)"', h)
-    vimeo = ext.group(1) if ext else ""
-    text = _html.unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", h)))
-    title = ""
-    mt = re.search(r"(RENTV CRE Talk Episode #?\d+[^|<]*|CRE Talk,? Episode #?\d+[^|<]*|Commercial Real Estate Talk,? Episode #?\d+[^|<]*)", text)
-    if mt:
-        title = mt.group(1).strip()[:90]
-    sponsors = []
-    ms = re.search(r"Sponsored by[:\s]+(.+?)\.\s*(?:To be a part|If you|Thank you|$)", text, re.I)
-    if ms:
-        raw = ms.group(1)
-        parts = re.split(r";|,|\band\b", raw)
-        sponsors = [re.sub(r"\s+", " ", p).strip().title() for p in parts if p.strip() and len(p.strip()) > 2]
-    date = ""
-    md = re.search(r"Date Created:\s*([A-Za-z]+ \d{1,2}, \d{4})", text)
-    if md:
-        date = md.group(1)
-    guest = ""
-    mg = re.search(r"interview\s+([A-Z][a-zA-Z.\-]+ [A-Z][a-zA-Z.\-]+)[,]?\s+((?:President|CEO|Founder|Partner|Managing|Chief|Head|Owner|Chairman)[^.]{0,80})", text)
-    if mg:
-        guest = f"{mg.group(1)} — {mg.group(2).strip()}"[:120]
-    related = re.findall(r'href="/Videos/View/(\d+)"', h)
-    return {"vimeo": vimeo, "title": title, "sponsors": sponsors, "date": date, "guest_note": guest}, related
+def clean_sponsors(raw):
+    raw = re.split(r"To be a part|If you have|Thank you", raw, 1)[0]
+    parts = re.split(r";|\band\b|,", raw)
+    out = []
+    for p in parts:
+        s = re.sub(r"\s+", " ", p).strip(" .;:").title()
+        if len(s) > 2 and not s.lower().startswith(("http", "www")):
+            out.append(s)
+    return out
 
 
 def main():
+    lib = json.load(open(MANIFEST))["videos"]
+    by_ep = {}
+    for v in lib:
+        n = epnum(v["title"])
+        if n is not None:
+            by_ep[n] = str(v["id"])
+
+    html = urllib.request.urlopen(urllib.request.Request(
+        f"https://www.rentvreview.com/Producers/View/{PRODUCER}", headers={"User-Agent": UA}), timeout=30
+    ).read().decode("utf-8", "ignore")
+
+    # split into per-video segments by the view links (order = listing order)
+    segs = re.split(r'href="/Videos/View/(\d+)"', html)
+    # segs = [pre, id1, block1, id2, block2, ...]
     out = json.load(open(OUT)) if os.path.exists(OUT) else {}
-    seen, q, fetched = set(), deque(SEEDS), 0
-    print(f"[rentvreview] BFS from {len(SEEDS)} seeds, cap {MAX_FETCH}, matching {len(VIMEO_IDS)} vimeo ids")
-    while q and fetched < MAX_FETCH:
-        rv = q.popleft()
-        if rv in seen:
+    mapped = 0
+    # each rv id appears twice (thumbnail link + title/description link); the title
+    # block is the one that parses — so process every segment and keep those with a title.
+    for i in range(1, len(segs) - 1, 2):
+        rv_id = segs[i]
+        block = _html.unescape(re.sub(r"\s+", " ", re.sub(r"<[^>]+>", " ", segs[i + 1])))[:1600]
+        mt = re.search(r"((?:RENTV )?CRE Talk,? Episode #?\d+[^|<.]*|Commercial Real Estate Talk,? Episode #?\d+[^|<.]*)", block)
+        title = mt.group(1).strip() if mt else ""
+        n = epnum(title)
+        if n is None or n not in by_ep:
             continue
-        seen.add(rv)
-        h = fetch(rv)
-        fetched += 1
-        if not h:
-            continue
-        rec, related = parse(h)
-        is_cre = ("Commercial Real Estate Talk" in h or "CRE Talk" in h)
-        if rec["vimeo"] and (rec["vimeo"] in VIMEO_IDS or is_cre):
-            key = rec["vimeo"]
-            out[key] = {"rv_id": rv, "url": f"https://www.rentvreview.com/Videos/View/{rv}", **rec}
-            # follow related to find sibling episodes
-            for r in related:
-                if r not in seen:
-                    q.append(r)
-        if fetched % 15 == 0:
-            print(f"  fetched={fetched} matched={len(out)} queue={len(q)}")
-        time.sleep(0.3)
+        vimeo = by_ep[n]
+        ms = re.search(r"Sponsored by[:\s]+(.+?)\.\s", block, re.I)
+        sponsors = clean_sponsors(ms.group(1)) if ms else []
+        md = re.search(r"Date Created:\s*([A-Za-z]+ \d{1,2}, \d{4})", block)
+        date = md.group(1) if md else ""
+        mg = re.search(r"interview\s+([A-Z][a-zA-Z.\-]+ [A-Z][a-zA-Z.\-]+)[,]?\s+((?:President|CEO|Co-?founder|Founder|Partner|Managing|Chief|Head|Owner|Chairman)[^.]{0,80})", block)
+        guest = f"{mg.group(1)} — {mg.group(2).strip()}"[:130] if mg else ""
+        out[vimeo] = {"rv_id": rv_id, "url": f"https://www.rentvreview.com/Videos/View/{rv_id}",
+                      "title": title[:90], "ep": n, "sponsors": sponsors, "date": date, "guest_note": guest}
+        mapped += 1
+
     json.dump(out, open(OUT, "w"), indent=1)
-    matched_lib = sum(1 for k in out if k in VIMEO_IDS)
-    print(f"[rentvreview] DONE fetched={fetched} matched={len(out)} (of which {matched_lib} in our Vimeo library) -> {OUT}")
+    withsp = sum(1 for r in out.values() if r.get("sponsors"))
+    print(f"[rentvreview] producer {PRODUCER}: mapped {mapped} episodes this run | total {len(out)} | with sponsors {withsp}")
+    for k, r in sorted(out.items(), key=lambda x: -(x[1].get("ep") or 0)):
+        print(f"  ep{r.get('ep'):>2} {r.get('date',''):>18}  sponsors={r.get('sponsors')}")
 
 
 if __name__ == "__main__":
diff --git a/scripts/reconcile-review.py b/scripts/reconcile-review.py
new file mode 100644
index 0000000..1386c5c
--- /dev/null
+++ b/scripts/reconcile-review.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+"""Reconcile the AUTHORITATIVE rentvreview.com data into the engine.
+
+- Marks each advertiser review_verified when RENTV's official "Sponsored by" lists it,
+  with an authoritative review_appearances count + the episodes.
+- Stamps each video's real air date (from The REview) onto the manifest.
+- Reports agreement between our transcript extraction and RENTV's official record.
+"""
+import json, os, re
+
+ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ADV = os.path.join(ROOT, "data", "advertisers.json")
+MANI = os.path.join(ROOT, "data", "manifest.json")
+RV = os.path.join(ROOT, "data", "rentvreview.json")
+
+
+def nk(s):
+    return re.sub(r"[^a-z0-9]", "", (s or "").lower())
+
+
+def main():
+    rv = json.load(open(RV))
+    advdoc = json.load(open(ADV)); advs = advdoc["advertisers"]
+    mani = json.load(open(MANI))
+
+    # authoritative advertiser -> set(vimeo episode ids) from RENTV official sponsor lists
+    auth = {}
+    for vid, r in rv.items():
+        for s in r.get("sponsors", []):
+            auth.setdefault(nk(s), {"name": s, "eps": set()})["eps"].add(vid)
+
+    # stamp real air dates onto manifest
+    dated = 0
+    for v in mani["videos"]:
+        r = rv.get(str(v["id"]))
+        if r and r.get("date"):
+            v["air_date"] = r["date"]; dated += 1
+    json.dump(mani, open(MANI, "w"), indent=1)
+
+    # cross-verify advertisers
+    verified = 0
+    for a in advs:
+        keys = [nk(a["name"])] + [nk(x) for x in a.get("aliases", [])]
+        hit = None
+        for k in keys:
+            for ak, av in auth.items():
+                if k and (k == ak or (len(k) > 5 and (k in ak or ak in k))):
+                    hit = av; break
+            if hit:
+                break
+        if hit:
+            a["review_verified"] = True
+            a["review_appearances"] = len(hit["eps"])
+            a["review_official_name"] = hit["name"]
+            verified += 1
+        else:
+            a["review_verified"] = False
+    advdoc["reconciled_at"] = __import__("time").strftime("%Y-%m-%d %H:%M:%S")
+    json.dump(advdoc, open(ADV, "w"), indent=1)
+
+    # agreement report
+    print(f"[reconcile] episodes dated from REview: {dated}")
+    print(f"[reconcile] advertisers REview-verified: {verified}/{len(advs)}")
+    print("[reconcile] authoritative sponsors (official appearances):")
+    for ak, av in sorted(auth.items(), key=lambda x: -len(x[1]["eps"])):
+        # compare to our transcript count
+        ours = next((a for a in advs if nk(a["name"]) == ak or av["name"].lower() in a["name"].lower()), None)
+        oc = ours["appearances"] if ours else "—"
+        print(f"    {av['name']:<34} official={len(av['eps']):>2}  ours(transcript)={oc}")
+
+
+if __name__ == "__main__":
+    main()

← 750f51f Integrate RENTV podcast (SoundCloud rentvnews) + The REview  ·  back to Rentv Ad Engine  ·  make ad-engine mountable under a path prefix (BASE_PATH -> < 87ad1ae →