Skip to content

fix(gateway): reject unknown session agents instead of provisioning them#111178

Merged
steipete merged 1 commit into
mainfrom
claude/fix-sessions-lazy-agent-create
Jul 19, 2026
Merged

fix(gateway): reject unknown session agents instead of provisioning them#111178
steipete merged 1 commit into
mainfrom
claude/fix-sessions-lazy-agent-create

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

Calling sessions.describe or sessions.abort with a session key for an agent id that doesn't exist (agent:ghost:zzz) silently PROVISIONED that agent — creating agents/ghost/agent/openclaw-agent.sqlite, an agent_databases row, and an agents.list entry that survives restart. A caller with operator scopes and arbitrary session keys could create unbounded agents/databases through a read/abort path. It was also inconsistent: agents.delete on an unknown id correctly returns not-found. Found by the R7 QA campaign; the fix approach was chosen by the maintainer (reject unknown).

Why This Change Was Made

Provisioning is a side effect of opening an agent's store while resolving a session key. The gate should block CREATION of a store that doesn't exist — without losing access to any store that DOES exist.

User Impact

sessions.describe/get/search and sessions.abort now resolve read-only: if no store exists for the agent, describe/search return not-found/empty and abort returns agent "<id>" not found, and nothing is created (no directory, SQLite, registry row, or agents.list entry). Every legitimate way to reach an EXISTING store is preserved — a configured agent, a retired/removed-from-config agent whose store still exists (per-agent, deterministic-template, discovered, or legacy sessions.json), an agent that has rows in a shared store, or an in-memory active run. main and agents.create are unchanged.

Evidence

  • Reuses the existing configured-agent existence check and the discovery path's lstat/realpath/root-containment validation (deterministic targets are validated the same way — a symlink escaping the agents root is rejected, not followed).
  • Fixed-store negative results get a cache-distinct identity so a batch/preview ordered [unknownKey, validKey] no longer mis-reports the valid session as missing.
  • Tests (167 across four files): unknown id creates nothing (dir/sqlite/registry/list all absent); retired agent with a validated persisted store readable/searchable/abortable; exact in-memory active run abortable; deterministic-template symlink-escape rejected; batch cache order-independence; legacy fixed store recognized; configured/main/agents.create unchanged.
  • Autoreview (codex gpt-5.6-sol, xhigh): clean after a deep multi-round review that surfaced and closed real edges (shared-store-vs-agent existence, retired-store search, active-run abort, deterministic-template validation, symlink containment, cache collision). Prod change is small; the bulk of the diff is regression tests.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XL maintainer Maintainer-authored PR labels Jul 19, 2026
@steipete steipete self-assigned this Jul 19, 2026
@clawsweeper

clawsweeper Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix(gateway): reject unknown session agents instead of provisioning them This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@steipete
steipete force-pushed the claude/fix-sessions-lazy-agent-create branch from 2121e66 to ba8a473 Compare July 19, 2026 03:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2121e66197

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// requested page when the same transcript was copied during a store migration.
limit: configured ? params.limit : 25,
...(targetSessionKeys ? { sessionKeys: targetSessionKeys } : {}),
...(target ? { storePath: target.storePath } : {}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep legacy-only transcript searches read-only

When an unconfigured agent exists only in a fixed legacy sessions.json, passing its storePath into searchSessionTranscripts resolves the sibling SQLite path and opens it through writable openOpenClawAgentDatabase. This provisions and registers the agent during sessions.search; worse, subsequent discovery sees the new empty SQLite database as authoritative and ignores the legacy file, so sessions.describe can no longer find the previously readable session. Use a read-only/missing-database search path instead of creating the derived store.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 19, 2026
@clawsweeper

clawsweeper Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 19, 2026, 12:07 AM ET / 04:07 UTC.

Summary
The PR prevents gateway session read, search, and abort requests for unknown agent IDs from provisioning persistent agent stores, while retaining access to configured, retired, legacy, shared-store, and active-run sessions.

PR surface: Source +284, Tests +884, Other +1. Total +1169 across 15 files.

Reproducibility: yes. from source inspection: use a fixed legacy-only sessions.json for an unconfigured agent, invoke gateway transcript search, and observe that the current changed path resolves and opens the sibling SQLite target. The supplied PR material did not include a runnable after-fix transcript to verify the full scenario live.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: src/config/sessions/legacy-store-readonly.ts, serialized state: src/config/sessions/session-accessor.sqlite-entry-store.ts, serialized state: src/config/sessions/session-transcript-search.ts, serialized state: src/config/sessions/targets.test.ts, serialized state: src/config/sessions/targets.ts, serialized state: src/gateway/server-methods/sessions-abort.test.ts, and 15 more. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦪 silver shellfish
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix the writable legacy-only transcript-search path and cover the no-provisioning invariant.
  • [P1] Avoid fixed-store discovery for configured agents unless an alternate target is genuinely required.
  • [P1] Add a redacted real gateway transcript or terminal artifact; after updating the PR body, request @clawsweeper re-review only if automatic re-review does not occur.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body provides tests and autoreview claims but no inspectable after-fix runtime evidence; add a redacted gateway run showing unknown describe/search/abort creates no state while a legacy-only retired agent remains readable and searchable. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] Merging the current transcript-search path can still create and register a SQLite store for a legacy-only agent, then cause subsequent session lookup to prefer an empty derived store over readable legacy sessions.
  • [P1] Configured fixed-store gateway reads can now incur an extra read-only database open and an O(number of sessions) key scan despite already having an authoritative configured store.
  • [P1] The behavior is session-state and availability sensitive: the intended fix changes how existing retired and legacy agent sessions are resolved, so after-fix proof must cover both unknown-agent non-provisioning and preserved legacy-session access.

Maintainer options:

  1. Fix the read-only legacy path (recommended)
    Route legacy-only transcript searches through a non-provisioning reader and add a regression that verifies no SQLite, registry row, or agent directory is created.
  2. Defer configured-store discovery
    Avoid resolveExistingAgentSessionStoreTargetsSync when a configured fixed store is already authoritative, preserving the discovery path only where alternate persisted targets are necessary.
  3. Pause if legacy-search semantics cannot stay safe
    Do not merge until maintainers choose a supported read-only legacy transcript-search contract that preserves existing data without provisioning derived state.

Next step before merge

  • [P1] The remaining defects are concrete, but the protected maintainer label and session-state boundary require explicit maintainer review rather than automated repair dispatch.

Security
Cleared: The diff is security-relevant because it removes an unintended state-creation path, but the reviewed changes introduce no separate concrete credential, authorization, dependency, workflow, or supply-chain concern.

Review findings

  • [P1] Keep legacy-only transcript searches non-provisioning — src/config/sessions/session-transcript-search.ts:55-65
  • [P2] Skip persisted-target discovery for configured fixed stores — src/gateway/session-utils.ts:1332-1336
Review details

Best possible solution:

Keep the reject-unknown boundary, make legacy-only transcript search use a genuinely non-provisioning reader or skip SQLite transcript search for that target, and defer persisted-target discovery until it is needed for an unconfigured or template-backed agent.

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

Yes from source inspection: use a fixed legacy-only sessions.json for an unconfigured agent, invoke gateway transcript search, and observe that the current changed path resolves and opens the sibling SQLite target. The supplied PR material did not include a runnable after-fix transcript to verify the full scenario live.

Is this the best way to solve the issue?

No: rejecting truly unknown agents is the right policy, but the implementation must not reopen a writable derived SQLite store for legacy-only targets or scan configured fixed stores unnecessarily.

Full review comments:

  • [P1] Keep legacy-only transcript searches non-provisioning — src/config/sessions/session-transcript-search.ts:55-65
    The earlier P1 remains: storePath now selects the legacy store's derived SQLite path, but this function still opens it with the writable database accessor. Searching a retired agent that exists only in fixed sessions.json can therefore provision/register an empty SQLite database and make later lookup prefer it over the legacy session. Use a read-only/missing-store path or skip SQLite search for a legacy-only target.
    Confidence: 0.98
  • [P2] Skip persisted-target discovery for configured fixed stores — src/gateway/session-utils.ts:1332-1336
    The new resolver calls resolveExistingAgentSessionStoreTargetsSync before the configured fixed-store branch discards its result. That adds a read-only database open and a full session_entries key scan to ordinary configured gateway lookups; defer discovery until an unconfigured or template-backed agent actually needs alternate persisted targets.
    Confidence: 0.96

Overall correctness: patch is incorrect
Overall confidence: 0.97

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against cc57514e680d.

Label changes

Label changes:

  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🧂 unranked krab, so this older rating label is no longer current.

Label justifications:

  • P1: The patch targets operator-accessible gateway session paths and the remaining legacy-only search path can still alter persistent session ownership and make existing sessions unavailable.
  • merge-risk: 🚨 session-state: The changed resolution logic can create a derived store and shadow a legacy session store for a retired agent.
  • merge-risk: 🚨 availability: The added unconditional persisted-store discovery can add an O(session-count) scan to configured gateway reads, while the legacy-store issue can make expected sessions disappear from later lookup.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body provides tests and autoreview claims but no inspectable after-fix runtime evidence; add a redacted gateway run showing unknown describe/search/abort creates no state while a legacy-only retired agent remains readable and searchable. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +284, Tests +884, Other +1. Total +1169 across 15 files.

View PR surface stats
Area Files Added Removed Net
Source 9 328 44 +284
Tests 5 885 1 +884
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 1 1 0 +1
Total 15 1214 45 +1169

What I checked:

  • Prior blocker remains in transcript search: The current head adds storePath resolution, then still opens the resolved sibling SQLite target with the writable openOpenClawAgentDatabase path; for a legacy-only fixed sessions.json, this can recreate the provisioning side effect and make the new empty SQLite store authoritative over the legacy data. (src/config/sessions/session-transcript-search.ts:55, 40a30a3c6293)
  • Configured-store lookup now performs unnecessary discovery: The new candidate resolver unconditionally calls resolveExistingAgentSessionStoreTargetsSync; the reviewed follow-up identifies that configured fixed-store lookups then discard that result after a read-only database open and complete session-key scan. (src/gateway/session-utils.ts:1332, 40a30a3c6293)
  • Review continuity: The legacy transcript-search provisioning defect was raised in the previous completed ClawSweeper review, and the current reviewed head is 40a30a3c629365f3da241157842a476c4c6ded00; the supplied current diff still contains the writable open path. (src/config/sessions/session-transcript-search.ts:55, 40a30a3c6293)
  • Proof remains absent from supplied PR material: The PR body reports tests and autoreview, but does not include a redacted runtime transcript, terminal output, recording, log, or linked artifact showing unknown and legacy-only gateway calls after the fix. (40a30a3c6293)

Likely related people:

  • steipete: The PR timeline assigns this gateway/session-store repair to steipete, and the supplied PR body says the reject-unknown direction was selected for this change. (role: assigned current implementation owner; confidence: medium; commits: 40a30a3c6293; files: src/gateway/server-methods/sessions-read.ts, src/gateway/server-methods/sessions-abort.ts, src/gateway/session-utils.ts)
  • chatgpt-codex-connector[bot]: Its two concrete review comments identify the legacy-store provisioning regression and configured-store hot-path scan in the current change surface. (role: prior and follow-up reviewer; confidence: high; files: src/config/sessions/session-transcript-search.ts, src/gateway/session-utils.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-07-19T03:44:37.625Z sha ba8a473 :: needs real behavior proof before merge. :: [P1] Keep legacy-only transcript searches read-only

@steipete
steipete force-pushed the claude/fix-sessions-lazy-agent-create branch from ba8a473 to 40a30a3 Compare July 19, 2026 03:58
@openclaw-barnacle openclaw-barnacle Bot added scripts Repository scripts agents Agent runtime and tooling labels Jul 19, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 19, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 40a30a3c62

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1333 to +1335
return {
existing: resolveExistingAgentSessionStoreTargetsSync(cfg, agentId),
fallback,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Skip existing-store discovery for configured fixed-store agents

When session.store is a fixed path and the requested agent is configured, every loadSessionEntry-style lookup now calls resolveExistingAgentSessionStoreTargetsSync, which opens the SQLite database read-only and selects every persisted session key. The result is then discarded because the configured branch always prepends fallback and filters the identical existing path. This adds a second database open and an O(number of sessions) query to hot Gateway reads and mutations; defer existing-store discovery until the agent is unconfigured, or only perform it for template-backed stores where alternate paths can exist.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 19, 2026
@steipete
steipete merged commit 16e967e into main Jul 19, 2026
219 of 227 checks passed
@steipete
steipete deleted the claude/fix-sessions-lazy-agent-create branch July 19, 2026 04:16
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

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

Labels

agents Agent runtime and tooling gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. scripts Repository scripts size: XL status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant