On this page
Decide whether the field is an identifier
A value is an identifier when its characters select or name something, rather than measure an amount. A fixed-width account key, postal code, warehouse bin, catalog code, and composite record key can all contain digits while remaining text. The first review question is not “can a parser convert this?” It is “would changing the character sequence change the key?” If yes, keep the lexical form.
The source dates shown in this guide identify documentation checks on 22 October 2026, not original publication dates. Use the producer contract to decide whether a prefix, case choice, separator, or width is significant. Do not infer that a field is numeric just because a spreadsheet displays it right-aligned.
| Field behavior | Likely wire type | Risk when cast to number |
|---|---|---|
Fixed-width key such as 0017 | String | Leading zeros disappear |
| Code with letters and digits | String | Prefix or case can change |
| Measured quantity | Number or documented decimal string | Arithmetic may be blocked if text is used |
| Sequence used only for ordering | Integer with range | Still needs a separate identifier policy if reused as a key |
| Unknown digit-only field | Keep source text until classified | A guess can make joins irreproducible |
Write a width and pattern contract
Make the lexical rule executable. State whether the identifier has an exact width, a minimum and maximum width, an allowed alphabet, a prefix, separators, and case behavior. If a value may be blank, model that state separately from a valid identifier. If the source uses several formats, version the contract instead of silently padding or trimming rows during export.
| Contract field | Synthetic choice | Question for the owner |
|---|---|---|
wire_type | string | Does every serializer emit quotes? |
pattern | ^[0-9]{4}$ | Are separators or prefixes ever valid? |
width | 4 | Is width fixed across versions? |
normalization | none | Would padding create a new identifier? |
case_policy | not_applicable | If letters occur, is case significant? |
invalid_action | reject_and_report | Can an invalid key enter a join? |
JSON Schema can express a string type, a regular-expression pattern, and length boundaries. The schema does not know that a value is a business key, so add a description or external data dictionary that names its role. Keep the schema validation result separate from ownership, uniqueness, and authorization findings.
Round-trip text through every serializer
Test the smallest path that can lose width: source reader, in-memory representation, JSON serializer, destination reader, and any spreadsheet or warehouse adapter. A parser that turns 0017 into an integer has already discarded evidence. Re-padding the integer later can make the output look tidy while hiding whether the source was 17, 0017, or an invalid longer value.
import json
import re
KEY = re.compile(r"^[0-9]{4}$")
source = {"record_key": "0017"}
wire = json.dumps(source, separators=(",", ":"))
loaded = json.loads(wire)
value = loaded["record_key"]
assert isinstance(value, str)
assert KEY.fullmatch(value)
assert value == "0017"
Minimum fixture set
- A valid all-zero value if the contract allows it.
- A valid value with one leading zero, such as
0017. - A valid value with no leading zero, such as
1700. - A short value, a long value, and a value with whitespace.
- A quoted JSON string and a deliberately rejected JSON number.
RFC 8259 also recommends unique object member names for interoperability. That matters here because a duplicate key can make a test appear to preserve one identifier while a receiver chooses another. Reject duplicate members or use a parser mode that exposes them before judging identifier behavior Internet Engineering Task Force, (opens in a new tab).
Join and sort without changing identity
A join review should compare the exact key text first. Do not repair a failed join by converting both sides to numbers unless the owner has confirmed that lexical width is irrelevant. If two source systems use different widths, retain each original value, map through a documented crosswalk, and record whether the mapping is one-to-one, many-to-one, or unresolved.
| Operation | Safe default | Finding to record |
|---|---|---|
| Equality | Compare strings under the stated case policy | Unresolved normalization or width mismatch |
| Sorting | Use lexical or numeric order only when declared | Consumer sorted a key as a measure |
| Join | Match exact contract values before crosswalks | Rows need a mapping or remain unmatched |
| Deduplication | Preserve source keys and collision evidence | Values collapse after coercion |
| Export | Quote identifiers and validate after serialization | Wire type changed at the boundary |
RFC 8785 provides a useful caution for canonicalization: strings and numbers are different JSON values, and number serialization follows a precision model. Canonical output cannot restore characters that an earlier numeric conversion discarded. Treat canonicalization as a final check, not a repair step Internet Engineering Task Force, (opens in a new tab).
Take a qualified next step
If the owner can describe the collection and its handling authority, the next step may be the appraisal route. That route is a request for review, not automatic acceptance, a quote, a buyer match, a legal opinion, or a license. A small synthetic fixture is enough to test leading-zero behavior; do not send private records merely to demonstrate a serializer bug.
Takeaways
- Classify digit-only fields as identifiers or measures before parsing.
- Use a string wire type when width or characters are meaningful.
- Validate width and pattern after every serialization boundary.
- Compare exact text before applying a documented crosswalk.
- Report lexical integrity separately from uniqueness and ownership.