Skip to content

fix: keep root session span open across session.idle#70

Closed
schemaitat wants to merge 3 commits into
DEVtheOPS:mainfrom
schemaitat:main
Closed

fix: keep root session span open across session.idle#70
schemaitat wants to merge 3 commits into
DEVtheOPS:mainfrom
schemaitat:main

Conversation

@schemaitat

@schemaitat schemaitat commented Jun 23, 2026

Copy link
Copy Markdown

Summary

  • The opencode.session span and accumulated session totals were ended and deleted on the first session.idle event. Since a session keeps receiving turns after going idle, every subsequent turn's LLM/tool spans had no local session span to nest under and became orphaned root traces, with their token/cost contributions silently dropped from session.total_*.
  • Keep the session span and totals alive across session.idle (only snapshotting attributes), and finalize them in a new session.deleted handler, on session.error, or on process shutdown.

Supersedes #64, which had the same fix but went stale against main after #67/#68/#69 landed. This PR is rebased directly on current main (via schemaitat:main, already merged with upstream) so the diff is clean.

Test plan

  • bun test (282 pass)
  • bun run typecheck
  • bun --bun eslint src/handlers/session.ts tests/handlers/spans.test.ts
  • bun run build

Summary by CodeRabbit

  • New Features

    • Added support for explicit session deletion with proper telemetry finalization.
  • Improvements

    • Sessions now maintain metrics and state across multiple interactions instead of resetting on each turn, improving continuous session tracking.
    • Session cleanup is now performed on deletion rather than on each idle event.

schemaitat and others added 3 commits June 13, 2026 08:19
The opencode.session span and accumulated session totals were ended and
deleted on the first session.idle event. Since a session keeps receiving
turns after going idle, every subsequent turn's LLM/tool spans had no
local session span to nest under and became orphaned root traces, and
their token/cost contributions were silently dropped from
session.total_*.

Keep the session span and totals alive across session.idle (only
snapshotting attributes), and finalize them in a new session.deleted
handler, on session.error, or on process shutdown.
…havior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Brings in upstream's agent-metadata support (PR DEVtheOPS#67, DEVtheOPS#69) and the
fix/issue-45 probe validation/release commits, on top of the
session-span-stays-open-across-idle fix merged from
fix/session-span-spans-whole-session.

Resolved conflicts in src/handlers/session.ts and
tests/handlers/spans.test.ts by keeping the session span/totals open
across session.idle (this fork's fix) while also recording the
agent.type attribute introduced upstream.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 42cd10c3-35a1-40ed-bc08-04db15d9652f

📥 Commits

Reviewing files that changed from the base of the PR and between c9fee7f and cbb3f56.

📒 Files selected for processing (4)
  • src/handlers/session.ts
  • src/index.ts
  • tests/handlers/session.test.ts
  • tests/handlers/spans.test.ts

📝 Walkthrough

Walkthrough

The PR separates session span teardown into two distinct lifecycle events. handleSessionIdle now retains the root opencode.session span and accumulated totals across turns, only sweeping per-turn pending state. A new handleSessionDeleted handler performs terminal cleanup: finalizing the span with accumulated totals, setting status to OK, and clearing context state. index.ts wires the new event and extends shutdown() to finalize any remaining open spans.

Changes

Session span lifecycle: idle vs. deleted

Layer / File(s) Summary
handleSessionIdle and handleSessionDeleted logic
src/handlers/session.ts
handleSessionIdle no longer ends the session span or deletes totals on idle; it sweeps only per-turn pending state. New exported handleSessionDeleted performs terminal cleanup: deletes totals/diff totals, sweeps pending state, ends the root span with final totals and OK status, and removes it from ctx.sessionSpans. EventSessionDeleted is added to imports.
index.ts wiring and shutdown finalization
src/index.ts
Imports SpanStatusCode, EventSessionDeleted, and handleSessionDeleted. Routes "session.deleted" events to handleSessionDeleted. Extends shutdown() to iterate sessionSpans, apply accumulated totals as attributes, set OK status, end each span, and clear the map before OTEL provider teardown.
Unit and span lifecycle tests
tests/handlers/session.test.ts, tests/handlers/spans.test.ts
handleSessionIdle tests now assert sessionTotals persists after idle. New handleSessionDeleted tests verify totals/diff totals are removed and the session span is ended and cleared. Span lifecycle tests replace prior idle-ends-span assertions with open-span assertions and add a test confirming subsequent-turn LLM spans nest under the still-open session span.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • DEVtheOPS/opencode-plugin-otel#8: Directly modifies src/handlers/session.ts session lifecycle instrumentation including ctx.sessionTotals and span cleanup, the same state points this PR restructures.
  • DEVtheOPS/opencode-plugin-otel#44: Modifies sessionTotals/sessionDiffTotals cleanup paths in src/handlers/session.ts on idle and deletion, overlapping directly with the lifecycle changes here.
  • DEVtheOPS/opencode-plugin-otel#69: Touches handleSessionIdle, session span attributes, and associated tests in the same files modified by this PR.

Suggested reviewers

  • dialupdisaster
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: keeping the root session span open across idle events, which is the core fix described in the PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@schemaitat

Copy link
Copy Markdown
Author

Superseded by #71 — same fix, moved to a dedicated branch per CONTRIBUTING.md (this one was opened directly from main) and squashed into a single Conventional-Commits-compliant commit.

@schemaitat schemaitat closed this Jun 23, 2026
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