Skip to content

feat: estimate iRating changes in practice - #689

Merged
tariknz merged 1 commit into
mainfrom
feat/ir-rating-practice
Aug 10, 2026
Merged

feat: estimate iRating changes in practice#689
tariknz merged 1 commit into
mainfrom
feat/ir-rating-practice

Conversation

@tariknz

@tariknz tariknz commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Description

Adds an opt-in standings setting to show hypothetical iRating changes during online practice sessions. The existing iRating calculation is reused and remains unchanged for official race weekends.

The new Estimate During Practice toggle is nested under the existing iRating Change display option and defaults to off, preserving current behavior for new and saved dashboards. Offline testing and qualifying sessions are excluded.

This is consistent with the Phase 2 settings direction in docs/ARCHITECTURE_REVIEW.md: the new field is additive and is supplied through the existing default-config deep merge, so no breaking settings migration is required.

Validation:

  • npm run test -- --no-coverage src/frontend/components/Standings/hooks/useDriverStandings.spec.ts src/types/defaultDashboard.spec.ts (46 tests passed)
  • npm run lint -- --no-fix
  • git diff --check

Screenshots

Before

The iRating Change display option has no practice-session estimate control, and standalone online practice sessions do not show hypothetical changes.

After

The iRating Change display option includes an Estimate During Practice toggle. When enabled, online practice standings display hypothetical iRating changes using the current running order.

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Performance improvement
  • Refactoring (no functional changes)
  • Documentation update
  • Dependency update

Checklist

  • I have discussed this change in the discord server
  • I have tested this in iRacing (either in an online session or with AI)
  • All tests pass locally via npm test
  • I have added tests that prove my fix is effective or that my feature works
  • I have run npm run lint and fixed any issues
  • I have performed a self-review of my own code
  • I have added/updated Storybook stories for visual changes
  • I have updated the README.md (if applicable)
  • I have updated defaultDashboard.ts if introducing new widgets or configurations (if applicable)

Architecture Pre-PR Checklist

  • N1 — no new synchronous filesystem access
  • N2 — no frontend imports from src/app
  • N3 — no new cross-widget imports
  • N4 — no new IPC handlers
  • R2.1/R2.2 — no new telemetry subscriptions
  • R3.1 — no new stores
  • R4.1 — no new bridges
  • R6.1 — no new storage code
  • R7.1 — existing widget extended; no registration changes
  • R8.1 — additive optional setting with a default; no breaking migration required
  • R10.1 — no native-code changes
  • R11.1 — no logging changes
  • R13.1 — no new high-frequency subscription path
  • R14.1 — decision logic has focused unit coverage
  • Storybook visual verification completed
  • iRacing online-session verification completed

Summary by CodeRabbit

  • New Features

    • Added an “Estimate During Practice” option for iRating changes in standings.
    • Practice-session iRating estimates are now configurable and disabled by default.
    • iRating changes continue to apply automatically in eligible official sessions.
  • Bug Fixes

    • Improved handling of standings configuration when optional settings are unavailable.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The standings widget adds an optional estimateInPractice setting for iRating changes. The setting defaults to false, appears in standings settings, and controls iRating calculation eligibility for practice sessions.

Changes

Standings iRating estimation

Layer / File(s) Summary
Configure practice estimation
src/frontend/components/Settings/..., src/types/...
The configuration types and default dashboard include estimateInPractice: false. The settings UI renders and persists the “Estimate During Practice” toggle.
Apply practice estimation
src/frontend/components/Standings/hooks/useDriverStandings.tsx
shouldCalculateIRatingChange enables iRating calculations for official races and opted-in practice sessions. The setting is included in standings memoization dependencies.
Validate eligibility rules
src/frontend/components/Standings/hooks/useDriverStandings.spec.ts, src/types/defaultDashboard.spec.ts
Tests cover official races, practice sessions, offline testing, qualifying sessions, and the default setting value.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant StandingsSettings
  participant StandingsWidgetConfig
  participant useDriverStandings
  StandingsSettings->>StandingsWidgetConfig: Update estimateInPractice
  StandingsWidgetConfig->>useDriverStandings: Provide standings configuration
  useDriverStandings->>useDriverStandings: Evaluate iRating eligibility
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature: estimating iRating changes during practice sessions.
Description check ✅ Passed The description explains the feature, behavior, testing, screenshots, change type, and checklist status; only optional verification items remain unchecked.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ir-rating-practice

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tariknz
tariknz marked this pull request as ready for review August 10, 2026 07:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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 `@src/frontend/components/Settings/sections/StandingsSettings.tsx`:
- Around line 155-171: Give the ToggleSwitch in the “Estimate During Practice”
setting an accessible name by associating it with the visible label text via
aria-labelledby, or by passing an accessible-label prop if supported. Update
ToggleSwitch as needed so its rendered switch button receives that name while
preserving the existing toggle behavior.

