[1.2.5] - 2026-08-04
中文
正确性 + 性能补丁版本 —— 0 项数据库改动。本版本修复 7 个 HIGH 严重度 Bug(数据错误、单位错算、跨日时区漂移、并发死锁等),并完成 6 项性能优化(异步化、并行、缓存、连接复用、写盘去抖)。共修改 ~352 行代码 + 新增 ~334 行测试代码,所有改动均为只读 SELECT 查询优化或 Python 逻辑改进,可直接 git pull 升级,无需迁移或停机。
🐛 Bug 修复(7 项)
数据正确性(7 项)
- BUG-A
tesla_live速度单位错算:TeslaMatepositions.speed存的就是 km/h,但代码当作 m/s 处理 —— 100 km/h 真实速度被报告成 360 km/h(3.6 倍虚高)。已改为直接使用 km/h 值,imperial 走0.621371换算。 - BUG-B
NULL续航产生虚假能耗:多工具的(start_ideal_range_km - end_ideal_range_km) * kwh_per_km计算中,只要任一端为 NULL,Pythonor 0把缺失当作 0,产出(400-0)*0.15 = 60 kWh之类的巨型虚假能耗。10 处 SQL 聚合已加IS NOT NULL谓词 +FILTER子句,tesla_drives循环已改用is None跳过缺失行。 - BUG-C
end_date跨 DST 边界错位:9 个工具用parse_date(end) + timedelta(days=1)构造排他右边界,在 DST 春令时(23h 日)多算 1h、秋令时(25h 日)少算 1h。新增_next_local_day()helper,改用"下一个本地日历日"再_parse_date,对所有时区 DST 安全。 - BUG-D 月度吸血鬼误判长驾驶为停车耗电:
_monthly_report_compute/tesla_monthly_summary的eventsCTE 丢失kind字段,导致一次 10h 长驾驶的drive_start → drive_end配对被错误归入 vampire(20% 电量差算成停车耗电)。已加kind='drive_end' AND next_kind IN ('drive_start','charge_start')过滤,并把硬编的 8h/168h 阈值改为%s参数,统一与VAMPIRE_MIN_HOURS/VAMPIRE_MAX_HOURS对齐。 - BUG-E
get_vehicle_persona_status忽略year/month截止:工具计算了 start 和 end,但所有 SQL 只用start_date >= cutoff,end 边界从未传进去。请求 2025 年 1 月实际返回 1 月至今所有数据,idle_percentage分母与分子口径不一致。已为 3 处查询加FILTER ... AND start_date < end_boundary,state 区间按[start, end]裁剪。 - BUG-F
tesla_location_history报"跨度"而非"累计停留":SQL 用MAX(date) - MIN(date)计算span_hours,周一停 1h + 周五停 1h → 报告 120h。已改用LAG()+ 同聚类内SUM(stay_seconds),跨聚类 / 间隔 > 30 分钟的采样正确排除。 - BUG-G
_cached_result不是 cancellation-safe:leader 任务被取消时CancelledError不被except Exception捕获,共享 future 永远 pending,follower 死锁;follower 取消时await传播取消到共享 future,后续set_result抛InvalidStateError。已改except BaseException+ follower 走asyncio.shield(inflight),set 前检查done()。
⚡ 性能优化(6 项)
- OPT-1
_savings_compute._merge异步化:嵌套 sync 函数调_query_one阻塞事件循环,statement_timeout=30s 触发时整个 MCP 服务器冻结 30 秒。已改为async def _merge+_query_one_async,无事件循环阻塞。 - OPT-2
TESLA_DB_MAXCONNenv 真正生效:之前硬编maxconn=8,但错误消息引导运维提高TESLA_DB_MAXCONN,实际无效。已读取 env(maxconn/minconn均支持),启动日志输出实际值。 - OPT-3 13 个昂贵工具加缓存:
tesla_vampire_drain/tesla_driving_score/tesla_location_history/tesla_state_history/tesla_tpms_history/tesla_monthly_driving_report(24h 历史 / 5min 当月)/tesla_driving_score/check_driving_achievements/check_daily_quest/get_driver_profile/get_charging_vintage_data/generate_weekend_blindbox/generate_travel_narrative_context/get_longest_trip_on_single_charge/calculate_eco_savings_vs_icev全部包装_cached_result(_vkey(...), ttl=...),LLM agent 重试 / 后续问题时不再重复全表扫。 - OPT-12 QWeather
asyncio.gather并行:tesla_vampire_drain5 个停车点 +tesla_efficiency_by_weather60 个采样 × 2 调用,均从串行改为并行。实测加速 5x(serial 0.51s → parallel 0.10s),最坏情况 5×8s=40s 串行 → ~8s 并行。 - OPT-13
httpx.AsyncClient模块级单例:5 个调用点(AMAP / QWeather ×3 / Nominatim)每次都新建 client → 50-200ms TCP/TLS 握手。已抽_get_http_client(),atexit 时aclose()。每次 QWeather 调用省 ~100ms。 - OPT-14 geocode cache 紧凑 JSON + 去抖:每次 miss 全文件重写 +
indent=2(150KB 在锁内串行执行)→ 改separators=(",", ":")(~40% 小)+threading.Timer去抖 1s 合并。20 个目的地 trip 计划从 3MB 写 + 150ms×20 等待,降到 30KB + 一次写。atexit安全网保证未刷盘数据不丢失。
测试
- 新增
test_bugfixes.py(334 行,无需 fastmcp/DB 即可运行):覆盖 7 个 bug 的核心逻辑 + 6 个优化的结构与行为断言,14/14 测试组全部通过(36 个独立断言)。 - 现有
test_all.py仍 100% 兼容,继续覆盖 80+ smoke 测试。
配置
- 新增
TESLA_DB_MAXCONN(默认 8) +TESLA_DB_MINCONN(默认 2),实际生效。 TESLA_GEOCODE_CACHE_DEBOUNCE_SEC默认 1.0s(可调)。- 全部向后兼容,默认值与历史行为一致。
备注
- 数据库访问仍然 100% 只读。46 个 SQL 查询全部为
SELECT/WITH...SELECT,0 处 INSERT/UPDATE/DELETE/TRUNCATE/CREATE/ALTER/DROP/commit/rollback,cur.execute仅 2 处(_queryL815 /_query_oneL845),后接fetchall()/fetchone()。 - 所有 7 个 bug 修复均为只读 SELECT 查询文本优化或 Python 逻辑改进,部署无需任何 schema 迁移或权限变更,直接替换
tesla.py即可生效。
English
Correctness + performance patch release — 0 database changes. Fixes 7 HIGH-severity bugs (data errors, unit mistakes, DST drift, cancellation deadlock, etc.) and lands 6 performance optimizations (async, parallel, cache, client reuse, debounced writes). ~352 lines modified + ~334 lines of tests added; every change is a read-only SELECT text optimization or Python logic improvement — deployable via git pull with no migration or downtime.
🐛 Bug fixes (7)
Data correctness (7)
- BUG-A
tesla_livespeed unit wrong: TeslaMatepositions.speedis km/h, but the code treated it as m/s — 100 km/h was reported as 360 km/h (3.6× inflation). Now uses km/h directly; imperial goes through0.621371. - BUG-B
NULLrange endpoints produced fake energy: Multiple tools computed(start - end) * kwh_per_kmwithor 0coercion — if either endpoint was NULL, the missing side was treated as 0, producing e.g.(400-0)*0.15 = 60 kWhof phantom energy. AddedIS NOT NULLpredicates +FILTERclauses to 10 SQL aggregates;tesla_drivesPython loop now usesis Noneto skip incomplete rows. - BUG-C
end_dateDST drift: 9 tools built the exclusive end boundary asparse_date(end) + timedelta(days=1), which over-counts 1h on spring-forward (23h) days and under-counts 1h on fall-back (25h) days. New_next_local_day()helper computes the next local calendar date then re-parses — DST-safe for all zones. - BUG-D Monthly vampire misclassified long drives as parked drain:
_monthly_report_compute/tesla_monthly_summarylost thekindcolumn from theeventsCTE, so a 10h drive_end → drive_start pair (with 20% battery drop) was tallied as vampire drain. Addedkind='drive_end' AND next_kind IN ('drive_start','charge_start')filter; hardcoded 8h/168h thresholds replaced with%sparams bound toVAMPIRE_MIN_HOURS/VAMPIRE_MAX_HOURS. - BUG-E
get_vehicle_persona_statusignoredyear/monthend: The tool computedstartandend, but every SQL only usedstart_date >= cutoff— the end boundary was never passed. Queryingyear=2025, month=1returned everything from January through "now". AddedFILTER ... AND start_date < end_boundaryto all 3 queries; state intervals clipped to[start, end]. - BUG-F
tesla_location_historyreported span, not cumulative stay: SQL usedMAX(date) - MIN(date)forspan_hours— Monday 1h + Friday 1h reported as ~120h. Replaced withLAG()+ intra-clusterSUM(stay_seconds). Cross-cluster transitions and >30min gaps correctly excluded. - BUG-G
_cached_resultwas not cancellation-safe: Leader task cancellation (aBaseException) wasn't caught byexcept Exception, leaving the shared future pending forever → follower deadlock. Follower cancellation propagated to the shared future → leader'sset_resultraisedInvalidStateError. Now usesexcept BaseException, follower wraps inasyncio.shield(inflight), andset_*checksdone()first.
⚡ Performance optimizations (6)
- OPT-1
_savings_compute._mergeasync: Nested sync function called_query_oneblocking the event loop; a 30sstatement_timeoutfroze the entire MCP server. Nowasync def _merge+_query_one_async— no event-loop block. - OPT-2
TESLA_DB_MAXCONNenv actually works: Hardcodedmaxconn=8misled operators (the error message even told them to raiseTESLA_DB_MAXCONN). Now reads env (maxconn+minconnboth supported); startup log shows actual values. - OPT-3 13 expensive tools cached:
tesla_vampire_drain/tesla_driving_score/tesla_location_history/tesla_state_history/tesla_tpms_history/generate_monthly_driving_report(24h historical / 5min current month) /check_driving_achievements/check_daily_quest/get_driver_profile/get_charging_vintage_data/generate_weekend_blindbox/generate_travel_narrative_context/get_longest_trip_on_single_charge/calculate_eco_savings_vs_icevall wrapped in_cached_result(_vkey(...), ttl=...). LLM agent retries / follow-ups no longer re-scan full tables. - OPT-12 QWeather
asyncio.gatherparallel: 5 parking spots intesla_vampire_drain+ 60 samples × 2 calls intesla_efficiency_by_weather— both moved from serial to parallel. Measured 5× speedup (serial 0.51s → parallel 0.10s); worst case 5×8s = 40s serial → ~8s parallel. - OPT-13
httpx.AsyncClientmodule-level singleton: 5 call sites (AMAP / QWeather ×3 / Nominatim) each rebuilt a client → 50-200ms TCP/TLS handshake per call. Extracted_get_http_client(),aclose()onatexit. Saves ~100ms per QWeather call. - OPT-14 geocode cache compact JSON + debounced writes: Every miss rewrote the entire 150KB JSON with
indent=2under the cache lock. Nowseparators=(",", ":")(~40% smaller) +threading.Timer1s debounce coalescing bursts. 20-destination trip planning: 3MB writes + 150ms×20 wait → 30KB + one write.atexitsafety net guarantees no pending writes are lost.
Testing
- New
test_bugfixes.py(334 lines, runs without fastmcp/DB): covers the core logic of all 7 bugs + structural and behavioural assertions for all 6 optimizations. 14/14 test groups pass (36 individual assertions). - Existing
test_all.pyremains 100% compatible, still covering 80+ smoke tests.
Configuration
- New
TESLA_DB_MAXCONN(default 8) +TESLA_DB_MINCONN(default 2), both effective. TESLA_GEOCODE_CACHE_DEBOUNCE_SECdefault 1.0s (tunable).- All backward compatible — defaults preserve historical behaviour.
Notes
- Database access remains 100% read-only. All 46 SQL queries are
SELECT/WITH...SELECT; 0INSERT/UPDATE/DELETE/TRUNCATE/CREATE/ALTER/DROP/commit/rollback.cur.executeonly fires from 2 sites (_queryL815 /_query_oneL845), both followed byfetchall()/fetchone(). - All 7 bug fixes are read-only SELECT text optimizations or Python logic improvements — no schema migration, no permission changes needed. Drop in the new
tesla.pyand you're done.