Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Experiment with trusted cache population and MT consumption by JanProvaznik · Pull Request #10834 · microsoft/testfx · GitHub
Skip to content

Experiment with trusted cache population and MT consumption - #10834

Draft
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment
Draft

Experiment with trusted cache population and MT consumption#10834
Jan Provazník (JanProvaznik) wants to merge 6 commits into
microsoft:mainfrom
JanProvaznik:janprovaznik-cache-population-experiment

Conversation

@JanProvaznik

@JanProvaznikJan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown

Experiment status

This is a draft experiment, not a merge-ready rollout. It explores the operational split discussed in #10726: trusted main builds populate MSBuildCache with process nodes, while PR builds consume it read-only with MSBuild's experimental multithreaded mode.

Design

BuildCommand shapeRemote mode
Trusted main populationeng\common\msbuild.ps1 -msbuildMultiThreaded:$false ... TestFx.slnx /restore /graph /m /reportfileaccesses /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=false
PR consumptioneng\common\msbuild.ps1 -msbuildMultiThreaded:$true ... TestFx.slnx /restore /graph /m /t:Build .../p:MSBuildCacheRemoteCacheIsReadOnly=true

Population remains process-based because Detours attribution assumes at most one active project per node/process. PR consumption deliberately omits /reportfileaccesses; hits materialize outputs, while misses execute under -mt but cannot publish remotely.

Every nonzero experimental cache-build exit runs the authoritative process-based Arcade fallback. MT changes task routing, so even a source-shaped error can be experiment-specific and must not suppress that fallback.

Patched MSBuild

The repository's pinned SDK does not contain the required engine fixes. Each eligible Windows cache job therefore:

  1. Fetches immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft PR #14871).
  2. Verifies the checked-out SHA.
  3. Builds the Release full-framework bootstrap without System.AccessToken.
  4. Verifies artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\amd64\MSBuild.exe (18.12.0.42801 in local validation).
  5. Injects it only into the cache graph step through _BuildToolPath and MSBUILD_EXE_PATH.

The job-wide PATH is not modified, so fallback and later validation retain the normal Visual Studio toolchain. If the source build or version check fails, the cache step is skipped and Arcade runs normally. Using the same prototype for seed and consumer avoids engine differences obscuring cache measurements.

Security model

  • Only batched/individual CI runs for refs/heads/main can populate remotely.
  • PR/manual/nightly consumers remain read-only.
  • Fork PRs receive neither the custom-engine cache path nor System.AccessToken; they run Arcade fallback.
  • The custom-engine source build has no cache token. The verified engine receives the token only when executing the cache graph step.
  • PR code cannot publish into the trusted cache universe.
  • CacheClient.log and the OAuth-bearing cache environment remain excluded from published artifacts.

Cache identity and expected behavior

The experiment reuses the existing Azure Pipeline Cache backend and plugin knobs:

  • Windows-only jobs on the pinned VS image.
  • Separate testfx-v1-Debug and testfx-v1-Release universes.
  • Project/TFM, evaluated properties, source inputs, toolchain inputs, package versions, and outputs participate in plugin fingerprints.
  • NUGET_PACKAGES=$(Build.SourcesDirectory)\.packages\ stays aligned between seed and consumer.
  • MSBuildCacheIdenticalDuplicateOutputPatterns=\** retains writable copy materialization.

Expected behavior:

  1. After a matching custom-engine main seed, unchanged nodes hit and materialize under -mt.
  2. Changed nodes miss and execute under MT, but a PR cannot publish them remotely.
  3. Any prototype/plugin/engine/sign-pack failure preserves diagnostics, cleans partial outputs, and runs Arcade fallback.
  4. Existing cache entries may miss until main seeds with the same prototype and configuration.

Required MSBuild fixes

  • dotnet/msbuild#14824: preserve FileAccessData across TaskHost deserialization.
  • dotnet/msbuild#14826: propagate and gate TaskHost reporting when /reportfileaccesses is absent.
  • dotnet/msbuild#14825: reject -mt plus /reportfileaccesses actionably. The underlying Detours attribution model remains incompatible with in-process MT, so population stays process-based.

TestFX-specific blockers and constraints

  • Azure Pipeline Cache is the only configured persistent remote backend.
  • Fork validation cannot access it by design.
  • A fresh GitHub SSO authorization succeeded, but the authenticated account still has repository role READ; direct origin push returns HTTP 403. A TestFX maintainer must push current HEAD ece35e7f3 to a microsoft/testfx branch for credentialed non-fork validation.
  • The cache plugin requires a clean Windows static-graph build, full-framework x64 MSBuild, and Git on PATH.
  • Arcade's outer Build.proj discovers projects too late for cache interception; the graph pass must invoke TestFx.slnx directly, followed by Arcade sign/pack with NoBuild=true.
  • Main must reseed after toolchain/shared-input changes. Azure Pipeline Cache entries are immutable.
  • Debug/Release remain isolated to prevent immutable-selector races.
  • Copy materialization adds I/O and relaxes identical duplicate-output checking, while different-content duplicate outputs remain errors.

