Skip to content

Move invasion onto the v2 write path now that grunt_type round-trips #841

Description

@hokiepokedad2

Depends on jfberry/PoracleNG#217.

Invasion is the one tracking type deliberately excluded from our v2 write path. PoracleTrackingProxy.ShouldTryV2 gates on TrackingV2Translator.Handles(type), and invasion has no entry in Specs, for the reason recorded there: a v2 read of a named-grunt rule carried no targeting field at all, and we hold only the grunt name.

#209 closes that. grunt_type becomes a first-class write mode and the single field every read emits, so the round trip we needed now exists.

Scope

Add an invasion TypeSpec to TrackingV2Translator and delete the exclusion, along with the <remarks> on ShouldTryV2 that explains it.

The spec differs from the others in two ways worth getting right.

grunt_type is a string, not an integer, and it is the targeting field. v2 requires exactly one of grunt_type / type_id / grunt_id / everything / boss, and since 58fcb732 omitting all of them stores everything. We only ever hold grunt_type, so we send that one and never the others. Prod has no null or empty grunt_type rows, so there is no case where we would have to rely on the omission wildcard.

gender needs its own enum array. The shared Genders table is any, male, female, genderless, but v2's invasion gender enum is any, male, female only. InvasionCreate.Gender is [Range(0, 3)], so a stored 3 is expressible on our side and has no v2 representation. Prod holds only 0, 1 and 2 today, which means this is a latent case rather than a live one, and the translator should return false for gender 3 and let it go to v1 rather than mapping it to something wrong.

Decide: what a user sees for a rule that will not write back

Ten rows in production hold space-separated grunt types (npc 0 through npc 10, player team leader). canonicalGruntTypes is derived from templates and holds the underscore forms, so those rows read fine and 422 on the way in.

They are already dead. matching/invasion.go compares the stored value against the same template-derived name, so they have never matched an invasion, and they predate our migration. But they are visible in the user's invasion list, and a user who opens one and saves it gets a validation error on a rule they did not break.

Options, roughly in order of how much I like them:

  1. Treat a 422 on a rule we could read as untranslatable and fall through to v1, the way the translator already handles rows v2 has no faithful place for. The row stays editable and stays dead, which is what it was before.
  2. Detect it on read and show it as unmatched with an explanation, since telling someone a rule has never fired is more useful than silently letting them keep it.
  3. Nothing, and let the 422 surface as a validation error.

Option 1 needs the fallback to trigger on a response rather than on inspecting the outbound body, which the current TryTranslate design does not do. Worth checking whether that is a small change or a structural one before committing to it.

Watch for

InvasionService fans out over InvasionGruntTypes.All for the "everything" case (#416). Check whether that is still needed now that everything is both a stored value and reachable by omission — it may be, for reasons unrelated to v2, but it should be a decision rather than an oversight.

Test with a rule of each shape: a type name (grass), a named grunt (giovanni), a catch-all (everything), a gender-bearing pair (mixed with gender 1), and one of the ten space-separated rows. The last one is the case the whole decision above turns on.

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