Skip to content

fix(csharp,python)!: replace MqttLocalId inheritance with composition - #70

Open
ronan-fesselier wants to merge 3 commits into
dnv-opensource:mainfrom
ronan-fesselier:fix/mqtt-local-id-lsp-violation
Open

ronan-fesselier wants to merge 3 commits into
dnv-opensource:mainfrom
ronan-fesselier:fix/mqtt-local-id-lsp-violation

Conversation

@ronan-fesselier

@ronan-fesselier ronan-fesselier commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Hi,

MqttLocalId overrides ToString()/__str__() with a format incompatible with LocalId.

Passing one where a LocalId is expected silently corrupts any pipeline that round-trips through the string: LocalId.TryParse(mqttLocalId.ToString()) fails.

The first commit adds failing tests that demonstrate the issue directly.

Replaced inheritance with composition.
This is a breaking change: MqttLocalId is no longer assignable to LocalId (C#) / no longer isinstance-true against it (Python).
Any project relying on that relationship will need updating.

See attached scripts and outputs for a concrete illustration:
cs_mqtt_lsp_violation.zip
py_mqtt_lsp_violation.zip

I looked at a less invasive fix first by keeping the inheritance (sealed/new on the C# side to block the unsafe upcast) but dropped it because Python has no static dispatch, so str() always calls the subclass's method regardless of the declared type, and I did not find a way to make both languages behave the same way.
Composition was the only option I found that worked in both.

…LSP violation

Adds a failing test per language simulating a real-world function signature
that accepts a LocalId parameter (exactly what happens when an MqttLocalId
is passed as an argument, since it IS-A LocalId): the returned string is
the MQTT format instead of the standard dnv-v2 format.
… inheriting LocalId

BREAKING CHANGE: MqttLocalId no longer inherits from LocalId (C#) / is no
longer a subclass of LocalId (Python). Code that upcasts MqttLocalId to
LocalId, or checks `is LocalId`/`isinstance(x, LocalId)`, will no longer
compile (C#) or will start returning False (Python).

MqttLocalId publicly inherited from LocalId but produced a fundamentally
incompatible ToString()/__str__() format (no leading slash, underscores,
no meta/ section), violating Liskov substitution: a caller holding a
LocalId reference could silently receive MQTT-topic text instead of the
standard dnv-v2 format.

MqttLocalId now composes a LocalIdBuilder directly. NamingRule/NAMING_RULE
and members unused by the MQTT format (VerboseMode/HasCustomTag/MetadataTags)
are reachable via .Builder/.builder instead of being duplicated.
@ronan-fesselier
ronan-fesselier force-pushed the fix/mqtt-local-id-lsp-violation branch 2 times, most recently from 65e20da to 88e6873 Compare September 15, 2026 18:51
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