diff --git a/docs/B3-ENTRYPOINT-COMPLIANCE.md b/docs/B3-ENTRYPOINT-COMPLIANCE.md
index 392bd09..13fce1e 100644
--- a/docs/B3-ENTRYPOINT-COMPLIANCE.md
+++ b/docs/B3-ENTRYPOINT-COMPLIANCE.md
@@ -171,9 +171,9 @@ contract supervision is a post-trade analytics concern.
| GAP-25 | 7.1.20 | In-flight modification semantics (priority loss rules) | partial | medium | — |
| GAP-26 | 8.3 | Daily GTC/GTD restatement at session boundary (carry-over + re-emit ER) | done | — | At each daily-reset boundary the exchange emits a private restatement `ExecutionReport_Modify` (`OrdStatus=RESTATED 'R'`, `ExecRestatementReason=GT_RESTATEMENT 1`) for every surviving GTC and unexpired-GTD order, plus parked GTC stop / stop-limit orders. The restatement echoes the order's real `OrdType` / `TimeInForce` / `ExpireDate` / `StopPx`, reports new-trading-day quantities (`CumQty=0`, `LeavesQty == OrderQty == open`, iceberg-aware), and changes no book state (no UMDF frame, no `RptSeq` advance, no eviction). Runs after `GtdExpirySweeper` so past-dated GTD orders are cancelled, not restated. ([#498](https://github.com/pedrosakuma/B3MatchingPlatform/issues/498), [#507](https://github.com/pedrosakuma/B3MatchingPlatform/pull/507)) Day-order boundary expiry is tracked separately by [#506](https://github.com/pedrosakuma/B3MatchingPlatform/issues/506). |
| GAP-27 | 15.4 | Self-Trading Prevention (STPC) | missing | medium (in-scope per ADR 0012) | covered by [#14](https://github.com/pedrosakuma/B3MatchingPlatform/issues/14) |
-| GAP-28 | 15.5 | Market Protections (price collars / fat-finger / max value) | done | — | Engine-side static per-instrument price bands, auction-phase TOP collars, per-instrument max order quantity, and per-instrument max order value are implemented with existing ER reject reasons. The gateway dynamic last-trade-relative `priceBandPercent` remains as an outer decode-time guardrail. EntryPoint `protectionPrice` is echoed on `ExecutionReport_New` / `ExecutionReport_Modify` for Market-with-leftover-as-Limit (`OrdType=K`) remainders that rest at the last execution price. Triggered Stop Protect → MWL behavior, if B3 requires it, is tracked separately and is not a GAP-28 blocker. Tracked by [#500](https://github.com/pedrosakuma/B3MatchingPlatform/issues/500) and [#530](https://github.com/pedrosakuma/B3MatchingPlatform/issues/530). |
+| GAP-28 | 15.5 | Market Protections (price collars / fat-finger / max value) | done | — | Market protections are implemented as a **layered defense**: (1) a gateway decode-time **dynamic last-trade-relative collar** (`tcp.priceBandPercent`), wired end-to-end via `LastTradePriceProvider` → `HostRouter.LastTradePriceMantissa` → the dispatcher's durable per-security `_lastTradePriceBySecurity`, rejecting orders outside `[lastTrade·(1−pct), lastTrade·(1+pct)]` with `PriceExceedsCurrentPriceBand` (wire 16); (2) engine-side **static** per-instrument price bands; (3) auction-phase **TOP collars**; plus per-instrument max order quantity / max order value — all using existing ER reject reasons. An engine-resident duplicate of the dynamic collar is intentionally **not** pursued: it would duplicate the working gateway guardrail and force a snapshot codec version bump to give the engine its own persisted last-trade reference (the dispatcher reference is rebuilt on trade replay). EntryPoint `protectionPrice` is echoed on `ExecutionReport_New` / `ExecutionReport_Modify` for Market-with-leftover-as-Limit (`OrdType=K`) remainders that rest at the last execution price. Triggered Stop Protect → MWL behavior, if B3 requires it, is tracked separately and is not a GAP-28 blocker. Closed by [#500](https://github.com/pedrosakuma/B3MatchingPlatform/issues/500) and [#530](https://github.com/pedrosakuma/B3MatchingPlatform/issues/530). |
| GAP-29 | 15.1 | User-Defined Spreads (UDS) — synthetic multi-leg instruments | missing | low (boundary case; borderline between exchange-side and broker-side) | — |
-| GAP-30 | 16.6 | Sweep & Cross | partial | low (in-scope per ADR 0012) | Matching semantics for `CrossType=AgainstBook` are implemented (#218), sweep-phase UMDF `Trade_53.trdSubType` emits `SWEEP_TRADE` (109), and EntryPoint `ExecutionReport_New` / `ExecutionReport_Trade` now echo `crossType` + `crossPrioritization` for cross-generated ERs (#529). Remaining wire refinement: residual-cancel `ExecRestatementReason=210` is intentionally out of scope while residuals rest. |
+| GAP-30 | 16.6 | Sweep & Cross | done | — | Matching semantics for `CrossType=AgainstBook` are implemented (#218), sweep-phase UMDF `Trade_53.trdSubType` emits `SWEEP_TRADE` (109), and EntryPoint `ExecutionReport_New` / `ExecutionReport_Trade` echo `crossType` + `crossPrioritization` for cross-generated ERs (#529). `ExecRestatementReason=210` (`CANCEL_REMAINING_FROM_SWEEP_CROSS`) is **not applicable** under the current design and is **not a schema gap**: value 210 exists only on `ExecutionReport_Cancel` (id=202) — it is absent from `ExecutionReport_New` (id=200) in schema 8.4.2 — and annotates a *cancelled* sweep residual. This simulator instead lets the residual **rest** (phase 2 emits ER_New, with the phase-1 IOC cancel suppressed in `MatchingEngine.cs`), so no ER_Cancel is ever emitted to carry 210. Emitting 210 would require a product-scope change from "residual rests" to "residual cancelled"; researched and dismissed in [#533](https://github.com/pedrosakuma/B3MatchingPlatform/issues/533). |
| GAP-31 | 7.1.19 / UMDF v2.2.0 `SecurityDefinition_12` | `SecurityDefinition_12` does not emit option fields (`strikePrice`, `putOrCall`, `exerciseStyle`, `contractMultiplier`, `noUnderlyings`, `optPayoutType`, `maturityMonthYear`). | missing | high | tracked via [RFC 0002](rfc/0002-equity-options-support.md) issue OPT-02 |
| GAP-32 | 8.3 / lifecycle | Expiring option series are not automatically moved to `Close` based on `ExpirationDate`. | missing | medium | tracked via [RFC 0002](rfc/0002-equity-options-support.md) issue OPT-03 |