Skip to content

Refactor MessageDecoder with label indexing and plugin helper methods#366

Merged
kevinelliott merged 6 commits intomasterfrom
claude/improve-library-architecture-6SsF3
Mar 19, 2026
Merged

Refactor MessageDecoder with label indexing and plugin helper methods#366
kevinelliott merged 6 commits intomasterfrom
claude/improve-library-architecture-6SsF3

Conversation

@kevinelliott
Copy link
Contributor

@kevinelliott kevinelliott commented Mar 19, 2026

Summary

This PR refactors the MessageDecoder and DecoderPlugin architecture to improve performance and reduce boilerplate code across plugins. The main changes include:

  1. Label-based plugin indexing in MessageDecoder for O(1) plugin lookup by label instead of iterating all plugins
  2. Protected helper methods in DecoderPlugin to eliminate repetitive initialization and state-setting code
  3. Label_44_Base abstract class to consolidate shared logic across Label 44 event decoders (ON, OFF, IN, ETA)
  4. Type-safe RawFields interface replacing untyped any for better IDE support and type checking
  5. Comprehensive test coverage for new functionality

Key Changes

MessageDecoder (lib/MessageDecoder.ts)

  • Extracted plugin registration into a static pluginClasses array at module level for clarity
  • Added labelIndex Map to track plugins by label for fast lookup
  • Added wildcardPlugins array for plugins matching all labels (qualifier '*')
  • Modified decode() to use label index for efficient plugin selection
  • Updated registerPlugin() to populate the label index when plugins are registered

DecoderPlugin (lib/DecoderPlugin.ts)

  • Added initResult(message, description) helper to replace boilerplate result initialization
  • Added setDecodeLevel(result, decoded, level?) helper to manage decode status and level inference
  • Added debug(options, ...args) helper for consistent debug logging with plugin name prefix
  • Added failUnknown(result, text, options?) helper to mark failed decodes and log debug messages

Label_44_Base (lib/plugins/Label_44_Base.ts)

  • New abstract base class for Label 44 event-style decoders (ON, OFF, IN)
  • Consolidates shared CSV parsing logic (position, airports, date/time)
  • Subclasses implement description, minFields, and decodeEventFields() hook
  • Reduces code duplication across Label_44_ON, Label_44_OFF, Label_44_IN

Label 44 Plugins

  • Label_44_ON, Label_44_OFF, Label_44_IN now extend Label_44_Base
  • Removed ~50 lines of duplicated parsing code per plugin
  • Label_44_ETA remains standalone (different field layout)

DecoderPluginInterface (lib/DecoderPluginInterface.ts)

  • Added RawFields interface with well-known fields (position, altitude, airports, times, fuel, etc.)
  • Includes index signature for plugin-specific custom fields
  • Replaced raw: any with raw: RawFields for type safety
  • Updated decode() signature to accept optional Options parameter

Tests

  • DecoderPlugin.test.ts: Tests for initResult, setDecodeLevel, debug, and failUnknown helpers
  • MessageDecoder.labelindex.test.ts: Tests for label indexing, wildcard plugins, and preamble filtering
  • Label_44_Base.test.ts: Tests for shared Label 44 decoding logic
  • RawFields.test.ts: Tests for type safety of RawFields interface

Implementation Details

  • Label indexing preserves order: Plugins are tried in registration order within each label bucket
  • Wildcard plugins tried first: Plugins with labels: ['*'] are always attempted before label-specific plugins
  • Preamble filtering: Plugins can specify preambles to match only messages starting with those strings
  • Backward compatible: All existing plugin APIs remain unchanged; new helpers are optional
  • Type inference: setDecodeLevel() automatically infers 'full' vs 'partial' based on remaining text when no explicit level given

https://claude.ai/code/session_01WHPebkdmNV4aEh8wzpzoj5

Summary by CodeRabbit

  • New Features

    • Decoder API now accepts optional options (e.g., debug) and label-based plugin selection includes wildcard matching.
  • Bug Fixes

    • Consistent unknown-message handling and unified decode-state/level rules across decoders.
  • Refactor

    • Centralized result initialization and decode-level helpers; new shared base for event-style reports to reduce duplication.
  • Tests

    • Added tests for plugin helpers, label-index selection, and typed raw-field handling.

claude added 3 commits March 18, 2026 15:11
Analyzes the codebase and documents opportunities for improving
code reuse, performance, type safety, and maintainability across
the 68 decoder plugins.

https://claude.ai/code/session_01WHPebkdmNV4aEh8wzpzoj5
…raw fields

- Fix bug: MessageDecoder now passes options through to plugin.decode()
- Add base class helpers: initResult(), setDecodeLevel(), debug(), failUnknown()
- Add label index (Map<label, plugin[]>) for O(k) plugin matching instead of O(n)
- Replace manual registerPlugin() calls with declarative pluginClasses array
- Add RawFields typed interface for DecodeResult.raw with index signature escape hatch
- Create Label_44_Base shared class for ON/OFF/IN event decoders
- Update 22 plugins to use new base class helpers, reducing boilerplate
- Add 30 new tests covering all new infrastructure

Net result: -103 lines, improved type safety, faster decode, less duplication.

https://claude.ai/code/session_01WHPebkdmNV4aEh8wzpzoj5
@kevinelliott kevinelliott requested review from Copilot and makrsmark and removed request for Copilot March 19, 2026 01:39
@coderabbitai
Copy link

coderabbitai bot commented Mar 19, 2026

Walkthrough

Adds DecoderPlugin helper APIs and an options-aware decode signature; types DecodeResult.raw as RawFields; introduces Label_44_Base and refactors Label_44 subclasses; changes MessageDecoder to register/index plugins by label and wildcard and forward options; updates ~20 plugins to use the new helpers and adds related tests.

Changes

Cohort / File(s) Summary
Core: Decoder plugin & types
lib/DecoderPlugin.ts, lib/DecoderPluginInterface.ts
Add protected helpers (initResult, setDecodeLevel, debug, failUnknown); change decode(message, options?) signature; introduce exported RawFields and type DecodeResult.raw: RawFields.
MessageDecoder / registration & dispatch
lib/MessageDecoder.ts
Replace hardcoded plugin registrations with pluginClasses iteration; add labelIndex and wildcardPlugins; build candidate list (wildcards then label bucket), filter by preambles, dedupe, and call plugin.decode(message, options).
Label 44 base & subclasses
lib/plugins/Label_44_Base.ts, lib/plugins/Label_44_IN.ts, lib/plugins/Label_44_OFF.ts, lib/plugins/Label_44_ON.ts, lib/plugins/Label_44_ETA.ts, lib/plugins/Label_44_POS.ts
Add Label_44_Base abstract class centralizing shared parsing and helpers (parseFuel, addRemainingFields); refactor Label_44 variants to extend base and implement decodeEventFields/getters, using unified init/fail/setDecodeLevel flow.
Plugin refactors: position/event/other
lib/plugins/... (many: Label_10_POS.ts, Label_12_POS.ts, Label_15*.ts, Label_16_POSA1.ts, Label_20_POS.ts, Label_21_POS.ts, Label_22_*.ts, Label_4A*.ts, Label_80.ts, Label_H1_*.ts, Label_SQ.ts)
Standardize plugin implementations to use initResult, setDecodeLevel, debug, and failUnknown; remove ad-hoc init, debug and decode-level logic across many plugins.
Tests
lib/DecoderPlugin.test.ts, lib/RawFields.test.ts, lib/MessageDecoder.labelindex.test.ts, lib/plugins/Label_44_Base.test.ts
Add tests validating DecoderPlugin helpers, RawFields typings, MessageDecoder label-index/preamble behavior and option propagation, and Label_44_Base decoding/edge cases.
Misc (formatting)
lib/DateTimeUtils.ts
Removed an extraneous blank line (formatting only).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested reviewers

  • andermatt64

Poem

🐰 I hopped through code both neat and spry,
Helpers tucked where branches lie,
Labels mapped and wildcards found,
RawFields typed and tests unbound,
A carrot-coded fix—hip-hop hooray! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main changes: refactoring MessageDecoder with label indexing and introducing plugin helper methods, matching the file-level changes and PR objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/improve-library-architecture-6SsF3
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@kevinelliott kevinelliott requested a review from Copilot March 19, 2026 01:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors the decoding architecture to improve plugin lookup performance and reduce per-plugin boilerplate by introducing label indexing in MessageDecoder and shared helper/base classes for decoders.

Changes:

  • Added label-based plugin indexing (plus wildcard handling and preamble filtering) to speed up plugin selection in MessageDecoder.
  • Introduced DecoderPlugin helper methods (initResult, setDecodeLevel, debug, failUnknown) and migrated multiple plugins to use them.
  • Added a new Label_44_Base abstract class to share common Label 44 event parsing logic, and added/updated tests plus a typed RawFields interface.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lib/plugins/Label_SQ.ts Migrates to initResult/setDecodeLevel helpers.
lib/plugins/Label_H1_WRN.ts Uses shared helpers; unknown handling now via failUnknown.
lib/plugins/Label_H1_M_POS.ts Uses shared helpers; unknown handling now via failUnknown.
lib/plugins/Label_H1_FLR.ts Uses shared helpers; unknown handling now via failUnknown.
lib/plugins/Label_80.ts Uses initResult and infers decode level via setDecodeLevel.
lib/plugins/Label_4A_DOOR.ts Replaces manual decode-level logic with setDecodeLevel.
lib/plugins/Label_4A_DIS.ts Replaces manual decode-level logic with setDecodeLevel.
lib/plugins/Label_4A_01.ts Replaces manual decode-level logic with setDecodeLevel.
lib/plugins/Label_4A.ts Replaces manual decode-level logic with setDecodeLevel.
lib/plugins/Label_44_POS.ts Uses initResult and debug; minor field naming/comment clarification.
lib/plugins/Label_44_ON.ts Refactored to extend Label_44_Base and implement event-specific hook.
lib/plugins/Label_44_OFF.ts Refactored to extend Label_44_Base and implement event-specific hook.
lib/plugins/Label_44_IN.ts Refactored to extend Label_44_Base and implement event-specific hook.
lib/plugins/Label_44_ETA.ts Uses shared helpers while remaining standalone (different layout).
lib/plugins/Label_44_Base.ts New shared base class for Label 44 event-style decoders.
lib/plugins/Label_44_Base.test.ts New tests validating shared Label 44 base parsing and helper behavior.
lib/plugins/Label_22_POS.ts Uses initResult, debug, and setDecodeLevel.
lib/plugins/Label_22_OFF.ts Uses initResult, debug, and setDecodeLevel.
lib/plugins/Label_21_POS.ts Uses initResult, debug, and setDecodeLevel.
lib/plugins/Label_20_POS.ts Uses initResult, debug, and setDecodeLevel.
lib/plugins/Label_16_POSA1.ts Uses initResult, setDecodeLevel, and failUnknown.
lib/plugins/Label_15_FST.ts Uses initResult and setDecodeLevel.
lib/plugins/Label_15.ts Uses initResult, setDecodeLevel, and failUnknown.
lib/plugins/Label_12_POS.ts Uses initResult, setDecodeLevel, and failUnknown.
lib/plugins/Label_10_POS.ts Uses initResult, setDecodeLevel, and failUnknown.
lib/RawFields.test.ts Adds tests demonstrating RawFields usage within DecodeResult.
lib/MessageDecoder.ts Adds plugin class list + label index and passes options through to plugins.
lib/MessageDecoder.labelindex.test.ts Adds tests for label indexing, wildcard ordering, and preamble filtering.
lib/DecoderPluginInterface.ts Introduces RawFields and updates plugin decode signature to accept options.
lib/DecoderPlugin.ts Adds protected helper methods to reduce plugin boilerplate.
lib/DecoderPlugin.test.ts Adds unit tests for new DecoderPlugin helper methods.
lib/DateTimeUtils.ts Removes an extra blank line (formatting-only change).
Comments suppressed due to low confidence (1)

lib/plugins/Label_SQ.ts:18

  • DecodeResult.raw.version is typed as number in RawFields, but this plugin assigns a single-character string (e.g. '2'). This will fail TypeScript type-checking and also conflicts with other decoders/formatters that treat raw.version as a numeric version (e.g. ResultFormatter.version() uses toFixed). Consider storing the squitter version in a different field (e.g. squitter_version) or converting to a number and updating related formatting/tests accordingly.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

