Repository navigation
feat(l10n): localize PLC I/O errors by type (#120) - #165
Merged
Merged
Conversation
The PLC producer surface stayed English after slice 6a typed only the
connection-lost fault. NotConnectedError and ProtocolVersionMismatchError
were internal (invisible to the localizer); the recipe-active,
write-verification and not-committed faults were free-text
new Error(...) / Result.Fail(string); and PlcSyncExecutor laundered typed
inners by re-wrapping their .Message into a fresh untyped Error before
emitting the fault, discarding the type so the localizing seam could not
reach it. On the diagnostics side, PlcTransactionExecutor's five
catch { return Result.Fail(ex.Message); } sites kept only the message
string -- the exception type and stack were gone before any log sink
(issue #120, second half).
Type the PLC producer surface, un-launder the fault forwarding, and land
the exception in a log:
- Make NotConnectedError (fieldless) and ProtocolVersionMismatchError
(with Expected/Actual) public; add the leaves RecipeActiveError,
WriteVerificationFailedError(attempts), RecipeNotCommittedError, and the
Rule-B envelope PlcCommandFailedError -- each with a ReasonLocalizer arm,
en/ru resx, and a coverage sample. Six typed faults now localize.
- Un-launder PlcSyncExecutor: forward the typed inner directly
(reportFault(Errors[0]), return activeResult.ToResult()) so it localizes
through the 6a seam; type the recipe-active and exception-stringify sites.
- Diagnostics: the five PlcTransactionExecutor catches now return
PlcCommandFailedError().CausedBy(ex) and log the exception once -- writes
at Error, reads at Warning. The redundant PlcExecutionMonitor poll-error
line is guarded to skip PlcCommandFailedError (already logged at the
catch) while still surfacing the decode-Fail path, keeping exactly-once
logging with no silenced failure.
English is behavior-preserving except PlcCommandFailedError, which replaces
the raw ex.Message headline with a localized "PLC command failed" and keeps
the exception on CausedBy plus the log. Cancellation threading (issue #120,
first half) and the two remaining English producers (short protocol-version
read; enable catch) are deferred to the next slice.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Slice 6a typed only the connection-lost fault. The rest of the PLC producer surface stayed English:
NotConnectedError/ProtocolVersionMismatchErrorwereinternal— invisible toReasonLocalizer.new Error(...)/Result.Fail(string).PlcSyncExecutorlaundered typed inners — it re-wrapped a typed inner's.Messageinto a fresh untypedErrorbefore emitting the fault, discarding the type so the localizing seam could not reach it.On the diagnostics side,
PlcTransactionExecutor's fivecatch { return Result.Fail(ex.Message); }sites kept only the message string — the exception type and stack were gone before any log sink, and nothing walksResult.Reasons. This is the second half of #120 ("exception type/stack lost atResult.Fail(ex.Message)").What changed
Type the PLC producer surface, un-launder the fault forwarding, and land the exception in a log.
Six typed faults localize by type (2 made public, 4 new), each with a
ReasonLocalizerarm, en/ru resx, Designer accessor, and a coverage sample:NotConnectedErrorProtocolVersionMismatchErrorExpected/ActualpropsRecipeActiveErrorWriteVerificationFailedErrorAttempts)RecipeNotCommittedErrorPlcCommandFailedErrorCausedBy(ex))Un-laundering —
PlcSyncExecutornow forwards the typed inner directly (reportFault(Errors[0]),return activeResult.ToResult()) so it localizes through the 6aReportFailure(IError)seam; the recipe-active and exception-stringify sites are typed.Diagnostics (#120, second half) — the five
PlcTransactionExecutorcatches returnPlcCommandFailedError().CausedBy(ex)and log the exception once (writes at Error, reads at Warning). ThePlcExecutionMonitorpoll-error line is guarded to skipPlcCommandFailedError(already logged at the catch) while still surfacing the decode-Result.Failpath — exactly-once logging, no silenced failure.Behavior-preserving for English except
PlcCommandFailedError, which replaces the rawex.Messageheadline with a localized "PLC command failed" and keeps the exception onCausedByplus the log.HasError<T>type assertions survive the make-public.Deferred to 6c (documented in
error-reporting.md): the #120 cancellation threading (part 1), the short protocol-version-read diagnostic, the enable catch, and the codec decode-Result.Failforwarding — all left English by design.Verification
dotnet build SemiStep.slnx— 0 warnings.dotnet test SemiStep/SemiStep.Tests/SemiStep.Tests.csproj— 1661 passed, 0 failed.ReasonLocalizerTestspins the ru render of all six types (e.g.ProtocolVersionMismatchError(2,1)→ "Версия протокола ПЛК 1 не соответствует ожидаемой 2") + enLocalize == .Message;CoreErrorLocalizationCoverageTestsauto-enrolls the public types;ResourceSyncTestsenforces en/ru/Designer key + placeholder parity.ResultReportingExtensionsTestsdrivesNotConnectedError/RecipeActiveError/PlcCommandFailedErrorthrough the seam and asserts Russian in the operation slot.PlcSyncCoordinatorTestspins theRecipeActiveErrorproduction path andPlcCommandFailedErrorcarrying the exception on.Reasons.Result.Failpath — restored guarded) and a symmetric write-path double-log (guarded).Addresses #120 (second half; part 1 — cancellation threading — deferred to 6c).
Per-task commits before collapse
🤖 Generated with Claude Code