Skip to Content
This documentation is provided with the HEAT environment and describes this HEAT instance.

Interface control document

1. Identification

ItemValue
DocumentICD-CMSONO-001 rev 1
ProductSonoMarc module (Sonomarc Module in the module registry and in the settings section)
Product versions covered8347c3b
PeerSonoMarc Core server, HTTP REST API and Server-Sent Events endpoint
HostHEAT Capture, HEAT.Capture.ModuleSDK 1.0.153
Data modelSimulationFrame carrying one EntityState per discovered seat, plus queued EntityEvents
Date2026-09-02
OwnerVRAI Simulation

2. Scope

This document defines the two interfaces the module holds with a SonoMarc Core server, the REST resources and JSON properties it reads, the event subscription it registers, and the components and events it publishes to HEAT Capture.

The module is read-only with respect to simulation state. It issues no REST call that changes seat, asset or session state. The only writes it performs are the two requests that create and populate its own event subscription.

3. Interface inventory

IDNameDirectionTransportPeer
IF-CMSONO-01Session, seat, asset and platform stateRequest/response, module initiatesHTTP/1.1 REST over TCPSonoMarc Core
IF-CMSONO-02Event subscription and event streamModule registers, service pushesHTTP POST and PUT, then a long-lived text/event-stream GETSonoMarc Core
IF-CMSONO-03Frame publicationModule to hostModule SDK publication pathHEAT Capture

4. IF-CMSONO-01 REST state interface

4.1 Transport and addressing

ItemValue
Base addresshttp://{Host}:{Port}/api/, built in InitialiseModule from the Host and Port settings
SchemePlain HTTP. The scheme is a compile-time literal; TLS cannot be selected through settings.
Per-request timeout10 seconds (HttpClient.Timeout)
Request methodGET only on this interface
Path escapingSession, platform and seat names are escaped with Uri.EscapeDataString in every polling call
Response formatJSON, parsed with System.Text.Json
Client lifetimeOne HttpClient created in InitialiseModule and disposed in EndCapture

4.2 Endpoints

Paths are relative to the base address above.

MethodPathCalledPurpose
GETsessionsRepeatedly during StartCapture until a match is foundFind a session whose state is Running and whose name matches SessionName
GETsessions/{session}/platformsOnce during StartCaptureEnumerate platform names
GETsessions/{session}/platforms/{platform}/seatsOnce per platform during StartCaptureEnumerate seats and their bindings
GETsessions/{session}/platforms/{platform}/seats/{seat}Once per seat, on the initial refresh and on every capture cycleSeat state: malfunctions, SIP and call state, push-to-talk, squelch
GETsessions/{session}/platforms/{platform}/seats/{seat}/assetsOnce per seat, on the initial refresh and on every capture cycleRadio, intercom and relay asset state
GETsessions/{session}/platforms/{platform}Once per seat, on the initial refresh and on every capture cycle, best effortPlatform callsign and geographic position source

The platform request is issued once per seat rather than once per platform, so in WholeSession mode the same platform resource is fetched as many times per cycle as it has seats.

4.3 Connection lifecycle

InitialiseModule only constructs the HTTP client; it performs no request and cannot fail on an unreachable server.

StartCapture runs four steps in order: poll sessions until a running session is found, discover platforms and seats, perform one full snapshot refresh so asset names are known, then register the event subscription described in section 5. It returns false only when the session poll ends without a session, which happens only on cancellation. Zero discovered seats is a warning, not a failure: the module starts and publishes frames that contain no entities.

StartCapture is bounded by the SDK StartupTimeout, which this module does not override, so the whole of that sequence must complete within 5 seconds. SessionPollRetryMs defaults to 5000, so if the first sessions response contains no matching running session the retry delay alone exhausts the startup budget and the module does not start. See section 4.7 for the consequence.

Each capture cycle re-polls every known seat. The seat set is fixed at StartCapture: a seat added to the SonoMarc session later is never discovered, and a seat removed continues to be polled and to log a refresh warning every cycle.

EndCapture unhooks the three receiver callbacks, stops the receiver, disposes the HTTP client, and clears the active session, the entity-id map and the seat snapshots.

4.4 Authentication

None. No credential, token, API key or client certificate is sent on any request, and no setting exists to supply one. Any host able to reach Host:Port can read the same resources.

4.5 JSON properties read

Only the properties listed here are read. Everything else in a response is ignored.

GET sessions:

PropertyTypePresenceUse
sessions[].namestringRequired; a missing property throws and the poll retriesCompared against SessionName case-insensitively, or accepted unconditionally when SessionName is blank; retained as the active session name
sessions[].statestringRequiredMust equal Running, compared case-insensitively

GET sessions/{session}/platforms:

PropertyTypePresenceUse
platforms[].namestringRequiredPlatform half of the seat key, and the input to the LinkedEntityComponent parent id

GET sessions/{session}/platforms/{platform}/seats:

PropertyTypePresenceUse
seats[].namestringRequiredSeat half of the seat key
seats[].bindingstringRequiredPerSeat filter only. A seat matches when its binding contains the configured SeatBinding, or the local hostname when that setting is empty. Never published.
seats[].typestringRequiredRetained in the snapshot, never published
seats[].volumeintegerOptional, defaults to 100Retained in the snapshot, never published

GET sessions/{session}/platforms/{platform}/seats/{seat}:

PropertyTypePresenceUse
malfunctions.microphonebooleanOptionalEdge-detected against the previous cycle; a change publishes a FaultEvent
malfunctions.speakerbooleanOptionalSame, as a separate fault type
sip_statestringOptionalRetained in the snapshot, never published
call_statestringOptionalRetained in the snapshot, never published
pttstringOptional, defaults to offRetained in the snapshot, never published
squelchstringOptional; true only when exactly on, compared case-sensitivelyRetained in the snapshot, never published

GET sessions/{session}/platforms/{platform}/seats/{seat}/assets:

PropertyTypePresenceUse
assets[]arrayOptional; an absent array yields zero assets and no warningAsset list
assets[].typestringRequired in practiceFilter and published value. Only radio, intercom and relay are kept; every other asset type is discarded silently.
assets[].namestringOptional, defaults to emptyPublished asset name; also the key the SSE handler uses to look the asset up
assets[].frequencystringOptionalPublished as the transmit frequency, for radio and relay only
assets[].frequency_rxstringOptionalPublished as the receive frequency, for radio and relay only
assets[].frequency_dualstringOptional; true only when it equals on, compared case-insensitivelyPublished as the dual-frequency flag, for radio and relay only
assets[].radio_typestringOptionalPublished as the radio band, for radio and relay only
assets[].secure.enabledbooleanOptionalPublished as the secure flag, for radio and relay only
assets[].volumeintegerOptional, defaults to 100Published volume, for every retained asset type
assets[].squelch.levelintegerOptional, defaults to 0Published squelch level, for radio and relay only

An intercom asset therefore publishes only its name, type and volume. Its frequency, band, secure and squelch fields are published as empty strings, false and 0 regardless of what the service reports for them, because the parser gates those reads on the asset being radio or relay.

GET sessions/{session}/platforms/{platform}:

PropertyTypePresenceUse
callsignstringOptional, defaults to emptyParsed into the platform snapshot, never published
postition_sourceobjectOptional; absence returns no position at allGate for the entire WorldPositionComponent
postition_source.sourcestringOptionalMust be geographic. geocentric is recognised and then rejected without conversion. Any other value, or absence, yields no position.
postition_source.latnumberOptional, defaults to 0Published latitude
postition_source.longnumberOptional, defaults to 0Published longitude
postition_source.altnumberOptional, defaults to 0Published altitude

The parser reads the property spelled postition_source while the comment immediately above it names position_source. If the service does not send that exact misspelling, the lookup fails, no position snapshot is produced, and the seat entity is published with no WorldPositionComponent: valid position data is silently omitted with no log line. This is audit finding SONO-01. Which spelling the service actually sends is not determinable from this module’s source and has not been confirmed against a live SonoMarc payload, so the defect is the divergence between the code and its own comment rather than a proven mismatch with the service.

4.6 Timing and cadence

ItemValue
Poll cadenceThe SDK Interval, default 1000 ms, re-read every cycle
Requests per cycleThree sequential GETs per known seat, awaited one after another; no concurrency and no batching
Effective cadencePoll duration plus Interval, because the SDK delays Interval after HandleCapture returns rather than on a fixed schedule
HandleCapture timeoutNone. A slow or hanging server stretches the cycle up to the 10-second per-request timeout multiplied by the number of outstanding requests.
Fault edge detectionComputed between consecutive polls only. A microphone or speaker fault that both starts and clears inside one cycle produces no event.
Session poll cadenceSessionPollRetryMs, default 5000 ms, inside StartCapture

4.7 Error behaviour

ConditionBehaviourLog
sessions request fails, or the response is missing sessions, name or stateRetry after SessionPollRetryMs, indefinitelyWarning beginning Sonomarc: session poll error, with the exception message
No session matches the name and state criteriaRetry after SessionPollRetryMs, indefinitelyDebug message containing Sonomarc: no running session yet and {Delay}ms
Session poll loop ends without a session, which requires cancellationStartCapture returns false and the module does not startError beginning Sonomarc Module: no running session found
StartCapture exceeds the 5-second StartupTimeoutThe SDK stops waiting and the module does not start. It does not cancel the operation: the abandoned StartCapture continues in the background, so the session poll keeps running, the subscription is eventually registered, and the event stream begins queueing events that no capture loop ever drains.SDK warning, "{Module} StartCapture timed out after {Timeout}. Module did not start."
Any failure during platform or seat discovery, including one malformed seat entryDiscovery aborts for that call and every remaining platform and seat. StartCapture continues with whatever was collected.Error beginning Sonomarc: seat discovery failed, with the exception message
No seat matches the capture-mode criteriaThe module starts and publishes frames containing no entitiesWarning, "Sonomarc Module: no seats found matching capture mode criteria"
Seat or asset request fails during a refreshThat seat retains its previous snapshot for the cycle and is still published with stale values. Other seats continue.Warning beginning Sonomarc: failed to refresh seat, with {Key} and the exception message
Platform request fails, or the platform JSON cannot be parsedSwallowed by an empty catch. The callsign and position snapshots become null for that cycle, so WorldPositionComponent disappears from the entity without any indication.None
HandleCapture throwsThe SDK logs it and the capture loop continuesSDK, "Error in module"

A stale snapshot and a fresh one are indistinguishable in the published frame: the module carries no per-seat freshness or validity flag, and the frame capture time is always the current host clock.

5. IF-CMSONO-02 Server-Sent Events interface

5.1 Transport and addressing

ItemValue
Base addresshttp://{Host}:{Port}/api, passed to the receiver separately from the REST client and trimmed of a trailing slash
ClientA second HttpClient with an infinite timeout, because the stream is long-lived
RegisterPOST {base}/events/subscriptions
PopulatePUT {base}/events/subscriptions/:{id}
StreamGET {base}/events/stream/:{id} with Accept: text/event-stream, read with ResponseHeadersRead so the body streams

The colon before the subscription id in the PUT and GET paths is a literal character in the URL the module builds, not placeholder notation. Whether the SonoMarc API expects that leading colon is a service property that cannot be established from this module’s source; the vendor’s own API documentation is the authority.

5.2 Subscription registration

The POST sends an empty body with no content type and expects a JSON object with a string id property. A non-success status, a missing id, or an empty id aborts registration.

The PUT sends a flat JSON object mapping each subscribed event path to the string "enable". The paths are built from the seats and assets discovered at start:

  • one seat base path, sessions/{session}/platforms/{platform}/seats/{seat}
  • one path per discovered asset, sessions/{session}/platforms/{platform}/seats/{seat}/assets/{asset}

Unlike the polling calls, these path segments are inserted unescaped, so a session, platform, seat or asset name containing a slash produces a malformed subscription path and a seat key that cannot be resolved back.

5.3 Subscription set actually enabled

For every supplied path the registration code enables {path}/rx_activity and {path}/tx_activity. It enables selected, secure, squelch and ptt only inside a branch guarded by the path ending in /assets. The path builder never produces a path ending in /assets: it produces the seat base and fully qualified .../assets/{asset} paths. That branch is therefore unreachable in this revision, and the subscription set is exactly:

Enabled event pathPer
sessions/{session}/platforms/{platform}/seats/{seat}/rx_activitySeat
sessions/{session}/platforms/{platform}/seats/{seat}/tx_activitySeat
sessions/{session}/platforms/{platform}/seats/{seat}/assets/{asset}/rx_activityAsset
sessions/{session}/platforms/{platform}/seats/{seat}/assets/{asset}/tx_activityAsset

Push-to-talk, asset selection, secure toggling and squelch are never subscribed, so the dispatcher and mapping table entries for them are only reachable if the service pushes events that were not requested. The registration log line reports the enabled count and can be used to check this: it is twice the number of seats plus assets.

Assets discovered after StartCapture receive no subscription, because the set is registered once and never revised.

5.4 Connection lifecycle and reconnect

StartAsync registers the subscription and then runs the stream loop on a background task. If registration fails, StartAsync returns without starting the loop and never retries: the capture session runs to completion with no events at all, while REST polling continues normally.

Once the loop is running, an ended stream or any exception other than cancellation is logged as a warning and retried after SseReconnectDelayMs, default 3000 ms, indefinitely. Reconnection reuses the subscription id from the original registration and does not re-register or re-PUT the path map. Whether the service retains a subscription across a dropped stream is a service property that cannot be established from this module’s source; if it does not, reconnection produces a stream that delivers nothing.

StopAsync cancels the loop, awaits the stream task, and disposes the streaming client.

5.5 Authentication

None, on all three requests. There is no setting for a credential on this interface either.

5.6 Wire format

The reader handles two SSE fields and dispatches on a blank line:

Line prefixHandling
event:Trimmed remainder is taken as the event path, matched case-insensitively on the prefix
data:Trimmed remainder is taken as the event payload
Blank lineDispatches the block when both an event path and a payload were seen, then clears both
Anything else, including id:, retry: and comment linesIgnored

A data: line assigns rather than appends, so a payload split across multiple data: lines is truncated to its last line. This breaks the SSE convention that multiple data: lines concatenate.

The payload must be a JSON object. Only one property is read from it on activity events:

PropertyTypeUse
valuestringRead as the event value; absent or non-string yields an empty string

On a virtual-platform command event the payload is instead read for virtual_platform.name, and the raw JSON text is forwarded whole.

The event path itself is parsed positionally: the segment after platforms and the segment after seats form the seat key, the last segment is the event type, and the second-to-last segment is taken as the asset name. On a seat-level path such as .../seats/{seat}/rx_activity the second-to-last segment is the seat name, so the asset lookup fails and the published event carries an empty frequency, an empty band, secure false, and a target of {platform}/{seat}/{seat}. Seat-level activity events are subscribed, so this is reachable in normal operation.

5.7 Event mapping

Event path suffixSubscribedTracking eventComms event
rx_activityYesRECEIVED when the value is on; none when it is offYes, voice
tx_activityYesVOICE_TRANSMISSION_STARTED when on, VOICE_TRANSMISSION_ENDED when offYes, voice
pttNoVOICE_TRANSMISSION_ENDED for off, VOICE_TRANSMISSION_STARTED for every other valueYes, voice
selectedNoINTERCOM_STATE_CHANGED, value ignoredNo
secureNoTRANSMITTER_STATE_CHANGED, both branches identical so the direction is not carriedNo
squelchNoINTERCOM_STATE_CHANGED, value ignoredNo
Any other suffixNoNoneNo
Path containing /virtual_platforms/ and ending /commandNoNoneYes, text-to-speech, plus a JSON event

A value counts as on when it equals on, or when it is neither off nor empty. An empty value counts as off. The push-to-talk value is instead matched literally, and normal, priority and emergency all map to the same started event, so the priority level is lost and is not carried into the comms event either. Receive ending produces nothing at all, so a reception has a start with no end.

Values arriving on selected never reach the published data: the selected flag on the radio component is hard-coded false in the parser, and no SSE handler writes back into the snapshot.

5.8 Error behaviour

ConditionBehaviourLog
POST /events/subscriptions returns a non-success statusRegistration aborts, stream never startsError, "SonomarcSseReceiver: POST /events/subscriptions returned {Code}"
Response carries no id, or an empty oneRegistration abortsError, "SonomarcSseReceiver: subscription POST returned no id"
PUT returns a non-success statusRegistration abortsError, "SonomarcSseReceiver: PUT subscription set returned {Code}"
Any exception during registrationRegistration abortsError beginning SonomarcSseReceiver: subscription registration error, with the exception message
Registration returned nothingStream loop is never started and never retriedError, "SonomarcSseReceiver: failed to register event subscription"
Stream ends or throwsReconnect after SseReconnectDelayMs, indefinitely, reusing the same subscription idWarning beginning SonomarcSseReceiver: stream disconnected, with the exception message
Event payload is not valid JSON, or dispatch throwsEvent droppedDebug message beginning SonomarcSseReceiver: failed to dispatch event, with {Path} and the exception message
Event path has no platforms or seats segmentEvent dropped with no logNone

6. IF-CMSONO-03 Frame publication and data model reference

6.1 Entity model

ItemValue
FrameOne SimulationFrame per capture cycle, with a capture time in UTC Unix milliseconds taken when the frame is built
EntitiesOne EntityState per known seat, published every cycle whether or not anything changed
Entity name{platform}/{seat}
Entity idGetHashCode of the seat key under OrdinalIgnoreCase, masked to 63 bits
Platform entityNever published. The parent id on each seat points at a hash of the platform name for which no EntityState exists.

The entity id is derived from the .NET string hash, which is seeded randomly per process. Ids are consistent within one run of HEAT Capture and change between runs for the same seat name, so they cannot be used to correlate entities across sessions. The parent id on the linked-entity component is computed the same way and stays consistent with the seat ids inside a single run.

6.2 Published components and fields

WorldPositionComponent, published only when a geographic position was resolved for the platform:

FieldSourceValue
latitudepostition_source.latDecimal degrees, read as a double and narrowed to float
longitudepostition_source.longDecimal degrees, same narrowing
altitudepostition_source.altPassed through unconverted
headingNoneAlways 0. No heading property is read from the service.

LinkedEntityComponent, published on every seat entity unconditionally:

FieldSourceValue
parent_entity_idPlatform nameMasked hash of the platform name

RadioComponent, one per retained asset:

FieldSource
asset_nameassets[].name
asset_typeassets[].type
frequency_txassets[].frequency, radio and relay only
frequency_rxassets[].frequency_rx, radio and relay only
frequency_dualassets[].frequency_dual equal to on, radio and relay only
radio_bandassets[].radio_type, radio and relay only
secure_enabledassets[].secure.enabled, radio and relay only
selectedNothing. Always false.
volumeassets[].volume
squelch_levelassets[].squelch.level, radio and relay only

6.3 Events published

Events are enqueued when they occur and drained into the next frame, so an event can be published up to one full cycle after it happened. Each event carries its own timestamp taken at the moment it was enqueued, which is the SSE arrival time or the poll at which a fault edge was detected, not the frame capture time.

TriggerPublished
Subscribed rx_activity, tx_activity, or an unsubscribed ptt eventA voice comms event carrying the asset’s current transmit frequency, band and secure flag from the last poll, and a target of {platform}/{seat}/{asset}
The same events, plus selected, secure and squelch where the mapping yields oneA tracking event of the mapped type
A microphone or speaker malfunction changing between two pollsA fault event with a type of microphone or speaker, activated or resolved
A virtual-platform command eventTwo events at once: a text-to-speech comms event whose target is the virtual person’s name and whose content is the raw command JSON, and a JSON event named sonomarc_voice_command carrying the same JSON

Comms and tracking events reference the seat entity id. Virtual-platform command events instead reference a hash of the platform name taken from the event path, which is not a published entity.

6.4 Polled but not published

The following are read from the service and retained in the module’s snapshot on every cycle, and then never reach a published field: the seat type, the seat binding, the seat-level volume, the SIP state, the call state, the seat-level push-to-talk value, the seat-level squelch state, and the platform callsign.

7. Units and conventions

ConceptConvention
FrequenciesOpaque display strings, passed through with no parsing, normalisation or validation. RadioComponent documents the shape as "243.000 MHz"; the module does not enforce it.
Radio bandString from the service’s radio_type. RadioComponent documents HF, VHF, UHF and UHF SATCOM; the module does not validate against that set.
VolumeInteger passed through. RadioComponent documents a 0 to 100 range; the module does not range check, and an absent property publishes 100.
Squelch levelInteger passed through. RadioComponent documents 0 as off and 1 to 100 otherwise. An absent property publishes 0, which is indistinguishable from a reported 0.
Latitude and longitudeDecimal degrees, positive north and east, per WorldPositionComponent. Read as JSON doubles and narrowed to float32, which quantises to roughly 0.3 to 1 metre.
AltitudeMetres per WorldPositionComponent. The module applies no conversion, so the published value is whatever unit the service reports.
Coordinate frameThe module neither declares nor checks a datum, and the component does not carry one. It relies on the service reporting geographic coordinates already in decimal degrees.
HeadingDegrees per WorldPositionComponent, but always published as 0 by this module.
Time baseHost wall clock, UTC Unix milliseconds. No service-supplied timestamp is read or carried on any frame or event.
Boolean stringsThe service’s on and off strings. The asset dual-frequency flag is compared case-insensitively; the seat squelch state is compared case-sensitively.

8. Configuration affecting the interfaces

SettingDefaultInterface effect
HostlocalhostREST and SSE host for both clients
Port80REST and SSE port for both clients
SessionNameemptySession filter. Empty accepts the first session found in the Running state, in whatever order the service returns them.
SessionPollRetryMs5000Session poll retry delay inside StartCapture. At the default it equals the whole 5-second startup budget.
CaptureModeWholeSessionWholeSession polls and subscribes to every seat on every platform. PerSeat restricts both to seats whose binding matches.
SeatBindingempty, meaning the local hostnameThe PerSeat match value. The match is a substring test, so a short binding value can select more than one seat.
SseReconnectDelayMs3000Delay between stream reconnection attempts. Does not affect subscription registration, which is never retried.
Interval1000 msREST poll cadence, fault edge-detection resolution, and the maximum queueing delay for an event
EnabledtrueWhether the module runs at all

The scheme, the 10-second REST request timeout, the infinite SSE timeout, and the 5-second startup budget are not configurable. See Manage capture modules for the generic settings and the Module SDK ICD for the lifecycle contract they belong to.

9. Compatibility and versioning

There is no version negotiation on either interface. The module assumes the resource paths, JSON property names and event-path grammar documented above. It is tolerant of missing optional properties and substitutes defaults for them, which means a renamed property degrades silently rather than failing: a renamed asset frequency publishes an empty string, a renamed volume publishes 100, and a renamed position source publishes no position component. The properties read with a required accessor are the session name and state, the platform name, and the seat name, binding and type; renaming one of those produces a logged failure instead.

The event grammar is parsed positionally on the segments named platforms and seats, so a change to the service’s path structure silently redirects or drops events rather than raising an error.

10. Security considerations

Both interfaces are unauthenticated plain HTTP with no setting to change either property, so credentials, tokens and TLS cannot be introduced through configuration. Any host with network access to the SonoMarc API can read the same session, seat and asset state, register its own event subscription, and observe the same event stream. Traffic is readable and modifiable in transit by anything on the path.

Captured data includes radio frequencies, band assignments, secure-mode flags and platform positions, and the recognised text of virtual-person voice commands is carried verbatim in the published event content. Restrict the SonoMarc service to an isolated network segment and treat captured sessions according to the deployment’s own classification of that material.

11. Conformance

  1. With a SonoMarc session in the Running state, start a capture session. Confirm the log records the starting mode and host, the selected session name, the discovered seat count, and the registered subscription id and path count.
  2. Confirm the frame carries one entity per expected seat, named {platform}/{seat}, and that the radio components match the assets on those seats.
  3. Confirm the registered path count equals twice the number of seats plus assets. Exercise push-to-talk, asset selection, secure toggling and squelch on the service and confirm that none of them produces an event, which is the observable consequence of the unreachable expansion branch in section 5.3.
  4. Exercise transmit and receive and confirm the paired comms and tracking events appear. Confirm a reception produces a start with no matching end.
  5. Capture the raw response of GET sessions/{session}/platforms/{platform} and inspect the spelling of the position source property. If it is not postition_source, no seat entity carries a position component, which is SONO-01. Record the observed spelling so the finding can be closed either way.
  6. Where a position component is published, confirm the heading is 0 and that latitude, longitude and altitude match the service’s reported values without conversion.
  7. Confirm the selected flag is false on every radio component even while an asset is selected on the service.
  8. Restart HEAT Capture without changing the SonoMarc configuration and confirm the seat entity ids differ from the previous run, so that no downstream analysis keys on them across sessions.
  9. Stop the SonoMarc service before starting capture. Confirm the SDK startup timeout warning and that no frames are published, then confirm whether the process continues to issue session polls, which is the abandoned startup operation described in section 4.7.
  10. With capture running, interrupt the network to the service. Confirm the refresh warnings, the stream disconnect warning, and whether events resume after reconnection without a capture restart. This is the test that determines whether the service retains a subscription across a dropped stream.

12. Revision history

RevDateProduct versionChange
12026-09-028347c3bInitial issue.
Opens your browser's print dialog. Choose "Save as PDF" as the destination.