fix(vinpin): claim warm on Fiat+Dialogys anchor (not full 3-window)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled

The full 3-window gate never warmed during a prolonged Rpartstore outage, so the
daemon re-attempted warm-up every backoff cycle — each ~2min attempt holds the
single-seat mutex and STARVES real decodes. Anchor warm on Fiat ePER + Dialogys
(the two windows that serve both brands; the Rpartstore-down cooldown routes
Renault to Dialogys anyway, so Rpartstore is an optional bonus). Warm is then
claimed once and HELD (no re-warm loop → no starvation); the Поиск-token foreground
fix makes warm Fiat raise the correct window. Rpartstore rejoins on recovery.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 13:42:31 +03:00
parent aa798ec03d
commit dac0708cda

View File

@@ -521,18 +521,20 @@ export class VinpinDriverService implements OnModuleDestroy {
// and re-binds by probing, so this is only a fast-path hint).
await this.bindTaskbarCoords(page);
if (!(fiatUp && okR && okD)) {
// Require the FULL warm session (all three catalog windows). A PARTIAL
// session — e.g. Rpartstore DOWN so only Fiat + Dialogys open — is proven
// UNSTABLE: the missing window's launch-error modal + the re-warm cycles
// keep knocking the Fiat window off its VIN panel, so warm Fiat decodes
// thrash to the budget. When we can't fully warm, DON'T claim warm — the
// reliable cold per-decode path serves every brand (Fiat ePER + Renault
// Rpartstore/Dialogys, all proven). The daemon backs off and retries, so
// warm resumes automatically once Rpartstore recovers. Clean the seat (log
// out) first so the next attempt isn't sabotaged by this one's dirty desktop.
// Claim warm when the two catalogs needed to serve BOTH brands are up: Fiat
// ePER (all Fiat decodes) AND Dialogys (the reliable Renault catalog — the
// Rpartstore-DOWN cooldown already routes Renault straight to Dialogys, so
// Rpartstore is an optional bonus window, not a warm requirement). Requiring
// ALL THREE would never warm during a (prolonged) Rpartstore outage, and the
// daemon would then re-attempt warm-up every backoff cycle — each ~2min
// attempt holds the single-seat mutex and STARVES real decodes. With Fiat +
// Dialogys as the anchor, warm is claimed once and HELD (no re-warm loop, no
// starvation), and the Fiat-foreground fix (dropped the Dialogys-shared Поиск
// token) means warm Fiat raises the correct window. Rpartstore joins the warm
// session automatically once it recovers.
if (!(fiatUp && okD)) {
this.logger.warn(
`warm-up incomplete (fiat=${fiatUp}, rpartstore=${okR}, dialogys=${okD}) — not claiming warm; cold path stays in effect until all three open`,
`warm-up incomplete (fiat=${fiatUp}, rpartstore=${okR}, dialogys=${okD}) — need Fiat+Dialogys; not claiming warm, cold path stays in effect`,
);
await this.cleanTeardown();
await this.close();