Skip to content

fix(terminal): realign legacy residual output metadata - #9720

Open
OnlyYu1996 wants to merge 2 commits into
stablyai:mainfrom
OnlyYu1996:codex/issue-9682-residual-output-meta
Open

fix(terminal): realign legacy residual output metadata#9720
OnlyYu1996 wants to merge 2 commits into
stablyai:mainfrom
OnlyYu1996:codex/issue-9682-residual-output-meta

Conversation

@OnlyYu1996

@OnlyYu1996 OnlyYu1996 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Realign plain buffered residual metadata after snapshot-boundary query suffix stripping.
  • Preserve metadata for genuinely transformed spans.
  • Prevent mobile and legacy clients from receiving plain residual text as OutputSpan and triggering a redundant resync.

Fixes #9682

Screenshots

No visual change.

Testing

  • pnpm lint - scoped oxlint and the max-lines ratchet pass; the full command is blocked by a pre-existing non-exhaustive switch in skill-freshness-group.tsx:101.
  • pnpm typecheck
  • pnpm test - 33,490 passed and 56 skipped; 7 environment-dependent failures remain in unrelated submodule, zsh path lookup, and system SSH tests. The two directly affected replay suites pass 11/11.
  • pnpm run build:desktop
  • Added or updated high-quality tests that would catch regressions, or explained why tests were not needed

AI Review Report

Reviewed the post-strip ordering, rawLength and sequence semantics, preservation of genuinely transformed spans, output batching behavior, and regression coverage. The initial review strengthened the existing query replay harness with zero net line growth. Follow-up coverage for sparse transformed output lives in a dedicated test file because the existing buffering suite is at its effective line limit, without adding a max-lines bypass. Cross-platform compatibility was checked for macOS, Linux, and Windows: this change is platform-neutral protocol metadata logic and touches no shortcuts, labels, paths, shell behavior, or Electron platform branches. The same behavior applies to local, SSH, and remote terminal streams.

Security Audit

Reviewed terminal data handling and frame metadata boundaries. The change only realigns an existing string-length field after existing query removal and does not execute or reinterpret terminal bytes. It adds no command execution, path handling, authentication, secrets, dependencies, permissions, or new IPC surface.

Notes

This is the mobile and legacy sibling of the multiplex residual metadata handling described in #8255.

X handle: N/A

ELI5

Legacy clients could get residual terminal text as the wrong span type and force a redundant full resync. Metadata is realigned after suffix stripping so plain residual output does not look like a structured span.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Terminal subscribe buffering now uses a shared helper to align rawLength with residual output data for non-transformed metadata. The mobile buffering drain applies this helper when emitting trimmed chunks. Tests cover boundary-spanning query replay and transformed residual replay, including emitted output content and preserved transformed metadata.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code and tests implement #9682's required residual rawLength realignment while preserving transformed spans and adding regression coverage.
Out of Scope Changes check ✅ Passed The changes stay focused on the terminal residual metadata fix and its regression tests, with no clear unrelated scope added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title is concise and accurately summarizes the main terminal metadata fix.
Description check ✅ Passed The description matches the required template and includes the mandatory summary, testing, review, security, and notes sections.

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7f7bca9f-eaa1-4573-984f-55c930988b6f

📥 Commits

Reviewing files that changed from the base of the PR and between 827cd49 and 2107b13.

📒 Files selected for processing (2)
  • src/main/runtime/rpc/methods/terminal.ts
  • src/main/runtime/rpc/terminal-subscribe-buffer.test.ts

Comment thread src/main/runtime/rpc/methods/terminal.ts

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
src/main/runtime/rpc/terminal-subscribe-transformed-residual.test.ts (1)

62-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the partial-runtime double assertion.

as unknown as OrcaRuntimeService deliberately bypasses structural checking for this partial mock; add a concise rationale.

Proposed change
+    // This test only exercises the runtime surface required by terminal.subscribe.
     } as unknown as OrcaRuntimeService

As per coding guidelines, “For non-obvious TypeScript code, add a concise comment explaining why the constraint exists, not how the code works.”

Source: Coding guidelines


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9ebc56ac-e366-474c-bfcc-fb9e6feedc7d

📥 Commits

Reviewing files that changed from the base of the PR and between 2107b13 and 132b81d.

📒 Files selected for processing (1)
  • src/main/runtime/rpc/terminal-subscribe-transformed-residual.test.ts

@AmethystLiang
AmethystLiang requested a review from OrcaWin July 22, 2026 17:04
@nwparker nwparker added the bug Something isn't working label Jul 27, 2026
@OnlyYu1996
OnlyYu1996 force-pushed the codex/issue-9682-residual-output-meta branch from 132b81d to 392d794 Compare July 29, 2026 08:27
Comment on lines +424 to +425
// 剥离查询字节后,普通残余需按实际数据重对齐,避免被误编码为 OutputSpan。
function realignResidualOutputMeta(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Chinese-language comment in an otherwise English-only codebase. The rest of the file uses English for all inline documentation.

Suggested change
// 剥离查询字节后,普通残余需按实际数据重对齐,避免被误编码为 OutputSpan
function realignResidualOutputMeta(
// After query bytes are stripped, plain residual output must be realigned to the actual data length to avoid being misencoded as an OutputSpan.
function realignResidualOutputMeta(

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +62 to +63
// 为什么:此用例只实现 terminal.subscribe 触及的 runtime 表面,避免构造无关方法。
} as unknown as OrcaRuntimeService

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Chinese-language comment in a file that otherwise follows the English-only convention of the rest of the test suite.

Suggested change
// 为什么:此用例只实现 terminal.subscribe 触及的 runtime 表面,避免构造无关方法。
} as unknown as OrcaRuntimeService
// Why: this case only implements the runtime surface that terminal.subscribe touches, avoiding construction of unrelated methods.
} as unknown as OrcaRuntimeService

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a metadata misalignment bug in the mobile/legacy terminal subscribe path: after a snapshot boundary clips a buffered chunk and query-suffix stripping further shortens it, the old code updated rawLength before stripping (using the wrong length), or skipped the update entirely when rawLength ≠ data.length. Either outcome caused createTerminalOutputBatcher to misclassify plain residual output as an OutputSpan, triggering unnecessary resyncs on mobile and legacy clients.

  • Introduces realignResidualOutputMeta, which recalculates rawLength from the final post-strip data length for plain (non-transformed) items, and passes transformed spans through unchanged.
  • Updates the existing boundary-spanning replay test (adjusting snapshot/data seqs to exercise the actual cross-boundary slice + strip path) and adds a dedicated test file to cover the transformed-span preservation path.

Confidence Score: 4/5

Safe to merge; the change is a narrow, well-reasoned metadata realignment that does not alter data bytes or control flow beyond the specific residual replay path.

The core logic in realignResidualOutputMeta is correct: moving the rawLength update to after query stripping (rather than before) fixes the misclassification of plain residual output as OutputSpan. The transformed-span guard (meta.transformed) correctly preserves metadata for the OutputSpan path. The batcher's coalescing behaviour is exploited intentionally — the query replay push (no meta) and the realigned residual push accumulate into a single frame with the original {seq, rawLength} pair, which is a subtle but verifiable invariant. The two new/updated tests confirm both the plain-residual and transformed-span paths. The only findings are a pair of Chinese-language comments inconsistent with the English-only convention of the rest of the codebase.

Files Needing Attention: No files require special attention beyond the two inline comment suggestions.

Important Files Changed

Filename Overview
src/main/runtime/rpc/methods/terminal.ts Adds realignResidualOutputMeta and calls it after query stripping rather than before; removes the pre-stripping uncoveredMeta update that had a race between slice length and strip length. Logic and math check out; Chinese-language inline comment is inconsistent with the rest of the file.
src/main/runtime/rpc/terminal-subscribe-buffer.test.ts Renames the test to match its new coverage focus, changes snapshot seq from 4→2 and data seq from 4→9 to force a genuine cross-boundary slice, and updates expected output accordingly. Test now exercises the stripped + coalesced path the fix targets.
src/main/runtime/rpc/terminal-subscribe-transformed-residual.test.ts New test verifying that transformed spans keep their original seq/rawLength/transformed metadata when replayed after a snapshot boundary trim. Comment at line 62 is in Chinese, inconsistent with the codebase style.

Sequence Diagram

sequenceDiagram
    participant D as dataListener
    participant P as pendingOutput buffer
    participant S as serializeTerminalBuffer
    participant G as getOutputAfterSnapshotSeq
    participant Strip as stripSnapshotBoundaryQuerySuffixes
    participant R as realignResidualOutputMeta (NEW)
    participant B as outputBatcher

    D->>P: "push('\x1b[6nafter', {seq:9, rawLength:9})<br/>while buffering=true"
    Note over D,P: query '\x1b[6n' added to pendingQuerySequences

    S-->>G: "snapshot resolves {seq:2}"
    Note over G: snapshotOutputSeq = 2

    G->>G: "slice data.slice(2) → '6nafter'<br/>(uncoveredData ≠ item.data → enter strip block)"
    G->>Strip: stripSnapshotBoundaryQuerySuffixes('6nafter', 2, 2, queries)
    Strip-->>G: 'after'  (removed '6n' bytes [2..4) of original stream)

    Note over B: queryReplayData path
    B->>B: push('\x1b[6n', no meta) — plain batch

    G->>R: "realignResidualOutputMeta('after', {seq:9, rawLength:9})"
    Note over R: !transformed → return {seq:9, rawLength:5}
    R-->>B: "push('after', {seq:9, rawLength:5})<br/>rawLength==data.length → plain batch, lastSeq=9"

    B->>B: "flush() → coalesce '\x1b[6nafter'<br/>meta: {seq:9, rawLength:9}"
    B-->>Client: "Output frame '\x1b[6nafter'<br/>(NOT OutputSpan — no redundant resync)"
Loading

Reviews (1): Last reviewed commit: "test(terminal): cover transformed residu..." | Re-trigger Greptile

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: mobile/legacy bufferedOutput residual push mis-frames as OutputSpan after query-suffix strip

3 participants