Skip to content

Send each association's position alongside its hex (contract 1.5.0) - #19

Closed
jehanazad wants to merge 1 commit into
mainfrom
feat/v1-adsb-position-tags
Closed

jehanazad wants to merge 1 commit into
mainfrom
feat/v1-adsb-position-tags

Conversation

@jehanazad

Copy link
Copy Markdown
Contributor

Summary

The node already knows where it saw the aircraft it correlated a detection to (blah2-api's enrichment carries lat/lon, altitude, ground speed, track and residuals), but the v1 wire only had room for the hex. Server contract 1.5.0 adds an optional adsb column, an AdsbTag or null per detection parallel to adsb_hex, so the server can file the position for the detection itself. This makes claiming and coverage calibration work on any environment that only sees the node through the detection mirror, where a bare hex cannot be placed.

Server side: offworldlabs/retina-server branch feat/v1-adsb-position-tags (PR linked in a comment below).

Changes

  • retina_telemetry/wire/detection.py: build_detection_frame fills adsb from the same associations adsb_hex reads. A tag is built only where the hex passed and lat/lon are finite, so the server's entry-for-entry agreement rule holds by construction. Null where no usable position, the whole column omitted when association is off, and the non-finite detection filter keeps the column aligned.
  • docs/node-ingest-v1.yml: the DetectionFrame.adsb property and the AdsbTag schema, copied from the server's 1.5.0 contract; info.version 1.5.0.
  • retina_telemetry/wire/models.py: regenerated (+17 lines).
  • retina_telemetry/wire/__init__.py: provenance table row for the new column.

Test coverage

  • tests/wire/test_detection.py::TestPositionTags: position carried with all fields; column omitted when association is off; documented wire shape; association without a position keeps its hex only; a refused position (lat 95, string lon, NaN, bool) costs that tag only; a dropped detection takes its tag with it.
  • tools/check.sh (ruff, dead code, models-match-spec, pytest) passes locally with the pinned tool versions.

Review notes

  • Rollout order matters. A pre-1.5.0 server rejects any frame carrying adsb (additionalProperties: false), and the client has no way to learn the server's contract version. Deploy the server change to every environment nodes post to before this reaches nodes.
  • Spec copy is partial on purpose. Only the DetectionFrame change is synced. Regenerating from the whole 1.5.0 document also pulls in the 1.3/1.4 schemas, which renames the generated node-state enum and breaks the service tests. That resync is its own change.
  • to_wire prunes optional nulls at the top level only, so a tag's unreported fields (for example gs, track) travel as null inside the tag. The contract admits them and the server drops them on filing.
  • No package version bump here; that has been a separate commit in this repo.

🤖 Generated with Claude Code

blah2-api's enrichment reports where the node saw the aircraft it matched a
detection to — lat, lon, altitude, ground speed, track, and its own delay and
Doppler residuals — and until now the wire reduced all of that to the hex.
Contract 1.5.0 adds an optional `adsb` column to DetectionFrame: an AdsbTag or
null per detection, parallel to `adsb_hex` and agreeing with it entry for
entry.  The server files the position for the detection itself, so it, and
every environment it mirrors the frame to, can claim the detection and
calibrate the node's coverage without a position source of its own.

build_detection_frame fills the column from the same associations `adsb_hex`
reads: a tag where the hex passed and a finite lat/lon is present, null where
either is missing, the whole column omitted when association is off.  A tag
the spec refuses (a latitude past 90) costs that one tag, the same trade the
other per-entry rules make, and a detection dropped for a non-finite value
takes its tag with it.

docs/node-ingest-v1.yml carries the DetectionFrame change and the AdsbTag
schema from the server's 1.5.0 contract; the 1.3/1.4 additions elsewhere in
that document are not synced here, because regenerating from the whole
document renames the generated node-state enum and is its own change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jehanazad

Copy link
Copy Markdown
Contributor Author

Server side: offworldlabs/retina-server#514 (contract 1.5.0). Merge and deploy that to prod and test before this ships to nodes.

@jehanazad

Copy link
Copy Markdown
Contributor Author

@Babissimo If I'm understanding correctly, the nodes aren't sending all the ADS-B data when there is an association. They're just sending the Hex of the aircraft.

@Babissimo

Copy link
Copy Markdown

Heads-up: the server side of 1.5.0 has changed under this PR. offworldlabs/retina-server#514 now makes adsb_hex optional and deprecated (offworldlabs/retina-server@1c49f974). The version is still 1.5.0, since it hasn't shipped.

What changed in DetectionFrame

  • adsb_hex is no longer required, and is marked deprecated: true.
  • adsb on its own now carries the association. Sending neither column means the node matched nothing.
  • If both are sent, the existing rules still apply: they must be parallel and agree entry for entry.

The motive: with the tags, every match went out twice, and nothing on the server reads the frame's adsb_hex. The tracker and path 1 claiming both read the per-detection adsb record.

What this PR needs

  • Re-copy DetectionFrame from contracts/nodes-v1.openapi.yaml at that commit, and regenerate models.py. The spec copy here has to match the server's byte for byte.
  • Stop sending adsb_hex. When association is on, send adsb with a tag or null per detection. When it's off, send neither column. The one thing this loses is a match with no usable position, which becomes null; the server ignores bare hexes, so nothing downstream notices.
  • It also needs a rebase: this branch conflicts with main, which has moved to 1.4.0.

The rollout order is unchanged. A server older than 1.5.0 refuses a frame carrying adsb, and equally one without adsb_hex. The server still has to reach every environment before this ships.

@Purple10101

Copy link
Copy Markdown
Collaborator

TODO by me: Remove adsb_hex from detections

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.

3 participants