Skip to content

Key resolution cannot express the configured judgment backend #8

Description

@Samuel-ML

Key resolution cannot express the configured judgment backend

Summary

pi-typesafe ships multiple judgment backends — DECISIONS_BACKENDS (client.js:11-14) maps
each to its own keyEnv, and createTypeSafe consumes it at :93 and :96-110. Requests
work. But the key reporting and login surfaces cannot express a backend, so with
typesafeBackend: "openrouter" they report the wrong state and verify against the wrong host.

Filed as the library-side half of a defect observed through pi-warden, which carries the
end-to-end reproduction.

Versions

Package Version Published
pi-typesafe 0.6.2 (latest) 2026-09-22T05:54:44Z
pi-warden 0.38.3 2026-09-22T03:39:04Z
Node v26.7.0 —

Line numbers are from 0.6.2.

What works and what does not

Function Knows the backend?
createTypeSafe(options) — client.js:88, client.d.ts:17 yes (backend?)
keySituation() — credentials.js:50 / .d.ts:32 no — takes no arguments
authState(options) — auth.js:53 / .d.ts:37-39 no — options carries only path
describeAuth(state) — auth.js:98 / .d.ts:56 no
ensureApiKey(ctx) — login.js:30 / .d.ts:27 no

Observed with OPENROUTER_API_KEY set and TYPESAFE_API_KEY unset:

keySituation()      // { kind: "missing" }
authState()         // { kind: "missing", usable: false, keyName: "no key" }
describeAuth().text // "TypeSafe key: missing — every Jev judgment is skipped …"

Judgments in fact run in that same process.

Note for anyone reproducing: do not check arity with fn.length — default parameters make
keySituation.length, authState.length and describeAuth.length all report 0. Read the
.d.ts.

The four relevant dist files are byte-identical between 0.6.1 and 0.6.2 (sha256 edd7057a…
credentials.js, 78f3986f… auth.js, 8580cd21… login.js, 9c9170d8… client.js). The
0.6.2 changes in extension.js and schema.js are unrelated to this path.

Scope of the fix

Threading the backend into the four signatures is necessary but not sufficient. Three more
places are backend-hardcoded or unpartitioned:

  1. loginWithPrompt — login.js:22 calls createTypeSafe({ apiKey: key }).listModels()
    with no backend, so client.js:85 defaults baseURL to https://api.typesafe.ai. An
    OpenRouter key is verified against the wrong service. Threading ensureApiKey without this
    leaves the login flow broken.
  2. Labels and copy — keySourceLabel (credentials.js:67) returns the literal
    "TYPESAFE_API_KEY" / "/typesafe login", surfaced as keyName at auth.js:65;
    credentials.js:21 and auth.js:98-104 name console.typesafe.ai and /typesafe login.
  3. Storage — storeApiKey (credentials.js:87) writes a single auth.json at
    credentialsPath(), reported at auth.js:63. A backend-aware environment variable over a
    single unpartitioned store is an inconsistent model.

resolveApiKey (credentials.js:81) is a second frozen public entry point and needs the same
treatment.

Two notes for the maintainer

The capability is shipped but undocumented. client.js:11-14 implements openrouter with
keyEnv: "OPENROUTER_API_KEY" and path: "/api/alpha/decisions", while README.md contains no
mention of "openrouter" or "backend". A reader cannot discover that the backend exists, or that
it changes which credential is required.

Part of this may be intended. auth.d.ts:26 defines verified as "accepted by
api.typesafe.ai", and credentials.d.ts:29-31 scopes keySituation to the environment, the
login store, and file permissions. Under that reading pi-typesafe reports its own credential
by design, and the only backend-aware surface is createTypeSafe. If so, this is a
documentation gap rather than a defect — worth stating either way, because consumers currently
cannot tell which surfaces are backend-aware.

Unverified

Whether listModels() succeeds against OpenRouter once the backend is forwarded.
DECISIONS_BACKENDS.openrouter carries no models endpoint, and I did not make an authenticated
request. If it fails, the login flow needs a backend-specific verification path rather than just
a forwarded argument.

Activity

  1. DevMortimer commented on Sep 22, 2026

    @DevMortimer
    Owner

    Duplicate of #9, which is fixed by #10.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions