fix: encode halt/resume via official SecurityStatus_3 semantics - #588
Closed
pedrosakuma wants to merge 2 commits into
Closed
fix: encode halt/resume via official SecurityStatus_3 semantics#588pedrosakuma wants to merge 2 commits into
pedrosakuma wants to merge 2 commits into
Conversation
Halt/resume UMDF encoding previously used out-of-domain marker values (securityTradingEvent=1/2) that are not defined in the vendored B3 market-data schema. This replaces them with the official semantics: - Halt: securityTradingStatus=FORBIDDEN(18), securityTradingEvent=SECURITY_STATUS_CHANGE(101). - Resume: restored pre-halt securityTradingStatus, securityTradingEvent=SECURITY_REJOINS_SECURITY_GROUP_STATUS(102). Also closes the snapshot/recovery gap identified in #583: a late subscriber joining mid-session previously had no way to learn an instrument's current trading status (e.g. FORBIDDEN while halted) from the snapshot channel alone. SnapshotPacketBuilder now always emits a trailing SecurityStatus_3 packet after every snapshot's header/orders packets, using securityTradingEvent=NULL(255) since it's a point-in-time report, not a transition event. ISnapshotBookSource gained GetSecurityTradingStatus(securityId), backed by MatchingEngineSnapshotSource (FORBIDDEN while halted, else the current TradingPhase). Halt state persistence across engine restarts already existed (added in #322 via EngineStateSnapshot.Halts) and required no further changes. Updated all affected wire-encoder and core tests for the new WriteSnapshot/GetPacketCount contract, and added a dedicated HaltedInstrument_TrailingStatusPacket_ReportsForbidden test asserting the FORBIDDEN byte is present on a halted instrument's snapshot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
gpt-5.5 review of PR #588 caught: the new trailing snapshot status packet was passing lastRptSeq as SecurityStatus_3.rptSeq, but the vendored schema explicitly documents this field as "Sequence number per instrument update. (Zeroed in snapshot feed)". Fixed to always write rptSeq=0 in the trailing packet, and added a test asserting this holds even when the header's LastRptSeq is non-null. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pedrosakuma
marked this pull request as ready for review
July 27, 2026 22:36
Owner
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #583
Problem
Halt/resume UMDF encoding used out-of-domain
securityTradingEventmarker values (1/2) not present in the vendored B3 market-data schema (schemas/b3-market-data-messages-2.2.0.xml). Additionally, a late subscriber joining mid-session while an instrument was halted had no way to learn its current trading status from the snapshot channel — only future incrementals carried it.Fix
UmdfFrameBuilder.cs,ChannelDispatcher.Sinks.cs):securityTradingStatus=FORBIDDEN(18),securityTradingEvent=SECURITY_STATUS_CHANGE(101).securityTradingStatus,securityTradingEvent=SECURITY_REJOINS_SECURITY_GROUP_STATUS(102).EngineStateSnapshot.Halts). No changes needed; verified via existing tests.SnapshotPacketBuilder.cs,ISnapshotBookSource.cs,SnapshotRotator.cs): every snapshot now always emits a trailingSecurityStatus_3packet after the header/orders packets, reporting the instrument's current status (FORBIDDENif halted, else currentTradingPhase) withsecurityTradingEvent=NULL(255)since it's a point-in-time report, not a transition event.Testing
WriteSnapshot/GetPacketCountcontract (trailing packet always present).HaltedInstrument_TrailingStatusPacket_ReportsForbidden(SnapshotRotatorTests.cs) — dedicated round-trip test asserting a halted instrument's snapshot trailing packet reportsFORBIDDEN.dotnet format --verify-no-changesclean.No changes to
schemas/or generated SBE bindings — this only fixes usage of already-defined official enum values.