Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:

strategy:
matrix:
node-version: [18.x, 20.x]
node-version: [20.x]

steps:
- name: Checkout code
Expand All @@ -25,7 +25,7 @@ jobs:
cache: 'npm'

- name: Install dependencies
run: npm ci
run: npm install
Comment on lines 27 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Tracked lockfiles:\n'
git ls-files | rg '(^|/)(package-lock\.json|npm-shrinkwrap\.json)$' || true

printf '\npackage.json snippets related to package manager selection:\n'
rg -n -C2 '"packageManager"|"engines"' --glob 'package.json'

Repository: ereezyy/Sol_Horse

Length of output: 309


🏁 Script executed:

cat -n .github/workflows/ci-cd.yml | head -120

Repository: ereezyy/Sol_Horse

Length of output: 3593


Use npm ci instead of npm install in CI/CD jobs.

Since this repo commits package-lock.json, using npm install will ignore the locked versions and potentially resolve different dependencies than what was tested locally, risking undetected lockfile drift in test, security, staging, and production workflows. Use npm ci to respect the lockfile.

This applies to lines 28, 61, 85, and 116.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci-cd.yml around lines 27 - 28, Replace all CI
dependency-install steps that currently run "npm install" with "npm ci" to
ensure the package-lock.json is respected; locate the workflow steps named
"Install dependencies" (there are multiple occurrences) and update their run
command to use npm ci instead of npm install so the CI uses the locked
dependency tree.


- name: Run linting
run: npm run lint
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
cache: 'npm'

- name: Install dependencies
run: npm ci
run: npm install

- name: Run security audit
run: npm audit --audit-level=moderate
Expand All @@ -82,7 +82,7 @@ jobs:
cache: 'npm'

- name: Install dependencies
run: npm ci
run: npm install

- name: Build for staging
run: npm run build
Expand Down Expand Up @@ -113,7 +113,7 @@ jobs:
cache: 'npm'

- name: Install dependencies
run: npm ci
run: npm install

- name: Build for production
run: npm run build
Expand Down
56 changes: 56 additions & 0 deletions src/services/raceEngine.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { describe, it, expect } from 'vitest';
import { RaceEngine, RaceHorse } from './raceEngine';

describe('RaceEngine', () => {
const mockHorses = [
{
id: '1',
name: 'Test Horse',
genetics: { baseSpeed: 50, stamina: 50, agility: 50, temperament: 50, intelligence: 50 }
}
];
const mockConfig = {
distance: 1000,
conditions: { weather: 'Clear', trackCondition: 'Fast' }
};
const mockCallbacks = {
onUpdate: () => {},
onFinish: () => {}
};

const engine = new RaceEngine(mockHorses, mockConfig, mockCallbacks);

describe('calculateEnergyFactor', () => {
it('returns 0.25 when energy is 0 or less', () => {
const horse = { energy: 0, stamina: 100 } as RaceHorse;
expect(engine.calculateEnergyFactor(horse)).toBe(0.25);

const exhaustedHorse = { energy: -10, stamina: 100 } as RaceHorse;
expect(engine.calculateEnergyFactor(exhaustedHorse)).toBe(0.25);
});

it('returns 1.0 when energy is 100 and stamina is 0', () => {
const horse = { energy: 100, stamina: 0 } as RaceHorse;
// baseFactor = Math.pow(100/100, 0.45) = 1
// staminaBonus = 0 / 200 = 0
// result = 1 * (1 + 0) = 1
expect(engine.calculateEnergyFactor(horse)).toBe(1.0);
});

it('returns 1.5 when energy is 100 and stamina is 100', () => {
const horse = { energy: 100, stamina: 100 } as RaceHorse;
// baseFactor = 1
// staminaBonus = 100 / 200 = 0.5
// result = 1 * (1 + 0.5) = 1.5
expect(engine.calculateEnergyFactor(horse)).toBe(1.5);
});

it('calculates factor correctly for mid-range values', () => {
const horse = { energy: 50, stamina: 50 } as RaceHorse;
const baseFactor = Math.pow(50 / 100, 0.45);
const staminaBonus = 50 / 200;
const expected = baseFactor * (1 + staminaBonus);
expect(engine.calculateEnergyFactor(horse)).toBeCloseTo(expected, 5);
});
});
});
4 changes: 2 additions & 2 deletions src/services/raceEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class RaceEngine {
// Calculate acceleration based on horse stats and race progress
try {
const raceProgress = horse.distanceCovered / this.raceState.distance;
const energyFactor = this.calculateEnergyFactor(horse, raceProgress);
const energyFactor = this.calculateEnergyFactor(horse);
const strategicSpeed = this.calculateStrategicSpeed(horse, raceProgress);

// Update speed with realistic acceleration/deceleration
Expand Down Expand Up @@ -199,7 +199,7 @@ export class RaceEngine {
}
}

private calculateEnergyFactor(horse: RaceHorse): number {
public calculateEnergyFactor(horse: RaceHorse): number {
// Energy affects performance exponentially
if (horse.energy <= 0) return 0.25; // Even completely exhausted horses move a little

Expand Down
Loading