Skip to content

feat(vehicle-hal): source health fail-closed consumption (PR-2)#72

Merged
selimmujdeci merged 4 commits into
mainfrom
feat/vehicle-hal-source-health-consumption
Jul 12, 2026
Merged

feat(vehicle-hal): source health fail-closed consumption (PR-2)#72
selimmujdeci merged 4 commits into
mainfrom
feat/vehicle-hal-source-health-consumption

Conversation

@selimmujdeci

@selimmujdeci selimmujdeci commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Amaç — sessiz ECU frame kaybı blokajını kapatmak

PR-1 worker'ın per-kaynak canlılığını (SRC_TIMEOUT_CAN_MS=3s, 1 Hz watchdog) halStatusStore.sourceHealth'e taşıdı. Bu PR onu tüketiyor:

worker watchdog → SOURCE_HEALTH → halStatusStore.sourceHealth
  → UnifiedVehicleStoreProvider snapshot → VehicleHalProviderAdapter
  → VehicleHal → VehicleHalEventBridge → appEventBus

Kablo takılı / port açık olsa bile (native canStatus connected:true der — CarLauncherPlugin.java:3748-3756) ECU susarsa CAN-özel sinyaller artık fail-closed olur.

Model

Provider snapshot'a bounded sourceHealth { can, obd, gps, ts } eklendi — yapısal DI (provider/adapter store'ları doğrudan import etmez). Araç + sağlık store abonelikleri tek unsub'a sarıldı → teşhisteki activeSubscriptionCount = 1 invaryantı korunur. Yeni registry/DI container yok.

unknown ≠ disconnected

Değer Anlam Davranış
null worker hiç bildirmedi sahte disconnect yok — davranış W4B ile aynı
false kaynak kesin ölü yalnız o kaynağa bağlı sinyaller unsupported
true canlı normal akış

Sinyal-kaynak matrisi (testle kilitli)

  • CAN-ÖZELcan=false ise source:'none' · supported=false · value=null · quality='unknown' · confidence=0:
    coolant_temp · oil_temp · throttle · battery_voltage · gear · ambient_temp · tpms · door_state · parking_brake
  • FÜZYON (CAN ölse de OBD/GPS/worker beslerse supported kalır): speed · rpm · fuel_level · odometer · reverse
    • rpm'in CAN fallback'i (canRpm) CAN ölüyken bayat sayılır ve kullanılmaz → fused rpm de yoksa unsupported.
  • ignition → kaynak yok, üretilmez (guessed false yok).

Diriltme yasağı (reconnect)

can=true tek başına eski değeri supported yapmaz: ölüm anındaki değer saklanır; sinyal ancak değer değişince (= taze frame kanıtı) gerçek source/quality/confidence ile geri döner. Store frame gelmeyince eski değeri tuttuğu için bu, sahte eski değer diriltmesini yapısal olarak engeller.

Batch / emit

Bir geçişte düşen (veya dönen) tüm sinyaller tek hal.ingest(batch) → tek HAL emit (W4A korunur). Aynı durum tekrarında duplicate ingest/emit yok. Batch throw ederse dedupe kirlenmez, sonraki refresh yeniden dener.

Bridge (W4C)

Tüm supported sinyaller kalkınca vehicle.connection.changed=false; kısmi kayıpta yayınlanmaz; reconnect'te yalnız gerçek veriyle true. droppedCount artmıyor (testli).

Diagnostic (PR #68 yüzeyi)

Bounded sourceHealth { can, obd, gps, lastChangeAt }null ile false ayrı. Sinyal değeri (hız/RPM), CAN frame, VIN, koordinat, ham payload, event history, secret gönderilmez. Yeni endpoint/timer/otomatik gönderim yok.

⚠️ Background riski (kanıt yok → davranış değiştirilmedi)

Kaynak kodda worker'a görünürlük/pause sinyali taşınmıyor (doğrulandı — VDL'de visibilitychange/pause yok). Dolayısıyla uygulama arka plandayken worker timer'ı kısılır veya plugin event teslimi gecikirse yanlış-pozitif can=false üretilebilir. Ölçümsüz "N ardışık tur" eşiği eklenmedi (magic number yasağı); açık risk olarak Ledger'a yazıldı ve cihaz planında ölçülecek.

Test / lint / build / guard

  • Yeni: vehicleHalSourceHealthConsumption.test.ts25 test (unknown, CAN-dead matrisi, fallback, diriltme yasağı, batch/emit, bridge connection true/false/reconnect, lifecycle/tek abonelik, kapsam)
  • Güncellenen kilitler: platformRuntimeDiagnostics (yeni sourceHealth bölümü) + workerSourceHealthTransport (adapter artık sağlığı snapshot'tan tüketiyor; halStatusStore doğrudan import etmiyor)
  • npm run test: 3544 test / 200 dosya yeşil · lint: 0 hata · build: başarılı · guard: 113/113 yeşil (pre-existing _hasAnyField timeout'u bu koşuda tekrarlamadı)

Kapsam dışı

W4D throttle · consumer migration · native canStatus wiring · worker watchdog davranışı · VehicleSignalResolver · SystemBoot · Event Bus/bridge/HAL foundation · Kernel · Capability · Deep Scan · UI · SQL. Hiçbiri değişmedi.

Rollback

Tek atomik commit → git revert. Provider/adapter eski (health'siz) davranışa döner; sourceHealth yalnız bilgi olarak store'da kalır.

🤖 Generated with Claude Code

https://claude.ai/code/session_012M8LbxyAqd22EU1rqtTjft


🔧 EK DÜZELTME (cf8aef7) — Background sahte "kaynak öldü" kapısı

Kök neden: watchdog canlılığı monotonik saat farkıyla ölçer (_alive(), VehicleCompute.worker.ts:409-411). Bu saat arka planda ilerler, ama WebView timer'ı kısılır ve adaptör frame'leri durur → foreground dönüşündeki ilk tikte now - lastSeen ≫ timeout → kaynak sağlamken false. Araç bağlıyken bu, CAN-özel sinyalleri gereksiz supported=false yapar ve bridge'ten sahte connection.changed=false/true çifti üretirdi. (Önceki cihaz testinde 45 sn arka plan sourceHealth.lastChangeAt'i 3171 → 699171'e taşımıştı.)

Çözüm — Model C (+ görünürlük kanalı), yeni timer YOK:

  • Yeni saf sourceHealthGate.ts (timer/DOM/store yok; zaman enjekte edilir):
    • hidden → sağlık geçişi dondurulur (lastSeen bozulmaz)
    • foregroundtimeout saati yeniden tabanlanır (arka plan süresi timeout'a yazılmaz)
    • taze frame → true · görünür zamanda gerçek timeout dolarsa → false (gerçek kayıp maskelenmez)
    • ikisi de değilse → karar yok (son bilinen değer korunur; yoksa unknown)
  • Worker: bounded VISIBILITY {visible:boolean} kontrol mesajı. Kapı yalnız SOURCE_HEALTH kararını etkiler — fusion/reverse/SAB ham _alive() kullanmaya devam eder. setInterval sayısı 4 → 4.
  • Resolver: tek visibilitychange dinleyicisi (mevcut proje deseni), stop()'ta sökülür, aynı durum tekrar postlanmaz.

Reddedilen modeller: B (yanlış false store'a yazılır → gelecekteki tüketiciler görür) · D (ölçümsüz "N ardışık tur" magic number).

Testler: +27 (sourceHealthVisibilityGating.test.ts) — görünürken alive→dead normal · hidden'da yeni false yok · arka plan süresi timeout'a yazılmıyor · dönüşte anında false yok · taze frame → true · görünür-zaman timeout'u → false · CAN/OBD/GPS bağımsız · duplicate visibility pencereyi uzatmıyor · background→foreground event fırtınası yok · zero-leak cleanup. Suite 3571 yeşil · lint 0 hata · build OK · guard 113/113.

🟢 Cihaz kanıtı (Xiaomi, araç YOK — gerçek rapor gövdesi, enstrümantasyonsuz):

  • Premise teyit: arka planda WebView document.visibilityState === 'hidden' döndürüyor.
  • ~20 dk arka plan sonrası sourceHealth.lastChangeAt boot değerinde kaldı (1026.6) → arka planda SIFIR sağlık geçişi. activeSubscriptionCount=1, halBridge.droppedCount=0, sahte connection.changed yok.
  • 🟡 Foreground dönüşünde bir gps:false→true çifti gözlendi — arka plan saatinden değil, tasarım gereği görünür zamandaki 5 sn GPS sessizliğinden (OS konum akışı dönüşte geç başlıyor). Kalıcı hasar yok (ingestedSignalCount 3'e döndü, droppedCount=0). Ölçümsüz grace eşiği eklenmedi.

Hâlâ eksik (Ledger #56 🔴): gerçek araç (CAN canlı→ölü→dönüş) · low-tier cihaz (K24/T507) · araç bağlıyken foreground görünür-zaman timeout'unun CAN'de geçici false üretip üretmediği.

PR-1'in taşıdığı halStatusStore.sourceHealth (worker 1 Hz watchdog) artık HAL veri
akışında tüketiliyor → SESSİZ ECU FRAME KAYBI blokajı kapanıyor: kablo takılı ve
port açık olsa bile (native canStatus connected:true der) worker frame sessizliğini
görüyor ve CAN-özel sinyaller fail-closed oluyor.

- Provider snapshot'a bounded sourceHealth {can,obd,gps,ts} (yapısal DI; provider/
  adapter store'ları doğrudan import etmez). Araç + sağlık abonelikleri TEK unsub'a
  sarıldı → activeSubscriptionCount=1 invaryantı korunur.
- unknown (null) ≠ dead (false): null iken sahte disconnect YOK (W4B davranışı).
- can=false → yalnız CAN-ÖZEL sinyaller source:'none'/supported=false/value=null/
  quality='unknown'/confidence=0. Füzyon (speed/rpm/fuel/odometer/reverse) başka
  kaynak canlıysa supported kalır; rpm'in canRpm fallback'i CAN ölüyken bayat sayılır.
- Diriltme yasağı: can=true tek başına eski değeri supported yapmaz — yalnız değer
  değişince (taze frame kanıtı) gerçek source/quality/confidence ile döner.
- Tek batch / tek HAL emit (W4A korunur); aynı durum duplicate ingest/emit üretmez.
- Bridge: tüm destek kalkınca connection.changed=false; kısmi kayıpta yayınlanmaz;
  reconnect'te yalnız gerçek veriyle true.
- Teşhis: support_snapshot'a bounded sourceHealth {can,obd,gps,lastChangeAt}
  (null≠false; sinyal değeri/CAN frame/VIN/koordinat yok).
- ignition üretilmez; yeni timer/polling yok.
- Background yanlış-pozitif riski: worker'a görünürlük sinyali TAŞINMIYOR (doğrulandı)
  → kanıtsız eşik EKLENMEDİ, açık risk olarak Ledger'a yazıldı.
- Ledger #56 🔴.

Kapsam dışı: W4D throttle, consumer migration, native canStatus, Kernel/Capability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012M8LbxyAqd22EU1rqtTjft
@vercel

vercel Bot commented Jul 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
car-launcher-pro Ready Ready Preview, Comment Jul 12, 2026 3:47pm
carospro Ready Ready Preview, Comment Jul 12, 2026 3:47pm

sourceHealth teşhis raporunda görünüyor (can:false/obd:false/gps:true — araçsız
doğru). Sahte disconnect yok (ingestedSignalCount=3 sabit), tek abonelik korunuyor
(activeSubscriptionCount=1), bridge dropped=0, boot/CPU/RAM regresyonu yok.

Background 45 sn testi: dönüşte gps:true kaldı ve HAL'e düşüş yansımadı; ancak
lastChangeAt taşındı → arka planda geçici gps:false DIŞLANAMADI (risk sürüyor).

Satır 🔴 KALIYOR: gerçek araç (can=false/reconnect/connection) ve low-tier eksik.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012M8LbxyAqd22EU1rqtTjft
…TH görünürlük gating

PR #72 (source health → HAL fail-closed) arka planda YANLIŞ-POZİTİF üretebiliyordu:
watchdog canlılığı monotonik saat farkıyla ölçer (_alive, VehicleCompute.worker.ts:409-411);
bu saat arka planda ilerler ama WebView timer'ı kısılır ve adaptör frame'leri durur →
foreground dönüşündeki ilk tikte now-lastSeen >> timeout → kaynak SAĞLAMKEN can=false.
Araç bağlıyken bu, CAN-özel sinyalleri gereksiz unsupported yapar ve bridge'ten sahte
connection.changed=false/true çifti üretirdi.

ÇÖZÜM (minimum, yeni timer YOK):
- sourceHealthGate.ts (yeni, SAF: timer/DOM/store yok, zaman enjekte edilir)
    hidden    → sağlık GEÇİŞİ dondurulur (lastSeen BOZULMAZ)
    foreground→ timeout SAATİ yeniden tabanlanır (arka plan süresi timeout'a YAZILMAZ)
    taze frame→ true · görünür zamanda gerçek timeout → false (gerçek kayıp MASKELENMEZ)
    ikisi de değilse → KARAR YOK (son bilinen değer korunur; yoksa unknown)
- worker: bounded VISIBILITY {visible:boolean} kontrol mesajı; kapı YALNIZ SOURCE_HEALTH
  kararını etkiler — fusion/reverse/SAB ham _alive() kullanmaya devam eder.
- resolver: TEK visibilitychange dinleyicisi (mevcut proje deseni), stop()'ta sökülür,
  duplicate durum POSTLANMAZ.

Kapsam dışı bırakıldı: Event Bus/bridge/HAL/Kernel/Capability/DeepScan foundation, UI,
SQL, throttle/coalescing, timer sayısı (worker setInterval 4 → 4).

Testler: +27 (sourceHealthVisibilityGating) — visible alive→dead, hidden'da false yok,
arka plan süresi timeout'a yazılmıyor, dönüşte anında false yok, taze frame → true,
görünür timeout → false, CAN/OBD/GPS bağımsız, duplicate visibility pencereyi uzatmıyor,
background→foreground event fırtınası yok, zero-leak cleanup.
Suite 3571 yeşil · lint 0 hata · build OK · guard 113/113.

Ledger #56 🔴 (gerçek araç + low-tier hâlâ eksik).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012M8LbxyAqd22EU1rqtTjft
…Xiaomi)

Gerçek "Tanı Gönder" rapor gövdesinden (enstrümantasyonsuz):
- Premise teyit: arka planda WebView `document.visibilityState === 'hidden'` döndürüyor.
- SAHTE DEAD YOK: ~20 dk arka plan sonrası `sourceHealth.lastChangeAt` boot değerinde
  KALDI (1026.6) → arka planda SIFIR sağlık geçişi. (Düzeltme öncesi 45 sn arka plan
  aynı cihazda 3171 → 699171 taşımıştı.)
- activeSubscriptionCount=1, halBridge.droppedCount=0, sahte connection.changed YOK.
- 🟡 Foreground dönüşünde gps false→true çifti: arka plan saatinden DEĞİL, görünür
  zamandaki 5 sn GPS sessizliğinden (OS akışı geç başlıyor); ölçümsüz eşik eklenmedi.

Ledger #56 🔴 KALIR — gerçek araç + low-tier hâlâ eksik.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012M8LbxyAqd22EU1rqtTjft
@selimmujdeci selimmujdeci merged commit 5095fe9 into main Jul 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant