Resolve conflict in backend/internal/handler/openai_gateway_handler_test.go.
main and this branch each appended a passthrough upstream stub plus a test at
the same two insertion points:
main openAIHTTPPassthroughSSERateLimitUpstream
TestOpenAIResponses_APIKeyPassthroughSSERateLimitUsesConfiguredPoolRetry
branch openAIHTTPPassthroughAuthFailoverUpstream
TestOpenAIResponses_APIKeyPassthroughPoolAuthFailureRetriesThenSwitchesToHealthyAccount
Both sides are kept verbatim; the only edit is giving each stub its own
calls() body instead of sharing the trailing one. No assertion was changed.
openai_gateway_passthrough.go and openai_oauth_passthrough_test.go merged
automatically.
The security audit group (Risk Control + Prompt Audit) was hidden from
the sidebar via `hideInSimpleMode`, but nothing else in the stack
restricts it in simple mode:
- `router/index.ts` simple-mode `restrictedPaths` does not cover
`/admin/risk-control` or `/admin/prompt-audit`
- the `/risk-control` and `/prompt-audit` admin route groups have no
`RunMode` gate, and neither does `internal/securityaudit/` nor
`service/content_moderation.go`
- `SettingsView.vue` renders the risk control toggle together with a
`<router-link to="/admin/risk-control">` shortcut, and the settings
page stays visible in simple mode
The feature is therefore fully usable in simple mode and already
reachable through the settings page — only the sidebar entry was
missing. Drop the flag so the menu matches actual behaviour.
The group remains gated by `risk_control_enabled` (opt-in, default
false) through `featureFlag: flagRiskControl`.
Three guards on the response_model billing basis, all scoped to the opt-in
channel mode so existing channels are unaffected.
1. Per-unit billing gate was stale. Audio (AudioUsage) and the search
surcharge (SearchCount) reached the billing paths after this branch was
cut; both are priced per unit rather than per token, so they must be
excluded like image/video/web-search already are. Audio pricing ignores
the model entirely, so the previous code "adopted" a basis switch that
changed nothing and emitted a misleading audit log for it.
2. Never zero out a billable request. A catalog entry whose token prices are
explicitly 0 still passes the identified-pricing gate (TokenPricingAbsent
only means both prices are missing), so an upstream could declare a free
model name and drop the bill to zero. Reject a zero (or negative)
recomputation whenever the baseline was billable; an already-zero baseline
is unaffected.
3. Never cross from channel pricing to the global table. Channel pricing
matches exact keys and prefix wildcards and does not strip date suffixes,
while the global table's identified lookup does. Upstreams routinely
declare dated model IDs (claude-opus-4-5-20251101), so allowing a
cross-source comparison would silently bypass an administrator's channel
markup on essentially every request. Admins who want a downgrade target
discounted can price it explicitly on the channel.
Also skip the recomputation entirely when the declared model equals the
baseline: it is provably the same cost and only burned a pricing resolve.
The identified-pricing helpers now return whether the model resolved to
channel pricing so the third guard costs no extra resolve.