Created
April 25, 2026 09:22
-
-
Save heumn/65b76f18cb5ad6b5b1bb42c31a4cbea3 to your computer and use it in GitHub Desktop.
Drive-away detection illustration for enode/api#11388
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Drive-Away Detection Change</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| font-family: 'Inter', system-ui, -apple-system, sans-serif; | |
| -webkit-font-smoothing: antialiased; | |
| background: #FFFFFF; | |
| color: #423F35; | |
| } | |
| .container { | |
| max-width: 72rem; | |
| margin: 0 auto; | |
| padding: 0 1rem; | |
| } | |
| /* Header */ | |
| .header { | |
| background: #191610; | |
| padding: 2.5rem 0; | |
| text-align: center; | |
| } | |
| .header h1 { | |
| color: #FCFCFB; | |
| font-size: 1.75rem; | |
| font-weight: 500; | |
| letter-spacing: -0.05em; | |
| line-height: 1.0; | |
| margin-bottom: 0.5rem; | |
| } | |
| .header .subtitle { | |
| color: rgba(252, 252, 251, 0.6); | |
| font-size: 0.9375rem; | |
| font-weight: 400; | |
| } | |
| .header .pr-badge { | |
| display: inline-block; | |
| background: #5D770D; | |
| color: #FFFFFF; | |
| font-size: 0.8125rem; | |
| font-weight: 500; | |
| padding: 0.25rem 0.75rem; | |
| border-radius: 5.5rem; | |
| margin-top: 0.75rem; | |
| font-family: 'JetBrains Mono', monospace; | |
| } | |
| /* Sentry stats */ | |
| .stats-section { | |
| background: #F5F3EE; | |
| padding: 2.5rem 0; | |
| } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 1.5rem; | |
| max-width: 48rem; | |
| margin: 0 auto; | |
| } | |
| .stat-card { | |
| background: #FFFFFF; | |
| border-radius: 6px; | |
| padding: 1.25rem; | |
| text-align: center; | |
| } | |
| .stat-card .number { | |
| font-size: 2rem; | |
| font-weight: 500; | |
| color: #002203; | |
| letter-spacing: -0.05em; | |
| line-height: 1.0; | |
| } | |
| .stat-card .number.red { color: #E2722C; } | |
| .stat-card .number.green { color: #5D770D; } | |
| .stat-card .label { | |
| font-size: 0.8125rem; | |
| color: #505038; | |
| margin-top: 0.375rem; | |
| } | |
| /* Flow section */ | |
| .flow-section { | |
| padding: 3rem 0; | |
| } | |
| .flow-section h2 { | |
| font-size: 1.5rem; | |
| font-weight: 500; | |
| color: #002203; | |
| letter-spacing: -0.05em; | |
| text-align: center; | |
| margin-bottom: 2rem; | |
| } | |
| .flow-comparison { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 2rem; | |
| max-width: 56rem; | |
| margin: 0 auto; | |
| } | |
| .flow-column { | |
| border-radius: 8px; | |
| overflow: hidden; | |
| } | |
| .flow-column.before { background: #FFF; border: 1px solid rgba(66, 63, 53, 0.12); } | |
| .flow-column.after { background: #FFF; border: 2px solid #5D770D; } | |
| .flow-header { | |
| padding: 0.75rem 1rem; | |
| font-weight: 500; | |
| font-size: 0.9375rem; | |
| text-align: center; | |
| letter-spacing: -0.03em; | |
| } | |
| .flow-column.before .flow-header { | |
| background: rgba(226, 114, 44, 0.1); | |
| color: #E2722C; | |
| } | |
| .flow-column.after .flow-header { | |
| background: rgba(93, 119, 13, 0.1); | |
| color: #5D770D; | |
| } | |
| .flow-body { | |
| padding: 1.25rem; | |
| } | |
| .flow-step { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 0.625rem; | |
| padding: 0.5rem 0; | |
| } | |
| .flow-step + .flow-step { | |
| border-top: 1px solid rgba(66, 63, 53, 0.06); | |
| } | |
| .step-icon { | |
| flex-shrink: 0; | |
| width: 1.5rem; | |
| height: 1.5rem; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 0.75rem; | |
| font-weight: 500; | |
| margin-top: 0.125rem; | |
| } | |
| .step-icon.check { background: rgba(93, 119, 13, 0.15); color: #5D770D; } | |
| .step-icon.cross { background: rgba(226, 114, 44, 0.15); color: #E2722C; } | |
| .step-icon.arrow { background: rgba(80, 80, 56, 0.1); color: #505038; } | |
| .step-icon.new { background: #5D770D; color: #FFFFFF; } | |
| .step-text { | |
| font-size: 0.8125rem; | |
| line-height: 1.4; | |
| color: #423F35; | |
| } | |
| .step-text strong { color: #002203; font-weight: 500; } | |
| .step-text code { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.75rem; | |
| background: #F5F3EE; | |
| padding: 0.1rem 0.3rem; | |
| border-radius: 3px; | |
| color: #505038; | |
| } | |
| .step-text .dim { color: rgba(66, 63, 53, 0.5); } | |
| /* Vehicle grid */ | |
| .vehicles-section { | |
| background: #F5F3EE; | |
| padding: 2.5rem 0; | |
| } | |
| .vehicles-section h2 { | |
| font-size: 1.5rem; | |
| font-weight: 500; | |
| color: #002203; | |
| letter-spacing: -0.05em; | |
| text-align: center; | |
| margin-bottom: 0.375rem; | |
| } | |
| .vehicles-section .section-sub { | |
| text-align: center; | |
| font-size: 0.8125rem; | |
| color: #505038; | |
| margin-bottom: 1.5rem; | |
| } | |
| .vendor-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 1rem; | |
| max-width: 48rem; | |
| margin: 0 auto; | |
| } | |
| .vendor-card { | |
| background: #FFFFFF; | |
| border-radius: 6px; | |
| padding: 1rem 1.25rem; | |
| } | |
| .vendor-card-header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 0.625rem; | |
| } | |
| .vendor-card-header h3 { | |
| font-size: 0.9375rem; | |
| font-weight: 500; | |
| color: #002203; | |
| letter-spacing: -0.03em; | |
| } | |
| .badge { | |
| display: inline-block; | |
| font-size: 0.6875rem; | |
| font-weight: 500; | |
| padding: 0.125rem 0.5rem; | |
| border-radius: 5.5rem; | |
| } | |
| .badge.suppressed { background: rgba(93, 119, 13, 0.12); color: #5D770D; } | |
| .badge.active { background: rgba(226, 114, 44, 0.12); color: #E2722C; } | |
| .badge.safe { background: rgba(93, 119, 13, 0.12); color: #5D770D; } | |
| .vendor-list { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.375rem; | |
| } | |
| .vendor-tag { | |
| font-family: 'JetBrains Mono', monospace; | |
| font-size: 0.6875rem; | |
| padding: 0.1875rem 0.5rem; | |
| border-radius: 4px; | |
| font-weight: 400; | |
| } | |
| .vendor-tag.capable { | |
| background: #F5F3EE; | |
| color: #505038; | |
| } | |
| .vendor-tag.incapable { | |
| background: rgba(226, 114, 44, 0.08); | |
| color: #E2722C; | |
| border: 1px solid rgba(226, 114, 44, 0.2); | |
| } | |
| .vendor-note { | |
| font-size: 0.75rem; | |
| color: #505038; | |
| margin-top: 0.5rem; | |
| line-height: 1.4; | |
| } | |
| /* Spot check */ | |
| .spotcheck-section { | |
| padding: 2.5rem 0; | |
| } | |
| .spotcheck-section h2 { | |
| font-size: 1.5rem; | |
| font-weight: 500; | |
| color: #002203; | |
| letter-spacing: -0.05em; | |
| text-align: center; | |
| margin-bottom: 1.5rem; | |
| } | |
| .spotcheck-bar { | |
| max-width: 36rem; | |
| margin: 0 auto 1rem; | |
| display: flex; | |
| border-radius: 6px; | |
| overflow: hidden; | |
| height: 2rem; | |
| } | |
| .bar-segment { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 0.6875rem; | |
| font-weight: 500; | |
| color: #FFFFFF; | |
| } | |
| .bar-segment.real { background: #5D770D; } | |
| .bar-segment.phantom { background: #E2722C; } | |
| .bar-segment.ambiguous { background: #505038; } | |
| .bar-legend { | |
| display: flex; | |
| justify-content: center; | |
| gap: 1.5rem; | |
| max-width: 36rem; | |
| margin: 0 auto; | |
| } | |
| .legend-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.375rem; | |
| font-size: 0.75rem; | |
| color: #505038; | |
| } | |
| .legend-dot { | |
| width: 0.5rem; | |
| height: 0.5rem; | |
| border-radius: 50%; | |
| } | |
| .legend-dot.real { background: #5D770D; } | |
| .legend-dot.phantom { background: #E2722C; } | |
| .legend-dot.ambiguous { background: #505038; } | |
| /* Footer */ | |
| .footer { | |
| background: #184602; | |
| padding: 1.5rem 0; | |
| text-align: center; | |
| } | |
| .footer p { | |
| color: rgba(252, 252, 251, 0.7); | |
| font-size: 0.8125rem; | |
| } | |
| .footer strong { | |
| color: #E6F77E; | |
| font-weight: 500; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Header --> | |
| <section class="header"> | |
| <div class="container"> | |
| <h1>Drive-Away Detection: Capability Gate</h1> | |
| <div class="subtitle">Sentry API-2P8 · staleDataScrubber.ts</div> | |
| <div class="pr-badge">enode/api#11388</div> | |
| </div> | |
| </section> | |
| <!-- Stats --> | |
| <section class="stats-section"> | |
| <div class="container"> | |
| <div class="stats-grid"> | |
| <div class="stat-card"> | |
| <div class="number red">517</div> | |
| <div class="label">warnings in 3 days</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="number">~170</div> | |
| <div class="label">false positives per day</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="number green">0</div> | |
| <div class="label">BMW / MINI / XPENG events</div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Flow comparison --> | |
| <section class="flow-section"> | |
| <div class="container"> | |
| <h2>How the detection logic changes</h2> | |
| <div class="flow-comparison"> | |
| <!-- Before --> | |
| <div class="flow-column before"> | |
| <div class="flow-header">Before (all vendors)</div> | |
| <div class="flow-body"> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Vehicle has a <strong>locationId</strong> (assigned to geofence)</div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Update arrives with <strong>no GPS</strong>, <strong>no odometer</strong></div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Vehicle is <code>UNPLUGGED</code></div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Battery dropped ≥10% from baseline</div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon cross">×</div> | |
| <div class="step-text"><strong>Clear locationId</strong> for <em>all</em> vendors<br><span class="dim">Including Tesla sleep mode, Renault charge-only polls...</span></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- After --> | |
| <div class="flow-column after"> | |
| <div class="flow-header">After (capability-gated)</div> | |
| <div class="flow-body"> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Vehicle has a <strong>locationId</strong> (assigned to geofence)</div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Update arrives with <strong>no GPS</strong>, <strong>no odometer</strong></div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon arrow">↓</div> | |
| <div class="step-text">Vehicle is <code>UNPLUGGED</code></div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon new">✓</div> | |
| <div class="step-text"><strong>Is odometer capable?</strong><br> | |
| <span class="dim">Yes → skip battery fallback, wait for GPS/odometer</span></div> | |
| </div> | |
| <div class="flow-step"> | |
| <div class="step-icon check">↓</div> | |
| <div class="step-text">Only <strong>odometer-incapable</strong> vehicles (BMW, MINI, XPENG) proceed to battery check</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Vendor cards --> | |
| <section class="vehicles-section"> | |
| <div class="container"> | |
| <h2>Impact by vendor</h2> | |
| <p class="section-sub">Based on 500 sampled Sentry events · 22 vehicles spot-checked in production</p> | |
| <div class="vendor-grid"> | |
| <div class="vendor-card"> | |
| <div class="vendor-card-header"> | |
| <h3>Odometer-capable (suppressed)</h3> | |
| <span class="badge suppressed">500 / 500 events</span> | |
| </div> | |
| <div class="vendor-list"> | |
| <span class="vendor-tag capable">RENAULT</span> | |
| <span class="vendor-tag capable">CUPRA</span> | |
| <span class="vendor-tag capable">DACIA</span> | |
| <span class="vendor-tag capable">SKODA</span> | |
| <span class="vendor-tag capable">AUDI</span> | |
| <span class="vendor-tag capable">TESLA</span> | |
| <span class="vendor-tag capable">SEAT</span> | |
| <span class="vendor-tag capable">POLESTAR</span> | |
| <span class="vendor-tag capable">ALPINE</span> | |
| </div> | |
| <div class="vendor-note">These vendors sometimes omit odometer from individual polls (e.g. Tesla sleep, Renault charge-only). Phantom drain on parked vehicles crosses the 10% threshold, causing false positives.</div> | |
| </div> | |
| <div class="vendor-card"> | |
| <div class="vendor-card-header"> | |
| <h3>Odometer-incapable (still active)</h3> | |
| <span class="badge active">0 / 500 events</span> | |
| </div> | |
| <div class="vendor-list"> | |
| <span class="vendor-tag incapable">BMW</span> | |
| <span class="vendor-tag incapable">MINI</span> | |
| <span class="vendor-tag incapable">XPENG</span> | |
| </div> | |
| <div class="vendor-note">These vendors can never report odometer. Battery fallback is the only drive-away signal beyond GPS. Currently zero events in production — the fallback remains available if needed.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Spot-check --> | |
| <section class="spotcheck-section"> | |
| <div class="container"> | |
| <h2>22 vehicles spot-checked</h2> | |
| <div class="spotcheck-bar"> | |
| <div class="bar-segment real" style="width: 59%">59% real</div> | |
| <div class="bar-segment phantom" style="width: 18%">18%</div> | |
| <div class="bar-segment ambiguous" style="width: 23%">23%</div> | |
| </div> | |
| <div class="bar-legend"> | |
| <div class="legend-item"><div class="legend-dot real"></div> Real drive-away (13)</div> | |
| <div class="legend-item"><div class="legend-dot phantom"></div> Phantom drain false positive (4)</div> | |
| <div class="legend-item"><div class="legend-dot ambiguous"></div> Ambiguous (5)</div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Footer --> | |
| <section class="footer"> | |
| <div class="container"> | |
| <p>After this change, Sentry API-2P8 volume drops to <strong>~0 events/day</strong> from current vendors.<br> | |
| BMW/MINI/XPENG retain the battery fallback for genuine no-odometer scenarios.</p> | |
| </div> | |
| </section> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment