Public: anyone can read this; the crew can change it.

A GPS track (.gpx) in a repository renders as its route drawn as an outline, with distance and climb #10382

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

A `.gpx` file on a repository's file page now renders as an inline SVG outline of its tracks and routes, with total distance, elevation gain and point count beside it. The new tests, the kinds and subtitles tests, `tsc` and `scripts/gate.ts` pass. I did not run `scripts/design-lint.ts` or open a rendered file page in the running app. I also did not write a `docs/features` page or run the rest of t…

shipped production is serving it deploy f21b126

opened this

A .gpx file on a repository's file page now renders as an inline SVG outline of its tracks and routes, with total distance, elevation gain and point count beside it. The new tests, the kinds and subtitles tests, tsc and scripts/gate.ts pass. I did not run scripts/design-lint.ts or open a rendered file page in the running app. I also did not write a docs/features page or run the rest of the suite.

  • Parser: src/web/render/gpx.ts is a small tag scanner with no dependency. It reads only the five predefined entities and numeric references in names. A DOCTYPE with <!ENTITY> definitions is skipped, so &b; stays the literal text &b; and nothing expands.
  • Fallback to text: a file whose tags don't nest, has no <gpx> root, or holds no valid point falls back to the source view.
  • Drawing: longitude is scaled by the cosine of the middle latitude and fitted to a 640×480 box. Distance is the haversine sum and climb is the sum of rises. Names are escaped.
  • Thinning: distance, climb and point count use every point. Only the drawing is thinned, evenly across the whole track and keeping both ends, once a file has more than 20,000 points.
  • Registration: gpx is a new file kind in kinds.ts with a 20 MB render cap and an extension-based mapping, and renderers.ts maps it to the new renderer. I added a gpx sample to test/render-kinds.test.ts, which walks every extension.
  • Tests: test/render-gpx.test.ts covers a known two-point track within 1% of 111.2 km, a malformed file, an entity-expansion attempt, escaped names, even thinning, and a single-point route.

I did not de-duplicate points or filter GPS noise out of the climb. Climb is the plain sum of rises. Waypoints (<wpt>) are not drawn, because the issue asks for tracks and routes only.

The push hook demanded a Try: commit line, so there is an empty commit with one. To try it, open any .gpx file in a repository.

🤖 Generated with Claude Code

Closes #10329

commented

A .gpx file on a repository's file page now renders as an inline SVG outline of its tracks and routes, with total distance, elevation gain and point count beside it. The new tests, the kinds and subtitles tests, tsc and scripts/gate.ts pass. I did not run scripts/design-lint.ts or open a rendered file page in the running app. I also did not write a docs/features page or run the rest of the suite.

  • Parser: src/web/render/gpx.ts is a small tag scanner with no dependency. It reads only the five predefined entities and numeric references in names. A DOCTYPE with <!ENTITY> definitions is skipped, so &b; stays the literal text &b; and nothing expands.
  • Fallback to text: a file whose tags don't nest, has no <gpx> root, or holds no valid point falls back to the source view.
  • Drawing: longitude is scaled by the cosine of the middle latitude and fitted to a 640×480 box. Distance is the haversine sum and climb is the sum of rises. Names are escaped.
  • Thinning: distance, climb and point count use every point. Only the drawing is thinned, evenly across the whole track and keeping both ends, once a file has more than 20,000 points.
  • Registration: gpx is a new file kind in kinds.ts with a 20 MB render cap and an extension-based mapping, and renderers.ts maps it to the new renderer. I added a gpx sample to test/render-kinds.test.ts, which walks every extension.
  • Tests: test/render-gpx.test.ts covers a known two-point track within 1% of 111.2 km, a malformed file, an entity-expansion attempt, escaped names, even thinning, and a single-point route.

I did not de-duplicate points or filter GPS noise out of the climb. Climb is the plain sum of rises. Waypoints (<wpt>) are not drawn, because the issue asks for tracks and routes only.

The push hook demanded a Try: commit line, so there is an empty commit with one. To try it, open any .gpx file in a repository.

🤖 Generated with Claude Code

commented

The preview deploy failure doesn't come from this pull's code, so I changed nothing and pushed nothing.

  • The log: it shows no error from the app. The last line is forge draining … why=SIGTERM, so the preview host was restarted during the deploy. "No tests declared, none run" is just what the preview deploy prints for this app.
  • The preview now: /healthz on https://lab--10382--forge-trevato-apps.open-platform.sh returns 200.
  • Checks I ran locally:

- bun scripts/gate.ts passes. - bun x tsc --noEmit is clean. - test/render-gpx.test.ts and test/render-kinds.test.ts pass (15 tests).

  • The Try: rule: CLAUDE.md requires a Try: line in a commit message when src/web changes. The subject of d7f3c66bc already satisfies it.

Pull description

A .gpx file in a repository now renders as its route outline, with distance, climb and point count. The renderer is src/web/render/gpx.ts, registered in kinds.ts and renderers.ts. Tests are in test/render-gpx.test.ts, with one added line in test/render-kinds.test.ts. There are no new dependencies. To try it, open a .gpx file in a repository on the preview.

🤖 Generated with Claude Code

the crew's run was interrupted: restart, resumes on the next pass — cancelled
commented

A GPS track (.gpx) in a repository now renders as a track view, and the branch is merged with current main and pushed. The merge had no conflicts and gate.ts and tsc --noEmit came back clean. I did not run the full suite. fast.ts named 1,424 test files (an estimated two hours), so I ran the GPX tests instead.

  • What changed: src/web/render/gpx.ts is new. It is registered in src/web/render/kinds.ts and src/web/render/renderers.ts. Tests are in test/render-gpx.test.ts, plus one added line in test/render-kinds.test.ts.
  • What I ran: test/render-gpx.test.ts, test/render-kinds.test.ts and test/security-floor-routes.test.ts. 18 of 19 tests pass.
  • The one failure: the "two passes' request loops together take under 5 s" timing check in test/security-floor-routes.test.ts took 7.1 s. That file came in with main, and I did not touch it. Requests there fail with posix_spawn 'git' ENOENT because my sandbox can't spawn git, which probably explains the slowness. I expect the forge's check to run it normally.
  • What I chose not to do: I did not touch anything outside the GPX renderer, its registration and its tests.
  • How to try it: open a .gpx file in a repository on the preview at https://lab--10382--forge-trevato-apps.open-platform.sh.
commented

I merged main into the branch and pushed. A GPS track (.gpx) in a repository still renders as a track view, now alongside the new calendar (.ics) renderer from main.

  • Conflicts: src/web/render/kinds.ts, src/web/render/renderers.ts and test/render-kinds.test.ts. Each was two registrations added at the same spot, so I kept both. That means the gpx and calendar kinds, their size caps, the extension mappings, the renderer entries, and one sample per kind in the registry test.
  • Checks:

- bun x tsc --noEmit is clean. - test/render-gpx.test.ts, test/render-kinds.test.ts and test/render-ics.test.ts pass. - bun scripts/gate.ts printed nothing, which I took as clean.

  • Not run: the full suite. It is too broad to run in the sandbox, so the forge's check will run it on this push.
  • Left alone: the timing test in test/security-floor-routes.test.ts that failed earlier in this sandbox. I did not re-run it this time.
  • To try it: open a .gpx file in a repository on the preview at https://lab--10382--forge-trevato-apps.open-platform.sh.
Changes requested — before the latest push

The parser, thinning and tests are solid, but the change is not finished on three counts.

  1. Phone: no CSS exists for gpx-view, and the SVG is emitted with fixed width/height (up to 640px), so on a 360px phone it overflows sideways. Fix first: size it with CSS (max-width:100%; height:auto) and drop the fixed width/height attributes (keep viewBox), adding the rule in the right style module.
  2. Both doors: the terminal workspace has no GPX view. The sibling .ics pull touched src/tui/screens/workspace.ts and test/tui-workspace.test.ts; this one must too (distance, climb, points as text).
  3. No docs/features/gpx.md how-to (ics added docs/features/ics.md).

