Skip to content

Automated Issue Completion — decisions taken unattended, 2026-09-07 #441

Description

@TGoodhew

Decisions taken without Tony present, on 2026-09-07, while working REQ-NFR-025 / #410. He asked
that anything I would otherwise have stopped to ask about be answered with my recommendation and
recorded here rather than left blocking.

The measurement that prompted all of this

artifacts/coldstart/coldstart-TG-W11VM-20260907-133247.log — the first valid cold-start figure.
A clean VMware Windows 11 VM, never had OpenVSA, NGen finished, virtual NVMe SSD.

phase cold warm (mean of 4) cold penalty
window (process start → main window) 2.43 s 0.60 s +1.83 s
+menu 0.64 s 0.53 s +0.11 s
+connect 0.02 s 0.02 s 0.00 s
+first frame 0.35 s 0.28 s +0.07 s
total 3.43 s 1.42 s

NOT MET: 3.43 s against 3.00 s. 91 % of the penalty is before a window exists, so the front-end
registry, ConnectAsync, the capabilities query and the first FFT are all cleared — the cost is
loading assemblies, and the lever is reading fewer bytes.

Decision 1 — split RegisterAccent, so the unused theme assembly never loads (DONE)

Measured, not guessed. Process.Modules cannot answer this — the CLR does not put managed
assemblies in the PEB loader list on .NET Framework, so it reports only OpenVSA.exe and nothing
else. Subscribing to AppDomain.AssemblyLoad and building a ShellWindow the way the test host
does gives the real ordered list. It showed:

0.444  4,470,784  Syncfusion.Themes.FluentLight.WPF
0.445  4,468,224  Syncfusion.Themes.FluentDark.WPF

One millisecond apart, i.e. from one method. ThemeCatalogue.RegisterAccent had both skins as
the two arms of a single if, and the jit resolves every type a method names when it compiles
that method, not when the arm runs. So applying either theme loaded both — 4.47 MB read from cold
disk for a skin the shell was not drawing. The shell opens Dark.

Split into RegisterDarkAccent / RegisterLightAccent, each [MethodImpl(MethodImplOptions.NoInlining)]
— the attribute is load-bearing, not a hint: inlined back into one body, both types are named again
and the loads return. Verified: Syncfusion.Themes.FluentLight.WPF no longer loads at all.

Decision 2 — do NOT gate the configuration system on an embedded key (ROLLED BACK)

ConfigurationManager costs 3.05 MB on the start-up path: System.Configuration (418 KB) then
System.Xml (2.63 MB), at 0.055 s and 0.056 s — and ~10 MB of GAC native images behind them, out
of the ~103 MB of framework native images the path touches.

I implemented and then reverted a change making SyncfusionLicense.ResolveKey prefer the
build-embedded key over appSettings when no local.secrets.config sits beside the exe (a shipped
installation, exactly). It was measured and it does not work: FftProviders.ResolveFromConfiguration
reads ConfigurationManager.AppSettings for the FFT-provider override independently, so the
configuration system loads regardless. The change was complexity plus a documented-precedence
subtlety in exchange for nothing, so it is gone. git checkout on SyncfusionLicense.cs, no trace
left.

Recommendation, for Tony: there are three appSettings overrides on or near the start-up path —
SyncfusionLicense, FftProviders (OpenVSA.Dsp) and VisaConfiguration (OpenVSA.Hal.Visa). All
three are deployment overrides that are absent in a normal install. Skipping the configuration system
when none of them is actually present would remove ~10 MB of cold read, but it needs one shared
mechanism across three layers, and any cheap test for "is the override there?" is a heuristic over
the .config text. That is a design decision, not a performance tweak, and it is his. I did not
take it. Deferring the reads does not help — the first trace is an FFT, so every one of them is on
the measured path wherever it is moved to.

Decision 3 — the harness could not see what it was there to check (DONE)

Measure-ColdStart.ps1 asked ngen display OpenVSA and reported the answer as the installation's
NGen status. It is not. ngen matches a partial assembly name, and a partial name still has to
match the simple name exactly — so OpenVSA says nothing whatever about OpenVSA.Core,
OpenVSA.Dsp, or the 21.7 MB of Syncfusion the start-up path spends most of its time reading.
The v0.1.1 log reads like a clean bill of health and is silent on everything that matters.

Now it walks every assembly beside the shell, asks about each, and prints the ones that were
missed
— that list is the difference between a cold start that jits 20 MB and one that does not.
Native (unmanaged) files are counted separately so OpenVSA.Fft.Native.dll is not a false alarm
every run.

Also fixed: the log said installed : 2026-08-08 for an MSI run three weeks later. It was reporting
the shell's CreationTime, which the MSI copies from the build. It now reports the build timestamp
as built, and asks Windows for the actual install date.

What is still open on #410

The single largest unknown is whether the Syncfusion assemblies get native images at all. The
installer hangs one netfx:NativeImage on OpenVSA.exe and relies on ngen install taking the
dependency closure. That is documented behaviour, not measured behaviour, and if it is not happening
then ~20 MB is jitted on the cold launch and that is the whole of the overrun. The patched harness
answers it on the next run; nothing on this machine can, because OpenVSA is not installed here and
installing it to find out would spend a machine's coldness and change Tony's dev box. I did not.

Next step is Tony's, and he is set up for it: roll the VM back to the pre-install snapshot, build
an installer from this commit, and re-run. That gives both the new figure and the NGen coverage list
in one go.

I have not closed #410 and have not touched its acceptance criteria. The 3 s is not moving —
Tony's rule from #421 is to root-cause a failure,
never widen a tolerance.

State

Landed on main as e721257. Solution-wide suite: 2 780 tests, 0 failures — the same count as
the d3bc59f bench-verified baseline, run over the whole solution rather than one project, because
the theming and layering guards only fire that way.

Bench verification of e721257 is reported in a comment below.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions