Skip to content

QUIC Experiment#3

Merged
dwd merged 93 commits into
mainfrom
quic
May 9, 2026
Merged

QUIC Experiment#3
dwd merged 93 commits into
mainfrom
quic

Conversation

@dwd
Copy link
Copy Markdown
Owner

@dwd dwd commented Apr 6, 2026

No description provided.

dwd and others added 30 commits April 4, 2026 11:05
Implement initial QUIC-over-XMPP transport integration following the XEP-0467 design direction for a single reliable channel, with automatic endpoint selection via DNS SRV and fallback through existing TCP SRV logic.

This adds QUIC endpoint planning and socket integration at the app layer, extends vendored xmpp_stone connection settings/APIs to model and attempt QUIC endpoints first, and preserves existing TCP failover behavior when QUIC attempts fail. It also records partial XEP-0467 support in doap.xml and includes the QUIC implementation plan document.

Tests and validation run:

- dart format on all touched Dart files

- flutter analyze

- flutter test

- (cd vendor/xmpp_stone && dart test)

New tests added:

- test/quic_endpoint_plan_test.dart

- vendor/xmpp_stone/test/connection_quic_failover_test.dart
Re-enable Linux QUIC transport usage and keep flutter_quic as a vendored path dependency so plugin metadata is controlled in-repo. This keeps QUIC active on Linux, Windows, and Android while preserving the existing TCP fallback behavior.

Update CI and release workflows to provision Rust toolchains and required targets for flutter_quic native builds, including cargo-ndk for Android cross-compilation.

Validation run before commit:

- flutter analyze

- flutter test

- (cd vendor/xmpp_stone && dart test)
Negotiate a conservative QUIC stream limit of 25 and add post-bind stream multiplexing in the client transport.

After resource binding is detected on the control stream, the QUIC socket now proactively opens up to 20 auxiliary bidirectional streams and keeps a dedicated control stream for account-scoped traffic.

Outgoing stanza routing is deterministic by bare JID:
- stanzas addressed to the account bare JID stay on the original control stream
- stanzas to other entities are mapped via stable hash to one of 20 auxiliary stream slots

Added routing helper tests for bare-JID extraction/normalization and deterministic slot bounds.

Tested with:
- flutter analyze
- flutter test
- (cd vendor/xmpp_stone && dart test)
…late

The foreground task plugin requires a top-level function annotated with
@pragma('vm:entry-point') to be used as the background isolate entry
point. Previously, setTaskHandler was called inside an instance method
(_startAndroidForegroundService), which meant the background isolate
could not find or invoke it, resulting in:

  MissingPluginException: No implementation found for method start
  on channel flutter_foreground_task/background

Fix by:
- Adding a top-level startCallback() function annotated with
  @pragma('vm:entry-point') that calls setTaskHandler with
  WimsyForegroundTaskHandler.
- Removing the misplaced setTaskHandler call from the instance method.
- Passing startCallback as the callback parameter to startService(),
  so the plugin registers the correct entry point for the background
  isolate.

Fixes WIMSY-6

Tested by running flutter analyze (no new issues), flutter test (all
pass except pre-existing quic_happy_eyeballs_test.dart which references
a missing file unrelated to this change), and dart test in
vendor/xmpp_stone (all 64 tests pass).

Co-authored-by: Junie <junie@jetbrains.com>
- Guard Log.logLevel = LogLevel.VERBOSE and Log.logXmpp = true behind
  an assert() block so verbose XMPP XML logging is only active in
  debug/profile builds and never leaks stanza content in release builds.

- Replace DateTime.now().millisecondsSinceEpoch.remainder(1 << 31) with
  bareJid.hashCode.abs() % (1 << 31) in both _handleIncomingMessage and
  _handleIncomingRoomMessage. The deterministic ID means rapid messages
  from the same contact update the same notification rather than stacking
  new ones, fixing the grouped-dismiss bug.

Tested: flutter analyze (clean), flutter test (145/145 passed),
dart test in vendor/xmpp_stone (65/65 passed).

Co-authored-by: Junie <junie@jetbrains.com>
ChatMessage gains a copyWith({...}) method covering all 28 fields. A
sentinel object (_absent) is used for nullable parameters so callers can
explicitly clear a field (pass null) vs. leave it unchanged (omit the
argument).

All five mutation sites that previously repeated the full 28-field
constructor are replaced with copyWith:
- lib/xmpp/chat_message_mutations.dart: applyCorrectionInList and
  updateReactionsInList (2 sites)
- lib/xmpp/mam_merge_engine.dart: messageId-match merge and
  heuristic body/time-window merge (2 sites)
- lib/xmpp/xmpp_service.dart: incoming-message dedup update,
  room-message dedup update, _updateFileTransferMessage,
  _updateOutgoingStatus, _updateOutgoingRoomStatus (5 sites)

The heuristic merge in mam_merge_engine previously omitted messageId
from the constructor (a latent bug — the field silently became null).
copyWith correctly preserves it; the characterization test in
mam_reliability_regression_test.dart is updated to assert the correct
behaviour.

Tested: flutter analyze (clean), flutter test (145/145 passed),
dart test in vendor/xmpp_stone (65/65 passed).

Co-authored-by: Junie <junie@jetbrains.com>
All 14 scattered SharedPreferences.getInstance() call sites in
lib/main.dart are replaced with a single PreferencesService instance
that is created once in main() and passed down through the widget tree.

New file lib/storage/preferences_service.dart holds all five preference
key constants (sentry_opt_in, wimsy_pin_ignored, wimsy_last_jid,
wimsy_audio_input, wimsy_video_input) and provides typed getters and
setters for each.

WimsyApp, _Gatekeeper, WimsyHome, _PresenceMenu, _PinSetupScreen, and
_PinUnlockScreen each receive PreferencesService via their constructors.
The raw shared_preferences import is removed from main.dart.

New test file test/preferences_service_test.dart covers all five
preference groups (default values and round-trip get/set) using
SharedPreferences.setMockInitialValues. test/widget_test.dart is updated
to supply the required PreferencesService to WimsyApp.

Tested: flutter analyze (clean), flutter test (156/156 passed),
dart test in vendor/xmpp_stone (65/65 passed).

Co-authored-by: Junie <junie@jetbrains.com>
Step 1 – Fix verbose logging and notification ID stability:
- Guard Log.logLevel/logXmpp behind assert() so verbose XMPP logging
  is only active in debug/profile builds, never in release.
- Replace DateTime.now().millisecondsSinceEpoch.remainder(1<<31) with
  bareJid.hashCode.abs() % (1<<31) for deterministic notification IDs,
  preventing notification stacking for the same sender.

Step 2 – Add copyWith to ChatMessage and replace all manual copy sites:
- Added ChatMessage.copyWith({...}) with sentinel-object pattern for
  nullable fields so callers can explicitly clear them to null.
- Replaced all manual full-constructor copy blocks in
  mam_merge_engine.dart (2 sites), chat_message_mutations.dart (2 sites),
  and xmpp_service.dart (4 sites) with copyWith calls.
- Updated mam_reliability_regression_test.dart: the heuristic-merge path
  now correctly preserves messageId (copyWith keeps all unspecified fields),
  fixing a latent bug where the old manual copy omitted messageId.

Step 3 – Centralise SharedPreferences into PreferencesService:
- New file lib/storage/preferences_service.dart with all key constants
  and typed getters/setters (sentryOptIn, pinIgnored, lastJid,
  audioInputId, videoInputId).
- Initialised once via PreferencesService.load() in main() and passed
  down through WimsyApp → _Gatekeeper → WimsyHome → _PresenceMenu /
  _PinSetupScreen / _PinUnlockScreen.
- Removed all 14 inline SharedPreferences.getInstance() call sites from
  lib/main.dart; removed the now-unused shared_preferences import.
- Added test/preferences_service_test.dart: 10 unit tests covering all
  five preference keys using SharedPreferences.setMockInitialValues.
- Updated test/widget_test.dart to pass a PreferencesService to WimsyApp.

Step 4 – Extract LoginScreen from _WimsyHomeState:
- New file lib/login_screen.dart containing LoginScreen stateful widget
  with all login form state (7 controllers, endpoint discovery, advanced
  options, connect logic).
- Removed _buildLogin, _handleConnect, _buildAdvancedOptions,
  _scheduleEndpointDiscovery, _discoverEndpoint, _domainFromBareJid and
  all login-only fields from _WimsyHomeState (~1100 lines removed).
- _WimsyHomeState.build now returns LoginScreen(...) when not connected.

Tested: flutter analyze (no issues), flutter test (156/156 pass),
dart test in vendor/xmpp_stone (65/65 pass).

Co-authored-by: Junie <junie@jetbrains.com>
- XEP-0388 (SASL2): upgraded status from 'partial' to 'complete'.
  The implementation now covers SCRAM authentication, user-agent binding,
  stream resumption inline, and IAP config-version pipelining (added on
  the quic branch and covered by sasl2_test.dart).
- XEP-0467 (QUIC transport): remains 'partial' — the current
  implementation uses a single reliable bidirectional channel only;
  multi-channel and datagram usage are explicitly out of scope for this
  phase (see doc/plan-quic.md).

Note: XmppFileTransferHandler extraction (also part of Step 5 in the
plan) was deferred — the file-transfer code is spread across ~50 sites
throughout xmpp_service.dart, deeply interleaved with IBB/Jingle event
handlers, Sentry spans, and message persistence callbacks. A safe
extraction requires a dedicated effort with broader test coverage and is
tracked as a follow-up task.

Tested: flutter analyze (no issues), flutter test (156/156 pass),
dart test in vendor/xmpp_stone (65/65 pass).

Co-authored-by: Junie <junie@jetbrains.com>
The copyWith method added in the cleanup pass had no direct test coverage
despite its non-trivial sentinel-object pattern for nullable fields.

New tests added (12 copyWith + 4 notification ID = 16 new cases):

copyWith group:
- 'returns identical field values when called with no arguments' — verifies
  all 29 fields are preserved when copyWith() is called with no arguments.
- 'overrides scalar non-nullable fields' — from, to, body, outgoing, edited,
  acked, receiptReceived, displayed can all be changed independently.
- 'overrides nullable String fields via sentinel' — messageId, mamId,
  stanzaId, oobUrl, oobDescription, rawXml, fileTransferId, fileName,
  fileMime, fileState, replyToId, replyToJid, replyFallback.
- 'overrides nullable int fields via sentinel' — fileSize, fileBytes.
- 'clears nullable fields to null via explicit null (sentinel pattern)' —
  passing null explicitly clears all 20 nullable fields; non-nullable fields
  are unaffected.
- 'updates reactions map independently' — new reactions map is applied;
  original message is unaffected.
- 'sets editedAt when marking a message as edited' — edited + editedAt
  updated together.
- 'does not mutate the original message' — copyWith never modifies the
  receiver.

notification ID stability group:
- 'same JID always produces the same notification ID' — deterministic hash.
- 'notification ID is non-negative' — abs() ensures no negative IDs.
- 'notification ID is within 32-bit signed range' — result < 2^31.
- 'different JIDs produce different notification IDs' — no collisions for
  typical JID strings.

Tested: flutter analyze (no issues), flutter test (168/168 pass),
dart test in vendor/xmpp_stone (65/65 pass).

Co-authored-by: Junie <junie@jetbrains.com>
The existing mutation tests only covered the happy path. Seven new tests
add coverage for the negative and boundary cases that are most likely to
regress silently.

New tests for applyCorrectionInList:
- 'returns false when replaceId not found' — list is unchanged when no
  message matches the replacement ID.
- 'returns false when sender bare JID does not match' — a correction from
  a different user (eve) is rejected even if the message ID matches.
- 'returns false when exact sender does not match and matchSenderBare is
  false' — same bare JID but different resource must not match in strict
  mode.
- 'applies correction to most-recent matching message' — when two messages
  share an ID the implementation iterates from the end; the last entry is
  corrected and the first is left untouched.

New tests for updateReactionsInList:
- 'returns false when stanza ID not found' — no mutation when the target
  stanza ID is absent from the list.
- 'returns false for empty sender' — the empty-sender guard returns false
  immediately without touching the list.
- 'matches by messageId when stanzaId absent' — reactions can be applied
  via messageId fallback when no stanzaId is set on the message.

Tested: flutter analyze (no issues), flutter test (175/175 pass),
dart test in vendor/xmpp_stone (65/65 pass).

