This repository was archived by the owner on Oct 12, 2026. It is now read-only.
Repository navigation
feat: add CNH, RENAVAM and boleto - #9
Merged
Merged
Conversation
The three left out of the catalogue because I could not settle which published algorithm was authoritative. brazilian-utils — already the reference for PIS and the voter ID — covers all three, so the same method applies: its vectors, then a differential run against a flat transcription of its algorithm. CNH's two check digits are coupled. When the first overflows past nine it is written as zero and the second is computed two lower to compensate. Treating them independently, which is what several published implementations do, accepts numbers the Detran would reject. RENAVAM runs its weights from the right, cycling two through nine, rather than the left-to-right descending series the rest of these documents use. Nine digits is the old format and eleven the current one; the shorter is the longer with leading zeros, so both are accepted and normalised to eleven. The boleto is two checks, not one. The linha digitável is the barcode's 44 digits shuffled into three typed groups, each carrying its own module-10 digit so that someone copying from paper is told which group they mistyped. Only after those pass is the barcode reassembled — the pieces are in a different order in each — and its own module-11 digit checked, which sits inside the barcode rather than at the end. A 48-digit arrecadação slip is a different structure and is not implemented. It is reported as not checked rather than as invalid: calling it invalid would be a lie about a number that may well be good. One deliberate deviation from the reference in each of the first two: stray characters are rejected rather than stripped, and a run of one repeated digit is not a registration. Both match what the rest of this service already does. Wiring was three lines, because #8 moved the validators into one table that both endpoints read. A test asserts all three are reachable through the batch without any further wiring — that table earning its keep.
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
The three left out of #6 because I could not settle which published algorithm was authoritative. brazilian-utils — already the reference for PIS and the voter ID — covers all three, so the same method applies: its published vectors first, then a differential run against a flat transcription of its algorithm.
What each one turned out to be
CNH's two check digits are coupled. When the first overflows past nine it is written as zero and the second is computed two lower to compensate. Treating them independently — which is what several published implementations do, and what I would have written from memory — accepts numbers the Detran would reject. This is exactly the variance that kept it out of #6.
RENAVAM runs its weights from the right, cycling two through nine, rather than the left-to-right descending series every other document here uses. Nine digits is the old format and eleven the current one; the shorter is the longer with leading zeros, so both are accepted and normalised to eleven.
The boleto is two checks, not one. The linha digitável is the barcode's 44 digits shuffled into three typed groups, each carrying its own module-10 digit — that exists so someone copying from paper is told which group they mistyped. Only once those pass is the barcode reassembled (the pieces sit in a different order in each) and its own module-11 digit checked, which lives inside the barcode at position 4 rather than at the end.
The 48-digit slip is reported as unchecked, not invalid
Arrecadação slips — utilities, taxes — are a different structure and are not implemented. They return a message saying the number was not checked. Calling it invalid would be a lie about a slip that may well be good, and the caller would have no way to tell the difference.
Two deliberate deviations from the reference
Both in the direction this service already goes:
639884962abcas a valid RENAVAM because it removes the letters first. This service has rejected that shape since fix: reject stray characters instead of stripping them #3 and is not making an exception.00000000000satisfies RENAVAM's arithmetic and the reference accepts it; every other document here excludes repeated-digit values by name, and so does this one.Both are asserted in the tests, so the divergence is recorded rather than accidental.
Verification
falseunconditionally would otherwise sail through a differential.go test ./... -racegreen;utilscoverage 71% → 76%.Wiring was three lines
Because #8 moved every validator into one table both endpoints read. A test asserts all three are reachable through
POST /validate/batchwith no further wiring — that refactor earning its keep.