Oklahoma tolls: how to maintain

Files: /srv/toll/draft/OK, last built 2026-10-10 01:44 ET · the OK toll page · map test · facts below are read from the files each time this page is built (python3 /home/geo1/system/handbuilt/maintain_pages.py OK)

Procedure for this state

Oklahoma: OTA's 13 turnpikes, cashless. The trip tables (every entry-exit pair, PIKEPASS and PlatePay, every class) come from the PIKEPASS calculator's public API. A route is priced from the first OTA plaza it passes on a turnpike to the last: OTA publishes no plaza positions, so ok_routes.py places each plaza name at the interchange it names on ODOT's 'Turnpikes' GIS layer (TOLLID), in OTA's order (= OSM exit numbers, OTA's mileposts) and by the cross road the name gives; a name at a turnpike's end also marks the mainline beyond its last interchange.

When to check

Rebuild

bash chain.sh OK; OK_ROUTES_REPORT=1 python3 ok_state.py prints every name's ramps and the ramps left without a name.

Watch out

The chain every state shares

Hosts: geo1 (192.168.50.220) holds the sources, builders, drafts, map and API; b100 (192.168.50.14) is the test client. All times are Eastern.

whatwhere (geo1 unless said)
sources list/home/geo1/maps/toll/OK/urls.txt (name <tab> URL)
archived sources/home/geo1/maps/toll/OK/sources/<name>/<YYYY-MM-DD>/ (file + meta.json: url, fetched, sha256)
builder/home/geo1/system/handbuilt/ok_state.py; shared code toll_common.py
OpenStreetMap inputs/home/geo1/system/handbuilt/osm/ok_* (cut from /home/geo1/maps/osm/us-latest.osm.pbf)
outputdraft /srv/toll/draft/OK/ (the builders write here); published /srv/toll/OK/ (copied from the draft by promote.py publish). The map and the API read the published page, or the draft while it is listed for review
toll enginesource /home/geo1/maps/web/tolls.js, served copy /srv/maps/tolls.js (the API runs the served copy)
API/home/geo1/maps/api/server.mjs on 127.0.0.1:8090 behind nginx /api/; pid in logs/test.pid
regression tripsb100: ~/apitest/site/cases.json, runner ~/apitest/run.py, browser check ~/apitest/browser.mjs

1. Refresh a source

  1. Fetch into a new dated folder: python3 /home/geo1/system/handbuilt/fetch_list.py OK [name ...] (no names = every line of urls.txt). A new source: add a line to urls.txt first, then fetch it by name.
  2. A site that refuses geo1 (HTTP 403) or scripts: fetch it on b100 in headless Chrome with node ~/apitest/fetch_b100.mjs <out> <name>=<url> ..., then rsync -a <out>/ geo1@192.168.50.220:/home/geo1/maps/toll/OK/sources/. Its meta.json records that it came from b100.
  3. Compare the new file with the previous dated one (diff, pdftotext -layout for PDFs). Same content: nothing to do. Changed amounts or a new effective date: rebuild (step 2) and update the expected amounts of the affected regression trips from the operator's own figures.

1b. The corpus (NJ, PA, VA start from it; DE is published from it)

python3 /home/geo1/maps/toll/bin/tollup.py OK update fetches the adapter's sources (bin/adapters/ok.py), stores a document only when its content changes, writes one rate file per version under /home/geo1/maps/toll/OK/rates/ and appends every price change to history.csv (every run to runs.log). TOLL_WEB=/home/geo1/maps/toll/corpus python3 /home/geo1/maps/toll/bin/publish.py OK writes the corpus /home/geo1/maps/toll/corpus/OK from it (DE: plain publish.py DE writes /srv/toll/DE). Never hand-edit either. Then rebuild the draft (step 2) so it picks up the new rates.

2. Rebuild

3. Load it into the API and test from b100

  1. The API reads the toll pages and tolls.js when it starts. Restart it: cd /home/geo1/maps/api && kill $(cat logs/test.pid); (nohup /home/geo1/maps/node/bin/node server.mjs > logs/server.log 2>&1 & echo $! > logs/test.pid) (it is started by hand, not a service).
  2. From b100 only: python3 ~/apitest/run.py ~/apitest/site/cases.json. Every trip must be OK. Add a trip for every rate or rule you change, with the amount taken from the operator's own source.
  3. Engine change (tolls.js): edit /home/geo1/maps/web/tolls.js, check with /home/geo1/maps/node/bin/node --check, copy to /srv/maps/tolls.js with sudo install -o www-data -g www-data -m 644, restart the API, run the trips.

4. OpenStreetMap refresh (all states at once)

The builders match toll points to the OSM way ids the router drives, so the extracts here must come from the same us-latest.osm.pbf the router (Valhalla, /home/geo1/maps/valhalla_data) was built from (now 2026-09-27). New OSM data means: rebuild the router tiles, then for each state cut the box, rebuild its OSM inputs and run the full chain, then compare untied_toll_nodes.csv and the estimated positions below. The box for OK and the cutting commands are in the state's procedure above; the toll-node and way index comes from python3 tollnode_ways.py OK.

5. Publish

A rebuild writes the draft (/srv/toll/draft/OK); the published page (/srv/toll/OK) does not change. python3 /home/geo1/maps/toll/bin/promote.py review OK lists the draft for review: the map and the API then read it instead of the published page. Run the regression trips from b100. After approval, python3 /home/geo1/maps/toll/bin/promote.py publish OK copies the draft to /srv/toll/OK (the previous page is kept under /home/geo1/maps/toll/OK/published/<time>/) and takes it off the review list. After a change, update the coverage line for OK in the API page (/api.html, generator /home/geo1/maps/api/doc/api_page.py) and rebuild this page: python3 /home/geo1/system/handbuilt/maintain_pages.py OK.

Sources (6)

Each fetch is kept in its own dated folder under /home/geo1/maps/toll/OK/sources/<name>/; the builder always reads the newest one, so a new fetch takes effect at the next rebuild and the old one stays for comparison.

sourcefetched (newest)fetches kepthowlisted in urls.txtrows using it
odot_turnpikes_layer
https://services6.arcgis.com/RBtoEUQ2lmN0K3GY/arcgis/rest/services/Turnpikes/FeatureServer
2026-10-101fetched on b100 (192.168.50.14): ODOT GIS open data layer 'Turnpikes' (gis-okdot.opendata.arcgis.com), TOLLID = OTA turnyes
ota_outlook_2026
https://oklahoma.gov/content/dam/ok/en/ota/documents/annual-outlook/2026_OTA%20Outlook.pdf
2026-10-101fetch_list.pyyes
ota_toll_schedules_2024
https://oklahoma.gov/content/dam/ok/en/ota/documents/annual-report/2024%20ACFR_Toll%20Sche
2026-10-101fetch_list.pyyes
ota_tollrates_api
https://ppentapi.pikepass.com/api/sharedlookuppublic/turnpikes/{t}/class/{c}/tollrates (al
2026-10-101fetched on b100 (192.168.50.14): the PIKEPASS toll calculator's public API, every turnpike x classyes9197
pikepass_home
https://pikepass.com/pikepass
2026-10-101fetch_list.pyyes
pikepass_toll_calculator
https://pikepass.com/plan-your-trip/toll-calculator
2026-10-101fetched on b100, headless Chrome, rendered pageyes

Facilities (13)

idfacilityoperatorpointsrate / trip rowseffective dates in the rowssource
OK-OTA-TURNERTurner TurnpikeOklahoma Turnpike Authority (OTA)1210802026-10-10_observedota_tollrates_api
OK-OTA-WILLROGEWill Rogers TurnpikeOklahoma Turnpike Authority (OTA)118002026-10-10_observedota_tollrates_api
OK-OTA-HEBAILEYH.E. Bailey TurnpikeOklahoma Turnpike Authority (OTA)1210202026-10-10_observedota_tollrates_api
OK-OTA-MUSKOGEEMuskogee TurnpikeOklahoma Turnpike Authority (OTA)94102026-10-10_observedota_tollrates_api
OK-OTA-INDIANNAIndian Nation TurnpikeOklahoma Turnpike Authority (OTA)94602026-10-10_observedota_tollrates_api
OK-OTA-CIMARRONCimarron TurnpikeOklahoma Turnpike Authority (OTA)83602026-10-10_observedota_tollrates_api
OK-OTA-KILPATRIKilpatrick TurnpikeOklahoma Turnpike Authority (OTA)1816322026-10-10_observedota_tollrates_api
OK-OTA-CHEROKEECherokee TurnpikeOklahoma Turnpike Authority (OTA)62002026-10-10_observedota_tollrates_api
OK-OTA-CHICKASAChickasaw TurnpikeOklahoma Turnpike Authority (OTA)5802026-10-10_observedota_tollrates_api
OK-OTA-CREEKCreek TurnpikeOklahoma Turnpike Authority (OTA)2125922026-10-10_observedota_tollrates_api
OK-OTA-KICKAPOOKickapoo TurnpikeOklahoma Turnpike Authority (OTA)73002026-10-10_observedota_tollrates_api
OK-OTA-SOUTHWESSouthwest JKT TurnpikeOklahoma Turnpike Authority (OTA)61302026-10-10_observedota_tollrates_api
OK-OTA-GILCREASGilcrease TurnpikeOklahoma Turnpike Authority (OTA)51202026-10-10_observedota_tollrates_api

Positions placed by estimate (0): re-check when OpenStreetMap or the operator changes

None: every position comes from an official layer or a mapped toll node.

Decisions by rule

R2: 129, no: 9, not: 2, priced: 1 (all in decisions.csv).

Open gaps (0)

None.

Untied OSM toll nodes: 0

Toll booths / gantries mapped in OpenStreetMap on or near this state's roads that no toll point claims; a route through one lists it under unpriced. After an OSM refresh, look at new ones here (untied_toll_nodes.csv): a new gantry on a priced road means a point is missing.

Regression trips for OK (15)

Run from b100 (never on geo1): python3 ~/apitest/run.py ~/apitest/site/cases.json. Every trip must come back OK; a changed amount is either a rate change (update the expected amount from the operator's own source) or a fault.

tripexpected
OK Turner OKC (I-35) -> Tulsa, PIKEPASS car$5.40
OK Turner OKC (I-35) -> Tulsa, PlatePay car$10.50
OK Turner Luther (Hogback Rd) -> Stroud (SH 99), PIKEPASS car$1.68
OK Will Rogers Tulsa -> Joplin MO, PIKEPASS car$5.40
OK H.E. Bailey Lawton -> Oklahoma City, PIKEPASS car$4.04
OK Indian Nation Henryetta -> Hugo, PIKEPASS car$7.31
OK Kickapoo Turner jct -> I-40, PIKEPASS car$2.82
OK Creek Sapulpa (SH 66) -> Broken Arrow (County Line Rd), PIKEPASS car$2.31
OK Kilpatrick Eastern Ave -> NW Expressway, PIKEPASS car$1.50
OK Muskogee Broken Arrow -> I-40 (Webbers Falls), PIKEPASS car$3.80
OK Cimarron I-35 -> Tulsa (Keystone), PIKEPASS car$3.65
OK Cherokee Locust Grove -> Arkansas line, PIKEPASS car$3.08
OK Chickasaw Sulphur -> Ada (SH 1), PIKEPASS car$0.72
OK Gilcrease Sand Springs Expwy -> I-44, PIKEPASS car$2.05
OK SW John Kilpatrick I-40 -> SH 152, PIKEPASS car$0.78