Skip to content

Modernize pycrash: type hints, tests, CLI, metrics, JSON persistence, AWD bugfix#2

Open
hordruma wants to merge 40 commits into
masterfrom
claude/analyze-and-document-QuRoJ
Open

Modernize pycrash: type hints, tests, CLI, metrics, JSON persistence, AWD bugfix#2
hordruma wants to merge 40 commits into
masterfrom
claude/analyze-and-document-QuRoJ

Conversation

@hordruma

Copy link
Copy Markdown
Owner

Summary

Full modernization pass on pycrash — everything except CI/CD.

  • 137 pytest tests covering Vehicle, SDOF solver, tire model, AR equations, and vehicle dynamics (momentum conservation, COR, braking decel, coordinate transforms, position integration)
  • Type hints across all public API and core internals using TYPE_CHECKING pattern to avoid circular imports
  • pyproject.toml — modern packaging with pytest/mypy/ruff config, Python >=3.9, updated deps
  • CLI (pycrash/cli.py) — Click-based entry point: pycrash info|sdof|vehicle|project
  • Metric units (pycrash/units.py) — MetricVehicle(dict) converts metric inputs to imperial, MetricResults(df) converts output DataFrame to metric
  • JSON persistencesave_project_json() / load_project_json() as safer alternative to pickle
  • numpy 2.0 / scipy compat — shims for np.trapz→np.trapezoid and cumtrapz→cumulative_trapezoid
  • Version bump to 0.0.18
  • CLAUDE.md — comprehensive development guide

Bug Fix: AWD Right-Front Tire

Found and fixed a parenthesis bug in tire_model.py:117 for AWD vehicles:

# Before (broken) — mu_max only multiplied throttle, not brake
rf_app = fz * (mu_max * (throttle) - brake * sign(vx))

# After (fixed) — mu_max multiplies the full expression
rf_app = fz * (mu_max * (throttle - brake * sign(vx)))

This caused the RF tire to exceed the friction limit during braking, trigger the lock condition, and produce a forward-accelerating force instead of braking. AWD vehicles were getting +24 ft/s² acceleration instead of -25.76 ft/s² deceleration under full braking.

Files Changed

Area Files
New: Tests tests/conftest.py, test_ar.py, test_sdof.py, test_tire_model.py, test_vehicle.py, test_vehicle_model.py
New: CLI pycrash/cli.py
New: Units pycrash/units.py
New: Build pyproject.toml
Modified: Core vehicle.py, vehicle_model.py, impact_main.py, sdof_model.py, project.py
Modified: Calcs tire_model.py, carpenter_momentum_calcs.py, impact_detect.py, sideswipe.py, sdof_calculations.py, spring_models.py
Modified: Utils ar.py, __init__.py, setup.py
Docs CLAUDE.md

Test Plan

  • All 137 tests pass (python -m pytest tests/ -v)
  • AWD braking deceleration verified at ~0.8g after bugfix
  • FWD/RWD braking unchanged by fix
  • numpy 2.0 and scipy compatibility verified
  • SDOF momentum conservation within 0.1%
  • Elastic collision energy conservation within 2%

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU

claude added 30 commits March 31, 2026 02:31
Documents architecture, data flow, all three collision models (SDOF, IMPC,
sideswipe), vehicle dynamics, key classes, build instructions, simulation
defaults, and development notes.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
…AWD tire bug

- Type hints across all public API and core internals using TYPE_CHECKING pattern
- 137 pytest tests covering vehicle, SDOF, tire model, AR equations, vehicle dynamics
- pyproject.toml with modern packaging, pytest/mypy/ruff config
- Click-based CLI entry point (pycrash info/sdof/vehicle/project)
- Metric unit conversion module (units.py) with MetricVehicle/MetricResults
- JSON save/load as safer alternative to pickle persistence
- Fix AWD right-front tire parenthesis bug in tire_model.py (rf_app mu_max scope)
- numpy 2.0 compat (np.trapz→np.trapezoid shim), scipy cumtrapz compat
- Version bump to 0.0.18

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
The AWD tire_model.py parenthesis bug is fixed, so tests should assert
correct ~0.8g deceleration, not the old buggy +24 ft/s² behavior.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
…t, PRD

Full agentic crash reconstruction platform:

- docker-compose.yml: api + worker + redis, one command startup
- FastAPI backend with sync/async SDOF simulation endpoints
- Claude-powered police report extraction agent (with mock fallback)
- Monte Carlo analysis via Celery distributed workers
- PDF report generation with WeasyPrint
- Vehicle database with 20 common US vehicles
- Pydantic models for full request/response validation
- 15 API tests (all passing without Docker via sync endpoints)
- Design thinking PRD with personas, jobs-to-be-done, phased roadmap

Run locally: ./pycrash_ai/run_local.sh
Run with Docker: cd pycrash_ai && docker compose up
Run tests: pytest pycrash_ai/tests/ -v

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
…unity

Replaced business model section with community growth strategy.
Reframed value prop around free self-hosted tooling, not managed services.
BYO API key model for AI features - no middleman.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
…n, and full pipeline integration

- FalkorDB-backed evidence graph: schema (nodes: Case, Vehicle, Evidence, Source, Scene, SimConfig, Gap; edges: INVOLVED_IN, OBSERVED, APPLIES_TO, SUPPORTS, CONTRADICTS, INFERRED_FROM, PROJECTED_TO), CaseGraph/CaseGraphStore with InMemory fallback for testing
- Case graph API routes: CRUD for cases, vehicles, evidence, sources; gap detection, contradiction detection, evidence-to-pycrash projection, .crash file export/import
- LLM provider abstraction: Anthropic (Claude) + OpenAI (GPT) with MockProvider for testing, auto-detection from env vars
- Dual-path document ingestion: PyMuPDF text extraction + vision model for scanned PDFs, OpenAI/Anthropic message format builders
- Pipeline now builds a case graph from extraction results, stores vehicle specs as evidence, and exports graph state
- FalkorDB added to docker-compose as dedicated graph database service
- 38 API tests all passing (graph store, case API, pipeline with graph, LLM providers, ingestion, extraction, SDOF, vehicles)

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
…ical

Refactored flat case graph into a composable 6-layer hypergraph architecture.
Each layer is a mixin class (layers/*.py), composed via multiple inheritance
into InMemoryCaseGraph. Cross-layer edges connect nodes across dimensions.

Layers:
- Entity: vehicles, drivers, pedestrians, objects
- Temporal: events, phases, timeline ordering, crash sequence
- Spatial: positions, trajectories, impact points, geometry
- Evidence: sources, confidence, contradictions, gap detection
- Causal: contributing factors, causal chains, counterfactual traces
- Physical: delta-V vectors, forces, crush profiles, energy dissipation

Cross-layer queries: full timeline (temporal+spatial+causal+physical),
causal chain tracing (causal→temporal→physical), evidence-to-pycrash
projection, layer summary statistics.

.crash v2.0 format: exports full raw graph (_nodes/_edges) for lossless
reimport, plus structured per-layer data for human readability.

57 API tests passing, 137 core tests passing (194 total).

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Step-by-step Docker setup, copy-paste examples for every endpoint,
troubleshooting section, and full API reference table.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Before: everything crammed under api/ with infra files mixed in
After: clean separation of concerns

  pycrash_ai/
    __init__.py          # proper package init (was missing)
    app.py               # FastAPI app (was api/main.py)
    config.py            # app config (was api/config.py)
    models.py            # Pydantic models (was api/models.py)
    agent/               # LLM extraction agents
    graph/               # hypergraph store + layers
    routes/              # API route handlers
    tasks/               # Celery async tasks
    data/                # vehicle database (was api/db/)
    docker/              # Dockerfile + compose (was at package root)
    scripts/             # run_local.sh (was at package root)
    tests/               # test suite

All imports simplified: pycrash_ai.api.X -> pycrash_ai.X
All 194 tests passing (57 API + 137 core).

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
libgdk-pixbuf2.0-0 -> libgdk-pixbuf-2.0-0 (renamed in newer Debian).
Also remove obsolete docker-compose version key.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
- Delete requirements.txt: frozen 2020 lockfile with pins contradicting
  pyproject.toml (pandas==1.2.0 vs >=2.0, matplotlib==3.3.3 vs >=3.7, etc)
- pyproject.toml is now single source of truth for all deps
- Add [ai] optional extra with all pycrash_ai deps (fastapi, anthropic, etc)
- Dockerfile simplified: `pip install -e ".[dev,ai]"` instead of manual list
- Fix setup.py python_requires: 3.6 -> 3.9
- Include pycrash_ai in package find

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
- Update CLAUDE.md with pycrash_ai directory layout and testing commands
- Update PRD.md project structure to match actual layout
- Fix stale path references in test comments

New tests (20):
- TestConfig: settings defaults, reports dir
- TestModels: SDOFRequest validation, ExtractedVehicle optionals, ExtractionResponse
- TestSchema: NodeLabel/GraphLayer enums, NODE_LAYER mapping, EVIDENCE_TO_PYCRASH
  converter, CrashPhase/ContributingFactor enums, REQUIRED_VEHICLE_PARAMS
- TestTools: tool definitions exist, required fields, extract_vehicle schema
- TestHeuristicExtraction: speed extraction, vehicle info, empty text handling

214 total tests passing (137 core + 77 API).

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Old pip (24.0) fails on editable installs with pyproject.toml.
Upgrade pip/setuptools/wheel first, then use regular install.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
setup.py reads README.md for long_description but the Dockerfile wasn't
copying it into the container. Added COPY README.md and a try/except
fallback in setup.py for resilience.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Setuptools 82+ enforces PEP 639 which prohibits license classifiers
alongside license expressions. Switched to license-expression field
and removed the license classifier from both pyproject.toml and setup.py.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Pin setuptools<82 in both build-system requires and Dockerfile to avoid
PEP 639 enforcement that creates a catch-22: setuptools 82 rejects license
classifiers alongside license field, but its validator also rejects the
new license-expression field. Using table-style license = {text = "..."}
with setuptools <82 resolves both issues.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Redis only needs to be accessible within the Docker network. Removing
the host port binding prevents conflicts when port 6379 is already in use.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
…e name

autodiscover_tasks looks for a 'tasks.py' inside each package, but ours
is named 'simulation_tasks.py'. Using conf.include explicitly registers
the correct module so tasks appear in the worker.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Creates appuser to avoid running Celery/Uvicorn as root, which
eliminates the Celery superuser security warning.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Full single-page application served from FastAPI:
- index.html shell with dark sidebar, Alpine.js router, page loading
- 7 page partials: dashboard, pipeline, simulator, monte carlo,
  vehicles, cases, reports
- 6 JS modules: simulator, montecarlo, vehicles, cases, pipeline, reports
- Custom CSS with animations and transitions
- All pages use Alpine.js for reactivity, Tailwind CSS, Plotly.js charts
- Added delete case endpoint
- Uses Alpine.initTree() for dynamic page loading

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
pycrash_ai has grown into its own platform (web UI, Docker stack, graph
DB, Celery workers, LLM agents). This creates a self-contained project
in pycrash_ai_standalone/ that imports pycrash as an external PyPI dep.

Standalone project includes:
- pyproject.toml with pycrash>=0.0.18 as dependency
- Docker setup (Dockerfile + compose with Redis, FalkorDB)
- Complete web UI (Alpine.js + Tailwind + Plotly.js)
- All routes, graph layers, agents, tasks, tests
- README for non-technical users
- .env.example, .gitignore

Also removes [ai] extra from pycrash's pyproject.toml since
pycrash_ai is now its own project.

To use: copy pycrash_ai_standalone/ contents into a fresh repo.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Work in progress from parallel agents:
- Sync Monte Carlo endpoint (no Celery needed)
- IMPC and sideswipe model endpoints
- API key auth middleware (optional via PYCRASH_API_KEY)
- Rate limiting (100/min general, 10/min simulation)
- Request logging middleware
- LLM prompt injection sanitization
- Case persistence config
- CLAUDE.md for standalone project
- Applied to both pycrash_ai/ and standalone copy

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
- store.py: disk persistence for cases (auto-save/load from data dir)
- simulate.py: IMPC momentum-based collision endpoint
- ingest.py (standalone): input sanitization for document ingestion

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
claude added 10 commits April 4, 2026 18:38
- Vehicle database: 20 -> 68 vehicles (sedans, SUVs, trucks, luxury, EVs)
- Scene diagram: new visualization endpoint + UI page + JS
- Case persistence: Docker volume mount, cases_dir config, auto-save
- Cases routes: _persist_case() called after all mutations
- Alpine.js: robust page loading with proper cleanup
- index.html: added Scene Diagram nav item + visualize.js

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
The host volume mount (../..:/app) overlays /app in the container,
which can cause bare 'uvicorn' and 'celery' commands to fail if
/usr/local/bin isn't in the appuser's PATH. Using 'python -m uvicorn'
and 'python -m celery' is more reliable.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
When pycrash_ai was separated, the [ai] extra was removed from
pycrash's pyproject.toml. The Dockerfile was only doing pip install
".[dev]" which installs pytest/ruff but not fastapi/uvicorn/celery.
Added explicit pip install for all pycrash_ai dependencies.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
- Project name: pycrash-ai (not generic 'docker')
- Container names: pycrash-api, pycrash-worker, pycrash-redis, pycrash-falkordb
- Dedicated network: pycrash-net (no conflicts with other projects)
- Prefixed volumes: pycrash-reports, pycrash-cases, pycrash-falkordb-data
- Fixed critical volume mount: was mounting ../..:/app which overwrote
  all pip-installed packages. Now mounts only source dirs (pycrash_ai/
  and pycrash/) as read-only, preserving installed deps.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Replace the dry form-based simulator with a visual, interactive experience:
- Canvas-based 2D top-down crash animation with 4 phases (approach, impact, separation, results)
- Vehicle rendering with crush deformation, impact sparks, screen shake
- Slider-based inputs with plain English labels ("How heavy?", "How fast?")
- Big gradient CRASH! button, severity labels, fun force comparisons
- Delta-V arrows and result overlays on the animation canvas
- Technical charts hidden in collapsible section for power users

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
Extended version with circular speedometer gauges, gravity-affected spark
particles, distance markers on road, rear windows on vehicles, and a
clickable replay button with hover cursor.

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
- Rename package directory pycrash_ai/ -> crashout/
- Update all Python imports, module paths, and logger names
- Update pyproject.toml package name, entry points, tool config
- Update Docker container/image/network/volume names to crashout-*
- Update README, CLAUDE.md, and all documentation references

https://claude.ai/code/session_01QLH89mFhr6EtaivkrygBcU
@hordruma hordruma closed this Jun 2, 2026
@hordruma hordruma reopened this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants