Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ csharp_wrap_before_ternary_opsigns = true

#### Naming Conventions ####

# The per-rule severities below drive the IDE only. Build enforcement of naming
# (EnforceCodeStyleInBuild) reads the IDE1006 diagnostic severity.
dotnet_diagnostic.IDE1006.severity = warning

# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@ on:
branches: [master, main]
paths:
- ".github/workflows/ci.yml"
- ".editorconfig"
- "SemiStep/**"
- "SemiStep.slnx"
- "ConfigFiles/**"
- "global.json"
- "!**.md"
pull_request:
paths:
- ".github/workflows/ci.yml"
- ".editorconfig"
- "SemiStep/**"
- "SemiStep.slnx"
- "ConfigFiles/**"
- "global.json"
- "!**.md"
Expand Down
4 changes: 2 additions & 2 deletions .run/Debug MBE.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug MBE" type="DotNetProject" factoryName=".NET Project">
<log_file alias="semistep.log" path="$USER_HOME$/AppData/Local/Temp/Semistep/semistep.log" checked="true" skipped_content="true" />
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.UI.exe" />
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.exe" />
<option name="PROGRAM_PARAMETERS" value="--config-dir &quot;$PROJECT_DIR$/ConfigFiles/MBE&quot; --log-file &quot;$USER_HOME$/AppData/Local/Temp/Semistep/semistep.log&quot; --logging-level verbose" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug" />
<option name="PASS_PARENT_ENVS" value="1" />
Expand Down
4 changes: 2 additions & 2 deletions .run/Debug MOCVD.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug MOCVD" type="DotNetProject" factoryName=".NET Project">
<log_file alias="semistep.log" path="$USER_HOME$/AppData/Local/Temp/Semistep/semistep.log" />
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.UI.exe" />
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.exe" />
<option name="PROGRAM_PARAMETERS" value="--config-dir &quot;$PROJECT_DIR$/ConfigFiles/MOCVD&quot; --log-file &quot;$USER_HOME$/AppData/Local/Temp/Semistep/semistep.log&quot; --logging-level verbose" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug" />
<option name="PASS_PARENT_ENVS" value="1" />
Expand Down
4 changes: 2 additions & 2 deletions .run/Debug RIE.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Debug RIE" type="DotNetProject" factoryName=".NET Project">
<log_file alias="semistep.log" path="$USER_HOME$/AppData/Local/Temp/Semistep/semistep.log" />
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.UI.exe" />
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.exe" />
<option name="PROGRAM_PARAMETERS" value="--config-dir &quot;$PROJECT_DIR$/ConfigFiles/RIE&quot; --log-file &quot;$USER_HOME$/AppData/Local/Temp/Semistep/semistep.log&quot; --logging-level verbose" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.UI/debug" />
<option name="PASS_PARENT_ENVS" value="1" />
Expand Down
2 changes: 1 addition & 1 deletion .run/Perf Gates.run.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<component name="ProjectRunConfigurationManager">
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Perf Gates" type="DotNetProject" factoryName=".NET Project">
<option name="EXE_PATH" value="$PROJECT_DIR$/SemiStep/Artifacts/bin/SemiStep.Tests/release/SemiStep.Tests.exe" />
<option name="PROGRAM_PARAMETERS" value="-explicit only" />
Expand Down
2 changes: 1 addition & 1 deletion .run/Publish.run.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<component name="ProjectRunConfigurationManager">
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="publish" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="dotnet publish SemiStep/SemiStep.UI/SemiStep.UI.csproj -c Release 2&gt;&amp;1" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
Expand Down
6 changes: 3 additions & 3 deletions .run/dotnet_restore.run.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<component name="ProjectRunConfigurationManager">
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="dotnet_restore" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="dotnet restore SemiStep.slnx" />
<option name="INDEPENDENT_SCRIPT_PATH" value="false" />
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/.run/dotnet_restore.ps1" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
Expand Down
6 changes: 3 additions & 3 deletions .zed/debug.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"label": "Launch SemiStep.UI (MBE)",
"adapter": "netcoredbg",
"request": "launch",
"program": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug/Semistep.dll",
"program": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.dll",
"cwd": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug",
"args": [
"--config-dir",
Expand All @@ -20,7 +20,7 @@
"label": "Launch SemiStep.UI (MOCVD)",
"adapter": "netcoredbg",
"request": "launch",
"program": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug/Semistep.dll",
"program": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.dll",
"cwd": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug",
"args": [
"--config-dir",
Expand All @@ -37,7 +37,7 @@
"label": "Launch SemiStep.UI (RIE)",
"adapter": "netcoredbg",
"request": "launch",
"program": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug/Semistep.dll",
"program": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug/SemiStep.dll",
"cwd": "${ZED_WORKTREE_ROOT}/SemiStep/Artifacts/bin/SemiStep.UI/debug",
"args": [
"--config-dir",
Expand Down
4 changes: 4 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ dotnet run --project SemiStep/SemiStep.UI/SemiStep.UI.csproj
dotnet format SemiStep.slnx # pre-commit hook enforces this
```

The build treats warnings and `.editorconfig` naming violations (IDE1006) as errors, so a new one
fails CI instead of accumulating; formatting is not gated by the build. See
`Docs/architecture/build-and-deployment.md`.

## Test

```powershell
Expand Down
84 changes: 84 additions & 0 deletions Docs/architecture/build-and-deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Build and Deployment

What the build enforces, what it does not, and where a released application looks on disk. Read
this before relaxing an MSBuild property, renaming the assembly, or changing a deployed path.

## What the build enforces

`SemiStep/Directory.Build.props` governs the three projects — the file sits under `SemiStep/`,
not at the repository root.

- **`TreatWarningsAsErrors=true`.** Any compiler or analyzer warning fails the build, in Debug and
Release alike. The repository is at zero warnings; a new one has to be fixed, not accumulated.
- **`WarningsNotAsErrors=NU1900;NU1901;NU1902;NU1903;NU1904`.** NuGet audit results depend on the
outside world. A newly published advisory against a transitive package, or an unreachable audit
source, must not turn restore red with no commit in the repository. The warnings still appear in
the build log.
- **`AnalysisLevel` is deliberately absent.** Without it the rule set derives from
`TargetFramework` and stays fixed at net10.0's. `global.json` uses `rollForward: latestFeature`,
so the SDK floats across feature bands; setting `AnalysisLevel=latest` would let a new band break
the build with no change in the repository.
- **`EnforceCodeStyleInBuild=true` plus `dotnet_diagnostic.IDE1006.severity = warning` in
`.editorconfig`.** Together these turn naming violations into build errors.

**`EnforceCodeStyleInBuild` alone does not gate naming.** The `dotnet_naming_rule.*.severity`
entries in `.editorconfig` drive the IDE only; build enforcement reads the IDE1006 diagnostic
severity, which is unset by default. Measured: with only `EnforceCodeStyleInBuild=true`, a private
field renamed to `StringMaxLengthProbe` built clean at zero warnings. Removing the
`dotnet_diagnostic.IDE1006.severity` line silently disables the naming gate while leaving every
naming rule visibly in place.

## What the build does not enforce

Whitespace and the `csharp_*` formatting preferences in `.editorconfig` are **not** part of the
build gate. They bind through `dotnet format SemiStep.slnx --verify-no-changes` in
`.git/hooks/pre-commit`, which is not versioned — a fresh clone has no hook — and
`.github/workflows/ci.yml` runs no `dotnet format` step. Formatting is therefore enforced only on
machines where someone installed the hook by hand.

## Release symbols

Release builds emit portable PDBs (`<DebugType>portable</DebugType>` in the Release
`PropertyGroup`). The installer's `[Files]` section copies the publish directory wholesale with no
`pdb` exclusion, so `SemiStep.pdb` ships next to the executable. That is what puts file names and
line numbers into the Serilog stack traces coming off installed machines, which is the primary
diagnostic for a deployed PLC-integration application.

## Assembly name casing

**The assembly is `SemiStep`.** Every `avares://` URI and every XAML `assembly=` reference carries
that casing: `avares://SemiStep/...`, `clr-namespace:SemiStep.UI.RecipeGrid;assembly=SemiStep`. The
build output is `SemiStep.dll`, the executable `SemiStep.exe`, the Russian satellite
`ru/SemiStep.resources.dll`.

`Docs/plans/completed/20260623-cell-change-highlight.md:149` instructs keeping `assembly=Semistep`
lowercase and says "do not correct the casing". That instruction was correct when the assembly was
named `Semistep` and is now obsolete; the historical plan stays as written. This section is the
current rule.

The full `AvaloniaFact` suite boots the real `App` and loads `avares://SemiStep/Styles/ColorPalette.axaml`,
so a broken asset URI shows up as the UI tests failing as a group.

## Deployed paths

An installed application uses two roots under `C:\DISTR`:

| Root | Default |
|---|---|
| Configuration | `C:\DISTR\Config\SemiStep\<preset>` (presets: `MBE`, `MOCVD`, `RIE`) |
| Logs | `C:\DISTR\Logs\SemiStep\semistep.log` |

Both are overridable per launch through `--config-dir` and `--log-file`; the installer's shortcuts
pass `--config-dir` explicitly, one shortcut per preset.

**The two sides of each path are duplicated by hand and nothing checks that they agree.** The
application holds them as `StartupOptions.DefaultConfigDir` and `StartupOptions.DefaultLogFilePath`
(`SemiStep/SemiStep.UI/StartupOptions.cs`); the installer holds them as `#define ConfigRoot` and
`#define LogRoot` (`Installer/SemiStep.iss`). No build step, no test and no CI job compares them.
The only thing that detects a divergence is a manual install followed by launching from a
created shortcut — an application that silently falls back to a directory the installer never
wrote configuration into looks like a missing-config error, not a path mismatch. Change one side,
change the other in the same commit.

NTFS is case-insensitive, so the casing of these paths is cosmetic on disk: an upgrade over an
installation created with the older `Semistep` spelling keeps reading the same directories.
4 changes: 2 additions & 2 deletions Docs/architecture/ui-localization.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Two resource files live in `SemiStep.UI/Localization`:
- `Resources.resx` — the neutral/invariant set, holding **English** values. English is the fallback
because it aligns with the English logs, so a missing satellite degrades to English rather than to
a partial mix.
- `Resources.ru.resx` — the Russian set, compiled into the `ru/Semistep.resources.dll` satellite
assembly (the entry assembly name is `Semistep`).
- `Resources.ru.resx` — the Russian set, compiled into the `ru/SemiStep.resources.dll` satellite
assembly (the entry assembly name is `SemiStep`).

Resources are referenced from AXAML via `{x:Static l:Resources.Key}` (with
`xmlns:l="clr-namespace:SemiStep.UI.Localization"`) and from C# via `Resources.Key`. Composite labels
Expand Down
2 changes: 1 addition & 1 deletion Docs/perf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ takes the same flags and is what `dotnet run` launches under the hood — the di
capture (below) is the one place that must call it directly.

IDE entry points for the same invocation: the Rider run configuration **Perf Gates**
(`SemiStep/.run/Perf Gates.run.xml`) and the Zed task **Perf Gates (explicit tests, Release)**
(`.run/Perf Gates.run.xml`) and the Zed task **Perf Gates (explicit tests, Release)**
(`.zed/tasks.json`). Rider's unit-test tree shows explicit tests as "not run" on Run All by
design; use the run configuration, not the test gutter.

Expand Down
Loading