{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://muhar.assay.guide/schema/spec.v1.json",
  "title": "muhar mutation spec",
  "description": "The JSON file passed to muhar with -spec. This schema is stricter than muhar's own decoder, which ignores unknown keys, matches keys case-insensitively, and reports a mutation with no file or old text as COULD_NOT_MUTATE instead of refusing the spec. A spec that validates here is always accepted by muhar. Reference: https://muhar.assay.guide/spec",
  "type": "object",
  "required": [
    "test",
    "control"
  ],
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string",
      "description": "Optional. muhar ignores this key; editors use it to find this schema."
    },
    "root": {
      "type": "string",
      "description": "Directory the suite runs in and relative file paths resolve against. Empty or absent: the current working directory."
    },
    "test": {
      "type": "string",
      "minLength": 1,
      "description": "Suite command, run with sh -c in root. A non-zero exit status means the suite failed, so the mutation in place was caught."
    },
    "control": {
      "$ref": "#/$defs/mutation",
      "description": "The positive control: a mutation the suite must catch. If it cannot be planted, or the suite stays green with it in place, the run is discarded with exit status 2."
    },
    "mutations": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/mutation"
      },
      "description": "The guards under test, run and reported in this order."
    }
  },
  "$defs": {
    "mutation": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "description": "Label in the report. Name the bug the edit simulates.",
          "minLength": 1
        },
        "file": {
          "type": "string",
          "description": "File to edit. Absolute paths are used as is; relative paths join root. Use relative paths with -j above 1.",
          "minLength": 1
        },
        "old": {
          "type": "string",
          "description": "Exact text to replace, matched byte for byte. Only the first occurrence is replaced.",
          "minLength": 1
        },
        "new": {
          "type": "string",
          "description": "Replacement text. Must differ from old. May be empty."
        }
      },
      "required": [
        "name",
        "file",
        "old"
      ]
    }
  }
}
