Skip to content

fix: shape endpoint polyline parity with Java (floor encoding, no point reduction)#1076

Open
Ahmedhossamdev wants to merge 2 commits into
mainfrom
fix/shape-endpoint-spec-gaps
Open

fix: shape endpoint polyline parity with Java (floor encoding, no point reduction)#1076
Ahmedhossamdev wants to merge 2 commits into
mainfrom
fix/shape-endpoint-spec-gaps

Conversation

@Ahmedhossamdev

@Ahmedhossamdev Ahmedhossamdev commented Jun 16, 2026

Copy link
Copy Markdown
Member

Fixes: #990, #1075

Description

Fixes two spec gaps in /api/where/shape/{id}, both verified byte-for-byte against the live Java reference server (all 18 unitrans shapes now identical).

1. Encoding rounded instead of flooring
The go-polyline library rounds coordinates; Java's PolylineEncoder floors (floor(coord * 1e5)). This produced ~1e-5° (~1 m) off-by-one errors on ~38% of points in every shape. Added utils.EncodePolyline, a floor-based encoder mirroring the Java algorithm.

2. Dropped consecutive duplicate points
The handler filtered consecutive duplicates, but the spec requires all points included with no simplification (Java's single-shape path does no filtering). Removed the filtering; length and points now reflect every GTFS point.

Updated the shape test that asserted the old dedup behavior; added unit tests for the encoder. Full suite + lint pass.

Note: stops-for-route shares the same rounding divergence (polyline.EncodeCoords); it'll be migrated to utils.EncodePolyline during that endpoint's review, after which the go-polyline dep can be dropped.

Summary by CodeRabbit

Release Notes

  • Bug Fixes
    • Improved route polyline encoding for more accurate shape representation
    • Enhanced coordinate precision handling in route data
    • Preserved duplicate points in route paths for accurate path fidelity

@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Ahmedhossamdev, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 39 minutes and 58 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b8046a79-6ea8-47f3-b061-0af48c0d5a47

📥 Commits

Reviewing files that changed from the base of the PR and between 1668917 and ad7a1cd.

📒 Files selected for processing (1)
  • internal/utils/polyline_test.go
📝 Walkthrough

Walkthrough

Replaces the go-polyline third-party library in shapesHandler with a new utils.EncodePolyline function in internal/utils/polyline.go. The encoder floors coordinates (rather than rounding) at 1e5 precision to match the Java OBA reference implementation. Consecutive-duplicate point filtering is removed from the handler, and tests are updated accordingly.

Changes

Polyline encoder replacement

Layer / File(s) Summary
EncodePolyline implementation and unit tests
internal/utils/polyline.go, internal/utils/polyline_test.go
Adds EncodePolyline using math.Floor-based coordinate scaling, zigzag signed-delta encoding, and 5-bit chunk output. Four unit tests cover canonical Google example output, flooring vs. rounding, duplicate point preservation, and nil input.
shapesHandler wiring and test update
internal/restapi/shapes_handler.go, internal/restapi/shapes_handler_test.go
Swaps go-polyline import for internal/utils, removes the consecutive-duplicate filtering loop, and calls utils.EncodePolyline. The handler test's "Consecutive duplicates" subcase is updated to expect both duplicate points in the decoded output.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #1075: The PR directly implements what issue #1075 describes — replacing go-polyline with a floor-based custom encoder and removing duplicate-point filtering.
  • #990: This change addresses a spec gap in the shape endpoint by aligning polyline encoding behavior with the Java OBA reference implementation.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main changes: fixing polyline encoding to use floor-based approach for Java parity and removing point deduplication.
Linked Issues check ✅ Passed The PR addresses specification gaps identified in #990 by fixing polyline encoding (floor vs. round) and removing point filtering to match Java implementation and spec requirements.
Out of Scope Changes check ✅ Passed All changes directly address the two identified specification gaps: polyline encoding method and point filtering behavior. No unrelated modifications are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/shape-endpoint-spec-gaps

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

Performance Smoke Test Results

Status: PASSED

Metric Value
p(95) latency 2.0 ms
Error rate 0.00%
Total requests 338
Req/sec 11.1

Smoke test config: 5 VUs x 30s. Thresholds: p(95) < 300ms, error rate < 1%.

Full results uploaded as workflow artifact: k6-smoke-summary.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/utils/polyline_test.go (1)

19-31: ⚡ Quick win

Add a negative-boundary flooring assertion to harden Java parity.

The flooring test currently covers only a positive near-boundary value. A regression to truncation semantics on negative coordinates could slip through; adding a negative near-zero case closes that gap.

Suggested test extension
 func TestEncodePolyline_FloorsNotRounds(t *testing.T) {
@@
 	if got == rounded {
 		t.Errorf("floored encoding should differ from rounded 0.00002 encoding %q", rounded)
 	}
+
+	negGot := EncodePolyline([][]float64{{-0.000019, 0}})
+	negFloored := EncodePolyline([][]float64{{-0.00002, 0}})
+	negTruncated := EncodePolyline([][]float64{{-0.00001, 0}})
+	if negGot != negFloored {
+		t.Errorf("floor(-0.000019*1e5) should match -0.00002 encoding; got %q want %q", negGot, negFloored)
+	}
+	if negGot == negTruncated {
+		t.Errorf("floored encoding should differ from truncated -0.00001 encoding %q", negTruncated)
+	}
 }
🤖 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 `@internal/utils/polyline_test.go` around lines 19 - 31, The
TestEncodePolyline_FloorsNotRounds test currently only verifies flooring
behavior for positive near-boundary coordinates. Add additional test assertions
within this function to verify that negative near-boundary values are also
properly floored (not truncated or rounded) by EncodePolyline. Include test
cases with negative coordinates near zero (such as -0.000019) to ensure the
flooring semantics work correctly across the negative boundary, matching the
Java implementation behavior and preventing regressions on negative coordinate
handling.
🤖 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 `@internal/utils/polyline_test.go`:
- Around line 19-31: The TestEncodePolyline_FloorsNotRounds test currently only
verifies flooring behavior for positive near-boundary coordinates. Add
additional test assertions within this function to verify that negative
near-boundary values are also properly floored (not truncated or rounded) by
EncodePolyline. Include test cases with negative coordinates near zero (such as
-0.000019) to ensure the flooring semantics work correctly across the negative
boundary, matching the Java implementation behavior and preventing regressions
on negative coordinate handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 90dc4594-16ed-42c2-a655-1fe7c0f792ef

📥 Commits

Reviewing files that changed from the base of the PR and between 9898b8f and 1668917.

📒 Files selected for processing (4)
  • internal/restapi/shapes_handler.go
  • internal/restapi/shapes_handler_test.go
  • internal/utils/polyline.go
  • internal/utils/polyline_test.go

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

Performance Smoke Test Results

Status: PASSED

Metric Value
p(95) latency 1.9 ms
Error rate 0.00%
Total requests 337
Req/sec 11.0

Smoke test config: 5 VUs x 30s. Thresholds: p(95) < 300ms, error rate < 1%.

Full results uploaded as workflow artifact: k6-smoke-summary.

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.

Spec review: shape

1 participant