Measurements needed

For Debug and Release, collect:

  • graph node and hit/miss/error counts;
  • local versus remote hits and bytes materialized;
  • lookup, materialization, execution, and total wall-clock time;
  • fallback frequency and reason;
  • compiler/shared-compilation activity on hits versus misses;
  • comparison with process-based consumption and Arcade fallback;
  • confirmation that the PR never attempts a remote write.

Validation and live iterations

  • Local patched MSBuild build: passed in 125 seconds; version 18.12.0.42801.
  • Upstream MSBuild PR build 1572304: passed all Windows, Linux, macOS, MT, source-build, and coverage legs in 55m21s.
  • TestFX fork stabilization 1572155: passed all legs before custom-engine wiring.
  • TestFX custom-engine fork validation 1572405: passed all legs. The custom-engine and cache steps were correctly skipped because System.PullRequest.IsFork=True; authoritative fallback passed on Windows Release/Debug, app-model, Linux, and macOS.
  • Earlier runs 1572106, 1572118, 1572121, and 1572370 were canceled by review-driven follow-up pushes.
  • Local pipeline checks passed: eng\validate-affected-tests.ps1, eng\classify-build-change.ps1 -SelfTest, and git diff --check.

The remaining E2E step is a maintainer-owned, non-fork draft run. The fork gate must not be weakened or manually bypassed.

Rollback and exit criteria

Proceed only when a trusted run shows stable read-only hits, no TaskHost/file-access failure, no write attempt, correct outputs/tests, and measurable benefit. Roll back by removing the patched-engine step, consumer -msbuildMultiThreaded:$true, and restoring /reportfileaccesses on process-based consumption. Exit if hit rate is too low, overhead erases benefit, fallback is nontrivial, correctness differs, credentials cannot be safely scoped, or the upstream attribution model changes.

Keep trusted cache population process-based with file-access reporting while PR consumers use multithreaded MSBuild without Detours reporting.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI balanced review requested due to automatic review settings August 28, 2026 09:17

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

Pull request overview

Draft experiment separating trusted cache population from multithreaded, read-only PR consumption.

Changes:

  • Forces process-based MSBuild for trusted cache seeding.
  • Enables -mt and disables file-access reporting for PR cache consumption.
  • Documents the design and pending MSBuild prerequisites.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

FileDescription
azure-pipelines.ymlConfigures distinct seed and consumer execution modes.
docs/dev-guide.mdDocuments cache commands, constraints, and upstream blockers.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threaddocs/dev-guide.md Outdated
Document that read-only cache misses still execute under multithreaded MSBuild while remaining unable to publish remotely.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:38

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Treat every nonzero experimental cache exit as inconclusive because multithreaded task routing can produce failures that the authoritative process-based Arcade build will not reproduce.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 09:49

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment threadazure-pipelines.yml
Clarify that only a fully successful cache path suppresses the authoritative Arcade build.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 10:13

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@JanProvaznik

Jan Provazník (JanProvaznik) commented Aug 28, 2026

Copy link
Copy Markdown
Author

Maintainer help needed for the trusted end-to-end cache validation: please create a branch inside microsoft/testfx from current experiment HEAD ece35e7f3 (or push that commit stack) and open/queue a separate non-fork draft PR against main.

The TestFX branch builds immutable dotnet/msbuild@16e184d749654ec43bf92c67ae4a9bcca2225401 (draft upstream PR dotnet/msbuild#14871) without cache credentials, verifies its x64 .NET Framework bootstrap, and injects it only into the trusted seed and read-only MT consumer cache graph steps. The bootstrap build was validated locally as MSBuild 18.12.0.42801; the authoritative fallback remains on the normal Visual Studio toolchain.

A direct push to microsoft/testfx was attempted and rejected with HTTP 403 (Permission to microsoft/testfx.git denied to JanProvaznik). SSO authorization completed, but GitHub still reports this account's repository role as READ; this is no longer a token-scope or SAML problem. This fork PR correctly skips the custom/cache consumer because System.PullRequest.IsFork=True; that gate must not be weakened or bypassed. The internal run is needed to collect credentialed Azure Pipeline Cache lookup, hit/miss, materialization, fallback, and read-only-write-attempt evidence.

Build the pinned full-framework MSBuild prototype without cache credentials, verify its amd64 bootstrap, and inject it into trusted seed and read-only multithreaded consumer graph builds with a safe Arcade fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:13

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment threadeng/pipelines/steps/build-patched-msbuild.yml Outdated
Avoid mutating job-wide PATH so the authoritative Arcade fallback continues to use the normally pinned Visual Studio toolchain.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings August 28, 2026 12:37

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Sign up for freeto 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.

2 participants

@JanProvaznik