Co-authored-by: Junie <junie@jetbrains.com>
The existing merge engine tests only covered the four main happy/sad paths.
Four new tests add coverage for boundary conditions that could silently
regress.

New tests:
- 'does not merge by heuristic when body differs' — a MAM replay with a
  different body must not be merged into an existing local message even
  when sender, timestamp, and direction all match.
- 'does not merge by heuristic when sender differs' — a message from a
  different JID is not merged even when body and timestamp match.
- 'merges oobUrl and oobDescription via message-id match' — when a MAM
  replay carries oobDescription and rawXml, both are propagated into the
  existing message alongside mamId/stanzaId.
- 'does not merge by message-id when both mamId and stanzaId already set'
  — once a message has both archive IDs the merge is skipped entirely,
  preventing accidental overwrite of already-resolved metadata.

Tested: flutter analyze (no issues), flutter test (179/179 pass),
dart test in vendor/xmpp_stone (65/65 pass).

Co-authored-by: Junie <junie@jetbrains.com>
…IMSY-19)

_ensureAuxStream could call connectionOpenBi on a Rust QUIC connection
object that had already been disposed by a concurrent close() call. This
caused a fatal DroppableDisposedException crash reported in Sentry (WIMSY-19).

The fix adds two guards:
1. Check _closed alongside the _connection null-check before calling
   connectionOpenBi, so we never enter the FFI call if teardown has begun.
2. Re-check _closed after the await returns, since close() may have fired
   during the async gap while connectionOpenBi was in flight; if so, we
   throw a StateError (caught by the write() error handler) rather than
   storing the now-orphaned streams.

Tested: flutter analyze (no issues), flutter test (179/179), dart test in
vendor/xmpp_stone (65/65).

Co-authored-by: Junie <junie@jetbrains.com>
Add debugPrint calls at three key points in the aux stream lifecycle:

- Outbound open: logged in _ensureAuxStream after the channel is
  registered in _auxStreamsBySlot, showing the slot number.
- Close: logged in close() before finishing aux send streams, showing
  the count and slot numbers of all channels being torn down.
- Recv loop exit: logged in the finally block of _startRecvLoop for
  non-control streams, showing which slot's recv loop has ended.

No inbound (server-initiated) aux stream acceptance exists in the
current implementation, so only outbound opens are covered.

Tested: flutter analyze clean; flutter test 179/179; dart test 65/65.
Co-authored-by: Junie <junie@jetbrains.com>
The stream features response was arriving in two TCP/QUIC chunks. The
old code in prepareStreamResponse appended </stream:stream> to the
first (incomplete) chunk, producing malformed XML mid-attribute
(e.g. 'https</stream:stream>://...'). A second broken buffering layer
in handleResponse then tried to re-assemble using magic fixed offsets
(strip 12 chars from start, 13 from end), which failed when the second
chunk was a raw continuation rather than a fresh <xmpp_stone>-wrapped
response. This caused the connection to hang on stream features and be
timed out by the server after 20 seconds.

Fix: consolidate all buffering into prepareStreamResponse using the
existing (but previously unused) restOfResponse field. After combining
any buffered data with the new chunk, attempt a full XML parse. If it
fails (incomplete), save the raw combined data to restOfResponse and
return '' so handleResponse has nothing to process. Only when the parse
succeeds is the wrapped, complete XML emitted. restOfResponse is also
reset in _attachOpenedSocket on reconnect.

The broken _unparsedXmlResponse field and its magic-offset reassembly
logic in handleResponse have been removed entirely.

Tested: flutter analyze clean; flutter test 179/179; dart test 65/65.
Co-authored-by: Junie <junie@jetbrains.com>
…(WIMSY-19)

When close() set _connection = null, it dropped the last Dart-side strong
reference to the RustArc, disposing it. Any concurrent _ensureAuxStream call
that had already captured the connection in a local variable would then crash
during connectionOpenBi's SSE argument encoding phase with
DroppableDisposedException.

Fix: do not null _connection in close(). The _closed flag already prevents
any new use of the connection. The RustArc is released naturally once all
local references (in-flight connectionOpenBi calls) drop. Since
QuicCapableXmppSocket is not reused after close(), there is no risk of
holding a stale reference across reconnects.

Tested: flutter analyze (no issues), flutter test 179/179, dart test 65/65.
Co-authored-by: Junie <junie@jetbrains.com>
XEP-0198 (urn:xmpp:sm:3) is incompatible with QUIC (XEP-0467): QUIC
provides its own reliable, ordered delivery at the transport layer, so
stream management's stanza acknowledgement and resumption are redundant
and can cause connection hangs.

Changes:
- Add 'bool get isQuic => false' to XmppWebSocket abstract base class
- Override 'isQuic => true' in QuicCapableXmppSocket
- Expose 'bool get isQuic' on Connection via '_socket?.isQuic ?? false'
- Guard StreamManagementModule.negotiate() and isReady() to return
  early/false when _connection.isQuic
- Add '@OverRide' annotation to QuicCapableXmppSocket.write()
- Add 'bool get isQuic => false' to all test fake socket classes that
  use 'implements XmppWebSocket' (9 files)

Tested: flutter analyze (no issues), flutter test (179/179),
dart test in vendor/xmpp_stone (65/65).

Co-authored-by: Junie <junie@jetbrains.com>
…IMSY-19)

The crash occurred when two concurrent callers of _ensureAuxStream (e.g.
_startAuxStreamsOpen and a write() call via _selectSendTarget) both captured
the same _connection RustArc and both attempted to call connectionOpenBi.
The FRB-generated binding transfers the arc via Auto_Owned (consuming it),
so the second caller tried to encode an already-disposed arc, causing
DroppableDisposedException during SSE argument encoding.

Fix: split _ensureAuxStream into a fast synchronous check plus a new
_openAuxStream async method. An _auxStreamOpening map caches the in-flight
Future per slot; putIfAbsent ensures only one connectionOpenBi call runs at
a time per slot, and concurrent callers await the same Future. The in-flight
entry is removed in a finally block so retries are possible after failure.
_auxStreamOpening is also cleared in close() for hygiene.

Tested: flutter analyze clean; flutter test 179/179; dart test 65/65.
Co-authored-by: Junie <junie@jetbrains.com>
…leXmppSocket

Log 'QUIC aux stream opening slot=N reason=...' immediately before calling
connectionOpenBi, so that if the open fails or causes a crash the log shows
both which slot was being opened and why:

- Post-bind pre-open (from _startAuxStreamsOpen): reason is
  'post-bind pre-open slot N of M'
- On-demand routing (from _getSendTarget): reason is
  'on-demand routing for <bareJid>'

The reason is threaded through _ensureAuxStream and _openAuxStream as an
optional/named parameter; coalesced concurrent opens for the same slot
preserve the reason of the first caller that triggered the open.

Tested: flutter analyze clean, flutter test 179/179 pass.
Co-authored-by: Junie <junie@jetbrains.com>
…(WIMSY-19)

connectionOpenBi uses Auto_Owned FFI transfer: it consumes the RustArc
passed as _connection and returns a new one. The previous per-slot
coalescing (_auxStreamOpening map) only prevented concurrent opens for
the *same* slot. Two opens for *different* slots could still run
concurrently, both capturing the same (about-to-be-consumed) arc; the
second call would then crash with DroppableDisposedException.

Fix: introduce a global async mutex (_auxOpenLock, a chained Future)
that serialises all connectionOpenBi calls regardless of slot. Each
_openAuxStream call chains onto the previous lock future, reads
_connection only after the previous call has completed and updated it,
then releases the lock in a finally block. _auxOpenLock is also reset
in close() so a reconnect does not wait on a stale chain.

Tested: flutter analyze clean, flutter test 179/179 pass.
Co-authored-by: Junie <junie@jetbrains.com>
Previously _startAuxStreamsOpen opened aux streams sequentially in a
single async loop, blocking each slot open on the previous one. This
meant the connection was effectively stalled waiting for all aux streams
to be established before proceeding with normal XMPP traffic.

Now each slot is fired as an independent unawaited async task. The
global _auxOpenLock mutex in _openAuxStream still serialises the
underlying connectionOpenBi FFI calls (which use Auto_Owned arc
transfer), so there is no race — the tasks simply queue up on the lock
rather than blocking the caller.

The main (control) stream continues to be used for all connection-state
work and for traffic to/from the user's own bare JID, as enforced by
the existing _postBindReady and _accountBareJid guards in
_selectSendTarget.

Tested: flutter analyze clean, flutter test 179/179 pass,
dart test vendor/xmpp_stone 65/65 pass.

Co-authored-by: Junie <junie@jetbrains.com>
Adds a 'Use QUIC transport (XEP-0467)' checkbox to the advanced options
section of the login screen, defaulting to enabled. When disabled, QUIC
SRV discovery is skipped and no QUIC endpoints are built, so the
connection falls back to plain TCP — allowing QUIC to be isolated as the
cause of post-bind stalls without changing any other settings.

Changes:
- AccountRecord: new useQuic field (default true), persisted in toMap /
  fromMap (old accounts without the key default to true).
- XmppService.connect(): new useQuic parameter (default true) gates both
  the QUIC SRV lookup and the quicEndpoints assignment.
- LoginScreen: _useQuic state loaded from stored account; passed to
  AccountRecord and service.connect(); checkbox rendered in advanced
  options between Resource and WebSocket, disabled on web.

Tested: flutter analyze clean, flutter test 179/179 pass,
dart test vendor/xmpp_stone 65/65 pass.

Co-authored-by: Junie <junie@jetbrains.com>
When using QUIC transport, StreamManagementModule.negotiate() was
returning early without setting NegotiatorState.DONE. This left the
ConnectionNegotiatorManager's negotiator queue permanently stalled:
stateListener() was never called, negotiateNextFeature() was never
triggered, doneParsingFeatures() was never called, and consequently
XmppConnectionState.Ready was never set.

The result was that all post-bind activity (presence, carbons enable,
roster fetch, MAM catch-up) never happened — the connection appeared
to hang silently after resource binding.

Fix: emit NegotiatorState.DONE before returning in the QUIC early-exit
path, so the queue advances normally and doneParsingFeatures() fires.

Tested: flutter analyze clean, flutter test 179/179 pass,
dart test vendor/xmpp_stone 65/65 pass.

Co-authored-by: Junie <junie@jetbrains.com>
…ady()

When using QUIC transport, XEP-0198 Stream Management is intentionally
skipped (QUIC provides its own reliability). The negotiate() method
already handled this correctly by immediately setting state = DONE and
returning early.

However, isReady() was returning false for QUIC connections, which
caused pickNextNegotiator() in ConnectionNegotiatorManager to skip the
SM negotiator entirely via firstWhere(). Since negotiate() was never
called, the state never advanced to DONE, and the negotiator queue
stalled indefinitely — causing the observed hang after resource binding.

Fix: isReady() now returns true for QUIC connections, allowing
negotiate() to be called and immediately complete (DONE), so the
negotiator queue advances normally to ServiceDiscovery and beyond.

Tested: flutter analyze (clean), flutter test (179 passed),
dart test in vendor/xmpp_stone (65 passed).

Co-authored-by: Junie <junie@jetbrains.com>
Previously the '---Xmpp Sending:---' log line was emitted from
Connection.write(), which runs at queue-time: before the bufferedWrites
flush, before the TCP/WS/QUIC socket handoff, and — crucially on QUIC —
before _selectSendTarget() had picked (or opened) the destination
stream. That made the log line misleading for any diagnostics about
what is actually on the wire, and it hid the fact that a stanza can be
routed to a QUIC aux stream that is still pending an open.

This change moves the send log to the transport layer:

- vendor/xmpp_stone/lib/src/Connection.dart:
  - Connection.write() no longer logs; a comment explains where the
    log is now emitted and why.
- vendor/xmpp_stone/lib/src/logger/Log.dart:
  - Log.xmppp_sending() gains an optional 'channel' parameter; when
    set, the header is rendered as '---Xmpp Sending [<channel>]:---'.
- vendor/xmpp_stone/lib/src/connection/XmppWebsocketIo.dart:
  - Logs with channel 'tcp' or 'ws' immediately before the actual
    socket/sink write, and skips logging entirely if the underlying
    socket is null (no transport handoff).
- lib/xmpp/quic_xmpp_socket.dart:
  - _QuicSendTarget now carries a channel label ('quic-control' or
    'quic-aux-<slot>') that reflects the real stream _selectSendTarget
    resolved to, including slot number for bare-JID-hashed aux
    streams.
  - The write queue logs the payload with that label right before
    sendStreamWriteAll, i.e. at the moment bytes are handed to the
    QUIC stream.

This directly addresses the wimsy.log observation that a post-bind
disco#info to the server domain appeared to be 'sent' but never
reached the server: the new log will show the exact QUIC stream
(control vs aux-N) the stanza was actually written to.

Testing:
- flutter analyze: clean (no issues)
- flutter test: 179 tests passed
- dart test in vendor/xmpp_stone: 65 tests passed
No new tests were added; the change is limited to log-site plumbing
and existing tests exercise Connection.write and the TCP/WS socket
write paths. The QUIC path has no unit-level test harness in-tree and
is verified at runtime via wimsy.log.

Co-authored-by: Junie <junie@jetbrains.com>
Fix the post-bind hang where ServiceDiscoveryNegotiator's disco#info to the
user's own server domain was queued but never actually written on the QUIC
transport, causing the 20s connect-ready timeout in XmppService and a
ForcefullyClosed reconnect loop.

Root cause: QuicCapableXmppSocket._selectSendTarget routed any stanza whose
'to' was not the account bare JID to an aux QUIC stream, and awaited
_ensureAuxStream on the single serial _writeQueue chain. The post-bind
disco#info is addressed to the account *domain* (e.g. dave.cridland.net),
which hashed to aux slot 0. slot 0's connectionOpenBi() was still in flight
(or hanging) from the pre-open pass started the moment the bind result
arrived, so the write queue deadlocked behind it and the disco stanza was
never handed to any send stream - no 'Xmpp Sending' log, no bytes on the
wire.

