How the rules are tested
97 of the pack's 110 registered rules mirror a clause in ZATCA's published validation rules, covering 96 of its 242 rule codes; the rest are Mutabiq's own checks. Every document in the fixture set is judged by ZATCA's own SDK before Mutabiq is held to it. This page says how, and its counts are read from the build's own files.
Where the rules come from
Rule pack 2.2.0 mirrors assertions in the validation rule files (Schematron) that ship in ZATCA's SDK 3.4.8: the KSA file dated 2025-12-01 and the EN16931 file dated 2025-09-02, kept in the repository byte for byte as the SDK ships them. 97 of Mutabiq's 110 registered rules mirror a published clause, and each rule's page quotes the clause it mirrors by file and line. The rest check what no published clause tests: whether the XML can be read and meets its schema, the QR payload and the previous invoice hash. The archive reader's own checks, MTB-BATCH, are separate and are not among these rules.
Where a severity comes from
Each assertion in ZATCA's files carries ZATCA's own flag, error or warning. A rule that mirrors an assertion flagged error is an Error in Mutabiq's report, because the SDK fails the document on it; a rule that mirrors one flagged warning is a Warning, because the SDK prints it and passes the document. Mutabiq does not raise a flag the files set. A rule that mirrors no clause is an Error where the SDK's schema or structure phase would fail the document, and a Warning where that is uncertain; the QR code's invoice hash, signature and public key, and the signature of ZATCA's technical CA over that key, are Advisory, because they come from the signing step and the certificate and Mutabiq cannot compute them. When the archive reader refuses an archive, that is an Error, because nothing in the archive was checked.
The test documents
The pack is held to 151 test documents built for it: documents that should pass, and documents that each carry one defect a named clause should catch. Every document is constructed from the SDK's schemas and rule files, with every field justified by a rule id. Most are unsigned, so the SDK's signature and certificate findings are expected on most of them, listed by code beside each, and never counted as a failure; one is signed with the SDK's sample key.
The SDK judges every document first
Before a document joins the set, ZATCA's SDK 3.4.8 is run on it, and the result it prints, phase by phase, is recorded beside the document with every rule code it tripped. Mutabiq's expected result for that document is set against that record, and a rule that disagrees with the SDK on a document the SDK judged is the rule that is wrong. A document the SDK stops on without a result is recorded as exactly that.
The record cannot drift
Each record carries the SHA-256 of the document's bytes at the moment the SDK judged it. A check that runs on every change recomputes every hash and fails on any difference, so an edited document cannot keep a verdict it never earned. The working rule is that a recorded verdict is changed only by running the SDK again.
The same bytes, the same verdict
A second check builds the whole set twice and runs the SDK on both, and fails if any document's bytes or any verdict differ between the runs: a generator that reached for the clock, or an oracle that answered differently, would show here. It is run when the test documents or the rule pack change, outside the checks that run on every change. One rule, MTB-BR-KSA-04, judges the issue date against a reference date, and the report of each new check states the date it used.
What runs on every change
Every change to the code runs the pack over all 151 documents and compares the findings with each record, rule by rule. A change that moves any verdict fails until the records and the code agree. The explanation text in either language has no part in a verdict, and no language model does.
When ZATCA publishes a new SDK
When ZATCA publishes a new SDK, Mutabiq re-runs its fixture set and the coverage count against the files the release ships, and records the result on the changelog within fourteen days.
What is not checked
Mutabiq checks 96 of the 242 rule codes in ZATCA's SDK 3.4.8 rule files. The coverage page lists every rule code it does not check, with ZATCA's own flag and message, and says how the codes were counted.