Skip to content

Fix/proxy admin auth and version stitch - #7

Open
damonleelcx wants to merge 3 commits into
develop-v1.0.5from
fix/proxy-admin-auth-and-version-stitch
Open

Fix/proxy admin auth and version stitch#7
damonleelcx wants to merge 3 commits into
develop-v1.0.5from
fix/proxy-admin-auth-and-version-stitch

Conversation

@damonleelcx

Copy link
Copy Markdown

No description provided.

damonleelcx and others added 2 commits August 3, 2026 08:32
…yte-equal one

stitchRequestURL removed the leading version segment from the request path only
when it was byte-equal to the row's own `version`. An OpenAI-compatible client
always sends /v1/chat/completions, so every row whose version was NOT "/v1" kept
both and dialled e.g.

  https://ark.cn-beijing.volces.com/api/v3/v1/chat/completions

Five rows were affected (2 pre-existing since the baseline, 3 added by the
cascade expansion). Invisible on the 23 rows whose version already is "/v1" —
/v1/v1 either way — which is how it survived. Found on real staging traffic:
qianfan returned 404 for exactly this path.

The function's own doc comment already promised the correct rule ("reqPath with
leading version stripped if present"); the implementation had diverged from it.

The fix is a UNION, not a replacement. Byte-equality still runs first because it
is the only branch that can strip a NON-numeric version such as gemini's
/v1beta; the new numeric rule then covers what byte-equality misses. The numeric
test is deliberately narrow — "v" followed by DIGITS ONLY — because
TestStitchContract/openai_v1abc_not_swallowed pins that /v1abc is a real path
segment that must survive.

Rows with no version are untouched: they re-attach nothing, so stripping the
client's segment would silently change three endpoints nobody has verified
against their vendor.

New fence covers 46 versioned rows and was proven red: reverting the fix fails
exactly the 5 known rows. A companion test enumerates the unversioned rows with
their probe results so the carve-out stays visible instead of silent.

Why this needed a NEW fence: I-2 asserts a shown URL resolves back to the row
that produced it. That is classification, not stitching — a row can classify
perfectly and still build a wrong upstream path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… code

Two corrections to the I-11 mixed-version fence, both of which were making it
describe a worker that does not exist.

1. clientPathFor returned `version + endpoint`, i.e. it simulated a client that
   sends whatever version the ROW declares. No client does that — OpenAI SDKs
   send /v1/chat/completions and Anthropic SDKs /v1/messages regardless of what
   the upstream serves. Feeding the row's own version in made the simulated URL
   byte-match the row's version and get stripped, which is how three rows of
   mixed-version-affected-rows.md came to state a destination no worker emits.

2. The old column was computed with the CURRENT stitch. That is a faithful model
   of an un-upgraded worker only while the algorithm is unchanged — a deployed
   old worker runs the old table AND the old code. Once the stitch changed, the
   fence began reporting a path no deployed binary produces and pointed at the
   manifest as the thing to correct. The manifest feeds release notes, so that
   direction of error publishes something false to customers. stitchOldRule
   freezes the retired behaviour for that column.

With both fixed, the fence's 26 computed old-worker URLs match, row for row,
what a real alpha.15 worker produced on staging on 2026-08-03 — two independent
methods agreeing. The three manifest cells are corrected to those measured
values.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@damonleelcx
damonleelcx changed the base branch from main to develop-v1.0.5 August 3, 2026 12:51
… row declares none

Third and last of the version:"" dispositions. The 2026-08-03 route-table health
check found that perplexity's declared endpoint answers 401 on
/chat/completions while /v1/chat/completions — the path this code actually
dialled — answers 404. So version:"" was never merely "unverified"; it was a
real mis-route, and the carve-out the previous fix made for it was wrong.

The strip is now unconditional for a row resolved OUT OF THE TABLE.

🚫 Not unconditional full stop, which is the one-line version of this fix and
the wrong one. The degraded literal-prepend branch also produces version "",
and it means the opposite thing: not "this vendor has no version segment" but
"we have never heard of this host". Swallowing the /v1 there would break every
private gateway and enterprise reverse proxy that is not in the yaml — exactly
the deployments with no coverage and no way to notice except a customer's 404.
resolveStitchComponents now reports which branch answered, and
TestFence_UnknownHostStillForwardsTheClientVersion pins the distinction. The
existing unknown_host_literal_prepend case does NOT catch this: its request path
has no version segment to swallow, so it stays green through the bad fix.

Table changes carried in with the yaml sync (canonical copy in aikey-cli):
github_models deleted (vendor 410), zhipu /api/paas given /v4.

The zhipu row is pre-existing, which I-3 exists to forbid. The baseline fixture
is NOT regenerated — it is the only record of what the table looked like before
the expansion, and rewriting it would make the fence assert that the table agrees
with itself, and would erase what an operator needs during a staggered rollout.
Instead intentionalRowChanges names the one row, pins its new field values, and
ASSERTS the upgrade consequence computed both ways: a pre-upgrade worker dials
…/api/paas/v1/chat/completions, this binary dials …/api/paas/v4/chat/completions.
Every other pre-cascade row is still held byte-exact.

TestFence_OAuthPathVersionDivergenceIsKnown now has an EMPTY set, and the defect
is NOT fixed. Both entries were zhipu openai rows that diverged only because
zhipu's default row declared no version, so StitchForProviderProtocol had nothing
to strip. Giving it /v4 made the three rows version-uniform and the mismatch
vanished by arithmetic. The function still applies the pair's default row's
version to a base URL that may belong to a different row. The test stays as a
regression fence so the next such provider reds on the day the row is added.

Four fences deliberately broken and observed red; failure text in the roadmap's
fence-proof.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant