feat: move positional status to channels - #669
Conversation
📝 WalkthroughWalkthroughThis PR adds the ChangesTrack-state snapshot pipeline
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (3)
src/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsx (1)
7-23: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTest the typed snapshot boundary directly.
These mocks derive typed snapshots from
useTelemetryValue. This keeps the
legacy telemetry interface in the test setup and can hide a regression back to
direct telemetry reads.
src/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsx#L7-L23: Return
independenttrack-stateanddriver-controlsfixture objects.src/frontend/components/PitlaneHelper/components/PitExitInputs.spec.tsx#L7-L16:
Return a direct driver-controls fixture and replace telemetry-call assertions
with snapshot-hook assertions.src/frontend/components/PitlaneHelper/hooks/usePitLimiterWarning.spec.tsx#L7-L19:
Return a direct track-state fixture for each hook state transition.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsx` around lines 7 - 23, Update the test mocks to exercise typed snapshot hooks directly: in src/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsx lines 7-23, return independent track-state and driver-controls fixtures; in src/frontend/components/PitlaneHelper/components/PitExitInputs.spec.tsx lines 7-16, return a direct driver-controls fixture and assert snapshot-hook calls instead of telemetry calls; in src/frontend/components/PitlaneHelper/hooks/usePitLimiterWarning.spec.tsx lines 7-19, return direct track-state fixtures for each hook state transition. Remove reliance on useTelemetryValue in these setup paths so regressions to direct telemetry reads are exposed.src/frontend/components/Standings/components/SessionBar/components/ClassRankItem/ClassRankItem.tsx (1)
11-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winSet a display name for
ClassRankItem.Add
ClassRankItem.displayName = 'ClassRankItem';after the memoized component declaration.As per coding guidelines, memoized components require a
displayName.Proposed fix
export const ClassRankItem = memo(({ standalone }: SessionBarItemProps) => { // ... }); + +ClassRankItem.displayName = 'ClassRankItem';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/frontend/components/Standings/components/SessionBar/components/ClassRankItem/ClassRankItem.tsx` at line 11, Set the display name on the memoized ClassRankItem component by adding ClassRankItem.displayName = 'ClassRankItem' immediately after its declaration.Source: Coding guidelines
src/frontend/context/shared/useFocusCarIdx.ts (1)
2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the configured context path alias.
Replace the relative
ChannelStoreimport with the@irdashies/contextalias.As per coding guidelines, use TypeScript path aliases for context imports.
Proposed fix
-import { useTrackStateSnapshot } from '../ChannelStore'; +import { useTrackStateSnapshot } from '`@irdashies/context`';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/frontend/context/shared/useFocusCarIdx.ts` at line 2, Update the import in useFocusCarIdx.ts to replace the relative ChannelStore path with the configured `@irdashies/context` alias, while preserving the existing useTrackStateSnapshot import.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.storybook/trackStateSnapshot.ts:
- Around line 3-27: Update the trackStateStorySnapshot fixture so focusCarIdx is
consistent with the empty carIdx* arrays: set focusCarIdx to null rather than 0,
preserving the existing empty-array fixture.
In `@docs/IMPLEMENTATION_PLAN.md`:
- Line 475: Correct the date on the PR `#669` activity-log entry to 2026-08-08 if
it documents the current PR opening; otherwise, move the entry after the
existing August 9, 2026 activity.
In `@src/app/processors/TrackStateProcessor.ts`:
- Around line 97-114: Run Prettier on the changed code: format the setter calls
in TrackStateProcessor.ts (lines 97-114), lifecycle callback registration in
trackStateRuntime.ts (lines 29-33), and test setup in
TrackStateProcessor.spec.ts (lines 45-48), preserving single quotes,
80-character lines, and ES5 trailing commas.
- Around line 82-86: Update the CarIdxOnPitRoad handling in TrackStateProcessor
to convert each SDK numeric flag to a boolean while copying into
latest.carIdxOnPitRoad, rather than relying on arrayValue<boolean>’s type
assertion. Add coverage verifying input [0, 1] is published as [false, true].
In `@src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx`:
- Line 27: Include useTrackStateSnapshot()?.version in the useMemo dependency
arrays for usePitboxPosition in
src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx:27-27 and
usePitlaneTraffic in
src/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsx:15-17, so
memoized pit calculations refresh for each track-state update even when the
reused arrays retain equal values.
In `@src/frontend/components/TrackMap/hooks/useDriverProgress.tsx`:
- Around line 17-18: Update the track-state flow used by useDriverProgress and
driversTrackData so carIdxLapDistPct is copied immutably and rounded to 3
decimals via useTelemetryValuesRounded. Ensure position-only updates produce a
new rounded driversLapDist reference, either by changing TrackStateProcessor or
by exposing a rounded selector that participates in snapshot memoization.
In `@src/frontend/context/PitLaneStore/usePitLaneDetection.tsx`:
- Around line 17-30: Update the pit transition detection flow in
usePitLaneDetection to trigger detectPitTransitions once for each new
trackState.version when carIdxOnPitRoad, carIdxTrackSurface, and
carIdxLapDistPct are all present. Remove the previous array-reference comparison
gate and track the last processed snapshot version instead, so reusable
projection buffers still produce detection updates.
---
Nitpick comments:
In `@src/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsx`:
- Around line 7-23: Update the test mocks to exercise typed snapshot hooks
directly: in src/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsx lines
7-23, return independent track-state and driver-controls fixtures; in
src/frontend/components/PitlaneHelper/components/PitExitInputs.spec.tsx lines
7-16, return a direct driver-controls fixture and assert snapshot-hook calls
instead of telemetry calls; in
src/frontend/components/PitlaneHelper/hooks/usePitLimiterWarning.spec.tsx lines
7-19, return direct track-state fixtures for each hook state transition. Remove
reliance on useTelemetryValue in these setup paths so regressions to direct
telemetry reads are exposed.
In
`@src/frontend/components/Standings/components/SessionBar/components/ClassRankItem/ClassRankItem.tsx`:
- Line 11: Set the display name on the memoized ClassRankItem component by
adding ClassRankItem.displayName = 'ClassRankItem' immediately after its
declaration.
In `@src/frontend/context/shared/useFocusCarIdx.ts`:
- Line 2: Update the import in useFocusCarIdx.ts to replace the relative
ChannelStore path with the configured `@irdashies/context` alias, while preserving
the existing useTrackStateSnapshot import.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a15c0c2f-a2be-424b-9f22-9195ebbc952c
📒 Files selected for processing (71)
.storybook/index.ts.storybook/trackStateSnapshot.tsdocs/IMPLEMENTATION_PLAN.mdsrc/app/bridge/iracingSdk/iracingSdkBridge.tssrc/app/bridge/iracingSdk/mock-data/mockSdkBridge.tssrc/app/processors/TrackStateProcessor.spec.tssrc/app/processors/TrackStateProcessor.tssrc/app/processors/trackStateRuntime.spec.tssrc/app/processors/trackStateRuntime.tssrc/frontend/components/Battle/Battle.stories.tsxsrc/frontend/components/Battle/Battle.tsxsrc/frontend/components/Battle/widgetRuntimeDefinition.tssrc/frontend/components/BlindSpotMonitor/BlindSpotMonitor.tsxsrc/frontend/components/BlindSpotMonitor/hooks/useBlindSpotMonitor.tsxsrc/frontend/components/BlindSpotMonitor/widgetRuntimeDefinition.tssrc/frontend/components/FasterCarsFromBehind/FasterCarsFromBehind.stories.tsxsrc/frontend/components/FasterCarsFromBehind/widgetRuntimeDefinition.tssrc/frontend/components/FlatTrackMap/widgetRuntimeDefinition.tssrc/frontend/components/InformationBar/InformationBar.stories.tsxsrc/frontend/components/Input/Input.stories.tsxsrc/frontend/components/Input/widgetRuntimeDefinition.tssrc/frontend/components/PitlaneHelper/PitlaneHelper.spec.tsxsrc/frontend/components/PitlaneHelper/PitlaneHelper.tsxsrc/frontend/components/PitlaneHelper/components/PitExitInputs.spec.tsxsrc/frontend/components/PitlaneHelper/components/PitExitInputs.tsxsrc/frontend/components/PitlaneHelper/hooks/usePitLimiterWarning.spec.tsxsrc/frontend/components/PitlaneHelper/hooks/usePitLimiterWarning.tsxsrc/frontend/components/PitlaneHelper/hooks/usePitSpeed.tsxsrc/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsxsrc/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsxsrc/frontend/components/PitlaneHelper/hooks/usePitlaneVisibility.tsxsrc/frontend/components/PitlaneHelper/widgetRuntimeDefinition.tssrc/frontend/components/RejoinIndicator/RejoinIndicator.tsxsrc/frontend/components/RejoinIndicator/widgetRuntimeDefinition.tssrc/frontend/components/RendererDataProviders/RendererDataProviders.spec.tsxsrc/frontend/components/RendererDataProviders/RendererDataProviders.tsxsrc/frontend/components/SlowCarAhead/hooks/useSlowCarAhead.tsxsrc/frontend/components/SlowCarAhead/widgetRuntimeDefinition.tssrc/frontend/components/Standings/components/SessionBar/SessionBarClassRank.stories.tsxsrc/frontend/components/Standings/components/SessionBar/SessionBarManufacturerPosition.stories.tsxsrc/frontend/components/Standings/components/SessionBar/components/ClassRankItem/ClassRankItem.spec.tsxsrc/frontend/components/Standings/components/SessionBar/components/ClassRankItem/ClassRankItem.tsxsrc/frontend/components/Tachometer/Tachometer.stories.tsxsrc/frontend/components/Tachometer/widgetRuntimeDefinition.tssrc/frontend/components/TrackMap/FlatTrackMap.spec.tsxsrc/frontend/components/TrackMap/FlatTrackMap.stories.tsxsrc/frontend/components/TrackMap/FlatTrackMap.tsxsrc/frontend/components/TrackMap/FlatTrackMapCanvas.tsxsrc/frontend/components/TrackMap/TrackCanvas.stories.tsxsrc/frontend/components/TrackMap/TrackCanvas.tsxsrc/frontend/components/TrackMap/TrackMap.spec.tsxsrc/frontend/components/TrackMap/TrackMap.stories.tsxsrc/frontend/components/TrackMap/TrackMap.tsxsrc/frontend/components/TrackMap/hooks/useDriverProgress.spec.tsxsrc/frontend/components/TrackMap/hooks/useDriverProgress.tsxsrc/frontend/components/TrackMap/trackDrawingUtils.tssrc/frontend/components/TrackMap/widgetRuntimeDefinition.tssrc/frontend/context/ChannelStore/index.tssrc/frontend/context/ChannelStore/useTrackStateSnapshot.tssrc/frontend/context/PitLaneStore/PitLaneStore.tssrc/frontend/context/PitLaneStore/usePitLaneDetection.tsxsrc/frontend/context/shared/useCarIdxOffTrack.tsxsrc/frontend/context/shared/useDrivingState.spec.tssrc/frontend/context/shared/useDrivingState.tssrc/frontend/context/shared/useFocusCarIdx.tssrc/frontend/widgetRuntime.spec.tsxsrc/frontend/widgetRuntime.tsxsrc/types/channels/channel.tstest-data/telemetry/ai-race-10min.golden.jsontools/telemetry-replay/run-curated-validation.tstools/telemetry-replay/track-state-probe.ts
|
|
||
| ## 6. Activity log | ||
|
|
||
| - **2026-08-09** — PR #668 merged. Opened PR #669 for the second final Phase 4 slice: a reusable-buffer, demand-driven 25 Hz `track-state.snapshot` for positional, pit-state, and warning data; migrated Pitlane Helper, Track Map, Flat Track Map, Battle, Blind Spot, Rejoin, Faster Cars From Behind, and Slow Car Ahead off the legacy renderer firehose; decoupled session and pit-lane providers from raw telemetry; added processor/runtime tests, Storybook snapshots, and a thirteenth curated replay probe — `feat/positional-status-channels` — in review |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the future activity-log date.
This entry is dated 2026-08-09, but the current date is 2026-08-08. If this entry documents the current PR opening, use 2026-08-08. Otherwise, add the entry after August 9, 2026.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/IMPLEMENTATION_PLAN.md` at line 475, Correct the date on the PR `#669`
activity-log entry to 2026-08-08 if it documents the current PR opening;
otherwise, move the entry after the existing August 9, 2026 activity.
| const session = useSessionStore((state) => state.session); | ||
| const focusCarIdx = useFocusCarIdx(); | ||
| const carIdxLapDistPct = useTelemetryValuesRounded('CarIdxLapDistPct', 3); | ||
| const carIdxLapDistPct = useTrackStateSnapshot()?.carIdxLapDistPct; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ast-grep outline src/app/processors/TrackStateProcessor.ts --items all
rg -n -C 5 \
'carIdxLapDistPct|carIdxOnPitRoad|projection|buffer|version|snapshot' \
src/app/processors/TrackStateProcessor.ts \
src/types/channels/channel.ts
rg -n -C 5 \
'useMemo|carIdxLapDistPct|carIdxOnPitRoad|version' \
src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx \
src/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsxRepository: tariknz/irdashies
Length of output: 28021
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- TrackStateProcessor relevant sections ---\n'
sed -n '1,170p' src/app/processors/TrackStateProcessor.ts
printf '\n--- usePitboxPosition relevant sections ---\n'
sed -n '1,170p' src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx
printf '\n--- usePitlaneTraffic relevant sections ---\n'
sed -n '1,75p' src/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsx
printf '\n--- behavioral probe for copyArray identity and useMemo key semantics ---\n'
python3 - <<'PY'
class Processor:
def __init__(self):
self.latest = {
'carIdxLapDistPct': [],
'carIdxOnPitRoad': [],
'version': 0,
}
def copyArray(self, target, source):
if len(target) != len(source):
target[:] = [0] * len(source)
changed = False
for i, value in enumerate(source):
if target[i] != value:
target[i] = value
changed = True
return changed
def onFrame(self, carIdxLapDistPct_source=None, carIdxOnPitRoad_source=None):
changed = False
if carIdxLapDistPct_source is not None:
changed = self.copyArray(self.latest['carIdxLapDistPct'], carIdxLapDistPct_source) or changed
if carIdxOnPitRoad_source is not None:
changed = self.copyArray(self.latest['carIdxOnPitRoad'], carIdxOnPitRoad_source) or changed
if changed:
self.latest['version'] += 1
processor = Processor()
carIdxLapDistPct = [0.1]
carIdxOnPitRoad = [True]
processor.onFrame(carIdxOnPitRoad=carIdxOnPitRoad)
first_pit = id(processor.latest['carIdxOnPitRoad'])
processor.onFrame(carIdxOnPitRoad=carIdxOnPitRoad)
second_pit = id(processor.latest['carIdxOnPitRoad'])
print(first_pit, second_pit, first_pit == second_pit)
print('version', processor.latest['version'])
print('snapshot object identity', id(processor.latest))
print('snapshot carIdxOnPitRoad identity same', id(processor.latest['carIdxOnPitRoad']))
print('value after no change', processor.latest['carIdxOnPitRoad'])
PYRepository: tariknz/irdashies
Length of output: 246
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- TrackStateProcessor relevant sections ---'
sed -n '1,170p' src/app/processors/TrackStateProcessor.ts
printf '%s\n' ''
printf '%s\n' '--- usePitboxPosition relevant sections ---'
sed -n '1,170p' src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx
printf '%s\n' ''
printf '%s\n' '--- usePitlaneTraffic relevant sections ---'
sed -n '1,75p' src/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsx
printf '%s\n' ''
printf '%s\n' '--- behavioral probe for copyArray identity and useMemo key semantics ---'
python3 - <<'PY'
class Processor:
def __init__(self):
self.latest = {
'carIdxLapDistPct': [],
'carIdxOnPitRoad': [],
'version': 0,
}
def copyArray(self, target, source):
if len(target) != len(source):
target[:] = [0] * len(source)
changed = False
for i, value in enumerate(source):
if target[i] != value:
target[i] = value
changed = True
return changed
def onFrame(self, carIdxLapDistPct_source=None, carIdxOnPitRoad_source=None):
changed = False
if carIdxLapDistPct_source is not None:
changed = self.copyArray(self.latest['carIdxLapDistPct'], carIdxLapDistPct_source) or changed
if carIdxOnPitRoad_source is not None:
changed = self.copyArray(self.latest['carIdxOnPitRoad'], carIdxOnPitRoad_source) or changed
if changed:
self.latest['version'] += 1
processor = Processor()
carIdxLapDistPct = [0.1]
carIdxOnPitRoad = [True]
processor.onFrame(carIdxOnPitRoad=carIdxOnPitRoad)
first_pit = id(processor.latest['carIdxOnPitRoad'])
processor.onFrame(carIdxOnPitRoad=carIdxOnPitRoad)
second_pit = id(processor.latest['carIdxOnPitRoad'])
print(first_pit, second_pit, first_pit == second_pit)
print('version', processor.latest['version'])
print('snapshot object identity', id(processor.latest))
print('snapshot carIdxOnPitRoad identity same', id(processor.latest['carIdxOnPitRoad']))
print('value after no change', processor.latest['carIdxOnPitRoad'])
PYRepository: tariknz/irdashies
Length of output: 13653
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
class Processor:
def __init__(self):
self.latest = {
'carIdxLapDistPct': [],
'carIdxOnPitRoad': [],
'version': 0,
}
def copyArray(self, target, source):
changed = len(target) != len(source)
if len(target) != len(source):
target[:] = [0] * len(source)
for index in range(len(source)):
if target[index] != source[index]:
target[index] = source[index]
changed = True
return changed
def onFrame(self, *, carIdxLapDistPct_source=None, carIdxOnPitRoad_source=None):
changed = False
if carIdxLapDistPct_source is not None:
changed = self.copyArray(self.latest['carIdxLapDistPct'], carIdxLapDistPct_source) or changed
if carIdxOnPitRoad_source is not None:
changed = self.copyArray(self.latest['carIdxOnPitRoad'], carIdxOnPitRoad_source) or changed
if changed:
self.latest['version'] += 1
processor = Processor()
array_identity = lambda key: id(processor.latest[key])
memo_key_equal = lambda keys, new_values: all(v == keys[idx] for idx, v in enumerate(new_values))
array = [0.1]
processor.onFrame(carIdxLapDistPct_source=array)
first = array_identity('carIdxLapDistPct')
processor.onFrame(carIdxLapDistPct_source=array)
second = array_identity('carIdxLapDistPct')
print('same_array_identity', first == second)
print('current_version', processor.latest['version'])
print('useMemo_dependents_equal', memo_key_equal(
[first, 'same-session'],
[second, 'same-session'],
))
print('snapshot_reused_by_reference', id(processor.latest) == id(processor.snapshot()))
PYRepository: tariknz/irdashies
Length of output: 365
Include the track-state version in the pitlane memo keys.
TrackStateProcessor reuses carIdxLapDistPct and carIdxOnPitRoad by mutating existing arrays. If the values in both frames stay the same, the memo key stays the same and the pit calculations can reuse the previous result. Include useTrackStateSnapshot()?.version in the useMemo dependency arrays for usePitboxPosition and usePitlaneTraffic.
📍 Affects 2 files
src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx#L27-L27(this comment)src/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsx#L15-L17
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx` at line
27, Include useTrackStateSnapshot()?.version in the useMemo dependency arrays
for usePitboxPosition in
src/frontend/components/PitlaneHelper/hooks/usePitboxPosition.tsx:27-27 and
usePitlaneTraffic in
src/frontend/components/PitlaneHelper/hooks/usePitlaneTraffic.tsx:15-17, so
memoized pit calculations refresh for each track-state update even when the
reused arrays retain equal values.
| const trackState = useTrackStateSnapshot(); | ||
| const driversLapDist = trackState?.carIdxLapDistPct ?? EMPTY_POSITIONS; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ast-grep outline src/app/processors/TrackStateProcessor.ts --items all
rg -n -C 4 \
'carIdxLapDistPct|version|projection|round' \
src/app/processors/TrackStateProcessor.ts \
src/frontend/context/ChannelStore/useTrackStateSnapshot.ts \
src/frontend/components/TrackMap/hooks/useDriverProgress.tsx \
src/frontend/components/SlowCarAhead/hooks/useSlowCarAhead.tsx \
src/frontend/context/PitLaneStore/usePitLaneDetection.tsxRepository: tariknz/irdashies
Length of output: 11768
🏁 Script executed:
#!/bin/bash
set -euo pipefail
wc -l src/app/processors/TrackStateProcessor.ts src/frontend/components/TrackMap/hooks/useDriverProgress.tsx src/frontend/theme/theme.css src/frontend/utils/*.ts src/frontend/utils/*.tsx 2>/dev/null || true
rg -n -C 6 'function copyArray|copyArray=|copyArray\(' src app frontend 2>/dev/null || true
sed -n '1,170p' src/app/processors/TrackStateProcessor.ts
sed -n '1,140p' src/frontend/components/TrackMap/hooks/useDriverProgress.tsx
python3 - <<'PY'
import ast, pathlib
files = [pathlib.Path('src/app/processors/TrackStateProcessor.ts'), pathlib.Path('src/frontend/components/TrackMap/hooks/useDriverProgress.tsx')]
for path in files:
if not path.exists():
continue
text = path.read_text()
try:
tree = ast.parse(text, filename=str(path))
except SyntaxError as exc:
print(f"\n[PARSE_ERROR] {path}: {exc}")
continue
print(f"\n[AST_EXPORTS_AND_USE_DRIVER_PROGRESS] {path}")
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == 'useDriverProgress':
print(ast.dump(node, indent=2)[:1200])
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef) and node.name == 'copyArray':
print(ast.dump(node, indent=2)[:1200])
PYRepository: tariknz/irdashies
Length of output: 13598
Emit a rounded immutable car idx lap-dist array for track-map position.
TrackStateProcessor mutates latest.carIdxLapDistPct in place and exposes the same array from snapshot(), so driversTrackData can keep the same driversLapDist identity when only positions change. In addition, map positions must use useTelemetryValuesRounded with 3 decimals. Move the rounding into TrackStateProcessor or expose a rounded selector that drives the snapshot memo.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/frontend/components/TrackMap/hooks/useDriverProgress.tsx` around lines 17
- 18, Update the track-state flow used by useDriverProgress and driversTrackData
so carIdxLapDistPct is copied immutably and rounded to 3 decimals via
useTelemetryValuesRounded. Ensure position-only updates produce a new rounded
driversLapDist reference, either by changing TrackStateProcessor or by exposing
a rounded selector that participates in snapshot memoization.
Source: Coding guidelines
| const trackState = useTrackStateSnapshot(); | ||
| const carIdxOnPitRoad = trackState?.carIdxOnPitRoad; | ||
| const carIdxTrackSurface = trackState?.carIdxTrackSurface; | ||
| const carIdxLapDistPct = trackState?.carIdxLapDistPct; | ||
|
|
||
| const { currentTrackId, pitEntryPct, pitExitPct, setCurrentTrack, reset } = | ||
| usePitLaneStore(); | ||
|
|
||
| // Use refs to track previous values and only call detectPitTransitions when data actually changes | ||
| // This prevents running expensive operations at 60 FPS when nothing has changed | ||
| const prevTelemetryRef = useRef<{ | ||
| carIdxOnPitRoad?: boolean[]; | ||
| carIdxTrackSurface?: number[]; | ||
| carIdxLapDistPct?: number[]; | ||
| carIdxOnPitRoad?: readonly boolean[]; | ||
| carIdxTrackSurface?: readonly number[]; | ||
| carIdxLapDistPct?: readonly number[]; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use the snapshot version to trigger pit transition detection.
The identity checks at Lines 83-87 do not detect element changes in reusable
projection buffers. Pit entry and exit detection can stop after the first
snapshot.
Trigger detectPitTransitions for each new trackState.version while all
three arrays are present. Remove the array-reference gate.
Based on PR objectives, the processor uses reusable projection buffers.
Proposed fix
const trackState = useTrackStateSnapshot();
+ const trackStateVersion = trackState?.version;
const carIdxOnPitRoad = trackState?.carIdxOnPitRoad;
const carIdxTrackSurface = trackState?.carIdxTrackSurface;
const carIdxLapDistPct = trackState?.carIdxLapDistPct;
...
- const prev = prevTelemetryRef.current;
- if (
- prev.carIdxOnPitRoad !== carIdxOnPitRoad ||
- prev.carIdxTrackSurface !== carIdxTrackSurface ||
- prev.carIdxLapDistPct !== carIdxLapDistPct
- ) {
- detectPitTransitions(
- carIdxOnPitRoad,
- carIdxTrackSurface,
- carIdxLapDistPct
- );
- prevTelemetryRef.current = {
- carIdxOnPitRoad,
- carIdxTrackSurface,
- carIdxLapDistPct,
- };
- }
- }, [carIdxOnPitRoad, carIdxTrackSurface, carIdxLapDistPct, trackId]);
+ detectPitTransitions(
+ carIdxOnPitRoad,
+ carIdxTrackSurface,
+ carIdxLapDistPct
+ );
+ }, [
+ carIdxOnPitRoad,
+ carIdxTrackSurface,
+ carIdxLapDistPct,
+ trackId,
+ trackStateVersion,
+ ]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/frontend/context/PitLaneStore/usePitLaneDetection.tsx` around lines 17 -
30, Update the pit transition detection flow in usePitLaneDetection to trigger
detectPitTransitions once for each new trackState.version when carIdxOnPitRoad,
carIdxTrackSurface, and carIdxLapDistPct are all present. Remove the previous
array-reference comparison gate and track the last processed snapshot version
instead, so reusable projection buffers still produce detection updates.
Description
Phase 4 of the channel-based bridge migration. Adds a demand-driven 25 Hz
track-state.snapshotprocessor for positional, pit-state, and warning data, with reusable projection buffers and live/tape plus demo/mock runtime wiring.Pitlane Helper, Track Map, Flat Track Map, Battle, Blind Spot Monitor, Rejoin Indicator, Faster Cars From Behind, and Slow Car Ahead now consume typed channel snapshots and opt out of the legacy renderer telemetry firehose. Session and pit-lane providers are activated independently from raw telemetry so channel-only widgets retain the session data and persisted pit entry/exit data they need.
This PR also includes the remaining SessionBar follow-up changes: InformationBar now seeds and applies
session-timing.snapshot, the class-rank and manufacturer-position stories use per-storysession-bar.snapshotfixtures instead of obsolete telemetry seeders, and class rank is hidden for unclassified drivers or invalid class sizes.Input and Tachometer are also completed as channel-only consumers: their indirect driving-state dependency now declares
track-state.snapshot, while their session visibility and Tachometer car metadata retainSessionProviderthrough explicit session-data runtime metadata. An Input/Tachometer-only renderer therefore keeps session state without restoring raw telemetry delivery.Track-state values are normalized at the processor boundary: pit-road
0/1flags become typed booleans and lap-distance percentages are rounded to three decimals before publication. Pitlane tests now mock typed channel snapshots directly rather than reconstructing them through legacy telemetry hooks.The deterministic curated replay now validates 13 probes over all 36,000 frames. This was not tested against a live iRacing session.
Architecture checklist:
Validation:
npm run lint -- --no-fixnpm run test -- --no-coverage— 1,210 passed, 1 skippednpm run test:replay:curated— 36,000 frames, 70 session revisions, 13 probesScreenshots
No visual changes expected; this replaces the data transport and preserves existing widget output.
Before
Affected renderers receive the legacy telemetry firehose.
After
Affected renderers subscribe only to their typed channel snapshots.
Type of Change
Checklist
npm testnpm run lintand fixed any issues