Skip to content

Comments

Additional H1 Decoding#332

Merged
makrsmark merged 1 commit intoairframesio:masterfrom
makrsmark:feature/h1-ldi-inmarsat
Feb 21, 2026
Merged

Additional H1 Decoding#332
makrsmark merged 1 commit intoairframesio:masterfrom
makrsmark:feature/h1-ldi-inmarsat

Conversation

@makrsmark
Copy link
Collaborator

@makrsmark makrsmark commented Feb 21, 2026

  • inmarsat prefix and checksum
  • LDI messages
  • enabled skipped tests

Summary by CodeRabbit

Release Notes

  • New Features

    • Added runway field extraction and parsing support for H1 messages.
    • Enhanced Inmarsat-formatted message decoding across multiple message types.
  • Bug Fixes

    • Improved checksum validation with support for multiple CRC algorithms.
    • Fixed message offset calculation for two-part message handling.
    • Enhanced field parsing for various H1 label message types.
  • Tests

    • Expanded test coverage for H1 message decoders and load distribution information decoding.

* inmarsat prefix and checksum
* LDI messages
* enabled skipped tests
@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

Walkthrough

This PR updates ACARS message decoding tests and refactors core H1 label decoding logic. Changes include converting skipped test cases to active inmarsat tests, modifying checksum parsing to use hexadecimal interpretation, enhancing H1Helper with runway processing and CRC checksum algorithm detection, and updating ResultFormatter to track checksum algorithm types.

Changes

Cohort / File(s) Summary
H1 Label Test Coverage
lib/plugins/Label_H1_FPN.test.ts, lib/plugins/Label_H1_FTX.test.ts, lib/plugins/Label_H1_PRG.test.ts, lib/plugins/Label_H1_REQ.test.ts
Enabled previously skipped inmarsat-related test cases and added new test scenarios with updated assertions for tail, flight number, fuel, checksum, and formatted item counts.
H1 LDI and POS Test Changes
lib/plugins/Label_H1_LDI.test.ts, lib/plugins/Label_H1_POS.test.ts
Added new comprehensive LDI test file covering variants, responses, and requests; removed long POS variant test and adjusted remaining text expectations for short variant.
Label 4J and Other H1 Tests
lib/plugins/Label_4J_POS.test.ts, lib/plugins/Label_H1_OHMA.test.ts
Converted skipped 4J test to active inmarsat test with expanded raw field assertions; added clarifying comment to skipped OHMA test.
Label 4N Checksum Parsing
lib/plugins/Label_4N.ts
Changed variant 2 checksum field interpretation from decimal to hexadecimal by applying hexadecimal parsing to the 32nd field.
Label H1 Offset Logic
lib/plugins/Label_H1.ts
Modified two-part message offset calculation to check for leading "\- " prefix in first part, setting offset to 3 or 4 accordingly, with exploratory comment added.
H1Helper Core Refactor
lib/utils/h1_helper.ts
Major refactor introducing checksum algorithm detection via two CRC implementations (crc16IbmSdlcRev, crc16Genibus), new runway processing logic, refactored ProcessDT with explicit field mappings, and updated message-type descriptors (INI, LDI).
ResultFormatter Checksum Methods
lib/utils/result_formatter.ts
Modified checksum method signature from string to number parameter; added new checksumAlgorithm method to track and store the algorithm type in decode results.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • airframesio/acars-decoder-typescript\Fix H1 parsing #310 — Both PRs modify H1 parsing and result formatting with overlapping changes to CG fields, fuel tracking, and test expectations in H1Helper and ResultFormatter.
  • airframesio/acars-decoder-typescript\Additional Label H1 decoding #309 — Both PRs make overlapping changes to H1 decoding logic in h1_helper.ts and result_formatter.ts, with refactored checksum handling and per-field parsing.
  • airframesio/acars-decoder-typescript\using generic H1 decoder instead of specific #235 — Both PRs modify H1 decoding code paths and change test expectations by switching to generic Label_H1 and adjusting H1 decoding/formatting behavior.

