Skip to content

Commit dbcf82e

Browse files
RedthCopilot
andcommitted
Split the sample out of the backend lane; make PublicAPI ownership real
An MSBuild review found two merge blockers. Both were reproduced before being fixed, and the fixes are mutation-tested. 1. The real sample compiled nothing. TizenPackage.props defaults EnableDefaultCompileItems to false, since most projects here still hold raw imported sources that do not build yet. The sample never opted back in, so it evaluated Compile=[] - an application head that built successfully while containing no code, produced no entry point, and demonstrated nothing. Confirmed with `dotnet msbuild -getItem:Compile`, which returned an empty array. Its four sources were instead compiled inside the backend ref-pack lane. That type-checked them but merged them into one Core+sample assembly, so the package boundary the sample exists to demonstrate was never crossed: a sample reaching for a backend internal, or for anything invisible across an assembly reference, compiled clean. The sample now globs its own sources, as a real Tizen app head does, and a new tests/Maui.Tizen.Sample.RefPackCompile compiles it as its own assembly with a ProjectReference to the backend lane - which now carries the real product AssemblyName, so the reference reproduces what a package consumer sees rather than a lane-shaped substitute. 2. PublicAPI ownership was false-green. With one merged compilation and both baseline pairs attached, either baseline satisfied either assembly. Moving Microsoft.Maui.Platforms.Tizen.TizenFlyoutView out of the backend baseline and into the SAMPLE's still built successfully - verified. Each lane now sees only its own baseline; that same mutation fails RS0016, and dropping a sample entry fails RS0016 in the sample lane, confirming the analyzer is genuinely live in both. Validation-gap fixes requested with the blockers: - The ref-pack-only PLATFORM define was already removed in 8b06927; it is now pinned by an evaluated-property assertion rather than csproj text. - Guards that grepped Sources.props are converted to EVALUATED MSBuild items via a shared MSBuildEvaluation helper. Text matching answered a different question than the one asked: the props file carries a supersession comment naming every file it documents, so deleting a real Compile item left the comment behind. Evaluation also follows imports, conditions and item removals, which text cannot. - ProjectEvaluationTests computed AdditionalFiles, assigned it to a discard, then asserted on raw csproj text - proving only that two strings appeared in the file. It now asserts what MSBuild evaluated. TizenFX reference wiring moved to eng/targets/TizenRefPack.targets so both lanes reference an identical TizenFX; the boundary between them proves nothing otherwise. Mutations confirmed caught: deleting a compile item; reverting the sample to EnableDefaultCompileItems=false; re-absorbing the sample into the backend lane; re-attaching the sample baseline to the backend lane; moving a Core API into the sample baseline (fast guard and RS0016). Validation: 280 host tests (was 270) Debug and Release; 42 foundation tests; both ref-pack lanes build Release against real TizenFX with the PublicAPI analyzer enabled and no RS0016/RS0017; full workload-free gate passes and now covers the sample lane. The real sample still cannot be built - it targets net11.0-tizen11.0 and is blocked on the Samsung workload - and nothing has been run on a device. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e23a54a9-6a68-4e30-8920-e2a17fd2ad6a
1 parent 8b06927 commit dbcf82e

12 files changed

Lines changed: 626 additions & 169 deletions

File tree

Maui.Tizen.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<Project Path="tests/UnitTests/Maui.Tizen.UnitTests.csproj" />
3131
<Project Path="tests/Maui.Tizen.Core.UnitTests/Maui.Tizen.Core.UnitTests.csproj" />
3232
<Project Path="tests/Maui.Tizen.Core.RefPackCompile/Maui.Tizen.Core.RefPackCompile.csproj" />
33+
<Project Path="tests/Maui.Tizen.Sample.RefPackCompile/Maui.Tizen.Sample.RefPackCompile.csproj" />
3334
<Project Path="eng/tests/PackageGraphProbe/PackageGraphProbe.csproj" />
3435
<Project Path="eng/tests/PublicApiOptIn/PublicApiOptIn.csproj" />
3536
<Project Path="eng/tests/PackReadmeProbe/PackReadmeProbe.csproj" />

docs/net11-status.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,33 @@ until Samsung publishes the 11.0.100 workload manifest (see blocker B1). Rather
1515
contract with a neutral fallback, verification is split across two **complementary** lanes. They do
1616
not compile identical sets - that would be impossible, since the platform sources need real TizenFX:
1717

18-
| Lane | Compiles | `TIZEN` defined |
19-
| --- | --- | --- |
20-
| `Maui.Tizen.Core.UnitTests` | portable + handler | no |
21-
| `Maui.Tizen.Core.RefPackCompile` | portable + handler + platform + sample | yes |
22-
| `Maui.Tizen.Core` (product) | portable + handler + platform | yes |
18+
| Lane | Compiles | Assembly | `TIZEN` |
19+
| --- | --- | --- | --- |
20+
| `Maui.Tizen.Core.UnitTests` | portable + handler | test host | no |
21+
| `Maui.Tizen.Core.RefPackCompile` | portable + handler + platform | `Maui.Tizen.Core` | yes |
22+
| `Maui.Tizen.Sample.RefPackCompile` | sample only, references the above | `Maui.Tizen.Sample` | yes |
23+
| `Maui.Tizen.Core` (product) | portable + handler + platform | `Maui.Tizen.Core` | yes |
2324

2425
Between them every owned source is compiled by at least one lane, and everything the product
2526
compiles is also compiled by the ref-pack lane. `SourceLaneCoverageTests` pins that invariant.
2627

28+
The sample gets its **own** lane rather than being folded into the backend's, and that separation is
29+
load-bearing in two ways an MSBuild review had to point out:
30+
31+
* The sample must cross a real assembly boundary. Compiled into the backend lane it produced one
32+
merged Core+sample assembly, so a sample that reached for a backend internal - or for anything
33+
invisible across a package reference - compiled clean. It now reaches the backend through a
34+
`ProjectReference` to an assembly carrying the real product `AssemblyName`.
35+
* PublicAPI ownership is only meaningful while each compilation is checked against its own baseline.
36+
With both pairs attached to one merged surface, moving `TizenFlyoutView` out of the backend
37+
baseline and into the *sample's* still built successfully. It now fails RS0016.
38+
39+
The real `samples/Maui.Tizen.Sample` separately evaluated `Compile=[]` - `TizenPackage.props`
40+
defaults `EnableDefaultCompileItems` to false for the not-yet-ported projects and the sample never
41+
opted back in, so it was an application head that built successfully while containing no code.
42+
`PackageBoundaryTests` asserts the evaluated item lists of the real sample and its lane are
43+
identical, so neither can drift from the other.
44+
2745
| Lane | Command | What it proves |
2846
| --- | --- | --- |
2947
| Unit tests | `dotnet test tests/Maui.Tizen.Core.UnitTests` | Mapper + command-mapper registration, DI/handler registration, hosting, dispatcher/timer/provider semantics, density conversion, layout z-index ordering, `IMauiContext` scoping. **102 tests, all passing.** |

eng/build-workload-free.sh

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,19 @@ WORKLOAD_FREE_PROJECTS=(
133133
# (mapper and DI registration, hosting, dispatching, density,
134134
# layout z-index ordering).
135135
#
136-
# Maui.Tizen.Core.RefPackCompile type-checks every `#if TIZEN` source, and the sample
137-
# head, against the REAL TizenFX reference assemblies from
138-
# Samsung.Tizen.Ref.API15. It is compile-only and unpackable,
139-
# so it cannot become a neutral fallback for the product.
136+
# Maui.Tizen.Core.RefPackCompile type-checks every `#if TIZEN` backend source against the
137+
# REAL TizenFX reference assemblies from Samsung.Tizen.Ref.API15,
138+
# and enforces the backend's PublicAPI baseline. Compile-only and
139+
# unpackable, so it cannot become a neutral fallback.
140+
#
141+
# Maui.Tizen.Sample.RefPackCompile compiles the sample head as its OWN assembly with a
142+
# ProjectReference to the backend, so the sample crosses a real
143+
# package boundary. It used to be folded into the backend lane,
144+
# which merged both into one assembly and meant the boundary was
145+
# never actually exercised - and left PublicAPI ownership
146+
# unverifiable, since either baseline satisfied either assembly.
140147
"tests/Maui.Tizen.Core.RefPackCompile/Maui.Tizen.Core.RefPackCompile.csproj"
148+
"tests/Maui.Tizen.Sample.RefPackCompile/Maui.Tizen.Sample.RefPackCompile.csproj"
141149
"tests/Maui.Tizen.Core.UnitTests/Maui.Tizen.Core.UnitTests.csproj"
142150

143151
# Foundation-owned probes.

eng/targets/TizenRefPack.targets

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<Project>
2+
3+
<!--
4+
Shared TizenFX reference-assembly wiring for the workload-free compile lanes.
5+
6+
The product targets net11.0-tizen11.0 and cannot be restored until Samsung publishes the
7+
11.0.100 workload manifest (blocker B1). Samsung.Tizen.Ref.API15 does however ship real
8+
ref/net8.0 reference assemblies for the whole of TizenFX, so the Tizen-only sources can still
9+
be type-checked on a plain net11.0 host.
10+
11+
This lives in its own file because there are now TWO lanes that need it - one for the backend
12+
and one for the sample - and they must reference an identical TizenFX or the boundary between
13+
them proves nothing.
14+
-->
15+
16+
<ItemGroup>
17+
<!--
18+
PackageDownload rather than PackageReference: these packages publish no net11.0-compatible
19+
assets, so a normal reference fails restore with NU1202. We only want the files on disk.
20+
-->
21+
<PackageDownload Include="$(TizenReferencePackId)" Version="[$(TizenReferencePackVersion)]" />
22+
<PackageDownload Include="Tizen.UIExtensions.NUI" Version="[$(TizenUIExtensionsPackageVersion)]" />
23+
</ItemGroup>
24+
25+
<Target Name="_AddTizenReferenceAssemblies" BeforeTargets="ResolveAssemblyReferences">
26+
<PropertyGroup>
27+
<_TizenRefPackDir>$(NuGetPackageRoot)$(TizenReferencePackId.ToLowerInvariant())/$(TizenReferencePackVersion)/ref/net8.0/</_TizenRefPackDir>
28+
<_TizenUIExtensionsDir>$(NuGetPackageRoot)tizen.uiextensions.nui/$(TizenUIExtensionsPackageVersion)/lib/tizen10.0/</_TizenUIExtensionsDir>
29+
</PropertyGroup>
30+
31+
<Error Condition="!Exists('$(_TizenRefPackDir)Tizen.NUI.dll')"
32+
Code="MAUITIZEN0102"
33+
Text="Could not find Tizen.NUI.dll under '$(_TizenRefPackDir)'. Expected it from $(TizenReferencePackId) $(TizenReferencePackVersion); run 'dotnet restore' for this project first." />
34+
35+
<ItemGroup>
36+
<Reference Include="$(_TizenRefPackDir)Tizen.NUI.dll" Private="false" />
37+
<Reference Include="$(_TizenRefPackDir)Tizen.NUI.Components.dll" Private="false" />
38+
<Reference Include="$(_TizenRefPackDir)Tizen.Applications.Common.dll" Private="false" />
39+
<Reference Include="$(_TizenRefPackDir)Tizen.Applications.UI.dll" Private="false" />
40+
<Reference Include="$(_TizenRefPackDir)Tizen.Log.dll" Private="false" />
41+
<Reference Include="$(_TizenRefPackDir)Tizen.dll" Private="false" />
42+
<Reference Include="$(_TizenUIExtensionsDir)Tizen.UIExtensions.NUI.dll" Private="false" Condition="Exists('$(_TizenUIExtensionsDir)Tizen.UIExtensions.NUI.dll')" />
43+
</ItemGroup>
44+
</Target>
45+
46+
</Project>

samples/Maui.Tizen.Sample/Maui.Tizen.Sample.csproj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@
3737
<IsPackable>false</IsPackable>
3838
<GenerateDocumentationFile>false</GenerateDocumentationFile>
3939
<Nullable>enable</Nullable>
40+
41+
<!--
42+
TizenPackage.props defaults EnableDefaultCompileItems to FALSE, because most projects in this
43+
repository still hold raw imported dotnet/maui sources that do not compile yet and are listed
44+
as <None> so they stay navigable.
45+
46+
The sample is not one of those. It is four hand-written files, all of which compile. Without
47+
this opt-in it evaluated Compile=[] - an application head that built successfully while
48+
containing no code at all, produced no entry point, and silently proved nothing. Verified with
49+
`dotnet msbuild -getItem:Compile`, which returned an empty array.
50+
51+
Default globbing rather than an explicit list, because that is what a real Tizen app head
52+
does and this project's job is to look like one. The ref-pack sample lane compiles the same
53+
files from @(MauiTizenSampleCompile); RealSampleCompilesItsOwnSources and
54+
SampleLaneCompilesExactlyTheRealSamplesSources pin the two sets together so neither can drift.
55+
-->
56+
<EnableDefaultCompileItems>true</EnableDefaultCompileItems>
4057
</PropertyGroup>
4158

4259

Lines changed: 38 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<!--
4-
Compile-validation lane.
4+
Backend compile-validation lane.
55
66
The product assembly targets net11.0-tizen11.0 and cannot be restored until Samsung publishes
77
the 11.0.100 workload manifest. That would normally leave every NUI-touching source file in this
8-
repository completely unverified.
9-
10-
Samsung.Tizen.Ref.API15 does, however, ship real `ref/net8.0` reference assemblies for the whole
11-
of TizenFX. This project pulls them down with PackageDownload (which skips NuGet's TFM
12-
compatibility check) and compiles the backend's Tizen-only sources against them with TIZEN
13-
defined, on a plain net11.0 host.
8+
repository completely unverified. This project compiles the backend's Tizen-only sources against
9+
the real TizenFX reference assemblies with TIZEN defined, on a plain net11.0 host.
1410
1511
This is NOT a neutral fallback for the product - it produces no shippable output
1612
(IsPackable=false, reference-only assemblies, never executed). It exists purely so `#if TIZEN`
1713
code is type-checked in CI instead of being taken on faith.
14+
15+
SCOPE: backend sources ONLY.
16+
17+
This lane used to compile the sample's sources too. That was wrong in two ways, both of which a
18+
review caught:
19+
20+
* It produced a single merged Core+sample assembly, so the sample never actually crossed the
21+
package boundary it exists to demonstrate. A sample that touched an internal, or a type it
22+
could not see through a real assembly reference, would have compiled clean here.
23+
* The analyzer saw one merged public surface with both baseline pairs attached, so PublicAPI
24+
ownership was false-green: moving a Core type into the SAMPLE's baseline still passed.
25+
Verified by mutation - Microsoft.Maui.Platforms.Tizen.TizenFlyoutView was moved into the
26+
sample baseline and the build still succeeded.
27+
28+
The sample is now compiled by tests/Maui.Tizen.Sample.RefPackCompile, which reaches this
29+
assembly through a ProjectReference exactly as a package consumer would.
1830
-->
1931

2032
<Import Project="$(RepositoryRoot)eng/Maui.props" />
@@ -23,7 +35,14 @@
2335
<PropertyGroup>
2436
<TargetFramework>$(DotNetTfm)</TargetFramework>
2537
<IsTizenProject>false</IsTizenProject>
26-
<AssemblyName>Maui.Tizen.Core.RefPackCompile</AssemblyName>
38+
39+
<!--
40+
Deliberately the REAL product assembly name, not a lane-specific one. The sample lane
41+
references this project, and the point of that reference is to reproduce what a consumer sees
42+
when they reference the Maui.Tizen.Core package. Referencing something called
43+
"Maui.Tizen.Core.RefPackCompile" would exercise a boundary that does not exist in the product.
44+
-->
45+
<AssemblyName>Maui.Tizen.Core</AssemblyName>
2746
<RootNamespace>Microsoft.Maui.Platforms.Tizen</RootNamespace>
2847

2948
<IsPackable>false</IsPackable>
@@ -33,80 +52,44 @@
3352

3453
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
3554

36-
<!-- The whole point of this lane: exercise the `#if TIZEN` branches. -->
3755
<!--
38-
TIZEN only. PLATFORM was also defined here but NOT by the product, which meant a future
39-
`#if PLATFORM` block would compile in this lane and vanish from the shipping assembly - the
40-
exact class of drift this lane exists to prevent. No source uses it today; removed before one
41-
does. A test pins the two define sets together.
56+
TIZEN only, and it must stay that way. PLATFORM was also defined here but NOT by the product,
57+
which meant a future `#if PLATFORM` block would compile in this lane and vanish from the
58+
shipping assembly - the exact class of drift this lane exists to prevent.
59+
RefPackLaneAndProductDefineTheSameSymbols pins the two define sets together.
4260
-->
4361
<DefineConstants>$(DefineConstants);TIZEN</DefineConstants>
4462
</PropertyGroup>
4563

4664
<!--
4765
Runs the PublicAPI analyzer over the REAL product sources with the REAL slice baselines.
48-
src/Maui.Tizen.Core cannot be built without the Samsung workload, so this is the only lane
49-
where RS0016/RS0017 can actually be enforced before that ships.
66+
src/Maui.Tizen.Core cannot be built without the Samsung workload, so this is the only lane where
67+
RS0016/RS0017 can actually be enforced before that ships.
68+
69+
ONLY the backend baseline is attached. The sample's baseline belongs to the sample's own
70+
compilation, and attaching it here is precisely what made ownership unverifiable.
5071
-->
5172
<ItemGroup>
5273
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers">
5374
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
5475
<PrivateAssets>all</PrivateAssets>
5576
</PackageReference>
56-
<!--
57-
The product baseline. This is the one that matters: it is what src/Maui.Tizen.Core itself
58-
consumes, and what a reviewer should read to see this package's public surface.
59-
-->
77+
6078
<AdditionalFiles Include="$(RepositoryRoot)src/Maui.Tizen.Core/PublicAPI/slice/PublicAPI.Shipped.txt" />
6179
<AdditionalFiles Include="$(RepositoryRoot)src/Maui.Tizen.Core/PublicAPI/slice/PublicAPI.Unshipped.txt" />
62-
63-
<!--
64-
The sample's baseline, kept separate so the product baseline is not polluted with app types.
65-
This lane compiles the sample sources too (so they are type-checked against real TizenFX), and
66-
the analyzer sees one merged API surface, hence both files.
67-
-->
68-
<AdditionalFiles Include="$(RepositoryRoot)samples/Maui.Tizen.Sample/PublicAPI/PublicAPI.Shipped.txt" />
69-
<AdditionalFiles Include="$(RepositoryRoot)samples/Maui.Tizen.Sample/PublicAPI/PublicAPI.Unshipped.txt" />
7080
</ItemGroup>
7181

7282
<ItemGroup>
7383
<PackageReference Include="Microsoft.Maui.Core" />
74-
75-
<!--
76-
PackageDownload rather than PackageReference: these packages publish no net11.0-compatible
77-
assets, so a normal reference fails restore with NU1202. We only want the files on disk.
78-
-->
79-
<PackageDownload Include="$(TizenReferencePackId)" Version="[$(TizenReferencePackVersion)]" />
80-
<PackageDownload Include="Tizen.UIExtensions.NUI" Version="[$(TizenUIExtensionsPackageVersion)]" />
8184
<PackageReference Include="Microsoft.Maui.Graphics" />
8285
</ItemGroup>
8386

84-
<Target Name="_AddTizenReferenceAssemblies" BeforeTargets="ResolveAssemblyReferences">
85-
<PropertyGroup>
86-
<_TizenRefPackDir>$(NuGetPackageRoot)$(TizenReferencePackId.ToLowerInvariant())/$(TizenReferencePackVersion)/ref/net8.0/</_TizenRefPackDir>
87-
<_TizenUIExtensionsDir>$(NuGetPackageRoot)tizen.uiextensions.nui/$(TizenUIExtensionsPackageVersion)/lib/tizen10.0/</_TizenUIExtensionsDir>
88-
</PropertyGroup>
89-
90-
<Error Condition="!Exists('$(_TizenRefPackDir)Tizen.NUI.dll')"
91-
Code="MAUITIZEN0102"
92-
Text="Could not find Tizen.NUI.dll under '$(_TizenRefPackDir)'. Expected it from $(TizenReferencePackId) $(TizenReferencePackVersion); run 'dotnet restore' for this project first." />
93-
94-
<ItemGroup>
95-
<Reference Include="$(_TizenRefPackDir)Tizen.NUI.dll" Private="false" />
96-
<Reference Include="$(_TizenRefPackDir)Tizen.NUI.Components.dll" Private="false" />
97-
<Reference Include="$(_TizenRefPackDir)Tizen.Applications.Common.dll" Private="false" />
98-
<Reference Include="$(_TizenRefPackDir)Tizen.Applications.UI.dll" Private="false" />
99-
<Reference Include="$(_TizenRefPackDir)Tizen.Log.dll" Private="false" />
100-
<Reference Include="$(_TizenRefPackDir)Tizen.dll" Private="false" />
101-
<Reference Include="$(_TizenUIExtensionsDir)Tizen.UIExtensions.NUI.dll" Private="false" Condition="Exists('$(_TizenUIExtensionsDir)Tizen.UIExtensions.NUI.dll')" />
102-
</ItemGroup>
103-
</Target>
87+
<Import Project="$(RepositoryRoot)eng/targets/TizenRefPack.targets" />
10488

10589
<ItemGroup>
10690
<Compile Include="@(MauiTizenPortableCompile)" LinkBase="Backend" />
10791
<Compile Include="@(MauiTizenHandlerCompile)" LinkBase="Backend" />
10892
<Compile Include="@(MauiTizenPlatformCompile)" LinkBase="Backend" />
109-
<Compile Include="@(MauiTizenSampleCompile)" LinkBase="Sample" />
11093
</ItemGroup>
11194

11295
</Project>

0 commit comments

Comments
 (0)