Skip to content

Fix WASM boot config ContentRoot to use IntermediateOutputPath#124125

Open
lewing wants to merge 4 commits intodotnet:mainfrom
lewing:fix/wasm-compression-stale-files
Open

Fix WASM boot config ContentRoot to use IntermediateOutputPath#124125
lewing wants to merge 4 commits intodotnet:mainfrom
lewing:fix/wasm-compression-stale-files

Conversation

@lewing
Copy link
Member

@lewing lewing commented Feb 7, 2026

Summary

Fix a .NET 11 regression causing SRI integrity failures during incremental Blazor WASM builds. Changes in Microsoft.NET.Sdk.WebAssembly.Browser.targets:

  1. Boot config ContentRoot: Change the boot config's DefineStaticWebAssets ContentRoot from $(OutDir)wwwroot to $(IntermediateOutputPath)
  2. Preload matching: Replace fragile %(FileName)%(Extension)-based scanning with direct references to the boot config output items
  3. WebCil ContentRoot (build-time): Use per-item ContentRoot="%(RootDir)%(Directory)" on _WebCilAssetsCandidates so each asset's Identity resolves to its actual file path on disk
  4. WebCil ContentRoot (publish-time): Add per-item ContentRoot="%(RootDir)%(Directory)" on both _NewWebCilPublishStaticWebAssetsCandidatesNoMetadata and _PromotedWasmPublishStaticWebAssets — the same fix applied to publish candidates

Regression

This is a regression in .NET 11 (works in 10.0). It was introduced by dotnet/sdk#52283, which fixed an esproj compression bug by flipping the order in AssetToCompress.TryFindInputFilePath to prefer RelatedAsset (Identity) over RelatedAssetOriginalItemSpec. That fix was correct for esproj, but exposed a latent issue in the WASM SDK targets: the boot config and webcil assets' Identity pointed to a wwwroot copy rather than the actual source files.

Before sdk#52283, OriginalItemSpec happened to point to the real file and was checked first, masking the wrong ContentRoot. After the flip, RelatedAsset (Identity) is checked first, and its stale wwwroot path is used — producing incorrect SRI hashes on incremental builds.

Reported in aspnetcore#65271.

Problem

The WASM boot config file (e.g. dotnet.boot.js) is generated at $(IntermediateOutputPath) (the obj/ folder), but its static web asset was defined with ContentRoot="$(OutDir)wwwroot". This caused DefineStaticWebAssets to compute an Identity pointing to the wwwroot copy rather than the actual file in obj/.

The same issue applied to WebCil asset candidates — files from obj/webcil/, the runtime pack, and other directories were all defined with ContentRoot="$(OutputPath)wwwroot", producing synthetic Identities under wwwroot/ that could become stale during incremental builds.

Fix

1. Boot config ContentRoot

Change ContentRoot to $(IntermediateOutputPath) so the asset Identity matches the real file location on disk. The CopyToOutputDirectory="PreserveNewest" attribute still ensures the file is copied to wwwroot for serving.

This follows Javier's suggestion in dotnet/sdk#52847 to "stop defining these assets with an item spec in the wwwroot folder and just define them in their original location on disk".

2. Preload matching simplification

The _AddWasmPreloadBuildProperties and _AddWasmPreloadPublishProperties targets previously scanned all @(StaticWebAsset) items by %(FileName)%(Extension) to find the boot config asset. This relied on the Identity path containing the fingerprint in the filename, which is an implementation detail of how DefineStaticWebAssets computes Identity based on ContentRoot.

The fix replaces the scanning with direct references to @(_WasmBuildBootConfigStaticWebAsset) and @(_WasmPublishBootConfigStaticWebAsset) — the output items already produced by DefineStaticWebAssets. This is both correct and simpler.

3. WebCil per-item ContentRoot (build-time)

Instead of using a single task-level ContentRoot parameter (which forces all candidates through the same ContentRoot path, causing synthesized Identity for files outside that directory), set per-item ContentRoot="%(RootDir)%(Directory)" on each _WebCilAssetsCandidates item. This means:

  • WebCil-converted files in obj/webcil/ → ContentRoot = their parent dir → FullPath.StartsWith(ContentRoot) = true → Identity = real FullPath ✅
  • Runtime pack files (e.g. dotnet.native.js, ICU .dat) → ContentRoot = their parent dir in the runtime pack → FullPath.StartsWith(ContentRoot) = true → Identity = real FullPath ✅

No synthesized paths, no CopyCandidate entries — every asset's Identity is its actual file on disk.

4. WebCil per-item ContentRoot (publish-time)

The publish DefineStaticWebAssets call in ProcessPublishFilesForWasm previously had no ContentRoot at all — neither task-level nor per-item. This caused publish candidates (especially promoted build assets with fingerprint placeholders in their RelativePath) to have their fingerprinted filename baked into the item spec as Identity, producing paths like dotnet.native.7z98fd2ohl.wasm that don't exist on disk → MSB3030 "Could not copy file".

The fix adds per-item ContentRoot="%(RootDir)%(Directory)" on both:

  • _NewWebCilPublishStaticWebAssetsCandidatesNoMetadata (freshly WebCil-converted publish files)
  • _PromotedWasmPublishStaticWebAssets (build assets promoted to publish)

Why this works: Promoted assets carry AssetKind=Build from the build-time DefineStaticWebAssets. In DefineStaticWebAssets.cs line 252: IsPublish("Build") = false, so contentRoot is NOT nulled for publish. The per-item ContentRoot = each file's parent directory → candidateFullPath.StartsWith(contentRoot) = true → computed=false → Identity = real FullPath on disk.

What's not changed

  • Publish boot config ContentRoot (ContentRoot="$(PublishDir)wwwroot"): Publish builds are clean and don't have the incremental staleness problem.

Build Progression

# Approach Build Result Why
1-3 Boot config + preload only ✅ Pass No WebCil changes
4-5 Per-item ContentRoot (build only) ❌ Fail Build works, but publish has no ContentRoot → MSB3030
6 Task-level IntermediateOutputPath ❌ Fail Runtime pack files outside IntermediateOutputPath → synthesized Identity → MSB3030
7 Per-item ContentRoot (build + publish) 🔄 Pending This commit — applies the fix to both build and publish

Fixes dotnet/aspnetcore#65271

Copilot AI review requested due to automatic review settings February 7, 2026 03:23
@github-actions github-actions bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Feb 7, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the Blazor WASM SDK targets to define the build boot config static web asset from its actual on-disk generation location (obj/) to prevent stale-asset Identity selection during incremental builds (which can lead to incorrect SRI integrity values at runtime).

Changes:

  • Change DefineStaticWebAssets ContentRoot for the build boot config asset from $(OutDir)wwwroot to $(IntermediateOutputPath).

@lewing lewing requested a review from javiercn February 7, 2026 03:33
@lewing lewing marked this pull request as ready for review February 7, 2026 03:33
@lewing lewing requested a review from akoeplinger as a code owner February 7, 2026 03:33
@lewing lewing requested a review from maraf February 7, 2026 03:49
@lewing lewing assigned javiercn and unassigned javiercn and lewing Feb 7, 2026
@lewing lewing added arch-wasm WebAssembly architecture area-Meta os-browser Browser variant of arch-wasm and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Feb 7, 2026
Copilot AI review requested due to automatic review settings February 7, 2026 16:43
Copy link
Contributor

Copilot AI left a comment

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 1 out of 1 changed files in this pull request and generated no new comments.

lewing added a commit that referenced this pull request Feb 8, 2026
Canceled AzDO jobs (typically from timeouts) still have pipeline
artifacts containing binlogs. The SendToHelix.binlog contains Helix
job IDs that can be queried directly to recover actual test results.

Discovered while investigating PR #124125 where a 3-hour timeout
caused a WasmBuildTests job to be canceled, but all 226 Helix work
items had actually passed.
lewing added a commit that referenced this pull request Feb 8, 2026
Canceled AzDO jobs (typically from timeouts) still have pipeline
artifacts containing binlogs. The SendToHelix.binlog contains Helix
job IDs that can be queried directly to recover actual test results.

Discovered while investigating PR #124125 where a 3-hour timeout
caused a WasmBuildTests job to be canceled, but all 226 Helix work
items had actually passed.
@lewing
Copy link
Member Author

lewing commented Feb 8, 2026

Canceled WasmBuildTests actually passed ✅

