Skip to content

Add Label B2 Oceanic Clearance Acknowledgement decoder plugin#413

Open
thepacket wants to merge 1 commit intoairframesio:masterfrom
thepacket:plugin/label-b2
Open

Add Label B2 Oceanic Clearance Acknowledgement decoder plugin#413
thepacket wants to merge 1 commit intoairframesio:masterfrom
thepacket:plugin/label-b2

Conversation

@thepacket
Copy link
Copy Markdown

Adds a decoder for FANS Oceanic Clearance Acknowledgement (OCRA / CLA) downlinks.

Wire format

/PIKCLYA.OC1/CLA 1911 260420 EGGX CLRNCE 296 AFR012 CLRD TO KJFK VIA
DINIM RANDOM ROUTE DINIM 5130N020W 5230N030W 5130N040W 4930N050W IBERG
FM DINIM/2039 MNTN F400 M085 END OF MESSAGE 694F

Surfaces ground station, UTC time, date (YYMMDD → ISO), oceanic FIR, clearance number, callsign, destination, route type (random/NAT track), waypoints, oceanic entry fix + entry time, cleared flight level, cleared Mach, trailing CRC.

npm run build passes.

New plugin registered in official.ts and MessageDecoder.ts.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Warning

Rate limit exceeded

@thepacket has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 55 minutes and 20 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 55 minutes and 20 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0edba02d-5274-40a8-b08a-135231f5495e

📥 Commits

Reviewing files that changed from the base of the PR and between 10f9f69 and 7607215.

📒 Files selected for processing (3)
  • lib/MessageDecoder.ts
  • lib/plugins/Label_B2_OCRA.ts
  • lib/plugins/official.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Copy link
Copy Markdown
Contributor

@kevinelliott kevinelliott left a comment

Choose a reason for hiding this comment

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

Summary

Adds Label_B2_OCRA for FANS Oceanic Clearance Acknowledgement (CLA) downlinks. Parses station envelope, time, date, oceanic FIR, clearance number, callsign, destination, route type (random / NAT track), waypoints, oceanic entry fix and entry time, cleared flight level, cleared Mach, and trailing CRC. Registered in both lib/MessageDecoder.ts and lib/plugins/official.ts. Build passes per the description.

Verdict

Needs changes before merge. The shape of the parser is correct and the field set is comprehensive, but there's a Mach decoding bug, two duplicate-row antipatterns, and the date-format choice deserves explicit justification.

Must Fix

  • Mach decoding bug. Line 105-106:
    const machM = routeClean.match(/\bM(\d{3})\b/);
    if (machM) machNumber = `0.${machM[1]}`.replace('0.0', '0.');
    
    This works for M085 (→ 0.085 → replace gives 0.85) but breaks for any Mach where the second digit isn't zero — e.g. M082 becomes 0.082 and the replace finds no match, leaving the wrong value. Mach numbers in oceanic clearances are typically M078M092. The intended decoding is "drop the leading M and divide by 100" — implement that directly:
    if (machM) machNumber = (Number(machM[1]) / 100).toFixed(2);
  • Duplicate Time row (project antipattern). Lines 130-133 call ResultFormatter.timestamp(...) which already pushes a {type:'time', code:'TIMESTAMP'} item. Then lines 162-168 explicitly push another {type:'time', code:'TIME'} row with the same value. Pick one. Same issue is flagged in PR #412.
  • Duplicate Callsign row (project antipattern). Line 137 calls ResultFormatter.flightNumber(decodeResult, callsign) (adds a "Flight Number" item) and lines 188-192 push a separate {code:'CALLSIGN', label:'Callsign'} row with the same string. For a callsign rather than a flight number, prefer ResultFormatter.callsign(...) (lib/utils/result_formatter.ts line 93) and drop the manual push.
  • No tests. Please add Label_B2_OCRA.test.ts with at least the wire-format example, a NAT-track variant (so routeType resolves to NAT Track <letter>), a missing-CRC body, and a body where the optional VIA group is absent. Use lib/plugins/Label_15.test.ts as a template.

Should Fix

  • Date format claim needs justification. Lines 21-23 declare YYMMDD and explicitly note "an earlier analyst report read this as DDMMYY; that interpretation is inconsistent with the real message date — corrected here." With only a single sample message, this is fragile. Please:
    • cite the source (ARINC 622 / FANS-1/A spec section, an additional message sample, or a libacars reference) in the docstring,
    • or accept both formats, validate the resulting date against a sanity window (year between e.g. 2000 and current year + 1), and pick whichever yields a valid date.
      Without one of these, the next operator that emits DDMMYY will produce wrong ISO dates silently.
  • time validation only checks HH/MM but the value passed to convertHHMMSSToTod is time + '00'. Fine because time is \d{4} per the regex, but the comment "Time field" in the docstring should call out that seconds are forced to zero (not parsed from the wire).
  • Destination regex [A-Z]{3,4}. Three-letter destinations risk colliding with route tokens. The wire format always uses 4-letter ICAO. Tighten to [A-Z]{4}, or document why the 3-letter form is needed.
  • Waypoint coordinate regex. Line 121: /^\d{4}N\d{3}W$/ and /^\d{4}N\d{3}E$/ — these reject southern-hemisphere waypoints (5130S020W). Add S to the latitude-hemisphere alternation and document that lat is (N|S) and lon is (E|W). Consider a single regex ^\d{4}[NS]\d{3,5}[EW]$ (longitudes can also be 5 digits at high latitudes if the format includes minutes).
  • channel raw key. The envelope splits station from channel on ., e.g. PIKCLYA.OC1 → station=PIKCLYA, channel=OC1. "Channel" isn't really the right word — OC1 is more like a service qualifier (Oceanic Clearance, instance 1). Suggest service_qualifier or imi, matching the FANS 1/A vocabulary used in PR #411.
  • route_type for NAT track. "NAT Track A" is a friendly label, but downstream consumers will more easily key off a stable code like NAT_A or a structured {type:'nat', track:'A'} object. Same logic for 'Random Route''random' raw, friendly value in formatted.

Nits

  • report_date: rename to clearance_date to match the surrounding domain vocabulary.
  • entry_time raw is HH:MM — better to store as a numeric tod (DateTimeUtils.convertHHMMSSToTod(entryTime + '00')) for consistency with message_timestamp.
  • cleared_flight_level value is 'F400' — most downstream consumers want a number (400). The formatted-display already strips the F.
  • The "Ground Station" formatted row uses the joined value ${station}.${channel} — but the raw fields store them separately. Worth surfacing the join only if you keep a separate parsed channel field.

Tests

Missing entirely. Beyond the four scenarios under Must Fix, please add: invalid HH (e.g. 2911), invalid date (260435), Mach values across the range (M078, M085, M092).

Notes

  • Registration: confirmed in both lib/MessageDecoder.ts (line 81) and lib/plugins/official.ts (line 67) at the PR HEAD.
  • FANS 1/A consistency: like PRs #409, #411, #412, this plugin introduces its own envelope-parse + CRC-strip + tail/callsign-extract logic. Please align raw-key naming with those three (crc here matches PR #412, but PR #411 uses crc and PR #409 uses crc_hex — pick one).

Thanks @thepacket!

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