Skip to content

A configured openai upstream drops the x-hypaware-upstream steering rung, so a steered turn routes nowhere #539

Description

@philcunliffe

Found while applying maintainer guidance on PR #510 (dropping priority: 100 from openaiUpstreamPreset()). Filed without neutral:fix because the only fixes change a documented ownership rule, so it wants a decision rather than a worker.

The seam

When an operator configures an openai upstream in TOML, config wins the name outright and the merged entry carries no match() - so the x-hypaware-upstream steering rung disappears along with the preset, and a steered /chat/completions routes nowhere.

Verified directly: with a configured openai, the compiled table is byte-identical at priority: 100 and at the default 0. The preset never reaches the table at all, so this is pre-existing and priority-independent - not a regression from #510's change, and not something dropping the priority introduces or fixes.

Why it was not fixed in place

The obvious remedy is to let a preset contribute its match() to a same-named config upstream. That changes the operator-owns-config rule (ai-gateway/src/source.js's merge, where config beats a same-named preset), which is a deliberate design decision, not an implementation detail. Silently changing it inside a change set about OpenClaw capture would be the wrong place for that call.

Rather than delete the shape from the tests or paper over it, #510 records it as an explicitly-labelled test asserting current behaviour, and documents it in LLP 0161 §3.4 as out of scope.

Why it matters

The steering plugin sets x-hypaware-upstream to route a shadowed provider's turn through the gateway. An operator who configures their own openai upstream - a reasonable thing to do - silently loses that rung, and the steered turn 404s. It fails the user's request, which is the class LLP 0157 R5 forbids ("the user's turn MUST NOT fail because of capture"), though by a different mechanism than the T6 registration race already analysed on #510.

Options

  • (a) Let a preset contribute match() to a same-named config upstream when the config entry declares none. Narrow, but amends the ownership rule.
  • (b) Have the steering plugin detect that its target upstream carries no steering rung and refuse to steer, so the turn falls back rather than 404s.
  • (c) Document it as a known operator footgun and surface it in hyp init / config validation when an openai upstream is declared alongside the OpenClaw client.
  • (d) Accept as designed: an operator who configures an upstream owns its routing entirely.

Related: PR #510 (the change set), PR #537 (fix/issue-536, hardening the same slot on master), LLP 0157 R5, LLP 0161 §3.4.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions