build: the exe is LlamaCasty.exe, and the publish script proves the artifact

Renames AssemblyName to LlamaCasty before the first Steam depot — Steamworks is explicit
that renaming a live exe is painful, so this had to land first, not later.

Four assembly-qualified pack URIs carried the old name, not three: MainWindow (window
icon), OverlayHost (logo), RenameRecordingDialog and KeepBroadcastDialog. Pack URIs
resolve by assembly name at runtime, so a stale one compiles, passes every test and then
silently renders nothing the first time that view opens. AssemblyIdentityTests guards
both halves — the assembly name, and no source XAML still naming the legacy assembly.
Packaging/Package.appxmanifest and package-msix.sh carry the exe name too.

scripts/publish.sh replaces the by-hand publish: single-file win-x64, ReadyToRun,
ffmpeg beside the exe, and it refuses to finish if ffmpeg, LICENSE, PRIVACY.md or
THIRD-PARTY-NOTICES.txt are missing, or if a test assembly leaked in.

That last guard exists because the first publish was wrong in a way no test could see:
PublishSingleFile + IncludeNativeLibrariesForSelfExtract bundled the libav*.dll family
into the exe — a 9-file output with no ffmpeg folder and a 182 MB binary, so the locator
would have found nothing at runtime. ExcludeFromSingleFile="true" on the content keeps
the folder a folder. Diffing against a control publish without the single-file flags
found it; guessing at item globs wasted two attempts first (recorded in MyMistakes.md).

Measured: 127 MB exe + 129 MB ffmpeg = 257 MB depot. Tests: AssemblyIdentity,
StorePackaging, BuildStamp, BundledFonts all pass; app builds with 0 warnings.
This commit is contained in:
2026-11-01 07:01:50 -08:00
parent 8f79b20a18
commit abfab25685
15 changed files with 240 additions and 54 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ mkdir -p "$STAGE_WSL"
--nologo -v minimal \
-o "$(wslpath -w "$STAGE_WSL")"
[ -f "$STAGE_WSL/ytLive.exe" ] || { echo "publish produced no ytLive.exe" >&2; exit 1; }
[ -f "$STAGE_WSL/LlamaCasty.exe" ] || { echo "publish produced no LlamaCasty.exe" >&2; exit 1; }
[ -d "$STAGE_WSL/ffmpeg" ] || {
echo "ffmpeg/ is missing from the package — it must ship bundled (Store policy 10.2.2)." >&2
exit 1
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# publish.sh — build the artifact that goes into the Steam depot.
# Usage: ./scripts/publish.sh [output-dir] (default: artifacts/steam-stage)
#
# Why a script: the flags below are load-bearing and easy to lose. PublishTrimmed stays OFF
# (WPF resolves XAML by reflection), the single-file bundle must extract natives or ffmpeg-
# adjacent loading breaks, and ReadyToRun is what keeps startup under a second on a cold
# machine. Getting one of them wrong does not fail the build — it fails on a user's PC.
#
# The output is a folder, not a zip: steamcmd uploads a directory into a depot, and Steam
# delivers it. There is no installer, no admin prompt and no self-updater (Steam updates).
#
# Requires WINDOWS dotnet — see docs/ai/environment.md -> Run.
set -euo pipefail
DOTNET="/mnt/c/Program Files/dotnet/dotnet.exe"
[ -x "$DOTNET" ] || { echo "❌ Windows dotnet not found at $DOTNET"; exit 1; }
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
OUT_REL="${1:-artifacts/steam-stage}"
OUT="$ROOT/$OUT_REL"
echo "══ publish ══"
rm -rf "$OUT"
mkdir -p "$OUT"
"$DOTNET" publish "$(wslpath -w "$ROOT/ytLive.csproj")" \
-c Release -r win-x64 --self-contained true \
-p:PublishSingleFile=true \
-p:IncludeNativeLibrariesForSelfExtract=true \
-p:EnableCompressionInSingleFile=true \
-p:PublishReadyToRun=true \
-p:DebugType=none \
--nologo -v minimal \
-o "$(wslpath -w "$OUT")"
echo "══ verify the staged artifact ══"
fail() { echo "❌ $1" >&2; exit 1; }
[ -f "$OUT/LlamaCasty.exe" ] || fail "publish produced no LlamaCasty.exe (AssemblyName reverted?)"
[ -d "$OUT/ffmpeg" ] || fail "ffmpeg/ is missing — it must ship beside the exe (docs/ai/output.md)"
[ -f "$OUT/LICENSE" ] || fail "LICENSE is missing from the artifact"
[ -f "$OUT/PRIVACY.md" ] || fail "PRIVACY.md is missing from the artifact"
[ -f "$OUT/THIRD-PARTY-NOTICES.txt" ] || fail "THIRD-PARTY-NOTICES.txt is missing from the artifact"
# Test artifacts must never reach a depot: a shipped xunit host is a support ticket.
if compgen -G "$OUT/*.Tests.dll" > /dev/null || compgen -G "$OUT/xunit*" > /dev/null; then
fail "test assemblies leaked into the publish output"
fi
# steam_api64.dll arrives with the Steamworks SDK; until then its absence is expected and the
# app must fall back to the free profile, so this is a notice, not a failure.
if [ ! -f "$OUT/steam_api64.dll" ]; then
echo "⚠ steam_api64.dll not staged — the build will run as the free profile only."
fi
echo ""
du -sh "$OUT" | awk '{print " artifact size: " $1}'
echo "✓ staged: $OUT_REL"
echo ""
echo "Next: steamcmd +run_app_build scripts/app_build_<appid>.vdf"