Context
House style says errors are LocalizedError with operator-facing errorDescription strings, and copy ships as part of the product. grep -rn 'LocalizedError' Sources/ lists 15 conformances.
ScanMargins.ValidationError is the only ValidationError in ScanDeckCore missing from that list. Its two siblings — BatchName.ValidationError and FilenameTemplate.ValidationError — both conform.
The consequence is visible in the batch-setup pane: one generic sentence covers all three failure modes, so an operator who typed a negative margin, a non-finite one, or one that overflows at 600 dpi gets the same nine words and no indication of which edge is wrong. And if the error reaches armBatch's catch it renders as the raw Foundation fallback:
The operation couldn't be completed. (ScanDeckCore.ScanMargins.ValidationError error 0.)
This is the smallest genuine slice of the error-copy work and it is pure ScanDeckCore.
What to change
Sources/ScanDeckCore/ScanMargins.swift — add LocalizedError and an errorDescription covering invalidValue, invalidDPI, pixelOverflow. Copy the register from BatchName.swift and FilenameTemplate.swift: operator-facing, says what is wrong and what to do, no jargon. If invalidValue should name the edge, changing the case's payload is fine — but it is an API change, so mention it in the PR.
- Improve the two call sites that currently paper over it in
Sources/ScanDeckApp/ScanDeckPresentationModel.swift — the "Enter a valid margin for every edge." message and the summary fallback to "Invalid margins". Follow the pattern batchNameValidationMessage already uses.
- Add cases to
Tests/ScanDeckCoreTests/ScanMarginsTests.swift, which today has four tests and asserts on no message.
How to verify
swift test --filter ScanMargins
swift test -c release
bash Scripts/bundle-app.sh --synthetic # then type a negative margin in batch setup
Use the bundle, not swift run ScanDeck — a bare SwiftPM executable registers as background-only and text fields silently ignore every keystroke.
See CONTRIBUTING.md. No scanner needed.
Context
House style says errors are
LocalizedErrorwith operator-facingerrorDescriptionstrings, and copy ships as part of the product.grep -rn 'LocalizedError' Sources/lists 15 conformances.ScanMargins.ValidationErroris the onlyValidationErrorinScanDeckCoremissing from that list. Its two siblings —BatchName.ValidationErrorandFilenameTemplate.ValidationError— both conform.The consequence is visible in the batch-setup pane: one generic sentence covers all three failure modes, so an operator who typed a negative margin, a non-finite one, or one that overflows at 600 dpi gets the same nine words and no indication of which edge is wrong. And if the error reaches
armBatch's catch it renders as the raw Foundation fallback:This is the smallest genuine slice of the error-copy work and it is pure
ScanDeckCore.What to change
Sources/ScanDeckCore/ScanMargins.swift— addLocalizedErrorand anerrorDescriptioncoveringinvalidValue,invalidDPI,pixelOverflow. Copy the register fromBatchName.swiftandFilenameTemplate.swift: operator-facing, says what is wrong and what to do, no jargon. IfinvalidValueshould name the edge, changing the case's payload is fine — but it is an API change, so mention it in the PR.Sources/ScanDeckApp/ScanDeckPresentationModel.swift— the "Enter a valid margin for every edge." message and thesummaryfallback to "Invalid margins". Follow the patternbatchNameValidationMessagealready uses.Tests/ScanDeckCoreTests/ScanMarginsTests.swift, which today has four tests and asserts on no message.How to verify
Use the bundle, not
swift run ScanDeck— a bare SwiftPM executable registers as background-only and text fields silently ignore every keystroke.See CONTRIBUTING.md. No scanner needed.