Skip to content

build(hygiene): ship symbols, gate warnings, align casing (#121) - #143

Merged
mrcsin merged 1 commit into
masterfrom
build-hygiene
Jul 21, 2026
Merged

build(hygiene): ship symbols, gate warnings, align casing (#121)#143
mrcsin merged 1 commit into
masterfrom
build-hygiene

Conversation

@mrcsin

@mrcsin mrcsin commented Jul 21, 2026

Copy link
Copy Markdown
Member

Closes #121.

Problem

Four build-infrastructure gaps, plus the deployed paths that carried the same defect.

  • Release shipped no symbols. DebugSymbols=False and DebugType=None meant every stack
    trace in the Serilog file landed without a file or line number. The log was never empty —
    exceptions are passed as objects and the template renders them, so type, message and the
    frame chain all arrived — but the in <file>:line <n> suffix did not, and on a long trace
    through the sync executor knowing the method is not enough to know which branch threw.
  • Nothing enforced the zero-warning state, so it could rise silently.
  • InternalsVisibleTo was declared two ways — the SDK item in Core, a raw
    AssemblyAttribute in UI.
  • The assembly was named Semistep while the product and every namespace are SemiStep.
    The deployed C:\DISTR\Config\ and C:\DISTR\Logs\ roots carried the same casing.

What changed

  • DebugType=portable for Release. The installer picks the PDB up on its own — it copies the
    publish directory whole and excludes nothing.
  • TreatWarningsAsErrors and EnforceCodeStyleInBuild set centrally. NuGet audit codes
    NU1900-NU1904 are exempt: an advisory published against a transitive package, or an
    unreachable audit feed, would otherwise fail CI with no change in the repository.
    AnalysisLevel is deliberately absent for the same reason — global.json rolls forward
    across feature bands, so latest would move on its own.
  • dotnet_diagnostic.IDE1006.severity = warning in .editorconfig. This is what makes the
    style gate actually bite: EnforceCodeStyleInBuild alone does not, because the
    dotnet_naming_rule severities drive the IDE rather than the build. It matters because CI
    runs no dotnet format step and the pre-commit hook is not versioned, so a fresh clone had
    no style enforcement at all.
  • One spelling of InternalsVisibleTo, matching Core.
  • AssemblyNameSemiStep, with the eleven avares:// URIs and one assembly= reference
    that resolve against it, the installer's AppExeName, .zed/debug.json and the localization
    doc. The deployed roots are recased in StartupOptions and in the installer.
  • The six [InstallDelete] entries clearing the legacy flat config layout are removed rather
    than recased — no machine carries that layout, so the cleanup has nothing left to do.
  • .github/workflows/ci.yml paths gains SemiStep.slnx and .editorconfig; both now define
    the build and a change to either alone would not have triggered CI.
  • New Docs/architecture/build-and-deployment.md records the gate, the audit exemption, the
    IDE1006 finding, and the fact that StartupOptions.cs and Installer/SemiStep.iss duplicate
    the deployed literals with nothing checking that they agree.

Verification

  • Clean Release build: 0 warnings, 0 errors
  • dotnet test SemiStep.slnx — 1444 passed, 0 failed
  • dotnet publish emits SemiStep.pdb alongside SemiStep.exe
  • ISCC.exe compiles the installer with the new SrcCfgDir / ConfigRoot / LogRoot defines
  • Both gates proven to bite: an unused local fails with CS0219, a private field violating the
    naming rule fails with IDE1006
  • The rename was the risk — the headless suite boots the real App and loads
    avares://SemiStep/Styles/ColorPalette.axaml, so a broken rename would have failed all 615
    AvaloniaFact tests as a group. It did not.

Note for reviewers

The C:\DISTR rename is safe on an existing installation because NTFS is case-insensitive:
Config\Semistep\ and Config\SemiStep\ are the same directory, so an upgraded machine keeps
reading its configuration and the installer overwrites in place. Nothing is stranded.

The deployed literals live in two places by hand — StartupOptions.cs and
Installer/SemiStep.iss — and nothing at build time checks that they agree. The only detection
is a manual install. That is documented rather than fixed here.

Four build-infrastructure gaps from the issue, plus the deployed paths that carried the same
defect.

Release shipped no symbols: DebugSymbols=False and DebugType=None meant every stack trace in
the Serilog file landed without a file or line number. The log was never empty — exceptions are
passed as objects and the template renders them, so type, message and the frame chain all
arrived — but the ` in <file>:line <n>` suffix did not, and on a long trace through the sync
executor knowing the method is not enough to know which branch threw. DebugType=portable now,
and the installer picks the PDB up on its own because it copies the publish directory whole.

Nothing enforced the zero-warning state, so it could rise silently. TreatWarningsAsErrors and
EnforceCodeStyleInBuild are set centrally. NuGet audit codes NU1900-NU1904 are exempt: an
advisory published against a transitive package, or an unreachable audit feed, would otherwise
fail CI with no change in the repository. AnalysisLevel is deliberately absent for the same
reason — global.json rolls forward across feature bands, so `latest` would move on its own.

EnforceCodeStyleInBuild alone did not gate the .editorconfig naming rules. The
dotnet_naming_rule severities drive the IDE; build enforcement reads
dotnet_diagnostic.IDE1006.severity, which was unset. Adding that one line is what makes the
gate bite, and it matters because CI runs no dotnet format step and the pre-commit hook is not
versioned — a fresh clone has no style enforcement at all without it.

InternalsVisibleTo was declared two ways, the SDK item in Core and a raw AssemblyAttribute in
UI. One spelling now, matching Core.

The assembly was named Semistep while the product and every namespace are SemiStep. The name is
load-bearing in XAML: eleven avares:// URIs and one assembly= reference resolve against it, and
the headless suite boots the real App, so a broken rename would have failed all 615 AvaloniaFact
tests as a group. It did not. The deployed C:\DISTR\Config\ and C:\DISTR\Logs\ roots are recased
to match, in StartupOptions and in the installer, which duplicate those literals by hand with
nothing checking that they agree.

The six [InstallDelete] entries clearing the legacy flat config layout are removed rather than
recased. No machine carries that layout, so the cleanup has nothing left to do.

Verified: clean Release build 0 warnings 0 errors, 1444 tests passed, publish emits SemiStep.pdb,
ISCC compiles the installer with the new defines, and both gates were proven to bite by
introducing a violation and watching the build fail.

Closes #121

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrcsin
mrcsin marked this pull request as ready for review July 21, 2026 15:59
@mrcsin
mrcsin merged commit 1eaa83d into master Jul 21, 2026
1 check passed
@mrcsin
mrcsin deleted the build-hygiene branch July 21, 2026 15:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build hygiene: Release ships no PDBs; no TreatWarningsAsErrors/AnalysisLevel; InternalsVisibleTo declared two ways; AssemblyName casing

1 participant