feat: canonical model and synthetic data#1
Conversation
Add canonical model (model.ts), seeded PRNG (rng.ts), and a deterministic generator (scripts/generate.ts) producing truth.json plus three incompatible raw provider formats (northwind/haulix/tracpoint) under src/data. Add data integrity tests. Expose node types to the app tsconfig so fs-based tests type-check.
📝 WalkthroughWalkthroughAdds a deterministic fleet data generator ( ChangesFleet Data Generator and Validation
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR adds FleetBridge “phase 2” data foundations: a canonical telematics model plus deterministic, seeded synthetic data generation that emits a ground-truth dataset and incompatible raw provider fixtures, along with tests that sanity-check the generated data.
Changes:
- Introduces canonical model types (
Provider,Vehicle,Location,SafetyEvent) and provider constants. - Adds a deterministic PRNG and a
scripts/generate.tsgenerator to produce reproducible truth + raw provider datasets. - Adds data integrity tests and updates TypeScript config to support Node APIs used by the tests.
Reviewed changes
Copilot reviewed 5 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.app.json | Adds Node type definitions so tests under src/ can use node:* imports. |
| src/data/raw/tracpoint.json | Adds TracPoint raw fixture data produced by the generator. |
| src/core/rng.ts | Adds a seeded PRNG helper (mulberry32) plus randRange/randInt. |
| src/core/model.ts | Adds canonical FleetBridge data model interfaces and provider constants. |
| src/tests/data.test.ts | Adds sanity checks for truth dataset invariants and raw-vs-truth counts. |
| scripts/generate.ts | Adds deterministic synthetic data generator and raw provider encoders. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Guarantee a couple of clear speeding bursts above 100 km/h. | ||
| const burst1 = randInt(rng, ramp + 2, Math.floor(n / 2)) | ||
| const burst2 = randInt(rng, Math.floor(n / 2), n - decel - 2) | ||
| for (const b of [burst1, burst2]) { | ||
| if (!inAnyIdle(idleWindows, b)) speed[b] = randRange(rng, 103, 109) | ||
| } |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
scripts/generate.ts (1)
220-225: 💤 Low valueComment says "Guarantee" but bursts can be skipped.
If a randomly selected burst index falls within an idle window, the burst is silently skipped (line 224). While the probability of both bursts being skipped is very low (~0.4%), the comment "Guarantee a couple of clear speeding bursts" is technically inaccurate.
This is unlikely to cause test failures since the cruise speed (98-110 km/h) will trigger speeding events anyway, but consider either:
- Retrying burst placement until it lands outside idle windows, or
- Adjusting the comment to "Attempt to inject..."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/generate.ts` around lines 220 - 225, The comment "Guarantee a couple of clear speeding bursts above 100 km/h" is inaccurate because the burst placement logic in the loop iterating over burst1 and burst2 can silently skip bursts if they fall within idle windows (via the inAnyIdle check). Either implement retry logic to guarantee burst placement by repeatedly calling randInt until inAnyIdle returns false, or update the comment to reflect that bursts are only "attempted" rather than "guaranteed" to be placed outside idle windows.src/__tests__/data.test.ts (1)
7-11: ⚡ Quick winConsider adding validation for the events array.
The
Truthinterface includesevents: SafetyEvent[], and events are loaded at module scope but never tested. Adding basic validation (non-empty check, timestamp alignment with locations, vehicleId references) would improve coverage of the canonical data integrity.🧪 Suggested test case
it('never reports a negative speed', () => { for (const loc of truth.locations) { expect(loc.speedKmh).toBeGreaterThanOrEqual(0) } }) + + it('includes valid safety events', () => { + expect(truth.events.length).toBeGreaterThan(0) + const vehicleIds = new Set(truth.vehicles.map((v) => v.id)) + const locationTimestamps = new Set(truth.locations.map((l) => l.timestamp)) + for (const event of truth.events) { + expect(vehicleIds.has(event.vehicleId)).toBe(true) + expect(locationTimestamps.has(event.timestamp)).toBe(true) + } + }) })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/__tests__/data.test.ts` around lines 7 - 11, The Truth interface's events array property is not being validated in tests. Add test cases that verify the canonical events data integrity by checking that the events array is not empty, that event timestamps align with the location data, and that all vehicleId references in events correspond to valid vehicles in the vehicles array. This will ensure the SafetyEvent array maintains data consistency with the other properties of the Truth interface.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@scripts/generate.ts`:
- Around line 220-225: The comment "Guarantee a couple of clear speeding bursts
above 100 km/h" is inaccurate because the burst placement logic in the loop
iterating over burst1 and burst2 can silently skip bursts if they fall within
idle windows (via the inAnyIdle check). Either implement retry logic to
guarantee burst placement by repeatedly calling randInt until inAnyIdle returns
false, or update the comment to reflect that bursts are only "attempted" rather
than "guaranteed" to be placed outside idle windows.
In `@src/__tests__/data.test.ts`:
- Around line 7-11: The Truth interface's events array property is not being
validated in tests. Add test cases that verify the canonical events data
integrity by checking that the events array is not empty, that event timestamps
align with the location data, and that all vehicleId references in events
correspond to valid vehicles in the vehicles array. This will ensure the
SafetyEvent array maintains data consistency with the other properties of the
Truth interface.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: e1b53d94-4382-4e48-9562-2c102773ff78
📒 Files selected for processing (10)
scripts/generate.tssrc/__tests__/data.test.tssrc/core/model.tssrc/core/rng.tssrc/data/raw/.gitkeepsrc/data/raw/haulix.jsonsrc/data/raw/northwind.jsonsrc/data/raw/tracpoint.jsonsrc/data/truth.jsontsconfig.app.json
Replace the burst placement with a pickBurst helper that retries randInt to find an index outside all idle windows (linear-scan then range-start fallback) and always writes both bursts, so a burst is no longer silently skipped. Regenerate committed data. Add truth.events tests: non-empty, every event within its vehicle's location time span, and every referenced vehicleId exists.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/__tests__/data.test.ts`:
- Around line 69-70: The variable `span` is declared twice in the same scope
within the test file, causing a TypeScript compile error. Remove the duplicate
declaration of the Map variable `span` that appears at lines 69-70 in the
data.test.ts file, keeping only one declaration of the span variable with the
type Map<string, { min: number; max: number }>.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 6bc88243-1246-416d-a698-8afd3c6021f4
📒 Files selected for processing (6)
scripts/generate.tssrc/__tests__/data.test.tssrc/data/raw/haulix.jsonsrc/data/raw/northwind.jsonsrc/data/raw/tracpoint.jsonsrc/data/truth.json
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/generate.ts
| const span = new Map<string, { min: number; max: number }>() | ||
| for (const loc of truth.locations) { |
There was a problem hiding this comment.
Remove duplicate span declaration (compile-time blocker).
span is declared twice in the same scope, which causes a TypeScript compile error and prevents the test suite from running.
Suggested fix
it('places every event within its vehicle location time span', () => {
- const span = new Map<string, { min: number; max: number }>()
const span = new Map<string, { min: number; max: number }>()🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/__tests__/data.test.ts` around lines 69 - 70, The variable `span` is
declared twice in the same scope within the test file, causing a TypeScript
compile error. Remove the duplicate declaration of the Map variable `span` that
appears at lines 69-70 in the data.test.ts file, keeping only one declaration of
the span variable with the type Map<string, { min: number; max: number }>.
|
|
||
| const CORRIDORS: Record<string, Corridor> = { | ||
| hwy401: { |
| export interface Location { | ||
| vehicleId: string | ||
| /** ISO 8601 timestamp, e.g. "2026-06-15T13:00:10.000Z". */ | ||
| timestamp: string | ||
| lat: number | ||
| lng: number | ||
| speedKmh: number | ||
| headingDeg: number | ||
| } |
| export const NORTHWIND: Provider = { id: 'northwind', name: 'Northwind' } | ||
| export const HAULIX: Provider = { id: 'haulix', name: 'Haulix' } | ||
| export const TRACPOINT: Provider = { id: 'tracpoint', name: 'TracPoint' } | ||
|
|
||
| export const PROVIDERS: Provider[] = [NORTHWIND, HAULIX, TRACPOINT] |
FleetBridge phase 2: common model, seeded generator, three raw provider formats, data tests
Summary by CodeRabbit