Skip to content

feat(l10n): localize PLC connection-lost fault - #164

Merged
mrcsin merged 1 commit into
masterfrom
plc-fault-seam
Jul 31, 2026
Merged

mrcsin merged 1 commit into
masterfrom
plc-fault-seam

Conversation

@mrcsin

@mrcsin mrcsin commented Jul 31, 2026

Copy link
Copy Markdown
Member

Problem

The panel had localizing seams for a Result's errors (ReportFailure(IResultBase)) and warnings (ReportWarnings, slice 5a), plus the snapshot-validity channel (RefreshReasons) — but none for a single transient IError. The PLC fault channel carries a typed IError end to end (PlcSyncCoordinator.EmitFault → Faults → RecipeCoordinator.OnPlcFault), yet OnPlcFault flattened it to .Message into the raw ReportError(string) sink — so the fault rendered raw English regardless of culture, and the one fault it carries was an untyped new Error("PLC connection lost") anyway.

What changed

The error-side twin of slice 5a's warning seam, proven on the connection-lost fault:

  • ReportFailure(this MessagePanelViewModel, IError error) — a localizing overload mirroring ReportFailure(IResultBase): panel.ReportError(ReasonLocalizer.Localize(error)). IError is not IResultBase, so the overload is unambiguous (all existing callers pass Results). The panel now has all four seams: ReportFailure(IResultBase), ReportFailure(IError), ReportWarnings, RefreshReasons.
  • ConnectionLostError (typed) replaces PlcSyncCoordinator's new Error("PLC connection lost").
  • OnPlcFault routes through the seam, keeping the English _logger.LogWarning("PLC fault: {Message}", ...) (log-English invariant).

Behavior-preserving for English: ConnectionLostError's base message equals today's string and the resx en value equals it byte-for-byte. Under ru the PLC fault now reads Russian. The seam localizes any IError — an untyped inner still falls through to .Message, so nothing else regresses.

Scope: this is the small mechanism cut of the PLC slice. The bulk error typing + un-laundering PlcSyncExecutor (6b) and the #120 cancellation plumbing (6c) follow.

Verification

  • dotnet build SemiStep.slnx — 0 warnings.
  • dotnet test SemiStep/SemiStep.Tests/SemiStep.Tests.csproj — 1643 passed, 0 failed.
  • ResultReportingExtensionsTests drives ReportFailure(new ConnectionLostError()) under ru (Russian in the operation slot, Error severity) + the untyped-fallthrough (.Message). PlcSyncCoordinatorTests pins BeOfType<ConnectionLostError>() at the emit source; PlcFault_RoutesToMessagePanelOperationChannel (en-scoped) keeps the routing/severity contract. ReasonLocalizerTests pins the ru render + en Localize == .Message; the coverage test forces the case.
  • Review chain: comprehensive (5 agents, all OUTCOME ACHIEVED) → smells → comment audit (Ship) → critical, all clean after two low fixes (a doc qualifier, a brace-style alignment).
  • Manual test (operator): dropped the PLC connection under the Russian UI — the fault shows in Russian in the operation channel.
Per-task commits before collapse
c99814c refactor(core): align ConnectionLostError to leaf-error brace style
9d2af24 docs: qualify ReportFailure overload in seam note
0b1bd01 test(l10n): cover transient-error seam and PLC connection-lost render
d3a86db feat(l10n): localize PLC connection-lost fault via transient seam

🤖 Generated with Claude Code

The panel had localizing seams for a Result's errors (ReportFailure) and
warnings (ReportWarnings), plus the snapshot-validity channel
(RefreshReasons), but none for a single transient IError. The PLC fault
channel carries a typed IError end to end, yet OnPlcFault flattened it to
.Message into the raw ReportError(string) sink -- so the fault rendered raw
English, and the one fault it carries was an untyped Error anyway.

Build the error-side twin of slice 5a's warning seam and prove it on the
connection-lost fault:

- ReportFailure(this MessagePanelViewModel, IError) -- a localizing overload
  mirroring ReportFailure(IResultBase): ReportError(ReasonLocalizer.Localize
  (error)). IError is not IResultBase, so the overload is unambiguous.
- ConnectionLostError (typed) replaces PlcSyncCoordinator's
  new Error("PLC connection lost").
- OnPlcFault routes through the seam, keeping the English
  LogWarning("PLC fault: {Message}", ...) (log-English invariant).

English is behavior-preserving: ConnectionLostError's base message equals
today's string and the resx en value equals it byte-for-byte. Under ru the
PLC fault now reads Russian. The seam localizes any IError -- an untyped
inner still falls through to .Message -- so nothing else regresses.

This is the small mechanism cut of the PLC slice; the bulk error typing +
un-laundering (6b) and the #120 cancellation plumbing (6c) follow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mrcsin
mrcsin marked this pull request as ready for review July 31, 2026 09:58
@mrcsin
mrcsin merged commit 543992d into master Jul 31, 2026
1 check passed
@mrcsin
mrcsin deleted the plc-fault-seam branch July 31, 2026 10:01
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.

1 participant