Also: tests do not cover the rendered page route, and design-lint was not run; run bun scripts/design-lint.ts. Ticks: box 2 and 3 are met; box 1 is not until the phone and terminal gaps close.

commented

A .gpx file in a repository now renders as a route outline with distance, climb and points, on the web and in the terminal workspace. I haven't opened it on a 360px screen. The checks that ran are green: bun x tsc --noEmit, bun scripts/gate.ts, bun scripts/design-lint.ts, and the GPX render, blob-page and TUI workspace tests. The full suite was not run here; the forge runs it on this push.

Changes since the review

  • Phone: I dropped the fixed width and height from the SVG and kept viewBox. A new .gpx-view rule in src/web/style/content.ts sets max-width:100%; height:auto, so the route scales to the column. The stroke is currentColor and there is no accent.
  • Facts: I replaced the bespoke figcaption with the existing .status-rows / .status-row rows for Track, Distance, Climb and Points. A new gpxFacts() in src/web/render/gpx.ts supplies them to both doors.
  • Terminal: src/tui/screens/workspace.ts opens a .gpx as a Fact / Value table using the same parser; s flips to the source and the status line reads 4 facts.
  • Docs: docs/features/gpx.md is the new how-to. docs/design/areas/render.md names .gpx-view, which is what design-lint asked for.
  • Tests:

- test/blob-gpx-page.test.ts fetches the real blob page route and checks the SVG, the fact rows and escaping. - test/render-gpx.test.ts checks that the SVG has no width or height and that the facts are status rows. - test/tui-workspace.test.ts opens a .gpx in the terminal workspace.

Not done: there are no map tiles and no elevation profile, as before. The terminal shows the facts as text only, with no outline drawing.

commented

Fixed the failing check and pushed. A .gpx file in a repository renders as a route outline with its facts, and the type error is gone.

origin/main had made download a required field on RenderInput, and test/render-gpx.test.ts built its input without it. I merged current main into the branch and added download: "/d" to the test's input, the same way the CSV tests do. Only that test line changed.

After the merge, bun scripts/gate.ts and bun x tsc --noEmit ran clean. The 8 tests in test/render-gpx.test.ts pass. I did not run the rest of the suite, since the forge runs the full check on the push.

To try it, open any .gpx file in a repository on the preview at https://lab--10382--forge-trevato-apps.open-platform.sh.

commented

This pull's GPX change is unchanged. I merged current main and made one edit to get the check green: I listed src/kernel/why_now.ts in scripts/unreached-allow.json.

The failing test was "every module under src/ is imported by another, or allowed". It failed because of main, not because of the GPX change. Commit 54dacba00 (retiring the gate's "why now" direction) left src/kernel/why_now.ts imported by nothing under src/. Only test/why-now.test.ts imports it.

After the merge and the allowlist edit, test/unreached.test.ts and tsc --noEmit pass here. I ran only those two; the forge's check will run the full suite on this push.

Decision for you: I did not delete the module or wire it into the app, because that is main's decision. If main fixes it first, this allowlist entry becomes stale and the "allowed module that has become reached" test will fail until the entry is removed.

Approved

Earlier asks are met. The SVG has no fixed width or height and scales to a 360px column. Facts are status-rows, not a figcaption. The terminal opens a .gpx as a Fact/Value table. docs/features/gpx.md exists and README is untouched. Blob-page, TUI and renderer tests cover the behaviour. Output is escaped and the DOCTYPE is never expanded. One accent rule holds: stroke is currentColor.

Two things I would do next, both non-blocking:

  1. Non-blocking: in src/web/style/content.ts the new gpx rules were inserted between the font specimen comment and .font-view, so that comment now sits above the wrong rules. Move the gpx block above it.
  2. Non-blocking: the src/kernel/why_now.ts entry in scripts/unreached-allow.json is unrelated to GPX. It goes stale once main fixes it, so drop it when main does. I did not load the preview with a .gpx file, so the rendered page is judged from the blob-page test and the served CSS source.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs