30-second answer

A rule is a YAML file. Thirteen fields are required, and the required set is chosen so that a rule cannot exist without saying what authority it has, what it needs to decide, and what it fails to establish when it passes.

The required fields

From the schema, rule.schema.json:

Text
schema_version  id      version    title       description
service         resource_type      basis       severity
evidence_requirements   condition  outcomes    limitations

applicability and remediation are optional. Everything else above is not.

Field by field

schema_version, version. Both are strings matching ^[0-9]+\.[0-9]+$, and the schema states why they are quoted: unquoted, 1.10 parses as the float 1.1.

id. The identifier a finding names. Ids are never reused; the validator enforces it across the whole set.

service, resource_type. What the rule is about. resource_type is what makes a rule apply to a list rather than to a site.

basis. The authority behind the rule. It has its own page, because it is the field that decides whether a finding is a defect or a decision.

severity. An object, not a word: a default of low, medium, high or critical, a rationale of at least 40 characters, and an optional configurable. The rationale is mandatory because a severity nobody argued for is a number somebody will argue with later.

evidence_requirements. A list of paths, each with a type and required: true. The constant is deliberate: optional evidence has no role in this version. Every declared path must be consumed, and every consumed path is required.

condition and the optional applicability. Both are comparisons: an operator, an evidence path and usually a value. The twelve operators are equals, not-equals, less-than, less-than-or-equal, greater-than, greater-than-or-equal, contains, not-contains, exists, not-exists, in, not-in. exists and not-exists take no value; the rest require one.

outcomes. Five messages: pass, fail, unknown, not_applicable, invalid_evidence. error is absent on purpose, and the schema says why: it describes the engine and not the resource, so a rule may not author its message.

limitations. Required, with a mandatory passes_without_resolving of at least 40 characters.

The one field that makes this engine different

limitations.passes_without_resolving is what the rule admits when it passes. SPO-LIST-002 puts it plainly:

A list at 49,000 scopes passes and is one sharing operation away from the ceiling, and a list at 6,000 passes this rule while sitting well above the number Microsoft recommends for performance. This rule measures only the supported ceiling, and passing it says nothing about whether the list is usable.

A rule cannot be merged without writing that paragraph. It is why a pass from this engine can be read as a bounded statement rather than as reassurance.