Sweep all .cshtml files for encoding corruption; add pre-commit guard

Replace all corruption variants with HTML entities across 226 view files:
- 3-char UTF-8-as-Win1252 sequences (ae-corruption)
- Standalone smart/curly quotes that break C# Razor expressions
- Partially re-corrupted variants where the 3rd byte was normalised to ASCII

tools/Fix-Encoding.ps1: re-runnable sweep; uses [char] code points so the
script itself never contains a literal non-ASCII character; supports -DryRun

.githooks/pre-commit: blocks commits containing the ae-corruption byte
signature (xc3xa2xe2x82xac); git core.hooksPath = .githooks so the
hook is repo-committed and active for all future work on this machine.

Build clean; 225 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-20 21:37:10 -04:00
parent 21b39161a3
commit a0bdd2b5b4
252 changed files with 1785 additions and 1633 deletions
@@ -33,7 +33,7 @@
@if (!string.IsNullOrEmpty(Model.SelectedItemName))
{
<div class="text-muted small">
<i class="bi bi-box-seam me-1"></i>@Model.SelectedItemSku @Model.SelectedItemName
<i class="bi bi-box-seam me-1"></i>@Model.SelectedItemSku &mdash; @Model.SelectedItemName
</div>
}
</div>
@@ -42,7 +42,7 @@
</a>
</div>
@* ── Filter Bar ─────────────────────────────────────────────── *@
@* -- Filter Bar ----------------------------------------------- *@
<form method="get" class="filter-bar">
<input type="hidden" name="tab" value="@activeTab" />
<div class="d-flex flex-wrap gap-2 align-items-end">
@@ -53,7 +53,7 @@
@foreach (var item in Model.AllItems)
{
<option value="@item.Id" selected="@(Model.InventoryItemId == item.Id)">
@item.SKU @item.Name
@item.SKU &mdash; @item.Name
</option>
}
</select>
@@ -85,7 +85,7 @@
</div>
</form>
@* ── Summary Pills ───────────────────────────────────────────── *@
@* -- Summary Pills --------------------------------------------- *@
<div class="d-flex flex-wrap gap-3 mb-3">
<div class="stat-pill">
<div class="stat-val text-success">@Model.TotalPurchased.ToString("N2")</div>
@@ -111,7 +111,7 @@
</div>
</div>
@* ── Tabs ─────────────────────────────────────────────────────── *@
@* -- Tabs ------------------------------------------------------- *@
<ul class="nav nav-tabs mb-3" id="ledgerTabs">
<li class="nav-item">
<button class="nav-link @(activeTab == "transactions" ? "active" : "")"
@@ -129,7 +129,7 @@
</li>
</ul>
@* ── Transactions Tab ─────────────────────────────────────────── *@
@* -- Transactions Tab ------------------------------------------- *@
<div id="tab-transactions" class="@(activeTab != "usage" ? "" : "d-none")">
@if (!Model.Transactions.Any())
{
@@ -200,7 +200,7 @@
}
else
{
<span class="text-muted"></span>
<span class="text-muted">&mdash;</span>
}
</td>
<td><small class="text-muted">@t.Notes</small></td>
@@ -226,7 +226,7 @@
}
</div>
@* ── Usage Tab ────────────────────────────────────────────────── *@
@* -- Usage Tab -------------------------------------------------- *@
<div id="tab-usage" class="@(activeTab == "usage" ? "" : "d-none")">
@if (!Model.PowderUsageLogs.Any())
{
@@ -291,7 +291,7 @@
}
</td>
}
<td>@(u.CoatColor ?? "")</td>
<td>@(u.CoatColor ?? "&mdash;")</td>
<td class="text-end">@u.EstimatedLbs.ToString("N3")</td>
<td class="text-end fw-semibold">@u.ActualLbsUsed.ToString("N3")</td>
<td class="text-end @(variance > 0 ? "variance-over" : variance < 0 ? "variance-under" : "")">
@@ -344,7 +344,7 @@
</div>
<div class="modal-body">
<div id="editUsageLoading" class="text-center py-4">
<div class="spinner-border spinner-border-sm me-2"></div>Loading
<div class="spinner-border spinner-border-sm me-2"></div>Loading&hellip;
</div>
<form id="editUsageForm" class="d-none">
@Html.AntiForgeryToken()
@@ -356,7 +356,7 @@
<div class="mb-3">
<label for="euJobId" class="form-label fw-semibold">Job <span class="text-muted fw-normal">(optional)</span></label>
<select id="euJobId" name="jobId" class="form-select">
<option value=""> No job </option>
<option value="">&mdash; No job &mdash;</option>
</select>
<div class="form-text">Select the job this powder was used on.</div>
</div>