Skip to content

refactor(server): move turn boundaries and the Devin session lookup into their own modules - #1765

Merged
devswha merged 1 commit into
mainfrom
refactor/transcript-turns-module
Oct 23, 2026
Merged

devswha merged 1 commit into
mainfrom
refactor/transcript-turns-module

Conversation

@devswha

@devswha devswha commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Wave C3 of the per-agent module split. The plan is .omo/plans/agent-modules-split.md in the maintainer's workspace, and plan-reviewer approved it. It follows C2 (#1763), which this wave builds on: StreamSource and ConversationUnavailable now come from server/conversation-shared.ts.

This wave moves two state-free clusters out of server/conversation.ts into new leaf modules. conversation.ts keeps every cache, paneReads (including Devin's per-pane reads), the paging core and the transcript resolvers. The three functions tests spy on (paneTranscript, readCommandTranscript, paneProcessRoots) stay.

What changes

  • server/transcript-turns.ts: the turn-boundary cluster, verbatim with its doc comments:

    • ClaudeBranch, claudeForks, answeredBetween, claudeCommandEchoRecord, CLAUDE_CHAIN_LINE_BYTES, followClaudeBranch;
    • PEER_MARK, TURN_MARK, opensTurn;
    • PromptChain, turnStarts.

    followClaudeBranch calls opensTurn, which turnStarts also needs, so the cluster moves as one module.

    export is added to the five names conversation.ts still uses: turnStarts, followClaudeBranch, claudeForks, and the types ClaudeBranch and PromptChain.

  • server/devin-session.ts: isDevinProcess and devinSessionForPane, verbatim. Both were already exported. conversation.ts re-exports them for server/session-history.ts and server/conversation.test.ts, so no importer changes.

  • conversation.ts imports: the imports from ./transcript-records.ts and ./claude-transcript.ts drop the names only the moved code used.

  • Not in this wave: rememberPaneDevin and DevinPaneRead stay, because they are fields of paneReads, which forgetPaneTranscriptState owns.

server/conversation.ts goes from 1,732 to 1,532 lines.

Checks

  • --color-moved: git diff --color-moved=plain --color-moved-ws=allow-indentation-change origin/main...HEAD shows 394 lines as moved. The other 23 lines are:

    • the two new files' imports;
    • conversation.ts's narrowed and new imports and its one re-export line;
    • the five declarations whose only change is the added export, each shown as removed and added.
  • No import cycles: bun <plan>/no-path.ts <new file> server/conversation.ts server/prompt.ts prints "no path to server/conversation.ts, server/prompt.ts" for both new files. They import only conversation-shared.ts, transcript-records.ts, claude-transcript.ts and shared/protocol.ts.

  • No new herdr calls: neither new file calls herdrRpc.

  • Typecheck: bun run typecheck passes.

  • Unit tests: 305 pass, 0 fail across 10 files, from:

    HERDR_TEST_MODE=unit bun test server/claude-turn-boundaries.test.ts server/native-incremental.test.ts server/chat-history.test.ts server/pi.test.ts server/pi-tree.test.ts server/pi-large-history.test.ts server/grok.test.ts server/cmd.test.ts server/conversation.test.ts server/devin.test.ts

  • bun run check fast: passes (unit 6253 pass, 0 fail, 13 skip in 443 files, 8 at a time, 58.7s)

  • Integration lane: runs in CI.

Outside PRs that touch the same files

No other maintainer PR touches these files. Three outside contributors' PRs touch server/conversation.ts: #1706, #1652 and #1442.

Move-only: moved declarations plus imports, five added exports and one re-export line. No changelog fragment: users see no change.

…nto their own modules

Move the Claude branch/turn-boundary code (ClaudeBranch, claudeForks, followClaudeBranch,
PromptChain, turnStarts and their helpers) verbatim into server/transcript-turns.ts, and
isDevinProcess/devinSessionForPane verbatim into server/devin-session.ts.
The moved names conversation.ts still uses gain `export`; conversation.ts re-exports
isDevinProcess and devinSessionForPane so importers are unchanged.
Plan: .omo/plans/agent-modules-split.md C3.
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between d6bf59b and 4e73598.

📒 Files selected for processing: 3
  • server/conversation.ts
  • server/devin-session.ts
  • server/transcript-turns.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.

📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Improved conversation session matching when multiple Devin panes are open, helping prevent conversations from being associated with the wrong session.
    • Improved transcript turn and branch tracking, including handling repeated prompts, peer-session messages, and command echoes.

Claude transcript branch tracking and turn detection now reside in transcript-turns.ts. Devin process detection and pane-session resolution now reside in devin-session.ts. conversation.ts imports these helpers and re-exports the Devin helpers.

Changes: Conversation helpers

Layer / File(s) Summary
Claude branch tracking
server/transcript-turns.ts, server/conversation.ts
transcript-turns.ts tracks Claude record ancestry, assistant answers, and prompt or command-echo forks. The local branch-tracking implementation is removed from conversation.ts.
Turn detection
server/transcript-turns.ts, server/conversation.ts
transcript-turns.ts identifies turn starts for supported transcript sources and tracks unanswered Claude prompts. The local turn-detection implementation is removed from conversation.ts, which imports the extracted helpers.
Devin session resolution
server/devin-session.ts, server/conversation.ts
devin-session.ts detects Devin executables and resolves pane session IDs from reported IDs or resume arguments. conversation.ts imports and re-exports the helpers.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to 4e735

This is a refactor that moves helper functions into dedicated modules without changing behavior. The reported typecheck and test runs pass, and no merge-blocking risk is evident.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 58.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the two main refactoring changes: moving turn-boundary logic and Devin session lookup into separate modules.
Description check Passed The description explains the problem, resulting module split, retained behavior, scope limits, affected files, and validation results. It includes the required Change and Validation sections and notes…
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.
Full details: Description check

Explanation

The description explains the problem, resulting module split, retained behavior, scope limits, affected files, and validation results. It includes the required Change and Validation sections and notes that no changelog fragment is needed.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@devswha

devswha commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

The first CI run's Browser regression (other scripts) failed in scripts/sticky-modifiers-regression.ts:127, on both attempts. A dropped z arrived wrapped in bracketed-paste markers, \x1b[200~z\x1b[201~.

I believe this PR did not cause it:

  • Where the wrapping happens: in the browser, before the input frame is sent.
  • What this PR changes: only server modules (server/conversation.ts, server/transcript-turns.ts, server/devin-session.ts). None of them is on the terminal input path.
  • Same base on main: main at d6bf59be9, the base this PR's merge commit used, passed CI, including this script.
  • Load: that CI run shared the self-hosted runner's PC with a full local browser lane from another branch.

Rerun on this branch (4e735981b) with nothing else running, using bun run check run --build bun scripts/sticky-modifiers-regression.ts:

  • exit 0;
  • PASS legacy: seven modifier combinations, repeated keys, actual PTY bytes, touch focus, paste, IME, reset;
  • PASS kitty: …, with the same checks.

@devswha

devswha commented Oct 23, 2026

Copy link
Copy Markdown
Owner Author

Merge pass: move-only PR (per-agent split, wave C3). It merges on its checks without waiting for a CodeRabbit review, as AGENTS.md allows.

  • Pure move. Comparing removed and added lines as multisets, the only differences are imports, the one re-export line and the five export keywords.
  • Gate review. A gate reviewer on a different model than the author's found:
    • no test spies on or mocks the moved functions or conversation.ts;
    • neither new module calls the three spied functions;
    • all mutable caches stay in conversation.ts.
  • Checks by the merge pass at this head:
    • 235 conversation, chat-history, turn-boundary, session-history and large-history tests pass;
    • the typecheck passes;
    • following value imports transitively, neither transcript-turns.ts nor devin-session.ts reaches conversation.ts or prompt.ts, so there is no cycle.
  • Outside contributors. feat(chat): read a droid pane's own session as its conversation #1442, feat(chat): read native Copilot CLI transcripts #1652 and feat(chat): read native Muse Code conversations #1706 touch server/conversation.ts. At most they need a rebase.

All required checks are green and no review thread is open.

Note: on the first CI run, sticky-modifiers-regression failed twice in the browser lane. A one-character drop arrived bracketed as paste (\x1b[200~z\x1b[201~). That code is client-side terminal input, which this server-only move doesn't touch: CI tested #1765 on top of d6bf59b, and the lane passed on d6bf59b itself. The re-run of the failed job passed.

@devswha
devswha merged commit 1b838cb into main Oct 23, 2026
23 of 25 checks passed
@devswha
devswha deleted the refactor/transcript-turns-module branch October 23, 2026 13:58
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