Skip to content

fix: key sessions on the clients native session id, not rotating credentials - #287

Closed
ranxianglei wants to merge 1 commit into
masterfrom
2026-08-27_native-session-identity
Closed

fix: key sessions on the clients native session id, not rotating credentials#287
ranxianglei wants to merge 1 commit into
masterfrom
2026-08-27_native-session-identity

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

refs #280
refs #286

Background

The proxy session id was hash(protocol | upstream | credential | conversation). Two of those dimensions are volatile even within ONE conversation:

  • credential — for Codex/ChatGPT this is a rotating OAuth bearer;
  • upstream — changes when a user switches relays.

Either change minted a brand-new session id and orphaned ALL compression state — in-memory blocks, lastInputTokens, and the persisted record (keyed by the same id, so it couldn't be restored either). That is the "sessions 缺失" root cause behind #280: after the churn, the session restarts at usage=0% with the full raw history replayed, the nudge goes blind, and the payload overflows the real window.

Change

The client's native session id (codex session-id header, claude x-claude-code-session-id, opencode x-opencode-session, Responses body session_id, prompt_cache_key) is the only invariant tied to a conversation — the user can switch accounts or relays anytime, and the session id is what stays bound to the conversation (#286, owner-confirmed direction):

  • src/session-id.ts: deriveSessionId takes the resolved identity; when it is client-provided (identity.clientProvided), the session id is hash(protocol | conversation) only.
  • src/server.ts: passes the resolved identity (per protocol: header signal for anthropic, the openai/responses identity objects) into the derivation.
  • The content-fingerprint fallback (hermes, dsh, anonymous clients — no client signal) keeps the 4-way hash: the fingerprint is a content hash with a real collision surface and still needs the account/upstream dimensions for isolation. previous_response_id (clientDerived, clientProvided:false) also stays 4-way.

One-time cost: existing persisted sessions re-key once (old records orphaned) — accepted per #286.

Tests

  • Codex native session id stable across bearer rotation AND relay switch; different conversation/protocol still separate.
  • Body session_id and prompt_cache_key identities credential-independent.
  • Fingerprint + previous_response_id keep 4-way isolation (no cross-account/cross-provider bleed).

Full suite: 660/660 pass.

Coordination

Complements #249 (thread-id subagent refinement + compaction fast path) — independent change, no overlap in the identity-derivation code path.

🤖 ework agent

…dentials

refs #280
refs #286

The proxy session id was hash(protocol|upstream|credential|conversation).
For Codex/ChatGPT the credential is a rotating OAuth bearer, and the
upstream changes when a user switches relays — either change minted a new
session id and orphaned ALL compression state (in-memory blocks,
lastInputTokens, and the persisted record keyed by the same id). That is
the "sessions 缺失" root cause behind #280: the restored session starts
at usage=0% with the full raw history replayed.

The client's native session id (codex session-id header, claude
x-claude-code-session-id, opencode x-opencode-session, Responses body
session_id, prompt_cache_key) is the only invariant tied to a conversation
— the user can switch accounts or relays anytime. So:

- client-provided identity (identity.clientProvided) → session id is
  hash(protocol|conversation) only; credential and upstream no longer
  break continuity.
- content-fingerprint fallback (hermes, dsh, anonymous clients — no
  client signal) keeps the 4-way hash: the fingerprint is a content hash
  with a real collision surface and still needs the account/upstream
  dimensions for isolation.

One-time cost: existing persisted sessions re-key once (old records
orphaned); accepted per #286 discussion.

Tests: codex native session id stable across bearer rotation + relay
switch; body session_id / prompt_cache_key credential-independent;
fingerprint + previous_response_id keep 4-way isolation. Full suite
660/660.
@github-actions

Copy link
Copy Markdown

📦 Built Package Artifact

Branch: 2026-08-27_native-session-identity (1d6b5a2)

Option A — Install from npm PR tag (recommended)

npm install -g billion-context@pr-287

Each push to this PR publishes a new version under the pr-287 npm tag.

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pr287.tgz
npm install -g package

This comment is automatically updated on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

Superseded by #288 (merged): the verbatim session-id design replaces the hash(protocol|conversation) approach here, and deriveSessionId no longer exists on master. Closing.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 ework agent · vllm-qwen/qwen3.8-27b

Acknowledged — closing #287 as superseded by #288. The verbatim native session-id design is the one that landed; the hash(protocol | conversation) fallback approach here is discarded. No further action on this branch.

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