Thanks to everyone who worked through #253/#260/#266/#273 — that was a long, careful thread and the resulting /retrieve-age-band endpoint is a genuinely useful addition. I don't have maintainer standing on this repo, and #273 is already merged — please treat this as a follow-up flag rather than a blocking objection; fine to close as won't-fix if the group prefers to leave it as-is.
Problem description
SimSwapAgeBand (added in #273) is type: integer with enum: [1, 2, ..., 17, 111], where 111 is a sentinel ("provider positively confirms a SIM swap has never happened for the subscriber and the number has never been ported") that deliberately sits far outside the 1–17 ordinal range.
Per the API Design Guide §2.2, an integer field MUST specify format and a minimum/maximum range — there's no enum-based exception for integers (unlike strings, where enum substitutes for maxLength). That's what's driving the S-310/S-311 findings already tracked in #276.
This isn't just a missing annotation — there isn't a correct minimum/maximum pair for this domain. 1–17 is a genuine, ordered range; 111 is explicitly documented as "NOT a position in the recency sequence." Any single numeric range either has to include 111 (misleadingly implying 18–110 are valid, or that 111 is "past band 17") or exclude it (contradicting the schema's own enum). Adding numbers to satisfy the linter won't fix this — the value domain genuinely can't be described by one min/max pair.
Possible evolution
Re-type the field as a string enum, which sidesteps the range problem since enum alone satisfies §2.2 for strings — e.g. BAND_01...BAND_17 plus a NEVER_SWAPPED value for the sentinel. Zero-padding the rank into the value (rather than a duration mnemonic like WITHIN_4H) keeps today's threshold comparisons working: plain string comparison ("BAND_03" <= "BAND_09") reproduces the same ordering as the current 3 <= 9, so consumers doing band-edge checks (e.g. the 72h/96h split from #273) don't need a lookup table or a unit-aware parser.
Alternative solution
No strong stake in that specific shape — happy to sketch it out further if useful, or to leave the fix entirely to the group for whenever this operation is next touched.
Additional context
- Out of curiosity: the enum went through a few shapes across #260/#266/#273 —
-1/0/1–15 in #260 and #266's initial version, then 1–15 + 999 in #273's first draft, settling on 1–17 + 111 after review. The -1/0 scheme at least kept the sentinels adjacent to the real range; unclear from the thread what motivated the move to a value chosen specifically to sit far outside it instead. Not trying to relitigate that — just flagging in case it's relevant to how you want to resolve this.
sim-swap is still alpha in the current release plan, so this should still be cheap to adjust if the group agrees it's worth doing before rc.
Thanks to everyone who worked through #253/#260/#266/#273 — that was a long, careful thread and the resulting
/retrieve-age-bandendpoint is a genuinely useful addition. I don't have maintainer standing on this repo, and #273 is already merged — please treat this as a follow-up flag rather than a blocking objection; fine to close as won't-fix if the group prefers to leave it as-is.Problem description
SimSwapAgeBand(added in #273) istype: integerwithenum: [1, 2, ..., 17, 111], where111is a sentinel ("provider positively confirms a SIM swap has never happened for the subscriber and the number has never been ported") that deliberately sits far outside the1–17ordinal range.Per the API Design Guide §2.2, an integer field MUST specify
formatand aminimum/maximumrange — there's noenum-based exception for integers (unlike strings, whereenumsubstitutes formaxLength). That's what's driving the S-310/S-311 findings already tracked in #276.This isn't just a missing annotation — there isn't a correct
minimum/maximumpair for this domain.1–17is a genuine, ordered range;111is explicitly documented as "NOT a position in the recency sequence." Any single numeric range either has to include111(misleadingly implying18–110are valid, or that111is "past band 17") or exclude it (contradicting the schema's own enum). Adding numbers to satisfy the linter won't fix this — the value domain genuinely can't be described by one min/max pair.Possible evolution
Re-type the field as a
stringenum, which sidesteps the range problem sinceenumalone satisfies §2.2 for strings — e.g.BAND_01...BAND_17plus aNEVER_SWAPPEDvalue for the sentinel. Zero-padding the rank into the value (rather than a duration mnemonic likeWITHIN_4H) keeps today's threshold comparisons working: plain string comparison ("BAND_03" <= "BAND_09") reproduces the same ordering as the current3 <= 9, so consumers doing band-edge checks (e.g. the 72h/96h split from #273) don't need a lookup table or a unit-aware parser.Alternative solution
No strong stake in that specific shape — happy to sketch it out further if useful, or to leave the fix entirely to the group for whenever this operation is next touched.
Additional context
-1/0/1–15in #260 and #266's initial version, then1–15+999in #273's first draft, settling on1–17+111after review. The-1/0scheme at least kept the sentinels adjacent to the real range; unclear from the thread what motivated the move to a value chosen specifically to sit far outside it instead. Not trying to relitigate that — just flagging in case it's relevant to how you want to resolve this.sim-swapis stillalphain the current release plan, so this should still be cheap to adjust if the group agrees it's worth doing beforerc.