Skip to content

fix(acquisition): read OpenSky state rows through the column-name table - #154

Merged
montge merged 2 commits into
developfrom
feature/unused-global-opensky
Sep 20, 2026
Merged

montge merged 2 commits into
developfrom
feature/unused-global-opensky

Conversation

@montge

@montge montge commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Resolves GitHub Code Quality finding #24 (py/unused-global-variable): "The global variable _STATE_COLUMNS_NEW is not used" in python/acquisition/opensky.py.

The tuple of OpenSky /api/states/all column names was added in #92 but never read: state_row_to_record hard-coded eleven magic indexes instead, and the comment above the tuple said it was used by _state_row_to_record, a function that never existed. Rather than delete the table, this PR uses it:

  • rename _STATE_COLUMNS_NEW -> _STATE_COLUMNS (the suffix referred to nothing; private, zero references anywhere in the repo)
  • derive _COL, a name -> index map, from the tuple
  • index rows by documented column name (row[_COL["geo_altitude"]] instead of row[13])
  • rewrite the comment so that it is true, with a link to the OpenSky REST docs

The column order is now written once. A mistyped name fails loudly with KeyError, where a mistyped number silently read the wrong column.

No behaviour change

  • Column order checked against https://openskynetwork.github.io/opensky-api/rest.html by two independent passes: the tuple matches indexes 0-17 exactly, and every index the function used before was correct.
  • Differential test of the old and new function, loaded side by side: every row length 0-20, every category value, each column nulled, and 20,000 seeded fuzz rows. 20,075 cases, 0 mismatches in records, exception types or messages.
  • Short rows still raise IndexError as before (kept on purpose; see follow-ups).

One new test

Mutation testing of the tuple showed that swapping time_position and last_contact passed every test, because the shared fixture gives both the same value (a gap that predates this change). test_timestamp_is_time_position_not_last_contact closes it; with the two names swapped it fails, as it should. It uses only the public function.

Checks (the python-training-tree lane's commands, run in python/)

  • ruff check .: passed
  • pyright (strict): 0 errors, 0 warnings
  • pytest -q: 119 passed, 3 skipped (torch / onnxruntime extras not installed, by design)

OpenSpec Validate is expected to be red: it fails on develop already (26 main specs with the placeholder Purpose that OpenSpec 1.13 rejects), which a separate PR addresses.

Found while verifying, NOT in this PR

The numeric -> letter emitter-category conversion in the same function is shifted by one relative to the OpenSky docs, where 0 = no information, 1 = "No ADS-B Emitter Category Information", 2 = Light ... 6 = Heavy, 7 = High Performance, 8 = Rotorcraft, 9 = Glider ... 14 = UAV. The code maps 1..7 to A1..A7, so:

OpenSky value becomes classed as should be
1 (no category info) A1 light fixed-wing none / other
3 (Small) A3 heavy fixed-wing light fixed-wing
6 (Heavy) A6 other heavy fixed-wing
8 (Rotorcraft) B1 glider / balloon / UAV rotorcraft
14 (UAV) B7 other glider / balloon / UAV

It shows in the checked-in sample: the only A1 aircraft in test-data/trajectories/opensky-sample.parquet are DLH85N and EJU64AM, both airliners. A live query on 2026-09-19 showed the same (a British Airways long-haul with category 6 = Heavy lands in other). Fixing it changes training labels, a test expectation (4 should give A3), the checked-in sample and its recorded SHA-256, and any OpenSky data already captured, so it needs its own branch and a decision on re-labelling.

Smaller observations, also left alone: a malformed short row escapes fetch_state_vectors as a bare IndexError rather than an OpenSkyError; NUM_CLASSES and the Decision 8 category table are each defined twice (they agree today).

🤖 Generated with Claude Code

`_STATE_COLUMNS_NEW` was added unused in #92 while `state_row_to_record`
hard-coded eleven magic indexes; the comment claiming the function used it
named a function that never existed. Rename it to `_STATE_COLUMNS`, derive a
name -> index map from it, and index rows by documented column name so the
/api/states/all column order is written once.

No behaviour change: every name resolves to the index that was hard-coded,
checked against the OpenSky REST docs column table and by a differential test
of the old and new function over 20,075 rows (0 mismatches).

Add a test that tells `time_position` from `last_contact`: the shared fixture
gives both the same value, so swapping them went unnoticed by every test.

Resolves GitHub Code Quality finding #24 (py/unused-global-variable).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 19, 2026 14:24

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 59 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: f633ac57-84d6-4041-bff1-28adfd02d71f

📥 Commits

Reviewing files that changed from the base of the PR and between eb91f22 and 26b15a2.

📒 Files selected for processing (2)
  • python/acquisition/opensky.py
  • python/tests/test_opensky.py

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.

@codecov

codecov Bot commented Sep 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@sonarqubecloud

Copy link
Copy Markdown

@montge
montge merged commit cfd3f49 into develop Sep 20, 2026
27 checks passed
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.

2 participants