In `@src/frontend/components/Standings/hooks/useDriverStandings.tsx`:
- Around line 36-45: The official-race branch of shouldCalculateIRatingChange
must require sessionType === 'Race' so qualifying sessions return false; update
src/frontend/components/Standings/hooks/useDriverStandings.tsx lines 36-45
accordingly. Add an assertion in
src/frontend/components/Standings/hooks/useDriverStandings.spec.ts lines 7-37
verifying ('Race', true, 'Open Qualify', true) returns false.
🪄 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: d1d092e4-e5ad-4b41-acbd-6475dcc94428

📥 Commits

Reviewing files that changed from the base of the PR and between f189c2e and c5ede9f.

📒 Files selected for processing (7)
  • src/frontend/components/Settings/sections/StandingsSettings.tsx
  • src/frontend/components/Settings/types.ts
  • src/frontend/components/Standings/hooks/useDriverStandings.spec.ts
  • src/frontend/components/Standings/hooks/useDriverStandings.tsx
  • src/types/defaultDashboard.spec.ts
  • src/types/defaultDashboard.ts
  • src/types/widgetConfigs.ts

Comment on lines +155 to +171
<div className="flex items-center justify-between gap-3 pl-8 mt-2 indent-8">
<span className="text-sm text-slate-300">
Estimate During Practice
</span>
<ToggleSwitch
enabled={
settings.config.iratingChange.estimateInPractice ?? false
}
onToggle={(enabled) =>
handleConfigChange({
iratingChange: {
...settings.config.iratingChange,
estimateInPractice: enabled,
},
})
}
/>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Give the switch an accessible name.

ToggleSwitch renders an unnamed role="switch" button. The sibling span does not label that button. Associate the text with the control through aria-labelledby, or extend ToggleSwitch with an accessible-label prop and pass Estimate During Practice.

🤖 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/Settings/sections/StandingsSettings.tsx` around lines
155 - 171, Give the ToggleSwitch in the “Estimate During Practice” setting an
accessible name by associating it with the visible label text via
aria-labelledby, or by passing an accessible-label prop if supported. Update
ToggleSwitch as needed so its rendered switch button receives that name while
preserving the existing toggle behavior.

Comment on lines +36 to +45
export const shouldCalculateIRatingChange = (
eventType: string | undefined,
isOfficial: boolean,
sessionType: string | undefined,
estimateInPractice: boolean
) =>
(eventType === 'Race' && isOfficial) ||
(eventType === 'Practice' &&
sessionType === 'Practice' &&
estimateInPractice);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Exclude qualifying sessions during official race weekends.

Line 42 returns true for ('Race', true, 'Open Qualify', false). This enables hypothetical iRating changes during qualifying. Require sessionType === 'Race' for the official-race branch.

  • src/frontend/components/Standings/hooks/useDriverStandings.tsx#L36-L45: require a race session in the official-race eligibility branch.
  • src/frontend/components/Standings/hooks/useDriverStandings.spec.ts#L7-L37: add an assertion that ('Race', true, 'Open Qualify', true) returns false.
📍 Affects 2 files
  • src/frontend/components/Standings/hooks/useDriverStandings.tsx#L36-L45 (this comment)
  • src/frontend/components/Standings/hooks/useDriverStandings.spec.ts#L7-L37
🤖 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/hooks/useDriverStandings.tsx` around lines
36 - 45, The official-race branch of shouldCalculateIRatingChange must require
sessionType === 'Race' so qualifying sessions return false; update
src/frontend/components/Standings/hooks/useDriverStandings.tsx lines 36-45
accordingly. Add an assertion in
src/frontend/components/Standings/hooks/useDriverStandings.spec.ts lines 7-37
verifying ('Race', true, 'Open Qualify', true) returns false.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5ede9f4de

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

export interface StandingsWidgetSettings extends BaseWidgetSettings {
config: {
iratingChange: { enabled: boolean };
iratingChange: { enabled: boolean; estimateInPractice?: boolean };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Version the changed standings settings schema

This adds a persisted field to the Standings settings shape, but StandingsWidgetSettings still has no version field. Architecture rule R8.1 explicitly requires every changed settings shape to carry a version; without one, this schema cannot participate in the required versioned migration path when later changes become breaking.

AGENTS.md reference: AGENTS.md:L12-L14

Useful? React with 👍 / 👎.

Comment on lines +189 to +193
const iratingAugmentedGroupedByClass = shouldCalculateIRatingChange(
eventType,
isOfficial,
sessionType,
settings?.iratingChange?.estimateInPractice ?? false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Instrument the new practice iRating hot path

When practice estimation is enabled, telemetry-driven standings recomputations now invoke augmentStandingsWithIRating, whose calculation allocates an N-by-N chance matrix, but this newly enabled high-frequency path has no perfMetrics.measure wrapper. Architecture rule R13.1 requires that instrumentation so regressions from large practice fields appear in the performance overlay.

AGENTS.md reference: AGENTS.md:L12-L14

Useful? React with 👍 / 👎.

@tariknz
tariknz merged commit e8469de into main Aug 10, 2026
7 checks passed
@tariknz
tariknz deleted the feat/ir-rating-practice branch August 10, 2026 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant