Skip to content

Discovery Rules

Discovery rules report on the run's own file selection rather than on the code it analysed. A filter that removes nothing looks exactly like no filter at all: the report covers files their author meant to leave out, and every number in it is computed over a set nobody asked for.


Unmatched Exclude

Rule ID: discovery.unmatched-exclude

What it measures

Every effective authored exact, subtree or regex selector is checked against observed entries: files, directories, links and special entries. All matching selectors bind before an entry is pruned. Equal writes from file, CLI and presets are grouped by canonical display with their full origin history.

Measured outcome What the run says
The selector bound Removed, with no unmatched warning
Nothing bound and no possible hidden location exists An unmatched-selector warning
A match could lie under a directory removed by its own source A qualified warning about matches outside the hider's removal
A possible hider has an origin absent from the selector's source set An unjudged value with a scope reason naming the hider and its foreign origins
A possible location cannot be listed The inaccessible directory is named; absolute absence is not claimed
PHP paths are incomplete or the universe is uncertain The unsettled selector is not judged

Scope and severity

The channel reports at project level with severity warning under final producer selection. It asks PHP-path completeness and universe certainty separately from declaration absence: authored PHP removal and generated files alone do not close this question. A bound selector remains Removed on a narrow run. Git --report limits publication, not analysis, and retains this channel even in strict mode. See Project scope.

The audit does not descend into removed directories. Possible hiders are physical directories, including accepted named directory-alias targets, not walked links or individual files. Regex might match in any such directory; exact/subtree uses literal containment. Any hider origin absent from the queried selector's sources makes it other-source. Intersecting sets are valid and other-source takes priority; equal sets give same-source.

An excluded directory outside selected paths has unseen descendants: it records named universe uncertainty without listing or PHP search there. Its selector remains bound while other unsettled selectors may be withheld. An inaccessible entry inside the selected run makes coverage incomplete with exit 4; a warning alone does not make that result authoritative.

How to settle the answer

Rerun the full project without the named CLI/preset exclusion. A same-source warning does not prove the selector is unnecessary everywhere; an other-source skip does not mean it is stale. Correct a typo or remove the selector after checking. Existing unmatched and inaccessible-location occurrence identities remain distinct: accepting one in a baseline does not accept the other.

The message names the configuration that wrote the selector (Written by configuration file "…" (imported by configuration file "qmx.yaml").). A selector that only files a Composer package installed wrote — imported from the project's install directory, vendor/ unless config.vendor-dir says otherwise — that matches nothing is not judged: the project cannot edit that file, and a later layer cannot remove an exclude entry. It is listed in projectScope.unjudgedValues with an installed-configuration reason naming the file. A selector the walk could not settle because a directory of the project's own tree is unreadable is still reported.

Options

Option Default Description
enabled true Enable or disable the rule.

Configuration

# qmx.yaml
rules:
  discovery.unmatched-exclude:
    enabled: true
bin/qmx check src/ --disable-rule=discovery.unmatched-exclude

Selection does not create coverage

Discovery audit runs only when its producer is active under final selection. enabled:true is an exact authored enable, not a reset; it can cancel a lower disable. Final projectScope judgement asks selector/path completeness separately from declaration absence. An only filter does not turn partial paths into full coverage. See Configuration.