Skip to content

test: session git-path decoding + recap loop detection boundaries#401

Closed
anandgupta42 wants to merge 1 commit intomainfrom
claude/test-discovery-20260323-session-01UgL6G8jZAPtoUUKBphH7f4
Closed

test: session git-path decoding + recap loop detection boundaries#401
anandgupta42 wants to merge 1 commit intomainfrom
claude/test-discovery-20260323-session-01UgL6G8jZAPtoUUKBphH7f4

Conversation

@anandgupta42
Copy link
Contributor

@anandgupta42 anandgupta42 commented Mar 23, 2026

Summary

1. unquoteGitPath via SessionSummary.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\251 for 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:

  • Plain ASCII paths pass through unchanged
  • 2-byte UTF-8 octal decoding (é = \303\251)
  • 3-byte UTF-8 octal decoding (CJK: 中 = \344\270\255, Japanese: テスト)
  • Standard escape sequences (\n, \t, \\, \")
  • Mixed octal + plain ASCII in a single path
  • Unquoted paths (no surrounding double quotes) pass through
  • Empty string edge case
  • Multiple files with mixed quoting in one diff

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:

  • History pruning boundary: When toolCallHistory exceeds 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.
  • Multiple simultaneous loops: When two different tools are both looping concurrently (e.g., bash + read with identical inputs), both loops must appear in trace.summary.loops. This was previously untested and could have silently dropped one loop.

Type of change

  • New feature (non-breaking change which adds functionality)

Issue for this PR

N/A — proactive test coverage from automated test-discovery

How did you verify your code works?

bun test test/session/summary-git-path.test.ts   # 10 pass
bun test test/altimate/tracing.test.ts            # 65 pass (63 existing + 2 new)

Checklist

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

https://claude.ai/code/session_01UgL6G8jZAPtoUUKBphH7f4

Summary by CodeRabbit

Release Notes

  • Tests
    • Added test coverage for loop detection robustness when tool-call history is pruned at boundaries.
    • Added comprehensive test suite for proper handling of Git-quoted file paths, including Unicode filename decoding and special character escapes.

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
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

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

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.

@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

Two 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

Cohort / File(s) Summary
Test Suites
packages/opencode/test/altimate/tracing.test.ts, packages/opencode/test/session/summary-git-path.test.ts
Added loop detection tests for pruned tool-call histories and comprehensive test suite for Git C-style escaped octal sequences, UTF-8 multi-byte characters, and standard backslash escapes in file path decoding.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 New tests hop into place,
Loop detections trace their grace,
Paths decoded, UTF-8 too,
Octal sequences shining through!
Quality assurance takes the lead,
Robust testing is what we need! 🧪✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: adding tests for session git-path decoding and loop detection boundary scenarios.
Description check ✅ Passed The description comprehensively covers both test additions with detailed rationale, implementation details, verification steps, and follows the template structure with Summary and Test Plan sections.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/test-discovery-20260323-session-01UgL6G8jZAPtoUUKBphH7f4

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 and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

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

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb13d4 and 09968e7.

📒 Files selected for processing (2)
  • packages/opencode/test/altimate/tracing.test.ts
  • packages/opencode/test/session/summary-git-path.test.ts

Comment on lines +21 to +174
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",
])
},
})
})
Copy link

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.

anandgupta42 added a commit that referenced this pull request Mar 23, 2026
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>
@anandgupta42
Copy link
Contributor Author

Consolidated into #403

@anandgupta42 anandgupta42 deleted the claude/test-discovery-20260323-session-01UgL6G8jZAPtoUUKBphH7f4 branch March 23, 2026 17:11
anandgupta42 added a commit that referenced this pull request Mar 23, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants