Adds five role agents under .claude/agents/, each pinned to a model in
frontmatter (sonnet for developer/debugger/operator/tech-writer, opus
for quality-reviewer) and directed to read the relevant mvp-* skills
before acting. Replaces the model enforcement lost when c239bb9 deleted
enforce-agent-model.sh. Updates .claude/CLAUDE.md and root CLAUDE.md
indexes.
Co-Authored-By: Claude Fable 5 <[email protected]>
Root CLAUDE.md: state the actual CI pipeline (image builds + staging deploy
+ health checks; no tests, lint, or security scanning), replace root-level
npm commands with per-workspace equivalents, correct the OCR engine
description, rename Sprint Workflow to Issue Workflow (sprints unused), and
replace the retired agent-system references with the skill library entry
points. Remove emoji from Quality Standards per the project's own rule.
.claude/CLAUDE.md: rewrite as a pure index of the current .claude/ contents
with one row per mvp-* skill.
Co-Authored-By: Claude Fable 5 <[email protected]>
Removes the old planner/decision-critic/role-agents/domain-agents system
(step-injector scripts, stale scopes, sprint-era workflow) and replaces it
with 16 ground-truth-verified skills under .claude/skills/: change control,
debugging playbook, failure archaeology, architecture contract, domain
reference, OCR/Gemini pipeline, config and secrets, build and env, run and
operate, diagnostics (with tested scripts), validation and QA, docs and
writing, launch readiness, deploy-safety campaign, proof and analysis
toolkit, and research frontier. RULE 0/1/2, the temporal-contamination rule,
and the decision stress-test protocol are carried forward into the new
skills; the retired content remains in git history.
Co-Authored-By: Claude Fable 5 <[email protected]>
Reorder the Add Fuel Log form so the most-used inputs come first and
calculated/auto-filled fields are de-emphasized:
Vehicle, Mileage, Cost Per Gallon, Fuel Amount, Fuel Type/Grade,
Location, MPG (read-only), Notes, Date & Time.
Mileage is the existing Trip Distance / Odometer Reading field,
repositioned only; toggle and logic unchanged. Fuel Type stays before
Fuel Grade to preserve the type-filters-grade dependency.
Add inputMode=decimal to the numeric fields (Mileage via DistanceInput,
Fuel Amount, Cost Per Gallon) so mobile shows the decimal keypad. MPG
and Date & Time become full-width since they are no longer paired.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The enhanced API path on FuelLogsRepository returned raw pg rows
straight to the service layer, so DECIMAL columns (fuel_units,
cost_per_unit, total_cost, gallons, price_per_gallon) arrived as
strings instead of numbers. The service layer compensated with
scattered Number() coercion in toEnhancedResponse and getVehicleStats,
and EfficiencyCalculationService silently leaned on JS string-to-
number coercion in division. Type signatures across the stack
declared number and the runtime delivered string.
Add a private mapEnhancedRow that coerces all DECIMAL columns with
parseFloat while preserving snake_case keys (the convention the
service layer already uses to access these rows). Apply it in every
enhanced read/write path: createEnhanced, findByVehicleIdEnhanced,
findByUserIdEnhanced, findByIdEnhanced, getPreviousLogByOdometer,
getLatestLogForVehicle, updateEnhanced. Drop the now-redundant
Number() wrappers in toEnhancedResponse and getVehicleStats.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
node-postgres returns numeric/decimal columns as JavaScript strings,
but the TypeScript interfaces for MaintenanceRecord and OwnershipCost
declare numeric fields as number. The mappers were passing values
through raw, breaking type-safe arithmetic and display (e.g. the
amount column on the vehicle summary screen was empty until the
recent frontend workaround in PR #240, and OwnershipCostsList silently
no-ops toLocaleString on the string).
Backend
- mapMaintenanceRecord: coerce cost via Number() when non-null.
- ownership-costs mapRow: coerce amount via Number().
Frontend (remove now-redundant workarounds)
- MaintenanceRecordsList: drop Number() coercion on cost and
odometerReading; use the number values directly.
- VehicleDetailPage / VehicleDetailMobile: revert the PR #240 cost
coercion to the simple typeof number guard now that the backend
honors the type.
Scope notes
- Other repositories with the same pattern (stations, community-stations,
fuel-logs enhanced methods) are tracked separately because they have
unclear downstream consumers and warrant their own investigation.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Postgres numeric columns come back as strings via node-postgres, so
typeof rec.cost === 'number' was false and the amount column rendered
as '—'. Coerce with Number() (matching the pattern in
MaintenanceRecordsList) so the cost displays as a dollar amount.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The Vehicle Records section on /garage/vehicles/:id never called
useMaintenanceRecords, so maintenance rows always rendered empty even
when records existed for the vehicle. Wire the existing hook into both
the desktop VehicleDetailPage and mobile VehicleDetailMobile, merge
records into the unified list with category + subtypes + shop name,
and include the maintenance loading state in the section's loading
and empty-state guards.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
new Date("YYYY-MM-DD") parses as UTC midnight per ES2015. toLocaleDateString()
then displays in local time, shifting the date back one day for users west of
UTC. This caused the list view and edit dialog to show different dates.
Fixed in: MaintenanceRecordsList (display + sort + delete confirm),
VehicleDetailPage (display + sort), VehicleDetailMobile (display + sort),
MaintenanceRecordForm (receipt title), OwnershipCostsList (formatDate).
Sorting now uses string comparison (YYYY-MM-DD is lexicographically sortable).
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
The parseServiceDate function used toISOString().split('T')[0] which converts
to UTC, shifting dates by one day depending on timezone. Standard parsing now
uses getFullYear/getMonth/getDate (local time). MM/DD/YYYY parsing now formats
directly from regex groups without round-tripping through a Date object.
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
- Remove AutomaticFunctionCallingConfig(max_remote_calls=3) which caused
pydantic validation error on the installed google-genai version
- Log full Gemini raw JSON response in OCR engine for debugging
- Add engine/transmission to backend raw values log
- Add hasTrim/hasEngine/hasTransmission to decode success log
Co-Authored-By: Claude Opus 4.6 <[email protected]>
The installed google-genai version does not support max_remote_calls on
AutomaticFunctionCallingConfig, causing a pydantic validation error that
broke VIN decode on staging.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace engine._model/engine._generation_config mocks with
engine._client/engine._model_name. Update sys.modules patches
from vertexai to google.genai. Remove dead if-False branch.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace vertexai.generative_models with google.genai client pattern.
Add Google Search grounding tool to VIN decode for improved accuracy.
Convert response schema types to uppercase per Vertex AI Schema spec.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
gemini-3-flash-preview was hallucinating year (e.g., returning 1993
instead of 2023 for position-10 code P). Prompt now includes the full
1980-2039 year code table and position-7 disambiguation rule.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Default 10s API client timeout caused frontend "Failed to decode" errors
when Gemini engine cold-starts (34s+ on first call).
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Prevent lower-confidence Gemini results from overwriting higher-confidence
cache entries, add reverse-contains matching so values like "X5 xDrive35i"
match DB option "X5", and show amber hint when dropdown matching fails.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Rename nhtsaValue to sourceValue in frontend MatchedField type and
VinOcrReviewModal component. Update NHTSA references to vehicle
database across guide pages, hooks, and API documentation.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Delete vehicles/external/nhtsa/ directory (3 files), remove VPICVariable
and VPICResponse from platform models. Update all documentation to
reflect Gemini VIN decode via OCR service architecture.
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace NHTSAClient with OcrClient in vehicles controller. Move cache
logic into VehiclesService with format-aware reads (Gemini vs legacy
NHTSA entries). Rename nhtsaValue to sourceValue in MatchedField.
Remove vpic config from Zod schema and YAML config files.
Co-Authored-By: Claude Opus 4.6 <[email protected]>