A mapping that had been dynamic for three years

Dynamic mapping infers a type from the first document it sees, which means the schema was decided in 2020 by whichever product was indexed first.

{ "mappings": {
    "dynamic": "strict",
    "properties": {
      "sku":   { "type": "keyword" },
      "name":  { "type": "text", "analyzer": "english" },
      "price": { "type": "scaled_float", "scaling_factor": 100 },
      "tags":  { "type": "keyword" }
    }
} }

The field that had been inferred wrong was a product code that looked numeric on the first document and was alphanumeric on most — indexed as a long, then silently rejected for three years. dynamic: strict turns a future inference into an error at index time, which is loud and is what you want; false stores the field without indexing it, which is quiet and is how this happened.