Skip to content

fix(sessions): exclude done sessions from transcript freshness rollover guard#99985

Merged
steipete merged 5 commits into
openclaw:mainfrom
SunnyShu0925:fix/done-session-transcript-guard-99964
Jul 6, 2026
Merged

fix(sessions): exclude done sessions from transcript freshness rollover guard#99985
steipete merged 5 commits into
openclaw:mainfrom
SunnyShu0925:fix/done-session-transcript-guard-99964

Conversation

@SunnyShu0925

@SunnyShu0925 SunnyShu0925 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Successful main sessions (status: "done") can roll over to new session IDs and archive transcript as .jsonl.reset.* when the transcript file mtime is slightly newer than the registry updatedAt, even though the session completed successfully.

  • Problem: resolveTerminalMainSessionTranscriptRegistryCheck applies the transcript freshness guard to status: "done" rows, forcing unnecessary session rotation on the next inbound message.
  • Solution: Exclude status: "done" from the guard alongside the already-excluded status: "failed", so successful sessions stay reusable.
  • What changed: One condition in src/config/sessions/lifecycle.ts (core fix), test expectations in 3 test files.
  • What did NOT change: killed/timeout still guarded; endedAt-only terminal rows still guarded; no config/API/docs changes.

Change Type

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Motivation

After a main session completes successfully (status: "done"), the next user message should reuse the same session. However, when the transcript file's mtime is slightly newer than the session registry's updatedAt (which can happen due to filesystem I/O timing — the transcript write may land after the registry update), hasTerminalMainSessionTranscriptNewerThanRegistry returns true, causing canReuseSession to be false. This forces a new UUID session and archives the old transcript as .jsonl.reset.*.

Three call paths are affected:

  1. Gateway agent session admission (src/gateway/server-methods/agent.ts:1956-1970)
  2. CLI command session resolver (src/agents/command/session.ts:379-389)
  3. Auto-reply session (src/auto-reply/reply/session.ts:548)

All three use the same shared guard function, so fixing it in one place covers all paths.

Evidence

  • Behavior addressed: resolveTerminalMainSessionTranscriptRegistryCheck() now returns undefined for status: "done" rows, preventing transcript-mtime-based rollover for successful completions.

  • Real environment tested: Linux x86_64, Node 22.19, branch fix/done-session-transcript-guard-99964

  • Exact steps or command run after this patch:

node --import tsx /media/vdb/code/github/contributions/pr-99964-evidence/full-chain-proof.ts
node scripts/run-vitest.mjs src/commands/agent.session.test.ts --run
node scripts/run-vitest.mjs src/auto-reply/reply/session.test.ts --run -t "terminal"
node scripts/run-vitest.mjs src/gateway/server-methods/agent.test.ts --run -t "terminal"
  • Evidence after fix:
============================================================
  PR #99964 Full-Chain Live Proof
============================================================

  Session status: done | transcript mtime > registry: YES

  [Layer 1] Guard function (shared by Gateway + CLI + Auto-reply)
    hasTerminalMainSessionTranscriptNewerThanRegistrySync() = false
    => PASS: Guard skipped for done sessions (enables reuse)

  [Layer 2] CLI resolveSession() - proven by passing test
    Test: 'reuses status-done terminal main sessions'
    File: src/commands/agent.session.test.ts
    Assertions: isNewSession=false, sessionId matches original
    => PASS (test suite: 8/8 passed)

  [Layer 3] Gateway handler - proven by passing test
    Test: 'reuses a status-done terminal main session when its transcript is newer'
    File: src/gateway/server-methods/agent.test.ts
    => PASS (test suite: 20/20 terminal tests passed)

  [Layer 4] Auto-reply session - proven by passing test
    Test: 'main status-done terminal rows reuse when transcript is newer'
    File: src/auto-reply/reply/session.test.ts
    => PASS (6/6 terminal tests passed)

  [Behavior Matrix] All 3 call paths, all session states
  +----------------+--------+-------------+----------+-----------+
  | Status         | mtime  | Before fix  | After fix | Guard    |
  +----------------+--------+-------------+----------+---------+
  | done           | > reg  | Rotation    | Reuses   | false    |
  | failed         | > reg  | Reuses      | Reuses   | false    |
  | killed         | > reg  | Rotation    | Rotation | true     |
  | timeout        | > reg  | Rotation    | Rotation | true     |
  | endedAt-only   | > reg  | Rotation    | Rotation | true     |
  +----------------+--------+-------------+----------+---------+

  ALL LAYERS PASSED
Test file Result
src/commands/agent.session.test.ts 8 passed
src/auto-reply/reply/session.test.ts (terminal) 6 passed, 108 skipped
src/gateway/server-methods/agent.test.ts (terminal) 20 passed, 308 skipped
  • Observed result after fix:

    1. status: "done" sessions with newer transcript mtime no longer trigger session rollover
    2. failed sessions remain reusable (existing behavior preserved)
    3. killed/timeout/endedAt-only sessions remain guarded (existing behavior preserved)
    4. All existing tests updated and pass
  • What was not tested: Full Gateway with a real remote model provider — the session reuse decision happens before any model call, so mocked model responses in the Gateway tests prove the same code path. All 4 layers (guard function, CLI resolveSession, Gateway handler, auto-reply) are covered.

Root Cause

In resolveTerminalMainSessionTranscriptRegistryCheck() (src/config/sessions/lifecycle.ts:162-184):

const hasTerminalLifecycle =
    isTerminalSessionStatus(params.entry.status) ||  // "done" is terminal
    resolvePositiveTimestamp(params.entry.endedAt) !== undefined;
if (!hasTerminalLifecycle) { return undefined; }
if (params.entry.status === "failed") {
    // Only "failed" was excluded — "done" fell through to the guard
    return undefined;
}

isTerminalSessionStatus() includes "done", "failed", "killed", "timeout" — but only "failed" was excluded from the mtime check, leaving "done" (successful completion) unprotected.

Provenance: Introduced in af906225fa (Fermin Quant, 2026-06-25) as part of PRs #0c9ac48d and #57bed6ae which added the terminal-main transcript freshness guard.

Alternative Approach Considered

Two approaches were considered:

Option A (chosen): Exclude status: "done" from the transcript freshness guard. Minimal change, low risk.

Option B (not chosen): Fix the persistence ordering so transcript mtime never exceeds registry updatedAt. This addresses the root cause (filesystem I/O timing), but involves more code paths and complexity. The persistence ordering issue is a known technical debt that could be addressed as a follow-up for other terminal states.

Option A was chosen because:

  • It directly fixes the user-facing bug with minimal risk
  • It follows the established pattern of excluding failure (same exclusion approach)
  • The guard remains active for abnormal terminal states (killed, timeout, endedAt-only) where transcript-continuity recovery logic is still important
  • A follow-up fix for persistence ordering would benefit all terminal states uniformly

User-visible / Behavior Changes

Successful main-agent sessions will no longer unexpectedly roll over to a new session ID when the transcript mtime is slightly newer than the registry updatedAt. The .jsonl.reset.* archive pattern will no longer appear for normal successful runs.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Regression Test Plan

  • Updated existing test expectation in src/gateway/server-methods/agent.test.ts for status: "done" case (now expects reuse instead of rotation)
  • Updated existing test expectation in src/commands/agent.session.test.ts for status: "done" cases (now expects reuse)
  • Updated existing test expectation in src/auto-reply/reply/session.test.ts for the default-done case
  • endedAt-only test cases unchanged (still assert rotation — guard remains active)
  • All 3 affected test suites pass

Human Verification

  • Verified scenarios: status-done with newer transcript (reuse), endedAt-only with newer transcript (rotation), failed with newer transcript (reuse, unchanged), killed/timeout with newer transcript (rotation, unchanged)
  • Edge cases checked: main session aliases (canonical, raw, custom) with done status; explicit session-id resume still works
  • What you did NOT verify: Full Gateway E2E; real agent run producing the mtime ordering race

Compatibility / Migration

  • Backward compatible? Yes — only relaxes session reuse, never tightens
  • Config/env changes? No
  • Migration needed? No

Best-fix Verdict

  • Best fix: Yes. The shared guard function is the right boundary because all three affected call paths (gateway, CLI, auto-reply) already depend on it. Adding the condition inline is minimal and follows the existing failed exclusion pattern.
  • Refactor needed: No. A follow-up to fix persistence ordering (Option B) could be filed separately.
  • Alternative considered: Fix persistence ordering so updatedAt >= transcript mtime. This is a deeper fix but involves more risk and wasn't necessary for this bug.

Risks and Mitigations

  • Lowest risk: Only relaxes the guard for successful completions (status: "done"). Abnormal terminal states (killed, timeout, endedAt-only) remain fully guarded.
  • Familiar pattern: Follows the exact same approach as the existing failed exclusion.
  • Test coverage: All 3 call paths covered by existing tests, with updated expectations for the new behavior.

AI Assistance

  • AI-assisted: Yes
  • Co-Authored-By: Claude Opus 4.8 [email protected]
  • Human confirmed understanding of code changes: Yes

Fixes #99964

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime commands Command implementations size: M labels Jul 4, 2026
@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 1:54 AM ET / 05:54 UTC.

Summary
This PR excludes successful done main sessions from the transcript freshness rollover guard and updates Gateway, CLI, and auto-reply tests to expect reuse while endedAt-only rows still rotate.

PR surface: Source +5, Tests +93. Total +98 across 4 files.

Reproducibility: yes. At source level, current main lets a status: "done" terminal main row with transcript mtime newer than updatedAt reach the guard, and Gateway, CLI, and auto-reply use that result to block reuse.

Review metrics: 1 noteworthy metric.

  • Terminal guard status handling: 1 status newly excluded. Excluding done from this shared guard changes whether main session ids and transcripts are preserved or rotated across Gateway, CLI, and auto-reply paths.

Stored data model
Persistent data-model change detected: serialized state: src/auto-reply/reply/session.test.ts, serialized state: src/commands/agent.session.test.ts, serialized state: src/gateway/server-methods/agent.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #99964
Summary: This PR is a candidate fix for the canonical issue about successful done main sessions rolling over when transcript mtime is newer than registry metadata; sibling PRs target the same root cause, but none has merged.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

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

Risk before merge

  • [P1] Merging changes the shared decision that preserves or rotates main session ids, transcript files, and CLI session bindings across Gateway, CLI command resolution, and auto-reply paths.
  • [P1] fix(sessions): reuse successful main sessions after completed runs #99975 targets the same root cause and overlaps textually, so maintainers should choose one canonical PR and close the sibling after merge.

Maintainer options:

  1. Land this as the canonical fix (recommended)
    Accept the session-state semantics in this PR, merge it as the canonical fix, and close the same-root sibling PRs afterward.
  2. Pick the sibling fix instead
    If maintainers prefer another same-root branch, make that PR prove the same Gateway, CLI, and auto-reply behavior before closing this one as superseded.
  3. Hold for fuller live proof
    Pause landing until a maintainer-requested full Gateway or CLI transcript reuse run proves the behavior in a broader real setup.

Next step before merge

  • No automated repair is needed; maintainers should choose the canonical same-root PR and accept the session-state behavior change before merge.

Maintainer decision needed

  • Question: Should this PR be the canonical fix for Successful main sessions can roll over as .jsonl.reset when transcript mtime is newer than registry updatedAt #99964, accepting the shared session reuse behavior change and closing sibling PRs after merge?
  • Rationale: The patch and proof are strong, but the change affects session-state rollover semantics across multiple entry points and another open PR targets the same root cause.
  • Likely owner: obviyus — They merged the original terminal-main transcript reconciliation PR and authored adjacent registry-marker work, making them the strongest routing candidate for the session-state tradeoff.
  • Options:
    • Land this PR as canonical (recommended): Use this branch because it covers the shared helper plus Gateway, CLI, and auto-reply expectations with after-fix live output and a clean check rollup.
    • Choose the sibling branch: Use fix(sessions): reuse successful main sessions after completed runs #99975 instead only if maintainers prefer that proof or branch history, then close this PR as superseded.
    • Request broader end-to-end proof: Ask for a packaged Gateway or CLI transcript reuse run before selecting a canonical branch if focused guard and caller proof is not enough for this session-state change.

Security
Cleared: The diff only changes local TypeScript session lifecycle logic and tests; it does not touch secrets, dependencies, workflows, downloads, permissions, or package execution paths.

Review details

Best possible solution:

Land one canonical lifecycle-helper fix that skips the guard for successful done rows, preserves endedAt-only and interrupted-state rollover, then close the same-root sibling PRs and linked issue after merge.

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

Yes. At source level, current main lets a status: "done" terminal main row with transcript mtime newer than updatedAt reach the guard, and Gateway, CLI, and auto-reply use that result to block reuse.

Is this the best way to solve the issue?

Yes. The shared lifecycle helper is the narrowest maintainable boundary, and the PR updates all three caller expectations while preserving endedAt-only and interrupted-state rollover; the remaining question is canonical branch selection.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P1: The PR targets a current session-continuity regression where successful main-agent runs can unexpectedly roll into a new session id and reset archive.
  • merge-risk: 🚨 session-state: The diff changes the shared decision that preserves or rotates main session ids, transcript files, and CLI session bindings.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes copied after-fix live output from a Linux/Node setup showing the changed guard behavior plus focused test results for the affected caller surfaces.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied after-fix live output from a Linux/Node setup showing the changed guard behavior plus focused test results for the affected caller surfaces.
Evidence reviewed

PR surface:

Source +5, Tests +93. Total +98 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 1 6 1 +5
Tests 3 160 67 +93
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 166 68 +98

What I checked:

Likely related people:

  • ferminquant: Authored the merged terminal-main transcript reconciliation commits that added the lifecycle helper and affected Gateway, CLI, and auto-reply admission paths. (role: introduced guard behavior; confidence: high; commits: 0c9ac48d2cc7, 57bed6ae0c4b; files: src/config/sessions/lifecycle.ts, src/gateway/server-methods/agent.ts, src/agents/command/session.ts)
  • obviyus: Merged the original reconciliation PR and authored nearby registry-marker commits in the same session transcript area. (role: merger and adjacent contributor; confidence: high; commits: 0c9ac48d2cc7, 57bed6ae0c4b, ceee4c6b019c; files: src/config/sessions/lifecycle.ts, src/config/sessions/transcript.ts, src/agents/command/session.ts)
  • Jerry-Xin: Authored recent terminal-session recovery work near visible inbound reuse behavior for Gateway and auto-reply paths. (role: recent adjacent contributor; confidence: medium; commits: 6f90ee4cb895; files: src/gateway/server-methods/agent.ts, src/gateway/server-methods/agent.test.ts, src/auto-reply/reply/session.ts)
  • jalehman: Recently refactored reply session initialization guard boundaries near the rollover admission path. (role: adjacent guard refactor contributor; confidence: medium; commits: 95e37f8e9517; files: src/gateway/server-methods/agent.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 (5 earlier review cycles)
  • reviewed 2026-07-04T14:19:05.647Z sha ce28347 :: needs real behavior proof before merge. :: [P2] Remove the stale status spread | [P3] Fix the mtime direction in the comment
  • reviewed 2026-07-04T14:32:12.432Z sha b1ce0ce :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-04T14:37:49.792Z sha b1ce0ce :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T14:44:09.713Z sha b1ce0ce :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T13:26:48.564Z sha b1ce0ce :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. 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. labels Jul 4, 2026
@SunnyShu0925

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

All ClawSweeper findings have been addressed:

  • [P1] TS type error: Fixed in 8faf707 (removed stale status spread + added as const)
  • [P1] Real behavior proof: Added live guard proof showing behavior matrix
  • [P2] Stale status spread: Removed
  • [P3] Comment direction: Fixed in b1ce0ce (trail -> exceed)

@clawsweeper

clawsweeper Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 4, 2026
@SunnyShu0925

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels Jul 5, 2026
@AmirF194

AmirF194 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Reviewed at head b1ce0ce. The fix is correct and lands at the right boundary.

Confirmed the bug on main: resolveTerminalMainSessionTranscriptRegistryCheck excludes only "failed" (src/config/sessions/lifecycle.ts:168), so status:"done" rows fall through to the transcript-mtime guard. That guard feeds canReuseSession in the gateway (src/gateway/server-methods/agent.ts:2251) and the equivalent fresh checks in src/agents/command/session.ts:383 and src/auto-reply/reply/session.ts:624, so a successful session whose transcript mtime is slightly newer than registry updatedAt rolls to a new id and archives its transcript. Excluding "done" alongside "failed" fixes all three paths at their shared seam.

Good points:

  • Right boundary — the one shared guard covers gateway/CLI/auto-reply; no logic duplicated.
  • Not re-deriving terminal state: entry.status is the persisted session-registry status (isTerminalSessionStatus, src/config/sessions/types.ts:453), which is distinct from agent-run outcome normalization in src/agents/agent-run-terminal-outcome.ts — that rule doesn't apply here.
  • Tests exercise the real guard against real fs.utimes transcripts, and the retained "rotates endedAt-only …" test proves killed/timeout/endedAt-only stay guarded.
  • No config/schema/migration impact; only relaxes reuse, so it's backward compatible.

One thing that needs a maintainer decision before merge: this overlaps with #99975 (and #99971, named in the body). #99975 makes a functionally identical change to the same lines in lifecycle.ts and edits the same three test files — the only difference is it uses a separate if (status === "done") branch instead of folding done into the failed condition. The two conflict textually and cannot both merge; exactly one should land and the others close as duplicates. This PR carries the stronger test split and provenance, so it's a reasonable one to keep, but that's a maintainer call.

Minor (non-blocking): the combined branch now shares one comment block for two different rationales (failed = retry/recovery, done = persistence-ordering). If you keep this PR, consider a one-line separation so the done rationale stays legible.

I did not run the suite locally; the PR's cited run-vitest invocations look appropriate for the touched files.

@SunnyShu0925

SunnyShu0925 commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@AmirF194 addressed in edd1b14 — added a blank comment line to separate the failed/done rationales. Thank you!

SunnyShu0925 and others added 5 commits July 6, 2026 11:51
…ollover guard

Exclude status: "done" from resolveTerminalMainSessionTranscriptRegistryCheck alongside the already-excluded status: "failed". Successful main sessions should stay reusable for the next user message even when transcript mtime slightly exceeds registry updatedAt.

Updated test expectations in:
- src/gateway/server-methods/agent.test.ts (split it.each into done-reuse + endedAt-only-rotate)
- src/commands/agent.session.test.ts (split into done-reuse + endedAt-only-rotate)
- src/auto-reply/reply/session.test.ts (default-done case now expects reuse)

Related to openclaw#99964

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Remove the conditional status spread that TS cannot resolve when
status is absent from the scenario type, and add 'as const' for
narrowed literal inference.
@steipete
steipete force-pushed the fix/done-session-transcript-guard-99964 branch from ee92570 to cd1b627 Compare July 6, 2026 15:51
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Maintainer repair is land-ready at cd1b627e62d9c3e44e387570e5d230891753ac6d.

  • Before: a completed main session could be rotated merely because final transcript persistence made its mtime newer than the registry row.
  • After: status: "done" reuses the existing session ID, while killed/timeout, endedAt-only, and failed recovery retain their established behavior.
  • Repair: centralized the distinction in the shared lifecycle helper and compacted Gateway, CLI, and auto-reply coverage into existing table/helper shapes.
  • Local lightweight checks: git diff --check; targeted formatting was verified with oxfmt.
  • Exact-head proof: full hosted CI is green: https://github.com/openclaw/openclaw/actions/runs/28804508852
  • Fresh autoreview: no accepted/actionable findings.

Known gap: no released binary was seeded; deterministic filesystem/session-store regressions cover every admission caller and terminal-state branch.

@steipete
steipete merged commit e580ed2 into openclaw:main Jul 6, 2026
96 checks passed
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 7, 2026
…er guard (openclaw#99985)

* [AI] fix(sessions): exclude done sessions from transcript freshness rollover guard

Exclude status: "done" from resolveTerminalMainSessionTranscriptRegistryCheck alongside the already-excluded status: "failed". Successful main sessions should stay reusable for the next user message even when transcript mtime slightly exceeds registry updatedAt.

Updated test expectations in:
- src/gateway/server-methods/agent.test.ts (split it.each into done-reuse + endedAt-only-rotate)
- src/commands/agent.session.test.ts (split into done-reuse + endedAt-only-rotate)
- src/auto-reply/reply/session.test.ts (default-done case now expects reuse)

Related to openclaw#99964

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* fix(ts): fix TypeScript error in endedAt-only test scenario type

Remove the conditional status spread that TS cannot resolve when
status is absent from the scenario type, and add 'as const' for
narrowed literal inference.

* [AI] fix(comment): correct mtime direction in done exclusion comment

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* review: separate failed/done rationale in comment

* fix(sessions): reuse completed main transcripts

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…er guard (openclaw#99985)

* [AI] fix(sessions): exclude done sessions from transcript freshness rollover guard

Exclude status: "done" from resolveTerminalMainSessionTranscriptRegistryCheck alongside the already-excluded status: "failed". Successful main sessions should stay reusable for the next user message even when transcript mtime slightly exceeds registry updatedAt.

Updated test expectations in:
- src/gateway/server-methods/agent.test.ts (split it.each into done-reuse + endedAt-only-rotate)
- src/commands/agent.session.test.ts (split into done-reuse + endedAt-only-rotate)
- src/auto-reply/reply/session.test.ts (default-done case now expects reuse)

Related to openclaw#99964

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* fix(ts): fix TypeScript error in endedAt-only test scenario type

Remove the conditional status spread that TS cannot resolve when
status is absent from the scenario type, and add 'as const' for
narrowed literal inference.

* [AI] fix(comment): correct mtime direction in done exclusion comment

Co-Authored-By: Claude Opus 4.8 <[email protected]>

* review: separate failed/done rationale in comment

* fix(sessions): reuse completed main transcripts

---------

Co-authored-by: Claude Opus 4.8 <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations gateway Gateway runtime 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. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Successful main sessions can roll over as .jsonl.reset when transcript mtime is newer than registry updatedAt

3 participants