Build 730 (creator):
- Left pill while recording: solid #2ECC71 dot pulsing 1.0 <-> 0.2 on the existing one-second timer, and
"REC: hh:mm:ss" in Consolas so the digits cannot jitter the pill's width. Idle face unchanged.
- Right pill while recording: a stop square and "Stop Recording"; clicking it runs the normal stop, which
halts and resets the clock and returns the pair to "Local MP4" / "Start Recording".
- The separate reality line (dot + REC/LIVE + elapsed + End) is now LIVE-ONLY: a recording would otherwise
print the same three facts twice. RunningVisible is IsLive, and ShowOutputStage no longer hides itself
for a recording (it must be on screen to carry the clock and the stop).
Two rules collided and are now separated rather than merged: a creator's Stop on a recording restores the
Local MP4 pair (build 730), while a pipeline FAILURE still clears both pills (the 2026-09-01 zombie rule).
StopStream(afterFailure:) carries the difference, and the pump-failure path passes it.
RealAppHost.Run was rethrowing with `throw failure;`, which destroyed the original stack — a failing
assertion inside the action reported the wrapper's line instead of its own. ExceptionDispatchInfo now
preserves it; that is how the two failures above were located in one pass instead of five.
680 pass (one audio-pipe instance flake under full-suite load, passes alone), 0 warnings.
Scope justification: Assets/starting-background.jpg is outside this unit — the creator's replacement art,
still awaiting their visual check.
The credit existed only as a WPF BrandFlashLayer TextBlock in the preview at
25% opacity on a 300s timer. A viewer of the stream or the recording never saw
it, so "free tier shows branding" was not actually being delivered. The frame
pump has carried an unused per-frame flashFrame slot for exactly this.
Reverses the documented "Pre-GA posture" (ai.md Monetization), which kept the
flash preview-only so test VODs stayed clean. Creator ruling 2026-09-26: the
free tier has to be honest advertising, so it now reaches the broadcast.
One rendered VideoFrame feeds BOTH the frame pump and the preview, so the
creator's view cannot drift from what viewers get. Spec: 500ms in / 1000ms hold
/ 500ms out, first credit ~5s after go-live then every rand(30s)+30s, single
unwrapped line at a random spot inside the frame every time, neon white core
with a feathered red/blue halo.
Neon recipe is derivative work, per AGENTS.md: bright core + feathered
multi-radius halo with R and B split in opposite directions, from
https://nudaui.dev/components/neon-glow (layered text-shadow falloff),
https://help.maxon.net/rg/en-us/Content/html/Blurs-and-Glows-chromatic-glow.html
("with no displacement, the green channel is all but invisible behind your
white text" once R and B are split) and the OBS obs-stroke-glow-shadow
"feathered stroke with user-defined size and intensity". Neon blue is #4d8bff
rather than the theme's #0f3460, which renders near-black as a halo.
Also fixes a PRE-EXISTING bug found on the way: FramePump's fully-static
shortcut stretched the cached bake and returned it, silently discarding every
per-frame overlay - the social bar and the alert ticker were already lost
there. SceneCompositor.Overlay is now internal (it copies before blitting, so
the bake is never mutated) and the shortcut composites overlays first.
The credit is deliberately NOT folded into SceneGraph.GetBakedBase:
SceneRegion.Matches compares element ids only, so a credit in the cached bake
would freeze there and never expire. Per-frame only, and Epoch is stamped
every read because the 8MB master buffer is recycled - without that the
paste cache would freeze a stale credit.
BrandFlashEnabled is now derived !IsPremium and non-assignable, and the
presenter re-checks the licence on every read, so a key entered mid-credit
cuts the advertisement on the next tick instead of letting it finish.
Tests: 10 new facts. 357 total, 356 pass; the one failure is the known
environment-flaky RealMouseDrag layer test (needs an uncovered desktop
session). Adds RealAppHost.RunAsync - a frame-pump test must await inside the
collection's shared STA thread or the whole suite deadlocks silently.
NOTE: scope-check.sh flags Helpers/InstanceProfile.cs, AppLog.cs,
TokenStore.cs, WebView2Manager.cs and InstanceIsolationTests.cs as outside
this commit. That is a false positive: it uses `git diff HEAD`, which cannot
distinguish a planned second commit in the same session from an unrelated
edit. Those files are the dev multi-instance unit, committed immediately
after this one - as is the InstanceProfile paragraph in ai.md, which shares a
file with the Monetization section corrected here.