Skip to content

v2 translator echoes wildcard sentinels the new value bounds refuse #835

Description

@hokiepokedad2

TrackingV2Translator copies v1 integers to the v2 body verbatim. Several of those columns hold a wildcard sentinel that PoracleNG writes itself, emits nothing for on read, and — once jfberry/PoracleNG#217 lands — refuses on write.

The sentinel is coherent on their side: omit the field and the write default stores the sentinel; read the sentinel back and you get null. Omission round-trips. Echoing does not, and echoing is what we do.

PoracleTrackingProxy.PutV2Async maps 422 to AlarmValidationException with no v1 fallback, so this surfaces as a user-facing validation error on edit, not a silent downgrade.

Affected fields

Taken from #217's head — read wildcard (ptrUnless) against the bound the same field now carries.

Type Field Stored wildcard New bound When it bites
pokemon size -1 minimum: 1 any rule not filtering on size — the default
pokemon rarity -1 minimum: 1 any rule not filtering on rarity — the default
pokemon min_iv -1 minimum: 0 any rule with no IV floor
raid level 9000 1–90 every rule with a specific pokemon_id — PoracleNG forces level to 9000 there
maxbattle level 9000 1–90 same
nest pokemon_id 0 minimum: 1 a nest rule tracking any species

Raid and max battle are the worst of these: the value we echo is one PoracleNG stamped on the row itself, so it isn't a rule anyone typed wrong. level: 90 ("any tier") sits inside the bound and is fine; only the 9000 placeholder fails.

Egg level is already handled — PositiveIntegers in the type spec, added when 5.2.1 shipped minimum: 1 on that one field. This is the same defect, and the other nine types were never checked. Second time on this shape.

Fix

Add a per-type wildcard table to TrackingV2Translator and drop a field from the outbound body when its value equals the sentinel. Dropping is correct rather than merely convenient: v2 PUT is full-replace, and every one of these fields' write default is the sentinel, so omitting stores exactly what was there.

null may work as an explicit clear — the fields are nullable: true and huma should skip the bound on null — but that is unconfirmed upstream, and omission needs no confirmation. Use omission.

Tests

TrackingV2TypeTranslationTests asserts our field tables against 5.2.1's openapi.golden.json, which is what should have caught this and didn't — it checks that every schema field is classified, not that every value we can emit is acceptable. Add a case per row of the table above: a v1 row holding the sentinel must produce a body with that key absent. Watch each one fail first — a test written next to the fix passes whether or not the fix is right.

Then extend the golden assertion to compare our sentinels against the schema's minimum/maximum, so the next bound added upstream fails the build instead of production.

Timing

Not live. The bounds arrive with #217, which is open. We should land the fix before adopting a build that carries it, and pin Poracle:TrackingApiVersion=v1 as the escape hatch if the ordering slips.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions