@@ -38,10 +38,10 @@ Everything else from the concept docs (league/season management, result aggregat
- React renderer: [`App`](apps/companion/renderer/App.tsx), UI components under [`components`](apps/companion/renderer/components).
- Automation & browser integration:
- Domain models around hosted sessions and steps, e.g. [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1), [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1).
- Application layer ports and use-cases, e.g. [`IAutomationEngine`](packages/application/ports/IAutomationEngine.ts:1), [`ISessionRepository`](packages/application/ports/ISessionRepository.ts:1), [`StartAutomationSessionUseCase`](packages/application/use-cases/StartAutomationSessionUseCase.ts:1).
- Playwright-based automation adapter and helpers, e.g. [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1), [`CheckoutPriceExtractor`](packages/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1).
- Logging, config and in-memory repository implementations, e.g. [`InMemorySessionRepository`](packages/infrastructure/repositories/InMemorySessionRepository.ts:1), [`AutomationConfig`](packages/infrastructure/config/AutomationConfig.ts:1), [`LoggingConfig`](packages/infrastructure/config/LoggingConfig.ts:1), [`PinoLogAdapter`](packages/infrastructure/adapters/logging/PinoLogAdapter.ts:1).
- Domain models around hosted sessions and steps, e.g. [`AutomationSession`](core/domain/entities/AutomationSession.ts:1), [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1).
- Application layer ports and use-cases, e.g. [`IAutomationEngine`](core/application/ports/IAutomationEngine.ts:1), [`ISessionRepository`](core/application/ports/ISessionRepository.ts:1), [`StartAutomationSessionUseCase`](core/application/use-cases/StartAutomationSessionUseCase.ts:1).
- Playwright-based automation adapter and helpers, e.g. [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1), [`CheckoutPriceExtractor`](core/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1).
- Logging, config and in-memory repository implementations, e.g. [`InMemorySessionRepository`](core/infrastructure/repositories/InMemorySessionRepository.ts:1), [`AutomationConfig`](core/infrastructure/config/AutomationConfig.ts:1), [`LoggingConfig`](core/infrastructure/config/LoggingConfig.ts:1), [`PinoLogAdapter`](core/infrastructure/adapters/logging/PinoLogAdapter.ts:1).
- Testing:
- Unit tests for domain, application and infrastructure.
@@ -162,14 +162,14 @@ The website under [`apps/website`](apps/website:1) is the primary presentation s
- Read standings, stats snapshots and rating values.
- Submit registrations, complaints and admin actions.
- Trigger or schedule result imports and (where allowed) automation runs.
- These APIs are implemented by the platform application layer and are conceptually separate from the automation-specific ports in `packages/application`.
- These APIs are implemented by the platform application layer and are conceptually separate from the automation-specific ports in `core/application`.
### 2.4 Platform Integration with Automation
The web platform uses the automation & companion subsystem as a hosted-session engine, without coupling to Playwright or Electron details:
- **From league/season data to automation intent**
- The platform aggregates league configuration (series settings, car/track choices, schedule, server settings) and derives a hosted-session configuration structure conceptually equivalent to [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1).
- The platform aggregates league configuration (series settings, car/track choices, schedule, server settings) and derives a hosted-session configuration structure conceptually equivalent to [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1).
- This configuration captures the intent of a single hosted session (or a batch of sessions across a season) in a platform-neutral format.
- **Hand-off to automation**
@@ -207,9 +207,9 @@ This section describes how the automation engine and companion in this repo sit
- **Automation Engine & Domain (this repo)**
- Clean Architecture core for iRacing hosted-session automation:
- Domain and value objects under [`packages/domain`](packages/domain/entities/AutomationSession.ts:1).
- Application use-cases and ports under [`packages/application`](packages/application/use-cases/StartAutomationSessionUseCase.ts:1).
- Infrastructure adapters under [`packages/infrastructure`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1).
- Domain and value objects under [`core/domain`](core/domain/entities/AutomationSession.ts:1).
- Application use-cases and ports under [`core/application`](core/application/use-cases/StartAutomationSessionUseCase.ts:1).
- Infrastructure adapters under [`core/infrastructure`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1).
- Exposes automation capabilities via application ports that can be used both by the companion and by external orchestrators.
- **iRacing Web (members.iracing.com)**
@@ -228,7 +228,7 @@ This section describes how the automation engine and companion in this repo sit
- Shared concept space:
- Both surfaces operate on the competition concepts described in [`CONCEPT.md`](docs/concept/CONCEPT.md), [`ADMINS.md`](docs/concept/ADMINS.md), [`DRIVERS.md`](docs/concept/DRIVERS.md), [`COMPETITION.md`](docs/concept/COMPETITION.md), [`RACING.md`](docs/concept/RACING.md), [`SOCIAL.md`](docs/concept/SOCIAL.md), [`TEAMS.md`](docs/concept/TEAMS.md).
- The automation engine uses [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) as the canonical representation of a hosted-session setup derived from those higher-level concepts.
- The automation engine uses [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) as the canonical representation of a hosted-session setup derived from those higher-level concepts.
- Division of responsibilities:
- The **website** is the primary UI for league management, discovery, stats and rating (core platform concerns).
@@ -245,7 +245,7 @@ At a high level, communication flows are designed around the automation engine a
- Core platform services or the web app can derive a [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) from league data and store it server-side.
- Core platform services or the web app can derive a [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) from league data and store it server-side.
- The companion app or a headless orchestrator retrieves these configs via platform APIs and invokes the automation engine using the same application ports used in this repo.
### 2.4 System context diagram
@@ -300,7 +300,7 @@ The automation strategy is shaped by iRacing’s platform boundaries and Terms o
- Hooking the sim process or game memory.
- Running any automation that is not clearly aligned with “browser automation of a public web UI”.
The [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) contains additional safeguards, such as:
The [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) contains additional safeguards, such as:
- Guardrails around checkout/payment-like buttons using iRacing-specific selector maps.
- Explicit “blocked selector” detection before clicks.
@@ -336,7 +336,7 @@ Inner layers:
**Layer responsibilities**
- **Domain**
- Competition-neutral automation concepts such as [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1), [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1), session and step invariants and validators.
- Competition-neutral automation concepts such as [`AutomationSession`](core/domain/entities/AutomationSession.ts:1), [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1), session and step invariants and validators.
- Independent of Electron, Playwright, HTTP or persistence.
- **Application**
@@ -354,9 +354,9 @@ Inner layers:
**Key rules in this repo**
-`packages/domain/*` has no dependencies on application, infrastructure, or Electron.
-`packages/application/*` depends only on `packages/domain/*` (plus shared types).
-`packages/infrastructure/*` depends on domain and application ports, and on external libraries (Playwright, Pino, etc.).
-`core/domain/*` has no dependencies on application, infrastructure, or Electron.
-`core/application/*` depends only on `core/domain/*` (plus shared types).
-`core/infrastructure/*` depends on domain and application ports, and on external libraries (Playwright, Pino, etc.).
-`apps/companion/*` depends on inner layers and glues application use-cases to Electron UI and IPC.
This keeps the **automation engine** stable and reusable across presentation surfaces (companion today, web or backend orchestrators later), while allowing infrastructure and UI details to evolve without rewriting business logic.
@@ -365,19 +365,19 @@ This keeps the **automation engine** stable and reusable across presentation sur
## 4. Layer-by-Layer Mapping
### 4.1 Domain Layer (`packages/domain/*`)
### 4.1 Domain Layer (`core/domain/*`)
The domain models what an “automation session” is, how it progresses, and which invariants must hold regardless of UI or tooling.
- Declaratively describes what it means for the automation to be “on the right wizard page”.
- Evaluates combinations of required/forbidden selectors into a structured result.
- Used by [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) to avoid driving the wrong UI state.
- Used by [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) to avoid driving the wrong UI state.
- Persists [`AutomationSession`](core/domain/entities/AutomationSession.ts:1) instances for tracking and later inspection.
- Screen & browser integration:
- [`IScreenAutomation`](packages/application/ports/IScreenAutomation.ts:1) (implemented by [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1)).
- [`IAuthenticationService`](packages/application/ports/IAuthenticationService.ts:1) for login/session management.
- [`ICheckoutService`](packages/application/ports/ICheckoutService.ts:1) and [`ICheckoutConfirmationPort`](packages/application/ports/ICheckoutConfirmationPort.ts:1) for safe credits/checkout flows.
- [`IScreenAutomation`](core/application/ports/IScreenAutomation.ts:1) (implemented by [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1)).
- [`IAuthenticationService`](core/application/ports/IAuthenticationService.ts:1) for login/session management.
- [`ICheckoutService`](core/application/ports/ICheckoutService.ts:1) and [`ICheckoutConfirmationPort`](core/application/ports/ICheckoutConfirmationPort.ts:1) for safe credits/checkout flows.
- Bridges the automation lifecycle (from infrastructure) to overlay/presentation consumers (companion renderer).
- Consumes an [`IAutomationLifecycleEmitter`](packages/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) (implemented by the Playwright adapter) and publishes state to an overlay sync port.
- Consumes an [`IAutomationLifecycleEmitter`](core/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) (implemented by the Playwright adapter) and publishes state to an overlay sync port.
- Creates a new [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1) from a [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1).
- Calls [`IAutomationEngine`](packages/application/ports/IAutomationEngine.ts:1) to perform validation before any browser work starts.
- Persists the session via [`ISessionRepository`](packages/application/ports/ISessionRepository.ts:1).
- Creates a new [`AutomationSession`](core/domain/entities/AutomationSession.ts:1) from a [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1).
- Calls [`IAutomationEngine`](core/application/ports/IAutomationEngine.ts:1) to perform validation before any browser work starts.
- Persists the session via [`ISessionRepository`](core/application/ports/ISessionRepository.ts:1).
- Returns a DTO that the companion app tracks as progress state.
- These map the ToS-compliant login flow described in [`CONCEPT.md`](docs/concept/CONCEPT.md) and [`ADMINS.md`](docs/concept/ADMINS.md) into explicit use-cases (no password handling by GridPilot).
- Uses [`ICheckoutService`](packages/application/ports/ICheckoutService.ts:1) from the Playwright layer to inspect price/state and defers to a UI-side confirmation port to comply with “never surprise-charge the admin”.
- Uses [`ICheckoutService`](core/application/ports/ICheckoutService.ts:1) from the Playwright layer to inspect price/state and defers to a UI-side confirmation port to comply with “never surprise-charge the admin”.
- Guarding against stale auth:
- [`VerifyAuthenticatedPageUseCase`](packages/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1) ensures the current page is still authenticated before continuing automation.
- [`VerifyAuthenticatedPageUseCase`](core/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1) ensures the current page is still authenticated before continuing automation.
The application layer is where “admin intent” (start automation, confirm checkout, verify login) is encoded and exposed to the companion, without exposing Playwright or DOM specifics.
- [`IAutomationLifecycleEmitter`](packages/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) used by [`OverlaySyncService`](packages/application/services/OverlaySyncService.ts:1).
- [`IAutomationLifecycleEmitter`](core/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) used by [`OverlaySyncService`](core/application/services/OverlaySyncService.ts:1).
- Responsibilities:
- Managing Playwright browser, context, and page lifecycle (headed/headless, fixture vs real mode).
- Navigating to the iRacing hosted-session wizard, login pages and fixtures.
- Driving wizard steps through an internal [`WizardStepOrchestrator`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1).
- Driving wizard steps through an internal [`WizardStepOrchestrator`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1).
- Injecting and updating the on-page automation overlay.
- Handling authentication flows, cookies and persistent sessions via [`SessionCookieStore`](packages/infrastructure/adapters/automation/auth/SessionCookieStore.ts:1) and [`PlaywrightAuthSessionService`](packages/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService.ts:1).
- Validating page state using [`PageStateValidator`](packages/domain/services/PageStateValidator.ts:1).
- Handling authentication flows, cookies and persistent sessions via [`SessionCookieStore`](core/infrastructure/adapters/automation/auth/SessionCookieStore.ts:1) and [`PlaywrightAuthSessionService`](core/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService.ts:1).
- Validating page state using [`PageStateValidator`](core/domain/services/PageStateValidator.ts:1).
- Controls headed/headless behavior, with [`BrowserModeConfigLoader`](packages/infrastructure/config/BrowserModeConfig.ts:1) used heavily in [`di-container`](apps/companion/main/di-container.ts:1).
- Controls headed/headless behavior, with [`BrowserModeConfigLoader`](core/infrastructure/config/BrowserModeConfig.ts:1) used heavily in [`di-container`](apps/companion/main/di-container.ts:1).
- Bridges application-level checkout confirmation flows to the companion renderer via IPC.
This layer is where the “messy reality” of Playwright, Electron, file paths and selectors is implemented, while honoring the constraints defined at the domain/application layers.
@@ -579,22 +579,22 @@ The presentation layer in this repo is currently a **single Electron app** that
- Logger ([`ILogger`](packages/application/ports/ILogger.ts:1)) via `createLogger()` and [`LoggingConfig`](packages/infrastructure/config/LoggingConfig.ts:1).
- Session repository ([`ISessionRepository`](packages/application/ports/ISessionRepository.ts:1)) via [`InMemorySessionRepository`](packages/infrastructure/repositories/InMemorySessionRepository.ts:1).
- Browser automation adapter via `createBrowserAutomationAdapter()` using [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) or [`MockBrowserAutomationAdapter`](packages/infrastructure/adapters/automation/engine/MockBrowserAutomationAdapter.ts:1) depending on mode.
- [`IAutomationEngine`](packages/application/ports/IAutomationEngine.ts:1) via [`AutomationEngineAdapter`](packages/infrastructure/adapters/automation/engine/AutomationEngineAdapter.ts:1) / [`MockAutomationEngineAdapter`](packages/infrastructure/adapters/automation/engine/MockAutomationEngineAdapter.ts:1).
- Logger ([`ILogger`](core/application/ports/ILogger.ts:1)) via `createLogger()` and [`LoggingConfig`](core/infrastructure/config/LoggingConfig.ts:1).
- Session repository ([`ISessionRepository`](core/application/ports/ISessionRepository.ts:1)) via [`InMemorySessionRepository`](core/infrastructure/repositories/InMemorySessionRepository.ts:1).
- Browser automation adapter via `createBrowserAutomationAdapter()` using [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) or [`MockBrowserAutomationAdapter`](core/infrastructure/adapters/automation/engine/MockBrowserAutomationAdapter.ts:1) depending on mode.
- [`IAutomationEngine`](core/application/ports/IAutomationEngine.ts:1) via [`AutomationEngineAdapter`](core/infrastructure/adapters/automation/engine/AutomationEngineAdapter.ts:1) / [`MockAutomationEngineAdapter`](core/infrastructure/adapters/automation/engine/MockAutomationEngineAdapter.ts:1).
- Overlay sync orchestration via [`OverlaySyncService`](packages/application/services/OverlaySyncService.ts:1) and [`IAutomationLifecycleEmitter`](packages/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1).
- Overlay sync orchestration via [`OverlaySyncService`](core/application/services/OverlaySyncService.ts:1) and [`IAutomationLifecycleEmitter`](core/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1).
- Exposes methods like `getStartAutomationUseCase()`, `initializeBrowserConnection()`, `getBrowserModeConfigLoader()`, and `refreshBrowserAutomation()` that are used by IPC handlers and tests.
- Allows switching between headed/headless behavior in development, talking to the [`BrowserModeConfigLoader`](packages/infrastructure/config/BrowserModeConfig.ts:1) through IPC.
- Allows switching between headed/headless behavior in development, talking to the [`BrowserModeConfigLoader`](core/infrastructure/config/BrowserModeConfig.ts:1) through IPC.
- Displays the final result of a successful race creation as modeled by [`RaceCreationResult`](packages/domain/value-objects/RaceCreationResult.ts:1).
- Displays the final result of a successful race creation as modeled by [`RaceCreationResult`](core/domain/value-objects/RaceCreationResult.ts:1).
The companion app is intentionally a **single presentation layer implemented in this repo**, but the application and domain layers are structured so that other presentation layers (web client, backend orchestration service) can reuse the same automation engine via the same ports.
@@ -644,7 +644,7 @@ This subsection summarizes how the GridPilot Web App / Website and the companion
- League and season management, scheduling and calendars.
- Driver and team views, stats, rating, discovery and social features as described in the concept docs.
- Runs in browsers, talking to core platform services over HTTP or GraphQL.
- Produces configuration artifacts such as hosted-session definitions that can be mapped into [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) on the platform side.
- Produces configuration artifacts such as hosted-session definitions that can be mapped into [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) on the platform side.
**GridPilot Companion App (desktop presentation, this repo)**
@@ -657,9 +657,9 @@ This subsection summarizes how the GridPilot Web App / Website and the companion
**Communication pattern between website, platform and companion**
- A typical flow for a scheduled league race:
- The web app and core platform services use competition data (league, calendar, formats) to derive a [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) or equivalent structure server-side.
- The web app and core platform services use competition data (league, calendar, formats) to derive a [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) or equivalent structure server-side.
- The core platform stores and schedules these configs and can expose them via APIs.
- The companion app fetches or receives the relevant configs, calls into the application layer (for example [`StartAutomationSessionUseCase`](packages/application/use-cases/StartAutomationSessionUseCase.ts:1)) and executes them against iRacing through Playwright.
- The companion app fetches or receives the relevant configs, calls into the application layer (for example [`StartAutomationSessionUseCase`](core/application/use-cases/StartAutomationSessionUseCase.ts:1)) and executes them against iRacing through Playwright.
- Status and results flow back through overlays and events, and can be consumed both by the companion UI and by platform-side stats and rating services.
- This repo provides:
@@ -679,66 +679,66 @@ This section describes how a typical hosted-session automation run flows through
1.**Admin configures a session**
- In the companion UI, the admin fills out [`SessionCreationForm`](apps/companion/renderer/components/SessionCreationForm.tsx).
- The form builds a [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1)-compatible object and calls `window.electronAPI.startAutomation(config)`.
- The form builds a [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1)-compatible object and calls `window.electronAPI.startAutomation(config)`.
2.**IPC → main process**
- The preload script forwards this call to an IPC handler in [`ipc-handlers`](apps/companion/main/ipc-handlers.ts).
- The handler resolves the singleton [`DIContainer`](apps/companion/main/di-container.ts:1) and obtains:
- [`IAutomationEngine`](packages/application/ports/IAutomationEngine.ts:1) and [`ISessionRepository`](packages/application/ports/ISessionRepository.ts:1) behind the scenes.
- [`IAutomationEngine`](core/application/ports/IAutomationEngine.ts:1) and [`ISessionRepository`](core/application/ports/ISessionRepository.ts:1) behind the scenes.
- Creates a new [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1) by calling `AutomationSession.create(config)`, which validates the core invariants (non-empty session name, track, cars).
- Creates a new [`AutomationSession`](core/domain/entities/AutomationSession.ts:1) by calling `AutomationSession.create(config)`, which validates the core invariants (non-empty session name, track, cars).
- Calls `automationEngine.validateConfiguration(config)` to perform more detailed checks (e.g. compatibility with supported wizard flows).
- Persists the new session via [`ISessionRepository`](packages/application/ports/ISessionRepository.ts:1) (implemented by [`InMemorySessionRepository`](packages/infrastructure/repositories/InMemorySessionRepository.ts:1)).
- Persists the new session via [`ISessionRepository`](core/application/ports/ISessionRepository.ts:1) (implemented by [`InMemorySessionRepository`](core/infrastructure/repositories/InMemorySessionRepository.ts:1)).
- Returns a DTO to the IPC handler which is forwarded to the renderer.
4.**Browser and Playwright setup**
- The [`DIContainer`](apps/companion/main/di-container.ts:1) uses [`AutomationConfig`](packages/infrastructure/config/AutomationConfig.ts:1) and [`BrowserModeConfig`](packages/infrastructure/config/BrowserModeConfig.ts:1) to:
- The [`DIContainer`](apps/companion/main/di-container.ts:1) uses [`AutomationConfig`](core/infrastructure/config/AutomationConfig.ts:1) and [`BrowserModeConfig`](core/infrastructure/config/BrowserModeConfig.ts:1) to:
- Decide between `production`, `development`, `test` modes.
- Decide headed vs headless rendering.
- Potentially start a [`FixtureServer`](packages/infrastructure/adapters/automation/engine/FixtureServer.ts:1) in test/fixture modes.
- [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) connects to a browser and ensures the context is ready via `connect()` / `ensureBrowserContext()`.
- Potentially start a [`FixtureServer`](core/infrastructure/adapters/automation/engine/FixtureServer.ts:1) in test/fixture modes.
- [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) connects to a browser and ensures the context is ready via `connect()` / `ensureBrowserContext()`.
5.**Authentication and login**
- For real iRacing usage:
- [`CheckAuthenticationUseCase`](packages/application/use-cases/CheckAuthenticationUseCase.ts:1) and [`VerifyAuthenticatedPageUseCase`](packages/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1) verify whether the session is still valid.
- If not, the renderer triggers [`InitiateLoginUseCase`](packages/application/use-cases/InitiateLoginUseCase.ts:1) via IPC.
- [`CheckAuthenticationUseCase`](core/application/use-cases/CheckAuthenticationUseCase.ts:1) and [`VerifyAuthenticatedPageUseCase`](core/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1) verify whether the session is still valid.
- If not, the renderer triggers [`InitiateLoginUseCase`](core/application/use-cases/InitiateLoginUseCase.ts:1) via IPC.
- The Playwright adapter opens a headed browser window, navigates to the login page, and lets the admin log in manually.
- Once login is complete, [`PlaywrightAuthSessionService`](packages/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService.ts:1) stores cookies in [`SessionCookieStore`](packages/infrastructure/adapters/automation/auth/SessionCookieStore.ts:1), and future runs reuse them.
- Once login is complete, [`PlaywrightAuthSessionService`](core/infrastructure/adapters/automation/auth/PlaywrightAuthSessionService.ts:1) stores cookies in [`SessionCookieStore`](core/infrastructure/adapters/automation/auth/SessionCookieStore.ts:1), and future runs reuse them.
6.**Step-by-step wizard automation**
- The automation engine (implemented by [`AutomationEngineAdapter`](packages/infrastructure/adapters/automation/engine/AutomationEngineAdapter.ts:1) and backed by [`PlaywrightAutomationAdapter`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1)) proceeds through steps:
- The automation engine (implemented by [`AutomationEngineAdapter`](core/infrastructure/adapters/automation/engine/AutomationEngineAdapter.ts:1) and backed by [`PlaywrightAutomationAdapter`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1)) proceeds through steps:
- Navigate to hosted sessions.
- Open “Create a Race” and the hosted-session wizard.
- For each step (race information, server details, admins, cars, tracks, weather, race options, conditions):
- Ensure the correct page is active using [`PageStateValidator`](packages/domain/services/PageStateValidator.ts:1) and selectors from [`IRACING_SELECTORS`](packages/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1).
- Fill fields and toggles using [`IRacingDomInteractor`](packages/infrastructure/adapters/automation/dom/IRacingDomInteractor.ts:1).
- Click the correct “Next” / “Create Race” / “New Race” buttons, guarded by [`SafeClickService`](packages/infrastructure/adapters/automation/dom/SafeClickService.ts:1) and blocked-selector logic.
- Ensure the correct page is active using [`PageStateValidator`](core/domain/services/PageStateValidator.ts:1) and selectors from [`IRACING_SELECTORS`](core/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1).
- Fill fields and toggles using [`IRacingDomInteractor`](core/infrastructure/adapters/automation/dom/IRacingDomInteractor.ts:1).
- Click the correct “Next” / “Create Race” / “New Race” buttons, guarded by [`SafeClickService`](core/infrastructure/adapters/automation/dom/SafeClickService.ts:1) and blocked-selector logic.
- At each step, the Playwright adapter:
- Updates the overlay via `updateOverlay(step, message)`.
- Emits lifecycle events consumed by [`OverlaySyncService`](packages/application/services/OverlaySyncService.ts:1), which the companion uses to update [`SessionProgressMonitor`](apps/companion/renderer/components/SessionProgressMonitor.tsx).
- Emits lifecycle events consumed by [`OverlaySyncService`](core/application/services/OverlaySyncService.ts:1), which the companion uses to update [`SessionProgressMonitor`](apps/companion/renderer/components/SessionProgressMonitor.tsx).
7.**Checkout and confirmation**
- For flows that involve iRacing credits or non-zero prices:
- [`CheckoutPriceExtractor`](packages/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1) is used by the Playwright adapter to parse price and state from the wizard UI.
- [`ConfirmCheckoutUseCase`](packages/application/use-cases/ConfirmCheckoutUseCase.ts:1) sends a confirmation request to the renderer via [`ElectronCheckoutConfirmationAdapter`](packages/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts:1).
- [`CheckoutPriceExtractor`](core/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1) is used by the Playwright adapter to parse price and state from the wizard UI.
- [`ConfirmCheckoutUseCase`](core/application/use-cases/ConfirmCheckoutUseCase.ts:1) sends a confirmation request to the renderer via [`ElectronCheckoutConfirmationAdapter`](core/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts:1).
- [`CheckoutConfirmationDialog`](apps/companion/renderer/components/CheckoutConfirmationDialog.tsx) shows the admin the price and state, with an explicit timeout and cancel path.
- Only after explicit confirmation does the adapter simulate the checkout sequence (and in real mode, additional safeguards ensure no ToS-violating clicks occur).
8.**Completion and result**
- Once the final step is reached, [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1) transitions into a terminal state (`STOPPED_AT_STEP_18`, `FAILED`, etc.).
- The companion renderer may present a [`RaceCreationResult`](packages/domain/value-objects/RaceCreationResult.ts:1) via [`RaceCreationSuccessScreen`](apps/companion/renderer/components/RaceCreationSuccessScreen.tsx).
- Once the final step is reached, [`AutomationSession`](core/domain/entities/AutomationSession.ts:1) transitions into a terminal state (`STOPPED_AT_STEP_18`, `FAILED`, etc.).
- The companion renderer may present a [`RaceCreationResult`](core/domain/value-objects/RaceCreationResult.ts:1) via [`RaceCreationSuccessScreen`](apps/companion/renderer/components/RaceCreationSuccessScreen.tsx).
- The browser context is closed or re-used based on mode and configuration; debug artifacts may be written by the Playwright adapter for failed runs.
---
@@ -763,7 +763,7 @@ Although this repo focuses on automation and companion, it is deliberately shape
- The automation engine is designed so that a future league platform can:
- Generate [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) from league and calendar data (cars, tracks, formats) defined in the core competition services.
- Generate [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) from league and calendar data (cars, tracks, formats) defined in the core competition services.
- Trigger automation runs at scheduled times, with the admin supervising in the companion app.
- Use consistent, error-free sessions as the basis for reliable result capture and stats, supporting the narratives in [`DRIVERS.md`](docs/concept/DRIVERS.md), [`TEAMS.md`](docs/concept/TEAMS.md), [`RACING.md`](docs/concept/RACING.md) and [`STATS.md`](docs/concept/STATS.md).
@@ -831,7 +831,7 @@ In a future GridPilot platform:
- The **automation engine** in this repo would be used as a **hosted-session execution backend**:
- The platform would derive [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) objects from league/season metadata (cars, tracks, formats) defined in the platform.
- The platform would derive [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) objects from league/season metadata (cars, tracks, formats) defined in the platform.
- It would call into the automation layer via explicit use-cases or IPC/API, using the same ports used by the companion app today.
- The Electron companion may remain the primary operator UI, or an additional headless orchestration mode could be added (still respecting ToS and admin control).
@@ -846,13 +846,13 @@ In a future GridPilot platform:
The automation domain (sessions, steps, validation) is free of Electron/Playwright details, making it straightforward to embed into other hosts.
- **Ports for automation & auth**:
Using [`IAutomationEngine`](packages/application/ports/IAutomationEngine.ts:1), [`IScreenAutomation`](packages/application/ports/IScreenAutomation.ts:1), [`IAuthenticationService`](packages/application/ports/IAuthenticationService.ts:1) means new drivers (or alternative browser runtimes) can be introduced without changing the use-cases.
Using [`IAutomationEngine`](core/application/ports/IAutomationEngine.ts:1), [`IScreenAutomation`](core/application/ports/IScreenAutomation.ts:1), [`IAuthenticationService`](core/application/ports/IAuthenticationService.ts:1) means new drivers (or alternative browser runtimes) can be introduced without changing the use-cases.
- **Explicit checkout/confirmation path**:
The combination of [`CheckoutPrice`](packages/domain/value-objects/CheckoutPrice.ts:1), [`CheckoutState`](packages/domain/value-objects/CheckoutState.ts:1), [`CheckoutConfirmation`](packages/domain/value-objects/CheckoutConfirmation.ts:1) and the UI-side confirmation port aligns with the transparency and fairness requirements in [`ADMINS.md`](docs/concept/ADMINS.md) and [`RACING.md`](docs/concept/RACING.md).
The combination of [`CheckoutPrice`](core/domain/value-objects/CheckoutPrice.ts:1), [`CheckoutState`](core/domain/value-objects/CheckoutState.ts:1), [`CheckoutConfirmation`](core/domain/value-objects/CheckoutConfirmation.ts:1) and the UI-side confirmation port aligns with the transparency and fairness requirements in [`ADMINS.md`](docs/concept/ADMINS.md) and [`RACING.md`](docs/concept/RACING.md).
- **Overlay and lifecycle emitter**:
The overlay and [`IAutomationLifecycleEmitter`](packages/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) abstraction make it easy to:
The overlay and [`IAutomationLifecycleEmitter`](core/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) abstraction make it easy to:
- Drive visual overlays (like those described in admin QoL features) across different frontends.
- Feed telemetry into a central stats/ops UI for debugging, while keeping the engine itself small.
@@ -57,8 +57,8 @@ This track is grounded in the existing code and architecture:
- Hosted wizard flow and step orchestration (see `tests/e2e/steps/*` and `tests/e2e/workflows/*`).
- Auth and cookie/session management.
- Overlay lifecycle via [`IAutomationLifecycleEmitter`](packages/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) and [`OverlaySyncService`](packages/application/services/OverlaySyncService.ts:1).
- Checkout safety via [`CheckoutPriceExtractor`](packages/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1), [`ConfirmCheckoutUseCase`](packages/application/use-cases/ConfirmCheckoutUseCase.ts:1), [`ElectronCheckoutConfirmationAdapter`](packages/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts:1) and the renderer dialog.
- Overlay lifecycle via [`IAutomationLifecycleEmitter`](core/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) and [`OverlaySyncService`](core/application/services/OverlaySyncService.ts:1).
- Checkout safety via [`CheckoutPriceExtractor`](core/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1), [`ConfirmCheckoutUseCase`](core/application/use-cases/ConfirmCheckoutUseCase.ts:1), [`ElectronCheckoutConfirmationAdapter`](core/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts:1) and the renderer dialog.
@@ -68,14 +68,14 @@ This track is grounded in the existing code and architecture:
**Automation (this repo)**
- [ ] Stabilize wizard step orchestration:
- [ ] Review and align wizard-step domain rules with [`StepTransitionValidator`](packages/domain/services/StepTransitionValidator.ts:1).
- [ ] Review and align wizard-step domain rules with [`StepTransitionValidator`](core/domain/services/StepTransitionValidator.ts:1).
- [ ] Ensure `tests/e2e/steps/*` cover all 18 hosted wizard steps end to end.
- [ ] Harden [`WizardStepOrchestrator`](packages/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) behavior for retries and timeouts.
- [ ] Harden [`WizardStepOrchestrator`](core/infrastructure/adapters/automation/core/PlaywrightAutomationAdapter.ts:1) behavior for retries and timeouts.
- [ ] Strengthen page validation:
- [ ] Extend [`PageStateValidator`](packages/domain/services/PageStateValidator.ts:1) to cover edge cases found in real-hosted tests.
- [ ] Ensure selector sets in `packages/infrastructure/adapters/automation/dom/*` match current iRacing UI.
- [ ] Extend [`PageStateValidator`](core/domain/services/PageStateValidator.ts:1) to cover edge cases found in real-hosted tests.
- [ ] Ensure selector sets in `core/infrastructure/adapters/automation/dom/*` match current iRacing UI.
- [ ] Tighten auth/session flows:
- [ ] Verify [`CheckAuthenticationUseCase`](packages/application/use-cases/CheckAuthenticationUseCase.ts:1), [`InitiateLoginUseCase`](packages/application/use-cases/InitiateLoginUseCase.ts:1), and [`VerifyAuthenticatedPageUseCase`](packages/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1) match the constraints in [`CONCEPT.md`](docs/concept/CONCEPT.md) and [`RACING.md`](docs/concept/RACING.md).
- [ ] Verify [`CheckAuthenticationUseCase`](core/application/use-cases/CheckAuthenticationUseCase.ts:1), [`InitiateLoginUseCase`](core/application/use-cases/InitiateLoginUseCase.ts:1), and [`VerifyAuthenticatedPageUseCase`](core/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1) match the constraints in [`CONCEPT.md`](docs/concept/CONCEPT.md) and [`RACING.md`](docs/concept/RACING.md).
- [ ] Confirm cookie handling in `automation/auth/*` matches the lifecycle described in [`ARCHITECTURE.md`](docs/ARCHITECTURE.md).
- [ ] Companion baseline:
- [ ] Ensure the Electron app boots and connects reliably on supported platforms (see smoke tests in `tests/smoke/*`).
@@ -96,8 +96,8 @@ This track is grounded in the existing code and architecture:
**Automation (this repo)**
- [ ] Lifecycle events:
- [ ] Review events emitted by [`IAutomationLifecycleEmitter`](packages/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) and consumed by [`OverlaySyncService`](packages/application/services/OverlaySyncService.ts:1).
- [ ] Ensure all critical state transitions of [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1) are reflected in overlay events.
- [ ] Review events emitted by [`IAutomationLifecycleEmitter`](core/infrastructure/adapters/IAutomationLifecycleEmitter.ts:1) and consumed by [`OverlaySyncService`](core/application/services/OverlaySyncService.ts:1).
- [ ] Ensure all critical state transitions of [`AutomationSession`](core/domain/entities/AutomationSession.ts:1) are reflected in overlay events.
- [ ] Align overlay messaging with admin QoL themes in [`ADMINS.md`](docs/concept/ADMINS.md) (less repetitive work, more transparency).
@@ -119,11 +119,11 @@ This track is grounded in the existing code and architecture:
**Automation (this repo)**
- [ ] Enrich checkout detection:
- [ ] Validate selector logic and price parsing in [`CheckoutPriceExtractor`](packages/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1) against current iRacing UI.
- [ ] Ensure [`CheckoutState`](packages/domain/value-objects/CheckoutState.ts:1) covers all relevant button states.
- [ ] Validate selector logic and price parsing in [`CheckoutPriceExtractor`](core/infrastructure/adapters/automation/CheckoutPriceExtractor.ts:1) against current iRacing UI.
- [ ] Ensure [`CheckoutState`](core/domain/value-objects/CheckoutState.ts:1) covers all relevant button states.
- [ ] Harden confirmation logic:
- [ ] Confirm [`ConfirmCheckoutUseCase`](packages/application/use-cases/ConfirmCheckoutUseCase.ts:1) is the *only* entry point for automation that proceeds past a non-zero price.
- [ ] Ensure [`ElectronCheckoutConfirmationAdapter`](packages/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts:1) and [`CheckoutConfirmationDialog`](apps/companion/renderer/components/CheckoutConfirmationDialog.tsx:1) enforce explicit admin confirmation and timeouts.
- [ ] Confirm [`ConfirmCheckoutUseCase`](core/application/use-cases/ConfirmCheckoutUseCase.ts:1) is the *only* entry point for automation that proceeds past a non-zero price.
- [ ] Ensure [`ElectronCheckoutConfirmationAdapter`](core/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts:1) and [`CheckoutConfirmationDialog`](apps/companion/renderer/components/CheckoutConfirmationDialog.tsx:1) enforce explicit admin confirmation and timeouts.
- [ ] Failure paths:
- [ ] Verify that any parsing failure or ambiguous state results in a safe stop, not a blind click.
- [ ] Add tests to cover “weird but possible” UI states observed via fixtures.
@@ -143,11 +143,11 @@ This track is grounded in the existing code and architecture:
- [ ] Map additional hosted workflows:
- [ ] Identify additional iRacing hosted flows that align with admin QoL needs from [`ADMINS.md`](docs/concept/ADMINS.md) (e.g. practice-only, league-specific hosted sessions).
- [ ] Encode them as configurations on top of [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) where feasible.
- [ ] Encode them as configurations on top of [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) where feasible.
- [ ] Workflow templates:
- [ ] Provide a small set of reusable presets (e.g. “standard league race”, “test session”) that can later be populated by external services.
- [ ] Resilience work:
- [ ] Improve behavior under partial UI changes (selectors, labels) using the validation patterns from [`PageStateValidator`](packages/domain/services/PageStateValidator.ts:1).
- [ ] Improve behavior under partial UI changes (selectors, labels) using the validation patterns from [`PageStateValidator`](core/domain/services/PageStateValidator.ts:1).
**Success criteria**
@@ -195,7 +195,7 @@ Each phase is intentionally high-level to avoid going stale; details belong in f
- Implement league identity, schedules and season configuration:
- public league pages, schedules, rules, rosters (see sections 3 and 4 in [`CONCEPT.md`](docs/concept/CONCEPT.md)).
- admin tools for creating seasons, calendars, formats (mirroring [`RACING.md`](docs/concept/RACING.md)).
- Model leagues, seasons and events as first-class entities that can later produce [`HostedSessionConfig`](packages/domain/entities/HostedSessionConfig.ts:1) instances for this repo’s automation engine.
- Model leagues, seasons and events as first-class entities that can later produce [`HostedSessionConfig`](core/domain/entities/HostedSessionConfig.ts:1) instances for this repo’s automation engine.
For the iRacing hosted-session automation, confidence is provided by these concrete suites:
- **Domain/Application unit tests**
- Entities and value objects such as [`AutomationSession`](packages/domain/entities/AutomationSession.ts:1), [`SessionState`](packages/domain/value-objects/SessionState.ts:1), [`CheckoutState`](packages/domain/value-objects/CheckoutState.ts:1), [`CheckoutConfirmation`](packages/domain/value-objects/CheckoutConfirmation.ts:1), and [`RaceCreationResult`](packages/domain/value-objects/RaceCreationResult.ts:1).
- Use cases such as [`StartAutomationSessionUseCase`](packages/application/use-cases/StartAutomationSessionUseCase.ts:1), [`VerifyAuthenticatedPageUseCase`](packages/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1), [`CompleteRaceCreationUseCase`](packages/application/use-cases/CompleteRaceCreationUseCase.ts:1), and [`ConfirmCheckoutUseCase`](packages/application/use-cases/ConfirmCheckoutUseCase.ts:1).
- Entities and value objects such as [`AutomationSession`](core/domain/entities/AutomationSession.ts:1), [`SessionState`](core/domain/value-objects/SessionState.ts:1), [`CheckoutState`](core/domain/value-objects/CheckoutState.ts:1), [`CheckoutConfirmation`](core/domain/value-objects/CheckoutConfirmation.ts:1), and [`RaceCreationResult`](core/domain/value-objects/RaceCreationResult.ts:1).
- Use cases such as [`StartAutomationSessionUseCase`](core/application/use-cases/StartAutomationSessionUseCase.ts:1), [`VerifyAuthenticatedPageUseCase`](core/application/use-cases/VerifyAuthenticatedPageUseCase.ts:1), [`CompleteRaceCreationUseCase`](core/application/use-cases/CompleteRaceCreationUseCase.ts:1), and [`ConfirmCheckoutUseCase`](core/application/use-cases/ConfirmCheckoutUseCase.ts:1).
- One test per wizard step under [`tests/e2e/steps`](tests/e2e/steps:1), all using the shared [`StepHarness`](tests/e2e/support/StepHarness.ts:1) and [`FixtureServer`](packages/infrastructure/adapters/automation/engine/FixtureServer.ts:1).
- One test per wizard step under [`tests/e2e/steps`](tests/e2e/steps:1), all using the shared [`StepHarness`](tests/e2e/support/StepHarness.ts:1) and [`FixtureServer`](core/infrastructure/adapters/automation/engine/FixtureServer.ts:1).
- These validate DOM-level selectors / flows for each step (1–18) against fixture-backed HTML, and are considered canonical for step behavior.
- Workflow-focused tests under [`tests/e2e/workflows`](tests/e2e/workflows:1) that drive the `PlaywrightAutomationAdapter` + `WizardStepOrchestrator` across multiple steps using the fixture server.
- Example: [`steps-07-09-cars-flow.e2e.test.ts`](tests/e2e/workflows/steps-07-09-cars-flow.e2e.test.ts:1) exercises cross-step cars flow, while [`full-hosted-session.workflow.e2e.test.ts`](tests/e2e/workflows/full-hosted-session.workflow.e2e.test.ts:1) runs a full 1–18 workflow via [`MockAutomationEngineAdapter`](packages/infrastructure/adapters/automation/engine/MockAutomationEngineAdapter.ts:1) and [`StartAutomationSessionUseCase`](packages/application/use-cases/StartAutomationSessionUseCase.ts:1), asserting final `SessionState` and step position.
- Additional workflow scenarios cover mid-flow failure using [`MockBrowserAutomationAdapter`](packages/infrastructure/adapters/automation/engine/MockBrowserAutomationAdapter.ts:1), ensuring failure states and diagnostics are surfaced without emitting false confirmations.
- Example: [`steps-07-09-cars-flow.e2e.test.ts`](tests/e2e/workflows/steps-07-09-cars-flow.e2e.test.ts:1) exercises cross-step cars flow, while [`full-hosted-session.workflow.e2e.test.ts`](tests/e2e/workflows/full-hosted-session.workflow.e2e.test.ts:1) runs a full 1–18 workflow via [`MockAutomationEngineAdapter`](core/infrastructure/adapters/automation/engine/MockAutomationEngineAdapter.ts:1) and [`StartAutomationSessionUseCase`](core/application/use-cases/StartAutomationSessionUseCase.ts:1), asserting final `SessionState` and step position.
- Additional workflow scenarios cover mid-flow failure using [`MockBrowserAutomationAdapter`](core/infrastructure/adapters/automation/engine/MockBrowserAutomationAdapter.ts:1), ensuring failure states and diagnostics are surfaced without emitting false confirmations.
- Uses the real Playwright stack (adapter + `WizardStepOrchestrator` + `FixtureServer`) with auto navigation enabled (`__skipFixtureNavigation` forbidden).
- Drives a representative subset of steps (e.g., 1 → 3 → 7 → 9 → 13 → 17) and asserts each step lands on the expected wizard container via [`IRACING_SELECTORS`](packages/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1).
- Drives a representative subset of steps (e.g., 1 → 3 → 7 → 9 → 13 → 17) and asserts each step lands on the expected wizard container via [`IRACING_SELECTORS`](core/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1).
- **Step-level fixture E2Es with explicit mismatch path**
- Existing step suites under [`tests/e2e/steps`](tests/e2e/steps:1) now have two execution paths via [`StepHarness`](tests/e2e/support/StepHarness.ts:1):
@@ -1265,7 +1265,7 @@ These suites assume the same fixture server and Playwright wiring as the rest of
#### Selector ↔ fixture ↔ real DOM guardrail
For hosted-session automation, [`IRACING_SELECTORS`](packages/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1) must match **either**:
For hosted-session automation, [`IRACING_SELECTORS`](core/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1) must match **either**:
- The current `html-dumps-optimized` fixtures under [`html-dumps-optimized/iracing-hosted-sessions`](html-dumps-optimized/iracing-hosted-sessions:1), or
- The real-site DOM as exercised by the hosted-real tests above.
@@ -1287,7 +1287,7 @@ Manual workflow when the iRacing DOM changes:
3. Re-align selectors and tests:
- Update [`IRACING_SELECTORS`](packages/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1) to reflect the new DOM shape.
- Update [`IRACING_SELECTORS`](core/infrastructure/adapters/automation/dom/IRacingSelectors.ts:1) to reflect the new DOM shape.
- Fix any failing step/workflow E2Es under [`tests/e2e/steps`](tests/e2e/steps:1) and [`tests/e2e/workflows`](tests/e2e/workflows:1) so they again describe the canonical behavior.
- Re-run:
- `npm test`
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.