export class Label_44_IN extends Label_44_Base {
name = 'label-44-in';
get description() {
return 'In Air Report';
Comment on lines +7 to +13
* Base class for Label 44 event-style decoders (ON, OFF, IN, ETA).
*
* These all share the same CSV structure:
* preamble, coordinates, [field(s)...], departure, arrival, date, time(s), fuel
*
* Subclasses provide the description, qualifiers, minimum field count,
* and a hook to decode their specific fields from the CSV data.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3b14c35a82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +126 to +127
const labelPlugins = this.labelIndex.get(message.label) ?? [];
const candidates = [...this.wildcardPlugins, ...labelPlugins];

Choose a reason for hiding this comment

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

P2 Badge Deduplicate wildcard and label buckets before decode

Combining wildcardPlugins and labelPlugins without deduplication means a plugin registered with mixed labels like ['*', '44'] will be invoked twice for label 44 (once from each bucket), which can duplicate side effects and distort precedence. This is a regression from the previous linear filter, where each plugin was evaluated at most once per message. Please ensure candidates are unique before iterating.

Useful? React with 👍 / 👎.

Copy link
Collaborator

@makrsmark makrsmark left a comment

Choose a reason for hiding this comment

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

I'll trust this. Check out the copilot comments. Approving to not block

- Fix Label_44_IN description from 'In Air Report' to 'In Gate Report'
  to match the OOOI convention (comment was correct, code was wrong)
- Remove ETA from Label_44_Base doc comment since Label_44_ETA doesn't
  extend this base class
- Change RawFields.version type to number | string since Label_SQ
  uses it as a string identifier
- Deduplicate candidate plugins in MessageDecoder.decode() to prevent
  double execution if a plugin registers both '*' and a specific label

https://claude.ai/code/session_01WHPebkdmNV4aEh8wzpzoj5
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: 3

🧹 Nitpick comments (1)
lib/plugins/Label_15_FST.ts (1)

46-47: Prefer failUnknown for invalid coordinate format branch.

This branch sets decode level to none but drops the invalid payload from standardized unknown handling (remaining.text), which reduces debuggability consistency versus other plugins.

♻️ Suggested change
-      this.setDecodeLevel(decodeResult, false);
-      return decodeResult;
+      return this.failUnknown(decodeResult, message.text, options);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/plugins/Label_15_FST.ts` around lines 46 - 47, The invalid-coordinate
branch currently calls this.setDecodeLevel(decodeResult, false) and returns
decodeResult without invoking the standardized unknown handling, so replace that
behavior by calling this.failUnknown(...) instead of only setDecodeLevel;
specifically, call this.failUnknown(decodeResult, remaining.text) (or pass
remaining.text into failUnknown's payload/message) to mark the decode as unknown
and preserve remaining.text for debugging, then return the result from
failUnknown rather than returning decodeResult after setDecodeLevel.
🤖 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/MessageDecoder.labelindex.test.ts`:
- Around line 133-151: The test's assertion is too indirect—update the test to
assert plugin-level options propagation explicitly by injecting or mocking a
plugin that emits a distinct debug-only log and then calling
MessageDecoder.decode with { debug: true }; specifically, create or stub a
deterministic plugin (or spy on an existing plugin method) that checks the
received options and logs a unique string only when options.debug is true, call
MessageDecoder.decode (the instance method) with that input and options, and
assert the spy was called with the plugin's unique debug message rather than
relying on decoder-level logs.

In `@lib/plugins/Label_44_IN.ts`:
- Around line 6-11: The file's class Label_44_IN has a comment "In Gate Report"
but its description getter returns "In Air Report", causing a mismatch; decide
which is correct and make them consistent by updating either the comment or the
description getter in the Label_44_IN class (and any related preamble handling
like IN01/IN02/IN03 if present) so that the comment, the name/description
getter, and any logic referencing Label_44_IN all reflect the chosen phrase ("In
Gate Report" or "In Air Report") consistently.

In `@lib/plugins/Label_44_POS.ts`:
- Around line 74-76: setDecodeLevel is being called unconditionally which marks
decodeResult as successful even when the regex failed; move the
setDecodeLevel(decodeResult, true, 'full') call inside the existing if
(results?.groups) block (where results and groups are processed) so it's only
invoked on a successful match, and ensure the else path leaves
decodeResult.decoded false (or explicitly calls setDecodeLevel(decodeResult,
false) if your codebase uses that) to avoid reporting false positives; update
references around setDecodeLevel, decodeResult, and results?.groups accordingly.

---

Nitpick comments:
In `@lib/plugins/Label_15_FST.ts`:
- Around line 46-47: The invalid-coordinate branch currently calls
this.setDecodeLevel(decodeResult, false) and returns decodeResult without
invoking the standardized unknown handling, so replace that behavior by calling
this.failUnknown(...) instead of only setDecodeLevel; specifically, call
this.failUnknown(decodeResult, remaining.text) (or pass remaining.text into
failUnknown's payload/message) to mark the decode as unknown and preserve
remaining.text for debugging, then return the result from failUnknown rather
than returning decodeResult after setDecodeLevel.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3eea3325-f2b4-48d5-8aea-1a30ce8e14b8

📥 Commits

Reviewing files that changed from the base of the PR and between a2fa6ef and 3b14c35.

📒 Files selected for processing (32)
  • lib/DateTimeUtils.ts
  • lib/DecoderPlugin.test.ts
  • lib/DecoderPlugin.ts
  • lib/DecoderPluginInterface.ts
  • lib/MessageDecoder.labelindex.test.ts
  • lib/MessageDecoder.ts
  • lib/RawFields.test.ts
  • lib/plugins/Label_10_POS.ts
  • lib/plugins/Label_12_POS.ts
  • lib/plugins/Label_15.ts
  • lib/plugins/Label_15_FST.ts
  • lib/plugins/Label_16_POSA1.ts
  • lib/plugins/Label_20_POS.ts
  • lib/plugins/Label_21_POS.ts
  • lib/plugins/Label_22_OFF.ts
  • lib/plugins/Label_22_POS.ts
  • lib/plugins/Label_44_Base.test.ts
  • lib/plugins/Label_44_Base.ts
  • lib/plugins/Label_44_ETA.ts
  • lib/plugins/Label_44_IN.ts
  • lib/plugins/Label_44_OFF.ts
  • lib/plugins/Label_44_ON.ts
  • lib/plugins/Label_44_POS.ts
  • lib/plugins/Label_4A.ts
  • lib/plugins/Label_4A_01.ts
  • lib/plugins/Label_4A_DIS.ts
  • lib/plugins/Label_4A_DOOR.ts
  • lib/plugins/Label_80.ts
  • lib/plugins/Label_H1_FLR.ts
  • lib/plugins/Label_H1_M_POS.ts
  • lib/plugins/Label_H1_WRN.ts
  • lib/plugins/Label_SQ.ts
💤 Files with no reviewable changes (1)
  • lib/DateTimeUtils.ts

label?: string;
sublabel?: string;
preamble?: string;
version?: number | string;
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would rather it always be a number unless it can't, then just make it a string

- Move setDecodeLevel() inside the regex match block in Label_44_POS
  so failed parses are not incorrectly marked as successful. Add
  failUnknown() fallback for non-matching messages.
- Replace indirect console.log spy test with a probe plugin that
  verifies options are passed directly to the plugin's decode method.

https://claude.ai/code/session_01WHPebkdmNV4aEh8wzpzoj5
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: 1

🤖 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/MessageDecoder.ts`:
- Around line 85-91: The public mutable array field plugins is misleading
because decode() uses labelIndex and wildcardPlugins, so external mutations to
plugins won't affect dispatch; make plugins private (or at least a read-only
getter that returns a copy) and funnel all changes through
registerPlugin()/unregisterPlugin() (or add registerPlugin/removePlugin methods)
which must update labelIndex and wildcardPlugins consistently whenever a plugin
is added/removed; alternatively, if you must keep the public field, wrap it with
setters that synchronize updates into labelIndex and wildcardPlugins so decode()
stays correct (refer to symbols: plugins, labelIndex, wildcardPlugins,
registerPlugin, decode).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 900e86f3-b0f2-47d6-a793-f5ad66894766

📥 Commits

Reviewing files that changed from the base of the PR and between 3b14c35 and 1702ce1.

📒 Files selected for processing (4)
  • lib/DecoderPluginInterface.ts
  • lib/MessageDecoder.ts
  • lib/plugins/Label_44_Base.ts
  • lib/plugins/Label_44_IN.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/plugins/Label_44_Base.ts

Comment on lines 85 to +91
plugins: Array<DecoderPluginInterface>;
debug: boolean;

/** Maps a label string to the plugins registered for it, preserving registration order. */
private labelIndex: Map<string, DecoderPluginInterface[]> = new Map();
/** Plugins that match all labels (qualifier label '*'). */
private wildcardPlugins: DecoderPluginInterface[] = [];
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

Don't leave plugins publicly mutable here.

decode() is now driven by labelIndex/wildcardPlugins, so direct mutations to decoder.plugins no longer affect dispatch even though plugins still looks like the live source of truth. That's a silent behavioral break for existing consumers. Either make plugins read-only/private and funnel changes through registerPlugin(), or keep the indexes synchronized with external mutations.

Also applies to: 103-118

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

In `@lib/MessageDecoder.ts` around lines 85 - 91, The public mutable array field
plugins is misleading because decode() uses labelIndex and wildcardPlugins, so
external mutations to plugins won't affect dispatch; make plugins private (or at
least a read-only getter that returns a copy) and funnel all changes through
registerPlugin()/unregisterPlugin() (or add registerPlugin/removePlugin methods)
which must update labelIndex and wildcardPlugins consistently whenever a plugin
is added/removed; alternatively, if you must keep the public field, wrap it with
setters that synchronize updates into labelIndex and wildcardPlugins so decode()
stays correct (refer to symbols: plugins, labelIndex, wildcardPlugins,
registerPlugin, decode).

- Revert RawFields.version to number (not number | string). Fix
  Label_SQ to store Number() instead of raw substring, and compare
  against numeric 2 instead of string '2'. Update tests accordingly.
- Replace setDecodeLevel(false) with failUnknown() in Label_15_FST
  for consistent error handling across all plugins.

https://claude.ai/code/session_01WHPebkdmNV4aEh8wzpzoj5
Copy link

Copilot AI commented Mar 19, 2026

@kevinelliott I've opened a new pull request, #367, to work on those changes. Once the pull request is ready, I'll request review from you.

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.

🧹 Nitpick comments (1)
lib/MessageDecoder.labelindex.test.ts (1)

55-57: Misleading comment: decoder does include default plugins.

The comment states "Create a fresh decoder with no default plugins," but the test expects result.decoder.name to contain 'c-band' (line 67), which is a default plugin. This could confuse future maintainers.

📝 Suggested comment fix
-    // Create a fresh decoder with no default plugins
+    // Create a fresh decoder (includes default plugins like CBand)
     const decoder = new MessageDecoder();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/MessageDecoder.labelindex.test.ts` around lines 55 - 57, The comment is
incorrect: MessageDecoder() does include default plugins; either update the
comment to say "Create a fresh decoder with default plugins" or explicitly
construct the decoder without defaults (e.g., using whatever option/constructor
overload disables defaults) so the test intent matches reality; locate the
instantiation of MessageDecoder and the expectation checking result.decoder.name
(which contains 'c-band') and either change the comment text to reflect default
plugins are present or modify the decoder construction to disable defaults so
the existing comment is accurate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/MessageDecoder.labelindex.test.ts`:
- Around line 55-57: The comment is incorrect: MessageDecoder() does include
default plugins; either update the comment to say "Create a fresh decoder with
default plugins" or explicitly construct the decoder without defaults (e.g.,
using whatever option/constructor overload disables defaults) so the test intent
matches reality; locate the instantiation of MessageDecoder and the expectation
checking result.decoder.name (which contains 'c-band') and either change the
comment text to reflect default plugins are present or modify the decoder
construction to disable defaults so the existing comment is accurate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 316576c7-3e31-4366-bafc-853b33075ce2

📥 Commits

Reviewing files that changed from the base of the PR and between 1702ce1 and 7c49535.

📒 Files selected for processing (6)
  • lib/DecoderPluginInterface.ts
  • lib/MessageDecoder.labelindex.test.ts
  • lib/plugins/Label_15_FST.ts
  • lib/plugins/Label_44_POS.ts
  • lib/plugins/Label_SQ.test.ts
  • lib/plugins/Label_SQ.ts
✅ Files skipped from review due to trivial changes (2)
  • lib/plugins/Label_SQ.test.ts
  • lib/plugins/Label_15_FST.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • lib/plugins/Label_SQ.ts
  • lib/plugins/Label_44_POS.ts
  • lib/DecoderPluginInterface.ts

@kevinelliott kevinelliott merged commit f81a55c into master Mar 19, 2026
10 checks passed
@kevinelliott kevinelliott deleted the claude/improve-library-architecture-6SsF3 branch March 19, 2026 02:20
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.

5 participants