30-second answer
collectors -> evidence -> engine -> results -> reports
^ ^
schemas rules + profileEvidence flows one way. Nothing downstream writes back.
The governing sentence
The engine reasons from what is known, not from whether collection was complete.
An incomplete collection does not produce an unknown result. It produces a
result that may be unknown, if and only if the missing part could change it.
That distinction is the difference between a tool that gives up when the data is imperfect and one that says exactly how far the imperfect data still goes.
The resolution order is fixed
invalid-evidence -> not-applicable -> unknown -> pass / failIt is not a choice the engine makes per rule. invalid-evidence is first so a
malformed value cannot vanish beneath an applicability decision: an engine free
to reorder could turn a broken collector into a clean report.
The five parts, and what each may not do
Collectors collect, normalise, expand groups where they can, and compute
factual bounds such as minimum_count. They never evaluate compliance, never
assume a default for a fact they could not read, never return an empty list in
place of an error, and never present a throttled or truncated response as
complete.
They are written in whatever speaks to the source most directly. Today that is PowerShell, because the Microsoft 365 administrative surface is reachable there with the least ceremony. That is an implementation choice. The boundary is the JSON they emit, and it is the only thing the rest of the system knows about them.
Schemas validate shape and types. They do not validate cross-field
relationships needing semantic context: a rule whose condition reads a path
its evidence_requirements never declared is invalid, and no JSON Schema
expresses that. That belongs to the validator, which needs its own tests.
The engine applies the resolution order, uses bounds where they exist, and
returns unknown only when the missing information could change the outcome.
It never alters evidence. Anything it derives lives in the result, next to
the evidence it was derived from, so a reader can see both. It never
classifies: basis is authored, and the engine's only relationship with it is
to carry it into the report unchanged.
Rules declare a condition, a basis, a severity with its own rationale, limitations, and a message per authorable outcome. They execute no code and infer no evidence. A rule that needs a script is a rule whose evidence is not yet in the right shape, and the fix belongs in the collector.
Profiles select which rules run.
What this system does not do
It does not change anything in a tenant. There is no write path, no remediation
command, and no --fix-all. Remediation is text in a rule, addressed to a
person.
This is not caution about bugs. A tool that both judges and repairs stops being auditable: the evidence for a finding is gone once the finding has been acted on, and the report can no longer be reproduced against the state that produced it.