Changes in lib/xmpp/quic_xmpp_socket.dart (_selectSendTarget):
  * Server-directed stanzas are kept on the control stream: this now covers
    stanzas with no 'to', stanzas addressed to the account bare JID, and
    stanzas addressed to the user's own server domain. Negotiation IQs
    (disco#info, session, etc.) never go to an aux stream.
  * For all other bare-JID targets, we no longer await aux-stream creation
    on the write queue. If the aux stream is already open we use it; if not,
    we kick off _ensureAuxStream in the background and send this payload on
    the control stream. Future writes to the same bare JID will use the aux
    stream once it is ready, but a slow or failing aux open can never stall
    the rest of the connection's outbound traffic again.

Tested: * flutter analyze: clean, no issues
  * flutter test: 179 passed
  * dart test in vendor/xmpp_stone: 65 passed
  * No new unit tests added: the QUIC transport has no in-tree test harness
    (it is runtime-verified via wimsy.log); the selection logic is a
    straightforward guard around an already-covered code path.
Co-authored-by: Junie <junie@jetbrains.com>
After the previous fix to keep negotiation traffic on the control stream,
runtime logs showed that the post-bind aux-stream opens never produced
any success or failure log after the initial 'QUIC aux stream opening
slot=0' line. Only slot 0 logged at all, because all other slots queue
behind _auxOpenLock and slot 0's completer never fires: connectionOpenBi
(Quinn open_bi) blocks indefinitely when the peer has not granted
additional bidirectional-stream credits via MAX_STREAMS.

Changes in lib/xmpp/quic_xmpp_socket.dart _openAuxStream:
- Log 'awaiting open lock' for each slot before taking the lock, so we
  can see that all slots are at least attempting to open.
- Log 'calling connectionOpenBi' immediately before the FFI call.
- Start a Timer.periodic (2s) that logs 'connectionOpenBi still pending
  after Nms' so a stuck open is visible in the logs.
- Wrap connectionOpenBi in a 10s timeout that throws TimeoutException
  with an explanatory message, so _auxOpenLock is released and
  subsequent slots can proceed (or fail) instead of being silently
  starved.
- Log elapsed time on success and on any error (with stack) so future
  failures are diagnosable from wimsy.log alone.

Tested:
- flutter analyze: clean
- flutter test: 179 passed
- dart test in vendor/xmpp_stone: 65 passed
No new unit tests: QUIC transport still has no in-tree harness; this is
diagnostic plumbing on a runtime-only code path, intended to be
validated via wimsy.log on the next QUIC session.

Co-authored-by: Junie <junie@jetbrains.com>
When a QUIC aux stream open fails (DroppableDisposedException after
connection teardown, StateError for closed connection, or TimeoutException
from the 10s open timeout), the error was being rethrown inside a
catchError() on an unawaited Future, causing it to surface as a fatal
unhandled exception via PlatformDispatcher.onError and reported to Sentry
as WIMSY-1D, WIMSY-1B, and WIMSY-1C.

The on-demand open path in _selectSendTarget used catchError() which
requires the handler to return a value of the Future's type; rethrowing
was the only way to satisfy the type checker, but that made the error
fatal. Replaced with .then((_) {}, onError: ...) which has a void
onError handler and correctly swallows the error after logging it.

These failures are expected during connection teardown: the payload was
already sent on the control stream, so the aux stream open failure is
non-fatal. The pre-open path in _startAuxStreamsOpen was already safe
(catch inside the async body).

Fixes: WIMSY-1D, WIMSY-1B, WIMSY-1C

Tested: flutter analyze (clean), flutter test (179 passed),
dart test in vendor/xmpp_stone (65 passed).

Co-authored-by: Junie <junie@jetbrains.com>
Log server MAX_STREAMS(bidi) frame counts via connectionStats() at two
key moments:
  - immediately after the QUIC handshake completes ('post-connect'), so
    we can see the server's initial credit situation in the log;
  - when connectionOpenBi times out ('aux-open-timeout slot=N'), so we
    know the credit count at the moment of failure.

Add _auxStreamsBlocked flag: set on connectionOpenBi timeout, cleared
when a new MAX_STREAMS(bidi) frame is detected. A periodic watcher
(every 5 s) polls connectionStats() while blocked and resumes aux
stream opens as soon as the server raises the limit.

Change _startAuxStreamsOpen to open slots sequentially rather than
firing all 20 concurrently. This means:
  - we stop immediately at the first credit-starvation timeout instead
    of queuing 19 more doomed calls that each fail with
    DroppableDisposedException (the Auto_Owned RustArc is consumed by
    the timed-out slot-0 call and never returned);
  - when the watcher detects new credits, _openAuxStreamsSequentially
    resumes from where it left off.

Reset all new state (_auxStreamsBlocked, _lastMaxStreamsBidiFrameCount,
_maxStreamsWatchTimer) in close() so a reconnect starts clean.

Tested: flutter analyze (no issues), flutter test (179 passed),
dart test in vendor/xmpp_stone (65 passed).

Co-authored-by: Junie <junie@jetbrains.com>
dwd and others added 26 commits May 1, 2026 16:38
…chive query

When _lastMamIdSeen is non-null (i.e. any session after the first),
_primeMamSync now issues a single MAM IQ against the user's own server
archive (no to= JID, afterId=_lastMamIdSeen) instead of fanning out one
catch-up IQ per DM contact. The server returns all missed DM messages
across every contact in one paginated stream; the existing _addMessage
routing dispatches each forwarded message to the correct chat by JID.

On completion the RSM <last> id from the <fin> IQ result is used to
advance _lastMamIdSeen via the existing _bumpLastMamIdSeen helper, so
the anchor stays current for the next session.

When _lastMamIdSeen is null (fresh install / first session) the
previous per-chat fan-out is retained as a fallback so each chat still
gets its initial 25-message tail. MUC archives are per-room by protocol
and remain as per-room queries regardless.

The IQ is built manually (rather than via MessageArchiveManager.queryById)
so the IQ id can be captured and an IqRouter response handler registered
to receive the <fin> result without polling.

New tests:
- test/unified_mam_catchup_test.dart: 6 tests covering the <fin> RSM
  <last> parsing logic (well-formed result, missing fin, missing RSM
  set, missing last element, non-RESULT type, whitespace trimming).
- vendor/xmpp_stone/test/mam_query_xml_test.dart: 1 new test verifying
  the unified query IQ has no toJid, carries after-id field with the
  correct anchor value, RSM max=50, and urn:xmpp:mam:2 namespace.

Tested: flutter test (246 pass), dart test in vendor/xmpp_stone (82 pass).
Co-authored-by: Junie <junie@jetbrains.com>
The server may open bidirectional QUIC streams to push large responses
(e.g. MAM pages) to the client without waiting for the client to open a
stream first. Previously the client had no accept loop, so these streams
were silently ignored: the MAM IQ result never arrived, _lastMamIdSeen
never advanced, and _primeMamSync re-issued the same unified catch-up
query on every Ready cycle — producing a continuous MAM request loop.

Changes:
- vendor/flutter_quic/rust/src/core/connection.rs: add accept_bi() to
  QuicConnection, wrapping Quinn's Connection::accept_bi(). Returns
  Option<(QuicSendStream, QuicRecvStream)> — None on connection close.
- vendor/flutter_quic/rust/src/api/bridge.rs: add connection_accept_bi()
  free function following the same Auto_Owned pattern as connection_open_bi().
  Returns (QuicConnection, Option<QuicSendStream>, Option<QuicRecvStream>).
- Regenerated vendor/flutter_quic/rust/src/frb_generated.rs and
  vendor/flutter_quic/lib/src/rust/frb_generated.dart via
  flutter_rust_bridge_codegen generate.
- lib/xmpp/quic_xmpp_socket.dart:
  * _startRecvLoop: add optional String? label parameter so server-stream
    recv loops log a meaningful channel name (quic-server-N).
  * _startServerStreamAcceptLoop: new method that loops on
    connectionAcceptBi(), starts an independent _startRecvLoop for each
    accepted stream with its own XML mapper (via _makeAuxMapper), and
    exits cleanly when the connection closes or _closed is set.
  * connect(): call _startServerStreamAcceptLoop() immediately after
    _startControlRecvLoop() so server-pushed streams are accepted from
    the moment the QUIC connection is established.
- test/quic_stream_routing_test.dart: add connectionAcceptBi bridge export
  test (compile-time regression guard); live-connection behaviour requires
  integration testing against a real QUIC server.

Tested: flutter test (247 pass, +1 new); dart test in vendor/xmpp_stone
(82 pass). Rust cargo build clean (7 pre-existing warnings, no errors).

Co-authored-by: Junie <junie@jetbrains.com>
Two related QUIC multi-stream bugs fixed:

1. DroppableDisposedException on aux stream open
   Root cause: _startServerStreamAcceptLoop called connectionAcceptBi
   using a local copy of _connection concurrently with connectionOpenBi
   in _openAuxStream. Both functions used Auto_Owned FFI transfer,
   consuming the same RustArc; the second caller found it already
   disposed.

   Fix: change connection_accept_bi in the Rust bridge to take
   &QuicConnection (shared reference) instead of QuicConnection
   (Auto_Owned). Quinn's accept_bi() only needs &self, so this is
   safe. The accept loop no longer consumes the arc and can run
   concurrently with connectionOpenBi without any locking.
   Regenerated frb_generated.rs / frb_generated.dart via
   flutter_rust_bridge_codegen generate.

2. Ready-burst stanzas sent on quic-control instead of aux streams
   Root cause: _selectSendTarget fell back to the control stream
   immediately when the aux stream for a bare JID was not yet open,
   so the entire post-Ready burst (vCard IQs, avatar polls, caps
   disco, MAM catch-up) went on quic-control.

   Fix: introduce _auxStreamPendingQueue (Map<int, List<String>>).
   When a stanza targets a slot whose aux stream is not yet open,
   enqueue it and kick off _ensureAuxStream. On success,
   _flushAuxPendingQueue sends all queued stanzas in order on the
   aux stream. On failure (disposed arc, timeout), the queue is
   drained to the control stream so no stanzas are silently dropped.
   _selectSendTarget now returns null for enqueued payloads; write()
   checks for null and skips the immediate send.

Also updated _auxOpenLock comment to clarify it serialises all
Auto_Owned FFI calls (connectionOpenBi, connectionStats, etc.) but
NOT connectionAcceptBi which now uses a shared ref.

Testing: all 247 flutter tests pass; all 82 xmpp_stone dart tests
pass; cargo build clean (no new warnings).

Co-authored-by: Junie <junie@jetbrains.com>
When the server opens a bidirectional QUIC stream (e.g. to push a MAM
page response), we now pool it rather than immediately starting a
receive-only loop. When _ensureAuxStream next needs a stream for a new
bare-JID slot it pops from this pool first, avoiding a connectionOpenBi
round-trip and conserving the peer's bidi-stream credit budget.

Changes:
- quic_xmpp_socket.dart: add _serverStreamPool (List<_QuicStreamChannel>).
  _startServerStreamAcceptLoop now pushes accepted streams onto the pool
  instead of starting a recv loop immediately (send-stream-less streams
  still get an immediate recv-only loop as a fallback).
  _openAuxStream checks the pool first; if non-empty it pops the front
  entry, assigns it to the slot, starts its recv loop, removes the slot
  from _auxStreamOpening, and returns without touching connectionOpenBi.
  Pool is cleared in close() alongside the other stream maps.
  Added @VisibleForTesting serverStreamPoolSize getter and
  injectServerStreamForTesting() for future integration tests.
- test/quic_stream_routing_test.dart: two new tests verifying
  serverStreamPoolSize is 0 at construction and after close().

Testing:
- flutter test: 249 tests pass (+2 new).
- dart test (vendor/xmpp_stone): 82 tests pass.
- cargo build (vendor/flutter_quic/rust): clean (no new warnings).

Co-authored-by: Junie <junie@jetbrains.com>
… pop

Previously, when a server-initiated QUIC stream was accepted and added to
_serverStreamPool, its recv loop was NOT started. Inbound stanzas pushed
by the server on that stream were silently dropped until the stream was
popped from the pool and assigned to a slot (which might never happen if
the client had no outbound traffic for that JID).

Fix: start _startRecvLoop immediately in _startServerStreamAcceptLoop for
every accepted stream (both send+recv pairs and recv-only streams). The
send stream is still pooled for outbound reuse as before.

Correspondingly, remove the now-redundant _startRecvLoop call in the
pool-reuse path of _openAuxStream — the loop is already running, starting
a second one would process each inbound chunk twice.

Outbound streams opened via connectionOpenBi already started their recv
loop immediately (line 901) — that path was correct and is unchanged.

Testing: all 249 flutter tests pass; all 82 xmpp_stone dart tests pass.
No new tests added — the fix is structural (ordering of side-effects in
the accept loop) and the existing quic_stream_routing_test.dart pool
tests continue to pass.

Co-authored-by: Junie <junie@jetbrains.com>
…red ref)

Previously every connection_* FFI function (connection_open_bi,
connection_stats, connection_close_reason, connection_rtt_millis, etc.)
took QuicConnection by value via flutter_rust_bridge's Auto_Owned
ownership-transfer mechanism. This meant only one such call could be
in-flight at a time: a second concurrent caller would find the RustOpaque
cell already in the 'moved' state and throw DroppableDisposedException.
Under high latency / low bandwidth (where connection_open_bi blocks
waiting for MAX_STREAMS credits) this race window was wide enough to
trigger reliably.

Quinn's Connection is Arc-based internally and every method only needs
&self, so the Auto_Owned restriction was purely a wrapper artefact.

This commit applies the fix already proven for connection_accept_bi to
all remaining connection_* functions:

Rust (bridge.rs):
- connection_open_bi, connection_open_uni: &QuicConnection, return
  (SendStream, RecvStream) without the connection in the tuple.
- connection_send_datagram, connection_send_datagram_wait: &QuicConnection,
  return Result<()> (no connection in tuple).
- connection_read_datagram: &QuicConnection, return Option<Vec<u8>>.
- connection_datagram_send_buffer_space, connection_max_datagram_size,
  connection_remote_address, connection_local_ip, connection_rtt_millis,
  connection_stable_id, connection_close_reason, connection_stats,
  connection_peer_transport_params: all &QuicConnection, return just
  the value (no connection tuple).
- endpoint_connect and send/recv stream functions are unchanged.
- FRB bindings regenerated (frb_generated.rs, frb_generated.dart,
  bridge.dart).

Dart (quic_xmpp_socket.dart):
- Removed _auxOpenLock field and the entire completer/chain pattern in
  _openAuxStream. Multiple concurrent connectionOpenBi calls are now
  safe; per-slot coalescing via _auxStreamOpening is retained to avoid
  duplicate opens for the same JID hash.
- Removed 'Re-read _connection after stats call' dance in _openAuxStream
  and _logConnectionStats: stats no longer consumes the arc.
- getQuicStats, _logConnectionStats, _logPeerTransportParams,
  _logQuicCloseReason: all simplified to use the direct return value
  instead of destructuring a (connection, value) tuple.
- _connectOneCandidateQuic: connectionOpenBi result is now
  (sendStream, recvStream); connection comes from endpointConnect result.
- Stale comments referencing Auto_Owned and _auxOpenLock removed.

Testing:
- cargo build: clean (no errors, no new warnings).
- flutter test: 253 tests pass (+4 new compile-time guards in
  quic_stream_routing_test.dart verifying connectionOpenBi,
  connectionStats, connectionCloseReason, connectionRttMillis are
  exported as Functions from the shared-ref bridge).
- dart test (vendor/xmpp_stone): 82 tests pass.

Co-authored-by: Junie <junie@jetbrains.com>
…ion errors

- Remove unnecessary null check on IqStanza response in xmpp_service.dart
  (response handler callback type is non-nullable, so the null check was
  always false and the body was dead code)
- Rename underscore-prefixed local functions in unified_mam_catchup_test.dart
  to satisfy the no_leading_underscores_for_local_identifiers lint rule
- Add 30 missing record codec implementations to
  vendor/flutter_quic/lib/src/rust/frb_generated.dart:
  - 10 dco_decode_record_*_quic_connection_* methods
  - 10 sse_decode_record_*_quic_connection_* methods
  - 10 sse_encode_record_*_quic_connection_* methods
  These were present as abstract declarations in frb_generated.io.dart
  but their concrete implementations were missing from frb_generated.dart,
  causing compilation failures in tests that import flutter_quic.

Tested: flutter analyze (no issues), flutter test (253/253 passed)
Co-authored-by: Junie <junie@jetbrains.com>
sentry_flutter: 9.14.0 → 9.20.0
sentry: 9.14.0 → 9.20.0
sentry_dart_plugin: 3.2.1 → 3.3.0

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Also pulls in connectivity_plus_platform_interface 2.0.1 → 2.1.0.

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Also pulls in flutter_secure_storage_darwin 0.2.0 → 0.3.0 and
flutter_secure_storage_web 2.1.0 → 2.1.1.

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
async 2.13.0 → 2.13.1
hooks 1.0.2 → 1.0.3
synchronized 3.4.0 → 3.4.0+1
vm_service 15.0.2 → 15.2.0

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
dart_webrtc 1.8.0 → 1.8.1
flutter_plugin_android_lifecycle 2.0.33 → 2.0.34
image_picker_android 0.8.13+14 → 0.8.13+17
path_provider_android 2.2.22 → 2.2.23
shared_preferences_android 2.4.21 → 2.4.23
url_launcher_android 6.3.28 → 6.3.29
url_launcher_web 2.4.2 → 2.4.3

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
…interface 2.4.1 → 2.4.2

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
file_picker 11 made FilePicker an abstract final class with static
methods, removing the .platform accessor. Updated all 3 call sites in
lib/main.dart from FilePicker.platform.pickFiles(...) to
FilePicker.pickFiles(...).

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
The -Wno-error=deprecated-literal-operator flag added in linux/CMakeLists.txt
is Clang-only. GCC does not recognise -Wdeprecated-literal-operator at all
and therefore rejects the -Wno-error= form with a hard error:

  cc1: error: '-Wno-error=deprecated-literal-operator':
       no option '-Wdeprecated-literal-operator'

This caused the CI Linux build to fail. Fix by wrapping the flag in a
CMAKE_CXX_COMPILER_ID Clang guard so it is only applied when building
with Clang (e.g. macOS), not with GCC (Linux CI).

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
connectivity_plus 7.1.1 references NWPath.isUltraConstrained behind an
#available(macOS 26.0, *) guard, but Xcode 16.4 ships with the macOS 15.5
SDK which does not define that symbol at all. The Swift compiler rejects
the reference even with the availability guard in place, causing the CI
macOS build to fail with:

  error: value of type 'NWPath' has no member 'isUltraConstrained'

Pinning to 7.0.0 (the previous release) avoids the broken code until
upstream ships a fix.

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
The flutter_webrtc plugin's libwebrtc headers trigger
-Wno-error=deprecated-literal-operator, which GCC rejects because it
does not recognise -Wdeprecated-literal-operator at all.  Clang handles
the flag correctly.

clang/clang++ are already installed by the 'Install Linux build deps'
step; we just need to tell CMake to use them by setting CC=clang and
CXX=clang++ on the 'Build Linux' step.  This makes the existing
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") guard in linux/CMakeLists.txt
effective.

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
… dep

Updated vulnerable dependencies to patched versions:
- rustls-webpki: 0.103.4/0.103.9/0.103.10 → 0.103.13
  (fixes GHSA-82j2-j2ch-gfr8, GHSA-965h-392x-2mh5, GHSA-xgp8-3hg3-c2mh,
   GHSA-pwjx-qhcg-rvj4)
- aws-lc-sys: 0.30.0/0.38.0 → 0.40.0
  (fixes GHSA-65p9-r9h6-22vj, GHSA-9f94-5g5w-gf6r, GHSA-hfpc-8r3f-gw53,
   GHSA-vw5v-4f2q-w9xf, GHSA-394x-vwmw-crm3)
- aws-lc-fips-sys: 0.13.7/0.13.12 → 0.13.14
  (fixes GHSA-65p9-r9h6-22vj, GHSA-9f94-5g5w-gf6r)
- rand: 0.9.2 → 0.9.4 (fixes GHSA-cq8v-f236-94qc)
- bytes: 1.10.1 → 1.11.1 (fixes GHSA-434x-w66g-qw3r)
- time: 0.3.41 → 0.3.47 (fixes GHSA-r6v5-fh4h-64xc)
- tracing-subscriber: 0.3.19 → 0.3.23 (fixes GHSA-xwfj-jgwm-7wp5)
- quinn-proto: 0.11.13 → 0.11.14 (fixes GHSA-6xvm-j4wr-6v98)
- cargokit github dart dep: 9.17.0 → 9.25.0 (fixes CVE-2012-2055)

Added acceptance for CVE-2022-3095-Flutter: Flutter 1.0.0 appears only in
vendor/flutter_quic/example/ios/Podfile.lock (example app, not shipped).

Tested: flutter analyze (no issues), flutter test (253/253 passed),
dart test in vendor/xmpp_stone (82/82 passed).

Co-authored-by: Junie <junie@jetbrains.com>
Updated vulnerable crates in vendor/flutter_quic/rust/vendor/quinn-proto/Cargo.lock:
- aws-lc-fips-sys 0.13.12 → 0.13.14 (fixes GHSA-9f94-5g5w-gf6r)
- aws-lc-sys 0.38.0 → 0.40.0 (fixes GHSA-394x-vwmw-crm3, GHSA-9f94-5g5w-gf6r)
- rustls-webpki 0.103.9 → 0.103.13 (fixes GHSA-82j2-j2ch-gfr8, GHSA-pwjx-qhcg-rvj4, GHSA-965h-392x-2mh5, GHSA-xgp8-3hg3-c2mh)
- rand 0.9.2 → 0.9.4 (fixes GHSA-cq8v-f236-94qc)
- tracing-subscriber 0.3.22 → 0.3.23

Tested: flutter analyze (no issues), flutter test (253/253 passed), dart test in vendor/xmpp_stone (82/82 passed).
Co-authored-by: Junie <junie@jetbrains.com>
CVE-2012-2055 is a 2012 CVE for the GitHub web service, not the Dart
'github' pub package. The scanner incorrectly matches by package name.
We are already on the latest available version (9.25.0).

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
…d verbosity

The -Wno-error=deprecated-literal-operator flag was added previously to suppress
a warning from third-party headers, but Flutter's build system already hardcodes
CC=clang/CXX=clang++ when invoking CMake on Linux (in build_linux.dart), so the
flag is never needed for GCC. Despite the Clang guard, the flag was still causing
cc1 errors in CI, so it has been removed entirely.

Also added a 'Show compiler versions' step and -v flag to flutter build linux in
CI to provide more diagnostic information if build failures recur.

Tested: flutter analyze (no issues), flutter test (253/253 passed).
Co-authored-by: Junie <junie@jetbrains.com>
@dwd dwd marked this pull request as ready for review May 9, 2026 16:22
Copilot AI review requested due to automatic review settings May 9, 2026 16:22
Copy link
Copy Markdown

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.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@dwd dwd merged commit 3c97fb7 into main May 9, 2026
31 checks passed
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