Skip to content
Merged
Show file tree
Hide file tree
Changes from 67 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
fdc3f30
feat(charging): overlay Tesla bills, fix energy baseline
atulmgupta Sep 7, 2026
6337833
Fix FSD trip meter glitch attribution
atulmgupta Sep 7, 2026
d0148d2
Add Grok dynamics briefing
atulmgupta Sep 7, 2026
3819d38
Add telemetry honesty insights
atulmgupta Sep 7, 2026
21ef53b
feat(driving): scope dynamics history by trip
atulmgupta Sep 8, 2026
1d67c53
fix(charging): correct history attribution
atulmgupta Sep 8, 2026
2b7a9d3
Fix sparse FSD drive detail attribution
atulmgupta Sep 8, 2026
da1e97d
Scope FSD insights to drive detail
atulmgupta Sep 10, 2026
d813d23
feat: add charging autopilot, OCPP, TCO ledger, and session insights
atulmgupta Sep 11, 2026
d30c301
Merge branch 'main' into muse-spark
atulmgupta Sep 11, 2026
8969c19
feat(charging): add charge autopilot
atulmgupta Sep 11, 2026
9095819
feat: expand charging and automation insights
atulmgupta Sep 11, 2026
49a0b3d
Expand automation and alert templates
atulmgupta Sep 11, 2026
e69c239
feat: storm guardian severe-weather auto-prep
atulmgupta Sep 11, 2026
cacdf6c
feat: cabin comfort autopilot with calendar-aware preconditioning
atulmgupta Sep 11, 2026
728760e
feat: warranty claim autopilot drafts service tickets
atulmgupta Sep 11, 2026
3a281be
feat: ghost-driver alerting for unknown-driver drives
atulmgupta Sep 11, 2026
7a581f3
feat: supercharger wait-time oracle from fleet history
atulmgupta Sep 11, 2026
3f050b0
fix(fsd): accept quantized FSD mileage ticks
atulmgupta Sep 12, 2026
583e034
fix: align wait-oracle, ghost, claim, comfort, storm with conventions
atulmgupta Sep 12, 2026
9af0f7e
feat(journey): trip sessions with status machine and versioned plans
atulmgupta Sep 12, 2026
6e5f05e
docs: redesign site and add feature catalogue
atulmgupta Sep 13, 2026
0db770f
fix(journey): clamp limits and localize status
atulmgupta Sep 13, 2026
2fa2af4
feat(i18n): add journey status labels
atulmgupta Sep 13, 2026
2bd335d
test(trips): align journey panel i18n
atulmgupta Sep 13, 2026
f3e59b7
merge origin/main into muse-spark
atulmgupta Sep 13, 2026
55386fe
refactor: tighten package boundaries
atulmgupta Sep 13, 2026
6dc2572
chore: document packages and update grpc
atulmgupta Sep 13, 2026
62e3abb
fix(ci): empty-state audit exemptions and Gitleaks policy fixture mount
atulmgupta Sep 13, 2026
4bc6c48
fix(ci): arch ratchet, chart-legend, CodeQL node, visual snapshots
atulmgupta Sep 13, 2026
34989da
fix(ci): restore CodeQL SHA pin and run SI gate on ubuntu-latest
atulmgupta Sep 13, 2026
a3adeb6
fix(ci): run SI canonical gate on push so the required workflow has jobs
atulmgupta Sep 13, 2026
e453ff6
fix(web): classify new mutation hooks for live-mode audit
atulmgupta Sep 13, 2026
17dd48c
fix(web): waive FSD observatory pagination in virtualization audit
atulmgupta Sep 13, 2026
88080af
fix(web): unblock frontend vitest QueryClient, breadcrumbs, and panel…
atulmgupta Sep 13, 2026
3796b0c
fix(web): show warranty claim draft when query data is present
atulmgupta Sep 13, 2026
00cc79c
fix(web): restore i18n provider and annotation hook tests under globa…
atulmgupta Sep 13, 2026
1c9dcd0
fix(web): unblock remaining frontend vitest failures
atulmgupta Sep 13, 2026
2c2ecb7
fix(ci): stop si-canonical-gate 0s push failures
atulmgupta Sep 13, 2026
6c6c050
fix(ci): run si-canonical-gate on push with a valid runner
atulmgupta Sep 13, 2026
cd43848
fix(ci): always run si-canonical-gate on push and PR
atulmgupta Sep 13, 2026
9be0a3b
fix(ci): move SI canonical gate Python out of invalid YAML
atulmgupta Sep 13, 2026
2f47434
fix(ci): repair span-budget, proto-gen, and load-test gates
atulmgupta Sep 13, 2026
3a147b8
fix(ci): run k6 on host network so load-test reaches the API
atulmgupta Sep 14, 2026
4b94ebc
fix(ci): treat 4xx as smoke-ok and write k6 summary in script cwd
atulmgupta Sep 14, 2026
272f432
fix(ci): persist k6 summary.json with host uid on bind mount
atulmgupta Sep 14, 2026
c8ac9b1
Merge branch 'main' into muse-spark
atulmgupta Sep 14, 2026
727d8ed
feat(journey): stop scoring on wait, price, health, corridor
atulmgupta Sep 14, 2026
b481cd6
feat(journey): departure advisor and ready-to-roll checklist
atulmgupta Sep 14, 2026
5e159fa
feat(journey): live trip session with trail checkpoints and glanceabl…
atulmgupta Sep 14, 2026
d9cec25
feat(journey): replan engine with deviation verdict and one-click res…
atulmgupta Sep 14, 2026
b4e1a21
feat(journey): arrival prep with pace ETA and destination charge advice
atulmgupta Sep 14, 2026
79c6e96
feat(journey): trip report card debrief
atulmgupta Sep 14, 2026
eb134ed
feat(journey): leave-now nudge from calm slots and blockers
atulmgupta Sep 14, 2026
e5d5337
feat(journey): route learning adjusts ETA and debrief
atulmgupta Sep 14, 2026
a22e294
feat(journey): offline check-in outbox with reconnect replay
atulmgupta Sep 14, 2026
ddb08bd
refactor(trips): remove obsolete journey strings
atulmgupta Sep 14, 2026
a317612
Merge branch 'main' into muse-spark
atulmgupta Sep 14, 2026
eb55402
fix(journey): SI identifiers and ops migration manifest
atulmgupta Sep 14, 2026
dc3a07a
fix(web): exempt journey EmptyStates from CTA audit
atulmgupta Sep 14, 2026
732ad19
fix(web): give journey empty states real CTAs
atulmgupta Sep 14, 2026
8f4ce57
fix(web): narrow checklist run before rendering items
atulmgupta Sep 14, 2026
966cff1
fix(web): classify journey mutations for live-mode audit
atulmgupta Sep 14, 2026
36f8072
fix(web): align DeparturePanel tests with render and hook args
atulmgupta Sep 14, 2026
c7b600d
Merge branch 'main' into muse-spark
atulmgupta Sep 15, 2026
fd449dd
feat(telemetry): add Fleet fields 260-269
atulmgupta Sep 15, 2026
05c2306
fix(ci): allow Tesla proto wire names and race-test on ubuntu
atulmgupta Sep 15, 2026
90b14ae
fix(ci): bump signal_log route count and wait for map container
atulmgupta Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/scripts/si_canonical_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@
"web/src/hooks/useSettings.test.ts",
}

