test: session git-path decoding + recap loop detection boundaries#401
test: session git-path decoding + recap loop detection boundaries#401anandgupta42 wants to merge 1 commit intomainfrom
Conversation
Add tests for two previously untested code paths: 1. SessionSummary's unquoteGitPath — decodes git's C-style quoted paths with octal-encoded UTF-8 (CJK, accented characters), preventing garbled filenames in session diffs. 2. Recap loop detection boundary behavior — history pruning at 201 entries preserves recent evidence, and two simultaneous distinct loops are both detected correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> https://claude.ai/code/session_01UgL6G8jZAPtoUUKBphH7f4
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review to trigger a review.
Tip: disable this comment in your organization's Code Review settings.
📝 WalkthroughWalkthroughTwo new test suites added to validate loop detection with pruned tool-call history and Git-quoted file path decoding behavior in SessionSummary.diff(). Both suites contain comprehensive test cases covering edge cases and encoding scenarios. No changes to public APIs or exported entities. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/opencode/test/session/summary-git-path.test.ts`:
- Around line 21-174: Tests currently reuse a shared projectRoot for
Instance.provide causing shared Storage state; switch each test to create an
isolated temporary directory via await using tmp = await tmpdir() and pass
tmp.path to Instance.provide (replace references to projectRoot), so roundtrip
and SessionSummary.diff run against an isolated tmp workspace and auto-clean on
scope exit; ensure any test helpers that depend on the repo root (e.g.,
roundtrip, Identifier.ascending sessionID usage) continue to work unchanged but
are invoked inside the await using block so Storage writes/read are isolated per
test.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 103b0f89-5697-46ed-bdc0-c830c4ace8f9
📒 Files selected for processing (2)
packages/opencode/test/altimate/tracing.test.tspackages/opencode/test/session/summary-git-path.test.ts
| const projectRoot = path.join(__dirname, "../..") | ||
| Log.init({ print: false }) | ||
|
|
||
| // Helper: write fake diffs to Storage for a session, then read them back via diff() | ||
| async function roundtrip(files: string[]): Promise<string[]> { | ||
| const sessionID = Identifier.ascending("session") as any | ||
| const diffs = files.map((file) => ({ | ||
| file, | ||
| before: "", | ||
| after: "", | ||
| additions: 1, | ||
| deletions: 0, | ||
| status: "added" as const, | ||
| })) | ||
|
|
||
| await Storage.write(["session_diff", sessionID], diffs) | ||
| const result = await SessionSummary.diff({ sessionID }) | ||
| return result.map((d) => d.file) | ||
| } | ||
|
|
||
| describe("SessionSummary.diff: unquoteGitPath decoding", () => { | ||
| test("plain ASCII paths pass through unchanged", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| const files = await roundtrip([ | ||
| "src/index.ts", | ||
| "README.md", | ||
| "packages/opencode/test/file.test.ts", | ||
| ]) | ||
| expect(files).toEqual([ | ||
| "src/index.ts", | ||
| "README.md", | ||
| "packages/opencode/test/file.test.ts", | ||
| ]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("git-quoted path with octal-encoded UTF-8 (2-byte: é = \\303\\251)", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| // Git quotes "café.txt" as "caf\\303\\251.txt" | ||
| const files = await roundtrip(['"caf\\303\\251.txt"']) | ||
| expect(files).toEqual(["café.txt"]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("git-quoted path with 3-byte UTF-8 octal (CJK character 中 = \\344\\270\\255)", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| // Git quotes "中文.txt" as "\\344\\270\\255\\346\\226\\207.txt" | ||
| const files = await roundtrip(['"\\344\\270\\255\\346\\226\\207.txt"']) | ||
| expect(files).toEqual(["中文.txt"]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("git-quoted path with standard escape sequences (\\n, \\t, \\\\, \\\")", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| const files = await roundtrip([ | ||
| '"path\\\\with\\\\backslashes"', | ||
| '"file\\twith\\ttabs"', | ||
| '"line\\nbreak"', | ||
| ]) | ||
| expect(files).toEqual([ | ||
| "path\\with\\backslashes", | ||
| "file\twith\ttabs", | ||
| "line\nbreak", | ||
| ]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("mixed octal and plain ASCII in one path", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| // "docs/résumé.md" → git quotes accented chars only | ||
| // é = \303\251 in UTF-8 | ||
| const files = await roundtrip(['"docs/r\\303\\251sum\\303\\251.md"']) | ||
| expect(files).toEqual(["docs/résumé.md"]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("unquoted path (no surrounding double quotes) passes through unchanged", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| // If git doesn't quote the path, it should pass through as-is | ||
| const files = await roundtrip(["normal/path.ts", "another-file.js"]) | ||
| expect(files).toEqual(["normal/path.ts", "another-file.js"]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("path with embedded double quote (\\\")", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| const files = await roundtrip(['"file\\"name.txt"']) | ||
| expect(files).toEqual(['file"name.txt']) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("empty string passes through unchanged", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| const files = await roundtrip([""]) | ||
| expect(files).toEqual([""]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("Japanese filename with 3-byte UTF-8 sequences (テスト = \\343\\203\\206\\343\\202\\271\\343\\203\\210)", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| // テ = E3 83 86 = \343\203\206 | ||
| // ス = E3 82 B9 = \343\202\271 | ||
| // ト = E3 83 88 = \343\203\210 | ||
| const files = await roundtrip(['"\\343\\203\\206\\343\\202\\271\\343\\203\\210.sql"']) | ||
| expect(files).toEqual(["テスト.sql"]) | ||
| }, | ||
| }) | ||
| }) | ||
|
|
||
| test("multiple files: some quoted, some not", async () => { | ||
| await Instance.provide({ | ||
| directory: projectRoot, | ||
| fn: async () => { | ||
| const files = await roundtrip([ | ||
| "plain.ts", | ||
| '"caf\\303\\251.txt"', | ||
| "normal/path.js", | ||
| '"\\344\\270\\255.md"', | ||
| ]) | ||
| expect(files).toEqual([ | ||
| "plain.ts", | ||
| "café.txt", | ||
| "normal/path.js", | ||
| "中.md", | ||
| ]) | ||
| }, | ||
| }) | ||
| }) |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Use per-test tmpdir() isolation instead of repository root directory.
Line 21 and repeated Instance.provide calls run against a shared repo path; these tests should use tmpdir() with await using and pass tmp.path to keep storage state isolated and auto-cleaned.
Suggested refactor
-import path from "path"
+import { tmpdir } from "../fixture/fixture"
...
-const projectRoot = path.join(__dirname, "../..")
Log.init({ print: false })
+
+async function withInstance<T>(fn: () => Promise<T>) {
+ await using tmp = await tmpdir()
+ return Instance.provide({
+ directory: tmp.path,
+ fn,
+ })
+}
...
- await Instance.provide({
- directory: projectRoot,
- fn: async () => {
+ await withInstance(async () => {
const files = await roundtrip([
"src/index.ts",
"README.md",
"packages/opencode/test/file.test.ts",
])
expect(files).toEqual([
"src/index.ts",
"README.md",
"packages/opencode/test/file.test.ts",
])
- },
})As per coding guidelines: Use the tmpdir function from fixture/fixture.ts to create temporary directories for tests with automatic cleanup in test files and Always use await using syntax with tmpdir() for automatic cleanup when the variable goes out of scope.
📝 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.
| const projectRoot = path.join(__dirname, "../..") | |
| Log.init({ print: false }) | |
| // Helper: write fake diffs to Storage for a session, then read them back via diff() | |
| async function roundtrip(files: string[]): Promise<string[]> { | |
| const sessionID = Identifier.ascending("session") as any | |
| const diffs = files.map((file) => ({ | |
| file, | |
| before: "", | |
| after: "", | |
| additions: 1, | |
| deletions: 0, | |
| status: "added" as const, | |
| })) | |
| await Storage.write(["session_diff", sessionID], diffs) | |
| const result = await SessionSummary.diff({ sessionID }) | |
| return result.map((d) => d.file) | |
| } | |
| describe("SessionSummary.diff: unquoteGitPath decoding", () => { | |
| test("plain ASCII paths pass through unchanged", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| const files = await roundtrip([ | |
| "src/index.ts", | |
| "README.md", | |
| "packages/opencode/test/file.test.ts", | |
| ]) | |
| expect(files).toEqual([ | |
| "src/index.ts", | |
| "README.md", | |
| "packages/opencode/test/file.test.ts", | |
| ]) | |
| }, | |
| }) | |
| }) | |
| test("git-quoted path with octal-encoded UTF-8 (2-byte: é = \\303\\251)", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| // Git quotes "café.txt" as "caf\\303\\251.txt" | |
| const files = await roundtrip(['"caf\\303\\251.txt"']) | |
| expect(files).toEqual(["café.txt"]) | |
| }, | |
| }) | |
| }) | |
| test("git-quoted path with 3-byte UTF-8 octal (CJK character 中 = \\344\\270\\255)", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| // Git quotes "中文.txt" as "\\344\\270\\255\\346\\226\\207.txt" | |
| const files = await roundtrip(['"\\344\\270\\255\\346\\226\\207.txt"']) | |
| expect(files).toEqual(["中文.txt"]) | |
| }, | |
| }) | |
| }) | |
| test("git-quoted path with standard escape sequences (\\n, \\t, \\\\, \\\")", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| const files = await roundtrip([ | |
| '"path\\\\with\\\\backslashes"', | |
| '"file\\twith\\ttabs"', | |
| '"line\\nbreak"', | |
| ]) | |
| expect(files).toEqual([ | |
| "path\\with\\backslashes", | |
| "file\twith\ttabs", | |
| "line\nbreak", | |
| ]) | |
| }, | |
| }) | |
| }) | |
| test("mixed octal and plain ASCII in one path", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| // "docs/résumé.md" → git quotes accented chars only | |
| // é = \303\251 in UTF-8 | |
| const files = await roundtrip(['"docs/r\\303\\251sum\\303\\251.md"']) | |
| expect(files).toEqual(["docs/résumé.md"]) | |
| }, | |
| }) | |
| }) | |
| test("unquoted path (no surrounding double quotes) passes through unchanged", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| // If git doesn't quote the path, it should pass through as-is | |
| const files = await roundtrip(["normal/path.ts", "another-file.js"]) | |
| expect(files).toEqual(["normal/path.ts", "another-file.js"]) | |
| }, | |
| }) | |
| }) | |
| test("path with embedded double quote (\\\")", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| const files = await roundtrip(['"file\\"name.txt"']) | |
| expect(files).toEqual(['file"name.txt']) | |
| }, | |
| }) | |
| }) | |
| test("empty string passes through unchanged", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| const files = await roundtrip([""]) | |
| expect(files).toEqual([""]) | |
| }, | |
| }) | |
| }) | |
| test("Japanese filename with 3-byte UTF-8 sequences (テスト = \\343\\203\\206\\343\\202\\271\\343\\203\\210)", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| // テ = E3 83 86 = \343\203\206 | |
| // ス = E3 82 B9 = \343\202\271 | |
| // ト = E3 83 88 = \343\203\210 | |
| const files = await roundtrip(['"\\343\\203\\206\\343\\202\\271\\343\\203\\210.sql"']) | |
| expect(files).toEqual(["テスト.sql"]) | |
| }, | |
| }) | |
| }) | |
| test("multiple files: some quoted, some not", async () => { | |
| await Instance.provide({ | |
| directory: projectRoot, | |
| fn: async () => { | |
| const files = await roundtrip([ | |
| "plain.ts", | |
| '"caf\\303\\251.txt"', | |
| "normal/path.js", | |
| '"\\344\\270\\255.md"', | |
| ]) | |
| expect(files).toEqual([ | |
| "plain.ts", | |
| "café.txt", | |
| "normal/path.js", | |
| "中.md", | |
| ]) | |
| }, | |
| }) | |
| }) | |
| import { tmpdir } from "../fixture/fixture" | |
| Log.init({ print: false }) | |
| // Helper: write fake diffs to Storage for a session, then read them back via diff() | |
| async function roundtrip(files: string[]): Promise<string[]> { | |
| const sessionID = Identifier.ascending("session") as any | |
| const diffs = files.map((file) => ({ | |
| file, | |
| before: "", | |
| after: "", | |
| additions: 1, | |
| deletions: 0, | |
| status: "added" as const, | |
| })) | |
| await Storage.write(["session_diff", sessionID], diffs) | |
| const result = await SessionSummary.diff({ sessionID }) | |
| return result.map((d) => d.file) | |
| } | |
| async function withInstance<T>(fn: () => Promise<T>) { | |
| await using tmp = await tmpdir() | |
| return Instance.provide({ | |
| directory: tmp.path, | |
| fn, | |
| }) | |
| } | |
| describe("SessionSummary.diff: unquoteGitPath decoding", () => { | |
| test("plain ASCII paths pass through unchanged", async () => { | |
| await withInstance(async () => { | |
| const files = await roundtrip([ | |
| "src/index.ts", | |
| "README.md", | |
| "packages/opencode/test/file.test.ts", | |
| ]) | |
| expect(files).toEqual([ | |
| "src/index.ts", | |
| "README.md", | |
| "packages/opencode/test/file.test.ts", | |
| ]) | |
| }) | |
| }) | |
| test("git-quoted path with octal-encoded UTF-8 (2-byte: é = \\303\\251)", async () => { | |
| await withInstance(async () => { | |
| // Git quotes "café.txt" as "caf\\303\\251.txt" | |
| const files = await roundtrip(['"caf\\303\\251.txt"']) | |
| expect(files).toEqual(["café.txt"]) | |
| }) | |
| }) | |
| test("git-quoted path with 3-byte UTF-8 octal (CJK character 中 = \\344\\270\\255)", async () => { | |
| await withInstance(async () => { | |
| // Git quotes "中文.txt" as "\\344\\270\\255\\346\\226\\207.txt" | |
| const files = await roundtrip(['"\\344\\270\\255\\346\\226\\207.txt"']) | |
| expect(files).toEqual(["中文.txt"]) | |
| }) | |
| }) | |
| test("git-quoted path with standard escape sequences (\\n, \\t, \\\\, \\\")", async () => { | |
| await withInstance(async () => { | |
| const files = await roundtrip([ | |
| '"path\\\\with\\\\backslashes"', | |
| '"file\\twith\\ttabs"', | |
| '"line\\nbreak"', | |
| ]) | |
| expect(files).toEqual([ | |
| "path\\with\\backslashes", | |
| "file\twith\ttabs", | |
| "line\nbreak", | |
| ]) | |
| }) | |
| }) | |
| test("mixed octal and plain ASCII in one path", async () => { | |
| await withInstance(async () => { | |
| // "docs/résumé.md" → git quotes accented chars only | |
| // é = \303\251 in UTF-8 | |
| const files = await roundtrip(['"docs/r\\303\\251sum\\303\\251.md"']) | |
| expect(files).toEqual(["docs/résumé.md"]) | |
| }) | |
| }) | |
| test("unquoted path (no surrounding double quotes) passes through unchanged", async () => { | |
| await withInstance(async () => { | |
| // If git doesn't quote the path, it should pass through as-is | |
| const files = await roundtrip(["normal/path.ts", "another-file.js"]) | |
| expect(files).toEqual(["normal/path.ts", "another-file.js"]) | |
| }) | |
| }) | |
| test("path with embedded double quote (\\\")", async () => { | |
| await withInstance(async () => { | |
| const files = await roundtrip(['"file\\"name.txt"']) | |
| expect(files).toEqual(['file"name.txt']) | |
| }) | |
| }) | |
| test("empty string passes through unchanged", async () => { | |
| await withInstance(async () => { | |
| const files = await roundtrip([""]) | |
| expect(files).toEqual([""]) | |
| }) | |
| }) | |
| test("Japanese filename with 3-byte UTF-8 sequences (テスト = \\343\\203\\206\\343\\202\\271\\343\\203\\210)", async () => { | |
| await withInstance(async () => { | |
| // テ = E3 83 86 = \343\203\206 | |
| // ス = E3 82 B9 = \343\202\271 | |
| // ト = E3 83 88 = \343\203\210 | |
| const files = await roundtrip(['"\\343\\203\\206\\343\\202\\271\\343\\203\\210.sql"']) | |
| expect(files).toEqual(["テスト.sql"]) | |
| }) | |
| }) | |
| test("multiple files: some quoted, some not", async () => { | |
| await withInstance(async () => { | |
| const files = await roundtrip([ | |
| "plain.ts", | |
| '"caf\\303\\251.txt"', | |
| "normal/path.js", | |
| '"\\344\\270\\255.md"', | |
| ]) | |
| expect(files).toEqual([ | |
| "plain.ts", | |
| "café.txt", | |
| "normal/path.js", | |
| "中.md", | |
| ]) | |
| }) | |
| }) | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/opencode/test/session/summary-git-path.test.ts` around lines 21 -
174, Tests currently reuse a shared projectRoot for Instance.provide causing
shared Storage state; switch each test to create an isolated temporary directory
via await using tmp = await tmpdir() and pass tmp.path to Instance.provide
(replace references to projectRoot), so roundtrip and SessionSummary.diff run
against an isolated tmp workspace and auto-clean on scope exit; ensure any test
helpers that depend on the repo root (e.g., roundtrip, Identifier.ascending
sessionID usage) continue to work unchanged but are invoked inside the await
using block so Storage writes/read are isolated per test.
Merges 9 test PRs (#390, #394, #395, #396, #397, #398, #399, #401, #387) into a single PR, discarding 4 duplicates (#391, #392, #393, #400). **New test coverage:** - `id.test.ts` — 14 tests: Identifier generation, monotonic ordering, timestamp extraction, Zod schema - `shell.test.ts` — 9 tests: shell blacklist enforcement for fish/nu, cache reset, fallback - `path-traversal.test.ts` — 7 tests (new): `Protected.isSensitiveWrite` for .pem/.key, .gnupg, .env variants - `ignore.test.ts` — 7 tests (new): `FileIgnore.match` directory patterns, globs, whitelist overrides - `paths-parsetext.test.ts` — 16 tests: `ConfigPaths.parseText` env/file substitution, JSONC parsing - `finops-formatting.test.ts` — 14 tests: `formatBytes`/`truncateQuery` edge cases - `finops-role-access.test.ts` — 10 tests: RBAC `formatGrants`/`formatHierarchy`/`formatUserRoles` - `tool-lookup.test.ts` — 4 tests: Zod schema introspection for tool parameters - `summary-git-path.test.ts` — 10 tests: `unquoteGitPath` decoding for non-ASCII filenames - `tracing.test.ts` — 2 tests (added): Recap loop detection boundaries - `patch.test.ts` — 9 tests (added): `maybeParseApplyPatchVerified` entry point coverage - `instruction.test.ts` — 13 tests (new): `InstructionPrompt.loaded()` dedup guards - `message-v2.test.ts` — 23 tests (new): `MessageV2.filterCompacted()` boundary detection **Bug fixes (discovered during testing):** - `finops-formatting.ts`: fix `formatBytes` crash on negative/NaN/fractional inputs - `finops-formatting.ts`: fix `truncateQuery` returning empty for whitespace-only, exceeding `maxLen` when < 4 - `training-import.test.ts`: fix pre-existing typecheck errors (missing `context`/`rule` mock keys) - `instruction.test.ts`, `message-v2.test.ts`: fix `MessageV2.Part` cast and branded ID type errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Consolidated into #403 |
* test: consolidated test coverage across 9 modules (133 new tests) Merges 9 test PRs (#390, #394, #395, #396, #397, #398, #399, #401, #387) into a single PR, discarding 4 duplicates (#391, #392, #393, #400). **New test coverage:** - `id.test.ts` — 14 tests: Identifier generation, monotonic ordering, timestamp extraction, Zod schema - `shell.test.ts` — 9 tests: shell blacklist enforcement for fish/nu, cache reset, fallback - `path-traversal.test.ts` — 7 tests (new): `Protected.isSensitiveWrite` for .pem/.key, .gnupg, .env variants - `ignore.test.ts` — 7 tests (new): `FileIgnore.match` directory patterns, globs, whitelist overrides - `paths-parsetext.test.ts` — 16 tests: `ConfigPaths.parseText` env/file substitution, JSONC parsing - `finops-formatting.test.ts` — 14 tests: `formatBytes`/`truncateQuery` edge cases - `finops-role-access.test.ts` — 10 tests: RBAC `formatGrants`/`formatHierarchy`/`formatUserRoles` - `tool-lookup.test.ts` — 4 tests: Zod schema introspection for tool parameters - `summary-git-path.test.ts` — 10 tests: `unquoteGitPath` decoding for non-ASCII filenames - `tracing.test.ts` — 2 tests (added): Recap loop detection boundaries - `patch.test.ts` — 9 tests (added): `maybeParseApplyPatchVerified` entry point coverage - `instruction.test.ts` — 13 tests (new): `InstructionPrompt.loaded()` dedup guards - `message-v2.test.ts` — 23 tests (new): `MessageV2.filterCompacted()` boundary detection **Bug fixes (discovered during testing):** - `finops-formatting.ts`: fix `formatBytes` crash on negative/NaN/fractional inputs - `finops-formatting.ts`: fix `truncateQuery` returning empty for whitespace-only, exceeding `maxLen` when < 4 - `training-import.test.ts`: fix pre-existing typecheck errors (missing `context`/`rule` mock keys) - `instruction.test.ts`, `message-v2.test.ts`: fix `MessageV2.Part` cast and branded ID type errors Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address code review findings — test artifact leakage and cleanup - summary-git-path.test.ts: use tmpdir() instead of projectRoot to prevent Storage.write() from polluting the developer's .opencode/storage/ directory - finops-role-access.test.ts: consolidate duplicate afterAll hooks to ensure ALTIMATE_TELEMETRY_DISABLED env var is cleaned up after tests Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
1.
unquoteGitPathviaSessionSummary.diff()—src/session/summary.ts(10 new tests)This private function decodes git's C-style quoted file paths back to Unicode. Git quotes paths containing non-ASCII bytes using octal sequences (e.g.,
\303\251for UTF-8 "é"). Zero tests existed for this function. Without correct decoding, session diffs show garbled filenames for any non-ASCII files — affecting users working in repos with CJK filenames, accented characters, or emoji. New coverage includes:\303\251)\344\270\255, Japanese: テスト)\n,\t,\\,\")2. Recap loop detection boundary behavior —
src/altimate/observability/tracing.ts(2 new tests)The loop detection feature (added in the tracer→recap rename) checks the last 10 tool calls for 3+ identical tool+input pairs. Existing tests covered basic detection and threshold behavior, but two important boundary scenarios were untested:
toolCallHistoryexceeds 200 entries, it's pruned to the last 100. This test verifies that a loop active in the surviving tail is still correctly detected after pruning — preventing false negatives in long sessions.trace.summary.loops. This was previously untested and could have silently dropped one loop.Type of change
Issue for this PR
N/A — proactive test coverage from automated test-discovery
How did you verify your code works?
Checklist
https://claude.ai/code/session_01UgL6G8jZAPtoUUKBphH7f4
Summary by CodeRabbit
Release Notes