# Skip rules Skip rules mark new opportunities **Skipped** as the sources fetch them, so opportunities that are never of interest don't need skipping by hand. The rules file is named by `sources.skip_rules_file`, and used by `fetcher service` and `job-search serve`. - Only **new** opportunities are skipped: the store keeps the marks of an opportunity it already has, so a new release never changes them. To apply rules to the opportunities already stored, run `job-search skip-rules apply` (`--dry-run` lists the matches only). - The file is checked before each save and read again when it has changed. An invalid edit is logged as an error and the last good rules are kept; a deleted file is logged as a warning and nothing is skipped until it is back. At startup, a missing or invalid file stops the command. - `job-search skip-rules check [file]` reports whether a file is valid. ## Format The file is a JSON list of filters. An opportunity is skipped when **any** active filter matches it. ```json [ { "comment": "Buyer X's IT work", "active": true, "logic_mode": "and", "rules": [ { "rule_type": "buyer", "values": ["GB-FTS-12345"] }, { "rule_type": "cpv", "values": ["72000000", "48000000"], "exact": false } ] }, { "comment": "Road repairs", "active": true, "rules": [ { "rule_type": "title", "values": ["road", "repairs"] } ] }, { "comment": "Agriculture only (turned off)", "active": false, "rules": [ { "rule_type": "cpv", "values": ["03000000"] }, { "rule_type": "cpv", "values": ["03100000", "03200000"] } ] }, { "comment": "Anything with a medical equipment code", "active": true, "rules": [ { "rule_type": "cpv", "values": ["33100000"], "exact": false, "exclusive": false } ] } ] ``` ### Filters | Field | Required | Meaning | |---|---|---| | `comment` | yes | What the filter is for; logged with each opportunity it skips. May be `""` | | `active` | yes | `false` turns the filter off | | `rules` | yes | One or more rules | | `logic_mode` | no | `"or"` (default): any rule matching is enough. `"and"`: every rule must match | ### Rules | Field | Required | Meaning | |---|---|---| | `rule_type` | yes | `"buyer"`, `"title"` or `"cpv"` | | `values` | yes | One or more strings; see below | | `exact` | no | CPV rules only; default `true`. See below | | `exclusive` | no | CPV rules only; default `true`. See below | | `rule_type` | Matches when | |---|---| | `buyer` | The buyer's ID is any one of `values` | | `title` | Every word in `values` is a word of the title. Matching ignores case and is by whole words (`road` doesn't match "Railroad"); anything but letters and digits separates words, and a value with a space in it is several words | | `cpv` | The opportunity has CPV codes, and **every** one of them is in `values`: they are a subset. `["C", "D", "E"]` matches an opportunity with only C and D, but not one with C and F. For "A or B or C+D+E", use three rules (or three filters). With `"exclusive": false`, **any** one of them being in `values` is enough: `["C"]` matches an opportunity with C and F | CPV codes are 8 digits; check digits (`72000000-5`) are ignored on both sides. With `"exact": false`, a value's trailing zeros are dropped and the rest matched as a prefix, keeping at least the first two digits (the division): `72000000` covers every `72…` code, `72200000` every `722…`, and `70000000` every `70…` but not `71…`. Anything else is refused when the file is read, with the filter and rule named by their place in the file: an unknown field, a missing required field, an empty `rules` or `values`, an unknown `rule_type` or `logic_mode`, `exact` or `exclusive` on a rule that isn't a CPV rule, a title value with no words, or a CPV value that isn't 8 digits.