Skip to content

Remove consolidated stops while importing - #1775

Draft
aaronbrethorst wants to merge 2 commits into
ab/stop-consolidation-applyfrom
ab/stop-consolidation-store
Draft

aaronbrethorst wants to merge 2 commits into
ab/stop-consolidation-applyfrom
ab/stop-consolidation-store

Conversation

@aaronbrethorst

@aaronbrethorst aaronbrethorst commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Part of #1977

Draft. Stacked on #1774. It stays draft until multi-feed phases B and C land.

What it does

GtfsData gets StopReplacements, keyed by absorbed stop ID. The import applies them the way Java's bundle builder does:

  • Absorbed stops are not stored.
  • Their stop times move to the canonical stop, or are dropped when the canonical stop isn't stored. Java's StopTimeEntriesFactory drops those too.
  • Children of an absorbed station point at the canonical stop, or at no parent. Java doesn't rewrite parent_station, but maglev's schema needs a valid parent.
  • Trip ends, and so the block indexes, see the consolidated stops.
  • Audit table: each absorbed stop is recorded in a new stop_consolidations table in the same transaction. The stop/{id} alias and realtime translation will read it, because a restart that skips an unchanged import never reads the file again.

Nothing sets StopReplacements yet; #1776 does.

Root cause

Maglev's import has no way to merge stops. That's the gap stop consolidation fills.

Testing

  • Test failing on main before this change: n/a (new feature).
  • Manual check: n/a: nothing reads the new table until Apply a stop consolidation file on static import #1776 applies a file. The RABA parity digests below show that nothing else changes.
  • TestStoreGtfsData_ConsolidatesStops, TestFeedRows_TripEndsUseConsolidatedStops and TestStoreGtfsData_ReimportClearsStopConsolidations.
  • RABA parity table digests are unchanged except for the new, empty stop_consolidations table, so nothing changes until a file is configured.
  • make test and go vet (both tag sets) pass.

Checklist

  • This PR addresses one issue.
  • It is under ~200 changed lines, or the description says why it can't be split.
    • About 230 hand-written lines; sqlc output is regenerated with make models.
  • This PR is not a bug fix, or the new or changed test fails on main and passes on this branch.
  • Each commit is one logical change with a clear message.
  • I did not hand-edit sqlc-generated files under gtfsdb/ (db.go, models.go, query.sql.go) or testdata/openapi.yml (synced from upstream).
  • This PR changes no handler, or handlers pass r.Context() to DB/service calls, not context.Background().
  • The response comparison above is filled in, or this PR doesn't change a Java-served response.
  • This PR adds no endpoint, or each new endpoint matches testdata/openapi.yml, has an issue open on OneBusAway/sdk-config, or is outside the SDK and the description says why.
  • I read every line of this diff and can explain it if asked.

Notes for reviewers

gtfsdb takes plain data (*gtfs.Stop pointers) and never imports internal/consolidation. That package imports internal/utils, which imports gtfsdb, so the reverse import would be a cycle.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

The description follows the PR template.

@github-actions

Copy link
Copy Markdown

Performance Smoke Test Results

Status: PASSED

Metric Value
p(95) latency 1.5 ms
Error rate 0.00%
Total requests 330
Req/sec 10.8

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

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

@github-actions github-actions Bot added the follows-template The PR description follows the PR template label Nov 8, 2026
@aaronbrethorst
aaronbrethorst force-pushed the ab/stop-consolidation-store branch from c510799 to dc4d63b Compare November 8, 2026 17:58
@aaronbrethorst
aaronbrethorst changed the base branch from ab/stop-consolidation-base to ab/stop-consolidation-apply November 8, 2026 17:58
@github-actions

github-actions Bot commented Nov 8, 2026

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.

@github-actions

github-actions Bot commented Nov 8, 2026

Copy link
Copy Markdown

Performance Smoke Test Results

Status: PASSED

Metric Value
p(95) latency 1.7 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.

@burma-shave burma-shave left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at dc4d63b. Looks correct; one ordering note.

  • On this branch alone, a trip whose stop times are all dropped (only_dropped in the fixture) is still stored in trips with no stop times, since stopTimes() returns early but nothing removes the trip row. #1777 fixes that by deleting it. Worth keeping #1775 and #1777 landing together (or folding the trip removal in here) so main never has trips without stop times.
  • Clearing stop_consolidations before stops is the right order for the canonical_id FK, and the RABA digests confirm nothing else moves.

Generated by Claude Code

A stop consolidation file removes the stops it absorbs. GtfsData now
carries StopReplacements, keyed by absorbed stop ID, and the import
applies them the way Java's bundle builder does:

- absorbed stops are not stored
- their stop times move to the canonical stop, or are dropped when the
  canonical stop is not stored (Java leaves them pointing at nothing,
  which maglev cannot store)
- trip ends, and so the block indexes, see the stops after this, and a
  trip left with no stop times has no ends

Java does not rewrite parent_station, so a child of an absorbed station
points at a stop that no longer exists. Maglev's schema does not allow
that, so the child points at the canonical stop, or at no parent when
its stop times would be dropped.

Each absorbed stop is recorded in a new stop_consolidations table in
the same transaction, with its name and location. A restart that skips
an unchanged import does not read the file again, so the API and
realtime will need this table to resolve absorbed IDs.

Nothing sets StopReplacements yet.
SonarCloud flags a DELETE with no WHERE clause as a blocker and an
ORDER BY with no direction as a smell. Clearing the table is the
intent, so say so with WHERE TRUE, as ClearStopAgencies already does,
and sort absorbed IDs ASC.
@aaronbrethorst
aaronbrethorst force-pushed the ab/stop-consolidation-store branch from dc4d63b to 58efad6 Compare November 9, 2026 19:04
@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown

Performance Smoke Test Results

Status: PASSED

Metric Value
p(95) latency 2.1 ms
Error rate 0.00%
Total requests 327
Req/sec 10.7

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

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

@aaronbrethorst
aaronbrethorst removed this pull request from stack #1985 November 9, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

follows-template The PR description follows the PR template

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants