Build failure
The Electron unit-test job failed on main with one deterministic failing test in SyncedCustomizationBundler:
1) SyncedCustomizationBundler
bundles complete SKILL.md directories:
AssertionError [ERR_ASSERTION]: Expected "actual" to be strictly unequal to: '737882158'
at syncedCustomizationBundler.test.js:200:12
The assertion assert.notStrictEqual(updatedResult!.ref.nonce, result.ref.nonce) expects the bundle nonce to change after a reference file inside a skill directory is edited, but the recomputed nonce was identical. The two subsequent macOS-stage failures (non-production check and Publish Log Files, both reporting a missing .build/logs) are cascades of the test job aborting.
Root cause
SyncedCustomizationBundler._bundle computed its change-detection nonce purely from file metadata:
entries.push({ ..., hashPart: `${hashKey}:${source.mtime}:${source.size}` });
The nonce therefore only reflects each file's mtime and size. When a file's content is edited to the same byte length within the filesystem's mtime resolution — as in the regression test, where references/notes.md changes from reference content (17 bytes) to updated reference (17 bytes) and the in-memory provider stamps both writes with the same Date.now() millisecond — the metadata is unchanged, so the nonce collides. The bundler then hits its "nothing changed" fast path and reuses the previous bundle, silently dropping the real content change from downstream agent-host syncs. This is a deterministic correctness bug, not a flake.
How the fix works
The nonce is now derived from actual file content instead of metadata. File contents are read before the nonce is computed, and each file contributes a length-sensitive content hash (hashBytes) to the nonce inputs. A same-size content edit now produces a different hash, so the nonce changes and the bundle is correctly rewritten and re-synced. The metadata (mtime/size) is no longer part of the nonce. The write-skip optimization is preserved: the fast path still short-circuits when the content-based nonce is unchanged. Reading contents up front is not extra work — the previous code already read every file's contents immediately afterward to write the plugin tree; only the ordering relative to the nonce check moved.
Rollback evaluation
Recommendation: Do not roll back. Public culprit: 400640316376fbbdc6e901a7f5c23810bd5a9329 (#334568) added the regression test that exposes this pre-existing metadata-only nonce; the nonce logic itself predates it (introduced in #333827, 42b530c885a). A reverting change would reintroduce the disposal-race log-noise fixes that #334568 also landed and would not correct the underlying content-insensitivity, so fix-forward is both safer and more complete. Owners to consult: @pwang347
Validation
Could not run npm ci, the build, or the unit test in this environment (dependency install and node execution are blocked by the sandbox). The change is verified by source inspection: hashBytes iterates every content byte seeded with the length, so the two 17-byte reference-file variants in the failing test hash differently, making updatedResult.ref.nonce !== result.ref.nonce hold. TypeScript usage is consistent (VSBuffer.buffer is a Uint8Array; numberHash is exported from base/common/hash).
Risk
Low and bounded. The change is confined to nonce derivation inside SyncedCustomizationBundler. Behavior is strictly more correct: the nonce now changes in more cases (content edits) and is stable across unrelated metadata churn (e.g. mtime-only touches no longer force a re-sync). No public API changes.
Recommended reviewer
Recommended owner: @pwang347
Fixes microsoft/vscode-engineering#3814
Generated by build-fix · opus48 · 373.7 AIC · ⌖ 13.6 AIC · ⊞ 11.7K · ◷
Original error: Validation Failed: {"resource":"PullRequest","code":"custom","field":"fork_collab","message":"fork_collab Fork collab can't be granted by someone without permission"} - https://docs.github.com/rest/pulls/pulls#create-a-pull-request
Retryable: false
Suggestion: This error cannot be resolved by retrying. Please check the error details and fix the underlying issue.
To create the pull request manually:
gh pr create --title "fix: derive synced customization nonce from file content (build fix for vscode-engineering#3814)" --base main --head vscodebot-pr:fix/synced-customization-nonce-content-3814-ad7e99b038e11199 --repo microsoft/vscode
Show patch preview (101 of 101 lines)
From d38d81c9ca98eac83ed27456a5e1100e8cd9b9ab Mon Sep 17 00:00:00 2001
X-GH-AW-Base-Commit: 333552ca38d5e15c8b734157159fcfcae9553c87
From: "github-actions[bot]" <github-actions[bot]@users.noreply.github.com>
Date: Wed, 9 Sep 2026 01:15:48 +0000
Subject: [PATCH] fix: derive synced customization nonce from file content
Fixes microsoft/vscode-engineering#3814
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../agentHost/syncedCustomizationBundler.ts | 36 +++++++++++++------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/syncedCustomizationBundler.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/syncedCustomizationBundler.ts
index 6aea301f226..bbe57338000 100644
--- a/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/syncedCustomizationBundler.ts
+++ b/src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/syncedCustomizationBundler.ts
@@ -11,7 +11,7 @@ import { equals } from '../../../../../../base/common/objects.js';
import { ResourceMap } from '../../../../../../base/common/map.js';
import { basename, dirname, extUri } from '../../../../../../base/common/resources.js';
import { URI } from '../../../../../../base/common/uri.js';
-import { hash } from '../../../../../../base/common/hash.js';
+import { hash, numberHash } from '../../../../../../base/common/hash.js';
import { IFileService, IFileStatWithPartialMetadata } from '../../../../../../platform/files/common/files.js';
import { ILogService } from '../../../../../../platform/log/common/log.js';
import { IMcpServerConfiguration } from '../../../../../../platform/mcp/common/mcpPlatformTypes.js';
@@ -32,6 +32,15 @@ const FILE_OPERATION_CONCURRENCY = 10;
const SKILL_DIRECTORY_IGNORE = new IgnoreFile('.git\nnode_modules\n', '/', undefined, true);
const bundleSequencer = new SequencerByKey<string>();
+/** Computes a stable content hash over the given bytes (length-se
... (truncated)
Build failure
The Electron unit-test job failed on
mainwith one deterministic failing test inSyncedCustomizationBundler:The assertion
assert.notStrictEqual(updatedResult!.ref.nonce, result.ref.nonce)expects the bundle nonce to change after a reference file inside a skill directory is edited, but the recomputed nonce was identical. The two subsequent macOS-stage failures (non-production check and Publish Log Files, both reporting a missing.build/logs) are cascades of the test job aborting.Root cause
SyncedCustomizationBundler._bundlecomputed its change-detection nonce purely from file metadata:The nonce therefore only reflects each file's
mtimeandsize. When a file's content is edited to the same byte length within the filesystem'smtimeresolution — as in the regression test, wherereferences/notes.mdchanges fromreference content(17 bytes) toupdated reference(17 bytes) and the in-memory provider stamps both writes with the sameDate.now()millisecond — the metadata is unchanged, so the nonce collides. The bundler then hits its "nothing changed" fast path and reuses the previous bundle, silently dropping the real content change from downstream agent-host syncs. This is a deterministic correctness bug, not a flake.How the fix works
The nonce is now derived from actual file content instead of metadata. File contents are read before the nonce is computed, and each file contributes a length-sensitive content hash (
hashBytes) to the nonce inputs. A same-size content edit now produces a different hash, so the nonce changes and the bundle is correctly rewritten and re-synced. The metadata (mtime/size) is no longer part of the nonce. The write-skip optimization is preserved: the fast path still short-circuits when the content-based nonce is unchanged. Reading contents up front is not extra work — the previous code already read every file's contents immediately afterward to write the plugin tree; only the ordering relative to the nonce check moved.Rollback evaluation
Recommendation: Do not roll back. Public culprit:
400640316376fbbdc6e901a7f5c23810bd5a9329(#334568) added the regression test that exposes this pre-existing metadata-only nonce; the nonce logic itself predates it (introduced in #333827,42b530c885a). A reverting change would reintroduce the disposal-race log-noise fixes that #334568 also landed and would not correct the underlying content-insensitivity, so fix-forward is both safer and more complete. Owners to consult:@pwang347Validation
Could not run
npm ci, the build, or the unit test in this environment (dependency install and node execution are blocked by the sandbox). The change is verified by source inspection:hashBytesiterates every content byte seeded with the length, so the two 17-byte reference-file variants in the failing test hash differently, makingupdatedResult.ref.nonce !== result.ref.noncehold. TypeScript usage is consistent (VSBuffer.bufferis aUint8Array;numberHashis exported frombase/common/hash).Risk
Low and bounded. The change is confined to nonce derivation inside
SyncedCustomizationBundler. Behavior is strictly more correct: the nonce now changes in more cases (content edits) and is stable across unrelated metadata churn (e.g.mtime-only touches no longer force a re-sync). No public API changes.Recommended reviewer
Recommended owner:
@pwang347Fixes microsoft/vscode-engineering#3814
Note
This was originally intended as a pull request, but PR creation failed. The changes have been pushed to the branch
fix/synced-customization-nonce-content-3814-ad7e99b038e11199.Original error: ERR_API: [2026-09-09T01:22:16.072Z] create pull request in microsoft/vscode failed (attempt 1)
Original error: Validation Failed: {"resource":"PullRequest","code":"custom","field":"fork_collab","message":"fork_collab Fork collab can't be granted by someone without permission"} - https://docs.github.com/rest/pulls/pulls#create-a-pull-request
Retryable: false
Suggestion: This error cannot be resolved by retrying. Please check the error details and fix the underlying issue.
To create the pull request manually:
gh pr create --title "fix: derive synced customization nonce from file content (build fix for vscode-engineering#3814)" --base main --head vscodebot-pr:fix/synced-customization-nonce-content-3814-ad7e99b038e11199 --repo microsoft/vscodeShow patch preview (101 of 101 lines)