# Tesla Fleet Telemetry Field enum identifiers are upstream-owned (ADR-004 R2).
# Wire names may contain Kwh/Mph even though TeslaSync stores SI (Wh, m/s).
TESLA_PROTO_FIELD_ALLOWLIST = (
"NominalFullPackEnergyKwh",
"LifetimeEnergyChargedKwh",
"MaxSpeedToReachDestinationMph",
"SemiCruiseSpeedLimitMph",
"ChargeRateMilePerHour",
)


def iter_added_lines(diff_text: str):
current_file = None
Expand Down Expand Up @@ -77,6 +87,8 @@ def check_go(diff_text: str) -> list[str]:
s = added.lstrip()
if s.startswith("//") or s.startswith("#") or s.startswith("--"):
continue
if any(name in added for name in TESLA_PROTO_FIELD_ALLOWLIST):
continue
Comment on lines +90 to +91
for pat in BANNED:
if pat.search(added):
violations.append(f"{current_file}: {added.rstrip()}")
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/codec-coverage-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ permissions:
jobs:
routing-coverage:
name: TestRoutingCoverage (every proto field is routed)
runs-on: ${{ inputs.runner || 'arc-runner' }}
# ubuntu-latest: `go test -race` needs CGO/gcc. arc-runner does not ship gcc
# (same pin as CI "Backend (lint + test + build)").
runs-on: ${{ github.event_name == 'workflow_dispatch' && inputs.runner || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 1 addition & 1 deletion api/proto/tesla/CHECKSUM
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4596EBA1D26B72EB69BBF747831BF0EB2EEC106A54048D9BC7D6DE765446697C
E8BE013478FC24DADE3B40DF10A269E6477D27FABB95C641A575A5214A101618
16 changes: 8 additions & 8 deletions api/proto/tesla/SOURCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ rationale.
|---|---|
| Upstream repository | `github.com/teslamotors/fleet-telemetry` |
| Upstream path | `protos/vehicle_data.proto` |
| Upstream tag | **v0.8.0** |
| Upstream commit | `031553a7d3d6952c1552ed13dc71aaf4fd4a882b` |
| Upstream commit date | 2025-12-12 |
| Upstream raw URL | <https://raw.githubusercontent.com/teslamotors/fleet-telemetry/031553a7d3d6952c1552ed13dc71aaf4fd4a882b/protos/vehicle_data.proto> |
| Upstream tree URL | <https://github.com/teslamotors/fleet-telemetry/blob/v0.8.0/protos/vehicle_data.proto> |
| File size | 21,291 bytes |
| SHA256 | `4596EBA1D26B72EB69BBF747831BF0EB2EEC106A54048D9BC7D6DE765446697C` |
| Fetched on | 2026-05-01 |
| Upstream tag | untagged (`Add new streamable fields 260-269`, #546) |
| Upstream commit | `8fbaa100bd365936dab6ecbf0e2d7070c4d765cb` |
| Upstream commit date | 2026-09-14 |
| Upstream raw URL | <https://raw.githubusercontent.com/teslamotors/fleet-telemetry/8fbaa100bd365936dab6ecbf0e2d7070c4d765cb/protos/vehicle_data.proto> |
| Upstream tree URL | <https://github.com/teslamotors/fleet-telemetry/blob/8fbaa100bd365936dab6ecbf0e2d7070c4d765cb/protos/vehicle_data.proto> |
| File size | 21,729 bytes |
| SHA256 | `E8BE013478FC24DADE3B40DF10A269E6477D27FABB95C641A575A5214A101618` |
| Fetched on | 2026-09-14 |
| Vendored by | phase-42 prompt 0010 |
| Reviewed by | Staff Engineer + Principal Engineer + Principal Architect (per ADR-004) |

Expand Down
6 changes: 3 additions & 3 deletions api/proto/tesla/VERSION
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
teslamotors/fleet-telemetry@v0.8.0
commit=031553a7d3d6952c1552ed13dc71aaf4fd4a882b
fetched=2026-05-01
teslamotors/fleet-telemetry@8fbaa100bd365936dab6ecbf0e2d7070c4d765cb
commit=8fbaa100bd365936dab6ecbf0e2d7070c4d765cb
fetched=2026-09-14
13 changes: 13 additions & 0 deletions api/proto/tesla/vehicle_data.proto
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,19 @@ enum Field {

MilesSinceReset = 258;
SelfDrivingMilesSinceReset = 259;

// fields 260-269 are first available in firmware version 2026.32 (device client version 1.3.0)

GpsAccuracyMeters = 260;
LifetimeEnergyChargedKwh = 261;
BrickSocMinPercent = 262;
NominalFullPackEnergyKwh = 263;
GradeEstimatePercent = 264;
MaxSpeedToReachDestinationMph = 265;
SoftwareUpdateAvailable = 266;
SoftwareUpdateInProgress = 267;
RemoteStartActive = 268;
SemiCruiseSpeedLimitMph = 269; // Semi-truck only
}

// ChargingState is deprecated and not used
Expand Down
23 changes: 23 additions & 0 deletions cmd/protogen-tesla/emit.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,29 @@ func classifyExplicit(name string) fieldClass {
return fieldClass{cat: "safety_security", kind: "float", unit: "distance", isSettingUnit: false}
case "SelfDrivingMilesSinceReset":
return fieldClass{cat: "safety_security", kind: "float", unit: "distance", isSettingUnit: false}
case "GpsAccuracyMeters":
// Wire unit is already metres (name-encoded). Do not treat as
// SettingDistanceUnit-following distance — ToSI would re-scale.
return fieldClass{cat: "location", kind: "float", unit: "none", isSettingUnit: false}
case "LifetimeEnergyChargedKwh":
return fieldClass{cat: "charging", kind: "float", unit: "none", isSettingUnit: false}
case "BrickSocMinPercent":
return fieldClass{cat: "charging", kind: "float", unit: "charge", isSettingUnit: false}
case "NominalFullPackEnergyKwh":
return fieldClass{cat: "charging", kind: "float", unit: "none", isSettingUnit: false}
case "GradeEstimatePercent":
return fieldClass{cat: "driving", kind: "float", unit: "none", isSettingUnit: false}
case "MaxSpeedToReachDestinationMph":
// Name-encoded mph; converted to m/s via fixedMphSpeedFields.
return fieldClass{cat: "driving", kind: "float", unit: "none", isSettingUnit: false}
case "SoftwareUpdateAvailable":
return fieldClass{cat: "vehicle_state", kind: "bool", unit: "none", isSettingUnit: false}
case "SoftwareUpdateInProgress":
return fieldClass{cat: "vehicle_state", kind: "bool", unit: "none", isSettingUnit: false}
case "RemoteStartActive":
return fieldClass{cat: "vehicle_state", kind: "bool", unit: "none", isSettingUnit: false}
case "SemiCruiseSpeedLimitMph":
return fieldClass{cat: "driving", kind: "float", unit: "none", isSettingUnit: false}
}
return fieldClass{}
}
Expand Down
5 changes: 3 additions & 2 deletions internal/tesla/normalize/normalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ func (p *Pipeline) toSI(ctx context.Context, atomic codec.Atomic, vehicleIntID i
// kWh/kW. Neither family may be dropped because a vehicle has no
// unit_history row.
if units.IsFixedMileDistanceField(atomic.Field) ||
units.IsFixedKiloToBaseField(atomic.Field) {
units.IsFixedKiloToBaseField(atomic.Field) ||
units.IsFixedMphSpeedField(atomic.Field) {
raw, ok := coerceFloat(atomic.Value)
if !ok {
return codec.Atomic{}, fmt.Errorf("%w: %s value of type %T not coercible to float64", units.ErrUnsupportedField, atomic.Field, atomic.Value)
Expand Down Expand Up @@ -218,7 +219,7 @@ func (p *Pipeline) toSI(ctx context.Context, atomic codec.Atomic, vehicleIntID i
// them. The SettingChargeUnit signal is recorded for UI display
// preference only.
func needsConversion(field string, meta *protomodel.SignalMeta) bool {
if isSpeedField(field) || units.IsFixedKiloToBaseField(field) {
if isSpeedField(field) || units.IsFixedKiloToBaseField(field) || units.IsFixedMphSpeedField(field) {
return true
}
if meta == nil {
Expand Down
33 changes: 33 additions & 0 deletions internal/tesla/protomodel/coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,39 @@ func TestCoverage_SettingUnitInvariants(t *testing.T) {
// (e.g. a temperature reading) gets misclassified into a non-measurement
// bucket and then gets silently dropped by the unit-history /
// unit-conversion layer, which only iterates measurement-bucket fields.
// TestCoverage_FleetTelemetryFields260to269 pins the firmware-2026.32 Field
// enum values (teslamotors/fleet-telemetry@8fbaa100) on the vendored generator
// output. The teslamotors Go module is still v0.9.0 (Go 1.25), so
// TestCoverage_EveryProtoFieldHasSignalMeta cannot see these names via
// ftproto.Field_name until that module pin moves.
Comment on lines +166 to +170
func TestCoverage_FleetTelemetryFields260to269(t *testing.T) {
want := []struct {
num int32
name string
}{
{260, "GpsAccuracyMeters"},
{261, "LifetimeEnergyChargedKwh"},
{262, "BrickSocMinPercent"},
{263, "NominalFullPackEnergyKwh"},
{264, "GradeEstimatePercent"},
{265, "MaxSpeedToReachDestinationMph"},
{266, "SoftwareUpdateAvailable"},
{267, "SoftwareUpdateInProgress"},
{268, "RemoteStartActive"},
{269, "SemiCruiseSpeedLimitMph"},
}
for _, w := range want {
meta, ok := SignalsByEnum[w.num]
if !ok {
t.Errorf("SignalsByEnum missing enum=%d (%s); re-vendor proto and run go generate", w.num, w.name)
continue
}
if meta.Field != w.name {
t.Errorf("SignalsByEnum[%d].Field=%q want %q", w.num, meta.Field, w.name)
}
}
}

func TestCoverage_UnitBearingFieldsAreMeasurements(t *testing.T) {
denied := sortedKeys(nonMeasurementCategories)

Expand Down
60 changes: 60 additions & 0 deletions internal/tesla/protomodel/signal_metadata_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions internal/tesla/router/routing.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ routes:
dest: signal_log
- field: BrickVoltageMin
dest: signal_log
- field: BrickSocMinPercent
dest: signal_log
- field: CabinOverheatProtectionMode
dest: climate_snapshot
column: cabin_overheat_protection_mode
Expand Down Expand Up @@ -435,6 +437,8 @@ routes:
- field: Gear
dest: drive_telemetry
column: gear
- field: GpsAccuracyMeters
dest: signal_log
- field: GpsHeading
dest: positions
column: heading_deg
Expand Down Expand Up @@ -506,6 +510,10 @@ routes:
- field: LateralAcceleration
dest: drive_telemetry
column: lateral_acceleration_mps2
- field: GradeEstimatePercent
dest: signal_log
- field: LifetimeEnergyChargedKwh
dest: signal_log
- field: LifetimeEnergyGainedRegen
dest: drive_telemetry
column: lifetime_energy_gained_regen_wh
Expand Down Expand Up @@ -602,6 +610,8 @@ routes:
# to meters before the SI value lands in signal_log.
- field: MilesSinceReset
dest: signal_log
- field: MaxSpeedToReachDestinationMph
dest: signal_log
- field: MilesToArrival
dest: signal_log
- field: MinutesToArrival
Expand All @@ -610,6 +620,8 @@ routes:
dest: signal_log
- field: ModuleTempMin
dest: signal_log
- field: NominalFullPackEnergyKwh
dest: signal_log
- field: NotEnoughPowerToHeat
dest: signal_log
- field: NumBrickVoltageMax
Expand Down Expand Up @@ -706,6 +718,8 @@ routes:
# per-vehicle feature flag, and RoofColor is paint trim. Each
# carries the change feed in signal_log; downstream readers fetch
# the most recent value back from there. No hot column exists.
- field: RemoteStartActive
dest: signal_log
- field: RemoteStartEnabled
dest: signal_log
- field: RightHandDrive
Expand Down Expand Up @@ -754,6 +768,8 @@ routes:
# UnitKindDistance). Same routing rationale as MilesSinceReset —
# the wire value is fixed in miles, normalize.toSI bypasses
# vehicle_unit_history, and the SI value lands in signal_log.
- field: SemiCruiseSpeedLimitMph
dest: signal_log
- field: SelfDrivingMilesSinceReset
dest: signal_log
- field: SemitruckPassengerSeatFoldPosition
Expand Down Expand Up @@ -840,10 +856,14 @@ routes:
dest: signal_log
# SoftwareUpdate* atomics (vehicle_state). Update-progress UI feeds
# off the signal_log change stream; no hot column exists.
- field: SoftwareUpdateAvailable
dest: signal_log
- field: SoftwareUpdateDownloadPercentComplete
dest: signal_log
- field: SoftwareUpdateExpectedDurationMinutes
dest: signal_log
- field: SoftwareUpdateInProgress
dest: signal_log
- field: SoftwareUpdateInstallationPercentComplete
dest: signal_log
- field: SoftwareUpdateScheduledStartTime
Expand Down
24 changes: 20 additions & 4 deletions internal/tesla/units/conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,30 @@ func IsFixedMileDistanceField(field string) bool {
// AC/DCChargingEnergyIn in kWh and AC/DCChargingPower in kW:
// https://developer.tesla.com/docs/fleet-api/fleet-telemetry/available-data
var fixedKiloToBaseFields = map[string]bool{
"ACChargingEnergyIn": true,
"DCChargingEnergyIn": true,
"ACChargingPower": true,
"DCChargingPower": true,
"ACChargingEnergyIn": true,
"DCChargingEnergyIn": true,
"ACChargingPower": true,
"DCChargingPower": true,
"LifetimeEnergyChargedKwh": true,
"NominalFullPackEnergyKwh": true,
}

// IsFixedKiloToBaseField reports whether a Tesla field has a fixed kWh/kW
// wire unit that must be converted to Wh/W without consulting unit history.
func IsFixedKiloToBaseField(field string) bool {
return fixedKiloToBaseFields[field]
}

// fixedMphSpeedFields lists linear-velocity proto fields whose wire
// value is ALWAYS miles per hour (name-encoded), independent of
// SettingDistanceUnit. Canonical SI is metres per second.
var fixedMphSpeedFields = map[string]bool{
"MaxSpeedToReachDestinationMph": true,
"SemiCruiseSpeedLimitMph": true,
}

// IsFixedMphSpeedField reports whether a Tesla speed field is always
// mph on the wire and must convert to m/s without unit history.
func IsFixedMphSpeedField(field string) bool {
return fixedMphSpeedFields[field]
}
4 changes: 4 additions & 0 deletions internal/tesla/units/units.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ func ToSI(field string, raw float64, active ActiveUnit) (float64, error) {
return raw * 1000.0, nil
}

if IsFixedMphSpeedField(field) {
return raw * 0.44704, nil
}

if meta.UnitKind == protomodel.UnitKindNone {
return 0, fmt.Errorf("%w: %q", ErrUnsupportedField, field)
}
Expand Down
Loading
Loading