Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

Stateful B3 exchange simulator. Inbound: B3 EntryPoint SBE over TCP. Outbound:
B3 UMDF wire format over UDP multicast, plus SBE ExecutionReports back to the
TCP client. Companion to the external `SbeB3UmdfConsumer` repo.
TCP client. Companion to the external `B3MarketDataPlatform` (UMDF
consumer) and `B3EntryPointClient` (EntryPoint client) repos.

## Toolchain

Expand Down Expand Up @@ -70,7 +71,8 @@ Layered projects under `src/` (build order roughly bottom-up):
1. `B3.EntryPoint.Sbe` / `B3.Umdf.Sbe` — generated SBE bindings from
`schemas/b3-entrypoint-messages-8.4.2.xml` and
`schemas/b3-market-data-messages-2.2.0.xml`. Vendored copies; keep in sync
with `SbeB3UmdfConsumer` when upgrading.
with `B3EntryPointClient` and `B3MarketDataPlatform` respectively when
upgrading.
2. `B3.Umdf.WireEncoder` — stateless byte-level encoders for UMDF MBO / Trade /
Snapshot frames (V16 schema).
3. `B3.Exchange.Instruments` — JSON instrument loader.
Expand Down Expand Up @@ -115,7 +117,7 @@ Layered projects under `src/` (build order roughly bottom-up):
per-session firm assignment is not implemented.
- **Schemas are vendored.** Do not hand-edit files under `schemas/`; regenerate
the SBE bindings in `B3.*.Sbe` when upgrading and mirror the change in
`SbeB3UmdfConsumer`.
`B3MarketDataPlatform` (UMDF) / `B3EntryPointClient` (EntryPoint).

## Configuration

Expand Down
32 changes: 22 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,20 @@ jobs:
echo "$changed"
fi

