Repository navigation
Depend on fixed MSIX build tools; fix duplicate lib/ folder in the Reactor package - #1276
Conversation
Reactor's three packages each shipped their generated .pri beside the assembly in lib/<tfm>/. RAR relates a same-base-name .pri to its reference (AllowedReferenceRelatedFileExtensions defaults to ".pdb;.xml;.pri;..."), so the Windows App SDK ran makepri.exe Dump on all three into $(IntermediateOutputPath). Those paths break past MAX_PATH, failing consumer builds with PRI175/PRI222/APPX0002 at depths where an equivalent XAML app builds fine. Nothing was lost: the .Advanced and .Devtools indexes were entirely empty, and the core one held a single embedded copy of ReactorApplication.xbf that also ships loose. Relocating the file would not have worked - a .pri that reaches the consumer's layout by any route is also expanded via _ExpandPriFiles - so it is excluded from pack entirely. Generation is untouched, leaving ProjectReference consumers unaffected. Measured on a 261-character output path: build goes from failing to clean, and Reactor makepri Dump calls drop from six to zero, leaving only the Windows App SDK's own framework indexes. Two further defects found while verifying this: - dotnet pack from a clean tree silently omitted ReactorApplication.xbf. It was packed by a <None> guarded with Exists(), which MSBuild evaluates before the build produces the file. Now resolved at pack time, and its absence is a hard error. - The package exposed two lib/ folders for the same framework: the .xbf used a literal lib\$(TargetFramework)\... path (net10.0-windows10.0.22621.0) while NuGet shortens build output to net10.0-windows10.0.22621. The sidecar is now emitted as build output with TargetPath so NuGet places it. Also fixes WindowsAppSDK#6394 for every consumer: an unpackaged app's own .pri and .xbf never reached the publish output, so published apps started with an empty resource dictionary and crashed with 0xC000027B. The new _ReactorCopyWinUIResourcesToPublish target in the shipped targets replaces the per-project _CopyWinUIResourcesForAot snippet in 11 projects. That snippet was gated on PublishAot=true, but the gap is not AOT-specific - a plain dotnet publish -c Release loses the .pri too, so apps that never opted into AOT were broken with no workaround available. Fixes: #1271 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
📦 Build metricsArtifact sizes for Packages (compressed .nupkg)
Assemblies in Microsoft.UI.Reactor
Assemblies in Microsoft.UI.Reactor.Advanced
Assemblies in Microsoft.UI.Reactor.Devtools
No size change beyond the noise floor. ✅ ✅ smaller / |
🧪 Merged coverageCoverage for
No coverage change beyond the noise floor. ✅ ✅ higher / |
The upstream issue (WindowsAppSDK#6394) carries a community suggestion to set EnableMsixTooling=true instead of copying the resources by hand. Measured both claims rather than repeating them: - It DOES fix the publish gap: the app .pri lands in the publish output and the published app runs. It works as a side effect of importing the MSIX packaging targets, which also drops the reference-path arm of the PRI expansion (makepri.exe Dump calls halve on a normal build). - It does NOT fix issue #1271. Built against pre-fix packages at the failing 177-character geometry with and without the switch: identical failure, PRI175/PRI222 on Microsoft.UI.Reactor.Devtools.pri.xml. Library .pri files are still expanded, so keeping them out of lib/ remains necessary. Reactor does not set the property for consumers: whether an app wants MSIX packaging tooling is the app's decision, and this is a community workaround on an open issue rather than a documented contract. The shipped target is narrower and works whichever way an app sets it. Verified the two compose cleanly - no errors, no duplicated files, app runs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
CI failure: ConsumerPublishIncludesTheAppPriAndXbfSidecars published the same project twice from one directory, once with an extra global property. That forces a full re-evaluation over the same obj/, and the second XAML compile failed with: WMC1006: Cannot resolve Assembly or Windows Metadata file '...\nuget-global-packages\microsoft.windowsappsdk.foundation\2.1.0\lib\...' That reference path is ~258 characters under the fixture's package folder and the XAML compiler is not long-path aware, so the first publish squeaked under the limit and the second did not. Give each cell its own project directory, shorten the temp-root and cell names, and reference only the core package for this test - the target under test ships there, and dropping Advanced (Win2D) and Devtools removes references the XAML compiler would otherwise resolve. Also address the code-quality finding: Dispose() caught every exception while cleaning up its temp directory. Narrow it to IOException and UnauthorizedAccessException, which is what Directory.Delete realistically throws here; anything else is a real bug and should surface. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…sion Checked the claim that WindowsAppSDK#6394 is fixed and that a newer SDK would let us drop the workaround. Both halves of that are worth recording. A first-party fix DOES exist: Microsoft.Windows.SDK.BuildTools.MSIX.Pri.targets defines AddProjectPriToResolvedFileToPublish and AddXbfFilesToResolvedFileToPublish, which add the project .pri and the .xbf files to @(ResolvedFileToPublish) - exactly the gap. But it is reachable only through EnableMsixTooling -> MsixPackageSupport -> ShouldImportMsixCommonTargets -> MsixCommonTargets -> Packaging.targets -> Pri.targets. With the flag off the build takes the MrtCore branch, which has no publish step at all. That is why the community EnableMsixTooling=true workaround works. So it is not version-gated and an SDK bump will not remove the need. Measured: - the fix targets are present in BOTH the MSIX build tools a current app resolves (1.7.251221100) and the newest published (1.7.260903100); - MsixPackageSupport is assigned in exactly one place, conditioned solely on EnableMsixTooling, and no Microsoft.WindowsAppSDK* package sets it (verified with a positive control so the empty result is a measurement, not a broken grep); - publishing the stock template on the newest stable SDK (metapackage 2.5.1, WinUI 2.3.9, Foundation 2.3.12) with Reactor's target disabled still produces no app .pri and still crashes 0xC000027B. Note the template already pins the newest stable SDK via its dotnet-new post-action, so earlier runs were on it too. Replace the vague "remove once #6394 closes" guidance in both the doc and the target's comment with the real signal: delete this when that fix runs WITHOUT EnableMsixTooling. PriPackagingTests' opt-out control starts failing when the platform begins doing the copy itself, so CI reports the moment it lands. Re-verified the shipped target after the edit: publish with it ON copies the .pri and the app runs; OFF reproduces the crash. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
Follow-up after checking the claim that Microsoft.Windows.SDK.BuildTools.MSIX 1.7.260903100 specifically carries the fix. It does carry a real one, and the previous commit undersold that: AddXbfFilesToResolvedFileToPublish is genuinely NEW in 1.7.260903100. Only the .pri half (AddProjectPriToResolvedFileToPublish) predates it in 1.7.251221100. The conclusion is unchanged, because both targets live in Pri.targets, which is imported only behind the EnableMsixTooling gate. Measured directly rather than inferred from the import chain this time - pinned 1.7.260903100 and published with -v:detailed, counting how many times each target actually executes: no EnableMsixTooling : AddProjectPri=0, AddXbf=0, app .pri NOT published EnableMsixTooling=true: AddProjectPri=2, AddXbf=2, app .pri published The second cell is the control that proves the probe can match, so the zeroes in the first are a measurement rather than a broken grep. So upgrading the build tools alone still does not remove the need for the workaround; the fix has to leave the EnableMsixTooling gate first. Record the per-version detail so nobody has to re-derive which half landed when. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…packaging-layout # Conflicts: # CHANGELOG.md
…ementary
Correcting an overstatement. Saying "apps do not set EnableMsixTooling" was too
broad: packaged (MSIX) WinUI apps normally DO - Visual Studio's packaged template
sets it, and so does every MSIX project in this repo.
That does not change the conclusion, it explains the target's scoping. The two
populations do not overlap:
unpackaged (WindowsPackageType=None) -> flag off -> platform fix does NOT run
-> Reactor's target runs
packaged (WindowsPackageType=MSIX) -> flag on -> platform fix runs
-> Reactor's target excluded by
AppxPackage/WindowsPackageType
Verified on samples/ReactorGallery, which builds both ways. Evaluated with
dotnet msbuild -getProperty rather than read off the file: default mode reports
EnableMsixTooling=false with MsixPackageSupport empty; -p:GalleryPackaged=true
reports true/true with AppxPackage=true. Publishing it unpackaged, the platform's
AddProjectPriToResolvedFileToPublish and AddXbfFilesToResolvedFileToPublish run 0
times, Reactor's target runs, the app .pri is published, and the build reports 0
errors.
Worth recording because I got this wrong first by grepping the csproj: the
WindowsPackageType=None and EnableMsixTooling=true lines sit in different
Condition'ed PropertyGroups, so a naive read makes it look like an unpackaged app
with the flag on. They never co-exist.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
The Fixed entries for this PR had grown to four entries over ~47 lines, against a repo median of 6 lines per entry. Most of that was intermediate work on the way to the fix rather than anything a consumer experiences. Cut to the two changes a consumer actually sees: - packages no longer ship a .pri, so builds stop failing on deep paths (#1271) - published unpackaged apps no longer start with an empty resource dictionary Folded the "two lib/ folders for one target framework" entry into the first as a single clause - it is a packaging-shape detail that never produced a failure, since NuGet happened to select the right group. Dropped the "dotnet pack silently omits ReactorApplication.xbf" entry entirely. It was a real bug in our own pack wiring, but no consumer ever received a broken package from it: the .pri shipped an embedded copy of the same file, so the gap only became load-bearing once this PR removed the .pri. It is a contributor-facing robustness fix, already documented in the csproj comment and spec 022. Net: 47 lines -> 17, with the two remaining entries at 9 and 8 lines. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The publish test misses consumer-generated XBF coverage, and the upstream-fix status in the documentation is contradictory.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Fixes Reactor package and publish-time WinUI resource handling to prevent long-path PRI failures and missing runtime resources.
Changes:
- Excludes library
.prifiles while reliably packagingReactorApplication.xbf. - Centralizes unpackaged-app
.pri/.xbfpublishing. - Adds integration coverage and updates packaging/AOT documentation.
| File | Description |
|---|---|
tests/Reactor.IntegrationTests/Packaging/PriPackagingTests.cs |
Adds package and publish integration tests. |
tests/Reactor.AppTests.Host/Reactor.AppTests.Host.csproj |
Removes local publish workaround. |
tests/perf_bench/PerfBench.ControlModel/PerfBench.ControlModel.csproj |
Removes local publish workaround. |
tests/aot_trim_proof/Reactor.AotHelloWorld/Reactor.AotHelloWorld.csproj |
Uses centralized publish handling. |
tests/aot_trim_proof/Reactor.AotHelloWorld.Advanced/Reactor.AotHelloWorld.Advanced.csproj |
Uses centralized publish handling. |
tests/aot_trim_proof/Reactor.AotHelloWorld.Advanced.Positive/Reactor.AotHelloWorld.Advanced.Positive.csproj |
Uses centralized publish handling. |
src/Reactor/Reactor.csproj |
Excludes PRI and packs XBF correctly. |
src/Reactor/build/Reactor.targets |
Copies unpackaged WinUI resources during publish. |
src/Reactor.Devtools/Reactor.Devtools.csproj |
Excludes the empty Devtools PRI. |
src/Reactor.Advanced/Reactor.Advanced.csproj |
Excludes the empty Advanced PRI. |
samples/apps/window-styles/WindowStyles.csproj |
Removes duplicated workaround. |
samples/apps/widget-creator/widget-creator.csproj |
Removes duplicated workaround. |
samples/apps/particle-storm/ParticleStorm.csproj |
Removes duplicated workaround. |
samples/apps/hello-world-aot/HelloWorldAot.csproj |
Removes duplicated workaround. |
samples/apps/hello-world-aot-devtools-on/HelloWorldAotDevtoolsOn.csproj |
Removes duplicated workaround. |
samples/apps/command-palette-window/CommandPaletteWindow.csproj |
Removes duplicated workaround. |
docs/specs/022-packaging-and-distribution.md |
Documents the corrected package layout. |
docs/aot-support.md |
Documents automatic publish handling. |
CHANGELOG.md |
Records the consumer-facing fixes. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Two findings from the Copilot review, both valid.
1. The publish test's XBF assertion was vacuous. It checked for
ReactorApplication.xbf, which the package already delivers through a
<None CopyToPublishDirectory="PreserveNewest"> item, so deleting the target's
$(OutputPath)**\*.xbf glob would have left it green. Confirmed against my own
earlier data, where the opt-out cell still reported that file present.
The consumer now compiles its own Themes/ConsumerStyles.xaml, and the test
asserts on the resulting Themes/ConsumerStyles.xbf. Measured both cells:
target ON -> Consumer.pri True, Themes/ConsumerStyles.xbf True
target OFF -> Consumer.pri False, Themes/ConsumerStyles.xbf False
(ReactorApplication.xbf is True in BOTH, which is exactly why it was the wrong
file to assert on.) The subfolder also covers the copy's RecursiveDir handling.
2. WindowsAppSDK#6394 was closed as fixed 19 minutes after I last checked it, in
MSIX build tools 1.7.260903100 - the version flagged for review. The docs still
said OPEN and claimed categorically that no upgrade could remove the workaround.
Both are now corrected, and the apparent contradiction is resolved rather than
restated: the fix is real, but lives behind the EnableMsixTooling gate, and the
official WinUI templates set that flag by default. So the mainstream WinUI app
IS fixed by upgrading; Reactor's template is the case outside it, shipping
WindowsPackageType=None without the flag.
That also corrects my earlier overstatement that apps do not set the flag - the
official template sets it unconditionally. The discriminator is the flag, not
packaged vs unpackaged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
… MAX_PATH
ConsumerPublishIncludesTheAppPriAndXbfSidecars failed on CI with
"WMC1006: Cannot resolve Assembly or Windows Metadata file" pointing at
microsoft.windowsappsdk.foundation's projection DLL. That path measured EXACTLY
260 characters - MAX_PATH - and the WinUI XAML compiler is not long-path aware.
It surfaced now because this test gained a consumer-owned .xaml in the previous
commit, so the XAML compiler runs on the first publish too. The same root cause
already bit once (fixed then by splitting the two publishes into separate
directories), which was treating the symptom.
The real cause is the shared fixture's naming: it becomes the consumer's
globalPackagesFolder, so every resolved reference is rooted under it.
reactor-template-packages-{guid}/nuget-global-packages -> rtp-{guid}/gp
Saves 41 characters, taking that reference from 260 to 219. Verified against the
whole closure rather than the one path that happened to fail first: the longest
of 496 reference files under a real restore is 142 characters relative, which
with CI's 80-character root is 222 - 38 under the limit. Comment added so the
names are not lengthened back for readability.
Note the local run cannot catch this class of failure: my temp root is 3
characters shorter than CI's runneradmin one, so the old naming measured 257
locally and squeaked through. The two local failures here are NU1301 (nuget.org
is TLS-blocked in this environment), which is the documented limitation these
tests already carry - not WMC1006.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
Code-quality flagged the Path.Combine call on the line shortened in e481021: "Call to System.IO.Path.Combine may silently drop its earlier arguments." That is Path.Combine's documented rooted-path behaviour - if a later segment is absolute it discards everything before it. Not reachable here, since the segment is always "rtp-{guid}", but Path.Join has no such behaviour and is already what the sibling PriPackagingTests uses, so there is no reason to keep the sharper tool. Scoped to the flagged line only. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
Answering a fair challenge: if #6394 is fixed upstream, why does _ReactorCopyWinUIResourcesToPublish exist, and shouldn't the template just set EnableMsixTooling=true? Measured rather than argued. The two halves of the upstream fix shipped separately, and only one is reachable today: AddProjectPriToResolvedFileToPublish -> in 1.7.251221100 AddXbfFilesToResolvedFileToPublish -> only in 1.7.260903100 and no Microsoft.WindowsAppSDK release pulls the newer one yet: a restore against the newest SDK (2.5.1) resolves Microsoft.Windows.SDK.BuildTools.MSIX 1.7.251221100. Publishing an unpackaged consumer with EnableMsixTooling=true on that resolved version: app .pri published : True consumer's own .xbf : False So turning the flag on today fixes half the gap while pulling in the entire single-project MSIX pipeline. That is why the template has not adopted it, and why this target is not redundant with the upstream fix. Also drops the previous wording that the template "does not enable the MSIX tooling, so the platform's fix never runs" - true, but it read as a justification when it is really a state with a revisit trigger. The deletion criteria are now concrete: an SDK release pulling build tools >= 1.7.260903100, AND either those targets leaving the MsixPackageSupport gate or the template adopting the flag - at which point the flag alone covers both halves and this target can go. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
Two claims in this PR were argued but never measured end to end. Both now are, and one of them closed a real gap. 1. Packaged (MSIX) consumers were never tested - every earlier cell was unpackaged. The worry was legitimate: for a packaged app the old lib/ .pri was NOT inert. It reached the app layout, so the app's own makepri New merged it into resources.pri. Measured, a packaged consumer of 0.1.0-preview.16 indexes ms-resource://<App>/Files/Reactor/Hosting/ReactorApplication.xbf; built against this branch it does not. So the .pri really was carrying the sidecar there. It is still safe to drop. Registering and launching the same packaged app: preview.16 runs with theme resources resolving; this branch runs identically; deleting the loose .xaml+.xbf crashes it with brush/style False. That third cell is the control that makes the second mean something. 2. "Just relocate the .pri out of lib/" - previously reasoned from the targets, now measured. Shipping Reactor.pri from a sidecar/ folder via a plain <None CopyToOutputDirectory> still produces a makepri.exe Dump on it, because it lands in @(PackagingOutputs) and _ExpandPriFiles picks it up. Absence is the only escape. Also re-verified the headline fix at the issue's exact geometry with all three packages referenced, adding a plain-WinUI cell as the reference point: BEFORE (preview.16, has .pri) -> FAILS, 10 PRI/APPX errors AFTER (this branch, no .pri) -> builds clean NO-reactor (plain WinUI) -> builds clean which is the actual claim: parity with a plain WinUI app, not immunity to depth. A deeper path fails for everyone on the SDK's own framework PRIs - at 177 chars those land at 258-259 while Microsoft.UI.Reactor.Devtools.pri.xml landed at 261, matching the arithmetic in the issue. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
main's #1277 replaced Reactor's own dotnet new templates with the Windows App SDK ones and deleted CreateTemplateTests.cs, renaming the shared fixture TemplatePackageTestFixture -> LocalPackageFeedFixture. That collided with this branch two ways: 1. modify/delete on CreateTemplateTests.cs. Accepted main's deletion - the template-scaffolding test is genuinely obsolete now that the templates are gone. My only change to it was the MAX_PATH fix below, which is carried over rather than lost. 2. PriPackagingTests took TemplatePackageTestFixture by constructor injection. Repointed to LocalPackageFeedFixture; every member it uses (PackageVersion, PackageSourceDir, NugetPackagesDir, RunArchitecture, CommandEnvironment) exists unchanged on the new fixture. Also restores the fix from e481021, which the rewrite dropped. That commit shortened the fixture's directory names because the feed directory becomes the consumer's globalPackagesFolder, and the longest resolved reference hit exactly 260 characters on CI - MAX_PATH - failing the XAML compiler with WMC1006. The new naming reverted to nuget-global-packages, measured at 253: under the limit, but 7 characters of headroom. rlf-{guid}/gp takes it back to 219. Not scope creep: the test that WMC1006 broke is the one added by this PR, and without this the branch reintroduces a failure it already fixed once. CHANGELOG auto-merged; both of this PR's entries survive alongside main's. Integration test project compiles clean. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…tire this Re-checked both upstream issues after @azchohfi flagged that upstream movement might make this PR redundant. Two developments, both 2026-09-25, and neither makes it redundant today. WindowsAppSDK#6394 was REOPENED the day after it closed. Upstream's reason is the gate this PR already documents: "Reopening because fix on MRT core version used when not enabling msix tooling is still not released." Our docs and the target's comment said CLOSED, which is now wrong - corrected, and the upstream quote recorded since it independently confirms the measurement rather than merely agreeing with it. WindowsAppSDK#6795 - the MAX_PATH defect behind issue #1271 - is verified fixed in MSIX build tools 1.7.260925103. That is the one that could retire the main fix here, so spec 022 now says so explicitly, along with why it does not yet: build tools reach an app only through Microsoft.WindowsAppSDK.Base, the sole package in the graph referencing them, and the newest Base (2.0.4, pulled by Windows App SDK 2.5.1) still pins 1.7.251221100. Checked against nuget.org directly, with positive and negative controls: 1.7.260925103 returns 404 while 1.7.251221100 and 1.7.260903100 return 200. Also records what happens when it does flow: the .pri removal stops being a build-failure fix, but the layout stays right on its own terms - the .Advanced and .Devtools indexes are entirely empty, and shipping them costs every consumer six wasted makepri Dump invocations per build. Flagged for re-evaluation rather than asserted as permanent. Fixes a duplicated "When to delete the shipped target" paragraph introduced by an earlier edit in this PR - the section had two, with drifting criteria. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
Strengthens the #6795 note after cross-checking with the session tracking these upstream issues. My previous wording claimed the weaker fact - that the fixed version is not published yet. The stronger one is true: 1.7.251221100 (ships today) -> FAILS, 6 PRI / 4 APPX 1.7.260903100 (latest published) -> FAILS, 6 PRI / 4 APPX 1.7.260925103 (private drop) -> builds clean So no published version fixes it, not merely "not the newest one". That version was A/B'd at a failing depth by the other session, and matches the structure: 1.7.260903100's MrtCore.PriExpansion.targets still passes a bare IntermediateDirectory="$(IntermediateOutputPath)" and its task assembly has no \\?\ handling at all. Independently confirmed the private-drop read from this machine, which can reach nuget.org (the other session's proxy cannot, and they flagged that as their one unverified number): 1.7.260925103 returns 404 while 1.7.251221100 and 1.7.260903100 return 200 and a nonsense version returns 404, so the probe distinguishes absent from broken. Same for Base 2.0.5/2.0.6/2.1.0 and WindowsAppSDK 2.5.2/2.6.0 - all 404. Also records why this section outlives the upstream fix, which the previous wording left as "re-evaluate then": build tools are transitive via Microsoft.WindowsAppSDK.Base - every Base including 2.0.5-experimental2 pins 1.7.251221100 - so a consumer cannot opt into a fixed build-tools release by upgrading Windows App SDK. Removing the .pri keeps the trigger away from every consumer still resolving an older version, which is not a version they control. Deliberately not recording anything about #6570 (MSB6003 MakePri output collision). The 925103 content-addressed cache may address it, but neither session has a repro, and an unverified claim in the spec is one we would have to walk back. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
Precision follow-up from the session tracking these upstream issues, so a future reader does not read our two probes as disagreeing. My earlier nuget.org sweep reported Microsoft.WindowsAppSDK.Base 2.0.5 -> 404. Theirs reported a 2.0.5-experimental2 that exists. Both are right: plain 2.0.5 does not exist, only 2.0.5-experimental2. A probe for the former 404s without that meaning there is no newer Base, so the spec now says so explicitly. The substantive finding is stronger with the prerelease included, not weaker. Verified at nuspec level (my own earlier fetch agrees with theirs): Base 2.0.4 -> BuildTools.MSIX 1.7.251221100 Base 2.0.5-experimental2 -> BuildTools.MSIX 1.7.251221100 Base 2.0.250911001-experimental -> BuildTools.MSIX 1.7.20250829.1 So the claim is not "no stable Base carries the fix" but "no Base at all, stable or prerelease, pins even the newest PUBLISHED build tools" - which makes the no-published-route conclusion airtight rather than merely likely. Three independent legs now support it: the fix exists in no published build-tools version; no Base pins even the newest published one; and that newest published one still fails the repro. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…ed both #1283 made Reactor depend on Microsoft.WindowsAppSDK.Runtime again, which turns a Reactor-only consumer from silently self-contained into framework-dependent. Every earlier measurement in this PR predates that, so both fixes were re-measured on the merged tree rather than assumed to carry over. 1. The .pri removal (#1271) is unaffected. The fair baseline is main itself - it has #1283 but still ships the .pri, so the only variable is this PR. (preview.16 was the wrong baseline here: it fails earlier with "WindowsAppSDKSelfContained requires a supported Windows architecture", the #822 regression #1283 fixed, and never reaches the PRI step. Counting that as a reproduction would have been a false positive.) Framework-dependent output drops the win-x64 path segment, so the failing geometry shifts. At a 185-char project dir only Microsoft.UI.Reactor.Devtools.pri.xml crosses MAX_PATH (261) while the SDK's own longest lands at 259: main (#1283, ships .pri) -> FAILS, 10 PRI/APPX, on Reactor.Devtools.pri.xml this branch -> builds clean plain WinUI, same depth -> builds clean Build tools still resolve 1.7.251221100 via Base 2.0.4; #1283 does not change that path. 2. The publish target is narrowed, not made redundant. Measured on a published Reactor-only app with the target disabled: framework-dependent (new default) -> runs, theme resources resolve self-contained (opt-in) -> crashes 0xC000027B A framework-dependent app loads WinUI from the installed runtime - its publish output contains no Microsoft.UI.Xaml.dll at all - so its own .pri is not on that path. Self-contained bundles WinUI and resolves it through its own .pri. Before #1283 every Reactor-only app was silently self-contained, which is why the crash was the default experience; now it is the opt-in case. The framework-dependent pass is not vacuous: deleting Reactor's loose sidecars from that same output drops both probes to False. Kept unconditional rather than keyed on WindowsAppSDKSelfContained, and verified that is harmless: for a framework-dependent publish the target adds exactly App.pri and the consumer's .xbf, and the app behaves identically. The CHANGELOG entry, aot-support.md, and the target's comment all claimed the crash was universal; each is now scoped to self-contained apps. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
After #1283 made framework-dependent the default, the publish test's WindowsAppSDKSelfContained=true looks like an arbitrary leftover that someone might reasonably simplify away. It is load-bearing: self-contained is the one deployment where a missing app .pri actually breaks a published app, since it resolves WinUI through its own .pri. A framework-dependent app loads WinUI from the installed runtime and runs fine without it. So switching the consumer to the framework-dependent default would leave the test passing while it stopped testing the case the target exists for. Documented on the helper, with the measurement that justifies it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…packaging-layout Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…ound Microsoft.Windows.SDK.BuildTools.MSIX 1.7.260930100 fixes WindowsAppSDK#6394 (the app .pri missing from publish output, now also on the MrtCore path that apps without EnableMsixTooling take, as Reactor's template does) and #6795 (MAX_PATH in makepri Dump). Every Microsoft.WindowsAppSDK.Base release still resolves 1.7.251221100, so Microsoft.UI.Reactor now declares the fixed version as a dependency floor and the shipped _ReactorCopyWinUIResourcesToPublish target is deleted. Measured with the build-tools version as the only variable: self-contained publish (JIT and NativeAOT) crashes with 0xC000027B without it and runs with it; a framework-dependent app cannot load its own XAML without it; deep-path builds fail with PRI175 without it, including on the SDK's own PRIs, which the .pri removal cannot address. The publish integration test now uses a consumer pinned back to 1.7.251221100 as its control. Also fixes two stale references to removed code (a SelfTestRunner comment and CreateTemplateTests). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
The MSIX build-tools dependency (1.7.260930100) fixes the MAX_PATH failure behind issue #1271 by itself. Measured with only the build-tools version changed, consumers of all three packages with their .pri files restored fail with PRI175 on 1.7.251221100 and build on 1.7.260930100, at the same depths that failed before (framework-dependent and self-contained). Self-contained, framework-dependent and packaged (MSIX) consumers all run. So the packages return to NuGet's standard layout: Advanced, Devtools and Reactor.targets match main again, and core only appends .xbf to the allow-list for _PackReactorApplicationXbf. The two tests that asserted the exclusion are gone. CHANGELOG, aot-support.md, spec 022 and the remaining code comments are cut down to what a reader needs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
…packaging-layout Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
- docs/aot-support.md: the no-setup statement now names the first Reactor version it applies to, with a one-line fallback for 0.1.0-preview.16 and earlier (verified on the published preview.16: without it the published app crashes with 0xC000027B; with it the .pri is published and the app runs). - release.yml: check that each packed .nupkg has one lib/ folder with ReactorApplication.xbf beside Reactor.dll. Only a pack of a built tree, as in that job, shows the second-folder defect, so the clean-tree integration test for it is removed. Verified against this head's artifacts (pass), 0.1.0-preview.16 (fails: two lib/ folders) and a core package without the .xbf (fails). - Keep the bump bots off Microsoft.Windows.SDK.BuildTools.MSIX: it moves by hand with the Windows App SDK. - threat-model.md: six NuGet dependencies, not five. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087


Summary
Microsoft.UI.Reactornow depends onMicrosoft.Windows.SDK.BuildTools.MSIX1.7.260930100. Without it, apps get 1.7.251221100 throughMicrosoft.WindowsAppSDK.Base, which has two bugs that affect Reactor apps:.priwithmakepri.exe Dumpfails pastMAX_PATH(PRI175), so apps failed to build in deeply nested folders (Shipping Reactor.pri under lib/ triggers the Windows App SDK PRI-expansion step, which fails on long paths #1271, WindowsAppSDK#6795)..priis left out of its publish output (WindowsAppSDK#6394). Published self-contained apps crashed at startup, and framework-dependent ones couldn't load their own XAML. This replaces the_CopyWinUIResourcesForAotworkaround, which is removed from 11 projects.docs/aot-support.mdnow says no setup is needed, and gives apps on 0.1.0-preview.16 or earlier a one-line fallback: reference the build tools directly.It also fixes the core package layout.
ReactorApplication.xbfwas packed to a literallib\$(TargetFramework)\path, which created a secondlib/folder, and through an item evaluated before the build, so a clean pack left it out. A pack-time target now adds it as build output.An earlier revision of this PR stopped shipping the packages'
.prifiles to avoid theMAX_PATHfailure. The new build tools make that unnecessary, so the packages keep NuGet's standard layout.Linked issue / spec
Fixes #1271. Spec:
docs/specs/022-packaging-and-distribution.md.Test plan
Every A/B varies only the build-tools version.
.prifiles) at the depths that failed before (framework-dependent in a 172-character folder, self-contained in a 174-character one). Both fail withPRI175on 1.7.251221100 and build with Reactor's dependency.0xC000027B, and framework-dependent apps can't load their own XAML. With Reactor's dependency, published self-contained and framework-dependent apps and a registered packaged (MSIX) app all run, with WinUI resources and their own XAML resolving..priand crashes with0xC000027B. With it, the.priis published and the app runs..priis published by the upstream target, and the TabView, NavigationView and Theme selftests pass against the AOT binary.PriPackagingTests(integration): the core package contains the.xbf/.xaml, and the publish output contains the app.pri. That test's control pins 1.7.251221100 and must not produce the.pri. I reproduced both halves locally..nupkghas onelib/folder, withReactorApplication.xbfbesideReactor.dll. I ran the check's script locally: it passes on this branch's Pack artifacts, and fails on 0.1.0-preview.16 (twolib/folders) and on a core package with the.xbfremoved.dotnet restore Reactor.slnx+dotnet build Reactor.slnx --no-restore -c Release: 0 errors.dotnet test tests/Reactor.Tests: 14,623 total, 0 failed in three runs; one earlier run had a single failure that didn't reproduce.Risk / breaking changes
No public API change. One new package dependency: every consumer, packaged apps included, moves from build tools 1.7.251221100 to 1.7.260930100, upstream's release with these fixes. Dependabot and the Windows NuGet update workflow skip it, so it moves by hand with the Windows App SDK. Remove it once the Windows App SDK resolves a fixed version by itself (noted in
Reactor.csprojand spec 022).