Skip to content

Lapache web-based lap analysis#158

Open
jacobjurek wants to merge 16 commits into
mainfrom
jake/lapache
Open

Lapache web-based lap analysis#158
jacobjurek wants to merge 16 commits into
mainfrom
jake/lapache

Conversation

@jacobjurek

Copy link
Copy Markdown
Contributor

Summary

Branch bundling the web-based Lapache lap-analysis work for review. Highlights:

  • New Lapache lap-analysis page in the dashboard plus backend endpoints.
  • Node-grouped signal dropdown shared by query and Lapache.
  • Date selector to scope raw-data browsing by day.
  • Calibration mode to plot signals vs. time.
  • Perf: anchor-signal cache and decimation of wide raw-data queries.
  • Latest fix: drop bad GPS fixes (non-finite + 0,0 "null island") from track points so a single bad outlier no longer collapses the real path.

Review notes

Opening this primarily to review the code on the branch. Several commits build on each other; the most recent is the GPS-track hardening.

🤖 Generated with Claude Code

jacobjurek and others added 16 commits May 29, 2026 15:41
Add a JSON analysis blob to the Session model so Lapache lap-analysis
results (lat/lon fields, normalization, crop, geometric segments, laps,
summary) persist via the existing session upsert. Add a custom JSON type
whose driver value is text so it casts cleanly into a Postgres jsonb column.

Add two query-service endpoints for browsing raw signal data when sessioning:
GET /query/signals/names (distinct signals in a window) and GET /query/clusters
(contiguous data blocks via minute-bucketed gap merging).

Includes Go and pytest coverage for the new model field, JSON type, cluster
merge logic, and route wiring.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
Port the PyQt Lapache desktop tool to a web page at /lapache. Pure logic
(segment intersection, coordinate normalization, lap/sector detection, the
segment manager) ports to TypeScript under lib/lapache; an API client swaps
the desktop app's direct DB access for the Mapache gateway endpoints.

The page browses sessions and raw-data clusters, fetches lat/lon telemetry,
renders the track on an HTML5 canvas where the user places S/F and sector
lines (click to add, shift/right-click to remove, keys 1-9 to switch, P to
process, Ctrl+Z to undo), then processes laps and saves the analysis blob
back to the session. Adds a sidebar nav entry and the route.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
main's mapache-go (v3.3.0) defaults Session.Analysis to {} rather than
null, so un-analyzed sessions now arrive as a truthy empty object. Add a
hasAnalysis() type guard keyed on a required field (lat_field) and use it
for the sidebar "analyzed ✓" badge and the LapachePage load-existing
branch, so the {} default no longer reads as "already analyzed."

Co-Authored-By: Claude Opus 4.8 <[email protected]>
query_signals bound a tuple to a single :signals placeholder, which only
worked by accident on psycopg2 (tuple adaptation) and errored on other
backends like SQLite. Declare it with bindparam(expanding=True) so the IN
list renders as individual placeholders on any backend.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
get_database_url interpolated DATABASE_USER/PASSWORD straight into the
DSN string. A password containing '@' (or '%'/non-ASCII bytes) bled into
the host portion, so psycopg2 tried to resolve "<pwtail>@<host>" and
failed with "could not translate host name". Build the URL via
sqlalchemy.URL.create so credentials are escaped. Go services were
unaffected because GORM doesn't parse a URL.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Keeps docker-compose.override.yml (used to point query at a remote DB for
local testing) out of git so it doesn't affect others' local stacks.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
…uency signal

- signal picker falls back to distinct signal names present for the selected
  vehicle when the curated signal_definition catalog is empty
- pass vehicle_id from the dashboard so the fallback can scope to the vehicle
- bucket clustering on the highest-frequency signal instead of the
  alphabetically-first name, which could be sparse and collapse every cluster

Co-Authored-By: Claude Opus 4.8 <[email protected]>
The signal_definition catalog is now populated, so the read-time fallback
to live signal names is no longer needed. Drops the fallback block, the
unused vehicle_id query param, and the dashboard query param.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
The bind-mounted /app/query holds .venv, scripts/ and tests/ alongside the
app package. uvicorn --reload watched the whole dir, so `uv run` touching
the venv triggered an endless reload loop that took the service down and
dropped it from Rincon's registry (gateway then 404'd /query/* routes,
surfacing as network errors in the dashboard). Limit the watcher to the
query package with --reload-dir.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Root .gitignore had no Python rules, so local .venv/ and __pycache__/
dirs (e.g. under gr26/tools, query) surfaced as untracked noise on
feature branches.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add a reusable SignalTree that groups signals by node prefix (ecu_,
bcu_, …) into collapsible sections, showing each signal's formatted
name with its full id as subtext. Wire it into the query signal
multi-select and the lapache lat/lon pickers.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Add a calendar date selector that limits cluster/session browsing to a
single local day. The backend gains a /clusters/dates endpoint
(get_data_dates) plus optional date/tz scoping on /clusters, so clusters
and the anchor bucketing are computed for just that day. On the frontend,
fetchClusters takes an optional date (sent with the browser timezone) and
a new fetchDataDates backs the default day and the "days with data" hints.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Two fixes for raw-data timeouts and latency:

- Cache the per-vehicle anchor signal (5 min TTL). Deriving it runs a
  GROUP BY name ORDER BY COUNT(*) that scans the whole vehicle partition,
  and it was recomputed on every /clusters and /clusters/dates request.

- Add optional server-side decimation to query_signals via a max_points
  param: when the window is known, bucket each signal by time and keep one
  row per bucket (DISTINCT ON), capping rows transferred, pivoted, and
  serialized. The track map (fetchSignalData) requests max_points=5000,
  which the canvas can't exceed visually; exports stay full-resolution.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
# Conflicts:
#	.gitignore
#	query/query/service/query.py
#	query/uv.lock
Add an in-page Lap/Calibration toggle. Calibration mode plots one or more
selected signals against time instead of a GPS track, for runs without a
usable GPS fix. Reuses the shared timeline crop to trim a window and create
a plain session over the crop (no lap/segment analysis). Chart supports a
raw <-> normalized Y-axis toggle so signals with different scales compare.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Coerce lat/lon to numbers and skip non-finite readings and the 0,0
"null island" fix the receiver emits before lock. The track autoscales
to its bounding box, so a single bad outlier collapsed the real path and
drew stray lines shooting to it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
@netlify

netlify Bot commented May 31, 2026

Copy link
Copy Markdown

Deploy Preview for gr-mapache ready!

Name Link
🔨 Latest commit daab264
🔍 Latest deploy log https://app.netlify.com/projects/gr-mapache/deploys/6a1bfbf45e539a000874fb6d
😎 Deploy Preview https://deploy-preview-158--gr-mapache.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 50
Accessibility: 95
Best Practices: 92
SEO: 83
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@jacobjurek jacobjurek requested a review from BK1031 May 31, 2026 09:28
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.

1 participant