You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Restore the Windows App Runtime dependency and document single-file apps - #1283
Two changes, in one PR because the second depends on the first.
1. Microsoft.UI.Reactor depends on Microsoft.WindowsAppSDK.Runtime again — fixes a regression from #822. Since #822 the package carried Microsoft.WindowsAppSDK.WinUI alone. Without the Runtime package, the Windows App SDK's Base.targets silently defaults WindowsAppSDKSelfContained to true, so every app that referenced only Reactor was built self-contained, and a plain dotnet run failed with "WindowsAppSDKSelfContained requires a supported Windows architecture". Directory.Build.targets now gives every framework-dependent WinUI project in the repo, libraries included, WinUI + Runtime, so the published packages (Microsoft.UI.Reactor, .Advanced, .Devtools) pass Runtime on to consumer apps.
2. Getting Started documents the single-file path. .NET 10 runs a lone .cs file whose header supplies what a .csproj would. With the fix, this header runs packaged under plain dotnet run, with no architecture flag:
winapp run counter.cs does the same, and #:property WindowsPackageType=None runs the app unpackaged under either runner. The shipped agent-kit skills (SKILL.md, reactor-build-and-check) teach the same header.
Risk / behaviour change
This changes the package graph consumers get; it is not docs-only.
Apps that reference only Reactor become framework-dependent instead of silently self-contained: they no longer need a runtime identifier, but they use the Windows App Runtime 2.x installed on the machine rather than bundling it. An app whose output folder was copied to machines without that runtime must now set WindowsAppSDKSelfContained=true to keep bundling it (called out in the CHANGELOG). Not tested on a machine without the runtime installed.
Bumping Microsoft.WindowsAppSDK.WinUI on its own now fails the build. NuGet raises WinUI but leaves Runtime at Reactor's version, and Runtime's component-version check rejects components newer than it expects. That check is the Windows App SDK's intended behaviour; the fix is to bump the full Microsoft.WindowsAppSDK package, which moves Runtime with the components. Documented in the packaging guide (with the error text), the landing page, spec 022, the CHANGELOG and the reactor-build-and-check error table.
The docs run ahead of the package until the next release. The guide renders the last published version, 0.1.0-preview.16, which predates the fix, so against it the new header fails with the architecture error. Only the "main (development)" docs will show the new section — the site root redirects to latest/, which is 0.1.0-preview.16 — and the release that ships the fix must bump ReactorPublicVersion (enforced by release.yml), which makes the rendered header correct.
Two in-repo test libraries (Reactor.AppTests.ThirdPartyControls, Reactor.Markdown.TestRenderer) now also receive Runtime; the Release build is clean.
16 files, +596 / −42.
Verification
Measured against a locally packed Reactor with the Runtime dependency:
Scenario
Result
Guide header, dotnet run counter.cs
packaged, with identity; no -r
Guide header, winapp run counter.cs
packaged, with identity
+ WindowsPackageType=None, either runner
unpackaged
Neither BuildTools nor WindowsPackageType=None, plain dotnet run
REGDB_E_CLASSNOTREG at startup (documented)
+ WindowsAppSDKSelfContained=true and -r win-x64
self-contained; output includes Microsoft.WindowsAppRuntime.dll
SingleFileGuideHeaderTests pins the header's directive set, its TFM against src/Reactor/Reactor.csproj, and where WindowsPackageType=None may appear. Mutation-checked.
dotnet restore Reactor.slnx + dotnet build Reactor.slnx --no-restore -c Release → 0 errors. Reactor.DocPipeline.Tests 479 passed / 0 failed. WinAppSDK guard, agent-kit, skill-prose and search-index gates 293 passed / 0 failed. CI green on c0fb1d406.
PR #1277 moved scaffolding onto the Windows App SDK templates and rewrote the
setup story, but the third path from the plan was never written: a Reactor app
does not need a .csproj at all. .NET 10 runs a lone .cs file whose
#:package / #:property header supplies what a project file otherwise would.
Both shapes are now covered, and the header is the switch between them: keep
WindowsPackageType=None for a plain unpackaged window, or drop it and add
Microsoft.Windows.SDK.BuildTools.WinApp, whose targets intercept `dotnet run`
and launch with real package identity. That second half is winappCli#794 and
#874 (the latter implements the issue we filed as winappCli#871); both shipped
in winapp 0.7.0 on 2026-09-24, which is what unblocked this.
Verified end to end against the currently published versions -- preview.16 and
BuildTools.WinApp 0.7.0 -- not against the versions this was first prototyped
with. All three commands were run: `dotnet run` unpackaged opens a window,
`winapp run` opens a packaged one, and packaged `dotnet run` prints
"[WinAppRunSupport] Intercepted 'dotnet run' for packaged app" and launches with
identity. Test packages were unregistered afterwards.
Re-verifying was necessary: the header prototyped in August no longer builds,
because the Windows App SDK now defaults to self-contained and refuses an
unspecified architecture. The fix is the one the docset already documents --
index.md.dt's minimal .csproj resolves RuntimeIdentifier from
$(NETCoreSdkPortableRuntimeIdentifier), and that works verbatim as a #:property.
An earlier draft instead pinned Microsoft.WindowsAppSDK, which built and ran but
contradicted index.md.dt on why that package is ever added by hand, and implied
`Platform=x64` was the only alternative when the docset's own guarded block
shows an architecture-neutral one. Both pages now tell one story.
The guide names the two failures whose error text does not point at the cause,
because both cost time here: omitting WindowsPackageType=None builds clean and
then dies at startup with REGDB_E_CLASSNOTREG (the bootstrapper ships but never
auto-initializes), and a Windows version below 22621 compiles against nothing
and reports CS0234 "the namespace 'Reactor' does not exist", which reads like a
missing package.
On verification: InlineSnippetLedgerTests correctly rejected these blocks, since
nothing compiles inline C#. They cannot be snippet-backed -- a file-based app is
defined by having no .csproj -- and they stay contiguous rather than splitting
into a ledgered header plus a snippet-backed body, because the section's claim
is "this is the entire file". What that costs is bounded and stated in the
ledger: every construct in the body already appears in a compiled snippet on the
same page (hello-world and usestate-counter), so an API rename reddens those
first. The unverified remainder is the directives, and SingleFileGuideHeaderTests
covers the one that can rot silently by pinning the documented TargetFramework
to src/Reactor/Reactor.csproj.
Mutation-checked, including the case a weaker assertion missed: a stale TFM
reddens, deleting WindowsPackageType=None reddens, and *moving* it from the
unpackaged block into the packaged one reddens -- the last of these is the
realistic drift, since the two blocks differ by two lines, and a whole-file
Contains check stays green through it while both examples become wrong.
Reactor.slnx Release: 0 errors. Reactor.Tests 14,205 passed / 0 failed.
DocPipeline.Tests 474 passed / 0 failed. WinAppSDKReferenceGuardTests 86 passed.
No image churn. The two Win2D cross-link warnings are pre-existing in
packaging.md.dt, which this does not touch.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
Artifact sizes for c0fb1d4 vs the base branch (e5a3edc).
Packages (compressed .nupkg)
Artifact
base
PR
Δ
Microsoft.UI.Reactor.nupkg
1.75 MB
1.75 MB
+795 B (+0.04%)
≈
Microsoft.UI.Reactor.Advanced.nupkg
487.6 KB
487.6 KB
+16 B (0.00%)
≈
Microsoft.UI.Reactor.Devtools.nupkg
284.1 KB
284.1 KB
+10 B (0.00%)
≈
Assemblies in Microsoft.UI.Reactor
Artifact
base
PR
Δ
Reactor.Analyzers.dll
373.0 KB
373.0 KB
+0 B (0.00%)
≈
Reactor.dll
2.47 MB
2.47 MB
+0 B (0.00%)
≈
Reactor.Localization.Generator.dll
16.0 KB
16.0 KB
+0 B (0.00%)
≈
Reactor.Wrappers.Abstractions.dll
10.5 KB
10.5 KB
+0 B (0.00%)
≈
Reactor.Wrappers.Generator.dll
99.5 KB
99.5 KB
+0 B (0.00%)
≈
Assemblies in Microsoft.UI.Reactor.Advanced
Artifact
base
PR
Δ
Reactor.Advanced.dll
1021.5 KB
1021.5 KB
+0 B (0.00%)
≈
Assemblies in Microsoft.UI.Reactor.Devtools
Artifact
base
PR
Δ
Microsoft.UI.Reactor.Devtools.dll
784.5 KB
784.5 KB
+0 B (0.00%)
≈
No size change beyond the noise floor. ✅
✅ smaller / ⚠️ larger / ≈ within noise. Sizes come from a Release dotnet pack on the CI runner: packages are the compressed .nupkg download size, assemblies the uncompressed DLL inside it. workflow run.
Coverage for c0fb1d4 vs the base branch (e5a3edc) — unit + selftest merged.
Metric
base
PR
Δ
Line
85.97%
85.96%
-0.01 pp
≈
Branch
77.32% (965/1248)
77.32% (965/1248)
0.00 pp
≈
No coverage change beyond the noise floor. ✅
✅ higher / ⚠️ lower / ≈ within noise. Δ is in percentage points; coverage is unit + selftest merged (Debug x64) on the CI runner. Cobertura reports attached to the workflow run as artifacts.
The prose said 'the four properties' while the header carries five, and the
table omitted OutputType -- which made the table read as complete while missing
a load-bearing line.
It is the easiest of the five to drop, because nothing fails: the build
succeeds and the app runs. It links for the wrong subsystem instead. Measured
on this tree by reading the PE subsystem byte of both builds -- 3 (console)
without the directive, 2 (Windows GUI) with it -- so omitting it leaves a
console window sitting behind the app's UI for as long as it runs.
Guarded in both examples, since the table now claims it. Mutation-checked:
removing it from either header block reddens.
DocPipeline.Tests 475 passed / 0 failed. Reactor.slnx Release: 0 errors.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
…ader
Two findings from review round 2.
SKILL.md ships inside the NuGet agent kit and told consumers a different
single-file setup than the guide now does: pin Microsoft.WindowsAppSDK, and pass
-p:Platform=ARM64 (or x64) on every run. Both work, but the arch flag has to be
repeated on each invocation and pins the file to one architecture, and having
two shapes for one task is how the docset drifts. Same defect class as the
index.md.dt contradiction caught in round 1, except this one ships to users.
It now uses the same RuntimeIdentifier header the guide documents and links to
the packaged variant.
reactor-build-and-check ships too, and its claim that single-file builds require
-p:Platform became incomplete rather than wrong once the header can supply the
architecture. Its build command and its MSB4025 / NETSDK1136 rows now mention
the header alternative alongside the flag, which keeps the existing advice
working while pointing at the less fragile option.
Also switches the new test file from Path.Combine to Path.Join, which is what
this suite already uses (105 occurrences to 36) and is the idiomatic answer to
the CodeQL finding: Join concatenates, where Combine silently discards earlier
segments if a later one is rooted. Behaviour here is identical, since both
constants are compile-time relative.
Reactor.Tests 14,205 passed / 0 failed. DocPipeline.Tests 475 passed / 0 failed.
AgentKit + WinAppSDKReferenceGuard gates 222 passed. Release: 0 errors.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
This rationale claims a Microsoft.WindowsAppSDK package pin in the header is covered by WinAppSDKReferenceGuardTests, but the new headers contain Microsoft.Windows.SDK.BuildTools.WinApp instead, and that guard's #:package regex only matches Microsoft.WindowsAppSDK.... As written, the test documentation falsely suggests the packaged dependency version is guarded; please describe the actual package or add a matching guard before claiming it is safe.
The guard covered TargetFramework, WindowsPackageType and OutputType but not
RuntimeIdentifier or UseWinUI, so deleting either from a header would leave the
suite green while a reader's dotnet run failed with the architecture error the
table documents. Each row of that table is a claim; each is now checked, and the
three presence checks share one theory rather than accreting a method apiece.
WindowsPackageType stays separate because it is the one directive that must
differ between the blocks, so it is asserted for placement rather than presence.
Also corrects a stale rationale. The class remarks still said the header's
Microsoft.WindowsAppSDK pin was covered by WinAppSDKReferenceGuardTests -- true
of an earlier draft, but the headers now carry
Microsoft.Windows.SDK.BuildTools.WinApp, which that guard's regex does not match.
Rather than claim a guard that does not exist, the remarks now say plainly that
the build-tools version is unguarded and why: there is no central pin in this
repo to check a doc against, since it is a consumer-side tool rather than a
framework dependency. Its presence is asserted; its version is not.
Mutation-checked: removing RuntimeIdentifier, UseWinUI, or the build-tools
package from either block reddens.
DocPipeline.Tests 478 passed / 0 failed. Reactor.slnx Release: 0 errors.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
The guide and the published blog quick-start showed the same feature two
different ways. The blog's version is the better one, and it is what readers
will have seen first, so the guide now matches it: same app, same four-directive
header, same `winapp run counter.cs`.
RuntimeIdentifier turned out to be conditional, not universal -- which is what
prompted this. Measured all three ways:
4 directives + winapp run -> works (winapp passes the architecture through)
4 directives + dotnet run -> "WindowsAppSDKSelfContained requires a
supported Windows architecture"
4 + RuntimeIdentifier
+ WindowsPackageType=None
+ dotnet run -> works
So the line is needed only when `dotnet` drives the build, and the guide had
been presenting it as part of the base header. It now sits where it belongs, in
a "Running it with plain dotnet" delta, and the primary block is the shortest
thing that actually runs.
The packaged `dotnet run` path (BuildTools.WinApp intercepting the run) drops
from a third code block to a sentence naming the one-line delta. It is a real
capability and still documented, but it was the least common of the three and
did not earn a full block once `winapp run` leads.
Test changes follow the restructure rather than adding coverage: the directives
are now asserted per-block -- OutputType/TargetFramework/UseWinUI in the primary
header, RuntimeIdentifier/WindowsPackageType in the delta, and each absent from
the other. That second half matters because a directive migrating into the
primary block would silently fork it from the blog, and a whole-file Contains
check stays green through exactly that move. Mutation-checked in both
directions, plus the BuildTools mention which is now prose and otherwise
unguarded.
Also trims the changelog entry. REGDB_E_CLASSNOTREG and CS0234 are the right
level of detail for the guide, where a reader is staring at the error; in a
release note they were noise.
Reactor.Tests 14,205 passed / 0 failed. DocPipeline.Tests 478 passed / 0 failed.
Reactor.slnx Release: 0 errors. No image churn.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
Apps that referenced only Microsoft.UI.Reactor were silently built
self-contained. Since #822 the package carried Microsoft.WindowsAppSDK.WinUI
alone, and without Microsoft.WindowsAppSDK.Runtime the Windows App SDK's
Base.targets defaults WindowsAppSDKSelfContained to true, which then demands an
architecture: `dotnet run` without -r or -p:Platform failed with
"WindowsAppSDKSelfContained requires a supported Windows architecture".
Directory.Build.targets now gives every framework-dependent WinUI project,
libraries included, WinUI + Runtime, so the published package flows Runtime to
consumer apps. WinAppSDKReferenceGuardTests asserts that Reactor resolves
Runtime and does not mark it private; restricting Runtime to apps again, or
making it private, reddens the guard.
With apps framework-dependent again, the single-file header in Getting Started
adds Microsoft.Windows.SDK.BuildTools.WinApp, so `dotnet run counter.cs`
launches the app packaged with no architecture flag, the same as
`winapp run counter.cs`. Both runners obey WindowsPackageType: None runs the app
unpackaged, and with neither that nor the BuildTools package, plain `dotnet run`
dies at startup with REGDB_E_CLASSNOTREG. Bundling the runtime is documented as
the WindowsAppSDKSelfContained=true opt-in, which is what needs -r; -r alone
bundles nothing. SKILL.md and reactor-build-and-check teach the same header,
with WindowsPackageType=None as the fallback when Developer Mode is off.
CONTRIBUTING, spec 022 and the packaging guide describe the new dependency.
Corrects earlier commits on this branch, which were measured against the
self-contained preview.16: the self-contained default came from #822, not from
a Windows App SDK change, and WindowsPackageType=None was a no-op for those apps
rather than the cause of REGDB_E_CLASSNOTREG. That crash only applies to
framework-dependent apps launched as a plain exe, which Reactor-only apps are
again after this change.
Measured against a locally packed Reactor with the Runtime dependency: the
guide's header runs packaged under both `dotnet run` and `winapp run`, and
unpackaged under both with WindowsPackageType=None; an explicit
WindowsAppSDKSelfContained=true app still builds and runs with -r win-x64.
Reactor.slnx Release: 0 errors. DocPipeline.Tests 479 passed / 0 failed.
WinAppSDKReferenceGuard, agent-kit, skill-prose and search-index gates pass.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
Resolves the CHANGELOG.md conflict by keeping both sides' new entries in the
Added and Fixed sections.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
Now that Microsoft.UI.Reactor depends on Microsoft.WindowsAppSDK.Runtime, a
consumer that references a newer Microsoft.WindowsAppSDK.WinUI on its own gets
a build error. NuGet raises WinUI (and the Foundation and InteractiveExperiences
packages it brings in) but leaves Runtime at the version Reactor asks for,
because neither package depends on the other. Runtime's component-version check
then fails the build with "One or more referenced Windows App SDK components are
newer than the versions expected by the Microsoft.WindowsAppSDK.Runtime
package". This is the Windows App SDK's intended behaviour: Runtime decides the
minimum Windows App Runtime the app asks for, so it must not lag the components
the app compiles against.
The error's own advice points the wrong way for someone upgrading on purpose:
it says to change the component references to match Runtime, which undoes the
upgrade, and it never mentions the full Microsoft.WindowsAppSDK package, which
moves Runtime and the components together. So the fix is now documented where a
consumer will look: the packaging guide quotes the error text so it can be
searched, the landing page and spec 022 say to bump the full package (spec 022
previously said NuGet would unify a consumer's own WinUI reference), and the
CHANGELOG entry and the reactor-build-and-check error table cover it.
Reproduced against a locally packed Reactor from this branch: adding
Microsoft.WindowsAppSDK.WinUI 2.3.9 fails with the error above; adding
Microsoft.WindowsAppSDK 2.5.1 instead builds, with Runtime 2.5.1 and WinUI
2.3.9. DocPipeline.Tests 479 passed / 0 failed. Agent-kit, skill-prose,
search-index and WinAppSDKReferenceGuard gates 293 passed / 0 failed.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 393937bf-e01f-4a84-a862-ca06ed302d2f
…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
…ence
The Reactor dotnet-new templates referenced the full Microsoft.WindowsAppSDK
metapackage, which also pulls in the AI, ML, Search, Widgets and DWrite
components. Their native payload (onnxruntime.dll, DirectML.dll, ...) is
copied into every app and can't be removed by trimming or Native AOT.
Starting with Microsoft.UI.Reactor 0.1.0-preview.17
(microsoft/microsoft-ui-reactor#1283), Reactor depends on
Microsoft.WindowsAppSDK.WinUI and Microsoft.WindowsAppSDK.Runtime, so the
templates get a framework-dependent Windows App SDK transitively and no
longer need their own reference.
- Remove the Microsoft.WindowsAppSDK PackageReference from the four Reactor
project templates.
- Bump the default reactorVersion to 0.1.0-preview.17.
- Remove the now-unused windowsAppSdkVersion / --wasdk-version parameter.
- Stop passing --wasdk-version to Reactor templates in
Test-DotnetNewTemplates.ps1.
- Document the behavior in the dotnet-new README.
Discussion: microsoft/microsoft-ui-reactor#1280
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…actor package (#1276)
* Stop shipping .pri in lib/; fix publish + lib-folder packaging defects
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
* docs: record EnableMsixTooling as an alternative, and its limits
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
* test: isolate the publish cells and narrow the cleanup catch
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
* docs: #6394's fix exists but is gated on EnableMsixTooling, not a version
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
* docs: correct which build-tools version adds which half of the #6394 fix
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
* docs: packaged apps DO set EnableMsixTooling; the two paths are complementary
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
* docs: trim the CHANGELOG to the two user-facing changes
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
* test: assert a consumer-owned .xbf; docs: reconcile the closed #6394
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
* test: shorten the shared package dir so the XAML compiler stays under 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
* test: use Path.Join for the fixture temp root
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
* docs: EnableMsixTooling alone does not close the gap yet - measured
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
* docs: record the packaged-app and relocation measurements
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
* docs: #6394 was reopened; record the #6795 fix and why it does not retire 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
* docs: no PUBLISHED build-tools version fixes the long-path defect
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
* docs: state the Base finding precisely across stable and prerelease
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
* docs: #1283 narrows the publish fix to self-contained apps; re-measured 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
* test: record why the publish test's consumer is self-contained
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
* Depend on fixed MSIX build tools instead of shipping a publish workaround
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
* Keep shipping .pri files; trim docs and comments
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
* Address pr-review findings
- 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
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3c093b4a-b747-4495-9317-0ecf8597d087
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two changes, in one PR because the second depends on the first.
1.
Microsoft.UI.Reactordepends onMicrosoft.WindowsAppSDK.Runtimeagain — fixes a regression from #822. Since #822 the package carriedMicrosoft.WindowsAppSDK.WinUIalone. Without the Runtime package, the Windows App SDK'sBase.targetssilently defaultsWindowsAppSDKSelfContainedtotrue, so every app that referenced only Reactor was built self-contained, and a plaindotnet runfailed with "WindowsAppSDKSelfContained requires a supported Windows architecture".Directory.Build.targetsnow gives every framework-dependent WinUI project in the repo, libraries included,WinUI+Runtime, so the published packages (Microsoft.UI.Reactor,.Advanced,.Devtools) pass Runtime on to consumer apps.2. Getting Started documents the single-file path. .NET 10 runs a lone
.csfile whose header supplies what a.csprojwould. With the fix, this header runs packaged under plaindotnet run, with no architecture flag:winapp run counter.csdoes the same, and#:property WindowsPackageType=Noneruns the app unpackaged under either runner. The shipped agent-kit skills (SKILL.md,reactor-build-and-check) teach the same header.Risk / behaviour change
This changes the package graph consumers get; it is not docs-only.
WindowsAppSDKSelfContained=trueto keep bundling it (called out in the CHANGELOG). Not tested on a machine without the runtime installed.Microsoft.WindowsAppSDK.WinUIon its own now fails the build. NuGet raises WinUI but leaves Runtime at Reactor's version, and Runtime's component-version check rejects components newer than it expects. That check is the Windows App SDK's intended behaviour; the fix is to bump the fullMicrosoft.WindowsAppSDKpackage, which moves Runtime with the components. Documented in the packaging guide (with the error text), the landing page, spec 022, the CHANGELOG and thereactor-build-and-checkerror table.0.1.0-preview.16, which predates the fix, so against it the new header fails with the architecture error. Only the "main (development)" docs will show the new section — the site root redirects tolatest/, which is0.1.0-preview.16— and the release that ships the fix must bumpReactorPublicVersion(enforced byrelease.yml), which makes the rendered header correct.Reactor.AppTests.ThirdPartyControls,Reactor.Markdown.TestRenderer) now also receive Runtime; the Release build is clean.16 files, +596 / −42.
Verification
Measured against a locally packed Reactor with the Runtime dependency:
dotnet run counter.cs-rwinapp run counter.csWindowsPackageType=None, either runnerWindowsPackageType=None, plaindotnet runREGDB_E_CLASSNOTREGat startup (documented)WindowsAppSDKSelfContained=trueand-r win-x64Microsoft.WindowsAppRuntime.dllMicrosoft.WindowsAppSDK.WinUI2.3.9Microsoft.WindowsAppSDK2.5.1WinAppSDKReferenceGuardTestsnow asserts Reactor resolves Runtime as a non-private dependency; restricting Runtime to apps again (the Depend on Windows App SDK sub-packages (WinUI) instead of the metapackage #822 shape) or making it private reddens it. Mutation-checked.SingleFileGuideHeaderTestspins the header's directive set, its TFM againstsrc/Reactor/Reactor.csproj, and whereWindowsPackageType=Nonemay appear. Mutation-checked.dotnet restore Reactor.slnx+dotnet build Reactor.slnx --no-restore -c Release→ 0 errors.Reactor.DocPipeline.Tests479 passed / 0 failed. WinAppSDK guard, agent-kit, skill-prose and search-index gates 293 passed / 0 failed. CI green onc0fb1d406.