refactor(sessions): route get-reply-run session refresh through the accessor#104880
Conversation
…ccessor Drops the last non-doctor whole-store resolveSessionStoreEntry read in the reply pipeline; exact working-set key plus accessor disk read match the sibling refresh sites in runPreparedReply. Part of #104219 (seam 8).
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
|
CI triage: the two failing checks are current Both failures reproduce on a clean
This PR's diff is Passing proof for this PR's own surface: |
|
Codex review: needs maintainer review before merge. Reviewed July 11, 2026, 10:53 PM ET / July 12, 2026, 02:53 UTC. Summary PR surface: Source +6, Tests -11, Other -1. Total -6 across 3 files. Reproducibility: not applicable. this is an architectural refactor rather than a reported failing behavior, and equivalence is established through source invariants plus runtime proof. Review metrics: none identified. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Run the normal exact-head merge gates and land this narrow accessor-boundary cleanup without expanding session APIs, compatibility paths, or product behavior. Do we have a high-confidence way to reproduce the issue? Not applicable; this is an architectural refactor rather than a reported failing behavior, and equivalence is established through source invariants plus runtime proof. Is this the best way to solve the issue? Yes; routing the residual caller through the existing accessor is the narrowest maintainable solution and preserves both the exact-key working set and legacy alias resolution. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 5e064bb7b4b7. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +6, Tests -11, Other -1. Total -6 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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
Review history (1 earlier review cycle)
|
|
Real behavior proof added (PR body Evidence updated). Ephemeral gateway built from this branch (
@clawsweeper re-review |
What Problem This Solves
src/config/sessions/session-accessor.tsis the storage-neutral session boundary (ownership contract #88838), and most historical bypasses were already rerouted by #98236/#101179. One non-doctor whole-store read remained in the reply pipeline:runPreparedReply(src/auto-reply/reply/get-reply-run.ts) still importedresolveSessionStoreEntryfromsessions/store.jsand alias-scanned the in-memory session map to refresh the entry beforeonSessionPrepared. That is the layout-encoding pattern (wholeRecord+ map-shape alias walk) the accessor exists to hide, and it keptget-reply-run.tson the session-accessor debt baseline.This is seam 8 of #104219 (session store accessor bypass), scoped to the residual mechanical caller. Re-verification against current
mainshowed the seam is mostly complete upstream; the remaining bypasses are named owners (doctor whole-store scan/repair,state-migrations.ts) or shipped public surfaces (library.tsroot exports,plugin-sdk/session-store-runtime.ts) that need their own compatibility decision, not a mechanical reroute.Why This Change Was Made
The refresh now reads the working set by exact key and falls back to the accessor disk read, matching the two sibling refresh sites in the same function (
get-reply-run.ts:852,:865-867) and the exact-key write at:842:sessionStore[sessionKey]— the reply working set is exact-keyed everywhere else inrunPreparedReply, so the old alias walk over the map had no live dependency.loadSessionEntry({ storePath, sessionKey, readConsistency: "latest" })— the accessor read performs full canonical-key and legacy-alias resolution internally (session-accessor.sqlite.tsreadSessionEntryRow→collectSessionEntryLookupKeys), so legacy lowercase-alias repair is preserved whenever a store path is known.sessionEntryremains the terminal fallback, unchanged.The dead
store.runtime.jsmock inget-reply-run.media-only.test.tsis deleted (prod stopped importing it before this change; verified zeroupdateSessionStorereferences onmain). The session-accessor debt baseline is regenerated because the ratchet fails on improvements (get-reply-run.tsdrops off the debt list).User Impact
None intended — pure boundary refactor; same reads, same fallback order for live states. Reply handling, session refresh, and
onSessionPreparedpayloads behave identically. Maintainer impact: the reply pipeline no longer imports whole-store file APIs, and the debt ratchet shrinks by one file.Evidence
src/auto-reply/reply/get-reply-run.ts:842,852,865-867predate this change; the replaced call was the only alias-walking access in the function.loadSessionEntry→loadSqliteSessionEntry→readSessionEntryRowbuilds plural lookup keys (collectSessionEntryLookupKeys), covering normalized + folded-legacy candidates the deletedresolveSessionStoreEntryhandled.git diff --numstat: +11/−17 (net −6), no new accessor surface, no behavior branches added.pnpm lint:tmp:session-accessor-boundarypasses with the regenerated baseline (one-line deletion:get-reply-run.tsleaves the debt list).pnpm check:changedexit 0 on commit f6a6496; the six covering shards (incl. fullauto-reply-reply: 141 files / 3,071 tests, andgateway-server) pass in isolated reruns on the same lease. The two failing PR checks are current-mainbreakage, reproduced on cleanorigin/maindfa580e9— see the CI-triage comment.Real behavior proof (ephemeral gateway, real Telegram channel path)
Built this branch (
f6a64961427), ran a real gateway (tempOPENCLAW_STATE_DIR, loopback) with a mock Telegram Bot API (:18931) and mock OpenAI-completions provider (:18932), and drove two consecutive real reply turns through the Telegram channel intorunPreparedReply:sendMessagetextssession-proof-reply-1,session-proof-reply-2captured from the Bot API mock — ground truth).agents/main/agent/openclaw-agent.sqlite):sessionKey agent:main:telegram:group:-100777001, samesessionIdef4af902-…across both run traces,updatedAtadvanced1783824157995 → 1783824162754.session turn created/embedded run start/message processed … outcome=completedon the same sessionId — the refreshed prepared-session binding (the changed accessor-backed read) held across turns.Part of #104219 (seam 8: session store accessor bypass — residual mechanical caller; doctor and public-surface bypasses excluded as named owners).