@inventure71/paddockjs 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/INSTALL_AND_UPDATE.md +31 -5
- package/README.md +34 -3
- package/docs/advanced_ai_pace.md +131 -0
- package/docs/advanced_physics_rebuild.md +166 -0
- package/docs/architecture.md +111 -30
- package/docs/cleanup_coverage.md +284 -0
- package/docs/component_inventory.md +32 -16
- package/docs/composable-layouts.md +2 -0
- package/docs/concepts.md +12 -1
- package/docs/custom_model_controller.md +1 -1
- package/docs/data_contract.md +33 -10
- package/docs/data_model.md +4 -2
- package/docs/efficiency_cleanup_2026-10-13.md +80 -0
- package/docs/getting-started.md +3 -0
- package/docs/grid_walk.md +80 -0
- package/docs/index.md +5 -2
- package/docs/keyboard_driving_fix.md +118 -0
- package/docs/limit_driving_2026-10-14.md +88 -0
- package/docs/loading.md +141 -0
- package/docs/maintainability_audit_2026-09-08.md +146 -0
- package/docs/racing_ai_improvements.md +145 -0
- package/docs/rules.md +43 -13
- package/docs/sense_contract.md +4 -1
- package/docs/system_specs.md +40 -12
- package/docs/testing-reliability-guide.md +67 -0
- package/docs/v11_improvements.md +108 -0
- package/package.json +23 -15
- package/src/api/MountedSimulatorComponents.js +101 -0
- package/src/api/PaddockSimulatorController.js +56 -81
- package/src/app/BrowserExpertAdapter.js +0 -6
- package/src/app/BrowserExpertExternalRenderer.js +72 -50
- package/src/app/ExternalTrackSnapshot.js +50 -0
- package/src/app/F1SimulatorApp.js +242 -297
- package/src/app/HostLifecycleEmitter.js +93 -0
- package/src/app/banners/raceDataBannerController.js +9 -4
- package/src/app/camera/cameraConstants.js +1 -1
- package/src/app/camera/cameraController.js +10 -13
- package/src/app/camera/cameraGeometry.js +1 -1
- package/src/app/controls/SimulatorViewControls.js +45 -0
- package/src/app/controls/workbenchBindings.js +64 -0
- package/src/app/controls/workbenchDisclosure.js +41 -0
- package/src/app/domBindings.js +21 -13
- package/src/app/gridWalk/GridWalkController.js +180 -0
- package/src/app/gridWalk/gridWalkCamera.js +88 -0
- package/src/app/gridWalk/gridWalkControls.js +24 -0
- package/src/app/gridWalk/gridWalkCrew.js +246 -0
- package/src/app/gridWalk/gridWalkLabels.js +104 -0
- package/src/app/gridWalk/gridWalkLayout.js +46 -0
- package/src/app/gridWalk/gridWalkNavigation.js +99 -0
- package/src/app/gridWalk/gridWalkProjectBanner.js +43 -0
- package/src/app/gridWalk/gridWalkSession.js +50 -0
- package/src/app/layoutSupport.js +2 -0
- package/src/app/raceOverlayClearanceSupport.js +21 -7
- package/src/app/readouts/carOverviewRenderer.js +9 -4
- package/src/app/readouts/readoutFormatters.js +1 -8
- package/src/app/readouts/telemetryRenderer.js +1 -3
- package/src/app/readouts/timingTowerRenderer.js +48 -50
- package/src/app/rendering/appAssets.js +8 -10
- package/src/app/rendering/carRenderer.js +27 -79
- package/src/app/rendering/displayUtils.js +0 -6
- package/src/app/rendering/expertSensorRenderer.js +1 -1
- package/src/app/rendering/replayGhostRenderer.js +4 -1
- package/src/app/rendering/trackRenderer.js +2 -2
- package/src/app/runtime/frameLoop.js +18 -17
- package/src/app/runtime/pixiStartupLifecycle.js +94 -0
- package/src/app/runtime/runtimeTiming.js +4 -1
- package/src/app/runtime/runtimeVisibility.js +7 -2
- package/src/config/cssValues.js +1 -1
- package/src/config/defaultOptions.js +12 -173
- package/src/config/restartOptions.js +1 -0
- package/src/config/runtimeSeed.js +10 -0
- package/src/config/simulatorDefaults.js +106 -0
- package/src/config/telemetryModules.js +20 -0
- package/src/config/theme/cssTokens.js +85 -0
- package/src/config/theme/themeCss.js +72 -0
- package/src/config/theme/themeInputs.js +155 -0
- package/src/config/theme/themeResolver.js +172 -0
- package/src/config/theme/themeSelectors.js +69 -0
- package/src/config/theme/themeTokens.js +257 -0
- package/src/config/theme/themeUtils.js +15 -0
- package/src/config/themeOptions.js +14 -830
- package/src/config/timingGapMode.js +0 -2
- package/src/config/uiOptions.js +53 -0
- package/src/data/championship.js +16 -158
- package/src/data/championshipDefaults.js +87 -0
- package/src/data/driverData.js +10 -20
- package/src/data/entryIdentity.js +67 -0
- package/src/data/entryPresentation.js +23 -0
- package/src/data/entryTypes.d.ts +160 -0
- package/src/data/index.d.ts +12 -195
- package/src/data/ratingScale.js +14 -0
- package/src/data/teamTypes.d.ts +23 -0
- package/src/data/trackTypes.d.ts +101 -0
- package/src/data/vehicleData.js +12 -23
- package/src/environment/actions.js +3 -2
- package/src/environment/controllerLoop.js +57 -44
- package/src/environment/controllerScheduler.js +30 -0
- package/src/environment/driverObservations.js +260 -0
- package/src/environment/driverReset.js +51 -0
- package/src/environment/episode.js +0 -1
- package/src/environment/evaluation.js +6 -90
- package/src/environment/evaluationTracker.js +100 -0
- package/src/environment/events.js +23 -0
- package/src/environment/index.d.ts +35 -91
- package/src/environment/metrics.js +3 -17
- package/src/environment/observationSchema.js +104 -0
- package/src/environment/observationVector.js +16 -115
- package/src/environment/observations.js +16 -316
- package/src/environment/options.js +5 -24
- package/src/environment/renderFrames.js +21 -0
- package/src/environment/resetOptions.js +41 -0
- package/src/environment/results.js +125 -0
- package/src/environment/rewards.js +10 -16
- package/src/environment/runtime.js +17 -300
- package/src/environment/scenarioOptions.js +90 -0
- package/src/environment/scenarioPlacements.js +70 -0
- package/src/environment/scenarioPresets.js +78 -0
- package/src/environment/scenarios.js +5 -236
- package/src/environment/scratch.js +18 -0
- package/src/environment/sensorOptions.js +20 -0
- package/src/environment/sensors/index.js +2 -556
- package/src/environment/sensors/indexedRayBands.js +0 -18
- package/src/environment/sensors/nearbyCars.js +18 -15
- package/src/environment/sensors/opponentRadar.js +3 -2
- package/src/environment/sensors/pitConnectorProximity.js +20 -0
- package/src/environment/sensors/rayBandTrace.js +1 -37
- package/src/environment/sensors/rayBatch.js +81 -0
- package/src/environment/sensors/rayConfig.js +26 -0
- package/src/environment/sensors/rayGeometry.js +0 -8
- package/src/environment/sensors/rayGuards.js +0 -6
- package/src/environment/sensors/rayOutputs.js +75 -0
- package/src/environment/sensors/rayQuery.js +110 -0
- package/src/environment/sensors/rayScratch.js +146 -0
- package/src/environment/sensors/sensorTargets.js +12 -4
- package/src/environment/sensors/surfaceRays.js +6 -61
- package/src/environment/sensors/trackRays.js +7 -80
- package/src/environment/simulationSetup.js +30 -0
- package/src/environment/specs.js +15 -109
- package/src/index.d.ts +43 -202
- package/src/index.js +28 -6
- package/src/placeholder/index.js +1 -8
- package/src/rendering/displayLifecycle.js +6 -0
- package/src/rendering/proceduralTrackAsset.js +1 -1
- package/src/rendering/renderSnapshot.js +3 -0
- package/src/rendering/track/finishLineRenderer.js +1 -1
- package/src/rendering/track/gridRenderer.js +1 -1
- package/src/rendering/track/offsetStrokeSafety.js +2 -2
- package/src/rendering/track/pitLaneRenderer.js +1 -1
- package/src/rendering/track/trackMaterialRenderer.js +4 -4
- package/src/rendering/track/trackRenderConstants.js +0 -1
- package/src/rendering/track/trackRenderGeometry.js +1 -7
- package/src/simulation/collisionGeometry.js +12 -20
- package/src/simulation/driver/advancedPathControls.js +53 -0
- package/src/simulation/driver/advancedRacePace.js +112 -0
- package/src/simulation/driver/advancedRacingControls.js +61 -0
- package/src/simulation/driver/advancedRacingEnvelope.js +255 -0
- package/src/simulation/driver/advancedRacingSteering.js +76 -0
- package/src/simulation/driver/advancedRacingTiming.js +16 -0
- package/src/simulation/driver/arcadeRacePace.js +83 -0
- package/src/simulation/driver/arcadeRacingControls.js +111 -0
- package/src/simulation/driver/arcadeRacingEnvelope.js +63 -0
- package/src/simulation/driver/driverControlConstants.js +0 -2
- package/src/simulation/driver/driverController.js +16 -5
- package/src/simulation/driver/edgeRecovery.js +2 -3
- package/src/simulation/driver/racingControls.js +10 -396
- package/src/simulation/driver/racingDriverProfile.js +48 -0
- package/src/simulation/driver/racingLinePlan.js +54 -20
- package/src/simulation/driver/rejoinControls.js +59 -112
- package/src/simulation/driver/safetyCarControls.js +12 -0
- package/src/simulation/driver/trafficScan.js +136 -27
- package/src/simulation/participants/participantInteractions.js +24 -15
- package/src/simulation/pit/pitCarPlacement.js +29 -0
- package/src/simulation/pit/pitFlow.js +8 -30
- package/src/simulation/pit/pitIntent.js +4 -3
- package/src/simulation/pit/pitOccupancy.js +2 -2
- package/src/simulation/pit/pitQueue.js +2 -18
- package/src/simulation/pit/pitRouteMovement.js +1 -36
- package/src/simulation/pit/pitRouting.js +5 -81
- package/src/simulation/pit/pitService.js +3 -32
- package/src/simulation/pit/pitServiceConstants.js +1 -0
- package/src/simulation/pit/pitServiceProgress.js +34 -0
- package/src/simulation/pit/pitSnapshots.js +8 -4
- package/src/simulation/pit/pitState.js +1 -5
- package/src/simulation/race/classification.js +1 -8
- package/src/simulation/race/raceFinish.js +3 -8
- package/src/simulation/race/raceOrder.js +2 -13
- package/src/simulation/race/raceProgress.js +6 -20
- package/src/simulation/race/raceSetup.js +1 -1
- package/src/simulation/race/raceStep.js +20 -11
- package/src/simulation/race/redFlag.js +2 -4
- package/src/simulation/race/safetyCar.js +5 -9
- package/src/simulation/race/stalledDnf.js +2 -4
- package/src/simulation/raceSimulation.js +6 -38
- package/src/simulation/replay/replayGhosts.js +44 -32
- package/src/simulation/rules/collisionSteward.js +0 -14
- package/src/simulation/rules/penaltyActions.js +37 -0
- package/src/simulation/rules/penaltyLedger.js +8 -1
- package/src/simulation/rules/pitLaneSpeedingSteward.js +1 -1
- package/src/simulation/rules/rulesReview.js +20 -16
- package/src/simulation/rules/trackLimitsSteward.js +2 -2
- package/src/simulation/simMath.js +4 -0
- package/src/simulation/snapshots/raceSnapshots.js +30 -11
- package/src/simulation/timing/drsState.js +8 -0
- package/src/simulation/timing/drsTiming.js +2 -4
- package/src/simulation/timing/lapTelemetry.js +7 -4
- package/src/simulation/timing/sectorPerformance.js +14 -6
- package/src/simulation/timing/timingLines.js +12 -6
- package/src/simulation/track/pitLaneAccess.js +2 -2
- package/src/simulation/track/pitLaneLayout.js +4 -135
- package/src/simulation/track/pitLaneModel.js +70 -0
- package/src/simulation/track/pitLaneState.js +0 -1
- package/src/simulation/track/pitServiceLayout.js +121 -0
- package/src/simulation/track/proceduralTrack.js +77 -0
- package/src/simulation/track/spatialQueries.js +76 -31
- package/src/simulation/track/trackBuilder.js +54 -0
- package/src/simulation/track/trackConstants.js +0 -22
- package/src/simulation/track/trackMath.js +4 -29
- package/src/simulation/track/trackModel.js +12 -240
- package/src/simulation/track/trackModelCache.js +105 -0
- package/src/simulation/track/trackNearestQueries.js +1218 -0
- package/src/simulation/track/trackQueryConstants.js +3 -0
- package/src/simulation/track/trackQueryConstruction.js +368 -0
- package/src/simulation/track/trackQueryIndex.js +12 -1933
- package/src/simulation/track/trackQuerySegments.js +174 -0
- package/src/simulation/track/trackQueryStats.js +12 -0
- package/src/simulation/track/trackRayQueries.js +165 -0
- package/src/simulation/vehicle/advancedContactResponse.js +89 -0
- package/src/simulation/vehicle/advancedTireForces.js +92 -0
- package/src/simulation/vehicle/advancedVehicleModel.js +65 -0
- package/src/simulation/vehicle/advancedVehiclePhysics.js +127 -0
- package/src/simulation/vehicle/contactResolution.js +23 -9
- package/src/simulation/vehicle/mainTrackWheelSurface.js +2 -13
- package/src/simulation/vehicle/pitWheelSurface.js +0 -12
- package/src/simulation/vehicle/runoffResponse.js +2 -4
- package/src/simulation/vehicle/sampledWheelSurface.js +266 -0
- package/src/simulation/vehicle/vehicleGeometry.js +85 -103
- package/src/simulation/vehicle/vehicleKinematics.js +10 -0
- package/src/simulation/vehicle/vehiclePhysics.js +42 -196
- package/src/simulation/vehicle/vehicleSnapshots.js +18 -6
- package/src/simulation/vehicle/vehicleState.js +5 -3
- package/src/simulation/vehicle/wheelSurface.js +13 -432
- package/src/simulation/vehicle/wheelSurfaceCache.js +55 -0
- package/src/simulation/vehicle/wheelSurfaceSummary.js +101 -0
- package/src/styles.css +173 -19
- package/src/ui/bannerTemplates.js +4 -2
- package/src/ui/cameraControlsTemplate.js +4 -2
- package/src/ui/gridWalkTemplate.js +29 -0
- package/src/ui/htmlEscaping.js +8 -0
- package/src/ui/raceCanvasTemplate.js +3 -2
- package/src/ui/shellTemplate.js +3 -0
- package/src/ui/telemetryDrawerTemplate.js +4 -2
- package/src/ui/telemetryTemplates.js +3 -22
- package/src/ui/templateUtils.js +2 -8
- package/src/ui/viewControlsTemplate.js +21 -0
- package/examples/train-basic-policy.mjs +0 -276
- package/examples/trainingData.mjs +0 -133
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Advanced lab keyboard driving
|
|
2
|
+
|
|
3
|
+
> Historical implementation report. Website source paths below predate the single-site migration. Current demo and engineering examples live under `site/src/demo/` and `site/src/showcase/`; see [Architecture](architecture.md) for current ownership.
|
|
4
|
+
|
|
5
|
+
## Scope and ownership
|
|
6
|
+
|
|
7
|
+
This change fixes manual driving in the demo's `#expert` lab. It preserves the
|
|
8
|
+
vehicle integrators, both AI controllers, normalized public policy actions,
|
|
9
|
+
observation precision, package layout and automatic arcade demos.
|
|
10
|
+
|
|
11
|
+
- `demo/src/runtime/expertKeyboard.js` owns held keys, progressive key travel,
|
|
12
|
+
pedal commands, focus cleanup and human-only traction assistance. Its only
|
|
13
|
+
vehicle inputs are the active observation's speed, grip usage and applied
|
|
14
|
+
throttle; outputs remain ordinary normalized actions.
|
|
15
|
+
- `demo/src/runtime/expertFrameScheduler.js` owns 60 Hz wall-time pacing and
|
|
16
|
+
cancellation. It preserves deadlines across display frames and discards
|
|
17
|
+
accumulated delay after a stall. It has no simulation or input state access.
|
|
18
|
+
- `demo/src/runtime/expertLab.js` supplies that scheduler to the existing
|
|
19
|
+
controller loop. The public loop's default scheduler remains unchanged.
|
|
20
|
+
|
|
21
|
+
## Verified causes and bounded fixes
|
|
22
|
+
|
|
23
|
+
1. The lab used one fixed 1/60-second simulation step per animation callback.
|
|
24
|
+
The observed browser delivered 120 callbacks in 987.5 ms, making manual
|
|
25
|
+
driving approximately twice as fast as real time. The explicit lab scheduler
|
|
26
|
+
produces 60 steps/second on 60, 120, 144 and 165 Hz display schedules. It never
|
|
27
|
+
performs multiple catch-up steps in one callback. Slow rendering may still
|
|
28
|
+
slow playback; it does not accelerate input after a stall.
|
|
29
|
+
2. The keyboard ramped an already speed-limited steering angle. At 200 km/h,
|
|
30
|
+
its allowed normalized lock is only about 0.047, reached from center in about
|
|
31
|
+
0.052 seconds at the old 0.9/second rate. A short tap therefore reached full
|
|
32
|
+
allowed steering. The controller now ramps normalized key travel first and
|
|
33
|
+
then applies the existing speed-dependent lock. Full held-key lock is
|
|
34
|
+
preserved, while brief taps are small at every speed.
|
|
35
|
+
3. Holding the digital accelerator while turning could saturate rear tire
|
|
36
|
+
forces and spin the car. A fixed steering-dependent throttle reduction was
|
|
37
|
+
tested and rejected because it still spun at 30–100 km/h. The retained
|
|
38
|
+
keyboard assistance reduces throttle from observed applied demand when
|
|
39
|
+
reported grip usage exceeds 0.9, reserving a margin of 0.85 divided by that
|
|
40
|
+
usage. Normal progressive throttle recovery resumes as grip permits. This
|
|
41
|
+
assistance does not steer toward the track, write vehicle state, add grip or
|
|
42
|
+
alter the commands received from external policies.
|
|
43
|
+
|
|
44
|
+
## Measurements
|
|
45
|
+
|
|
46
|
+
Before/after steering maneuvers used the same normalized demo car, asphalt
|
|
47
|
+
contact patches, seed 171, track seed 7301, fixed 1/60-second integration,
|
|
48
|
+
2-frame keyboard action repeat and disabled tire degradation. Each coasting
|
|
49
|
+
maneuver held right for 0.3 seconds and settled for 0.7 seconds. These are
|
|
50
|
+
handling measurements, not CPU-performance improvements or lap-time claims.
|
|
51
|
+
|
|
52
|
+
| Initial speed | Old peak lateral acceleration | New peak lateral acceleration | Old heading change | New heading change |
|
|
53
|
+
| --- | --- | --- | --- | --- |
|
|
54
|
+
| 80 km/h | 1.35 g | 0.42 g | 10.3° | 2.7° |
|
|
55
|
+
| 150 km/h | 1.60 g | 0.39 g | 8.0° | 1.7° |
|
|
56
|
+
| 250 km/h | 1.72 g | 0.36 g | 4.9° | 1.0° |
|
|
57
|
+
|
|
58
|
+
Combined accelerator/steering characterization covered four car configurations,
|
|
59
|
+
five initial speeds (30, 60, 100, 160 and 220 km/h), and 0.3-second taps or
|
|
60
|
+
2-second holds followed by 0.7-second recovery. The retained normal-throttle-rise
|
|
61
|
+
feedback variant kept peak body slip below 0.057 radians across all 40 cases.
|
|
62
|
+
The original controls reached approximately 3.14 radians. A slower throttle-rise
|
|
63
|
+
variant reduced pedal cycling but added another steering-dependent rule without
|
|
64
|
+
improving the slip envelope, so it was not retained.
|
|
65
|
+
|
|
66
|
+
In the actual 120 Hz browser, the old 300 ms coasting right tap reached 132%
|
|
67
|
+
reported grip usage and left the track during the following 700 ms. With the
|
|
68
|
+
new controls and pacing, the same input reached approximately 23% reported usage,
|
|
69
|
+
settled on track, and the lab displayed approximately 60 FPS. A combined
|
|
70
|
+
accelerator/right/left/release/braking sequence stayed on track. Losing focus clears held inputs but does not pause the race; with two-frame
|
|
71
|
+
action repeat, one previously held action frame can precede neutral input.
|
|
72
|
+
Tire saturation indicators can still appear transiently; this is assistance, not immunity from
|
|
73
|
+
spins, missed corners or crashes.
|
|
74
|
+
|
|
75
|
+
## Verification
|
|
76
|
+
|
|
77
|
+
Baseline `npm run check` passed: 1,051 fast tests, 93 slow skips, public types,
|
|
78
|
+
dry pack, packed consumer, bundle boundaries, showcase/demo builds and browser
|
|
79
|
+
smokes. Existing build chunk-size warnings are unrelated. No pre-existing gate
|
|
80
|
+
failure was found.
|
|
81
|
+
|
|
82
|
+
Thirteen physical keyboard regressions pass; substituting the preserved original
|
|
83
|
+
keyboard handler makes eleven fail. These tests use actual demo car normalization
|
|
84
|
+
and snapshot-derived body senses through keyboard actions, public action
|
|
85
|
+
normalization and the unmodified advanced integrator. They cover mirrored taps,
|
|
86
|
+
combined acceleration/turning, release, countersteering and exact replay.
|
|
87
|
+
|
|
88
|
+
Final `npm run check` passed: 1,078 fast tests, 93 slow skips, public types,
|
|
89
|
+
pack/consumer/bundle boundaries, both builds, quick Chromium and the expanded
|
|
90
|
+
demo driving smoke. `npm run check:release` passed all 1,171 tests across 64 files, the same package
|
|
91
|
+
gates, the full Chromium matrix and the expanded demo smoke. Input tests cover speed-independent short key taps,
|
|
92
|
+
countersteering, release, observed-load throttle relief, focus/visibility and
|
|
93
|
+
disposal; scheduler coverage includes refresh rates, long stalls and cancellation.
|
|
94
|
+
The demo smoke now physically presses left/right and checks settling and track
|
|
95
|
+
surface, then checks that accelerator input clears when focus leaves the lab.
|
|
96
|
+
|
|
97
|
+
Reproduction artifacts for this session are in
|
|
98
|
+
`/tmp/paddockjs-keyboard-20260909/` and
|
|
99
|
+
`/tmp/paddockjs-manual-steering-20260909/`. Existing repository changes were
|
|
100
|
+
preserved; no Git or GitHub mutation is part of this fix.
|
|
101
|
+
|
|
102
|
+
## Changed files and handoff
|
|
103
|
+
|
|
104
|
+
The three demo runtime files above contain the control changes.
|
|
105
|
+
`src/__tests__/expertKeyboard.test.js`, `expertKeyboardDriving.test.js`,
|
|
106
|
+
`expertFrameScheduler.test.js` and `demoLifecycle.test.js` verify input, physical
|
|
107
|
+
response, cadence and wiring. `smoke/demo-smoke.mjs` verifies actual browser keys.
|
|
108
|
+
`demo/index.html`, `demo/README.md`, `docs/rules.md`, `docs/architecture.md` and this
|
|
109
|
+
report document the new human-only behavior.
|
|
110
|
+
|
|
111
|
+
Read-only Git inspection: branch `v11` at `fedff4eec4e213f910748d67282542120454354c`,
|
|
112
|
+
123 modified tracked files, 53 untracked entries and an empty index. The locally
|
|
113
|
+
recorded upstream comparison is 0 ahead / 0 behind; no fetch was performed. All
|
|
114
|
+
117 simulation JavaScript files hash-identically to this task's baseline.
|
|
115
|
+
|
|
116
|
+
Review and staging/commit proposals remain separate approval-gated Git actions.
|
|
117
|
+
The repository already contains extensive ongoing work; this fix does not claim
|
|
118
|
+
the entire repository is clean or ready to publish.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Skill-dependent limit driving — 2026-10-14
|
|
2
|
+
|
|
3
|
+
Work is isolated in `PaddockJS-v11-improvements`, branch `v11-improvements`, from approved v11 commit `5bd587528a1b95cd78dd77768129e71a2b09a0e6`. Original v11 remains untouched. This report follows the completed efficiency/cleanup pass; it does not replace that pass’s measured resource limitations.
|
|
4
|
+
|
|
5
|
+
## Goal and boundaries
|
|
6
|
+
|
|
7
|
+
Built-in racers should exploit their actual vehicle’s speed, braking and handling capabilities. Ability and consistency determine control precision; risk tolerance and aggression determine willingness to use smaller margins. Strong cautious and strong aggressive drivers both exist. Risk is not skill, and incidents are not deliberately scheduled.
|
|
8
|
+
|
|
9
|
+
Vehicle force/integration equations, setup coefficients, action limits, deterministic seed ordering, model observation precision and the 330 km/h ceiling are preserved. Only racing policy, additive physical prediction/inverse helpers, normalized consistency retention, and timing-line boundary correctness change. Recovery, safety-car and pit routing retain their ownership. No host-specific behavior or new public options are introduced. Existing legacy vehicle fallbacks remain: when explicit vehicle coefficients are omitted, car creation derives power from pace and grip partly from racecraft. Use explicit vehicle entries for comparisons that must hold the car identical across skills.
|
|
10
|
+
|
|
11
|
+
## Implementation
|
|
12
|
+
|
|
13
|
+
- `racingDriverProfile`: existing pace/racecraft → ability; consistency → bounded continuous distance-based judgement variation; aggression/risk tolerance → smaller chosen margins. No RNG calls, new per-car controller history, extra power or grip.
|
|
14
|
+
- `advancedRacingEnvelope`: transferred four-contact capacities, yaw-balanced limiting axle, equal rear drive and 57/43 brake allocation. Safeguarded root solving finds nonzero feasible braking windows near front-axle saturation.
|
|
15
|
+
- `advancedRacingSteering`: velocity-oriented pursuit and inverse nonlinear brush slip, including current-pedal front force projection. Steering remains a normal rate-limited physical wheel-angle request.
|
|
16
|
+
- `advancedRacingTiming` / pace: shared pursuit/yaw response; contiguous curvature preview. The braking recurrence counts only distance outside its pursuit, response, driver anticipation and one-sample reserve.
|
|
17
|
+
- Arcade: actual model corner and longitudinal limits plus racing-only 8–35 m smooth pursuit horizon. Arcade has no fictitious combined friction circle.
|
|
18
|
+
- Timing: exact forward half-open line boundaries replace a tolerance dead zone that could permanently omit a lap timestamp.
|
|
19
|
+
|
|
20
|
+
## Verification evidence
|
|
21
|
+
|
|
22
|
+
The final source hash is `8f7349f261feda96cceb40647e645636ba270b1fb7d3ef6d151707964007c5c0`; envelope harness hash is `9d8d1d433086c97fa4c8742a4b3ed72b83b6a16ff633c97857ebe8262deeb564`. Across both modes, five profiles × six development/held-out tracks × two repeats produce **120 full three-lap solo runs: all finished, no off-road time or DNFs, all 60 repeat pairs exact**. Profiles are novice, expert, skilled-cautious, expert-risky and skilled-risky. The cautious/expert-risky pair has identical ability, consistency and vehicle coefficients; only personality changes. The less consistent skilled-risky profile is slower despite greater risk willingness.
|
|
23
|
+
|
|
24
|
+
Same-car advanced expert flying-lap means on tracks 12 / 7110 / 7203 are **138.59 → 122.11 s**, **167.50 → 147.39 s**, **103.00 → 92.49 s** (about 10–12% faster). Final novice means are 134.96 / 164.32 / 100.59 s. Cautious experts average 122.64 / 148.13 / 92.81 s; aggressive experts 121.93 / 147.15 / 92.37 s. Risk influences pace modestly and does not manufacture ability.
|
|
25
|
+
|
|
26
|
+
The six actual worn/pitting demo fields run twice in each mode: **24 final executions, all 240 car results finished without DNF, all 12 repeat pairs exact**, compared against 24 baseline executions. First-repeat results below count every field interval; off-road time uses wheel-derived `onTrack=false` outside pit routing, which differs from all-four-wheels white-line stewarding. Contacts are physical event counts, not penalty consequences.
|
|
27
|
+
|
|
28
|
+
| Mode / field | Field finish seconds, baseline → final | Off-road seconds | Contacts | Final finishers |
|
|
29
|
+
| --- | --- | --- | --- | --- |
|
|
30
|
+
| advanced / hero | 879.13 → 780.93 | 0.000 → 0.000 | 2 → 1 | 10/10 |
|
|
31
|
+
| advanced / components | 596.77 → 544.07 | 0.050 → 0.083 | 0 → 2 | 10/10 |
|
|
32
|
+
| advanced / dashboard | 524.13 → 479.13 | 0.000 → 0.100 | 0 → 1 | 10/10 |
|
|
33
|
+
| advanced / timing-overlay | 601.02 → 551.95 | 0.000 → 0.000 | 0 → 0 | 10/10 |
|
|
34
|
+
| advanced / compact-race | 483.50 → 445.15 | 0.000 → 0.117 | 1 → 2 | 10/10 |
|
|
35
|
+
| advanced / full-dashboard | 354.67 → 340.07 | 0.000 → 1.983 | 4 → 5 | 10/10 |
|
|
36
|
+
| arcade / hero | 716.78 → 658.53 | 0.050 → 0.000 | 6 → 10 | 10/10 |
|
|
37
|
+
| arcade / components | 500.45 → 461.40 | 2.350 → 0.000 | 8 → 12 | 10/10 |
|
|
38
|
+
| arcade / dashboard | 448.35 → 406.95 | 0.450 → 0.000 | 7 → 8 | 10/10 |
|
|
39
|
+
| arcade / timing-overlay | 493.62 → 465.40 | 0.000 → 0.000 | 5 → 12 | 10/10 |
|
|
40
|
+
| arcade / compact-race | 407.85 → 368.57 | 0.333 → 0.000 | 7 → 5 | 10/10 |
|
|
41
|
+
| arcade / full-dashboard | 313.92 → 289.62 | 1.017 → 0.533 | 6 → 3 | 10/10 |
|
|
42
|
+
|
|
43
|
+
All fields finish faster. Advanced aggregate first-repeat off-road time rises 0.050 → 2.283 s and contacts 7 → 11; arcade off-road time falls 4.200 → 0.533 s while contacts rise 39 → 50. These regressions in contacts are retained as a tradeoff; this is not a claim of universally cleaner racing. There are no scheduled accidents or forced contact effects.
|
|
44
|
+
|
|
45
|
+
A read-only advanced integrator hook observes every one of four contacts in every substep. On minimum supported Node 20.19, observed/unobserved final expert runs have identical trajectory, event and behavior hashes across three complete tracks and two repeats. Contact counts equal exactly 16 per active fixed frame. Final force equations match the prior accepted implementation exactly across 288 contact cases and 2,400 integrated car frames (hash `c42a9690aba8b69920558544f166c36fadc52fbe3f802ffbb9ec826fea8509a8`).
|
|
46
|
+
|
|
47
|
+
Phase-specific delivered forces, pedal occupancy, speed-ceiling fractions, slips and denominators are in the JSONL records. Advanced expert corner delivered combined utilization is 0.681 / 0.676 / 0.701; steady corner utilization 0.789 / 0.752 / 0.727, with short steady windows. Actual-integrator circle tests additionally verify both turn directions at 93% of physical corner speed, track within half a car width and deliver at least 90% of actual-speed turning demand. These are bounded measurements, not a global optimal-lap certificate.
|
|
48
|
+
|
|
49
|
+
## Resource cost
|
|
50
|
+
|
|
51
|
+
Invocation-local input reuse refreshes surfaces, nominal loads, drag and rolling characteristics on every public helper call, then reuses them inside its transfer/bracket passes. Surface scans drop 60 → 4 straight, 156 → 4 mixed, 28 → 4 brake preview, and 20 → 4 corner estimation. One thousand helper cases and three tracks × 1,800 frames × four cars retain exact outputs, including immediate DRS, tire and surface changes. All 120 final solo records also have identical trajectory/event/behavior/metric hashes to the uncached candidate.
|
|
52
|
+
|
|
53
|
+
Five alternating fresh-process pairs share identical serialized real 20-car states and 2,000 production driver decisions. Median policy CPU is **124.376 → 113.352 ms** after reuse (8.86% less); wall time **89.813 → 76.958 ms** (14.31% less), with identical control hashes. The old pre-limit policy uses **43.521 ms**: the optimized advanced policy still costs **2.60×** the old policy in this fixture. These are policy-only CPU measurements, not whole browser/physics CPU or frame rate.
|
|
54
|
+
|
|
55
|
+
## Hardware frame measurements
|
|
56
|
+
|
|
57
|
+
An isolated headed Chrome uses `ANGLE Metal Renderer: Apple M4 Pro`, fixed 1,280 × 800 viewport, DPR/renderer density 2 and identical 2,450 × 1,210 pixel canvases. Each 30-second sample uses ten cars, the complete broadcast host, same seeds/setup, a 10-second fixed-step warmup, leader camera and settled visible runtime. The initial paths differ because the driving policy changes; this is not a claim of identical post-warmup poses. No tests/field benchmarks run during frame sampling; typed-array instrumentation and CDP metrics are restored afterward.
|
|
58
|
+
|
|
59
|
+
| Mode | FPS, baseline → final | Draw p95 ms | Draw p99 ms | Mean update work ms | Draw gaps >50 ms |
|
|
60
|
+
| --- | --- | --- | --- | --- | --- |
|
|
61
|
+
| arcade1 | 58.53 → 58.49 | 23.1 → 23.6 | 25.5 → 26.1 | 0.998 → 0.911 | 0 → 0 |
|
|
62
|
+
| advanced1 | 58.54 → 58.60 | 23.6 → 23.4 | 25.7 → 26.1 | 0.851 → 1.379 | 0 → 0 |
|
|
63
|
+
| advanced10 | 58.59 → 58.59 | 20.4 → 25.8 | 26.5 → 27.9 | 2.034 → 5.150 | 0 → 0 |
|
|
64
|
+
|
|
65
|
+
FPS is maintained in the measured hardware configuration. Advanced update work rises and 10× draw tail times worsen, despite no >50 ms gaps or long tasks. No browser CPU/FPS improvement is claimed; slower devices and larger fields can expose this added controller cost. Arcade’s single paired callback decrease is not a general performance claim. The collaborative preview reports SwiftShader and is excluded from hardware timing. An off-screen probe correctly paused with zero draw frames and is excluded; the first cold baseline is retained separately, with the settled repeat used above.
|
|
66
|
+
|
|
67
|
+
## Package and interaction gates
|
|
68
|
+
|
|
69
|
+
`npm run check` passes 81 fast files / 1,254 tests, with 93 intentional slow skips, public types, dry pack, fresh packed consumer/build, bundle boundaries, both builds, quick Chromium showcase smoke and complete demo smoke. Minimum Node20.19 passes the 74 focused new/affected tests and full observed/unobserved advanced characterization. The final standard runtime benchmark validates all 23 cases. `npm run check:release` passes all 81 exhaustive test batches / 1,347 tests, four dependency audits with zero vulnerabilities, public types, dry pack, fresh packed consumer/build, bundle boundaries, both builds, the full Chromium showcase matrix and complete demo smoke.
|
|
70
|
+
|
|
71
|
+
Native interaction verifies telemetry open/close, timing reveal, Budget Buddy selection, interval→leader gap switching and Overview camera at 390 × 844. Document width remains 390 px with all ten rows. An open telemetry drawer intentionally overlays timing controls; the interaction closes the drawer before selecting/toggling the board. Package-owned sizing is untouched. Raw successful readback is `native-interaction-verified.txt`.
|
|
72
|
+
|
|
73
|
+
All source changes precede the final gates. Subsequent edits only record evidence; final documentation and whitespace checks are rerun. Original v11 remains clean at the approved starting commit; candidate changes remain uncommitted with no upstream. No remote fetch, commit or publication occurs. Raw frozen-source experiments and final measurements are under `/tmp/paddock-v11-limit-driving-20261014/`; observational harnesses under `scripts/` are excluded from package runtime.
|
|
74
|
+
|
|
75
|
+
The release gate’s old natural-kerb assertion was found to depend on overshoot: the baseline chassis moved 2.45 m beyond its requested line before touching a kerb. The shorter pursuit follows its intended line more closely. The 90-second legal-surface and >180 kph mean-pace requirements remain; both-side public-state placement tests now directly verify two outer wheels on legal kerb, real AI/physics motion, bounded controls, speed and return to asphalt. No apex change was made solely to recreate overshoot.
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
## Rejected approaches and limits
|
|
79
|
+
|
|
80
|
+
Raising the old static grip multiplier alone caused excursions/retirements. Front slip feedforward alone also failed. A shifted preview origin could skip nearby bends and accelerate into a corner; extra constant anticipation hid that defect in some solo races but did not pass full fields. The accepted preview keeps near-field constraints contiguous and reserves response distance. A tighter reserve was quicker solo but worse in traffic; an adaptive brush-slope predictor added cost and conservatism without superior field evidence.
|
|
81
|
+
|
|
82
|
+
Higher raw `gripUsage` is not proof of better delivered force. The nonlinear brush model can report demand above one before actual lateral force reaches contact capacity. Delivered utilization is measured independently from the integrator. Phase-specific steady tight-corner windows can be sparse; no claim of continuous 100% grip use or globally optimal racing lines is made. Top-speed, engine and traffic constraints also prevent a meaningful 100% grip expectation on every bend.
|
|
83
|
+
|
|
84
|
+
Arcade pursuit validation against its preceding candidate reduced six-field aggregate off-road time 46.517 → 0.533 s, all 60 cars finished, and contacts 51 → 50; combined finish times increased 2.09% and pit stops changed 19 → 22. Faster isolated laps do not automatically imply faster worn/pitting races.
|
|
85
|
+
|
|
86
|
+
No Git staging, commit, fetch, push, merge or publication has been authorized or performed. Release publishing and lock synchronization follow-ups remain separately approval-gated.
|
|
87
|
+
|
|
88
|
+
The [PaddockJS Linear project document](https://linear.app/mgiorgetti/document/v11-improvement-pass-racecraft-render-cost-and-lifecycle-reliability-b6c4a20b8501) is updated with task, solution, verification and tradeoffs; readback preserves previous content and verifies the new section. Temporary profiling servers and the isolated native QA browser are closed. The rebuilt demo stays available at `http://127.0.0.1:4181/`. Native painted-track capture: `output/playwright/limit-final-track-narrow.png`.
|
package/docs/loading.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Startup Loading
|
|
2
|
+
|
|
3
|
+
PaddockJS has two different startup loading surfaces. They solve different timing problems and should not be treated as interchangeable.
|
|
4
|
+
|
|
5
|
+
## The Two Phases
|
|
6
|
+
|
|
7
|
+
| Phase | When it can appear | Owner | Purpose |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| Pre-JS placeholder | Before the full PaddockJS browser bundle has downloaded, parsed, and imported | Host page, using the optional package placeholder helper/CSS | Give the user immediate lightweight visual feedback during the network/import gap |
|
|
10
|
+
| Package loading overlays | After `mountF1Simulator()` or a composable `mount*()` call starts | PaddockJS runtime | Cover PixiJS setup, asset loading, control binding, simulation creation, readout initialization, and the first real frame |
|
|
11
|
+
|
|
12
|
+
The pre-JS placeholder exists because PaddockJS cannot render anything before PaddockJS code exists on the page. The package loading overlays exist because, once the package has started, the runtime still needs time to build the simulator.
|
|
13
|
+
|
|
14
|
+
## Phase 1: Pre-JS Placeholder
|
|
15
|
+
|
|
16
|
+
Use the optional placeholder subpath when a host wants visible simulator UI before importing the full browser runtime:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
20
|
+
import '@inventure71/paddockjs/placeholder.css';
|
|
21
|
+
|
|
22
|
+
root.innerHTML = createPaddockLoadingPlaceholder({
|
|
23
|
+
label: 'Loading simulator',
|
|
24
|
+
detail: 'Preparing race control',
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`@inventure71/paddockjs/placeholder` is intentionally separate from the root package. It does not import PixiJS, simulator assets, package runtime CSS, `F1SimulatorApp`, or the browser mount. The stylesheet at `@inventure71/paddockjs/placeholder.css` is a tiny standalone stylesheet for the default start-light placeholder.
|
|
29
|
+
|
|
30
|
+
The helper returns inert escaped HTML. It does not mount the simulator, register event listeners, fetch assets, or start any timers. The default `lights` variant uses CSS animation only.
|
|
31
|
+
|
|
32
|
+
## Bundled Browser Hosts
|
|
33
|
+
|
|
34
|
+
In Vite, Rollup, Webpack, or another browser bundler, render the placeholder first, then dynamically import the full simulator:
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
38
|
+
import '@inventure71/paddockjs/placeholder.css';
|
|
39
|
+
|
|
40
|
+
const root = document.getElementById('f1-simulator-root');
|
|
41
|
+
|
|
42
|
+
root.innerHTML = createPaddockLoadingPlaceholder({
|
|
43
|
+
label: 'Loading simulator',
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const startSimulator = async () => {
|
|
47
|
+
const { mountF1Simulator } = await import('@inventure71/paddockjs');
|
|
48
|
+
await mountF1Simulator(root, { drivers, entries });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
if ('requestIdleCallback' in window) {
|
|
52
|
+
window.requestIdleCallback(startSimulator);
|
|
53
|
+
} else {
|
|
54
|
+
setTimeout(startSimulator, 0);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The dynamic root import lets the page paint the placeholder before paying for the full browser simulator bundle. The full mount replaces the placeholder root content when PaddockJS starts.
|
|
59
|
+
|
|
60
|
+
## Static HTML Hosts
|
|
61
|
+
|
|
62
|
+
Plain static HTML pages cannot resolve bare npm imports such as `@inventure71/paddockjs/placeholder` directly in the browser unless the page also provides a bundler output or import map. Do not add a runtime bundling step only to render the placeholder.
|
|
63
|
+
|
|
64
|
+
For static hosts with a build script, run the helper at build time and inject the generated HTML into the static page:
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
68
|
+
import { createRequire } from 'node:module';
|
|
69
|
+
import { dirname } from 'node:path';
|
|
70
|
+
import { createPaddockLoadingPlaceholder } from '@inventure71/paddockjs/placeholder';
|
|
71
|
+
|
|
72
|
+
const require = createRequire(import.meta.url);
|
|
73
|
+
|
|
74
|
+
const placeholderHtml = createPaddockLoadingPlaceholder({
|
|
75
|
+
label: 'Loading simulator',
|
|
76
|
+
detail: 'Preparing race preview',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const cssSource = require.resolve('@inventure71/paddockjs/placeholder.css');
|
|
80
|
+
const cssTarget = 'dist/f1-simulator/paddock-placeholder.css';
|
|
81
|
+
|
|
82
|
+
mkdirSync(dirname(cssTarget), { recursive: true });
|
|
83
|
+
copyFileSync(cssSource, cssTarget);
|
|
84
|
+
|
|
85
|
+
const html = readFileSync('projects.html', 'utf8')
|
|
86
|
+
.replace('<!-- paddock-placeholder -->', placeholderHtml)
|
|
87
|
+
.replace(
|
|
88
|
+
'</head>',
|
|
89
|
+
' <link rel="stylesheet" href="/f1-simulator/paddock-placeholder.css">\n</head>',
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
writeFileSync('dist/projects.html', html);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
That pattern keeps the first paint static and cheap while avoiding manual markup drift. The HTML still comes from the package helper, and the CSS still comes from the package stylesheet.
|
|
96
|
+
|
|
97
|
+
If a static host cannot run the helper during its build, copying the generated placeholder markup contract is acceptable as a fallback, but it is weaker. Manual markup can drift if the package changes the placeholder structure in a later release.
|
|
98
|
+
|
|
99
|
+
## Phase 2: Package Loading Overlays
|
|
100
|
+
|
|
101
|
+
After PaddockJS JavaScript starts, `mountF1Simulator(root, options)` synchronously writes a lightweight package shell into the mount root. The shell includes package-owned loading overlays for startup-capable surfaces such as the race canvas, controls, timing tower, race-data panel, telemetry stack, and composable component roots.
|
|
102
|
+
|
|
103
|
+
Composable hosts get the same behavior per mounted surface:
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const simulator = createPaddockSimulator(options);
|
|
107
|
+
|
|
108
|
+
simulator.mountRaceCanvas(canvasRoot);
|
|
109
|
+
simulator.mountTimingTower(timingRoot);
|
|
110
|
+
simulator.mountTelemetryPanel(telemetryRoot);
|
|
111
|
+
|
|
112
|
+
await simulator.start();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Each `mount*()` call writes static package markup and a surface-specific `data-paddock-loading` overlay immediately. `start()` removes those overlays only after PixiJS, assets, controls, initial DOM readouts, and the first frame have initialized.
|
|
116
|
+
|
|
117
|
+
These overlays are automatic. Hosts should not recreate them, query them for simulator state, or patch package internals to hide them. If a host needs a different pre-PaddockJS first paint, use the phase-1 placeholder around or inside the same root before calling the package mount.
|
|
118
|
+
|
|
119
|
+
## Replacement Flow
|
|
120
|
+
|
|
121
|
+
A typical lazy startup flow is:
|
|
122
|
+
|
|
123
|
+
1. Host HTML/CSS paints the page and optional pre-JS placeholder.
|
|
124
|
+
2. Host code imports the full PaddockJS browser bundle.
|
|
125
|
+
3. `mountF1Simulator()` or composable `mount*()` calls replace the placeholder with package startup markup.
|
|
126
|
+
4. PaddockJS shows package loading overlays while runtime setup finishes.
|
|
127
|
+
5. PaddockJS removes those overlays after the first real simulator frame is ready.
|
|
128
|
+
|
|
129
|
+
The pre-JS placeholder and package overlays can look similar, but they are intentionally separate. The first is a host-rendered shell for the network/import gap. The second is package runtime UI for simulator boot.
|
|
130
|
+
|
|
131
|
+
## What Not To Do
|
|
132
|
+
|
|
133
|
+
- Do not expect a plain static HTML page to resolve `@inventure71/paddockjs/placeholder` as a browser import without a bundler or import map.
|
|
134
|
+
- Do not eagerly import the root `@inventure71/paddockjs` package just to show a loading screen; that defeats the payload split.
|
|
135
|
+
- Do not copy simulator assets or PixiJS into the pre-JS placeholder.
|
|
136
|
+
- Do not manually maintain copied placeholder markup when the host has a build step that can call `createPaddockLoadingPlaceholder()`.
|
|
137
|
+
- Do not style package runtime internals such as `.start-lights`, `.timing-list`, or `.race-data-panel` from host CSS. Size the host root and let PaddockJS own runtime layout.
|
|
138
|
+
|
|
139
|
+
## Related Placeholders
|
|
140
|
+
|
|
141
|
+
PaddockJS also shows an `Unsupported size` placeholder when a shell or component is constrained below its supported bounds. That is not a startup loader. It is a layout safety state that tells the host to fix the container size rather than letting package controls overlap or clip.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Maintainability audit — 2026-09-08
|
|
2
|
+
|
|
3
|
+
This records the initial pass and its original evidence. The subsequent repository-wide review, resolved follow-ups, final verification, and current Linear status are in [cleanup coverage](cleanup_coverage.md). Counts, locations, and deferred decisions below describe that earlier baseline.
|
|
4
|
+
|
|
5
|
+
## Scope and baseline
|
|
6
|
+
|
|
7
|
+
This is a bounded audit of package entry points, data/configuration, environment input boundaries, pit and vehicle snapshot assembly, runtime/readout loops, sensor infrastructure, selected tests, and documentation. It is not a claim that every module is clean. Existing product behavior, supported exports, sensor precision, snapshot ownership, deterministic stepping, lifecycle recovery, and timing-board sizing must remain unchanged.
|
|
8
|
+
|
|
9
|
+
Initial checkout: `v11` at `fedff4e`, tracking the locally recorded `origin/v11` at the same commit. No fetch was performed. There were 55 modified tracked files and 11 untracked top-level status entries, including substantial ongoing runtime, sensor, API, test, documentation, and demo work. The initial contents of 376 tracked/untracked files, their SHA-256 hashes, status, and binary Git diff were saved outside the repository in `/tmp/paddockjs-audit-20260908/` before any edits. Changes described here are relative to that working-tree baseline, not relative to HEAD.
|
|
10
|
+
|
|
11
|
+
Baseline `npm run check`: **passed**, including 44 fast test files, 846 passing tests and 78 intentionally skipped tests, public types, dry pack, packed consumer install/build and subpath bundle boundaries, showcase/demo builds, quick Chromium smoke, and desktop/mobile demo smoke. Existing build warnings about large chunks were present; no baseline gate failure was observed. Baseline log: `/tmp/paddockjs-audit-20260908/baseline-check.log`.
|
|
12
|
+
|
|
13
|
+
## Checkable plan
|
|
14
|
+
|
|
15
|
+
- [x] Preserve the initial file contents and inspect read-only Git state.
|
|
16
|
+
- [x] Read supported exports, architecture, contracts, and verification commands; run the baseline gate.
|
|
17
|
+
- [x] Audit candidate defects and check internal, dynamic, type, documentation, and local portfolio consumer references.
|
|
18
|
+
- [x] Define bounded fixes and ownership before implementation (below).
|
|
19
|
+
- [x] Collect three standard runtime benchmark runs before implementation.
|
|
20
|
+
- [x] Apply dead-code and stale-documentation cleanup first.
|
|
21
|
+
- [x] Consolidate pit-intent policy, pit snapshot ownership, and participant validation.
|
|
22
|
+
- [x] Add meaningful boundary and snapshot ownership characterization; keep existing assertions.
|
|
23
|
+
- [x] Run final `npm run check` and `npm run check:release`.
|
|
24
|
+
- [x] Repeat the same standard runtime benchmark three times and report noise separately from cleanup; additionally alternate three baseline/current pairs to control for observed timing drift.
|
|
25
|
+
- [x] Log task, solution, verification, and remaining concerns in the PaddockJS Linear project (completed during the continuation).
|
|
26
|
+
- [x] Compare final files against the saved baseline and report read-only Git status.
|
|
27
|
+
|
|
28
|
+
## Verified findings selected for cleanup
|
|
29
|
+
|
|
30
|
+
Locations in this section refer to the saved pre-edit baseline. Each finding was checked as a hypothesis before selection.
|
|
31
|
+
|
|
32
|
+
| ID | Exact evidence and unnecessary cost | Smallest coherent fix | Compatibility risk and verification |
|
|
33
|
+
| --- | --- | --- | --- |
|
|
34
|
+
| F1 | `src/config/themeOptions.js:370-383`: `deriveDarkColor`, `deriveLightColor`, and `resolveModePair` forward fixed primary-token arguments to existing implementations. No code, dynamic import, type, supported export, documentation, or local portfolio source consumer references them. Three unused internal exports suggest alternate theme APIs without providing a boundary. | Remove the three wrappers; retain active token derivation and every supported theme alias. | Unsupported source imports outside the audited workspace cannot be disproved. Public types, theme tests, packed consumers, and browser checks cover supported usage. |
|
|
35
|
+
| F2 | `src/data/championship.js:243` builds `CHAMPIONSHIP_PROJECT_DRIVERS` eagerly; only `src/__tests__/championship.test.js:5,16-29,89` reads it. Package exports and declarations do not expose it. Production import initialization owns a fixture it never uses. | Construct the default grid in the test file and remove the internal fixture export. Keep the default builder and entry data unchanged. | Preserve all existing championship assertions and verify data subpath consumers. This removes unused initialization; no startup speed claim is made. |
|
|
36
|
+
| F3 | `src/simulation/raceSimulation.js:392-394` exposes `vehicleSnapshotDependencies()` with no callers. Actual snapshot functions call their factory directly. Neither the class nor this method is a supported export. | Remove the unused facade method and its otherwise unused factory import. | Check all snapshot variants and packed consumers. Do not remove the factory used by snapshot assembly. |
|
|
37
|
+
| F4 | `src/simulation/pit/pitFlow.js:4` imports `normalizePitIntent` without reading it. | Remove that binding only. | No changed execution; package gate verifies module loading. |
|
|
38
|
+
| F5 | `src/environment/actions.js:56-60` duplicates the exact numeric conversion and integer range `0..2` from `src/simulation/pit/pitIntent.js:16-20`. Two owners can drift. | Use the canonical pit normalizer and test for `!= null`, retaining valid zero. | Preserve coercion, omitted-field handling, compound validation, strict/report errors, and their ordering. Exercise accepted/coerced/rejected inputs through `resolveActionMap`. |
|
|
39
|
+
| F6 | `src/simulation/pit/pitSnapshots.js:16,50` requests a normalizer and default constant as injected arguments; its only callers at `src/simulation/snapshots/raceSnapshots.js:41-46` always pass identical pit-owned values through closures. The assembly layer must know and repeat pit policy. | Import the existing policy in pit snapshots and pass the serializers directly from race assembly. | Preserve full/observation/render/training shapes, null/nonfinite defaults, and copied mutable arrays/profile objects. Verify through real simulation snapshots. |
|
|
40
|
+
| F7 | `src/environment/options.js:62-68` creates a second participant ID set and checks membership already proved by `resolveScenario` at `132-136`. `all` and `controlled-only` include already validated controlled IDs by construction at `145-148`. | Remove the second set and loop; retain the earlier validation owner. | Test all participant modes, duplicate IDs, unknown IDs, missing controlled IDs, and error precedence. No stricter input rules or changed defaults. |
|
|
41
|
+
| F8 | `docs/data_model.md:97` calls `tireCare` reserved, but both vehicle integrators divide wear by it at `src/simulation/vehicle/vehiclePhysics.js:196-197,375-377`. Constructor-output examples at `53-66,99-113` omit current `customFields`. | Correct the active behavior description and output examples. | Documentation only; compare with implementations and run the docs checker. |
|
|
42
|
+
|
|
43
|
+
## Ownership and data flow before refactoring
|
|
44
|
+
|
|
45
|
+
F1–F4 remove paths without a runtime owner or caller; no replacement abstraction is needed. Championship tests own their fixture, while the public builder continues to own normalization.
|
|
46
|
+
|
|
47
|
+
For F5, `pitIntent.js` owns numeric pit intent values and coercion. `actions.js` owns external action presence, driver identity, required controls, compound shape, and strict/report error handling. Input is an optional action field; output is a normalized intent or the existing error. Simulation receives the same numeric value or intent/compound object. Invalid integer range and nonfinite inputs remain failures; coercible zero remains valid. No simulation or app object crosses this boundary.
|
|
48
|
+
|
|
49
|
+
For F6, pit snapshot serializers own pit field selection, fallback values, and copies of mutable pit state. Their sole input is a pit-stop state object; their output is the requested public pit snapshot variant. They depend on the existing pit normalizer/default and finite-number serializer. Race snapshot assembly owns selecting cars and constructing the overall snapshot, and vehicle serializers continue selecting the pit snapshot variant. Existing broader vehicle dependency injection is retained in this bounded change; no new dependency cycle or generic service is introduced. Missing pit state remains `null`; nonfinite service values remain `null`; returned penalty ID arrays and top-level profile objects must not alias live pit state. Existing nested pit-crew metadata is shared; this cleanup does not change that ownership.
|
|
50
|
+
|
|
51
|
+
For F7, the environment option boundary validates controlled driver IDs first, then scenario membership/placements, then filters normalized drivers. `resolveScenario` is the only owner of explicit participant-list membership validation. The return shape and validation order remain unchanged. Default participant modes require no second validation because their construction proves membership.
|
|
52
|
+
|
|
53
|
+
## Findings retained or deferred
|
|
54
|
+
|
|
55
|
+
- **Dependencies:** all declared dependencies have identifiable runtime, verification, or release consumers. No unused dependency was established; no upgrades are proposed.
|
|
56
|
+
- **Compatibility paths:** track, vehicle, driver, sensor, and UI barrels still have active imports. Their small size is not evidence of a defect. Supported legacy theme aliases remain contracts.
|
|
57
|
+
- **Shared rating conversion:** `src/data/driverData.js:3-25` and `src/data/vehicleData.js:3-27` duplicate rating limits and conversion. A focused rating-scale owner is plausible, but vehicle direction and domain-specific error strings must remain distinct. Maintenance cost is modest, so defer instead of expanding this change. Verify coercion, clamping, defaults, nonfinite input, and inverse direction before consolidation.
|
|
58
|
+
- **Asset error scope:** `src/app/rendering/appAssets.js:3-10` catches both asset loading and texture configuration failures. Returning `Texture.WHITE` intentionally recovers from missing assets, but also hides configuration faults. Separating those failure modes would change initialization behavior; characterize both and obtain a behavior decision before changing it.
|
|
59
|
+
- **Intentional error containment:** environment external-renderer callbacks, host lifecycle callbacks, controller-loop scheduling, and external-renderer state reporting provide deliberate failure boundaries. Their catches are not removed. Warmup is best effort and its failure path preserves normal execution.
|
|
60
|
+
- **Nested snapshot ownership:** `src/simulation/pit/pitSnapshots.js:37` shallow-copies `serviceProfile`, while `src/simulation/pit/pitServiceProfile.js:20` includes a nested `pitCrew` object. The snapshot therefore retains that nested reference. Tests exercise a real generated service profile and verify top-level isolation only. Clarify the intended nested ownership contract before adding deeper cloning; no snapshot ownership change is bundled here.
|
|
61
|
+
- **Whole-runtime dependencies:** `src/app/runtime/frameLoop.js:12` and pit orchestration consume broad mutable owners. Moving their methods into helpers with the same app/simulation object would not reduce coupling. The pit snapshot adapters are a smaller demonstrated ownership problem that can be corrected now.
|
|
62
|
+
- **Tests:** `src/__tests__/componentApi.test.js:1611-1617,1864-1870,2059-2068` includes source-text assertions coupled to spelling, but they guard documented module boundaries. Replacing them requires equivalent import-graph or behavior checks; deleting them would remove coverage. Large test files alone do not justify splitting.
|
|
63
|
+
- **Documentation:** architecture and sensor contract passages repeat detailed hot-path information, but distinguish ownership from externally observable precision. No broad prose rewrite is justified without checking every corresponding claim. Historical design plans are not authoritative runtime contracts.
|
|
64
|
+
|
|
65
|
+
## Performance audit and measurement protocol
|
|
66
|
+
|
|
67
|
+
Inspect existing runtime benchmarks across simulation phases, pit routing, collision, track queries, road/surface/recovery rays, wheel surfaces, environment stepping, snapshots/JSON, policy JSON, render interpolation, and DOM readouts. Run `node scripts/benchmark-runtime-efficiency.mjs --profile=standard --verify --json` three times before and three times after, sequentially without concurrent package gates. Keep the existing benchmark code, seeds, settings, and operation counts identical. Record raw JSON under `/tmp/paddockjs-audit-20260908/{before,after}-{1,2,3}.json`.
|
|
68
|
+
|
|
69
|
+
Environment: Node `v24.13.0`, arm64 macOS `27.0` build `26A5421a`. Wall-clock timings include normal local-machine noise and fixture setup. Compare per-operation medians and ranges; retain deterministic counters/checks. These runs characterize structural cleanup, not a controlled claim about a specific optimization.
|
|
70
|
+
|
|
71
|
+
Representative browser workloads are the existing quick/full showcase smoke matrix and product demo smoke, covering mounted/composable lifecycle, expert/headless flows, readouts, presets, and desktop/mobile sizing. They verify behavior rather than establish browser latency gains. The benchmark DOM workload uses a test DOM, so do not describe its timings as real-browser rendering performance.
|
|
72
|
+
|
|
73
|
+
Hot-path decisions: retain frame pacing, throttled DOM updates, separate render/full snapshots, sensor scratch reuse, track query indexing, precision-aware ray fallback, and timing-row reconciliation. The frame loop at `src/app/runtime/frameLoop.js:43-68` already avoids most full snapshots; `src/app/readouts/timingTowerRenderer.js` reuses row DOM. Repeated overview key construction in `src/app/readouts/carOverviewRenderer.js:61-84` is a candidate only if a real-browser profile identifies it as material. No new cache, pooling, precision change, or algorithmic optimization is planned.
|
|
74
|
+
|
|
75
|
+
## Results and work log
|
|
76
|
+
|
|
77
|
+
F1–F8 are implemented. The audit added 32 characterization tests for action coercion/errors, participant modes/error precedence, and real simulation snapshot fields/copy ownership. They pass against the original implementation and the cleanup; the real generated-service-profile fixture was also checked independently against both trees. Existing championship assertions remain intact. Independent review of the input/pit/snapshot delta found no actionable issue.
|
|
78
|
+
|
|
79
|
+
Verification:
|
|
80
|
+
|
|
81
|
+
- Baseline `npm run check`: passed (846 tests; 78 intentionally skipped).
|
|
82
|
+
- Final `npm run check`: passed (878 tests; 78 intentionally skipped).
|
|
83
|
+
- `npm run check:release`: passed (956 tests across 47 test batches, public types, dry pack, packed consumer build/subpath boundaries, showcase/demo builds, full Chromium showcase matrix and demo smoke).
|
|
84
|
+
- Full browser matrix: loading overlays, desktop/mobile/tablet and timing breakpoints, composable components, customization, API, playable, Policy Runner, behavior, stewarding, and collision lab passed. Demo desktop/mobile runtime, public surfaces, presets, expert/headless, and search passed.
|
|
85
|
+
- Exact serialized environment output matches between the saved baseline and current source for seed `71`, track seed `2097`, full/vector/object observation modes, reset, 60 steps per mode with frame skip 4, and final state. Combined SHA-256: `4ea290b6504cfe3b4903de58baab9e2eb32ff979255a393628e00ee28eb4b06d`.
|
|
86
|
+
- `git diff --check`: passed. No pre-existing gate failures were found. Existing chunk-size build warnings remain.
|
|
87
|
+
|
|
88
|
+
Logs and comparison scripts are in `/tmp/paddockjs-audit-20260908/`; these are local temporary evidence, not published assets. `audit-only.patch` isolates this task from the larger uncommitted tree. The exhaustive gate was run because the cleanup crosses environment and simulation snapshot boundaries; no portfolio integration source was changed.
|
|
89
|
+
|
|
90
|
+
### Measurement result
|
|
91
|
+
|
|
92
|
+
The first consecutive before/after groups suggested a roughly one-third speedup even in untouched algorithms. That was not credible evidence of a cleanup benefit. The measurement plan was revised to alternate the preserved baseline and current source in fresh Node processes, using the same installed dependencies without creating a Git worktree or changing either benchmark harness. Three pairs ran after the gates finished. Simulation uses seed `71` and the benchmark's explicit canonical `TRACK`; environment settings and operation counts are unchanged.
|
|
93
|
+
|
|
94
|
+
All 22 workload identities, operation counts, and non-timing checks match across the six paired runs. Before/after ranges overlap for every workload. No material performance gain is established, and no hot-path optimization was introduced. The table reports milliseconds per benchmark-defined operation; the DOM workload is synthetic, not browser paint latency. Browser smoke supplies behavior evidence only.
|
|
95
|
+
|
|
96
|
+
| Workload | Before median [min, max] ms/op | After median [min, max] ms/op |
|
|
97
|
+
| --- | ---: | ---: |
|
|
98
|
+
| simulation.step advanced field | 0.032442 [0.031945, 0.034029] | 0.031913 [0.031660, 0.033126] |
|
|
99
|
+
| simulation phase profile | 0.355519 [0.351087, 0.357263] | 0.350887 [0.348334, 0.355748] |
|
|
100
|
+
| timing history and line maintenance | 0.000122 [0.000121, 0.000128] | 0.000122 [0.000117, 0.000129] |
|
|
101
|
+
| timing-line gap without stored crossings | 0.000054 [0.000054, 0.000055] | 0.000057 [0.000054, 0.000061] |
|
|
102
|
+
| lap telemetry in-progress sync | 0.000153 [0.000148, 0.000164] | 0.000154 [0.000154, 0.000155] |
|
|
103
|
+
| pit route transition geometry | 0.000600 [0.000590, 0.000645] | 0.000613 [0.000612, 0.000621] |
|
|
104
|
+
| collision candidate and narrowphase | 0.014346 [0.014100, 0.014780] | 0.014325 [0.014252, 0.014630] |
|
|
105
|
+
| nearest track query index | 0.002226 [0.002203, 0.002256] | 0.002278 [0.002214, 0.002325] |
|
|
106
|
+
| sensor ray road and surface channels | 0.032712 [0.032159, 0.033753] | 0.032801 [0.032604, 0.035977] |
|
|
107
|
+
| batch-training sensor surface channels | 0.016548 [0.016198, 0.017499] | 0.016499 [0.015432, 0.022635] |
|
|
108
|
+
| sensor ray barrier illegal-surface validation | 0.042978 [0.042229, 0.044926] | 0.040824 [0.040024, 0.042457] |
|
|
109
|
+
| sensor ray barrier off-track recovery | 0.056817 [0.054710, 0.057457] | 0.053189 [0.052965, 0.059095] |
|
|
110
|
+
| sensor ray pit-lane direct boundary | 0.014867 [0.013823, 0.018707] | 0.014279 [0.013579, 0.015012] |
|
|
111
|
+
| wheel surface near pit connector | 0.012874 [0.012743, 0.013432] | 0.012937 [0.012330, 0.014278] |
|
|
112
|
+
| wheel surface connector local-refresh path | 0.003203 [0.002642, 0.003578] | 0.002867 [0.002862, 0.003264] |
|
|
113
|
+
| wheel surface main-track analytic | 0.002045 [0.001932, 0.002120] | 0.002089 [0.001967, 0.002196] |
|
|
114
|
+
| headless environment vector step | 0.051907 [0.050513, 0.087385] | 0.050693 [0.050625, 0.051605] |
|
|
115
|
+
| snapshot construction | 0.018195 [0.017968, 0.018811] | 0.018014 [0.017356, 0.018649] |
|
|
116
|
+
| snapshot JSON serialization | 0.231152 [0.230037, 0.235442] | 0.234313 [0.231366, 0.235079] |
|
|
117
|
+
| policy server compact JSON transport | 0.056871 [0.056494, 0.059002] | 0.057974 [0.054731, 0.058445] |
|
|
118
|
+
| render snapshot interpolation | 0.000570 [0.000563, 0.000624] | 0.000626 [0.000610, 0.000678] |
|
|
119
|
+
| timing tower row markup | 0.003913 [0.003845, 0.004045] | 0.003741 [0.003425, 0.004084] |
|
|
120
|
+
|
|
121
|
+
Raw paired results: `/tmp/paddockjs-audit-20260908/paired-{before,after}-{1,2,3}.json`. The initial six results are retained separately as `before-*.json` and `after-*.json` so the timing drift is auditable.
|
|
122
|
+
|
|
123
|
+
### Changed file inventory
|
|
124
|
+
|
|
125
|
+
This task changed 11 existing files:
|
|
126
|
+
|
|
127
|
+
- `src/config/themeOptions.js`: remove unused internal theme wrappers.
|
|
128
|
+
- `src/data/championship.js`, `src/__tests__/championship.test.js`: relocate the test-only default grid fixture.
|
|
129
|
+
- `src/environment/actions.js`: consume canonical pit-intent normalization.
|
|
130
|
+
- `src/environment/options.js`: remove redundant participant validation.
|
|
131
|
+
- `src/simulation/pit/pitFlow.js`: remove unused import.
|
|
132
|
+
- `src/simulation/pit/pitSnapshots.js`, `src/simulation/snapshots/raceSnapshots.js`: put pit serialization policy in the pit module and remove fixed adapters.
|
|
133
|
+
- `src/simulation/raceSimulation.js`: remove unused snapshot dependency facade method.
|
|
134
|
+
- `docs/architecture.md`, `docs/data_model.md`: document actual ownership and data behavior.
|
|
135
|
+
|
|
136
|
+
Four files were added: this report and `src/__tests__/environmentPitActions.test.js`, `src/__tests__/environmentParticipants.test.js`, and `src/__tests__/pitSnapshots.test.js`.
|
|
137
|
+
|
|
138
|
+
Preservation check: 365 of the 376 baseline files remain byte-identical. The other 11 were reviewed against the saved contents; existing edits in the three overlapping dirty files (`themeOptions.js`, `options.js`, and `architecture.md`) were preserved. Initial untracked work, package exports/types, dependency versions, benchmark harnesses, and browser implementation remain unchanged by this task.
|
|
139
|
+
|
|
140
|
+
Read-only final Git state: branch `v11`, HEAD `fedff4e`, locally recorded upstream `origin/v11`, ahead/behind `0/0` without fetching. There are 63 modified tracked files, 15 untracked status entries (including pre-existing directory entries), and no staged changes. No Git/GitHub mutation was performed. Proposed next step is review of the audit-only diff; any later staging, commit, branch, or push requires separate approval of exact commands and targets.
|
|
141
|
+
|
|
142
|
+
### Initial Linear logging blocker (resolved)
|
|
143
|
+
|
|
144
|
+
The required Linear work log could not be posted. The official connector returned `UNAUTHORIZED` / reauthentication required; the prescribed `mcp-remote` route opened authorization and waited for sign-in before timing out. A reauthentication request was sent to the user during local work. The task summary, implementation rationale, verification, and remaining concerns are preserved here and in `/tmp/paddockjs-audit-20260908/linear-work-log.md`, ready to log in the PaddockJS project once authentication is restored. No Linear write is claimed.
|
|
145
|
+
|
|
146
|
+
Authentication was restored during the continuation. Both passes are logged in the [PaddockJS audit document](https://linear.app/mgiorgetti/document/2026-09-08-repository-cleanup-audit-14d678a1a82c). Shared ratings and nested snapshot ownership were resolved, asset recovery was characterized and retained, and repository-wide dispositions are recorded in the current coverage report.
|