feat(v2): Intelligent Mail - #233
Merged
Merged
Conversation
The other four-state codes draw a character at a time. Here the payload becomes one 102-bit number, that number becomes ten thirteen-bit characters, and those bits are scattered across all sixty-five bars: no bar belongs to a digit, one changed digit moves at least a quarter of the symbol, and every symbol is the same width whether it carries a routing code or not. That is the damage tolerance, and an eleven-bit CRC folded into the value is what catches what survives it. Everything in the symbology is arithmetic except one table: which bit of which character each bar draws. That one is measured against zint rather than transcribed (tools/intelligent_mail_placement.py), the same way MaxiCode's placement is -- and a unique solution for all 130 assignments across 240 payloads confirms the routing offsets, the CRC and the radices along with it, before a line of PHP ran. The 102-bit arithmetic is done by hand on thirteen bytes, since thirty-one digits do not fit in a PHP integer and the library requires no extensions. Overflow throws rather than wraps.
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.
The twenty-eighth generator, and the first four-state code in the library that is not read a character at a time.
intelligent-mail(aliasesimb,usps-imb,onecode,usps4cb), pure PHP, no options. Twenty digits of tracking code and then 0, 5, 9 or 11 of routing code, written after a hyphen or run straight on.What makes it different
The payload becomes one 102-bit number, that number becomes ten thirteen-bit characters, and those hundred and thirty bits are scattered across the sixty-five bars. Nothing is local: every symbol is sixty-five bars wide whether it carries a routing code or not, and changing one digit moves at least a quarter of them (the observed minimum over a twenty-five digit payload is twenty-five bars). That scattering is the damage tolerance — mail is read at speed off folded and stamped envelopes, so a character spread over the full width loses a bit to a smudge instead of being destroyed. An eleven-bit CRC folded into the value catches what is left: detection, not correction.
The one table, measured rather than typed
Routing offsets, CRC-11, base-1365 codewords, and even the 1365-entry character table are all arithmetic — the table is every thirteen-bit pattern with five bits set, then every one with two, each beside its mirror image.
The exception is which bit of which character each bar draws: sixty-five rows USPS-B-3200 prints as letter-and-number pairs. A transposition there moves two bits between characters and is invisible in anything but a bar-for-bar comparison. So
tools/intelligent_mail_placement.pysolves it instead — the characters are computed, zint draws the bars, and each bar's two bits are matched to the (character, bit) they track across 240 payloads. A unique candidate for all 130 assignments is the whole chain confirmed at once, before a line of PHP ran; same method astools/maxicode_placement.py, for the same reason.102 bits without a dependency
Thirty-one digits do not fit in a PHP integer and this library requires no extensions, so
Numbercarries the value as thirteen bytes and does multiply-and-add and divide-with-remainder by hand. Overflow throws rather than wraps.Verification
Same one-opinion caveat as the rest of the family — no free decoder reads a four-state postal code. 78 reference symbols bar for bar against zint (
composer reference:intelligent-mail), reaching all four routing lengths, all five endorsement digits and every check bit both ways; plus the rendered PNG measured back into bars, which is now one test over the family.Because a symbol this scattered is either right or wrong nearly everywhere at once, the properties underneath the fixture are asserted separately: the character table's two enumeration rules, the bar map being a permutation of all 130 bits, the four routing lengths drawing four different symbols, and the arithmetic surviving a trip past 2^63 and back.
Checks
composer lintclean (cs, phpstan, rector, kb-lint)SCANME_REQUIRE_DECODER=1round trip: 363 tests, 1408 assertions