Skip to content

fix(session): persist listing deltas so Moonshot prefix cache survives --resume - #2070

Closed
ussoewwin wants to merge 32 commits into
Gitlawb:mainfrom
ussoewwin:fix/moonshot-prefix-cache-on-resume
Closed

ussoewwin wants to merge 32 commits into
Gitlawb:mainfrom
ussoewwin:fix/moonshot-prefix-cache-on-resume

Conversation

@ussoewwin

@ussoewwin ussoewwin commented Jul 30, 2026 •

Copy link
Copy Markdown

Summary

Fix catastrophic automatic prefix-cache busts on --resume for OpenAI-compatible providers that cache by byte-stable leading messages prefix (most visibly Moonshot / Kimi).

Root cause: for non-ant users, isLoggableMessage dropped almost all attachment types from the transcript. Turn-0 listing attachments (skill_listing, agent_listing_delta, deferred_tools_delta, mcp_instructions_delta) were therefore missing after resume, so the next turn re-injected agent/skill catalogs into the wire history. That rewrote early messages[N] content → shared prefix collapsed to ~messages[0] → Moonshot reported cached_tokens → 0 on the first post-resume call.

This PR:

  1. Persists only those four listing attachment types for external users (catalog text — not project files / hook dumps).
  2. Mirrors the existing suppressNextSkillListing pattern with suppressNextAgentListing so resume does not re-announce agents when the delta is already in the transcript.

Why this is Moonshot-shaped (but not Moonshot-only)

Provider path Cache mechanism Impact of mid-history listing rewrite
Moonshot / Kimi (Chat Completions + automatic prefix cache) Server matches a stable prefix of the request; usage exposes cached_tokens / prompt_tokens_details.cached_tokens Severe — one early content change zeros the entire prefix hit
OpenAI / Codex (automatic / provider-side prefix caching where enabled) Same class of “leading bytes must match” Same failure mode when auto-prefix cache is on
Anthropic / ant Attachments already persisted for ants; Anthropic also uses explicit cache_control breakpoints No behavior change — getUserType() === 'ant' still logs all attachments as before
Tool schemas Already identical across turns in our dumps (toolsEqual: true before and after) Confirmed not the bust vector

So the fix is scoped to transcript fidelity for listing deltas — the same invariant ants already enjoy — not a Moonshot-special-case API quirk or a provider #ifdef.

Privacy / training-surface consistency

The historical filter comment still stands: most attachments stay out of public transcripts.

Allowed through for non-ants (this PR only):

  • skill_listing
  • agent_listing_delta
  • deferred_tools_delta
  • mcp_instructions_delta

These carry agent/skill/tool catalog text already sent to the model at turn 0. They do not include project file contents.

Still blocked unless explicitly opted in:

  • hook_additional_context (unchanged — still requires CLAUDE_CODE_SAVE_HOOK_ADDITIONAL_CONTEXT)
  • all other attachment types

Code changes (minimal)

File Change
src/utils/sessionStorage.ts Allow-list the four listing attachment types in isLoggableMessage for non-ants
src/utils/attachments.ts Add suppressNextAgentListing + consume latch in getAgentListingDeltaAttachment (same shape as skills)
src/utils/conversationRecovery.ts On resume, if transcript already has agent_listing_delta, call suppressNextAgentListing()

No changes to openaiShim request shaping, tool definitions, or provider routing.

Measurement method

Real CLI path: dist/cli.mjs + Moonshot kimi-k3, localhost forward-proxy dumping every chat/completions body + SSE response.

Protocol:

  1. T1 — tool-using turn (cold then same-process tool loop)
  2. T2 — --resume <session> with another tool turn
  3. T5 — --resume with “Do not use tools” follow-up

Compared:

  • Wire messages[] first divergence index (prefix stability)
  • tools fingerprint equality
  • Moonshot SSE usage (choices[0].usage.cached_tokens / prompt_tokens)

Note: OpenClaude’s own Anthropic-shaped usage fields stay 0 when OPENAI_BASE_URL points at localhost (self-hosted cache metrics path). Moonshot’s raw SSE cached_tokens is the ground truth below.


Results — BEFORE (broken)

Dump: oc-reqdump-1785444725950 · model kimi-k3 · session 921bae3f-4a94-49b2-baf4-daf4a310d60b

Wire prefix

Comparison First break toolsEqual Meaning
T1 call1 → T1 call2 (same process) (duplicate / retry noise in that run) true Same-process path OK
T1 last → T2 first (--resume) messages[1].content true Early user/system blob rewritten (agent listing present in A, missing / replaced in B). Shared stable prefix ≈ message 0 only
T2 last → T5 messages[7].content true Mid-history agent listing re-injected again

Concrete A/B snippet at messages[1] (resume):

  • A (T1 last): still contains Available agent types for the Agent tool: …
  • B (T2 first): that block is gone / replaced with different system-reminder content (# claudeMd …) — different SHA, different length (11746 vs 8856 chars in one captured pair)

Moonshot cached_tokens (SSE)

Call msgs prompt_tokens cached_tokens hit
#7 T1 last (warm tool loop) 6 23425 23296 99.4%
#11 post-resume 8-msg call 8 23541 0 0%
#16 later warm call 12 27481 27392 99.7%

Interpretation: within a process, cache works. The first resume request that rewrites early history pays full prompt price (cached_tokens = 0).


Results — AFTER (this PR)

Dump: oc-reqdump-1785447394725 · model kimi-k3 · session e458eefd-1e29-4946-b0e3-78ffed319a5c · build including this commit

Wire prefix

Comparison First break toolsEqual Meaning
T1 call1 → T1 call2 messages[2] length only (2 → 6) true Append-only tool loop
T1 last → T2 first (--resume) messages[6] length only (6 → 8) true Entire T1 history is a shared prefix; only new turn messages appended
T2 last → T5 messages[12] length only (12 → 14) true Append-only again — no mid-history listing rewrite

Moonshot cached_tokens (SSE)

Call msgs prompt_tokens cached_tokens hit
#1 T1 cold 2 19491 0 0%
#2 T1 tool loop 6 23433 19456 83.0%
#3 T2 --resume first 8 23551 23296 98.9%
#4 T2 tool loop 12 27493 23552 85.7%
#5 T5 14 27577 27392 99.3%

Head-to-head (the money shot)

Metric Before After
Resume wire break messages[1].content (rewrite) messages[6] (append-only)
Resume first-call cache hit 0% (cached=0 / prompt≈23.5k) 98.9% (cached=23296 / prompt=23551)
Tools schema across turns equal equal (unchanged)

Test plan

  • Wire dump: T1 → --resume T2 → T5 on Moonshot kimi-k3 (before/after)
  • Confirm tools SHA identical across compared calls
  • Confirm Moonshot SSE cached_tokens on resume first call recovers from 0 → ~99%
  • CI / unit: existing sessionStorage / conversationRecovery tests (if any) still pass
  • Sanity: Anthropic / ant path unchanged (attachments already fully loggable)
  • Sanity: non-listing attachments still not persisted for non-ants
  • Optional: OpenAI auto-prefix-cache provider smoke (same append-only expectation)

Risks / non-goals

  • Slightly larger transcripts for external users (listing catalogs only).
  • Does not invent Anthropic-style cache_control for Moonshot — unnecessary once the prefix is stable.
  • Does not change how tools are declared on the wire.

Checklist for reviewers

  1. Is allow-listing only the four catalog attachment types acceptable vs the training-filter goal?
  2. Is mirroring suppressNextSkillListing for agents the right resume latch (vs reconstructing announced set only from transcript)?
  3. Any other turn-0 attachment types that also merge into early messages[1] and should join the allow-list?

Commit: b53a9fdf on ussoewwin/openclaude

Summary by CodeRabbit

  • Bug Fixes

    • Session recovery now keeps agent, skill, tool, and MCP instruction listings consistent.
    • Changes to descriptions, policies, and instructions are detected correctly.
    • Malformed transcript data is handled safely.
  • Privacy

    • External transcript sharing and feedback reports exclude sensitive listing data while preserving local cache behavior.
  • Reliability

    • Improved handling of disconnected, pending, newly available, and deferred tools.
    • Transcript continuity is preserved in external exports.
    • Listing state is restored consistently when continuing or resuming sessions.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fa68f543-8f5c-4cf1-a79c-294f1e7ea538

📥 Commits

Reviewing files that changed from the base of the PR and between 3fb14c4 and e770e64.

📒 Files selected for processing (1)
  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Add or update tests when behavior changes, and run the narrowest useful focused test checks.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Add or update tests when a code change affects behavior.
Use focused tests such as bun test ./path/to/test-file.test.ts when validating a narrowly scoped change.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts
🔇 Additional comments (1)
src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts (1)

12-256: 📐 Maintainability & Code Quality

Run the focused validation checks.

The provided context does not include check output. Run these commands before merge approval:

bun test ./src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts

bun test ./src/utils/mcpInstructionsDelta.test.ts

bun run typecheck

bun run typecheck:type-tests

As per coding guidelines, “Add or update tests when behavior changes, and run the narrowest useful focused test checks.” As per path instructions, “Validate with focused Bun tests ... plus typecheck/build or other applicable checks; report exact commands.”

Sources: Coding guidelines, Path instructions


📝 Walkthrough

Walkthrough

Resume recovery now restores agent-listing state. Local transcripts retain listing attachments, while external transcript and feedback paths filter them and repair parent links. MCP and deferred-tool delta handling validates malformed records. Release tests cover version 0.27.0 metadata and ordering.

Changes

Resume attachment handling

Layer / File(s) Summary
Resume attachment retention
src/utils/cachePaths.ts, src/utils/sessionStorage.ts, src/cli/print.ts
Local transcripts retain listing attachments. External persistence validates entries, records omissions, repairs parent links, and adopts resumed session files before later writes.
Listing delta reconstruction
src/utils/attachments.ts, src/utils/conversationRecovery.ts, src/utils/toolSearch.ts, src/utils/mcpInstructionsDelta.ts, src/services/mcp/types.ts, src/services/compact/compact.ts, src/screens/REPL.tsx
Agent, MCP, and deferred-tool deltas validate records, apply removals before additions, detect rendered-content changes, defer MCP-dependent removals, and restore suppression state during resume.
Listing resume validation
src/utils/attachments.agentListingResume.test.ts, src/utils/mcpInstructionsDelta.test.ts, src/utils/deferredToolsDelta.malformed.test.ts, src/utils/deferredToolsDelta.resumeRace.test.ts
Tests cover unchanged, changed, removed, recovered, malformed, MCP-gated, and re-added listing records.

External transcript egress

Layer / File(s) Summary
Attachment classification and egress filtering
src/utils/sessionStorage.ts, src/hooks/useLogMessages.ts, src/utils/sessionStorage.listingAllowlist.test.ts
Message arrays and JSONL are filtered for external egress. Unsafe entries are removed, malformed payloads fail closed, and surviving parent links are rewritten.
Feedback transcript sanitization
src/components/Feedback.tsx, src/components/FeedbackSurvey/submitTranscriptShare.ts, src/components/Feedback.egress.test.ts, src/components/FeedbackSurvey/submitTranscriptShare.test.ts
Feedback and transcript sharing filter main, subagent, and raw JSONL transcripts before normalization or upload.

Release metadata

Layer / File(s) Summary
Release entry and version validation
web/src/data/releases.test.ts
Tests validate version 0.27.0, release ordering, metadata, and dotted semantic-version comparison.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested reviewers: kevincodex1

🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
No Hidden Policy Change ⚠️ Warning The PR changes trust policy: four listing attachments are retained locally, stripped from remote/CCR/share/feedback egress (including ant), and MCP removals are held for needs-auth clients. Obtain explicit maintainer approval for the local-retention/egress allowlist and the needs-auth MCP removal policy; record the approved trust-model behavior in the PR.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, scoped to session resume behavior, and accurately describes the listing-delta persistence change.
Description check ✅ Passed The description clearly explains the problem, implementation, impact, testing, risks, and non-goals, with detailed validation results.
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.
Risk Surface Disclosed ✅ Passed The review identifies provider, privacy/egress, resume, skills, and MCP risks, with a dedicated Risks/non-goals section and no blocking change identified.
✨ 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.

@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: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/attachments.ts`:
- Around line 1648-1657: Add regression tests for the attachment resume flow
around the suppressNextAgent latch: verify an unchanged listing is suppressed
only once, changed listings preserve and emit agent additions/removals, and
resetSentSkillNames() clears the suppression state. Run the targeted tests, bun
run typecheck, and bun run typecheck:type-tests when available.
- Around line 1648-1657: The suppressNextAgent branch in the attachment listing
flow should consume the latch and return an empty delta only when the current
filtered agent set is unchanged from the persisted listing. When agent types
were removed, added, or the filtered set is empty, preserve the latch for normal
processing so the existing removedTypes/addedTypes calculation emits the
legitimate delta; update announced only for the unchanged duplicate case.

In `@src/utils/conversationRecovery.ts`:
- Around line 650-654: Add an end-to-end resume regression test covering the
agent_listing_delta branch in conversation recovery: restore a transcript
containing this attachment, verify the next attachment pass suppresses only the
duplicate listing, and confirm it emits a delta when the available agent set
changes. Place the test alongside the existing resume/attachment coverage and
preserve unrelated attachment behavior.

In `@src/utils/sessionStorage.ts`:
- Around line 4775-4791: Add regression coverage in sessionStorage tests for all
four allowed attachment types—skill_listing, agent_listing_delta,
deferred_tools_delta, and mcp_instructions_delta—while preserving the
hook_additional_context environment gate and verifying unrelated attachments
remain filtered. Run the targeted tests, bun run check, and bun run typecheck.
- Around line 4783-4791: Update the attachment-type allowlist in the transcript
filtering logic around m.type and getUserType() so it retains only skill_listing
and agent_listing_delta; remove deferred_tools_delta and mcp_instructions_delta
from the accepted types to prevent sensitive MCP instruction payloads from being
persisted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 65b37ce1-c504-46db-b9a5-4e784ca1afd1

📥 Commits

Reviewing files that changed from the base of the PR and between 5cac15c and b53a9fd.

📒 Files selected for processing (3)
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
🔇 Additional comments (2)
src/utils/attachments.ts (1)

2938-2938: LGTM!

Also applies to: 2962-2973

src/utils/conversationRecovery.ts (1)

21-24: LGTM!

Comment thread src/utils/attachments.ts Outdated
Comment on lines +650 to +654
// Same for agent_listing_delta — mid-history re-announce busts Moonshot
// / OpenAI automatic prefix cache on every --resume.
if (attachment.type === 'agent_listing_delta') {
suppressNextAgentListing()
}

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add an end-to-end resume regression test for this trigger.

Restore a transcript containing agent_listing_delta, then verify the next attachment pass suppresses only the duplicate listing and still emits a delta when the available agent set changes.

As per coding guidelines, TypeScript behavior changes must add/update tests. As per path instructions, resume/attachment behavior must be covered by tests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/conversationRecovery.ts` around lines 650 - 654, Add an end-to-end
resume regression test covering the agent_listing_delta branch in conversation
recovery: restore a transcript containing this attachment, verify the next
attachment pass suppresses only the duplicate listing, and confirm it emits a
delta when the available agent set changes. Place the test alongside the
existing resume/attachment coverage and preserve unrelated attachment behavior.

Sources: Coding guidelines, Path instructions

Comment thread src/utils/sessionStorage.ts Outdated
Comment thread src/utils/sessionStorage.ts
ussoewwin added a commit to ussoewwin/openclaude that referenced this pull request Jul 30, 2026
CodeRabbit follow-up for PR Gitlawb#2070: suppressNextAgentListing only skips when
the filtered agent set matches the transcript announced set; otherwise emit
a normal add/remove delta. Keep all four prefix-cache listing types on the
external allowlist (dropping mcp/deferred without a resume latch re-busts
cache). Add unit coverage for latch and isLoggableMessage.
@ussoewwin

Copy link
Copy Markdown
Author

CodeRabbit follow-up (373d413)

Addressing the review on this PR under the agreed policy:

1. Latch - fixed (not always return [])

suppressNextAgentListing now only skips when the current filtered agent set equals the transcript's announced set. If agents were added/removed across the process boundary, the latch still clears but a normal addedTypes / removedTypes delta is emitted.

2. Tests - added

  • src/utils/attachments.agentListingResume.test.ts - unchanged set -> []; changed set -> delta; resetSentSkillNames clears latch; restoreSkillStateFromMessages arms suppress and still allows deltas when the set changed.
  • src/utils/sessionStorage.listingAllowlist.test.ts - external users persist the four listing types; unrelated attachments still filtered; hook_additional_context stays behind its env gate; ants still allow all.

3. Allowlist - keeping all four types (intentional)

We are not dropping mcp_instructions_delta / deferred_tools_delta from the external allowlist.

  • These catalogs were already sent to the model at turn 0; persistence is not a new disclosure of project file contents.
  • Ants already persist all attachments.
  • Dropping MCP/deferred without a matching resume suppress latch reintroduces the same mid-history rewrite and Moonshot prefix-cache bust (cached_tokens -> 0). Skill/agent alone is insufficient for providers that auto-cache the full leading prefix.

Privacy note in isLoggableMessage was strengthened to document this.

4. Policy change

Yes - this is an intentional, narrow policy change for non-ant transcript persistence of turn-0 listing deltas only, required for OpenAI-compatible automatic prefix cache (Moonshot measured: resume first-call cache 0% -> 98.9%).

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/attachments.agentListingResume.test.ts`:
- Around line 86-112: Update both suppressNextAgentListing tests to verify
one-shot latch consumption: after the existing assertion, call
getAgentListingDeltaAttachment with the same context and an empty messages
array, then assert the current agents are emitted as an initial listing. Apply
this follow-up check to both the unchanged-set and changed-set cases, preserving
their existing assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b500241f-9d2c-43bd-9c43-0aa973af598b

📥 Commits

Reviewing files that changed from the base of the PR and between b53a9fd and 373d413.

📒 Files selected for processing (4)
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/sessionStorage.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/attachments.agentListingResume.test.ts
🔇 Additional comments (4)
src/utils/attachments.ts (1)

1648-1672: LGTM!

Also applies to: 2951-2951, 2981-2988

src/utils/attachments.agentListingResume.test.ts (1)

1-152: 📐 Maintainability & Code Quality

Run the focused validation before merge.

No check results were provided. Run the targeted Bun test, bun run typecheck, and bun run check; run bun run typecheck:type-tests if that script applies.

As per coding guidelines, changed TypeScript requires relevant validation. As per path instructions, narrow Bun tests and type checks should be run for resume/attachment changes.

Sources: Coding guidelines, Path instructions

src/utils/sessionStorage.ts (1)

4783-4787: Enforce the “already sent at turn 0” privacy invariant.

The allowlist accepts every mcp_instructions_delta, whose payload contains raw instruction blocks. This comment assumes those blocks are always already-sent and non-sensitive, but the predicate does not enforce that. Confirm the attachment is initial-only; otherwise narrow or redact the external transcript payload while preserving the data required for cache reconstruction.

src/utils/sessionStorage.listingAllowlist.test.ts (1)

1-120: LGTM!

Comment thread src/utils/attachments.agentListingResume.test.ts
@ussoewwin

Copy link
Copy Markdown
Author

CodeRabbit follow-up (latch test)

Addressed the remaining actionable comment:

  • attachments.agentListingResume.test.ts - after existing assertions, both unchanged-set and changed-set tests call getAgentListingDeltaAttachment(ctx, []) and assert an initial listing. Makes one-shot latch consumption observable.

Non-blocking: keeping all four allowlist types remains intentional; mcp/deferred are turn-0 model-visible catalogs needed for Moonshot prefix-cache reconstruction.

Commit: cdcd966
Validation: bun test attachments.agentListingResume.test.ts - 5 pass.

@kevincodex1

Copy link
Copy Markdown
Member

@coderabbitai please do intensive review on this again

@coderabbitai

coderabbitai Bot commented Jul 30, 2026 •

Copy link
Copy Markdown
Contributor

@kevincodex1 I’ll perform a fresh, intensive end-to-end review of #2070, including the resume flow, attachment persistence policy, state/latch behavior, and test coverage.

✅ Action performed

Full review finished.

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/attachments.ts`:
- Around line 2987-2990: Persist the recovered announced agent-type set
alongside the suppression latch in src/utils/attachments.ts:2987-2990, compare
against it in the attachment-generation logic at
src/utils/attachments.ts:1657-1671 when messages are missing or unhydrated, and
clear it during reset at src/utils/attachments.ts:2951. In
src/utils/conversationRecovery.ts:650-654, reconstruct and pass/store the final
set across transcript deltas instead of only arming the boolean. Add the
regression coverage in src/utils/attachments.agentListingResume.test.ts:148-170
for restoring a listing followed by attachment generation with missing or
unhydrated messages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 043dc734-ed76-4bb3-a844-c16ad33c08b2

📥 Commits

Reviewing files that changed from the base of the PR and between 5cac15c and cdcd966.

📒 Files selected for processing (5)
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/sessionStorage.ts
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: smoke-and-tests (24.11.x)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/conversationRecovery.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/conversationRecovery.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/sessionStorage.ts
  • src/utils/attachments.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/conversationRecovery.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
🔇 Additional comments (3)
src/utils/sessionStorage.ts (1)

4769-4807: LGTM!

src/utils/sessionStorage.listingAllowlist.test.ts (2)

1-119: LGTM!


29-119: 📐 Maintainability & Code Quality

Confirm required Bun validation.

No check results were provided. Run and report the focused test plus bun run typecheck; run bun run typecheck:type-tests if this repository enables it.

Sources: Coding guidelines, Path instructions

Comment thread src/utils/attachments.ts Outdated

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found issues that need to be addressed before this is ready.

Findings

  • [P1] Keep externally persisted listing payloads behind the privacy boundary
    src/utils/sessionStorage.ts:4791
    Before this change, external sessions filtered all attachments. The new allow-list instead sends these four payload classes through cleanMessagesForLogging and recordTranscript, including remote persistence, even though the surrounding policy explicitly excludes non-ant attachments because they can contain sensitive data. They are not a structured safe catalog: skill_listing.content includes local skill descriptions, agent_listing_delta.addedLines includes custom agent descriptions and tool policy, and mcp_instructions_delta.addedBlocks copies arbitrary server-provided InitializeResult.instructions. MCP servers can also connect after turn zero, so the stated turn-zero invariant is not enforced. The existing CodeRabbit privacy request is therefore valid on the current head. Keep raw payloads out of external transcripts, or introduce explicit opt-in/redaction with an enforceable safe-data contract and a separate resume-cache mechanism.

  • [P1] Refresh same-named MCP instructions after resume
    src/utils/sessionStorage.ts:4794
    Persisting mcp_instructions_delta makes the next process reconstruct an announced set from server names alone. A resumed session creates a fresh MCP connection, so a server can return different InitializeResult.instructions under the same configured name after a deployment or configuration/auth-policy change; however, getMcpInstructionsDelta sees the old name and returns no attachment. I verified this exact old-block/new-block case returns null. The model therefore keeps following stale server instructions. This is newly reachable for external sessions because this PR starts retaining those deltas. Compare the rendered instruction block (or a connection/version fingerprint) and emit an update when it changes; a name-only scan is not sufficient across a process boundary.

  • [P2] Re-announce changed definitions for an existing agent type
    src/utils/attachments.ts:1648
    The new resume path considers an agent listing unchanged when its set of agentType strings matches the transcript. That ignores the content the listing actually gives the model: formatAgentLine includes whenToUse plus the effective tool allow/deny policy. Editing a project/plugin agent while the CLI is stopped, while retaining its type name, now resumes with the old description and capability contract and emits no corrective delta; before this PR the external transcript did not carry the prior delta, so the current listing was sent again. Fingerprint the rendered listing data as well as the type names and add coverage for a same-type description/tool-policy change.

  • [P2] Serialize the new environment-mutating test
    src/utils/sessionStorage.listingAllowlist.test.ts:29
    These tests repeatedly change process-global USER_TYPE and CLAUDE_CODE_SAVE_HOOK_ADDITIONAL_CONTEXT, but unlike the adjacent attachment-resume test and the repository's other environment-mutating tests they never acquire sharedMutationLock. Bun can execute test files concurrently, so another test observing or changing either variable can race these assertions and leak state across files. Acquire and release the shared mutation lock in setup/teardown before mutating the environment.

@ussoewwin

Copy link
Copy Markdown
Author

P2 (sharedMutationLock / env-mutating listingAllowlist test) — addressed

src/utils/sessionStorage.listingAllowlist.test.ts now acquires sharedMutationLock in beforeEach and releases it in afterEach, matching attachments.agentListingResume.test.ts and the other environment-mutating tests in this repo. Push: e624f724.

Remaining review feedback — in progress (not in this commit)

Still working locally on:

  • P1-1 — keep listing deltas off the external transcript allow-list (privacy); restore prefix stability via a separate local resume-cache (not raw payloads in the public transcript / remote ingress)
  • P1-2 — MCP instructions announced-set: content fingerprint (not name-only), so stale instructions re-announce after resume
  • P2-1 — agent listing latch / delta: compare formatAgentLine content, not type names alone

Will follow up with commits for those once the resume-cache path is wired end-to-end.

@ussoewwin

ussoewwin commented Jul 31, 2026 •

Copy link
Copy Markdown
Author

How P1-2 and P2-1 were fixed (4d7b5c79)

Scope of this comment: P1-2 (MCP same-name instruction refresh) and P2-1 (agent same-type listing refresh) only.

P1-1: Local resume-cache / privacy boundary for listing deltas — I'm currently making every effort to address this.


P1-2 — Refresh same-named MCP instructions after resume

Reviewer finding (verbatim intent):
Persisting mcp_instructions_delta reconstructs an announced set from server names alone. After --resume, a fresh MCP connection can return different InitializeResult.instructions under the same configured name. getMcpInstructionsDelta saw the old name, returned null, and the model kept stale instructions. Name-only scan is not sufficient across a process boundary. Compare the rendered instruction block (or equivalent fingerprint) and emit an update when it changes.

What was wrong before:

// announced = Set<string> of names only
for (const n of msg.attachment.addedNames) announced.add(n)
for (const n of msg.attachment.removedNames) announced.delete(n)

for (const [name, block] of blocks) {
  if (!announced.has(name)) added.push({ name, block })  // name present → skip, even if block changed
}

How it is fixed now (src/utils/mcpInstructionsDelta.ts):

  1. Reconstruct Map<name, renderedBlock> via getAnnouncedMcpInstructionBlocks (not a name-only Set).
  2. Removals are applied before adds so same-name update deltas reconstruct correctly.
  3. Diff current rendered blocks (## ${name}\n${instructions} + client-side append) against the map:
    • prev === undefined → new server → add
    • prev !== block → same name, different content → re-add with the new block
    • name gone from connected set → removedNames

Does this solve the reviewed case?

Reviewer case Result after fix
Old block in transcript for docs, fresh handshake returns new instructions, same name Delta is not null; addedNames: ['docs'] with the new addedBlocks
Same name, same block Still null (no spurious cache bust)
Server disconnected Still in removedNames

Test that matches the reviewer’s “I verified old-block/new-block returns null” case:
src/utils/mcpInstructionsDelta.test.ts → getMcpInstructionsDelta re-announces when same-name instructions change after resume


P2-1 — Re-announce changed definitions for an existing agent type

Reviewer finding (verbatim intent):
The resume path treated an agent listing as unchanged when the set of agentType strings matched the transcript. That ignores what the model actually sees: formatAgentLine includes whenToUse plus the effective tool allow/deny policy. Editing a project/plugin agent while the CLI is stopped (same type name) resumed with the old description/capability contract and emitted no corrective delta. Fingerprint the rendered listing data as well as type names; add coverage for same-type description/tool-policy change.

What was wrong before:

const announced = new Set<string>()  // types only
// suppress latch: unchanged iff Set equality of types
const added = filtered.filter(a => !announced.has(a.agentType))  // same type → never re-announce

How it is fixed now (src/utils/attachments.ts → getAgentListingDeltaAttachment):

  1. Reconstruct Map<agentType, formatAgentLine> from prior agent_listing_delta attachments (addedLines paired with addedTypes).
  2. Suppress latch (suppressNextAgent): skip only when every current agent’s formatAgentLine(a) equals the announced line for that type (size match + content match). Same types with different whenToUse/tool policy → latch does not swallow the delta.
  3. Normal delta path: add when type is new or announced.get(type) !== formatAgentLine(a).

formatAgentLine is exactly: `- ${type}: ${whenToUse} (Tools: ${toolsDescription})` — so both description and tool policy are in the fingerprint.

Does this solve the reviewed case?

Reviewer case Result after fix
Same agentType, whenToUse changed across resume (+ suppress latch armed) Emits delta with new addedLines containing the new description
Same type, tool allowlist/denylist changed (formatAgentLine Tools: …) Emits delta; line contains the new tool policy
Same type, same rendered line Suppress latch still returns [] (prefix-stable path preserved)

Coverage:
src/utils/attachments.agentListingResume.test.ts

  • suppressNextAgentListing re-announces when same-type whenToUse changed across resume
  • getAgentListingDeltaAttachment re-announces when same-type tool policy changed
  • suppressNextAgentListing still skips when same-type content matches transcript

Summary vs review asks

Ask Addressed? Mechanism
P1-2: compare rendered MCP instruction block, not name alone Yes Map<name, block> + prev !== block → re-announce
P1-2: old-block / new-block after resume must not return null Yes Explicit unit test for that case
P2-1: fingerprint rendered listing (formatAgentLine), not type names alone Yes Map<type, line> in latch + added filter
P2-1: coverage for same-type description / tool-policy change Yes Two dedicated tests + latch still-skips when content matches

@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: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/mcpInstructionsDelta.test.ts`:
- Around line 70-78: Add a test alongside “getMcpInstructionsDelta removes
disconnected servers by name” covering a server that remains connected but
returns no instructions after resume; assert the delta reports that server in
removedNames while addedNames remains empty, locking in the behavior of
getMcpInstructionsDelta.

In `@src/utils/mcpInstructionsDelta.ts`:
- Around line 128-135: Update the removal logic in the loop over
announced.keys() to remove a server when it is either no longer connected or has
no current entry in blocks, while preserving announced blocks for connected
servers that still provide instructions. Use the existing connectedNames and
blocks symbols so a reconnected server without instructions clears its stale
announcement.

In `@src/utils/resumeCache.ts`:
- Around line 232-303: Add focused tests for
hydrateListingAttachmentsFromResumeCache covering existing-listing skip
behavior, deferred-to-agent-to-mcp-to-skill injection order, and empty-cache
no-op behavior. Add tests for updateResumeCacheFromMessages verifying cache data
merges correctly across repeated message slices. Use the project’s established
test patterns, and report the focused bun test command plus bun run typecheck.
- Around line 169-179: Update the skill_listing branch in
updateResumeCacheFromMessages to deduplicate entries using contentHash before
pushing to cache.skillListings. Reuse the computed hash to detect an existing
listing and skip appending duplicates, while preserving the current metadata and
dirty-flag behavior for newly added listings.
- Around line 165-168: Update the attachment loop in
updateResumeCacheFromMessages to skip records whose m.attachment is null or not
an object before reading a.type, matching the guard used by
hasListingAttachment. Preserve processing for valid attachment records and
prevent malformed legacy transcript entries from throwing during
recordTranscript.
- Around line 305-345: Remove getAnnouncedMcpInstructionHashes and
getAnnouncedAgentListingLines from resumeCache.ts, then reuse
getAnnouncedMcpInstructionBlocks from mcpInstructionsDelta.ts and the existing
agent-listing reconstruction helper from attachments.ts. Preserve the MCP
hash-map result by applying hashContent(block) to each reconstructed block, and
update all local callers/imports accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: adbbdbea-2a58-43c1-98ec-72ed8d8b7d24

📥 Commits

Reviewing files that changed from the base of the PR and between e624f72 and 4d7b5c7.

📒 Files selected for processing (9)
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/cachePaths.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/sessionStorage.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/cachePaths.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/resumeCache.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/cachePaths.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/resumeCache.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/cachePaths.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/resumeCache.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/attachments.agentListingResume.test.ts
🔇 Additional comments (10)
src/utils/attachments.ts (2)

1667-1681: The latch is still consumed when the comparison falls through, so an attachment pass that receives undefined or un-hydrated messages burns it and re-injects a full initial listing. This was raised previously.


1639-1655: LGTM!

Also applies to: 1683-1690

src/utils/cachePaths.ts (1)

21-21: LGTM!

src/utils/mcpInstructionsDelta.ts (1)

46-67: LGTM!

Also applies to: 118-126

src/utils/conversationRecovery.ts (1)

25-25: LGTM!

Also applies to: 809-819

src/utils/sessionStorage.ts (1)

85-85: LGTM!

Also applies to: 1522-1525, 4780-4787

src/utils/attachments.agentListingResume.test.ts (1)

10-10: LGTM!

Also applies to: 68-85, 89-89, 110-110, 151-159, 174-222

src/utils/mcpInstructionsDelta.test.ts (1)

1-68: LGTM!

Also applies to: 80-100

src/utils/sessionStorage.listingAllowlist.test.ts (1)

38-53: LGTM!

Also applies to: 64-82, 132-153

src/utils/resumeCache.ts (1)

72-77: 🩺 Stability & Availability

No change needed. Resume switches the active session to asSessionId(result.sessionId) before --resume writes, so getResumeCachePath() resolves using the same resumed session ID.

Comment thread src/utils/mcpInstructionsDelta.test.ts Outdated
Comment thread src/utils/mcpInstructionsDelta.ts Outdated
Comment thread src/utils/resumeCache.ts Outdated
Comment thread src/utils/resumeCache.ts Outdated
Comment thread src/utils/resumeCache.ts Outdated
Comment on lines +232 to +303
export async function hydrateListingAttachmentsFromResumeCache(
messages: Message[],
sessionId: string = getSessionId(),
): Promise<Message[]> {
if (hasListingAttachment(messages)) {
return messages
}

const cache = await loadResumeCache(sessionId)
const injected: Message[] = []

// Match turn-0 collection order in attachments.ts (deferred → agent → mcp → skill).
if (cache.deferredTools && Object.keys(cache.deferredTools.lines).length > 0) {
const names = Object.keys(cache.deferredTools.lines).sort()
injected.push(
createAttachmentMessage({
type: 'deferred_tools_delta',
addedNames: names,
addedLines: names.map(n => cache.deferredTools!.lines[n]!),
removedNames: [],
}),
)
}

if (cache.agentListing && Object.keys(cache.agentListing.lines).length > 0) {
const types = Object.keys(cache.agentListing.lines).sort()
injected.push(
createAttachmentMessage({
type: 'agent_listing_delta',
addedTypes: types,
addedLines: types.map(t => cache.agentListing!.lines[t]!),
removedTypes: [],
isInitial: true,
showConcurrencyNote: cache.agentListing.showConcurrencyNote,
}),
)
}

if (
cache.mcpInstructions &&
Object.keys(cache.mcpInstructions.blocks).length > 0
) {
const names = Object.keys(cache.mcpInstructions.blocks).sort()
injected.push(
createAttachmentMessage({
type: 'mcp_instructions_delta',
addedNames: names,
addedBlocks: names.map(n => cache.mcpInstructions!.blocks[n]!),
removedNames: [],
}),
)
}

for (const listing of cache.skillListings) {
injected.push(
createAttachmentMessage({
type: 'skill_listing',
content: listing.content,
skillCount: listing.skillCount,
isInitial: listing.isInitial,
}),
)
}

if (injected.length === 0) {
return messages
}

// Prepend so normalizeAttachmentForAPI rebuilds the same early prefix the
// original session sent before the first real user turn content.
return [...injected, ...messages]
}

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add tests for cache hydration.

No test file for resumeCache.ts appears in this change set. Cover: hydration skipped when a listing attachment already exists, injection order (deferred → agent → mcp → skill), empty-cache no-op, and merge behavior of updateResumeCacheFromMessages across repeated slices. Report the exact commands, for example the focused bun test path plus bun run typecheck.

As per coding guidelines, "Add or update tests when a TypeScript or TSX change affects behavior." As per path instructions, add or update tests for cache hydration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/resumeCache.ts` around lines 232 - 303, Add focused tests for
hydrateListingAttachmentsFromResumeCache covering existing-listing skip
behavior, deferred-to-agent-to-mcp-to-skill injection order, and empty-cache
no-op behavior. Add tests for updateResumeCacheFromMessages verifying cache data
merges correctly across repeated message slices. Use the project’s established
test patterns, and report the focused bun test command plus bun run typecheck.

Sources: Coding guidelines, Path instructions

Comment thread src/utils/resumeCache.ts Outdated
Comment on lines +305 to +345
/** Content hash map for MCP instruction blocks currently announced in messages. */
export function getAnnouncedMcpInstructionHashes(
messages: Message[],
): Map<string, string> {
const announced = new Map<string, string>()
for (const msg of messages) {
if (msg.type !== 'attachment') continue
if (msg.attachment.type !== 'mcp_instructions_delta') continue
const { addedNames, addedBlocks, removedNames } = msg.attachment
// Removals first so same-name updates keep the new block's hash.
for (const n of removedNames) announced.delete(n)
for (let i = 0; i < addedNames.length; i++) {
const name = addedNames[i]
const block = addedBlocks[i]
if (name && block !== undefined) {
announced.set(name, hashContent(block))
}
}
}
return announced
}

/** agentType → rendered line for attachments already in the conversation. */
export function getAnnouncedAgentListingLines(
messages: Message[],
): Map<string, string> {
const announced = new Map<string, string>()
for (const msg of messages) {
if (msg.type !== 'attachment') continue
if (msg.attachment.type !== 'agent_listing_delta') continue
const { addedTypes, addedLines, removedTypes } = msg.attachment
// Removals first so same-type content updates keep the new line.
for (const t of removedTypes) announced.delete(t)
for (let i = 0; i < addedTypes.length; i++) {
const type = addedTypes[i]
const line = addedLines[i]
if (type && line !== undefined) announced.set(type, line)
}
}
return announced
}

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.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find callers of the announced-scan helpers.
rg -n 'getAnnouncedMcpInstructionHashes|getAnnouncedAgentListingLines|getAnnouncedMcpInstructionBlocks' src

Repository: Gitlawb/openclaude

Length of output: 813


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file sizes =="
wc -l src/utils/resumeCache.ts src/utils/attachments.ts src/utils/mcpInstructionsDelta.ts

echo "== resumeCache relevant export area =="
sed -n '280,360p' src/utils/resumeCache.ts | cat -n

echo "== mcpInstructionsDelta relevant function area =="
sed -n '1,120p' src/utils/mcpInstructionsDelta.ts | cat -n

echo "== attachments referenced area =="
rg -n -C 4 'get.+Announced|announced|agent_listing_delta|mcp_instructions_delta' src/utils/attachments.ts

echo "== diff stat and changed file markers if available =="
git diff --stat || true
git diff -- src/utils/resumeCache.ts src/utils/mcpInstructionsDelta.ts src/utils/attachments.ts | sed -n '1,220p' || true

echo "== AST outline candidates =="
ast-grep outline src/utils/resumeCache.ts --match getAnnouncedAgentListingLines --view expanded || true
ast-grep outline src/utils/mcpInstructionsDelta.ts --match getAnnouncedMcpInstructionBlocks --view expanded || true

Repository: Gitlawb/openclaude

Length of output: 15773


Unify the announced-attachment reconstruction helpers.

getAnnouncedAgentListingLines duplicates the agent listing delta reconstruction in src/utils/attachments.ts, while getAnnouncedMcpInstructionHashes duplicates getAnnouncedMcpInstructionBlocks in src/utils/mcpInstructionsDelta.ts. Neither new helper has callers outside src/utils/resumeCache.ts, so remove them and reuse the existing helper plus hashContent(block) where needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/resumeCache.ts` around lines 305 - 345, Remove
getAnnouncedMcpInstructionHashes and getAnnouncedAgentListingLines from
resumeCache.ts, then reuse getAnnouncedMcpInstructionBlocks from
mcpInstructionsDelta.ts and the existing agent-listing reconstruction helper
from attachments.ts. Preserve the MCP hash-map result by applying
hashContent(block) to each reconstructed block, and update all local
callers/imports accordingly.

@ussoewwin

Copy link
Copy Markdown
Author

Thanks for the latest review on e624f72…4d7b5c7 — addressed in f4944bbb.

Actionable items

Item Change
MCP: remove when connected but empty instructions mcpInstructionsDelta.ts — !connectedNames.has(n) || !blocks.has(n) + test
resume-cache: guard malformed attachments updateResumeCacheFromMessages skips null/non-object attachment
resume-cache: dedupe skill_listing by contentHash Prevents duplicate prepend on every recordTranscript
resume-cache: focused tests New resumeCache.test.ts (hydrate skip/order/empty, dedupe, merge, malformed)
Remove unused helpers Dropped getAnnouncedMcpInstructionHashes / getAnnouncedAgentListingLines
Agent latch: recovered announced set suppressNextAgentListing(recoveredLines?) + restoreSkillStateFromMessages retains rendered lines so unhydrated messages=[] first pass does not re-announce

Verification

bun test src/utils/mcpInstructionsDelta.test.ts \
  src/utils/attachments.agentListingResume.test.ts \
  src/utils/resumeCache.test.ts
→ 22 pass

P1-1 (privacy / local resume-cache boundary) remains in progress — this commit tightens Bot-flagged correctness on top of that work; please re-review when convenient.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/attachments.ts (1)

1644-1655: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Skip malformed attachments before reading msg.attachment.type. Runtime transcript data can have attachment set to null, undefined, or a non-object; these two attachment-scanning loops currently try to read .type before those guards would skip the message. Add the same guard used in updateResumeCacheFromMessages to getAgentListingDeltaAttachment (src/utils/attachments.ts#L1640-L1642) and to getAnnouncedMcpInstructionBlocks/getMcpInstructionsDelta (src/utils/mcpInstructionsDelta.ts#L54-L92).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/attachments.ts` around lines 1644 - 1655, Guard attachment values
before accessing attachment.type in getAgentListingDeltaAttachment in
src/utils/attachments.ts (lines 1644-1655) and
getMcpInstructionsDelta/getAnnouncedMcpInstructionBlocks in
src/utils/mcpInstructionsDelta.ts (lines 86-92), reusing the existing
updateResumeCacheFromMessages malformed-attachment guard so null, undefined, and
non-object attachments are skipped safely.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/resumeCache.test.ts`:
- Around line 1-179: Update the resume cache test cleanup around
resetResumeCacheForTesting and the asynchronous updateResumeCacheFromMessages
flow so afterEach waits for all pending scheduled writes before clearing state.
Ensure tests that trigger cache saves do not leave dangling writeChain or
scheduleSave promises after completion, including tests that do not await
hydration.

---

Outside diff comments:
In `@src/utils/attachments.ts`:
- Around line 1644-1655: Guard attachment values before accessing
attachment.type in getAgentListingDeltaAttachment in src/utils/attachments.ts
(lines 1644-1655) and getMcpInstructionsDelta/getAnnouncedMcpInstructionBlocks
in src/utils/mcpInstructionsDelta.ts (lines 86-92), reusing the existing
updateResumeCacheFromMessages malformed-attachment guard so null, undefined, and
non-object attachments are skipped safely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 762e2ccc-a2d0-48bb-a078-046410182593

📥 Commits

Reviewing files that changed from the base of the PR and between 4d7b5c7 and f4944bb.

📒 Files selected for processing (7)
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/resumeCache.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/attachments.ts
  • src/utils/resumeCache.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/attachments.ts
  • src/utils/resumeCache.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/attachments.ts
  • src/utils/resumeCache.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/resumeCache.test.ts
  • src/utils/attachments.agentListingResume.test.ts
🔇 Additional comments (8)
src/utils/resumeCache.ts (2)

165-188: LGTM!


189-234: LGTM!

src/utils/attachments.ts (2)

1656-1698: LGTM!


2978-2983: LGTM!

Also applies to: 3006-3032

src/utils/mcpInstructionsDelta.ts (1)

118-136: LGTM!

src/utils/mcpInstructionsDelta.test.ts (1)

80-86: LGTM!

src/utils/conversationRecovery.ts (1)

619-685: LGTM!

src/utils/attachments.agentListingResume.test.ts (1)

224-243: LGTM!

Comment thread src/utils/resumeCache.test.ts Outdated
@ussoewwin

Copy link
Copy Markdown
Author

Addressed the latest CodeRabbit follow-ups on 44ed8b8d:

  1. resumeCache tests — afterEach / beforeEach now await flushResumeCacheWritesForTesting() and unlink the on-disk {session}.resume-cache.json so pending writeChain work cannot leak across cases (and empty-cache tests stay empty).
  2. Malformed attachments — getAgentListingDeltaAttachment and MCP announced/delta scans skip null/non-object attachment payloads before reading .type.
  3. Comment wording — corrected misleading comments that implied external transcript persistence or hashes + names only resume-cache storage. External users keep full listing payloads in the local resume-cache only; public transcript filter remains the privacy boundary.

Targeted tests: resumeCache / listingAllowlist / mcpInstructionsDelta / attachments.agentListingResume — all pass.

ussoewwin added a commit to ussoewwin/openclaude that referenced this pull request Jul 31, 2026
CodeRabbit follow-up for PR Gitlawb#2070: suppressNextAgentListing only skips when
the filtered agent set matches the transcript announced set; otherwise emit
a normal add/remove delta. Keep all four prefix-cache listing types on the
external allowlist (dropping mcp/deferred without a resume latch re-busts
cache). Add unit coverage for latch and isLoggableMessage.
@ussoewwin
ussoewwin force-pushed the fix/moonshot-prefix-cache-on-resume branch from 44ed8b8 to 3c1c78f Compare July 31, 2026 03:09

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/attachments.ts (1)

1647-1656: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate complete attachment schemas at the runtime boundary.

Both paths accept partial objects with recognized type values. These records can throw during reconstruction and can produce incorrect MCP diagnostics.

  • src/utils/attachments.ts#L1647-L1656: validate removedTypes, addedTypes, and addedLines before iteration.
  • src/utils/mcpInstructionsDelta.ts#L57-L66: validate removedNames, addedNames, and addedBlocks before iteration.
  • src/utils/mcpInstructionsDelta.ts#L93-L95: apply the same validity rule before incrementing diagnostics.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/attachments.ts` around lines 1647 - 1656, Validate the complete
recognized attachment schema before processing: in src/utils/attachments.ts
lines 1647-1656, require removedTypes, addedTypes, and addedLines to be valid
arrays before iteration; in src/utils/mcpInstructionsDelta.ts lines 57-66,
require removedNames, addedNames, and addedBlocks to be valid arrays before
reconstruction; and in src/utils/mcpInstructionsDelta.ts lines 93-95, apply the
same validity rule before incrementing diagnostics. Anchor these checks to the
existing attachment reconstruction and MCP delta diagnostic functions, skipping
malformed records without throwing or counting them.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/resumeCache.test.ts`:
- Around line 15-22: Update the cleanup in the beforeEach hook around
resetResumeCacheForTesting and unlink(getResumeCachePath(SESSION)) to ignore
only ENOENT missing-file errors; rethrow all other unlink failures so
stale-cache or isolation problems fail the test. Apply the same handling to the
other catch block covering this cleanup.

---

Outside diff comments:
In `@src/utils/attachments.ts`:
- Around line 1647-1656: Validate the complete recognized attachment schema
before processing: in src/utils/attachments.ts lines 1647-1656, require
removedTypes, addedTypes, and addedLines to be valid arrays before iteration; in
src/utils/mcpInstructionsDelta.ts lines 57-66, require removedNames, addedNames,
and addedBlocks to be valid arrays before reconstruction; and in
src/utils/mcpInstructionsDelta.ts lines 93-95, apply the same validity rule
before incrementing diagnostics. Anchor these checks to the existing attachment
reconstruction and MCP delta diagnostic functions, skipping malformed records
without throwing or counting them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 101b47b5-b9e7-47c8-91b9-6a43f87476bc

📥 Commits

Reviewing files that changed from the base of the PR and between f4944bb and 44ed8b8.

📒 Files selected for processing (5)
  • src/utils/attachments.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/resumeCache.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/attachments.ts
  • src/utils/resumeCache.test.ts
  • src/utils/resumeCache.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/attachments.ts
  • src/utils/resumeCache.test.ts
  • src/utils/resumeCache.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/attachments.ts
  • src/utils/resumeCache.test.ts
  • src/utils/resumeCache.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/resumeCache.test.ts
🔇 Additional comments (4)
src/utils/sessionStorage.listingAllowlist.test.ts (1)

43-45: LGTM!

src/utils/resumeCache.ts (1)

12-15: LGTM!

Also applies to: 127-137

src/utils/attachments.ts (1)

1662-1702: LGTM!

Also applies to: 2985-2986, 3012-3038

src/utils/mcpInstructionsDelta.ts (1)

78-92: LGTM!

Also applies to: 94-99, 124-139

Comment thread src/utils/resumeCache.test.ts Outdated

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/sessionStorage.ts (1)

4788-4797: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard malformed attachment records here too.

m.attachment.type is read without checking that m.attachment is a non-null object. resumeCache.ts, attachments.ts, and mcpInstructionsDelta.ts all add if (!m.attachment || typeof m.attachment !== 'object') continue/return for the same reason: legacy transcripts can carry malformed attachment records. isLoggableMessage runs inside cleanMessagesForLogging, called on every recordTranscript, so one malformed record crashes transcript recording with a TypeError instead of just being skipped.

🛡️ Proposed fix
   if (m.type === 'attachment' && getUserType() !== 'ant') {
+    // Legacy transcripts may carry malformed attachment records
+    // (null/undefined/non-object payload). Treat as non-loggable instead
+    // of throwing.
+    if (!m.attachment || typeof m.attachment !== 'object') return false
     const t = m.attachment.type
     if (
       t === 'hook_additional_context' &&
Consider adding a regression test in `src/utils/sessionStorage.listingAllowlist.test.ts` for a malformed `attachment: null` record, matching the coverage already added in `resumeCache.test.ts`. Would you like me to draft that test?
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/sessionStorage.ts` around lines 4788 - 4797, Update the attachment
branch in isLoggableMessage to return false when m.attachment is null or not an
object before reading m.attachment.type. Preserve the existing
hook_additional_context and environment-flag checks for valid attachment
objects, and add regression coverage for an attachment: null record if the
surrounding tests support it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/conversationRecovery.ts`:
- Around line 837-848: Remove the redundant if/else around
hydrateListingAttachmentsFromResumeCache in the conversation recovery flow and
make a single call with messages. Rely on the function’s default sessionId
parameter to obtain the session when no explicit value is available, preserving
the existing message hydration behavior.

---

Outside diff comments:
In `@src/utils/sessionStorage.ts`:
- Around line 4788-4797: Update the attachment branch in isLoggableMessage to
return false when m.attachment is null or not an object before reading
m.attachment.type. Preserve the existing hook_additional_context and
environment-flag checks for valid attachment objects, and add regression
coverage for an attachment: null record if the surrounding tests support it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 273e663b-72f2-4b02-9285-d73c4683731f

📥 Commits

Reviewing files that changed from the base of the PR and between 44ed8b8 and 3c1c78f.

📒 Files selected for processing (10)
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/cachePaths.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/resumeCache.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/sessionStorage.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/cachePaths.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/attachments.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/resumeCache.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/cachePaths.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/attachments.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/resumeCache.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/cachePaths.ts
  • src/utils/conversationRecovery.ts
  • src/utils/sessionStorage.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/attachments.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/resumeCache.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/resumeCache.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/attachments.agentListingResume.test.ts
🔇 Additional comments (12)
src/utils/resumeCache.test.ts (2)

15-22: 🩺 Stability & Availability | ⚡ Quick win

Catch only ENOENT during resume-cache file cleanup.

Both beforeEach (Lines 15-22) and afterEach (Lines 24-34) swallow every unlink error, not just "file does not exist." If unlink fails for another reason (permissions, I/O), the stale resume-cache file remains on disk, and the next test can load leftover data instead of a clean cache.

Catch only ENOENT and rethrow other errors so cleanup failures fail the test loudly instead of silently corrupting isolation.

🛡️ Proposed fix
 beforeEach(async () => {
   resetResumeCacheForTesting()
   try {
     await unlink(getResumeCachePath(SESSION))
-  } catch {
-    // missing is fine
+  } catch (err) {
+    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err
   }
 })

 afterEach(async () => {
   await flushResumeCacheWritesForTesting()
   resetResumeCacheForTesting()
   try {
     await unlink(getResumeCachePath(SESSION))
-  } catch {
-    // missing is fine
+  } catch (err) {
+    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err
   }
 })

37-196: LGTM! Test cases exercise the no-op, skip-when-present, injection order, skill dedup, agent-delta merge, and malformed-attachment tolerance paths, and afterEach correctly flushes writeChain before reset to avoid dangling writes.

src/utils/cachePaths.ts (1)

21-23: LGTM!

src/utils/resumeCache.ts (2)

139-241: LGTM! The malformed-attachment guards and contentHash-based skill dedup requested in prior reviews are in place, and hydration order matches the documented turn-0 sequence.

Also applies to: 243-319


63-137: 🗄️ Data Integrity & Integration

No resume-cache cross-process issue to raise.

The existing background-session code treats running sessions as already-active and does not start a second process against the same live sessionId, so the module-level cache mirrors the intended single-OS-process writer per active session.

			> Likely an incorrect or invalid review comment.
src/utils/attachments.ts (1)

1639-1730: LGTM! The suppression latch now falls back to the recovered baseline only when the in-memory scan is empty, the unchanged check compares rendered line content (not just type membership), and the latch is consumed correctly in both the unchanged and changed-set paths. This matches the regression tests in attachments.agentListingResume.test.ts.

Also applies to: 2982-2987, 3010-3038

src/utils/mcpInstructionsDelta.ts (1)

46-162: LGTM! Removal now correctly covers both the disconnected case and the connected-but-instructionless case, and content changes under the same server name are re-announced via block comparison rather than name comparison.

src/utils/mcpInstructionsDelta.test.ts (1)

1-108: LGTM!

src/utils/conversationRecovery.ts (1)

21-25: LGTM! Restoration correctly reconstructs the recovered agent-line baseline (removals before additions) and arms the one-shot latch with it, matching the consumer logic in attachments.ts.

Also applies to: 619-685

src/utils/sessionStorage.ts (1)

85-85: LGTM! updateResumeCacheFromMessages runs on the full pre-filter message list before cleanMessagesForLogging, matching the documented privacy boundary (listing payloads go to the local cache, not the public transcript).

Also applies to: 1522-1525

src/utils/sessionStorage.listingAllowlist.test.ts (1)

1-156: LGTM! Environment mutation is properly isolated with sharedMutationLock and restored in afterEach, and coverage spans all four listing types plus the hook-context gate for both external and ant users.

src/utils/attachments.agentListingResume.test.ts (1)

1-244: LGTM!

Comment thread src/utils/conversationRecovery.ts Outdated
Comment on lines +837 to +848
// External transcripts omit listing deltas (privacy). Reinject from the
// local resume-cache before announced-set / latch restoration so --resume
// keeps a byte-stable API prefix for OpenAI/Moonshot automatic caching.
if (sessionId) {
messages = await hydrateListingAttachmentsFromResumeCache(
messages!,
sessionId,
)
} else {
messages = await hydrateListingAttachmentsFromResumeCache(messages!)
}

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.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify the redundant sessionId branch.

hydrateListingAttachmentsFromResumeCache declares sessionId: string = getSessionId() as a default parameter. Passing sessionId explicitly, even when it is undefined, produces the same result as omitting it. The if (sessionId) {...} else {...} split is unnecessary.

♻️ Proposed simplification
-    if (sessionId) {
-      messages = await hydrateListingAttachmentsFromResumeCache(
-        messages!,
-        sessionId,
-      )
-    } else {
-      messages = await hydrateListingAttachmentsFromResumeCache(messages!)
-    }
+    messages = await hydrateListingAttachmentsFromResumeCache(
+      messages!,
+      sessionId,
+    )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// External transcripts omit listing deltas (privacy). Reinject from the
// local resume-cache before announced-set / latch restoration so --resume
// keeps a byte-stable API prefix for OpenAI/Moonshot automatic caching.
if (sessionId) {
messages = await hydrateListingAttachmentsFromResumeCache(
messages!,
sessionId,
)
} else {
messages = await hydrateListingAttachmentsFromResumeCache(messages!)
}
// External transcripts omit listing deltas (privacy). Reinject from the
// local resume-cache before announced-set / latch restoration so --resume
// keeps a byte-stable API prefix for OpenAI/Moonshot automatic caching.
if (sessionId) {
messages = await hydrateListingAttachmentsFromResumeCache(
messages!,
sessionId,
)
} else {
messages = await hydrateListingAttachmentsFromResumeCache(messages!)
}
messages = await hydrateListingAttachmentsFromResumeCache(
messages!,
sessionId,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/conversationRecovery.ts` around lines 837 - 848, Remove the
redundant if/else around hydrateListingAttachmentsFromResumeCache in the
conversation recovery flow and make a single call with messages. Rely on the
function’s default sessionId parameter to obtain the session when no explicit
value is available, preserving the existing message hydration behavior.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/conversationRecovery.ts (1)

659-680: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject partial agent_listing_delta attachments before restoring state.

This code defaults missing fields to empty arrays. A partial attachment can then change recoveredAgentLines and arm suppressNextAgentListing(). getAgentListingDeltaAttachment() rejects the same partial schema, so a resume race can use a baseline that no valid transcript delta established.

Require addedTypes, addedLines, and removedTypes to all be arrays before setting sawAgentListing or applying removals and additions. Add a regression test for a partial delta with removedTypes or addedTypes missing.

Proposed fix
     if (attachment.type === 'agent_listing_delta') {
-      sawAgentListing = true
-      const addedTypes = Array.isArray(attachment.addedTypes)
-        ? attachment.addedTypes
-        : []
-      const addedLines = Array.isArray(attachment.addedLines)
-        ? attachment.addedLines
-        : []
-      const removedTypes = Array.isArray(attachment.removedTypes)
-        ? attachment.removedTypes
-        : []
+      if (
+        !Array.isArray(attachment.addedTypes) ||
+        !Array.isArray(attachment.addedLines) ||
+        !Array.isArray(attachment.removedTypes)
+      ) {
+        continue
+      }
+      sawAgentListing = true
+      const { addedTypes, addedLines, removedTypes } = attachment
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/conversationRecovery.ts` around lines 659 - 680, Update the
agent_listing_delta handling in conversation recovery to validate that
addedTypes, addedLines, and removedTypes are all arrays before setting
sawAgentListing or mutating recoveredAgentLines. Ignore partial attachments
entirely, matching getAgentListingDeltaAttachment() validation, and add a
regression test covering a delta missing removedTypes or addedTypes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/utils/conversationRecovery.ts`:
- Around line 659-680: Update the agent_listing_delta handling in conversation
recovery to validate that addedTypes, addedLines, and removedTypes are all
arrays before setting sawAgentListing or mutating recoveredAgentLines. Ignore
partial attachments entirely, matching getAgentListingDeltaAttachment()
validation, and add a regression test covering a delta missing removedTypes or
addedTypes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3be1d77a-752d-4efb-8cff-bc15369ad9c5

📥 Commits

Reviewing files that changed from the base of the PR and between 3c1c78f and 7205617.

📒 Files selected for processing (4)
  • src/utils/attachments.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/resumeCache.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

TypeScript code in this repository must use strict mode and ESM imports.

**/*.{ts,tsx}: Add or update tests when a TypeScript or TSX change affects behavior.
Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.

Files:

  • src/utils/resumeCache.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/conversationRecovery.ts
  • src/utils/attachments.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*: Preserve existing repository patterns unless intentionally refactoring them.
Keep changes small, readable, and focused; avoid broad rewrites or unrelated cleanup.
Do not reformat unrelated files, and keep comments useful and concise.
Update documentation when setup, commands, or user-facing behavior changes.
Review AI-generated changes for correctness, style consistency, unnecessary noise, and adherence to project architecture before submitting them.
Provider changes must follow the documented integration patterns in docs/integrations/overview.md and the focused guides under docs/integrations/how-to/.
When changing provider behavior, avoid breaking third-party providers and test the exact provider/model path changed when possible.
Provider pull requests must explicitly identify affected providers, limitations, and follow-up work.
Run the narrowest meaningful validation command for the touched area, and ensure relevant CI checks pass before merging.
Use bun install to install dependencies and the repository's Bun scripts for building, testing, smoke testing, and development.
Dependency changes require a concrete project benefit such as a bug fix, security issue, or approved feature; preference alone is insufficient.
Do not change the project's language, core runtime, or dependency stack, or introduce a new runtime, without prior maintainer agreement.
Keep each pull request focused on one issue or clearly scoped improvement and avoid bundling unrelated fixes, features, or refactors.

Files:

  • src/utils/resumeCache.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/conversationRecovery.ts
  • src/utils/attachments.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/resumeCache.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/conversationRecovery.ts
  • src/utils/attachments.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/resumeCache.test.ts
🔇 Additional comments (4)
src/utils/resumeCache.test.ts (2)

15-35: LGTM!


15-35: 📐 Maintainability & Code Quality

Provide the required validation results.

The supplied context does not include command output for the changed TypeScript behavior. Before merge, provide results for the focused resume-cache, agent-listing, and MCP tests, bun run typecheck, and bun run typecheck:type-tests when that script exists.

As per coding guidelines, “Run the relevant TypeScript validation checks for changed code, including bun run typecheck and, when applicable, bun run typecheck:type-tests.” As per path instructions, “Run the narrowest relevant Bun test suites plus typecheck/build checks, and document exact validation commands in the PR.”

Sources: Coding guidelines, Path instructions

src/utils/attachments.ts (1)

1650-1670: LGTM!

Also applies to: 3005-3012, 3121-3124

src/utils/mcpInstructionsDelta.ts (1)

60-80: LGTM!

Also applies to: 108-117, 146-161

@ussoewwin

Copy link
Copy Markdown
Author

Addressed the latest CodeRabbit actionable items on 72056171:

  1. Comment wording (skill path) — suppressNextSkillListing / skill resume latch / conversationRecovery no longer imply skill listings always live in the public transcript. Wording now matches the agent path: local resume-cache for external users; transcript for ants (after hydrate).
  2. Complete schema validation (outside-diff) — agent_listing_delta and mcp_instructions_delta reconstruction now require removed* / added* array fields (and skip arrays-as-attachment) before iterating; MCP diagnostic midCount uses the same validity check.
  3. resumeCache tests — unlink ignores ENOENT only; other errors rethrow.

Targeted tests: 26 pass (resumeCache, attachments.agentListingResume, mcpInstructionsDelta, sessionStorage.listingAllowlist).

@ussoewwin
ussoewwin requested a review from jatmn July 31, 2026 03:39
@ussoewwin

Copy link
Copy Markdown
Author

P1-1 Countermeasures Report: Privacy boundary for listing deltas

PR: #2070
Scope: P1-1 only — sensitive listing payloads must not enter external / public transcripts or remote ingress.
HEAD at report time: 72056171 (fix/moonshot-prefix-cache-on-resume)
Primary fix commit: 238bbfba (fix(session): resume-cache + content fingerprints for MCP/agent listings)

This report answers the P1-1 privacy concern raised in review: putting skill_listing / agent_listing_delta / deferred_tools_delta / mcp_instructions_delta into the external transcript (or remote ingress) would expose local catalogs. The final design keeps those payloads out of the public log path and stores them only in a local resume-cache so --resume can still keep OpenAI/Moonshot automatic prefix cache stable.


1. Problem statement (what P1-1 required)

These attachment types carry local catalogs, not generic UI chrome:

Attachment type Sensitive content
skill_listing Skill descriptions / listing body
agent_listing_delta Custom agent whenToUse / tool policy lines (formatAgentLine)
deferred_tools_delta Deferred tool names / listing lines
mcp_instructions_delta Server-provided InitializeResult.instructions blocks

Privacy requirement: for non-ant (external) users, these must not be persisted into the public transcript or sent through remote session ingress.

Prefix-cache requirement (same PR, separate mechanism): on --resume, if those catalogs are missing from the loaded history, the runtime rebuilds an empty announced set and re-injects full listings mid-history → cached_tokens → 0 (prefix cache bust). P1-1 forbids solving that by allowlisting the sensitive payloads into the external transcript.


2. Design chosen (honest chronology)

Earlier commits on this PR (8b78c445, 00a9a88e) temporarily put the four listing types on an external allowlist so prefix cache would survive resume. That approached the cache goal but failed the privacy boundary that P1-1 calls out.

Final design (238bbfba and follow-ups) reverses that:

  1. Keep the existing external filter: non-ant attachments stay non-loggable (including the four listing types).
  2. Before filtering, snapshot full listing payloads into a local-only file: {sessionId}.resume-cache.json.
  3. On conversation recovery / --resume, hydrate those payloads back into the in-memory message list (turn-0-equivalent), restore announced sets / suppress latches, and avoid mid-history re-injection.

So: privacy is enforced by isLoggableMessage; resume stability is enforced by resumeCache, not by widening the external allowlist.


3. Write path (record → local cache → public filter)

In src/utils/sessionStorage.ts → recordTranscript:

// External transcripts filter listing deltas (privacy). Persist announced
// catalogs to the local resume-cache so --resume can reinject them without
// putting sensitive payloads in the public transcript / remote ingress.
updateResumeCacheFromMessages(messages)
const cleanedMessages = cleanMessagesForLogging(messages, allMessages)

Order matters and is intentional:

  1. updateResumeCacheFromMessages(messages) — receives the full, pre-filter slice and merges listing attachments into the local resume-cache (src/utils/resumeCache.ts).
  2. cleanMessagesForLogging — applies isLoggableMessage, then (for non-ant) transformMessagesForExternalTranscript. Listing deltas are dropped here for external users.
  3. Only cleanedMessages are inserted into the on-disk transcript chain that feeds public / remote logging.

updateResumeCacheFromMessages is documented to take the full list so external sessions still persist announced catalogs without writing them to the public transcript.


4. Privacy gate (what never becomes “loggable” for external)

In isLoggableMessage (sessionStorage.ts):

  • For attachment messages when getUserType() !== 'ant', the default is return false.
  • The only documented exception in that block is hook_additional_context when CLAUDE_CODE_SAVE_HOOK_ADDITIONAL_CONTEXT is truthy.
  • Comments at this site explicitly name the four prefix-cache listing types and state they stay filtered; resume stability is delegated to the separate local resume-cache.

Consequence: skill_listing, agent_listing_delta, deferred_tools_delta, and mcp_instructions_delta are not passed through cleanMessagesForLogging into the external transcript for external users.

Ant (first-party) sessions are unchanged: attachments remain loggable for /share / training-oriented transcripts. The privacy boundary is scoped to external users, matching the existing product split.


5. Local resume-cache (what holds the sensitive payloads)

src/utils/resumeCache.ts header (verbatim intent of the module):

  • Local-only store for prefix-cache listing attachments.
  • External transcripts deliberately omit the four listing types (privacy boundary).
  • File lives beside the session transcript: {sessionId}.resume-cache.json.
  • Never passed through cleanMessagesForLogging / sessionIngress.
  • Stores full listing payloads so hydrate can reinject turn-0-equivalent attachments on resume (content hashes are for dedupe / stale detection, not a substitute for payloads).

Stored shape (ResumeCache):

  • skillListings[] — full content + metadata + contentHash
  • agentListing — agentType → formatAgentLine map
  • deferredTools — tool name → listing line
  • mcpInstructions — server name → instruction block

Path helper: getResumeCachePath() under the session project dir.


6. Read / resume path (hydrate without public log)

src/utils/conversationRecovery.ts calls hydrateListingAttachmentsFromResumeCache before announced-set / latch restoration so --resume sees the catalogs in memory even when the loaded transcript (external privacy filter) has no listing attachments.

Hydrate reinjects into the in-memory message list used for continuation. It does not route those payloads through sessionIngress or re-append them as newly loggable external transcript entries via isLoggableMessage.


7. Remote ingress relationship

src/services/api/sessionIngress.ts (appendSessionLog / appendSessionLogImpl) persists transcript entries that have already been cleaned for logging. It does not import or read resumeCache. Sensitive listing payloads therefore cannot reach remote ingress through that path unless they first pass isLoggableMessage — which they do not for external users.


8. Automated verification (P1-1 privacy)

src/utils/sessionStorage.listingAllowlist.test.ts:

Test Assertion
isLoggableMessage filters prefix-cache listing deltas for external users (privacy boundary) All four listing types → false when USER_TYPE=external
isLoggableMessage still filters unrelated attachments for external users Unrelated attachments remain filtered
isLoggableMessage keeps hook_additional_context behind its env gate Env gate still works
isLoggableMessage allows all attachments for ant users Ant keeps listings in transcript; privacy boundary is external-only

Tests serialize env mutations via sharedMutationLock (0c2dca9a) so parallel suite runs do not corrupt USER_TYPE.

Additional coverage for resume behavior (agent latch / MCP / resume-cache) lives in:

  • src/utils/resumeCache.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/mcpInstructionsDelta.test.ts

Those files support the cache-stability half of the PR; the allowlist test file is the direct P1-1 privacy lock.


9. What this report does not claim

To stay accurate:

  • This report does not claim the first PR commits already satisfied P1-1. The allowlist approach was an intermediate step; 238bbfba is the privacy-correct fix.
  • Content fingerprints for MCP blocks / agent lines (same commit family) address stale same-name / same-type updates after resume (P1-2 / P2-1 class). They are complementary to P1-1 but are not the privacy gate itself.
  • Schema / Array.isArray hardening and ENOENT-only unlink test fixes (72056171 and related) improve robustness; they are not the P1-1 privacy mechanism.

10. Summary (P1-1 status)

Requirement Status on HEAD 72056171
External transcript must not contain the four sensitive listing payloads Met — isLoggableMessage filters them for non-ant
Remote ingress must not receive those payloads via the logging path Met — ingress consumes cleaned transcript; no resume-cache bridge
--resume must still recover announced catalogs for prefix-cache stability Met — local {sessionId}.resume-cache.json + hydrate in conversationRecovery
Ant / first-party transcript behavior preserved Met — filter applies only when getUserType() !== 'ant'
Regression lock for privacy Met — sessionStorage.listingAllowlist.test.ts

Bottom line: P1-1 is addressed by keeping the external privacy filter and adding a local-only resume-cache write/hydrate path. Prefix-cache stability no longer depends on shipping sensitive listing catalogs into the public transcript.

Keep skill/agent/deferred-tools/mcp listing attachments in non-ant transcripts and suppress agent listing re-injection on --resume so automatic prefix cache is not busted.
CodeRabbit follow-up for PR Gitlawb#2070: suppressNextAgentListing only skips when
the filtered agent set matches the transcript announced set; otherwise emit
a normal add/remove delta. Keep all four prefix-cache listing types on the
external allowlist (dropping mcp/deferred without a resume latch re-busts
cache). Add unit coverage for latch and isLoggableMessage.
…script

CodeRabbit follow-up: after suppressNextAgentListing is consumed, a call with
messages=[] must re-emit an initial agent_listing_delta. Covers both the
unchanged-set and changed-set resume paths.
Address P2 review: serialize USER_TYPE / CLAUDE_CODE_SAVE_HOOK_ADDITIONAL_CONTEXT
mutations via sharedMutationLock in beforeEach/afterEach, matching other
environment-mutating tests in this repo.
Persist listing deltas in a local resume-cache (not the public transcript) and reinject on --resume for prefix-cache stability. Diff MCP instruction blocks and formatAgentLine content so same-name/same-type updates after resume are re-announced.
@ussoewwin

Copy link
Copy Markdown
Author

CodeRabbit close-out — d4fcbf2d

Branch: fix/moonshot-prefix-cache-on-resume
HEAD: d4fcbf2df0d66efcfe47bb157f82c59ebc5d6c89

Findings closed this turn

Finding Change
agent_listing_delta restore fail-closed (length + all strings) conversationRecovery.ts — ignore partial / mismatched / non-string addedTypes/addedLines before arming suppress
getAnnouncedMcpInstructionBlocks same contract mcpInstructionsDelta.ts — same fail-closed parse
In-REPL resume() must clear process-local sentSkillNames before restore prepareInReplResumeListingState(messages) = resetSentSkillNames() then restoreSkillStateFromMessages; wired in REPL.tsx
Extract shared subagent egress filter filterSubagentTranscriptsForExternalEgress next to filterMessagesForExternalEgress in sessionStorage.ts; wired in submitTranscriptShare.ts + Feedback.tsx
Outside-diff: rebuild remoteEgressOmittedParents after local resume Project.rebuildRemoteEgressOmittedParentsFromLocalTranscript() called from adoptResumedSessionFile()

Obsolete / N/A on this PR

Finding Reason
Outside-diff background-session block in REPL.tsx (~2873–3028) Not in this PR’s REPL delta vs main; no change required for Option A prefix-cache resume

Tests

bun test ./src/utils/attachments.agentListingResume.test.ts ./src/utils/mcpInstructionsDelta.test.ts ./src/utils/sessionStorage.listingAllowlist.test.ts ./src/components/FeedbackSurvey/submitTranscriptShare.test.ts
bun run typecheck

Result: 52 pass / 0 fail; tsc --noEmit clean.

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Feedback.tsx (1)

164-180: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Add a focused regression test for the Feedback upload path.

Feedback.test.ts only covers issue-draft URL generation. submitTranscriptShare.egress covers the survey/share code path.

Add an intercepted Feedback submission test with main messages, subagent transcripts, and raw JSONL containing permission/attachment listings. Assert the posted content excludes listing payloads and retains normal conversation turns.

Run bun run typecheck and bun run typecheck:type-tests after adding the test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Feedback.tsx` around lines 164 - 180, Add a focused
intercepted upload regression test for the Feedback submission flow, distinct
from issue-draft and submitTranscriptShare.egress tests. Exercise main messages,
subagent transcripts, and raw JSONL containing permission/attachment listings,
then assert the posted content excludes those listing payloads while retaining
normal conversation turns. Run bun run typecheck and bun run
typecheck:type-tests afterward.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/FeedbackSurvey/submitTranscriptShare.test.ts`:
- Around line 33-40: Restore process-wide test state after execution: in
submitTranscriptShare test setup, capture the original process.env.USER_TYPE
before changing it and capture whether globalThis.MACRO existed, then add
afterAll cleanup that restores or deletes each value accordingly. Keep
postedBodies restoration in the individual test rather than shared setup, while
preserving the existing shared mutation-lock cleanup.

---

Outside diff comments:
In `@src/components/Feedback.tsx`:
- Around line 164-180: Add a focused intercepted upload regression test for the
Feedback submission flow, distinct from issue-draft and
submitTranscriptShare.egress tests. Exercise main messages, subagent
transcripts, and raw JSONL containing permission/attachment listings, then
assert the posted content excludes those listing payloads while retaining normal
conversation turns. Run bun run typecheck and bun run typecheck:type-tests
afterward.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8a85d50e-3542-4339-a594-1ed3d7a593df

📥 Commits

Reviewing files that changed from the base of the PR and between 877c882 and d4fcbf2.

📒 Files selected for processing (10)
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/screens/REPL.tsx
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
  • src/utils/sessionStorage.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/screens/REPL.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/screens/REPL.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/screens/REPL.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/screens/REPL.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/screens/REPL.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/FeedbackSurvey/submitTranscriptShare.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/conversationRecovery.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/sessionStorage.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Add or update tests when behavior changes, and run the narrowest useful focused test checks.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Add or update tests when a code change affects behavior.
Use focused tests such as bun test ./path/to/test-file.test.ts when validating a narrowly scoped change.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
🔇 Additional comments (9)
src/utils/sessionStorage.listingAllowlist.test.ts (1)

17-26: LGTM!

Also applies to: 866-885, 887-935

src/components/FeedbackSurvey/submitTranscriptShare.ts (1)

14-14: LGTM!

Also applies to: 44-62

src/components/FeedbackSurvey/submitTranscriptShare.test.ts (1)

140-171: LGTM!

src/utils/sessionStorage.ts (1)

7-7: LGTM!

Also applies to: 918-936, 1235-1280, 1948-1969, 2267-2285, 5609-5627

src/utils/conversationRecovery.ts (1)

22-22: LGTM!

Also applies to: 662-681, 691-702

src/screens/REPL.tsx (1)

178-178: LGTM!

Also applies to: 1985-1988

src/utils/mcpInstructionsDelta.ts (1)

65-82: LGTM!

src/utils/attachments.agentListingResume.test.ts (1)

16-19: LGTM!

Also applies to: 239-252, 287-334

src/utils/mcpInstructionsDelta.test.ts (1)

146-181: LGTM!

Comment thread src/components/FeedbackSurvey/submitTranscriptShare.test.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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Feedback.egress.test.ts`:
- Around line 76-97: Update the Feedback egress test’s upload-body assertions to
verify that content contains “feedback main turn,” ensuring the raw JSONL
fixture is included and filtered correctly. Add this assertion alongside the
existing main and subagent transcript checks.
- Around line 47-125: Update the Feedback egress test setup and teardown to
restore every module overridden by mock.module(), not only Axios. Capture stable
originals for providers, auth, HTTP, privacy, and session storage before
mocking, then re-register those originals in afterAll; apply the same cleanup
pattern to the transcript-share egress test.

In `@src/components/Feedback.tsx`:
- Around line 214-220: Update the submitReport callback’s dependency array to
include backgroundTasks, ensuring it uses the latest task transcripts when
submitting. Add a focused regression test that changes the task transcript
before submission and verifies the updated backgroundTasks are uploaded.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a700a90b-497c-4ca5-8534-d3c29c94afeb

📥 Commits

Reviewing files that changed from the base of the PR and between d4fcbf2 and 4bec70b.

📒 Files selected for processing (3)
  • src/components/Feedback.egress.test.ts
  • src/components/Feedback.tsx
  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/Feedback.egress.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/Feedback.egress.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.egress.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Add or update tests when behavior changes, and run the narrowest useful focused test checks.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.egress.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/Feedback.egress.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Add or update tests when a code change affects behavior.
Use focused tests such as bun test ./path/to/test-file.test.ts when validating a narrowly scoped change.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.egress.test.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/Feedback.egress.test.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.tsx
  • src/components/Feedback.egress.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  • src/components/Feedback.egress.test.ts
🔇 Additional comments (2)
src/components/Feedback.tsx (1)

67-132: LGTM!

Also applies to: 167-167, 511-512

src/components/FeedbackSurvey/submitTranscriptShare.test.ts (1)

14-16: LGTM!

Also applies to: 39-41, 131-140

Comment on lines +47 to +125
const realProviders = await import('../utils/model/providers.js')
mock.module('../utils/model/providers.js', () => ({
...realProviders,
getAPIProvider: () => 'firstParty',
isFirstPartyAnthropicBaseUrl: () => true,
}))

const realAuth = await import('../utils/auth.js')
mock.module('../utils/auth.js', () => ({
...realAuth,
checkAndRefreshOAuthTokenIfNeeded: async () => {},
}))

const realHttp = await import('../utils/http.js')
mock.module('../utils/http.js', () => ({
...realHttp,
getAuthHeaders: () => ({
headers: { Authorization: 'Bearer test' },
error: undefined,
}),
getUserAgent: () => 'test-agent',
}))

const realPrivacy = await import('../utils/privacyLevel.js')
mock.module('../utils/privacyLevel.js', () => ({
...realPrivacy,
isEssentialTrafficOnly: () => false,
}))

tempDir = await mkdtemp(join(tmpdir(), 'openclaude-feedback-egress-'))
const transcriptPath = join(tempDir, 'session.jsonl')
await writeFile(
transcriptPath,
`${JSON.stringify({
type: 'user',
uuid: '00000000-0000-4000-8000-00000000f001',
parentUuid: null,
timestamp: '2026-08-07T00:00:00.000Z',
message: { role: 'user', content: 'feedback main turn' },
})}\n${JSON.stringify({
type: 'attachment',
uuid: '00000000-0000-4000-8000-00000000f002',
parentUuid: '00000000-0000-4000-8000-00000000f001',
timestamp: '2026-08-07T00:00:00.000Z',
attachment: {
type: 'skill_listing',
content: 'Available skills:\n- /leak-me-please',
skillCount: 1,
isInitial: true,
},
})}\n`,
)

const realSession = await import('../utils/sessionStorage.js')
mock.module('../utils/sessionStorage.js', () => ({
...realSession,
getTranscriptPath: () => transcriptPath,
loadAllSubagentTranscriptsFromDisk: async () => ({
'agent-leak': [
{
type: 'attachment',
uuid: '00000000-0000-4000-8000-00000000a201',
attachment: {
type: 'agent_listing_delta',
addedTypes: ['Explore'],
addedLines: ['- Explore: /leak-agent-listing'],
removedTypes: [],
isInitial: true,
showConcurrencyNote: false,
},
},
{
type: 'user',
uuid: '00000000-0000-4000-8000-00000000a202',
message: { role: 'user', content: 'subagent turn' },
},
],
}),
}))

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
.set -euo pipefail

echo "== repo files of interest =="
git ls-files | rg '(^|/)(Feedback\.egress\.test\.ts|submitTranscriptShare\.test\.ts|AGENTS\.md)$|package\.json$' || true

echo
echo "== target test excerpt =="
if [ -f src/components/Feedback.egress.test.ts ]; then
  wc -l src/components/Feedback.egress.test.ts
  sed -n '1,230p' src/components/Feedback.egress.test.ts
fi

echo
echo "== related test excerpt =="
if [ -f src/components/FeedbackSurvey/submitTranscriptShare.test.ts ]; then
  wc -l src/components/FeedbackSurvey/submitTranscriptShare.test.ts
  sed -n '1,220p' src/components/FeedbackSurvey/submitTranscriptShare.test.ts
fi

echo
echo "== mock.module patterns in tests =="
rg -n "mock\.module|mock\.restore|afterAll|beforeAll|process\.exitCode|globalTestId|describe|it\(" src/components src/components/FeedbackSurvey src -g '*.test.ts' | head -200

Repository: Gitlawb/openclaude

Length of output: 31534


🌐 Web query:

Bun test mock.module module cache restore module override mock restore documentation

💡 Result:

In Bun's test runner, mock.module() is used to override the behavior of a module, replacing its exports with the result of a factory function [1][2]. Regarding the restoration of module mocks: 1. Restoration Behavior: While mock.restore() is designed to restore mocks to their original implementation, historically it primarily targeted function spies/mocks [3][4]. Recent updates have improved mock.restore() to better handle mock.module() overrides, specifically by reverting module namespaces and cache entries [5][6]. 2. Preload Survival: Mocks created using mock.module() during a --preload phase are considered persistent [5]. These are designed to survive calls to mock.restore(), allowing developers to keep global test setup intact while resetting other mocks between tests [5][7]. 3. Recommended Pattern: The standard practice is to use afterEach(mock.restore) in your test files to clean up transient mocks [4][5]. If you encounter issues with mocks persisting between tests, ensure you are not relying on side effects from --preload and that your environment is utilizing recent versions of Bun that support proper mock.module() eviction [5][7]. 4. Alternative Strategy: If mock.restore() does not meet your specific requirements, you can scope mocks to individual files by using bun test --isolate (experimental), which provides a fresh environment per test file, preventing cross-file mock leakage [4]. In summary, for most use cases, mock.restore() is the intended method for cleanup [5]. If transient module mocks are not being cleared as expected, verify your Bun version and consider the afterEach pattern [4][5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Feedback.egress cleanup mock presence =="
sed -n '130,155p' src/components/Feedback.egress.test.ts

echo
echo "== submission test cleanup mock presence =="
sed -n '138,150p' src/components/FeedbackSurvey/submitTranscriptShare.test.ts

echo
echo "== nearby cleanup patterns documenting process-wide mock.module"
sed -n '1,40p' src/components/ModelPicker.switchProfile.test.ts
sed -n '65,80p' src/hooks/fileSuggestions.test.ts

echo
echo "== test runner config =="
if [ -f package.json ]; then
  node -e "const p=require('./package.json'); console.log(JSON.stringify({scripts:p.scripts, devDependencies:p.devDependencies?.bun?:" (not available to avoid parse crash?)"}, null, 2))"
fi

echo
echo "== imports of affected tests in other tests =="
rg -n "Feedback\.egress|submitTranscriptShare|mock\.restore\(" src -g '*.test.ts' | head -120

Repository: Gitlawb/openclaude

Length of output: 3909


Restore the non-axios mock.module() overrides.

beforeAll() registers modules for providers, auth, HTTP, privacy, session storage, and Axios, but afterAll() restores only Axios. Bun keeps mock.module() overrides process-wide unless each override is explicitly remapped back to its captured original module. Capture stable module values for all overridden modules before mocking, and re-register each original module in afterAll. The same cleanup applies to the transcript-share egress test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Feedback.egress.test.ts` around lines 47 - 125, Update the
Feedback egress test setup and teardown to restore every module overridden by
mock.module(), not only Axios. Capture stable originals for providers, auth,
HTTP, privacy, and session storage before mocking, then re-register those
originals in afterAll; apply the same cleanup pattern to the transcript-share
egress test.

Source: Path instructions

Comment thread src/components/Feedback.egress.test.ts
Comment thread src/components/Feedback.tsx
@ussoewwin

Copy link
Copy Markdown
Author

CodeRabbit close-out (complete)

HEAD: 4bec70b3d15d2a3d795114c1a636ba255533da3f
Branch: ussoewwin:fix/moonshot-prefix-cache-on-resume

Finding Change
Outside-diff Feedback.tsx — Feedback upload egress regression Added src/components/Feedback.egress.test.ts (axios-intercepted upload). Exported assembleFeedbackEgressReportData / submitFeedback. Asserts posted content has no listing payloads while keeping normal turns.
Inline submitTranscriptShare.test.ts — restore process-wide state in afterAll Capture original process.env.USER_TYPE and whether globalThis.MACRO existed; restore/delete in afterAll.

Tests

bun test ./src/components/Feedback.egress.test.ts ./src/components/FeedbackSurvey/submitTranscriptShare.test.ts ./src/utils/sessionStorage.listingAllowlist.test.ts
→ 21 pass / 0 fail

bun run typecheck → pass
bun run typecheck:type-tests → pass (10 files)

No unfinished Outside-diff items left open on this review round.

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I found issues that need to be addressed before this is ready.

Findings

  • [P2] Rebuild remote egress omission map on print-mode resume when remote persistence is active
    src/cli/print.ts:5163
    This PR adds remoteEgressOmittedParents and rebuilds it from adopted local JSONL inside adoptResumedSessionFile() (sessionStorage.ts:2264-2270). Interactive resume paths call adopt after resetSessionFilePointer(); openclaude -p --resume / -p --continue only reset the pointer (print.ts:5163, 5401) and never rebuild. That gap was latent on main because external users did not persist listing attachments locally; this PR makes local JSONL parent chains reference withheld listing UUIDs, so the omission map matters on resume.

    Scope is narrower than “all print resume”: persistToRemote is a no-op unless CCR v2’s internalEventWriter is registered or both ENABLE_SESSION_PERSISTENCE and remoteIngressUrl are set (sessionStorage.ts:2042-2047). Plain local UUID print resume without URL/CCR hydrate often never hits remote persistence. The failure is real on paths that do — e.g. print resume from local JSONL that still contains listing attachments while CCR v2 or session-ingress persistence is enabled — where the first post-resume remote append can ship a parentUuid pointing at a listing UUID never stored remotely. URL-based hydrate writes egress-filtered remote logs (no listings), so an empty omission map is usually correct there.

    Please call adoptResumedSessionFile() (or equivalent rebuild) on print resume whenever persistence can reach remote/CCR, and add a focused test: local JSONL with a listing attachment, resume via print, assert the next remote append is reparented.

  • [P2] Hold deferred_tools_delta removals until the deferred tool pool has settled on resume
    src/utils/toolSearch.ts:750
    The removal loop here is unchanged from main; this PR newly makes it reachable for external users by persisting deferred_tools_delta in local JSONL. Runtime check on head: transcript announces mcp__docs__search, tools is still [], and getDeferredToolsDelta returns removedNames: ['mcp__docs__search']. That is the same resume race class already fixed in this PR for mcp_instructions_delta and MCP-gated agent listings.

    Reach is feature-gated for externals: getDeferredToolsDeltaAttachment only runs when isDeferredToolsDeltaEnabled() is true (USER_TYPE === 'ant' or GrowthBook tengu_glacier_2xr). When that gate is on and MCP tools join after the first attachment pass, a false removal followed by re-add is another mid-history listing rewrite and prefix-cache bust. Please mirror the MCP/agent hold logic for deferred tools and add resume-race coverage under the enabled gate.

  • [P3] Treat needs-auth MCP clients as unsettled for instruction removals
    src/utils/mcpInstructionsDelta.ts:171
    This PR correctly holds removals while mcpClients is empty or a server is still pending (mcpInstructionsDelta.test.ts). clientSetSettledForRemovals also becomes true when the only client is needs-auth (type !== 'pending'), and serverStillPending does not include that state. Runtime check on head: announced docs with mcpClients = [{ type: 'needs-auth', name: 'docs' }] returns removedNames: ['docs'] while mcpClients: [] correctly returns null. Auth-window spurious removal/re-add is a narrower edge than empty/pending, but it is the same delta churn class. Please hold name-based removals while the required server is pending or needs-auth, and add a focused test.

Call adoptResumedSessionFile after reset on print -p --continue/--resume so
remoteEgressOmittedParents rebuilds before the first CCR append (Finding 1).
Add contract tests: happy path, no-adopt negative control, local vs remote
asymmetry, multi-listing chain.
@ussoewwin

ussoewwin commented Aug 8, 2026 •

Copy link
Copy Markdown
Author

[P2] Rebuild remote egress omission map on print-mode resume when remote persistence is active — closed

HEAD: c9b1f356 on fix/moonshot-prefix-cache-on-resume
jatmn item: [P2] Rebuild remote egress omission map on print-mode resume when remote persistence is active (src/cli/print.ts:5163)

What this P2 is

Print-mode -p --resume / -p --continue only called resetSessionFilePointer() and never called adoptResumedSessionFile(). Interactive resume already adopts after reset, which rebuilds remoteEgressOmittedParents from local JSONL.

After this PR persists listing attachments locally, those listings stay in the local parentUuid chain but are withheld from remote/CCR. Without the omission map on print resume, the first post-resume remote append can ship a parentUuid pointing at a listing UUID that was never stored remotely.

Scope jatmn called out: when remote persistence can run (CCR v2 internalEventWriter, or ENABLE_SESSION_PERSISTENCE + remoteIngressUrl) — not every plain local UUID print resume.

Code change

src/cli/print.ts — after restoreSessionMetadata(...), when !options.forkSession && persistSession && result.sessionId, call adoptResumedSessionFile() on both:

  • print continue path
  • print resume path

Same order as interactive resume: reset → restore metadata → adopt (sessionFile + rebuild omission map before the first post-resume remote/CCR append).

Test command

bun test ./src/utils/sessionStorage.listingAllowlist.test.ts

Detailed results

bun test v1.3.13 (bf2e2cec)

src\utils\sessionStorage.listingAllowlist.test.ts:
(pass) isLoggableMessage retains prefix-cache listing deltas for external users (local transcript)
(pass) isSafeForExternalEgress strips prefix-cache listing deltas for external users
(pass) isLoggableMessage still filters unrelated attachments for external users
(pass) isLoggableMessage keeps hook_additional_context behind its env gate
(pass) isLoggableMessage allows all attachments for ant users
(pass) isSafeForExternalEgress strips listing attachments before ant fast path
(pass) isLoggableMessage fails closed on malformed null attachment for external users
(pass) isLoggableMessage fails closed on non-object attachment payload
(pass) local retain vs egress strip matrix for all prefix-cache listing types
(pass) filterMessagesForExternalEgress keeps conversation turns and drops listings
(pass) filterJsonlForExternalEgress strips listing lines but keeps neighbors
(pass) external egress projection preserves a walkable parentUuid chain without listing payloads
(pass) filterJsonlForExternalEgress drops unparseable non-empty lines fail-closed
(pass) normalizeMessagesForAPI after egress filter does not bake skill catalog into user text
(pass) loadTranscriptFile reloads local JSONL byte-stable through the last pre-resume message
(pass) remote-resume contract: omit-without-reparent truncates early history on hydrate path
(pass) remote-resume contract: hydrate-equivalent reparented projection walks early history as listing cache miss
(pass) filterSubagentTranscriptsForExternalEgress strips listings per agent
(pass) rebuildRemoteEgressOmittedParentsForTesting rebuilds omission ancestry from local JSONL
(pass) print-style resume adopt rebuilds omission map so remote append reparents past listing
(pass) print-style resume WITHOUT adopt leaves remote parentUuid on withheld listing
(pass) print-style resume adopt keeps listing locally while remote reparents and strips catalog
(pass) print-style resume adopt reparents past a multi-listing prefix chain

 23 pass
 0 fail
 140 expect() calls
Ran 23 tests across 1 file. [814.00ms]

Coverage for this P2

Test What it asserts
print-style resume adopt rebuilds omission map so remote append reparents past listing reset → adopt → next remote append reparents listing UUID → surviving user UUID
print-style resume WITHOUT adopt leaves remote parentUuid on withheld listing Negative control: reset only (pre-fix print path) keeps remote parentUuid on listing UUID
print-style resume adopt keeps listing locally while remote reparents and strips catalog Local JSONL still has listing + local parent=listing; remote payload only is reparented and catalog-free
print-style resume adopt reparents past a multi-listing prefix chain Nested skill_listing → agent_listing_delta; omission map compresses to user in one hop

Remaining jatmn items (not in this push — submitting next)

  • [P2] Hold deferred_tools_delta removals until the deferred tool pool has settled on resume (src/utils/toolSearch.ts:750)
  • [P3] Treat needs-auth MCP clients as unsettled for instruction removals (src/utils/mcpInstructionsDelta.ts:171)

@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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/sessionStorage.listingAllowlist.test.ts`:
- Line 952: Update enablePrintResumePersistenceForTest to save and restore
process.env.USER_TYPE alongside its existing state, then route all four affected
tests through the helper without direct USER_TYPE assignments:
src/utils/sessionStorage.listingAllowlist.test.ts lines 952, 1148, 1230, and
1321. Preserve each test’s external-user behavior while ensuring the environment
variable is restored after every test.
- Around line 953-1046: Update this test to reuse the existing
enablePrintResumePersistenceForTest setup and restore helpers, and replace the
inline post-resume assistant message construction with
postResumeAssistantMessage. Preserve the test’s existing assertions and flow
while removing the duplicated environment setup, cleanup, and message
definition.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e338b432-1fd0-46e2-96f7-092fce18bd36

📥 Commits

Reviewing files that changed from the base of the PR and between 4bec70b and c9b1f35.

📒 Files selected for processing (2)
  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/cli/print.ts
  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Add or update tests when behavior changes, and run the narrowest useful focused test checks.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Add or update tests when a code change affects behavior.
Use focused tests such as bun test ./path/to/test-file.test.ts when validating a narrowly scoped change.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/sessionStorage.listingAllowlist.test.ts
🔇 Additional comments (3)
src/utils/sessionStorage.listingAllowlist.test.ts (3)

1005-1005: switchSession(sessionId as never, dir) still uses an as never cast. Prefer as unknown as SessionId.


1389-1392: LGTM!


1295-1300: 🎯 Functional Correctness

No duplicate JSON.parse call is present.

The chain runs JSON.parse(line) only once before .find(...), so this concern does not apply.

			> Likely an incorrect or invalid review comment.

Comment thread src/utils/sessionStorage.listingAllowlist.test.ts Outdated
Comment thread src/utils/sessionStorage.listingAllowlist.test.ts Outdated
@ussoewwin

Copy link
Copy Markdown
Author

CodeRabbit review 4887934171 — closed

HEAD: 5f9fd15d on fix/moonshot-prefix-cache-on-resume

Actionable Change
USER_TYPE leak in four print-resume tests (discussion) enablePrintResumePersistenceForTest now saves/restores process.env.USER_TYPE (sets external). Direct USER_TYPE assignments removed from all four print-resume tests.
Deduplicate first print-resume test setup (discussion) Same test now uses enablePrintResumePersistenceForTest + postResumeAssistantMessage + persist.restore() instead of inline env/message/cleanup.

Tests: bun test ./src/utils/sessionStorage.listingAllowlist.test.ts — 23 pass.

@ussoewwin

Copy link
Copy Markdown
Author

Finding 2 (jatmn P2) — deferred_tools_delta resume hold

HEAD: 9644d077

Change

Hold deferred_tools_delta removals until the tool / MCP pool has settled on resume (same class as mcp_instructions_delta + agent listing MCP holds):

Condition Behavior
tools.length === 0 Hold all removals (empty pool ≠ mass disconnect)
Announced mcp__… while that server is pending Hold that removal
Announced mcp__… while MCP client set unsettled and no MCP tools in pool Hold MCP removals
Pool settled / server gone Emit removal as before

Wired mcpClients through getDeferredToolsDelta / getDeferredToolsDeltaAttachment (attachments + compact call sites).

Tests

bun test src/utils/deferredToolsDelta.malformed.test.ts src/utils/deferredToolsDelta.resumeRace.test.ts
→ 11 pass

Closes jatmn review Finding 2 / P2 on toolSearch removal loop.

Add alternate-angle cases (all-pending MCP, undeferred silent, two-pass resume, reappear after settle, ant attachment wrapper). Align comments with jatmn [P2] wording.
@ussoewwin

Copy link
Copy Markdown
Author

Addressed: jatmn [P2] — deferred tools hold + expanded resume-race tests

PR: #2070
Branch tip: e4db0f2b (fix/moonshot-prefix-cache-on-resume)
Review item (verbatim title): [P2] Hold deferred_tools_delta removals until the deferred tool pool has settled on resume

Code (already on tip from 9644d077, tests expanded this commit)

getDeferredToolsDelta (src/utils/toolSearch.ts) holds removals when:

  • tools.length === 0 (pool not loaded yet)
  • MCP-named removals while that server is still pending
  • MCP removals while no MCP tools are in the pool and the client set is unsettled (empty / all-pending)

Otherwise removals emit as before. getDeferredToolsDeltaAttachment / compact call sites pass mcpClients.

Test command

bun test src/utils/deferredToolsDelta.resumeRace.test.ts src/utils/deferredToolsDelta.malformed.test.ts src/utils/mcpInstructionsDelta.test.ts src/utils/attachments.agentListingResume.test.ts src/utils/sessionStorage.listingAllowlist.test.ts src/utils/toolSearch.test.ts

Result summary

  • 80 pass / 0 fail
  • 257 expect() calls
  • 6 files, ~786ms (bun test v1.3.13)

Per-file detail

deferredToolsDelta.resumeRace.test.ts (11) — [P2] focus + extra angles

  • holds removals when tools pool is empty (resume race)
  • holds MCP removals while MCP client set is unsettled
  • holds MCP removals while that server is still pending
  • removes MCP tool once client set settled and server gone
  • removes non-MCP deferred tool once pool is non-empty
  • holds MCP removals while every MCP client is still pending (sibling of instructions hold)
  • does not report removal when announced tool is still in pool but no longer deferred
  • two-pass resume: empty pool holds, then settled pool emits removal
  • keeps announced MCP tool when it reappears as deferred after resume
  • attachment wrapper holds empty-pool removal (gate + call-site angle)
  • attachment wrapper emits removal once MCP pool settled (gate + call-site angle)

deferredToolsDelta.malformed.test.ts (6)

  • null / partial / missing addedLines / non-string addedLines fail-closed
  • empty-pool hold + settled removal for complete records

mcpInstructionsDelta.test.ts (11) — sibling hold pattern

  • unchanged / same-name refresh / empty clients / all-pending / pending+connected / settled removals / connected without instructions / reconstruction / malformed / newly connected

attachments.agentListingResume.test.ts (21) — sibling agent listing hold

  • suppress latch / restore / recovered announced set / MCP-gated hold while pool empty or server pending / emit once MCP in pool / in-REPL restore contract

sessionStorage.listingAllowlist.test.ts (23) — local retain vs egress strip

  • local retain / egress strip / malformed fail-closed / matrix / JSONL filter / parentUuid chain / print-style resume adopt / subagent egress

toolSearch.test.ts (8)

  • resolveToolSearchMode + modelSupportsToolReference (HY3 / kill switch / ENABLE_TOOL_SEARCH)

Full console transcript

bun test v1.3.13 (bf2e2cec)

src\utils\attachments.agentListingResume.test.ts:
(pass) suppressNextAgentListing skips duplicate listing once when agent set is unchanged
(pass) suppressNextAgentListing still emits delta when agent set changed across resume
(pass) resetSentSkillNames clears the agent-listing suppress latch
(pass) restoreSkillStateFromMessages arms agent suppress and skips duplicate on resume pass
(pass) restoreSkillStateFromMessages still allows agent delta when available set changed
(pass) suppressNextAgentListing re-announces when same-type whenToUse changed across resume
(pass) getAgentListingDeltaAttachment re-announces when same-type tool policy changed
(pass) suppressNextAgentListing still skips when same-type content matches transcript
(pass) suppressNextAgentListing uses recovered announced set when messages lack listing
(pass) suppressNextAgentListing emits corrective delta from recovered set when messages lack listing
(pass) restoreSkillStateFromMessages retains recovered set for unhydrated first pass
(pass) restoreSkillStateFromMessages ignores partial agent_listing_delta before arming suppress
(pass) restoreSkillStateFromMessages ignores mismatched-length agent_listing_delta
(pass) prepareInReplResumeListingState clears prior suppress latch before restore
(pass) prepareInReplResumeListingState restores transcript listing after clear
(pass) getAgentListingDeltaAttachment ignores mismatched addedTypes/addedLines lengths
(pass) getAgentListingDeltaAttachment ignores non-string agent delta entries
(pass) holds MCP-gated agent removals while MCP tool pool is still empty
(pass) holds MCP-gated agent removals while required server is still pending
(pass) emits MCP-gated agent removal once MCP tools are in the pool
(pass) in-REPL resume contract: restoreSkillStateFromMessages after deserialize arms suppress

src\utils\deferredToolsDelta.malformed.test.ts:
(pass) getDeferredToolsDelta skips null attachment payloads without throwing
(pass) getDeferredToolsDelta skips partial deferred_tools_delta without removedNames
(pass) getDeferredToolsDelta ignores record missing addedLines and emits current deferred tool as addition
(pass) getDeferredToolsDelta ignores non-string addedLines and emits current deferred tool as addition
(pass) getDeferredToolsDelta holds removals for complete records when tools pool is empty
(pass) getDeferredToolsDelta removes announced tool once pool is settled without it

src\utils\deferredToolsDelta.resumeRace.test.ts:
(pass) getDeferredToolsDelta holds removals when tools pool is empty (resume race)
(pass) getDeferredToolsDelta holds MCP removals while MCP client set is unsettled
(pass) getDeferredToolsDelta holds MCP removals while that server is still pending
(pass) getDeferredToolsDelta removes MCP tool once client set settled and server gone
(pass) getDeferredToolsDelta removes non-MCP deferred tool once pool is non-empty
(pass) holds MCP removals while every MCP client is still pending (sibling of instructions hold)
(pass) does not report removal when announced tool is still in pool but no longer deferred
(pass) two-pass resume: empty pool holds, then settled pool emits removal
(pass) keeps announced MCP tool when it reappears as deferred after resume
(pass) attachment wrapper holds empty-pool removal (gate + call-site angle)
(pass) attachment wrapper emits removal once MCP pool settled (gate + call-site angle)

src\utils\mcpInstructionsDelta.test.ts:
(pass) getMcpInstructionsDelta returns null when same-name block is unchanged
(pass) getMcpInstructionsDelta re-announces when same-name instructions change after resume
(pass) getMcpInstructionsDelta does not remove when mcpClients empty (not settled yet)
(pass) getMcpInstructionsDelta does not remove while every client is still pending
(pass) getMcpInstructionsDelta does not remove docs while docs is pending and other is connected
(pass) getMcpInstructionsDelta removes disconnected servers once client set is settled
(pass) getMcpInstructionsDelta removes a connected server that no longer has instructions
(pass) getAnnouncedMcpInstructionBlocks applies removals before same-name re-adds
(pass) getAnnouncedMcpInstructionBlocks ignores mismatched addedNames/addedBlocks lengths
(pass) getAnnouncedMcpInstructionBlocks ignores non-string mcp delta entries
(pass) getMcpInstructionsDelta announces newly connected servers

src\utils\sessionStorage.listingAllowlist.test.ts:
(pass) isLoggableMessage retains prefix-cache listing deltas for external users (local transcript)
(pass) isSafeForExternalEgress strips prefix-cache listing deltas for external users
(pass) isLoggableMessage still filters unrelated attachments for external users
(pass) isLoggableMessage keeps hook_additional_context behind its env gate
(pass) isLoggableMessage allows all attachments for ant users
(pass) isSafeForExternalEgress strips listing attachments before ant fast path
(pass) isLoggableMessage fails closed on malformed null attachment for external users
(pass) isLoggableMessage fails closed on non-object attachment payload
(pass) local retain vs egress strip matrix for all prefix-cache listing types
(pass) filterMessagesForExternalEgress keeps conversation turns and drops listings
(pass) filterJsonlForExternalEgress strips listing lines but keeps neighbors
(pass) external egress projection preserves a walkable parentUuid chain without listing payloads
(pass) filterJsonlForExternalEgress drops unparseable non-empty lines fail-closed
(pass) normalizeMessagesForAPI after egress filter does not bake skill catalog into user text
(pass) loadTranscriptFile reloads local JSONL byte-stable through the last pre-resume message
(pass) remote-resume contract: omit-without-reparent truncates early history on hydrate path
(pass) remote-resume contract: hydrate-equivalent reparented projection walks early history as listing cache miss
(pass) filterSubagentTranscriptsForExternalEgress strips listings per agent
(pass) rebuildRemoteEgressOmittedParentsForTesting rebuilds omission ancestry from local JSONL
(pass) print-style resume adopt rebuilds omission map so remote append reparents past listing
(pass) print-style resume WITHOUT adopt leaves remote parentUuid on withheld listing
(pass) print-style resume adopt keeps listing locally while remote reparents and strips catalog
(pass) print-style resume adopt reparents past a multi-listing prefix chain

src\utils\toolSearch.test.ts:
(pass) resolveToolSearchMode > defaults to tst when nothing is configured
(pass) resolveToolSearchMode > kill switch forces standard mode on Anthropic-wire providers
(pass) resolveToolSearchMode > kill switch does not disable tool search on converted-wire providers
(pass) resolveToolSearchMode > explicit ENABLE_TOOL_SEARCH=false still disables everywhere
(pass) resolveToolSearchMode > auto mode is preserved on converted-wire providers despite kill switch
(pass) modelSupportsToolReference > keeps Tencent HY3 on the inline tool-schema path
(pass) modelSupportsToolReference > does not defer TaskCreate for Tencent HY3
(pass) modelSupportsToolReference > keeps built-in HY3 compatibility when feature flags add exceptions

 80 pass
 0 fail
 257 expect() calls
Ran 80 tests across 6 files.

Still open (next)

  • [P3] Treat needs-auth MCP clients as unsettled for instruction removals (mcpInstructionsDelta.ts) — not in this commit. Will address after this [P2] close-out.

@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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utils/deferredToolsDelta.resumeRace.test.ts`:
- Around line 125-135: Update getDeferredToolsDelta so MCP clients with a
needs-auth status are treated as unsettled alongside pending clients, preventing
removals until authorization is resolved. Add a focused regression test in the
deferred-tools resume race tests using a needs-auth client and assert the result
is null, while preserving the existing pending-client behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b183b241-565a-4e62-8771-29b1abfb50c3

📥 Commits

Reviewing files that changed from the base of the PR and between 9644d07 and e4db0f2.

📒 Files selected for processing (1)
  • src/utils/deferredToolsDelta.resumeRace.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Add or update tests when behavior changes, and run the narrowest useful focused test checks.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Add or update tests when a code change affects behavior.
Use focused tests such as bun test ./path/to/test-file.test.ts when validating a narrowly scoped change.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
🔇 Additional comments (1)
src/utils/deferredToolsDelta.resumeRace.test.ts (1)

1-18: LGTM!

Also applies to: 59-121, 137-211

Comment on lines +125 to +135
test('holds MCP removals while every MCP client is still pending (sibling of instructions hold)', () => {
const messages = [
deltaMessage(['mcp__docs__search'], ['mcp__docs__search']),
]
const tools = [{ name: 'SomeBuiltin', isMcp: false }] as unknown as Tools
const delta = getDeferredToolsDelta(tools, messages, undefined, [
pending('docs'),
pending('other'),
])
expect(delta).toBeNull()
})

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep needs-auth MCP clients unsettled.

This test covers only pending clients. getDeferredToolsDelta currently treats every non-pending client as settled, so a needs-auth client can emit a removal while its MCP server still requires authorization. Add a needs-auth regression case that expects null, and exclude needs-auth from the settlement predicate.

As per coding guidelines, add or update tests when behavior changes. As per path instructions, block risky runtime changes that lack focused regression coverage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/deferredToolsDelta.resumeRace.test.ts` around lines 125 - 135,
Update getDeferredToolsDelta so MCP clients with a needs-auth status are treated
as unsettled alongside pending clients, preventing removals until authorization
is resolved. Add a focused regression test in the deferred-tools resume race
tests using a needs-auth client and assert the result is null, while preserving
the existing pending-client behavior.

Sources: Coding guidelines, Path instructions

Hold deferred_tools_delta, mcp_instructions_delta, and agent-listing
removals while a required MCP client is needs-auth (same as pending).
Add regression tests; Feedback submitReport deps + egress assert.

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utils/toolSearch.ts (1)

750-755: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Apply deferred-tool removals before additions.

Lines 750-755 add names before they remove names. If one valid delta removes and re-adds the same tool name, reconstruction leaves that tool absent. The next pass then emits an unnecessary listing delta.

Process removedNames first. Then process addedNames. Add a focused regression test with the same name in both arrays.

As per coding guidelines, add or update tests when behavior changes. As per path instructions, preserve regression coverage for changed resume behavior.

Proposed fix
-    for (const n of addedNames) {
-      announced.add(n)
-    }
     for (const n of removedNames) {
       announced.delete(n)
     }
+    for (const n of addedNames) {
+      announced.add(n)
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/toolSearch.ts` around lines 750 - 755, In the deferred-tool
reconstruction loop, process every name in removedNames before processing names
in addedNames so a name present in both arrays remains announced. Add a focused
regression test covering the same tool name in both deltas and verify the next
pass emits no unnecessary listing delta.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Feedback.egress.test.ts`:
- Line 192: Run the required validation checks for the Feedback changes: bun
test ./src/components/Feedback.egress.test.ts, bun run typecheck, bun run
typecheck:type-tests, and the repository-defined build check in AGENTS.md.
Report the exact commands and their results before merge.

In `@src/components/Feedback.tsx`:
- Line 242: Update the dependency array for the submitReport callback to include
abortSignal alongside the existing dependencies, ensuring both submission and
title generation use the current signal when it changes.

---

Outside diff comments:
In `@src/utils/toolSearch.ts`:
- Around line 750-755: In the deferred-tool reconstruction loop, process every
name in removedNames before processing names in addedNames so a name present in
both arrays remains announced. Add a focused regression test covering the same
tool name in both deltas and verify the next pass emits no unnecessary listing
delta.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bd55f7f7-89a1-4c6c-b7f2-7e61a6cdc884

📥 Commits

Reviewing files that changed from the base of the PR and between e4db0f2 and a2461f6.

📒 Files selected for processing (9)
  • src/components/Feedback.egress.test.ts
  • src/components/Feedback.tsx
  • src/services/mcp/types.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/utils/attachments.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/toolSearch.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript strict mode and ESM imports throughout the source code.

Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.

Files:

  • src/utils/toolSearch.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/services/mcp/types.ts
  • src/components/Feedback.tsx
  • src/utils/attachments.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/mcpInstructionsDelta.test.ts
**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use React and Ink patterns for terminal UI components.

Files:

  • src/utils/toolSearch.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/services/mcp/types.ts
  • src/components/Feedback.tsx
  • src/utils/attachments.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/mcpInstructionsDelta.test.ts
src/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.ts: Prefer existing service, provider, settings, permission, and UI patterns over introducing new abstractions.
Use chalk for terminal color and execa for child-process execution when those capabilities are needed.

Files:

  • src/utils/toolSearch.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/services/mcp/types.ts
  • src/utils/attachments.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/mcpInstructionsDelta.test.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add new Python code, Python provider paths, or Python dependencies without explicit maintainer approval.

**/*.{ts,tsx,js,jsx}: Follow the existing code style in touched source files, prefer small readable changes, avoid unrelated reformatting, and keep comments useful and concise.
Preserve existing repository patterns unless intentionally refactoring them, and avoid broad rewrites or unnecessary generated changes.
Review AI-assisted code for correctness, style consistency, unnecessary changes, and adherence to project architecture before submitting it.

Files:

  • src/utils/toolSearch.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/services/mcp/types.ts
  • src/components/Feedback.tsx
  • src/utils/attachments.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/mcpInstructionsDelta.test.ts
**/*

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Update documentation when setup, commands, or user-facing behavior changes.

Files:

  • src/utils/toolSearch.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/services/mcp/types.ts
  • src/components/Feedback.tsx
  • src/utils/attachments.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/mcpInstructionsDelta.test.ts

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/toolSearch.ts
  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/services/mcp/types.ts
  • src/components/Feedback.tsx
  • src/utils/attachments.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.ts
  • src/utils/mcpInstructionsDelta.test.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Add or update tests when behavior changes, and run the narrowest useful focused test checks.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{test,spec}.{ts,tsx,js,jsx}: Add or update tests when a code change affects behavior.
Use focused tests such as bun test ./path/to/test-file.test.ts when validating a narrowly scoped change.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/utils/deferredToolsDelta.resumeRace.test.ts
  • src/utils/attachments.agentListingResume.test.ts
  • src/components/Feedback.egress.test.ts
  • src/utils/mcpInstructionsDelta.test.ts
src/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Use existing service and provider integration patterns when implementing API, MCP, OAuth, wiki, voice, or related integrations.

Files:

  • src/services/mcp/types.ts
src/{skills,utils/plugins,services/mcp}/**

⚙️ CodeRabbit configuration file

src/{skills,utils/plugins,services/mcp}/**: Review skill/plugin/MCP behavior as a trust boundary. Check registry fetches, local and remote installs, path normalization, hash verification, revocation/trust metadata, tools_required handling, config-home behavior, and startup-time loading. Block on path traversal risk, unverified downloads, silent trust promotion, or unexpected code/tool activation.

Files:

  • src/services/mcp/types.ts
🔇 Additional comments (8)
src/utils/attachments.ts (1)

190-193: LGTM!

Also applies to: 1741-1759

src/services/mcp/types.ts (1)

228-237: LGTM!

src/utils/mcpInstructionsDelta.ts (1)

3-6: LGTM!

Also applies to: 166-187

src/utils/attachments.agentListingResume.test.ts (1)

436-480: LGTM!

src/utils/mcpInstructionsDelta.test.ts (1)

93-104: LGTM!

Also applies to: 127-144

src/utils/deferredToolsDelta.resumeRace.test.ts (1)

59-65: LGTM!

Also applies to: 109-133

src/components/Feedback.tsx (1)

28-28: LGTM!

Also applies to: 67-132, 167-167, 214-220, 511-512

src/components/Feedback.egress.test.ts (1)

1-156: LGTM!

Also applies to: 158-196

expect(postedBodies).toHaveLength(1)
const content = postedBodies[0]?.content ?? ''
expect(content).toContain('plain turn')
expect(content).toContain('feedback main turn')

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.

🎯 Functional Correctness | 🔵 Trivial

Run the required checks before merge.

No test, typecheck, or build results are included in this review. Run:

  • bun test ./src/components/Feedback.egress.test.ts
  • bun run typecheck
  • bun run typecheck:type-tests
  • The repository-defined build check from AGENTS.md

As per coding guidelines, “Run bun run typecheck and bun run typecheck:type-tests for TypeScript changes when applicable.” As per path instructions, “Run narrow Bun tests plus typecheck/build checks and report exact commands.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Feedback.egress.test.ts` at line 192, Run the required
validation checks for the Feedback changes: bun test
./src/components/Feedback.egress.test.ts, bun run typecheck, bun run
typecheck:type-tests, and the repository-defined build check in AGENTS.md.
Report the exact commands and their results before merge.

Sources: Coding guidelines, Path instructions

Comment thread src/components/Feedback.tsx Outdated
@ussoewwin

Copy link
Copy Markdown
Author

Bot close-out (a2461f6e)

Addressed still-valid CodeRabbit / jatmn items on HEAD.

Item Change
[P3] Treat needs-auth MCP clients as unsettled for instruction removals isMcpClientUnsettledForRemovals (pending | needs-auth) in src/services/mcp/types.ts; used by getMcpInstructionsDelta, getDeferredToolsDelta, and agent-listing hold in attachments.ts
CodeRabbit: getDeferredToolsDelta needs-auth regression Tests in deferredToolsDelta.resumeRace.test.ts
Feedback submitReport deps backgroundTasks added to useCallback deps
Feedback egress body assert Posted content must include feedback main turn

Tests

bun test src/utils/deferredToolsDelta.resumeRace.test.ts \
  src/utils/mcpInstructionsDelta.test.ts \
  src/utils/attachments.agentListingResume.test.ts \
  src/components/Feedback.egress.test.ts
→ 49 pass / 0 fail

N/A (already on HEAD from prior commits)

  • Print-resume USER_TYPE restore / helper inlining — covered by 5f9fd15d
  • Recovered-baseline corrective agent-listing delta — already in attachments.agentListingResume.test.ts
  • Malformed / partial delta parser hardening — already on branch

@ussoewwin

Copy link
Copy Markdown
Author

Bot close-out — 3fb14c4c

Branch: fix/moonshot-prefix-cache-on-resume
HEAD: 3fb14c4cd3509ee16699780a0a450555b7e60f22

Closes CodeRabbit review 4888222038 (Actionable: 2 + Caution outside-diff).

Item Change
Outside-diff src/utils/toolSearch.ts (~750–755) — process removedNames before addedNames so a name in both stays announced Reconstruction loop now removes first, then adds. Regression: reconstruction applies removals before additions for same name (CodeRabbit outside-diff) in deferredToolsDelta.resumeRace.test.ts
Inline Feedback.tsx — abortSignal missing from submitReport useCallback deps Deps: [abortSignal, backgroundTasks, description, envInfo.isGit, messages]
Inline Feedback.egress.test.ts — run required checks and report Ran (see below)

Checks run (this turn / prior same close-out)

bun test ./src/utils/deferredToolsDelta.resumeRace.test.ts \
  ./src/utils/deferredToolsDelta.malformed.test.ts \
  ./src/components/Feedback.egress.test.ts \
  ./src/utils/mcpInstructionsDelta.test.ts \
  ./src/utils/attachments.agentListingResume.test.ts
→ 56 pass / 0 fail

No open “in progress” items remaining for review 4888222038.

@ussoewwin

Copy link
Copy Markdown
Author

[P3] Treat needs-auth MCP clients as unsettled for instruction removals — addressed

Head: e770e64e (fix/moonshot-prefix-cache-on-resume)
Fix commit: a2461f6e — isMcpClientUnsettledForRemovals (pending | needs-auth) wired into mcpInstructionsDelta (and sibling resume-hold paths)
Tests commit: e770e64e — alternate-angle coverage in mcpInstructionsDelta.needsAuthAngle.test.ts

Finding (verbatim ask)

Hold name-based instruction removals while the required server is pending or needs-auth.
Old bug: type !== 'pending' treated needs-auth as settled → announced docs + mcpClients = [{ type: 'needs-auth', name: 'docs' }] returned removedNames: ['docs'], while mcpClients: [] correctly returned null.

Change

Item Status
needs-auth unsettled for instruction removals Done (isMcpClientUnsettledForRemovals)
Empty mcpClients still holds (null / no attachment) Done
Mixed: connected other + needs-auth docs does not remove docs Done
Focused + alternate-angle tests Done

Detailed test results (just re-run)

bun test \
  ./src/utils/mcpInstructionsDelta.test.ts \
  ./src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts \
  ./src/utils/deferredToolsDelta.resumeRace.test.ts \
  ./src/utils/attachments.agentListingResume.test.ts

→ 58 pass / 0 fail
  116 expect() calls
  Ran 58 tests across 4 files. [1092.00ms]

A. Direct getMcpInstructionsDelta (includes jatmn [P3] cases)

Test Result
does not remove when mcpClients empty pass
does not remove while every client is still pending pass
does not remove while every client needs-auth (jatmn [P3]) pass
does not remove docs while docs is pending and other is connected pass
does not remove docs while docs needs-auth and other is connected pass
removes disconnected servers once client set is settled pass
(+ remaining mcpInstructionsDelta unit cases) pass

B. Alternate angles (mcpInstructionsDelta.needsAuthAngle.test.ts) — 9/9 pass

Angle Test Result
Production attachment wrapper needs-auth docs alone → no mcp_instructions_delta pass
Production attachment wrapper empty mcpClients → no removal attachment pass
Production attachment wrapper settled other + missing docs → removal attachment pass
Old buggy predicate contrast type !== 'pending' would remove needs-auth docs; current holds pass
Old buggy predicate contrast mixed connected + needs-auth: old removes docs; current holds pass
Two-pass resume needs-auth hold → same-name connected does not remove pass
Two-pass resume needs-auth hold → only other connected removes docs pass
Settled contrast failed docs alone authorizes removal pass
Settled contrast disabled docs alone authorizes removal pass

C. Sibling resume-hold paths (same unsettled helper)

Suite Notable [P3]-related cases Result
deferredToolsDelta.resumeRace.test.ts holds MCP removals while server needs-auth; every client needs-auth pass (14)
attachments.agentListingResume.test.ts holds MCP-gated agent removals while required server needs-auth pass (22)

Runtime check (jatmn scenario)

Input Result
announced docs + [{ type: 'needs-auth', name: 'docs' }] null (no removedNames: ['docs'])
mcpClients: [] null

@ussoewwin

Copy link
Copy Markdown
Author

Bot / maintainer close-out — e770e64e

PR: #2070
Branch: fix/moonshot-prefix-cache-on-resume
HEAD: e770e64e00d8f4b0d9e041f85772019f677ebe23

Closes still-valid jatmn / CodeRabbit items on current HEAD (including follow-up coverage after 3fb14c4c / a2461f6e).

Finding Change on HEAD
jatmn [P2] Rebuild remote egress omission map on print-mode resume src/cli/print.ts — adoptResumedSessionFile() after resume paths so remoteEgressOmittedParents is rebuilt against the resumed JSONL
jatmn [P2] Hold deferred_tools_delta removals until tool / MCP pool settled Hold gates + resume-race / attachment-wrapper tests in deferredToolsDelta.resumeRace.test.ts
jatmn [P3] Treat needs-auth MCP clients as unsettled for resume removals isMcpClientUnsettledForRemovals in src/services/mcp/types.ts; instructions + deferred-tools hold; alternate-angle tests in mcpInstructionsDelta.needsAuthAngle.test.ts
CodeRabbit Process deferred_tools removals before additions (same name) src/utils/toolSearch.ts — apply removedNames then addedNames; covered in resume-race test
CodeRabbit Feedback abortSignal dependency src/components/Feedback.tsx — abortSignal included in effect deps

Tip since prior comment (3fb14c4c)

  • e770e64e — alternate-angle coverage for MCP needs-auth instruction hold [P3] (attachment wrapper, two-pass resume, failed/disabled contrast, old-predicate regression)

Obsolete / not a #2070 actionable

Validation

bun test src/utils/mcpInstructionsDelta.needsAuthAngle.test.ts \
  src/utils/mcpInstructionsDelta.test.ts \
  src/utils/deferredToolsDelta.resumeRace.test.ts \
  src/components/Feedback.egress.test.ts
→ 37 pass, 0 fail

Ready for re-review.

@jatmn

jatmn commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Closing this PR rather than requesting another patch round.

The underlying report is valid: local resume needs to preserve the same model-visible ordered history when prefix caching depends on it. But this branch is no longer a reviewable fix for that problem. It has accumulated serial follow-ups across transcript privacy, remote/CCR persistence, feedback and sharing, MCP lifecycle policy, compaction, print-mode resume, and an unrelated web release test. Continuing to apply individual review-bot suggestions here has made the design and regression surface too broad to merge safely.

Please do not keep amending this branch. Reopen the work as a small ordered series, with each PR independently reviewable and revertible:

  1. External transcript projection — establish one privacy boundary for remote persistence, CCR, sharing, and feedback. It must omit listing payloads from every external path while preserving a walkable parent chain. Do not change local logging or resume behavior in this PR.

  2. Local resume-prefix preservation — retain the model-visible listing attachments in the existing local ordered JSONL history and restore them unchanged for local --resume / --continue. Add only the minimal recovery/suppression behavior needed to avoid re-announcing an unchanged catalog. Prove the end-to-end local prefix contract.

  3. MCP listing lifecycle — separately define and test how agent listings, MCP instructions, and deferred tools behave while servers are pending, need auth, fail, are disabled, or are removed. This must distinguish initial connection from a deliberately empty configuration, and include compaction's required reannouncement behavior.

  4. Print/remote-resume parity, if it remains necessary after the projection contract lands — keep it limited to the relevant entry points and prove both the private remote projection and the local prefix-stable chain.

Explicitly leave web/src/data/releases.test.ts out of this work; release catalog validation belongs in release/web-owned work. Do not introduce another replay cache, aggregate reconstruction layer, or alternate transcript representation: the local JSONL should remain the authoritative ordered history.

For future PRs, treat cross-cutting automated-review suggestions as candidates for a follow-up issue/PR unless they are necessary to the narrow contract under review. A large test matrix does not make an otherwise cross-cutting patch focused.

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.

3 participants