Skip to main content
v1.5.11

Changelog

This release rebases Bifrost Enterprise on OSS transports v1.6.11. The main work is a rewrite of cluster usage sync that sends only changed governance entries instead of full snapshots, quarterly budget support carried end to end through the enterprise UI and business unit APIs, and SCIM provenance protection so an OIDC login or token refresh can no longer overwrite roles that SCIM owns.

✨ Features

  • Incremental Cluster Usage Sync - Governance usage now gossips changed entries every 5 seconds, a lightweight heartbeat every 10 seconds, and a full repair snapshot every 30 seconds, instead of a complete snapshot on every tick. Internal cluster gzip compression is removed, remote budget and rate-limit totals are precomputed into an immutable snapshot so the request path does a direct id lookup, and a new governance_usage_v2 message keeps rolling upgrades safe because older nodes ignore it and still receive the legacy full snapshot. Docs
  • Quarterly Budgets Across the Enterprise UI - reset_config (the fiscal quarter start month) is now propagated through every budget create, edit, duplicate, and save flow for access profiles, teams, customers, and users. The 1Q duration renders as “Quarterly” with a fiscal quarter note next to it, and the dirty-state check includes quarter_start_month so changing the start month is detected as an unsaved edit.
  • Role Filter and Real Sorting on the Users List - The users table gains a Role filter populated from the RBAC roles endpoint, plus a “No role” option. Name and email sorting now actually works: sort_by and sort_order are URL-backed, allowlisted at the handler, and applied in SQL, and roleless users are grouped last in both directions so SQLite and Postgres agree. Docs
  • Keycloak Department and Title Mapping - convertKeycloakUser now promotes the department and title custom attributes (including the job_title and jobTitle variants) into the dedicated provisioned-user fields, so attribute-to-team, attribute-to-role, and attribute-to-business-unit mappings apply during SCIM import instead of being silently dropped. Docs
  • Gray Swan Sees the Original Request - Guardrail evaluations forward the original Chat or Responses request JSON to the monitor API instead of rebuilding it from extracted text. Multi-part content arrays, images and files, native Responses tool shapes, and fields such as name and the developer role survive intact, per-turn batches are sliced from a cached snapshot without re-parsing or re-fetching media, and the raw body size cap is removed. Docs

🌎 Open Source Features

  • URL Sources Inlined for AWS-Hosted Claude - URL-sourced images and documents are fetched and inlined on the native Anthropic path, because Bedrock Mantle rejects {"source":{"type":"url"}}. Fetches use the SSRF-safe dialer with a size cap, and a failed fetch aborts the request instead of silently dropping the attachment. Docs
  • Quarterly Budgets for Customers - The customer entity and virtual key provider configs now accept quarterly budgets, so a customer budget can reset on a quarter boundary rather than only monthly or weekly.
  • Fiscal Year Start in Budget Labels - Budget labels surface the configured fiscal year start through a new fiscalQuarterNote helper, and the quarter start selector is relaid out as a horizontal label and preview row.
  • Configurable Entity Selector Width - The entity selector accepts a contentClassName, so a caller can widen or constrain its dropdown instead of being pinned to the default width.

🐞 Fixed

  • SCIM Roles Overwritten by OIDC Login or Refresh - Role and team sync from token claims is now skipped for SCIM-managed users on both the login and token refresh paths, and the source=scim profile marker is re-stamped before the OAuth upsert overwrites the parsed profile. Truncated or stale claims can no longer downgrade a role that SCIM owns. Provenance checks fail closed, so an error in the check skips the sync.
  • Claims Not Enriched on Token Refresh - The refresh path now enriches claims from the provider, so claims that arrive through the provider API rather than directly in the token are no longer missing after a refresh.
  • Keycloak Auth Cookie Used the Wrong Token - Keycloak is added to the id-token providers in ChooseAuthCookieToken, matching how Keycloak populates both the access token and the id token.
  • Fiscal Quarter Start Lost on Business Unit Budgets - ResetConfig is now assigned on the budget create path, the budget update path, and the create-during-update path. It was omitted from all three, so a fiscal quarter start was silently dropped on every save. The update path assigns it unconditionally, so clearing the quarter start is respected too.
  • User-Scoped Model Configs Survived User Deletion - CascadeDeleteUser now removes every scope=user model config and its owned budgets, rate limits, and alert rules, and clears the access-profile materialization tracking rows. These rows are keyed by user id rather than being foreign-key children, so nothing else in the cascade reached them and a restored user with the same id inherited stale rows.
  • gRPC Peer Connection Falsely Stuck - The dial loop read the channel state twice per iteration, so a peer that became ready in between made WaitForStateChange wait for a change away from ready and triggered needless reconnects. State is now read once per iteration, idle channels are explicitly connected, and a bounded probe RPC reports the real transport failure (connection refused, TLS handshake failure, mesh rejection) instead of only the channel state.
  • WebSocket Writes After Disconnect - A broadcast racing a client disconnect could panic on a nil connection or deliver to an unrelated client’s socket, because fasthttp recycles the hijacked connection as soon as the upgrade handler returns. Clients now carry an explicit closed flag, and close blocks until in-flight writes finish.
  • Realtime Heartbeat Panic on Disconnect - stopHeartbeat waits for the heartbeat goroutine to exit before the upgrade handler returns. A ping already inside WriteMessage dereferenced a recycled connection, and with no recover on that path the panic took down the process.
  • Stop Sequences Dropped for Nova and Titan - Bedrock’s Converse camelCase stopSequences now maps to the neutral stop parameter alongside Anthropic’s stop_sequences. 81 catalog rows were losing stop, so those models ran to end_turn instead of stopping.
  • Reasoning Replay Rejected on Chat-Shaped Requests - /v1/chat/completions and /v1/messages carry replayed reasoning on reasoning_details, but the fail-soft strip only handled Responses-shaped items. A router that switched models mid-conversation returned an invalid signature error instead of retrying without the signature.
  • Thinking Signatures on Responses Content Blocks - Signatures are stripped from content blocks, not only from encrypted_content on the reasoning item, and only reasoning items are dropped when nothing survives, so an ordinary message keeps its own content.
  • Reasoning Content Rejected by OpenAI and Azure Models - reasoning.content is no longer sent to non-gpt-oss reasoning models, which cap that array at zero entries and reject a populated one. Replayed Anthropic thinking blocks were hitting this; summary and encrypted_content already carry everything those models accept.
  • Reasoning Effort Cleared for Current Grok Models - The rule substring-matched “grok-3-mini”, so grok-4.5, grok-4.6, and grok-4.20-multi-agent silently lost reasoning_effort and answered at the wrong depth, cost, and latency. It is now an exact-match deny-list that normalizes routing prefixes, -latest, and xAI’s 4-digit date suffixes.
  • xhigh Reasoning Effort Downgraded for Grok - The shared OpenAI-dialect normalizer downgraded xhigh to high before the xAI compat pass ran. grok-4.5 still downgrades on purpose, matching xAI’s documented upstream coercion.
  • Empty Structured-Output Streams - content_part.added, output_text.delta, output_text.done, and content_part.done are emitted when a tool-based structured-output call is reassembled on the Responses streaming path. Only output_item.added and done were emitted, so consumers reading incremental events saw no text while tokens were billed. Affects Vertex, Bedrock Mantle, and Azure Claude.
  • HTTP 529 Rotating Credentials - Anthropic’s overloaded_error is treated as a transient server error and retried with backoff on the same key, since it reflects capacity across all callers rather than anything about the credential.

🗄️ Database Migrations

No new database migrations in this release, in either the OSS transports layer or the enterprise repo.

📀 Base OSS version

transports/v1.6.11

🔌 If you are compiling plugin against this release - use following deps