Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b4e1727
fix(vscode-lm): sanitize surrogates, recover leaked tool calls, and w…
Aug 7, 2026
306976d
test(vscode-lm): cover leaked tool-call salvage and tool_result trunc…
Aug 8, 2026
ed3e8ec
fix(vscode-lm): guard leaked tool-call recovery against quoted markup
Aug 8, 2026
cbac74d
chore(knip): exclude .roo skill assets from unused-file analysis
Aug 8, 2026
220ee89
fix(vscode-lm): address review feedback on leaked tool-call recovery
Aug 9, 2026
8c80252
docs(skill): drop probe transcripts from repo
Aug 9, 2026
d587392
chore: move probe skill scripts under scripts/, drop .roo knip ignore
Aug 9, 2026
14e8556
fix(vscode-lm): harden quoted-markup detection and bound the salvage …
Aug 10, 2026
d4e639d
test(vscode-lm): assert the salvage buffer flushes mid-stream
Aug 10, 2026
aa57a19
test(vscode-lm): cover fence-close branch of isInsideCodeFence
Aug 12, 2026
fbe5079
fix(vscode-lm): clamp messages budget to a positive floor
Aug 13, 2026
87d8a68
fix(vscode-lm): require function_calls wrapper and sanitize tool-call…
Aug 15, 2026
1511498
chore: remove probe skill and harness from PR
Aug 16, 2026
8eb1d93
docs: drop dangling probe skill path from vscode-lm comment
Aug 16, 2026
9660bc1
fix(vscode-lm): harden streaming tool-call recovery and token budgeting
Sep 7, 2026
4c9c0af
Merge remote-tracking branch 'origin/main' into port/vscode-lm-reliab…
Sep 9, 2026
4f4e27a
fix: derive mutation gate base from the PR merge commit's first parent
Sep 9, 2026
3f7ccce
fix(vscode-lm): admit requests against the raw context budget, not th…
Sep 9, 2026
e340cb6
fix(vscode-lm): accept an explicit null for a nullable leaked-tool pa…
Sep 10, 2026
0fa5f01
Merge branch 'main' into port/vscode-lm-reliability
simurg79 Sep 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions scripts/stryker-diff.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,19 @@ function git(repoRoot, args) {
return execFileSync("git", args, { cwd: repoRoot, encoding: "utf8", maxBuffer: 20 * 1024 * 1024 })
}

// GitHub checks out the synthetic pull request merge commit, but `pull_request.base.sha` is frozen at
// event-creation time. When main advances afterwards, that stale base attributes unrelated upstream
// lines to the pull request. The merge commit's first parent is the base actually merged into.
export function resolvePullRequestBase(repoRoot, baseSha, headSha) {
const parents = git(repoRoot, ["rev-list", "--parents", "-n", "1", headSha]).trim().split(/\s+/).slice(1)
if (parents.length < 2) return baseSha
return parents[0]
}

export function selectFromGit(repoRoot, baseSha, headSha) {
validateSha(baseSha, "base SHA")
validateSha(headSha, "head SHA")
baseSha = resolvePullRequestBase(repoRoot, baseSha, headSha)
const mergeBase = git(repoRoot, ["merge-base", baseSha, headSha]).trim()
const nameStatus = git(repoRoot, ["diff", "--name-status", "-z", "--find-renames", `${mergeBase}...${headSha}`])
const entries = parseNameStatus(nameStatus)
Expand Down
81 changes: 80 additions & 1 deletion scripts/stryker-diff.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,86 @@ describe("mutation testing workflow", () => {
})
})

function createSyntheticPullRequestRepository() {
const repository = fs.mkdtempSync(path.join(os.tmpdir(), "stryker-diff-revision-"))
const run = (...args) => execFileSync("git", args, { cwd: repository, encoding: "utf8" }).trim()
const write = (filePath, contents) => {
fs.mkdirSync(path.join(repository, path.dirname(filePath)), { recursive: true })
fs.writeFileSync(path.join(repository, filePath), contents)
}

run("init", "--quiet", "--initial-branch", "main")
run("config", "user.email", "gate@example.com")
run("config", "user.name", "Gate")
run("config", "commit.gpgsign", "false")

write("packages/core/src/unrelated.ts", "export const unrelated = () => 1\n")
write("packages/core/src/feature.ts", "export const feature = () => 1\n")
run("add", ".")
run("commit", "--quiet", "-m", "initial")
const eventBaseSha = run("rev-parse", "HEAD")

run("checkout", "--quiet", "-b", "pull-request")
write("packages/core/src/feature.ts", "export const feature = () => 2\n")
run("add", ".")
run("commit", "--quiet", "-m", "pull request change")

// The upstream change lands after the pull_request event recorded its base SHA, which is what
// made the stale event base attribute unrelated main-only lines to the pull request.
run("checkout", "--quiet", "main")
write("packages/core/src/unrelated.ts", "export const unrelated = () => 99\n")
run("add", ".")
run("commit", "--quiet", "-m", "unrelated upstream change")
const upstreamSha = run("rev-parse", "HEAD")

run("merge", "--quiet", "--no-ff", "-m", "merge pull request", "pull-request")
const mergeSha = run("rev-parse", "HEAD")

return { repository, eventBaseSha, upstreamSha, mergeSha }
}

describe("pull request revision selection", () => {
it("excludes unrelated upstream files by diffing from the merge commit's first parent", () => {
const { repository, eventBaseSha, upstreamSha, mergeSha } = createSyntheticPullRequestRepository()

// A failed assertion must still remove the temporary repository, or a failing run leaks it.
try {
const manifest = selectFromGit(repository, eventBaseSha, mergeSha)
const changedPaths = manifest.packages.flatMap((entry) => entry.files.map((file) => file.path))

assert.deepEqual(changedPaths, ["packages/core/src/feature.ts"])
assert.equal(manifest.baseSha, upstreamSha)
assert.equal(manifest.mergeBase, upstreamSha)

// Selectors must stay aligned with the checked-out head content.
assert.equal(manifest.headSha, mergeSha)
assert.deepEqual(
manifest.packages.flatMap((entry) => entry.selectors),
["src/feature.ts:1-1"],
)
} finally {
fs.rmSync(repository, { recursive: true, force: true })
}
})

it("keeps the supplied base for non-merge heads such as manual runs", () => {
const { repository, eventBaseSha, upstreamSha } = createSyntheticPullRequestRepository()

try {
const manifest = selectFromGit(repository, eventBaseSha, upstreamSha)

assert.equal(manifest.baseSha, eventBaseSha)
assert.equal(manifest.mergeBase, eventBaseSha)
assert.deepEqual(
manifest.packages.flatMap((entry) => entry.files.map((file) => file.path)),
["packages/core/src/unrelated.ts"],
)
} finally {
fs.rmSync(repository, { recursive: true, force: true })
}
})
})

describe("parseNameStatus", () => {
it("parses added, modified, and renamed paths", () => {
assert.deepEqual(
Expand Down Expand Up @@ -249,7 +329,6 @@ describe("shouldUseVitestRelated", () => {
})
})


describe("related-test discovery", () => {
it("keeps Stryker's temp directory relative to each run root", () => {
assert.equal(resolveStrykerTempDir("/repo", "/repo"), ".stryker-tmp")
Expand Down
Loading
Loading