Suggested reviewers

  • kevinelliott
  • andermatt64
  • fredclausen

Poem

🐰 Checksums align in hex, not decimal's way,
Runways now processed, new CRC's at play,
Tests awaken from skips with inmarsat's call,
H1 messages decoded, reformatted for all! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Additional H1 Decoding' directly relates to the main changes: Inmarsat prefix handling, checksum support, and LDI message decoding for H1 messages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


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

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
lib/utils/result_formatter.ts (1)

255-263: Commented-out formatted item push — intentional?

The checksumAlgorithm method stores the value in raw but the formatted item push is commented out. If this is intentional (e.g., raw-only for now, to be exposed later), consider adding a brief // TODO or explanation comment so future contributors know the intent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils/result_formatter.ts` around lines 255 - 263, In checksumAlgorithm
(function checksumAlgorithm and the DecodeResult handling), either restore the
commented formatted item push so decodeResult.formatted.items receives a
message_checksum_algorithm entry (matching the raw.checksum_algorithm value), or
add a brief explanatory comment/TODO above the commented block stating why the
formatted push is intentionally omitted (e.g., "TODO: keep raw-only until UI
support for checksum algorithm is added"); update the comment to reference the
decoded field name (checksum_algorithm) so future contributors can locate and
understand the intent.
lib/utils/h1_helper.ts (1)

560-584: Minor JSDoc inaccuracy: @param data says "byte array" but it's a string.

The function signature takes data: string, not a Uint8Array as the JSDoc implies.

Proposed fix
 /**
  * Calculates the CRC-16/GENIBUS checksum for a given Uint8Array.
- * `@param` data The input data as a byte array.
+ * `@param` data The input data as a string.
  * `@returns` The 16-bit checksum as a number.
  */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils/h1_helper.ts` around lines 560 - 584, The JSDoc for crc16Genibus
incorrectly describes the parameter as a "byte array" while the function
signature accepts a string; update the `@param` data description and type to
reflect that it's a string (e.g., "input string to be encoded as ASCII bytes")
and optionally note the encoding used (ascii) so callers know how the string is
converted; ensure the function-level description matches the actual parameter
type and behavior of crc16Genibus.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/plugins/Label_H1.ts`:
- Around line 39-40: The ternary that computes offset in Label_H1.ts currently
includes a redundant parts[0] === '- ' check which can force an incorrect offset
for messages like '- `#M1B`...' — replace the expression const offset = parts[0]
=== '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4; with a simpler check that only
uses the numeric test (e.g., const offset = isNaN(parseInt(parts[1][1])) ? 3 :
4;) so offset is 3 when the second char is non-numeric and 4 when numeric; keep
or update the inline comment to note fragility around slicing logic in the
function that uses parts/offset.

In `@lib/utils/h1_helper.ts`:
- Around line 522-533: processRunway can throw when the incoming data array has
only one element (no ":" in the RW field); add a guard at the start of
processRunway to check whether data[1] exists before accessing it, and
return/handle gracefully if missing; also avoid duplicate splitting by assigning
data[1].split(',') to a local variable (use that variable for
ResultFormatter.departureAirport and the subsequent ResultFormatter.unknownArr
call) and keep the existing handling of data[0]/parts/more as-is.

---

Nitpick comments:
In `@lib/utils/h1_helper.ts`:
- Around line 560-584: The JSDoc for crc16Genibus incorrectly describes the
parameter as a "byte array" while the function signature accepts a string;
update the `@param` data description and type to reflect that it's a string (e.g.,
"input string to be encoded as ASCII bytes") and optionally note the encoding
used (ascii) so callers know how the string is converted; ensure the
function-level description matches the actual parameter type and behavior of
crc16Genibus.

In `@lib/utils/result_formatter.ts`:
- Around line 255-263: In checksumAlgorithm (function checksumAlgorithm and the
DecodeResult handling), either restore the commented formatted item push so
decodeResult.formatted.items receives a message_checksum_algorithm entry
(matching the raw.checksum_algorithm value), or add a brief explanatory
comment/TODO above the commented block stating why the formatted push is
intentionally omitted (e.g., "TODO: keep raw-only until UI support for checksum
algorithm is added"); update the comment to reference the decoded field name
(checksum_algorithm) so future contributors can locate and understand the
intent.

Comment on lines +39 to +40
// need a better way to figure this out
const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4;
Copy link

@coderabbitai coderabbitai bot Feb 21, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the actual code in Label_H1.ts around lines 39-40
find . -type f -name "Label_H1.ts" | head -5

Repository: airframesio/acars-decoder-typescript

Length of output: 105


🏁 Script executed:

# Search for test files related to H1 or Label_H1
find . -type f -name "*test*" -o -name "*spec*" | grep -i h1

Repository: airframesio/acars-decoder-typescript

Length of output: 723


🏁 Script executed:

# Let's also look for fixture or example data files
find . -type f \( -name "*.json" -o -name "*.txt" -o -name "*.fixture*" \) | xargs grep -l "^-\s*#M" 2>/dev/null | head -10

Repository: airframesio/acars-decoder-typescript

Length of output: 62


🏁 Script executed:

# Let's examine the actual code in Label_H1.ts around lines 39-40
cat -n ./lib/plugins/Label_H1.ts | sed -n '30,50p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1329


🏁 Script executed:

# Let's look at the test file to see what message formats are tested
cat -n ./lib/plugins/Label_H1.test.ts | head -100

Repository: airframesio/acars-decoder-typescript

Length of output: 744


🏁 Script executed:

# Let's look at H1_FTX test file for actual message examples
cat -n ./lib/plugins/Label_H1_FTX.test.ts | head -150

Repository: airframesio/acars-decoder-typescript

Length of output: 4285


🏁 Script executed:

# Let's also check H1_FPN test file
cat -n ./lib/plugins/Label_H1_FPN.test.ts | head -150

Repository: airframesio/acars-decoder-typescript

Length of output: 9786


🏁 Script executed:

# Search for all message text patterns in test files to identify actual message formats
rg "message\.text\s*=" ./lib/plugins/Label_H1*.test.ts -A 1 | grep -oE "'[^']*'" | head -30

Repository: airframesio/acars-decoder-typescript

Length of output: 2431


🏁 Script executed:

# Specifically search for any '- `#M`' patterns with digits
rg "'\s*-\s*#M[0-9]" ./lib/plugins/ -r '$0' 2>/dev/null

Repository: airframesio/acars-decoder-typescript

Length of output: 62


🏁 Script executed:

# Let's check if there are any patterns like '- `#T1B`' or similar
rg "'\s*-\s*#[MT][0-9]" ./lib/plugins/ -r '$0' 2>/dev/null

Repository: airframesio/acars-decoder-typescript

Length of output: 62


🏁 Script executed:

# Let's check the H1_helper to understand the message structure better
cat -n ./lib/utils/h1_helper.ts | head -100

Repository: airframesio/acars-decoder-typescript

Length of output: 4289


🏁 Script executed:

# Look for any comments or documentation about H1 message formats
rg -i "message.*format|format.*message" ./lib/ -B 2 -A 2 | head -80

Repository: airframesio/acars-decoder-typescript

Length of output: 4625


🏁 Script executed:

# Check if there are any other references to parts[1][1] or offset logic
rg "parts\[1\]\[1\]" ./lib/ -B 3 -A 3

Repository: airframesio/acars-decoder-typescript

Length of output: 593


🏁 Script executed:

# Check if there's any git history showing when this condition was added
git log --oneline --all -S "parts[0] === '- '" -- ./lib/plugins/Label_H1.ts | head -5

Repository: airframesio/acars-decoder-typescript

Length of output: 110


🏁 Script executed:

# Let's also verify the complete split logic by looking at what the msg variable contains
cat -n ./lib/plugins/Label_H1.ts | sed -n '25,50p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1532


🏁 Script executed:

# Let's check the git commit to see what was changed
git show 3c8ed5b --stat | head -20

Repository: airframesio/acars-decoder-typescript

Length of output: 879


🏁 Script executed:

# Let's verify the complete logic by examining what `msg` is before the split
cat -n ./lib/plugins/Label_H1.ts | sed -n '1,25p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1064


🏁 Script executed:

# Let's check the exact change that introduced the parts[0] === '- ' condition
git show 3c8ed5b -- lib/plugins/Label_H1.ts | grep -A 10 -B 10 "parts\[0\]"

Repository: airframesio/acars-decoder-typescript

Length of output: 1502


🏁 Script executed:

# Let's also check if there are any other tests that might use '- `#M1`' or similar patterns
rg "- #" ./lib/plugins/*.test.ts -n | head -20

Repository: airframesio/acars-decoder-typescript

Length of output: 484


🏁 Script executed:

# Search for test patterns with escaped characters
rg '\- #' ./lib/plugins/*.test.ts -n | head -20

Repository: airframesio/acars-decoder-typescript

Length of output: 841


🏁 Script executed:

# Let's check all test cases in the H1 tests that use the "- #" prefix
grep -rn "- #" ./lib/plugins/Label_H1*.test.ts | head -30

Repository: airframesio/acars-decoder-typescript

Length of output: 190


🏁 Script executed:

# Let's trace through the logic with concrete examples
# For '- `#MDFTX/ID77170A`,...':
# - msg = '- `#MDFTX/ID77170A`,...'
# - parts = msg.split('#') = ['- ', 'MDFTX/ID77170A,...']
# - parts[0] = '- ' (length 2)
# - parts[1][1] = 'D'
# Let's verify the exact message format in the test
cat -n ./lib/plugins/Label_H1_FTX.test.ts | sed -n '37,65p'

Repository: airframesio/acars-decoder-typescript

Length of output: 1853


🏁 Script executed:

# Let's verify what the offset calculation should be for '- `#MDFTX`' format
python3 << 'EOF'
msg = '- `#MDFTX/ID77170A`,RCH836,ABZ01G6XH273/MR2,/FXIRAN IS LAUNCHING MISSILES'
parts = msg.split('#')
print(f"msg = '{msg}'")
print(f"parts[0] = '{parts[0]}' (length {len(parts[0])})")
print(f"parts[1] = '{parts[1]}'")
print(f"parts[1][1] = '{parts[1][1]}'")

# Current logic
offset_current = 3 if (parts[0] == '- ' or int(parts[1][1]) != int(parts[1][1])) else 4
# Simulating: parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4
import math
is_nan = math.isnan(float(parts[1][1])) if parts[1][1] not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' else True
offset_current = 3 if (parts[0] == '- ' or is_nan) else 4
print(f"\nFor '- `#MDFTX`' (D is non-numeric):")
print(f"  isNaN(parseInt('D')) = True")
print(f"  offset = 3")
print(f"  msg.slice({len(parts[0])} + 3) = msg.slice({len(parts[0]) + 3})")
print(f"  Result: '{msg[len(parts[0]) + 3:]}'")

# Hypothetical '- `#M1B`' message
msg2 = '- `#M1BFTX/ID77170A`,RCH836'
parts2 = msg2.split('#')
print(f"\nFor hypothetical '- `#M1BFTX`' (1 is numeric):")
print(f"  parts[1][1] = '{parts2[1][1]}'")
print(f"  isNaN(parseInt('1')) = False")
print(f"  WITH parts[0] === '- ': offset = 3, msg.slice({len(parts2[0]) + 3}) = '{msg2[len(parts2[0]) + 3:]}'")
print(f"  WITHOUT parts[0] === '- ': offset = 4, msg.slice({len(parts2[0]) + 4}) = '{msg2[len(parts2[0]) + 4:]}'")
EOF

Repository: airframesio/acars-decoder-typescript

Length of output: 729


Remove the redundant parts[0] === '- ' condition that introduces a latent offset bug.

For all currently tested '- #MD...' messages, the second character is 'D' (non-numeric), so isNaN(parseInt('D')) already returns true and produces the correct offset = 3. The new parts[0] === '- ' clause adds no value for known cases.

However, it creates a latent bug: if a '- #M1B...' or '- #T1B...' message is ever encountered, the condition forces offset = 3 (incorrect) instead of the proper 4. For example, with '- #M1BFTX/...', slicing at 2 + 3 = 5 yields 'BFTX/...' (includes trailing B), while correct offset of 4 would yield 'FTX/...'.

The inline comment already acknowledges this approach is fragile. Remove the redundant clause:

♻️ Suggested simplification
-      // need a better way to figure this out
-      const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4;
+      // offset: 3 for '#MD...' style (non-numeric 2nd char), 4 for '#M1B...' style
+      const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// need a better way to figure this out
const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4;
// offset: 3 for '#MD...' style (non-numeric 2nd char), 4 for '#M1B...' style
const offset = isNaN(parseInt(parts[1][1])) ? 3 : 4;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/plugins/Label_H1.ts` around lines 39 - 40, The ternary that computes
offset in Label_H1.ts currently includes a redundant parts[0] === '- ' check
which can force an incorrect offset for messages like '- `#M1B`...' — replace the
expression const offset = parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3
: 4; with a simpler check that only uses the numeric test (e.g., const offset =
isNaN(parseInt(parts[1][1])) ? 3 : 4;) so offset is 3 when the second char is
non-numeric and 4 when numeric; keep or update the inline comment to note
fragility around slicing logic in the function that uses parts/offset.

Copy link
Collaborator Author

@makrsmark makrsmark Feb 21, 2026

Choose a reason for hiding this comment

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

the suggestion does not work for the example that is - #M1FPN...

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for test messages that contain the '- `#M1`' pattern
rg "- `#M1`" lib/plugins/Label_H1*.test.ts -n -C3

Length of output: 404


🏁 Script executed:

#!/bin/bash
# Search for test messages that contain the '- `#M1`' pattern (properly escaped)
rg '- `#M1`' lib/plugins/Label_H1*.test.ts -n -C3

Length of output: 404


🏁 Script executed:

#!/bin/bash
# Search for test messages containing '- `#M1`' pattern using -e flag
rg -e '- `#M1`' lib/plugins/Label_H1*.test.ts -n -C3

# Also search for messages starting with '- `#M`' more broadly
rg -e '- `#M`' lib/plugins/Label_H1*.test.ts -n -C2

# Look at the actual H1_FPN test file to see the inmarsat test
cat lib/plugins/Label_H1_FPN.test.ts | grep -A5 -B5 "inmarsat"

Length of output: 3158


🏁 Script executed:

#!/bin/bash
# Search for messages containing M1 in test files
rg 'M1' lib/plugins/Label_H1*.test.ts -n -B2 -A2 | head -80

# Also look for the specific pattern in the FPN test file since user mentioned M1FPN
cat lib/plugins/Label_H1_FPN.test.ts

Length of output: 27333


@makrsmark, you're absolutely right—thank you for the correction! My analysis was incorrect.

For a message like '- #M1FPN/...':

  • parts[0] = '- ' and parts[1][1] = '1' (numeric)
  • Current code: parts[0] === '- ' returns trueoffset = 3msg.slice(2+3) skips '- #M1' → correctly decodes 'FPN/...'
  • My suggestion: isNaN(parseInt('1')) returns falseoffset = 4msg.slice(2+4) skips '- #M1F' → incorrectly decodes 'PN/...'

The current logic is correct: when the prefix is '- ', the offset should always be 3 (to skip the 3 characters after #), regardless of whether parts[1][1] is numeric. My suggestion would break this case.

I apologize for the confusion! The parts[0] === '- ' condition is necessary, not redundant.

  /\_/\
 ( o.o )
  > ^ <
(Sorry!)

🧬 Code Graph Analysis Results
  • File: lib/utils/result_formatter.ts

    • Snippet:
      static flightNumber(decodeResult: DecodeResult, value: string) {
      if (value.length === 0) {
      return;
      }
      decodeResult.raw.flight_number = value;
      decodeResult.formatted.items.push({
      type: 'flight_number',
      code: 'FLIGHT',
      label: 'Flight Number',
      value: decodeResult.raw.flight_number,
      });
      }
    • This snippet is relevant because Label_H1 uses ResultFormatter.flightNumber(...) when parsing an H1 message that starts with a flight number prefix (as seen in the code path handling parts[0]). Understanding this function helps interpret how flight numbers get recorded in the decode result.
  • File: lib/utils/h1_helper.ts

    • Summary (docstring-style description):
      Class: H1Helper
      • Method: static decodeH1Message(decodeResult: DecodeResult, message: string)
        • Parameters:
          • decodeResult: the DecodeResult object being populated.
          • message: the H1 data payload (excluding the trailing checksum).
        • Returns: boolean indicating whether decoding succeeded.
        • Behavior:
          • Computes checksum from the last 4 hex characters of the message; validates using CRC16 IBM SDLC reversed or GENIBUS algorithms on the data portion.
          • If checksum is valid, splits data into fields (by '/'), validates message type (via parseMessageType), and processes each field key/data pair (AF, AK, CG, DC, DI, DT, DQ, ET, etc.) by invoking corresponding processing/formatter routines.
          • For each known key, it delegates to specialized handlers (e.g., processPS, processPosition, processDateCode, processETA, etc.) or records unknowns via ResultFormatter.unknown.
          • After processing all fields, it records the checksum algorithm and checksum itself.
        • Exceptions/Error handling:
          • If checksum validation fails or message type parsing fails, sets decodeResult.decoded = false and decodeResult.decoder.decodeLevel = 'none', and returns false.
        • Important implementation notes:
          • Handles many H1 field types by dispatching to helper functions (e.g., processPS, processCenterOfGravity, processDateCode, etc.).
          • On success, returns true; on failure, returns false and adjusts decode state accordingly.
        • This function is central to interpreting H1 payloads and is directly invoked by Label_H1 for various message formats.
  • File: lib/DecoderPluginInterface.ts

    • Snippet: Message interface
      export interface Message {
      label: string;
      sublabel?: string;
      text: string;
      }
    • Snippet: Options interface
      export interface Options {
      debug?: boolean;
      }
    • Snippet: DecodeResult interface
      export interface DecodeResult {
      decoded: boolean;
      decoder: {
      name: string;
      type: 'pattern-match' | 'none';
      decodeLevel: 'none' | 'partial' | 'full';
      };
      error?: string;
      formatted: {
      description: string;
      items: {
      type: string;
      code: string;
      label: string;
      value: string;
      }[];
      };
      message?: Message;
      raw: any; // eslint-disable-line @typescript-eslint/no-explicit-any
      remaining: {
      text?: string;
      };
      }
    • These interfaces define the core structures used by Label_H1.ts (Message, DecodeResult, and Options), and help explain how text messages are represented, how decoding state is tracked, and how results are formatted.
  • File: lib/DecoderPluginInterface.ts

    • Rationale: The Label_H1.ts decoder interacts with the DecodeResult, Message, and Options types defined here. Understanding the fields of DecodeResult (especially remaining.text, decoded, decoder.decodeLevel, and formatted.items) is important for diagnosing why certain inputs like "- #M1FPN..." might not be parsed as expected.

✏️ Learnings added
Learnt from: makrsmark
Repo: airframesio/acars-decoder-typescript PR: 332
File: lib/plugins/Label_H1.ts:39-40
Timestamp: 2026-02-21T01:32:00.829Z
Learning: In lib/plugins/Label_H1.ts, when parsing two-part H1 messages (split by '#'), the offset logic `parts[0] === '- ' || isNaN(parseInt(parts[1][1])) ? 3 : 4` is correct. The `parts[0] === '- '` condition ensures that messages like '- `#M1FPN/`...' use offset=3 to skip 3 characters after '#' ('M1' + next char), whereas messages like 'F37AKL0767#M1BFPN/...' use offset=4 to skip 4 characters ('M1B' + '/'). Removing the `parts[0] === '- '` check would break '- `#M1`...' messages where parts[1][1] is numeric.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: makrsmark
Repo: airframesio/acars-decoder-typescript PR: 309
File: lib/utils/h1_helper.ts:12-19
Timestamp: 2026-01-30T02:52:39.855Z
Learning: In H1 message decoding (lib/utils/h1_helper.ts), the checksum in incoming messages is always uppercase, so case normalization is not required when comparing against calculateChecksum() output.

Comment on lines +522 to +533
function processRunway(decodeResult: DecodeResult, data: string[]) {
//FIXME - figure out names
const parts = data[0].split('.');
const more = parts[0].split(',');

ResultFormatter.departureRunway(decodeResult, more[0]);
ResultFormatter.unknownArr(decodeResult, more.slice(1), ',');
ResultFormatter.unknownArr(decodeResult, parts.slice(1), '.');
ResultFormatter.departureAirport(decodeResult, data[1].split(',')[0]);
ResultFormatter.unknownArr(decodeResult, data[1].split(',').slice(1), ',');
//ResultFormatter.unknownArr(decodeResult, data.slice(2), ':');
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

rg -n "processRunway|case 'RW'" --type=ts -C3

Repository: airframesio/acars-decoder-typescript

Length of output: 963


🏁 Script executed:

sed -n '522,533p' lib/utils/h1_helper.ts

Repository: airframesio/acars-decoder-typescript

Length of output: 656


processRunway will throw if the RW field has no : separator.

At line 104, the function is called with data.split(':'). If the RW field contains no :, this returns a single-element array, making data[1] undefined. Accessing undefined.split(',') on line 530 throws TypeError. Add a bounds check before accessing data[1].

Also, data[1].split(',') is evaluated twice (lines 530–531); extract it to a local variable to avoid redundant splitting.

Proposed fix
 function processRunway(decodeResult: DecodeResult, data: string[]) {
   //FIXME - figure out names
   const parts = data[0].split('.');
   const more = parts[0].split(',');
 
   ResultFormatter.departureRunway(decodeResult, more[0]);
   ResultFormatter.unknownArr(decodeResult, more.slice(1), ',');
   ResultFormatter.unknownArr(decodeResult, parts.slice(1), '.');
-  ResultFormatter.departureAirport(decodeResult, data[1].split(',')[0]);
-  ResultFormatter.unknownArr(decodeResult, data[1].split(',').slice(1), ',');
+  if (data.length > 1) {
+    const airportParts = data[1].split(',');
+    ResultFormatter.departureAirport(decodeResult, airportParts[0]);
+    ResultFormatter.unknownArr(decodeResult, airportParts.slice(1), ',');
+  }
   //ResultFormatter.unknownArr(decodeResult, data.slice(2), ':');
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils/h1_helper.ts` around lines 522 - 533, processRunway can throw when
the incoming data array has only one element (no ":" in the RW field); add a
guard at the start of processRunway to check whether data[1] exists before
accessing it, and return/handle gracefully if missing; also avoid duplicate
splitting by assigning data[1].split(',') to a local variable (use that variable
for ResultFormatter.departureAirport and the subsequent
ResultFormatter.unknownArr call) and keep the existing handling of
data[0]/parts/more as-is.

@makrsmark makrsmark merged commit b48dd0c into airframesio:master Feb 21, 2026
6 checks passed
@makrsmark makrsmark deleted the feature/h1-ldi-inmarsat branch February 21, 2026 23:34
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.

1 participant