Skip to content

feat: expose durable session id match selection helpers#79970

Open
100yenadmin wants to merge 409 commits intoopenclaw:mainfrom
100yenadmin:feat/openclaw-79903-session-lineage
Open

feat: expose durable session id match selection helpers#79970
100yenadmin wants to merge 409 commits intoopenclaw:mainfrom
100yenadmin:feat/openclaw-79903-session-lineage

Conversation

@100yenadmin
Copy link
Copy Markdown
Contributor

@100yenadmin 100yenadmin commented May 9, 2026

Summary

Implements the first narrow public discovery seam from the SQLite companion-fit stack.

This PR exposes the existing alias-aware session-id selection logic through a reusable public helper and adds a richer run-id resolution result that preserves ambiguity instead of collapsing everything to string | undefined.

Why this is better

This helps OpenClaw core and downstream consumers in a generic way:

  • duplicate sessionId matches now have one canonical selection policy instead of each caller guessing
  • ambiguity becomes a first-class outcome rather than being flattened into a cache miss
  • run-id lookups can preserve both store-key and request-key shape without redoing the conversion logic
  • the public seam stays narrow and extraction-only; it does not introduce a new lineage table or LCM-specific projection

Scope

Included:

  • public SessionIdMatchSelection re-export on openclaw/plugin-sdk/session-store-runtime
  • new resolveSessionKeySelectionForRun(...) helper in gateway code
  • compatibility wrapper preserved for existing resolveSessionKeyForRun(...) callers
  • targeted gateway/session-id tests and plugin SDK API baseline refresh

Not included:

  • transcript cursor/frontier work from #79904
  • typed transcript projections from #79905
  • broader lineage family projections beyond the minimal selection seam

Review Follow-up

This PR now preserves active-run semantics in the richer resolver too.

Fix:

  • resolveSessionKeySelectionForRun(...) now checks getAgentRunContext(runId)?.sessionKey before the store scan, matching the existing behavior already preserved by resolveSessionKeyForRun(...)

Why this was necessary:

  • gateway paths can register active run context before the store scan is meaningful
  • consumers adopting the richer helper should not regress from a resolvable active run to { kind: "none" }

Primary follow-up files:

  • src/gateway/server-session-key.ts
  • src/gateway/server-session-key.test.ts

Real Behavior Proof

Runtime proof from a direct module invocation on the PR branch:

{
  "selection": {
    "kind": "selected",
    "storeSessionKey": "agent:retired:acp:run-live",
    "requestSessionKey": "acp:run-live"
  },
  "direct": "agent:retired:acp:run-live"
}

That proof shows:

  • the rich resolver returns a selected result from active run context
  • the legacy direct resolver still returns the same canonical store key

Validation

cd /Volumes/LEXAR/repos/openclaw-79903-session-lineage
OPENCLAW_TEST_PROJECTS_SERIAL=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=120000 \
  node scripts/run-vitest.mjs \
  src/sessions/session-id-resolution.test.ts \
  src/gateway/server-session-key.test.ts

cd /Volumes/LEXAR/repos/openclaw-79903-session-lineage
pnpm plugin-sdk:api:gen

Observed locally:

  • 2 files passed, 15 tests passed
  • plugin SDK API baseline regenerated cleanly

Stack placement

This PR is the narrow lineage/discovery seam in the companion-fit stack.

Related stack:

Why this is separate:

  • OpenClaw owns canonical selection policy
  • Lossless Claw can later map richer family and segment identity on top without pushing that storage model into OpenClaw core

Issue

Refs openclaw/openclaw#79903.

steipete added 30 commits May 9, 2026 18:01
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 9, 2026

Codex review: found issues before merge.

Summary
The branch exports session-id match selection helpers through the plugin SDK, adds a richer gateway run-id selection helper, updates targeted tests/API baseline, and carries the broader SQLite runtime-state refactor/docs surface.

Reproducibility: not applicable. as a user bug because this is a new public helper feature. For the patch finding, yes: source inspection shows a normal call sequence where resolveSessionKeyForRun registers a request-shaped context key and the new rich resolver can later report that same value as storeSessionKey.

Real behavior proof
Sufficient (live_output): The updated PR body includes copied after-fix JSON output from a direct module invocation on the PR branch showing the rich resolver and legacy resolver behavior for active context.

Next step before merge
This protected security-labeled XL PR needs maintainer/security review and branch cleanup; the remaining work is not a safe autonomous repair lane.

Security
Needs attention: Needs security review because the branch is security-labeled and changes broad durable runtime state far beyond the helper seam.

Review findings

  • [P2] Return the real store key from active selections — src/gateway/server-session-key.ts:118-119
Review details

Best possible solution:

Land a narrow, security-reviewed public selection seam after the SQLite storage boundary is settled, preserving distinct store/request key semantics and keeping companion-specific lineage models outside core.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a user bug because this is a new public helper feature. For the patch finding, yes: source inspection shows a normal call sequence where resolveSessionKeyForRun registers a request-shaped context key and the new rich resolver can later report that same value as storeSessionKey.

Is this the best way to solve the issue?

No. The helper direction is plausible, but this landing shape is not the best yet because it bundles the seam into a broad security-sensitive SQLite refactor and the rich result can mislabel request keys as store keys.

Full review comments:

  • [P2] Return the real store key from active selections — src/gateway/server-session-key.ts:118-119
    After resolveSessionKeyForRun resolves from the store, it registers active context with selection.requestSessionKey. A later resolveSessionKeySelectionForRun hits the active-context fast path first and returns that single context value as storeSessionKey, so callers can receive storeSessionKey: "acp:run-1" instead of the canonical agent:retired:acp:run-1 row key. Consumers using the rich result for store lookup or lineage will miss the row.
    Confidence: 0.83

Overall correctness: patch is incorrect
Overall confidence: 0.8

Security concerns:

  • [medium] Route broad SQLite state rewrites through security review
    The live PR API and file list show an XL branch that changes exec approvals, pairing/device state, migrations, SQLite stores, app/protocol surfaces, and docs while framed as a session-id helper. Permission semantics, migration idempotency, rollback behavior, and secret-adjacent durable state need owner/security sign-off before merge.
    Confidence: 0.84

What I checked:

  • Current main internal helper: Current main already has the internal alias-aware resolveSessionIdMatchSelection and preferred-key policy. (src/sessions/session-id-resolution.ts:96, dd224c85603d)
  • Current main SDK gap: Current main session-store-runtime exports file-era session helpers and SessionEntry types, but not SessionIdMatchSelection or the selection helper functions requested by this PR. (src/plugin-sdk/session-store-runtime.ts:1, dd224c85603d)
  • PR SDK export: PR head adds resolvePreferredSessionKeyForSessionIdMatches, resolveSessionIdMatchSelection, and SessionIdMatchSelection to the public plugin SDK subpath. (src/plugin-sdk/session-store-runtime.ts:27, 43d86feb128d)
  • Follow-up fix present: PR head now checks active run context before the store scan in resolveSessionKeySelectionForRun, addressing the earlier ClawSweeper finding in that specific path. (src/gateway/server-session-key.ts:111, 43d86feb128d)
  • Protected broad PR: Live pull API reports security, triage: needs-real-behavior-proof, 2,174 changed files, 79,364 additions, 67,922 deletions, and mergeable_state: dirty. (43d86feb128d)
  • Review finding source: The rich active-context resolver returns the single context value as storeSessionKey, while the compatibility resolver can register request-shaped keys after store resolution. (src/gateway/server-session-key.ts:118, 43d86feb128d)

Likely related people:

  • steipete: Current-main blame for the central session-id, gateway run-key, and SDK runtime files points to Peter Steinberger, and the related database-first runtime PR is authored in this area. (role: active refactor owner / recent maintainer; confidence: high; commits: 9353febc9aa6, 6bd6f4d27c6d, 0d938748a54d; files: src/sessions/session-id-resolution.ts, src/gateway/server-session-key.ts, src/plugin-sdk/session-store-runtime.ts)
  • BunsDev: Prior related-review context ties the usage-family rollup commit to the continuity fields this helper seam is trying to expose. (role: lineage semantics contributor; confidence: medium; commits: d12c92c216ab; files: src/auto-reply/reply/session.ts, src/auto-reply/reply/agent-runner-session-reset.ts, src/gateway/server-methods/usage.ts)
  • gumadeiras: Prior related-review context connects this maintainer to custom session-store discovery hardening in the gateway matching path this PR builds on. (role: gateway session discovery contributor; confidence: medium; commits: 46f0bfc55b58; files: src/gateway/server-session-key.ts, src/sessions/session-id-resolution.ts)

Remaining risk / open question:

  • The PR is protected by the security label and rewrites broad runtime state, pairing, exec-approval, migration, app/protocol, and SQLite storage surfaces beyond the titled helper seam.
  • The branch is dirty/unmergeable against current main, so any final review needs conflict-resolution and touched-surface validation on the exact head that would merge.
  • The copied runtime proof covers the narrow active-context helper behavior, not the full security-sensitive SQLite runtime refactor carried by the branch.

Codex review notes: model gpt-5.5, reasoning high; reviewed against dd224c85603d.

@100yenadmin
Copy link
Copy Markdown
Contributor Author

Architecture fit for this slice:

flowchart TD
    A["runId / sessionId input"] --> B["canonical session-id match selection"]
    B --> C["none"]
    B --> D["ambiguous"]
    B --> E["selected"]
    E --> F["gateway consumers"]
    E --> G["plugin-sdk consumers"]
Loading

Why this slice exists:

  • OpenClaw already has alias-aware session-id selection logic, but consumers should not have to rediscover or reimplement it
  • ambiguity is a real state, not just a failed lookup
  • this seam lets downstream code preserve selection semantics without demanding a larger lineage schema change yet

Why it was chosen before broader lineage work:

  • it is narrow, extraction-only, and generic
  • it improves OpenClaw-native consumers too
  • it is a prerequisite for LCM conversation continuity work, but it does not force LCM's own family/segment model into OpenClaw core

Stack placement:

  • companion umbrella: #79902
  • child issue: #79903
  • related downstream follow-up: Martian-Engineering/lossless-claw#642

Lossless Claw connection:

  • LCM later needs stable session-family continuity, but the first upstream step is a canonical selection seam
  • this keeps the boundary clean: OpenClaw owns selection policy, LCM owns its richer continuity model

@100yenadmin
Copy link
Copy Markdown
Contributor Author

Follow-up on the live review finding:

  • addressed the active-run-context gap in resolveSessionKeySelectionForRun(...)
  • pushed in 43d86feb12
  • updated the PR body with direct runtime proof and refreshed validation counts

What changed:

  • the rich resolver now checks getAgentRunContext(runId)?.sessionKey before the store scan, matching the compatibility behavior already preserved by resolveSessionKeyForRun(...)
  • targeted tests now cover both store-shape and request-shape active run context

Runtime proof is now in the PR body and shows:

  • resolveSessionKeySelectionForRun("run-live") returns kind: "selected"
  • storeSessionKey stays canonical
  • requestSessionKey stays normalized for request-facing consumers

This keeps the seam extraction-only while preserving the actual runtime semantics gateway callers already depend on.

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

Labels

agents Agent runtime and tooling app: macos App: macos app: web-ui App: web-ui channel: discord Channel integration: discord channel: feishu Channel integration: feishu channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: irc channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: qa-channel Channel integration: qa-channel channel: qqbot channel: signal Channel integration: signal channel: slack Channel integration: slack channel: synology-chat channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: twitch Channel integration: twitch channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser cli CLI command changes commands Command implementations docker Docker and sandbox tooling docs Improvements or additions to documentation extensions: acpx extensions: anthropic extensions: cloudflare-ai-gateway extensions: codex extensions: device-pair extensions: diagnostics-otel Extension: diagnostics-otel extensions: kilocode extensions: kimi-coding extensions: llm-task Extension: llm-task extensions: lmstudio extensions: memory-core Extension: memory-core extensions: memory-wiki extensions: minimax extensions: openai extensions: phone-control extensions: qa-lab extensions: tts-local-cli gateway Gateway runtime plugin: azure-speech Azure Speech plugin plugin: file-transfer plugin: google-meet plugin: migrate-claude plugin: migrate-hermes scripts Repository scripts security Security documentation size: XL triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants