I'm trying to write a watcher alert that triggers when any other watcher alert fails to execute. However, due to a bug, we're getting a lot of failed watch executions because a given watch is executed at the same time by multiple nodes resulting in a version mismatch exception. Until this bug is fixed and we've upgraded versions, i've updated our alert to exclude watch execution failures of this nature. However, what i think should be a working query, is not excluding the failed executions. i've narrowed it down to the "must_not" clause not kicking out documents that contain the term.
Here is a document that should be excluded (cleaned up for simplicity):
{
  "_index": ".watcher-history-7-2018.03.06",
  "_type": "doc",
  "_id": "My_Failing_Test_Alert_624fd320-47a9-476c-87bb-7fa90037e3cf-2018-03-06T16:36:28.323Z",
  "_score": null,
  "_source": {
    "watch_id": "My_Failing_Test_Alert",
    "node": "hlvBERyKR5-XvzTE-Ud44g",
    "state": "failed",
    "status": {
      ... snip ...
    },
    "trigger_event": {
      "type": "schedule",
      "triggered_time": "2018-03-06T16:36:28.323Z",
      "schedule": {
        "scheduled_time": "2018-03-06T16:36:28.190Z"
      }
    },
    "input": {
      ... snip ...
    },
    "condition": {
      ... snip ...
    },
    "metadata": {
      ... snip ...
    },
    "result": {
      ... snip ...
    },
    "exception": {
      "type": "version_conflict_engine_exception",
      "reason": "[doc][My_Failing_Test_Alert]: version conflict, current version [22262] is different than the one provided [22261]",
      "index_uuid": "YR1UZaG-Rf6PEC82jg4YLg",
      "shard": "0",
      "index": ".watches",
      ... snip ...
    }
  },
  "sort": [
    1520354188323
  ]
}
Here is my explain query informing me that the document matches:
GET .watcher-history-7-2018.03.06/doc/My_Failing_Test_Alert_624fd320-47a9-476c-87bb-7fa90037e3cf-2018-03-06T16:36:28.323Z/_explain
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "must_not": [
            {
              "term": {
                "exception.type": "version_conflict_engine_exception"
              }
            }
          ],
          "must": [
            {
              "term": {
                "state": "failed"
              }
            },
            {
              "range": {
                "trigger_event.triggered_time": {
                  "gte": "now-2h"
                }
              }
            }
          ]
        }
      }
    }
  }
}
And the output of the explain query:
{
  "_index": ".watcher-history-7-2018.03.06",
  "_type": "doc",
  "_id": "My_Failing_Test_Alert_624fd320-47a9-476c-87bb-7fa90037e3cf-2018-03-06T16:36:28.323Z",
  "matched": true,
  "explanation": {
    "value": 1,
    "description": "sum of:",
    "details": [
      {
        "value": 1,
        "description": "ConstantScore(+state:failed +trigger_event.triggered_time:[1520351559689 TO 9223372036854775807] -exception.type:version_conflict_engine_exception)",
        "details": []
      },
      {
        "value": 0,
        "description": "match on required clause, product of:",
        "details": [
          {
            "value": 0,
            "description": "# clause",
            "details": []
          },
          {
            "value": 1,
            "description": "DocValuesFieldExistsQuery [field=_primary_term]",
            "details": []
          }
        ]
      }
    ]
  }
}
Even if i just reduce the explain query down to just the "must_not" it still matches:
GET .watcher-history-7-2018.03.06/doc/My_Failing_Test_Alert_624fd320-47a9-476c-87bb-7fa90037e3cf-2018-03-06T16:36:28.323Z/_explain
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "must_not": [
            {
              "term": {
                "exception.type": "version_conflict_engine_exception"
              }
            }
          ]
        }
      }
    }
  }
}
And the output:
{
  "_index": ".watcher-history-7-2018.03.06",
  "_type": "doc",
  "_id": "My_Failing_Test_Alert_624fd320-47a9-476c-87bb-7fa90037e3cf-2018-03-06T16:36:28.323Z",
  "matched": true,
  "explanation": {
    "value": 1,
    "description": "sum of:",
    "details": [
      {
        "value": 1,
        "description": "ConstantScore(-exception.type:version_conflict_engine_exception +*:*)",
        "details": []
      },
      {
        "value": 0,
        "description": "match on required clause, product of:",
        "details": [
          {
            "value": 0,
            "description": "# clause",
            "details": []
          },
          {
            "value": 1,
            "description": "DocValuesFieldExistsQuery [field=_primary_term]",
            "details": []
          }
        ]
      }
    ]
  }
}
The question is what am i not understanding about the query DSL thats preventing me from excluding documents that match a term? I am fairly new to querying with ES but according to this document, this should work.
https://www.elastic.co/guide/en/elasticsearch/guide/master/combining-filters.html
Thank you for your help