# Best-effort cross-check against the companion SbeB3UmdfConsumer
# repo, which vendors the same UMDF market-data schema and is kept
# in lock-step per README.md/CONTRIBUTING.md. Network/availability
# issues here only warn (they must not make an unrelated outage
# block every PR); an entrypoint-only file that isn't vendored
# there also just warns. An actual content mismatch on a shared
# file is treated the same as a local edit.
# Best-effort cross-check against the companion repo that vendors
# the same schema file, kept in lock-step per README.md/
# CONTRIBUTING.md: b3-market-data-messages-*.xml against
# B3MarketDataPlatform, b3-entrypoint-messages-*.xml against
# B3EntryPointClient. Network/availability issues here only warn
# (they must not make an unrelated outage block every PR); a
# file with no known companion also just warns. An actual
# content mismatch on a shared file is treated the same as a
# local edit.
# Scoped to files this PR actually touched under schemas/ — PRs
# that don't touch schemas/ must not be blocked by pre-existing
# drift between the two repos that predates this PR. Iterated
# line-by-line (not word-split) so filenames with spaces survive.
# line-by-line (not word-split) so filenames with spaces
# survive.
#
# NOTE: because this only runs for files already in $changed, it
# can never independently flip flagged from 0 to 1 — flagged is
Expand All @@ -72,12 +75,21 @@ jobs:
continue
fi
name="$(basename "$f")"
url="https://raw.githubusercontent.com/pedrosakuma/SbeB3UmdfConsumer/main/schemas/$name"
case "$name" in
b3-market-data-messages-*.xml) companion_repo="B3MarketDataPlatform" ;;
b3-entrypoint-messages-*.xml) companion_repo="B3EntryPointClient" ;;
*) companion_repo="" ;;
esac
if [ -z "$companion_repo" ]; then
echo "::warning::No known companion repo for $name; skipping cross-repo check."
continue
fi
url="https://raw.githubusercontent.com/pedrosakuma/$companion_repo/main/schemas/$name"
if remote_sha="$(curl -fsSL --connect-timeout 5 --max-time 15 "$url" 2>/dev/null | sha256sum | awk '{print $1}')"; then
local_sha="$(sha256sum "$f" | awk '{print $1}')"
if [ "$remote_sha" != "$local_sha" ]; then
flagged=1
echo "$f (sha256 $local_sha) diverges from SbeB3UmdfConsumer's vendored copy (sha256 $remote_sha)."
echo "$f (sha256 $local_sha) diverges from $companion_repo's vendored copy (sha256 $remote_sha)."
fi
else
echo "::warning::Could not fetch $url to cross-check vendored schema fidelity; skipping cross-repo check for $name."
Expand Down
2 changes: 1 addition & 1 deletion .vscode/mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"servers": {
"github": {
"type": "copilot",
"description": "GitHub MCP — repos, issues, PRs, Actions, code search (companion repo SbeB3UmdfConsumer)"
"description": "GitHub MCP — repos, issues, PRs, Actions, code search (companion repos B3MarketDataPlatform, B3EntryPointClient)"
},
"filesystem": {
"command": "npx",
Expand Down
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,6 @@ Both must pass before merge.

Do not hand-edit files under `schemas/`. When upgrading B3 EntryPoint
or UMDF, regenerate the SBE bindings in `B3.*.Sbe` and mirror the
change in the companion `SbeB3UmdfConsumer` repo. The two repos must
agree on the schema version.
change in the companion repo (`B3MarketDataPlatform` for UMDF,
`B3EntryPointClient` for EntryPoint). The repos must agree on the
schema version.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ EntryPoint TCP listener (default port 9876).

`schemas/b3-market-data-messages-2.2.0.xml` and
`schemas/b3-entrypoint-messages-8.4.2.xml` are vendored copies of the
official B3 SBE schemas. The same files exist in `SbeB3UmdfConsumer`; keep
official B3 SBE schemas. The same files exist in `B3MarketDataPlatform`
(market-data schema) and `B3EntryPointClient` (entrypoint schema); keep
them in sync when upgrading.

### Inbound EntryPoint compatibility matrix
Expand Down
6 changes: 3 additions & 3 deletions docs/B3-ENTRYPOINT-ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,7 @@ Three test surfaces, mirroring the component split.
client speaking SBE + SOFH against it.
- Scenarios: full session lifecycle, gap recovery, CoD trigger, daily
reset mid-session, throttle reject.
- Use `SbeB3UmdfConsumer` style decoder to verify multicast output.
- Use a `B3MarketDataPlatform` style decoder to verify multicast output.

---

Expand Down Expand Up @@ -806,7 +806,7 @@ is on so they are inspectable).

**EntryPoint and UMDF version independently.** Each schema is bumped on
its own cadence; you do not need to upgrade both at once. The companion
[`SbeB3UmdfConsumer`](https://github.com/pedrosakuma/SbeB3UmdfConsumer)
[`B3MarketDataPlatform`](https://github.com/pedrosakuma/B3MarketDataPlatform)
repo vendors the same UMDF schema and must be kept in lock-step when the
UMDF version moves.

Expand Down Expand Up @@ -843,7 +843,7 @@ UMDF version moves.
the version we target and per-template gap status; bump the version
and audit any newly added or removed templates.
8. **Mirror UMDF changes** in
[`SbeB3UmdfConsumer`](https://github.com/pedrosakuma/SbeB3UmdfConsumer)
[`B3MarketDataPlatform`](https://github.com/pedrosakuma/B3MarketDataPlatform)
when bumping the market-data schema; the consumer is what proves the
wire is end-to-end correct.

Expand Down
2 changes: 1 addition & 1 deletion docs/EXCHANGE-SIMULATOR.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ TCP client ──► EntryPointSession ──► HostRouter ──► ChannelDis

```bash
# 1. Build
dotnet build SbeB3UmdfConsumer.slnx
dotnet build SbeB3Exchange.slnx

# 2. Run with the sample config
dotnet run --project src/B3.Exchange.Host -- config/exchange-simulator.json
Expand Down
2 changes: 1 addition & 1 deletion docs/RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ umdf_chaos_duplicated_total{channel="1"} <n>
umdf_chaos_reordered_total{channel="1"} <n>
```

Recovery scenario (companion `SbeB3UmdfConsumer`):
Recovery scenario (companion `B3MarketDataPlatform`):

1. Start the host with `dropProbability: 0.01` on a channel of interest.
2. Drive load with a synthetic trader.
Expand Down
6 changes: 3 additions & 3 deletions docs/adr/0013-options-channel-topology.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

Real B3 publishes equity options on a UMDF channel distinct from
cash equities and from derivatives. The simulator must reflect that
topology so consumers (e.g. `B3MarketDataPlatform`, the
`SbeB3UmdfConsumer` companion repo) can validate per-group ring
and cross-group fan-in against a shape that matches production.
topology so consumers (e.g. the `B3MarketDataPlatform` companion repo)
can validate per-group ring and cross-group fan-in against a shape
that matches production.

Two designs were considered while drafting RFC 0002:

Expand Down
2 changes: 1 addition & 1 deletion docs/rfc/0002-equity-options-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ as ADRs are written.

## 8. Risks and consequences

- **Schema coupling with `SbeB3UmdfConsumer`.** No schema is
- **Schema coupling with `B3MarketDataPlatform`.** No schema is
modified — only encoder output. Consumers compatible with UMDF
v2.2.0 receive the new fields transparently. **Action:** no-op,
but confirm in the encoder PR that the companion repo's parser
Expand Down
2 changes: 1 addition & 1 deletion src/B3.Exchange.Core/ChaosUdpPacketSinkDecorator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace B3.Exchange.Core;
/// <summary>
/// <see cref="IUmdfPacketSink"/> decorator that injects controlled packet loss,
/// duplication, and reordering into an inner sink. Designed for testing the
/// companion <c>SbeB3UmdfConsumer</c>'s recovery paths (snapshot bootstrap,
/// companion <c>B3MarketDataPlatform</c>'s recovery paths (snapshot bootstrap,
/// gap detection) without external network-shaping tools.
///
/// <para>NOT thread-safe; like the inner sinks it expects to be called from a
Expand Down