fix: seed a vehicle discovered mid-dispatch from its triggering config event - #30
fix: seed a vehicle discovered mid-dispatch from its triggering config event#30Bre77 wants to merge 2 commits into
Conversation
A generic listener that discovers an uncached VIN via get_vehicle()
while handling that VIN's config event registers a new internal
listener after listen() has already snapshotted the registry for the
current event. The new vehicle's config-sync listener then misses the
very event that revealed its config, leaving it at fields={}/
preferTyped=None until (if ever) a later config event arrives.
💡 Codex Reviewpython-teslemetry-stream/teslemetry_stream/vehicle.py Lines 325 to 328 in f1d43e1 After a reconnect, AGENTS.md reference: AGENTS.md:L21-L21 ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Superseded by #32 - a simpler fix (populated flag + lazy fetch, no second dispatch pass) per captain direction. Closing. |
… fetch (#32) add_field/prefer_typed no longer gate their no-op skip on connection/topic state (_record_is_live). Instead, TeslemetryStreamVehicle tracks whether its record has ever been populated (by a push event or a REST fetch); an unpopulated vehicle awaits a single-flight get_config() before deciding, a populated one trusts the optimistically-updated record outright. A disconnect notification unpopulates the record so a call landing in the reconnect window (before the next connection's config snapshot arrives) refetches instead of trusting stale pre-disconnect data. This replaces the mechanisms proposed in #30 (a second dispatch pass for listeners added mid-event) and #31 (per-connection snapshot tracking) with a smaller, self-contained fix scoped to the vehicle itself.
Intent
listen()dispatches each event over a sorted snapshot of_listeners.values()taken before iterating, so a callback that adds a listener mid-dispatch can't mutate the dict out from under the loop.get_vehicle()while handling that VIN's ownconfigevent registers a new internal config-sync listener that the current snapshot already passed by. It never sees the event that triggered its own creation, so the vehicle stays atfields={}/preferTyped=Noneuntil (if ever) a later config event arrives.tests/test_stream_lifecycle.pyadds a regression test reproducing the race (fails without the fix) and asserting the newly discovered vehicle'sfields/preferTypedcome from the triggering event.