Use encoding/json instead of Go string quoting when promoting message content to cached text blocks. Add regression coverage for control characters, Unicode, literal backslashes, text preservation, and idempotence.
An OpenAI group that keeps a failover account for a shared public alias
produced a Codex model descriptor with no reasoning levels and text-only
input, which leaves the client's reasoning-effort slider with nothing to
select.
Two accounts explicitly mapping one alias to different upstream models
makes codexExplicitModelTargetsConflictForPlatform true. With no
upstream_model_metadata snapshot to intersect, groupCodexModelMetadata
short-circuits to {reasoningConflict, inputModalitiesConflict}, so
DefaultReasoningLevel is nil (the key vanishes under omitempty) and
SupportedReasoningLevels is an empty array. mergeMissingCodexModelFields
fills only missing-or-null fields, so an empty array is never repaired.
Failing closed is right when the alias target is genuinely ambiguous, but
a group that declares model_routing for the alias has already resolved
that ambiguity: the operator stated which accounts serve it and which is
primary. Treating that as a conflict rejects a deliberate failover setup.
Manifest side: when a routing rule names the alias, restrict capability
declaration to the routed accounts and skip the conflict override.
Capabilities then fall back to the same by-name derivation used for a
single account without a metadata snapshot. Groups with no rule, a
disabled rule, or a rule for another alias keep failing closed.
Scheduling side: model_routing was stored and read platform-agnostically
(admin_group.go, Group.GetRoutingAccountIDs) but four gates in
gateway_scheduling.go only consulted it for Anthropic, so an OpenAI
group's rules were accepted and displayed yet never honored. Without
this, the manifest would honor a rule that scheduling ignores. Both
gates now share one predicate, with the allowed platform set defined in
a single place.
Selection inside a routing list is unchanged: the list is a membership
set, and the winner is still decided by Priority, then load, then
LastUsedAt.
Tests: alias-failover manifest recovery plus the three negative cases,
the platform predicate table, and an OpenAI routed selection that must
beat a higher-priority unrouted account.
Payment and admin fulfillment shared the public Redeem entry point, so
fulfillment retries were blocked by, and contributed to, the user's
public redeem failure counter, and lookup errors were silently treated as
"code does not exist" on a partial re-run.
- resolveRedeemAction now distinguishes a genuine not-found lookup from
other lookup errors (which now fail the fulfillment instead of being
swallowed and re-created).
- Add validatePaymentRedeemCode: before reusing an existing code during
fulfillment, verify it belongs to the order (code id, balance type,
amount, user, status), so a stale or foreign code can never be
credited against the wrong order/user.
- Split Redeem into a policy-based core: public redemption enforces the
failure counter; payment fulfillment (redeemForPaymentFulfillment) and
admin fulfillment (RedeemForAdminFulfillment) bypass it, while all code
validation and transactional updates remain identical. Admin
fulfillment keeps the normal redeem-level affiliate rebate.
- The admin CreateAndRedeem endpoint now uses RedeemForAdminFulfillment.
Tests: updated resolveRedeemAction cases, new TestValidatePaymentRedeemCode,
code-used-by-another-user rejection, payment/admin rate-limit bypass
coverage, and public-path regression coverage.
Cyber-policy detection only inspected response.failed, and the ingress check ran after error-specific early returns. As a result, error-shaped failures and the connection-pool, HTTP-bridge, and WSv2 paths could miss cyber-policy hits.
Centralize event marking and invoke it before retry and failover returns across the WebSocket implementations. Preserve the recorded guard during account failover and defer connection blocking until the logical failover chain completes, avoiding duplicate records while ensuring subsequent turns are blocked.