- Added a shared TrustedProxyResolver in core identity infrastructure so HTTP auth and header identity extraction use the same CIDR-aware trust decision path and env var.
- WebSocket auth now goes through the lifecycle auth wrapper by treating websocket scopes like HTTP scopes and mapping `?token=` to an Authorization header before authn.
- EventStreamQueue backpressure is safer when it drops the oldest queued event and logs a per-connection `ws_event_dropped` warning instead of letting stale backlog accumulate.
- Security regressions are best covered at the exploit path: HTTP policy push should be rejected even with the old `x-hangar-agent-internal` header, websocket auth should fail closed with code 1008, and non-loopback HTTP startup without auth must stay blocked.
- Command validation was safer after switching from a blacklist to a default-deny allow-list with `MCP_ALLOWED_COMMANDS` as the runtime override, because unknown executables now fail closed.
- Discovery and subprocess launch paths both need to handle allow-list denials explicitly so rejected executables are blocked before MCP server registration or process spawn.
- MCP Server REST endpoints now use a shared core-side _check_permission helper that reads request.state.auth, allows requests when authz middleware is unavailable, and authorizes fine-grained MCP servers:read/write/lifecycle actions via context auth components.
- Granular RBAC constants for MCP servers API and config reload live in domain.value_objects.security so enterprise roles can reuse them without crossing the src/enterprise boundary.
- `server.state` can keep backward-compat exports without import-time side effects by using a lazy `get_runtime()` singleton plus module-level `__getattr__` that emits `DeprecationWarning` for legacy symbols.
- Removing the `ProviderDict` shim is easier when callers switch to the shared runtime repository and the remaining dict-like behavior is provided directly by repository methods (`items`, `values`, `get_all_ids`, `count`, `exists`, `add`, `remove`).
- Enterprise bootstrap is safer when core discovers optional enterprise loaders through the `mcp_hangar.enterprise` entry-point group, because missing plugins cleanly return empty `EnterpriseComponents` while real loader failures are no longer masked by broad import fallbacks.
- Extracting a small @runtime_checkable ILock protocol into domain.contracts lets InMemoryProviderRepository accept an injected lock factory while preserving backward-compatible default construction for callers that do not pass one.
- A-7 auth middleware cleanup was mostly a separation/documentation task: core `IdentityMiddleware` stays extraction-only, while enterprise `AuthMiddlewareHTTP` now reuses shared core-side header and source-IP normalization helpers from `infrastructure.identity.trusted_proxy` before enforcing auth.
- A-3 launcher extraction works cleanly when the domain owns only an `IProviderLauncher` protocol plus `LaunchResult`, while concrete subprocess/container/http launchers live under `infrastructure.launchers` and the old `domain.services.provider_launcher` package stays as a deprecation shim.
- WebSocket event streams can stay backward-compatible by accepting first, waiting up to 5 seconds for an initial `{"type": "subscribe"}` negotiation message, and falling back to empty filters when no subscription arrives.
- Reusing the normal websocket message handler for both the negotiation message and the long-lived reader loop keeps subscribe acknowledgments isolated to the first explicit `subscribe` frame while still allowing later filter updates and pong handling.
