schemas/v1/config.schema.json
|
{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://raw.githubusercontent.com/Fortigi/PSMutant/main/schemas/v1/config.schema.json", "title": "PSMutant configuration", "description": "The configuration format for PSMutant: every key Invoke-PSMutation -ConfigFile understands, what it means, and what it must hold. This is the definition a config is written against. Add a \"$schema\" key pointing here and the config becomes self-describing -- it can be checked before a run rather than several minutes into one, and the descriptions below are the reference without leaving the file. The module checks the same format again when it runs, so nothing depends on the config having been checked first, and because two things here cannot be expressed in a schema: the operator names come from the operator map itself rather than a copied list, and a misspelled key is answered with the nearest valid name instead of 'property not allowed'. The two are kept in step by a test, not by discipline.", "type": "object", "required": [ "mutate", "tests" ], "properties": { "mutate": { "description": "The source files to mutate. A bare string is accepted for a single file.", "type": [ "array", "string", "null" ], "items": { "type": "string" }, "minItems": 1 }, "tests": { "type": [ "object", "null" ], "description": "Maps each mutated file to the test file(s) covering it. A mutant runs only its covering tests, which is most of what makes a run affordable.", "additionalProperties": { "type": [ "array", "string" ], "items": { "type": "string" } } }, "operators": { "type": [ "array", "null" ], "description": "Which mutation operators to apply. Omit for the default expression set. Four are opt-in because enabling one roughly doubles the mutant count and lowers the score, so a repo gating on thresholds.break would go red purely from turning one on.", "items": { "enum": [ "BinaryOperator", "BooleanLiteral", "ConditionForcing", "ConditionalBoundary", "NegationRemoval", "NumberLiteral", "ReturnValue", "StringLiteral" ] } }, "coveredLinesOnly": { "type": [ "boolean", "null" ], "description": "Mutate only lines the baseline suite covers. Default true. A string here is NOT a boolean: any non-empty string is truthy in PowerShell, so 'no' would mean yes.", "default": true }, "sandboxSubtrees": { "type": [ "array", "null" ], "items": { "type": "string" }, "description": "Which directories are copied into the temp sandbox. Default ['src','tests']. A covering suite that reaches outside these finds nothing there, proves nothing, and leaves its file silently unmutated." }, "workers": { "type": [ "integer", "null" ], "minimum": 0, "description": "How many mutants to evaluate at once, each in its own sandbox copy and its own Pester runspace. Omitted means 1: parallel evaluation runs your covering suite N times concurrently, and a suite that binds a fixed port or an absolute temp path is not parallel-safe, so this is opted into rather than assumed. 0 means this machine (ProcessorCount - 1). The per-mutant timeout is multiplied by this, because a budget measured on a solo baseline turns contention into false kills -- which raises the score." }, "timeoutFactor": { "type": [ "number", "null" ], "exclusiveMinimum": 0, "description": "Per-mutant deadline as a multiple of the baseline duration. A mutant that hits the deadline is scored KILLED, so this is a number to raise rather than shave." }, "timeoutFloorSeconds": { "type": [ "number", "null" ], "exclusiveMinimum": 0, "description": "Lower bound on that deadline. It matters for fast suites: a 0.2s baseline would otherwise give a near-zero budget and kill every mutant on time rather than on behaviour, scoring 100% against tests that never ran." }, "equivalents": { "type": [ "object", "null" ], "description": "Mutants that provably cannot change behaviour, excluded from the denominator. Keyed 'File:Function:Description' (preferred) or 'File:Line:Description'. Each value is the written ARGUMENT for the claim -- the run fails if a declared mutant is ever killed, stops matching, or matches more than one, so this is a checkable claim rather than a mute button.", "additionalProperties": { "type": "string", "minLength": 1 } }, "thresholds": { "type": [ "object", "null" ], "description": "The score bands. 'break' unset means report-only: the run does not fail on the score.", "properties": { "high": { "type": [ "number", "null" ], "description": "At or above this, the score prints green. Default 85." }, "low": { "type": [ "number", "null" ], "description": "At or above this, yellow; below it, red. Default 70." }, "break": { "type": [ "number", "null" ], "description": "Below this, the run FAILS. Omit for report-only." } }, "additionalProperties": false }, "reportPath": { "type": [ "string", "null" ], "description": "Where the JSON report is written, relative to the source root. A -RecheckFrom run writes a sibling and never overwrites this file." }, "recordAllKillers": { "type": "boolean", "description": "Record every test that kills a mutant rather than only the first. Default false. Setting it forfeits Pester's early stop on failure, which costs roughly 63% more wall clock." }, "survivorBaseline": { "type": "string", "description": "Path to a committed list of accepted surviving mutants, relative to the source root unless rooted. Its presence enables the baseline gate: a survivor not listed fails the run, and a listed one that is fixed, whose file leaves mutate, or that is also declared equivalent, fails too. Written by -UpdateBaseline. Absent means no baseline gate." }, "runTimeoutSeconds": { "type": "integer", "minimum": 0, "description": "Wall-clock budget for the whole run, checked between mutants. Defaults to the baseline plus twice one per-mutant budget for every mutant, which no correct run can exceed. Zero disables it, for a harness that already kills wedged jobs." } }, "patternProperties": { "^[_$]": { "description": "JSON has no comments, so `_`-prefixed keys are how a config explains itself, and `$schema` names the format this config is written against. Both are ignored by the module." } }, "additionalProperties": false } |