The browser-wasm windows Release WasmBuildTests job in build 1284169 was canceled after the 3-hour timeout, but all Helix work items completed successfully.

Recovery steps:

  1. Downloaded the Logs_Build_Attempt1_browser_wasm_windows_Release_WasmBuildTests pipeline artifact
  2. Loaded the truncated \SendToHelix.binlog\ and extracted 12 Helix job IDs
  3. Queried each job via Helix API — all 226 work items passed (0 failures)
Scenario Server2022 Server2025
NoWorkload-ST ✅ 2/2 ✅ 2/2
NoWebcil-ST ✅ 53/53 + 2/2 ✅ 53/53 + 2/2
Workloads-ST ✅ 53/53 ✅ 53/53
NoFingerprint-ST ✅ 2/2 + 2/2 ✅ 2/2 + 2/2

The failure was purely the AzDO job wrapper timing out while waiting to collect results, not an actual test failure.

lewing added a commit that referenced this pull request Feb 8, 2026
Canceled AzDO jobs (typically from timeouts) still have pipeline
artifacts containing binlogs. The \SendToHelix.binlog\ contains Helix
job IDs that can be queried directly to recover actual test results.

## What changed
- Added **Recovering Results from Canceled Jobs** section to helix skill
SKILL.md
- Documents the workflow: download artifacts → load binlog → extract
Helix job IDs → query Helix API
- Includes concrete example from PR #124125 (226 work items all passed
despite 3h timeout cancellation)
- Added tip about binlog MCP server for structured binlog analysis

## Context
Discovered while investigating #124125 where \�rowser-wasm windows
Release WasmBuildTests\ was canceled after 3 hours. The script reported
no failures (correct — no *failed* jobs) but also couldn't surface that
the tests actually passed. With the documented recovery workflow, the
Helix results were fully recoverable.
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="Never"
ContentRoot="$(OutDir)wwwroot"
ContentRoot="$(IntermediateOutputPath)"
Copy link
Member

Choose a reason for hiding this comment

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

I believe this needs to happen in other places like the definition of the .wasm files as assets (after webcil conversion).

I believe the important bit here is that ContentRoot + RelativePath must exist for all assets

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. Added a commit that sets per-item ContentRoot metadata on each _WebCilAssetsCandidates item to %(RootDir)%(Directory) (its own directory). This ensures candidateFullPath.StartsWith(normalizedContentRoot) is always true in DefineStaticWebAssets.ComputeCandidateIdentity, so Identity equals the physical file path for all candidates — webcil-converted files in obj/webcil/, runtime pack files in packs/, PDBs from obj/, etc.

The task-level ContentRoot parameter is kept as a fallback but the per-item metadata takes precedence via ComputePropertyValue.

Copilot AI review requested due to automatic review settings February 9, 2026 15:10
@lewing lewing requested review from janvorli and kg as code owners February 9, 2026 15:30
@dotnet-policy-service dotnet-policy-service bot added the linkable-framework Issues associated with delivering a linker friendly framework label Feb 9, 2026
@kg
Copy link
Member

kg commented Feb 9, 2026

Bad base commit?

@lewing lewing force-pushed the fix/wasm-compression-stale-files branch from b649bd9 to dc5c351 Compare February 9, 2026 18:46
Copilot AI review requested due to automatic review settings February 9, 2026 18:46
Copy link
Contributor

Copilot AI left a comment

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 1 out of 1 changed files in this pull request and generated no new comments.

@lewing
Copy link
Member Author

lewing commented Feb 9, 2026

Bad base commit?

yup, and then github stopped responding

@lewing lewing removed the linkable-framework Issues associated with delivering a linker friendly framework label Feb 9, 2026
@lewing lewing requested a review from javiercn February 9, 2026 20:41
@lewing lewing added this to the 11.0.0 milestone Feb 9, 2026
lewing added a commit that referenced this pull request Feb 9, 2026
## Summary

Work around
[dotnet/dnceng#6072](dotnet/dnceng#6072) in
the CI analysis skill by using the Helix \ListFiles\ endpoint instead of
file URIs from the \Details\ endpoint.

## Problem

The Helix work item Details API (\GET .../workitems/{id}\) has two bugs
in its \Files[].Uri\ values:

1. **Subdirectory flattening**: Files uploaded from subdirectories (e.g.
\xharness-output/logs/test/build.binlog\) get URIs with only the base
filename (\.../files/build.binlog\), so multiple distinct files with the
same base name collide
2. **Unicode rejection**: The \/files/{name}\ endpoint validates against
an ASCII-only regex, rejecting filenames containing unicode characters
(e.g. CJK test directory names like \鿀蜒枛遫䡫煉\)

The previous workaround reconstructed permalink URIs from the \FileName\
field, but this still routed through the broken \/files/\ endpoint which
rejects unicode.

## Fix

Use the separate \ListFiles\ endpoint (\GET .../workitems/{id}/files\)
which returns direct blob storage URIs. These URIs:
- Preserve full subdirectory paths
- Have properly percent-encoded unicode
- Don't route through the permalink/regex validation layer

Verified against PR #124125 CI artifacts: 53 files with unicode paths
all return HTTP 200 via ListFiles blob URIs, vs broken/colliding URIs
from the Details endpoint.
Change the boot config's DefineStaticWebAssets ContentRoot from
wwwroot to  so the asset Identity
points to the actual file location on disk rather than a stale copy
in the output wwwroot folder.

This fixes SRI integrity failures during incremental Blazor WASM builds
where the compressed boot config used a stale fingerprint from the
wwwroot copy instead of the fresh file in obj/.

Fixes aspnetcore#65271
Replace the fragile FileName-based scanning of all StaticWebAsset items
with direct references to _WasmBuildBootConfigStaticWebAsset and
_WasmPublishBootConfigStaticWebAsset. These items are already produced
by the DefineStaticWebAssets task in _GenerateBuildWasmBootJson and
_AddPublishWasmBootJsonToStaticWebAssets respectively.

The previous approach relied on FileName containing the fingerprint
(e.g. dotnet.FINGERPRINT.js), which is an implementation detail of
how DefineStaticWebAssets computes Identity. Using the pipeline's
own output items is correct regardless of ContentRoot or Identity
format.
WebCil candidates come from multiple source directories (obj/webcil/
for converted DLLs, runtime pack for native files, etc.) but were
all defined with ContentRoot pointing to OutputPath/wwwroot.

Use IntermediateOutputPath as ContentRoot instead. Files outside obj/
(e.g., runtime pack native files) get synthesized Identities with
CopyCandidates to materialize the fingerprinted copies. Files already
under obj/ (webcil-converted DLLs) use their physical path directly.

This avoids the stale wwwroot Identity problem that caused SRI
integrity failures during incremental builds, while maintaining
correct publish behavior through CopyCandidate materialization.
@lewing lewing force-pushed the fix/wasm-compression-stale-files branch from dc5c351 to 2e74845 Compare February 10, 2026 00:28
lewing added a commit that referenced this pull request Feb 12, 2026
…on guides (#124240)

## ci-analysis: structured output, MCP integration, and deep
investigation guides

### Changes to `Get-CIStatus.ps1` (+216/-132)
- **Add `[CI_ANALYSIS_SUMMARY]` JSON block** — structured summary
emitted at end of script with all key facts (builds, failed jobs, known
issues, PR correlation, recommendation hint)
- **Replace 47-line if/elseif recommendation chain** with a single
`recommendationHint` field in JSON (one of: `BUILD_SUCCESSFUL`,
`KNOWN_ISSUES_DETECTED`, `LIKELY_PR_RELATED`, `POSSIBLY_TRANSIENT`,
`REVIEW_REQUIRED`, `MERGE_CONFLICTS`, `NO_BUILDS`)
- **Add `failedJobDetails` to JSON** — per-job `errorCategory`
(test-failure, build-error, test-timeout, crash,
tests-passed-reporter-failed, unclassified), `errorSnippet`, and
`helixWorkItems`
- **Add `failedJobDetailsTruncated`** — boolean flag indicating when
`-MaxJobs` cap means `failedJobDetails` is incomplete vs
`failedJobNames`
- **Add top-level `knownIssues`** from Build Analysis (not per-job —
Build Analysis reports at the PR level, not per-job)
- **Add timeout pattern** to `Format-TestFailure` — catches `Timed Out
(timeout` that was previously invisible
- **Show log tail in PR mode** when no failure pattern matches (Helix
Job mode already did this)
- **Add accumulation variables** for cross-build aggregation
(`totalFailedJobs`, `totalLocalFailures`, `lastBuildJobSummary`)
- **Fix early-continue scoping bug** — job summary computation was at
end of build loop, after 3 `continue` paths that skipped it
- **Fix empty array falsy check** — `if ($listFiles)` → proper count
check
- **Fix `mergeable_state` trimming** — `gh api --jq` output trimmed to
prevent whitespace comparison failures
- **Remove interpretive prose** — "These failures are likely PR-related"
moved from script to agent reasoning
- **Fix empty catch** — merge state error now logged via `Write-Verbose`

### Changes to `SKILL.md` (+97/-144, net reduction)
- **Add Step 0: Gather Context** — PR type classification table (code,
flow, backport, merge, dependency update)
- **Add Step 3: Verify before claiming** — systematic checklist
- **Add build progression analysis** (Step 2, item 4) — comparing
pass/fail across PR builds to narrow down which commit introduced a
failure
- **Add prior-build mismatch detection** (Step 2, item 6) — ask user
when they reference jobs not in current results
- **Document `failedJobDetails`** — per-failure error categories in
Interpreting Results
- **Add Build Analysis check status enforcement** — red check means
unaccounted failures exist, never claim "all known" when it's red
- **Add timeout recovery workflow** — explicit guidance for verifying
timed-out builds have passing Helix results via `hlx_status`
- **Add crash/canceled job recovery procedure** — step-by-step using
`hlx_batch_status`, `hlx_files`, `hlx_download_url` to recover results
from crashed Helix work items
- **Fix MCP tool references** — use canonical short-form tool names
consistently
- **Condense anti-patterns** — tighter, more targeted, near relevant
steps
- **Net token reduction** — despite adding new content, SKILL.md shrank
from ~4.6K to ~3.5K tokens

### New reference files
- `references/azure-cli.md` — Azure CLI deep investigation guide
- `references/binlog-comparison.md` — binlog comparison workflow
- `references/delegation-patterns.md` — subagent delegation patterns (5
patterns including parallel artifact extraction and canceled job
recovery)
- `references/build-progression-analysis.md` — commit-to-build
correlation using `triggerInfo.pr.sourceSha`, SQL-based progression
tracking, MCP-first with AzDO MCP tools as primary

### Updated reference files
- `references/manual-investigation.md` — fix nonexistent `msbuild-mcp
analyze` tool refs, use real `mcp-binlog-tool-*` tools

### Design principles
- **Data/reasoning boundary**: Script emits structured JSON facts →
agent synthesizes recommendations. No more canned prose from the script.
- **MCP-first**: AzDO MCP tools (`get_builds`, `get_build_log_by_id`)
and Helix MCP tools (`hlx_status`, `hlx_logs`) positioned as primary,
CLI/script as fallback.
- **Token budget**: Orchestrating SKILL.md kept within 2K-4K token
budget by extracting depth to `references/`.
- **SQL for structured investigations**: Build progression tracking uses
SQL tables to persist SHAs across context, enabling queries for
pass→fail transitions and target branch movement.

### Testing
- Multi-model subagent testing (Sonnet 4 + GPT-5 + Opus 4.5) — two
review rounds with findings addressed
- Live MCP integration test confirmed `hlx_status`, `hlx_logs`,
`get_builds`, `get_build_log_by_id` all work
- Real-world validation against PRs #123245, #123883, #124125, #124232
Replace task-level ContentRoot= with per-item
ContentRoot=%(RootDir)%(Directory) on build-time WebCil candidates, and
add per-item ContentRoot on publish-time candidates.

Per-item ContentRoot ensures DefineStaticWebAssets resolves each asset's
Identity to its actual file path on disk, preventing synthesized paths
for runtime pack files that live outside IntermediateOutputPath. At
publish time, promoted assets carry AssetKind=Build which means
contentRoot is not nulled (IsPublish('Build')=false), so the per-item
ContentRoot is used by ComputeCandidateIdentity to produce Identity=
real FullPath instead of a fingerprinted filename that doesn't exist.
Copilot AI review requested due to automatic review settings February 12, 2026 13:58
Copy link
Contributor

Copilot AI left a comment

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 1 out of 1 changed files in this pull request and generated 1 comment.

RemoveMetadata="Integrity;Fingerprint" />
<!-- Set per-item ContentRoot so each asset's Identity matches its actual file on disk -->
<_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata Update="@(_NewWebCilPublishStaticWebAssetsCandidatesNoMetadata)" ContentRoot="%(RootDir)%(Directory)" />
<_PromotedWasmPublishStaticWebAssets Update="@(_PromotedWasmPublishStaticWebAssets)" ContentRoot="%(RootDir)%(Directory)" />
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

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

_PromotedWasmPublishStaticWebAssets are produced by ComputeWasmPublishAssets, which explicitly sets ContentRoot to $(PublishDir)wwwroot for publish assets. Overwriting ContentRoot here to %(RootDir)%(Directory) will redirect publish asset identities/content roots back to their build-time paths (often under $(OutputPath)), which risks incorrect publish manifests/copy behavior and can break incremental publish. Consider not overriding ContentRoot for promoted publish assets (or only doing so conditionally when it is empty).

Suggested change
<_PromotedWasmPublishStaticWebAssets Update="@(_PromotedWasmPublishStaticWebAssets)" ContentRoot="%(RootDir)%(Directory)" />
<_PromotedWasmPublishStaticWebAssets Update="@(_PromotedWasmPublishStaticWebAssets)" Condition="'%(ContentRoot)' == ''" ContentRoot="%(RootDir)%(Directory)" />

Copilot uses AI. Check for mistakes.
@lewing
Copy link
Member Author

lewing commented Feb 12, 2026

@javiercn I've been doing deep binlog analysis of the CI failures (builds 4-6) and want to make sure I'm heading in the right direction.

What the latest commit does: Sets per-item ContentRoot="%(RootDir)%(Directory)" on both build-time and publish-time WebCil candidates. This makes candidateFullPath.StartsWith(contentRoot) trivially true → computed=false → Identity = real FullPath on disk → Copy works.

Why the previous approaches failed:

  • Build 4-5 (per-item ContentRoot, build only): Build-time works perfectly. But the publish DefineStaticWebAssets at ProcessPublishFilesForWasm (line 722) had no ContentRoot at all. With contentRoot=null, the fingerprint gets baked into the candidate item spec (e.g., dotnet.native.7z98fd2ohl.wasm) and becomes the Identity — a file that doesn't exist → MSB3030.
  • Build 6 (task-level IntermediateOutputPath): Runtime pack files outside IntermediateOutputPath get synthesized Identity paths (e.g., obj/Debug/net11.0/_framework/dotnet.native.HASH.wasm). A CopyCandidate is created but never materialized — the build-time Copy resolves via CollectStaticWebAssetsToCopy.ResolveFile() and copies to OutputDir, not to the synthesized Identity location. At publish time, the same synthesized path is used as Copy source → MSB3030.

My concern: You said "ContentRoot + RelativePath must exist for all assets." Per-item ContentRoot fixes Identity (Copy source) but doesn't satisfy that invariant for runtime pack files — because RelativePath includes _framework/ and a fingerprint hash, and no ContentRoot makes ContentRoot/_framework/dotnet.native.HASH.wasm equal the actual file at /nuget/.../native/dotnet.native.wasm.

The $(IntermediateOutputPath) approach could satisfy the invariant if CopyCandidates were materialized at IntermediateOutputPath/_framework/dotnet.native.HASH.wasm before publish. But today the build-time Copy resolves sources via CollectStaticWebAssetsToCopy and copies to $(OutputPath), not to the Identity location. The publish path uses ComputeStaticWebAssetsTargetPaths → Copy without source resolution, so it relies on Identity pointing to a real file.

Options I see:

  1. Per-item ContentRoot (current commit): Pragmatic fix — Identity = real FullPath, Copy works. ContentRoot + RelativePath is inconsistent for runtime pack files but nothing reads that combination for file I/O today.
  2. $(IntermediateOutputPath) + fix CopyCandidate materialization: Architecturally cleaner — ContentRoot + RelativePath would be consistent after materialization. But requires an SDK-side change to materialize CopyCandidates before publish (or fix the publish Copy to use CollectStaticWebAssetsToCopy's source resolution).
  3. Something else?

Which direction would you prefer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Meta os-browser Browser variant of arch-wasm

Projects

None yet

3 participants