Files
LlamaCasty/ytLive.csproj
T
gramps 6d1c982e26 feat(entitlement): IEntitlement seam — Steam DLC answers, everything fails closed
The first half of surge day 1. One question, "may this session emit Pro output?", with
one method on the interface so nothing downstream knows which rail proved it.

SteamEntitlement reads the lifetime SKU the way Valve intends: SteamAPI.Init() then
SteamApps.BIsDlcInstalled(dlcAppId). Four different failure paths all resolve to the
free tier rather than to Pro or to a crash — no DLC id configured, no Steam client,
steam_api64.dll missing (a throw on first touch), and simply not owned. A copied folder
run without Steam is the common case, not an exceptional one.

NotConfigured() is the shipping default until Steamworks creates the DLC app; it answers
false without ever touching the native library, so today's builds behave exactly as they
did before this commit.

HasProOutput is now IsPremium || DeveloperMode || rail, with an internal EntitlementOverride
test seam (internal, because a public setter here is a licence bypass). Four tests: no id
reads false, no client reads false without throwing, the fake reports what a test sets, and
the view model takes its answer from the rail.

Steamworks.NET 2024.8.0 added; the native DLL still comes from scripts/steam-sdk.sh, so the
csproj change is three lines and no formatting churn.
2026-11-01 08:13:25 -08:00

186 lines
11 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<ApplicationIcon>Assets\llamacasty-icon.ico</ApplicationIcon>
<!-- The shipped exe is LlamaCasty.exe (renamed 2026-11-01, before the first Steam depot so
the store never sees the legacy name). RootNamespace stays `ytLive` — the C# namespaces
are not user-visible and renaming them would churn every file for no benefit. -->
<AssemblyName>LlamaCasty</AssemblyName>
<RootNamespace>ytLive</RootNamespace>
<!-- 64-bit Windows only (creator ruling 2026-10-09). The bundled ffmpeg is the win64 build
and ONNX Runtime ships no win-x86 native, so a 32-bit process could never stream; a
32-bit address space (2–4 GB) would also choke on 1080p frame buffers. x64 makes the
exe refuse to start on 32-bit Windows instead of failing at Go Live. -->
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Compile Remove="ytLive.Tests\**" />
<EmbeddedResource Remove="ytLive.Tests\**" />
<None Remove="ytLive.Tests\**" />
<Page Remove="ytLive.Tests\**" />
</ItemGroup>
<!-- Per-build identity stamp (2026-09-04): takes 1–6 could not be attributed to an
exact binary — render perf "fixes" were being judged against builds we could not
prove were running. A fresh GUID per build makes an incremental compile impossible
(that is the point: every exe you launch was compiled NOW), the wordmark shows the
id, and startup.log records id + build time. -->
<Target Name="GenerateBuildStamp" BeforeTargets="CoreCompile">
<PropertyGroup>
<BuildStampFile>$(IntermediateOutputPath)BuildStamp.g.cs</BuildStampFile>
<BuildStampId>$([System.Guid]::NewGuid().ToString('N').Substring(0,8))</BuildStampId>
<BuildStampTime>$([System.DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss'))</BuildStampTime>
<!-- RELEASE COUNTER (creator ruling 2026-09-04): the UI shows a sequential number that
ticks +1 per COMMIT, starting at 13 — a per-BUILD GUID changed on every launch and read
as noise (rightly). Derived from git rev-list count (stable per commit, no bookkeeping).
Baseline 241 = count at introduction, first display 13. Missing git or unparsed output
falls back to the start (build never breaks). GUID + compile time stay in startup.log,
where build-identity forensics actually live. -->
<BuildNumberBaseline>17</BuildNumberBaseline>
<BuildNumberStart>13</BuildNumberStart>
</PropertyGroup>
<Exec Command="&quot;C:\Program Files\Git\cmd\git.exe&quot; rev-list --count HEAD"
WorkingDirectory="$(ProjectDir)" ConsoleToMSBuild="true" IgnoreExitCode="true">
<Output TaskParameter="ConsoleOutput" PropertyName="CommitCountRaw" />
</Exec>
<PropertyGroup>
<CommitCount>$(CommitCountRaw.Trim())</CommitCount>
<BuildCounterFile>$(ProjectDir)BuildCounter.txt</BuildCounterFile>
<PriorBuildCount Condition="Exists('$(BuildCounterFile)')">$([System.IO.File]::ReadAllText('$(BuildCounterFile)').Trim())</PriorBuildCount>
<PriorBuildCount Condition="'$(PriorBuildCount)' == ''">423</PriorBuildCount>
<BuildNumber>$([MSBuild]::Add($(PriorBuildCount), 1))</BuildNumber>
</PropertyGroup>
<WriteLinesToFile File="$(BuildCounterFile)" Lines="$(BuildNumber)" Overwrite="true" WriteOnlyWhenDifferent="false" />
<PropertyGroup>
<BuildNumber Condition="! $([System.Text.RegularExpressions.Regex]::IsMatch('$(BuildNumber)', '^[0-9]+$'))">$(BuildNumberStart)</BuildNumber>
</PropertyGroup>
<ItemGroup>
<BuildStampLines Include="// &lt;auto-generated&gt; Per-build identity (ytLive.csproj GenerateBuildStamp)."/>
<BuildStampLines Include="// Release/Label = the sequential UI stamp (+1 per commit, started at 13)."/>
<BuildStampLines Include="// Id/BuiltLocal = per-build forensic identity, logged to startup.log only. Never edit by hand."/>
<BuildStampLines Include="namespace ytLive.Helpers%3B"/>
<BuildStampLines Include="public static class BuildStamp { public const int Release = $(BuildNumber)%3B public const string Label = &quot;#$(BuildNumber)&quot;%3B public const string Id = &quot;$(BuildStampId)&quot;%3B public const string BuiltLocal = &quot;$(BuildStampTime)&quot;%3B }"/>
</ItemGroup>
<WriteLinesToFile File="$(BuildStampFile)" Lines="@(BuildStampLines)" Overwrite="true" WriteOnlyWhenDifferent="false" />
<ItemGroup>
<Compile Include="$(BuildStampFile)" />
</ItemGroup>
</Target>
<ItemGroup>
<Resource Include="Assets\llamacasty-icon.png" />
<Resource Include="Assets\llamacasty-logo.jpg" />
<Resource Include="Assets\starting-background.jpg" />
<Resource Include="Assets\brb-background.jpg" />
<Resource Include="Assets\live-background.jpg" />
<Resource Include="Assets\ending-background.jpg" />
<Resource Include="Assets\chat-background.jpg" />
<Resource Include="Assets\alert-default.mp4" />
<!-- Design-standard typefaces (DESIGN.md): Inter + JetBrains Mono, OFL-1.1. -->
<Resource Include="Assets\Fonts\Inter-Regular.ttf" />
<Resource Include="Assets\Fonts\Inter-Medium.ttf" />
<Resource Include="Assets\Fonts\Inter-SemiBold.ttf" />
<Resource Include="Assets\Fonts\Inter-Bold.ttf" />
<Resource Include="Assets\Fonts\JetBrainsMono-Medium.ttf" />
<Resource Include="Assets\Fonts\JetBrainsMono-SemiBold.ttf" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)' != 'Debug'">
<!-- ⛔ Development-only UI never ships: no BAML, no code-behind, nothing to reveal.
OverlayHost adds the panel at runtime inside #if DEBUG, so a Release build has no
reference to it and compiles cleanly. -->
<Page Remove="Controls\DeveloperPanel.xaml" />
<Compile Remove="Controls\DeveloperPanel.xaml.cs" />
</ItemGroup>
<!-- Steamworks runtime (scripts/steam-sdk.sh extracts it; steam/ is gitignored).
⛔ Link puts it BESIDE the exe rather than under steam/, because the loader looks there.
⛔ ExcludeFromSingleFile matters for the same reason as ffmpeg: a native DLL otherwise
gets swallowed into the single-file bundle and the app cannot load it at runtime. -->
<ItemGroup>
<None Remove="steam\**" />
<None Include="steam\steam_api64.dll" Link="steam_api64.dll"
CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always"
ExcludeFromSingleFile="true" />
<!-- Local-only: lets SteamAPI.Init() resolve an app id outside the Steam client (480 =
Valve's Spacewar test app). Never published — Valve's guidance is to omit it. -->
<None Include="steam\steam_appid.txt" Link="steam_appid.txt" Condition="'$(Configuration)' == 'Debug'"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<None Include="THIRD-PARTY-NOTICES.txt" CopyToOutputDirectory="PreserveNewest" />
<!-- The EULA and privacy policy travel with every copy: they are what the About screen and
any store listing are checked against. -->
<None Include="LICENSE" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
<None Include="PRIVACY.md" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" />
</ItemGroup>
<!-- Webcam background effects (TASK 51): Google's MediaPipe Selfie Segmenter (landscape,
Apache-2.0), converted to ONNX by tools/selfie-seg/ and embedded in the assembly —
~430 KB, so it lives in git, ships inside the exe, and is never downloaded at runtime
(Store policy 10.2.2, same posture as the bundled ffmpeg). -->
<ItemGroup>
<EmbeddedResource Include="Assets\Models\selfie_segmenter_landscape.onnx" LogicalName="ytLive.Assets.Models.selfie_segmenter_landscape.onnx" />
</ItemGroup>
<!-- Bundled FFmpeg (TASK 48 item 1, Store policy 10.2.2 dynamic code inclusion).
The app used to DOWNLOAD an unsigned ffmpeg from GitHub at first run and execute
it; that 404'd on the creator's first real recording (2026-09-01) and is the one
hard certification gate. ffmpeg.exe + ffprobe.exe + the libav*.dll family now ship
in the output under a single ffmpeg/ folder — the shared build resolves its DLLs
from the exe's own directory, so they must stay siblings.
The binaries are NOT in git (135 MB). scripts/fetch-ffmpeg.sh populates ./ffmpeg
from a pinned URL, verifying SHA-256 first. CopyToPublishDirectory=Always is the
one that matters for the MSIX package. -->
<ItemGroup>
<!-- `Remove` first: the SDK's default None glob already matched ffmpeg\**, so an Include
without removing it produced DUPLICATE items — one carrying the copy metadata and one
with none. Harmless until PublishSingleFile + IncludeNativeLibrariesForSelfExtract came
along, where the bundler collapses the duplicate and the folder silently stops being
published (found 2026-11-01: a 9-file publish with no ffmpeg in it). -->
<!-- ⛔ ExcludeFromSingleFile is load-bearing. With PublishSingleFile +
IncludeNativeLibrariesForSelfExtract the bundler treats the libav*.dll family as native
libs and swallows them INTO the exe — a 182 MB exe with no ffmpeg\ folder beside it, so
the locator finds nothing and every stream fails at runtime. The metadata keeps the
folder a folder. (Found 2026-11-01 by diffing the publish output against a control
publish without the single-file flags.) -->
<None Remove="ffmpeg\**" />
<None Include="ffmpeg\**" CopyToOutputDirectory="PreserveNewest" CopyToPublishDirectory="Always" ExcludeFromSingleFile="true" />
</ItemGroup>
<Target Name="GuardBundledFfmpeg" BeforeTargets="CoreCompile">
<Error Condition="!Exists('$(MSBuildProjectDirectory)\ffmpeg\ffmpeg.exe')"
Text="Bundled FFmpeg is missing from ffmpeg\. Run scripts/fetch-ffmpeg.sh once before building (it pins the URL and verifies SHA-256). FFmpeg must be bundled, never downloaded at runtime — that is Windows Store policy 10.2.2, and the previous download path 404'd on 2026-09-01." />
</Target>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>ytLive.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.10" />
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.31.0" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
<PackageReference Include="NAudio.WinMM" Version="2.2.1" />
<PackageReference Include="Notification.Wpf" Version="11.0.0" />
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.12" />
<!-- Steam's managed wrapper. The native steam_api64.dll comes from the SDK via
scripts/steam-sdk.sh; this package only provides the C# surface (SteamAPI, SteamApps). -->
<PackageReference Include="Steamworks.NET" Version="2024.8.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
</ItemGroup>
</Project>