How it works

Four layers, and they fail differently. Knowing which layer an answer came from is how you know how much to trust it.

1. The importer reads the file

It reads the bytes as received, takes a SHA-256 digest of them before doing anything else, and parses. What it cannot take literally it says so about, by name: a file with no terminator, a calendar with part days, a missing relationship table. Those appear in the report as an inventory of the schedules considered, ahead of any finding.

The importer's fidelity is measured against MPXJ, an independent and mature reader of the same formats: 1,923,733 of 1,947,919 field comparisons, 98.76%, over 80 projects in 65 files, with every one of the 24,186 disagreements carrying a named cause.

Read that carefully. It measures agreement with another importer's convention, not with what Primavera stored. It is not a measure of correctness. It is, however, the ceiling on the layer below.

2. The scheduler computes dates and floats

An independent critical-path implementation. This is the layer that disagrees with Primavera, and the honest statement of how much is on the Does this actually work? page rather than here.

265 of the 351 conformance rules never touch this layer at all. 56 rest on the CPM arithmetic and 30 are engine-gated. That partition matters more than it looks: a finding that reads the file directly would still stand if this engine's date arithmetic were wrong, and a finding that rests on the arithmetic would not. Every finding in a report is tagged with which it is — from your file or from our arithmetic — so a reader can discount the second class without discarding the first.

3. The rule packs read the specification

Each rule is a transcription of a clause in a public document, and each finding cites that clause. This project never asserts its own standard of good practice. A generic threshold — "5% lag ratio" — would be this project's opinion about what a schedule should look like. A clause citation is your own contract read back to you.

Given a missing input, a rule may do exactly three things and never a fourth:

  1. decide it anyway, where the file settles it;
  2. report not evaluated and name the term it wanted — no industry default is ever substituted;
  3. assemble the evidence, state the question, and return referred to a person.

A rule registered as judgment cannot return a pass. The registry rebuilds every finding with the determinism it holds before the finding's own constructor sees it, so a pack cannot award itself a green tick by labelling its finding deterministic — it loses the rule to a not-evaluated instead. And a referred finding that names no activities has done nothing, so that too is refused at construction.

4. The report renders

The reporting layer computes nothing. It renders one object into Markdown, HTML or JSON, so the three cannot disagree with each other.

The order is fixed and there is no parameter to reorder it:

  1. Method
  2. Governing documents, and where they disagree
  3. Choices that could have gone the other way
  4. Assumptions
  5. Limitations
  6. Principles relied on
  7. Findings

Assumptions come before findings because the assumptions are what the other side will attack, and burying them reads as concealment even where nothing was concealed. AACE RP 29R-03 §1.1 states that the recommended practice exists to eliminate black-box analyses, and §1.2(d) states as a premise that every method is subject to manipulation through analyst judgment. A tool presenting any of them as mechanical is misrepresenting the standard it cites.

Where the standards disagree with each other

They do, and the report says so rather than picking one. Three worked examples already in the packs:

Each is registered as a conflict record and printed, rather than resolved.

What the record binds, and what it cannot

construct record writes three digests: the bytes as received, the network parsed out of them, and every date, float and flag computed from it. The third is the one that matters — a record without it supports only "we both read the same file".

construct verify re-runs the files against that record. It takes no --jurisdiction, --terms or --baseline, deliberately: an option supplied at verification time would let it answer a different question from the recorded one, which is the thing it exists to detect.

The record is append-only, hash-chained and independently verifiable. It is not more than that, and the report says so in its own words:

Date prepared is a self-asserted local time, read from the clock of the machine that ran this analysis and checked against nothing. It records when this document was produced. It is not evidence that this document, or the files it describes, predate any dispute; only an external timestamp authority is, and this engine wires none up.

Four things no record here can establish, and no format could:

Certification.to_dict reports "signed": false unconditionally, and no code path in the engine may set it otherwise. An FRE 902(13) certification is a sworn statement by a qualified person; it is not a boolean. What the engine emits is draft text for a qualified person to review, adopt and sign — and it is not a certification until they do.

The validation corpus, and by what right

The engine is measured against 82 real Primavera projects assembled by script from public code-hosting sites, pinned by commit and verified by digest. We redistribute none of it: what is published is the retrieval method and the aggregate result, so the measurement is reproducible without us handing anybody a file. It is one collection rather than a sample — most of the activities come from a single anonymous aggregation that carries no licence, and most of them have never started — so it is evidence about reading and rescheduling that body of files, and not evidence of general correctness against progressed construction schedules.

Specifically: 96.7% of the activities descend from a single anonymous 2019 aggregation that states no licence, no copyright, no attribution and no provenance, and 85.2% of the activities have never started. Nothing was downloaded in bulk, no account was created and no terms were accepted; two candidate sources were stopped at the point where proceeding would have required one of those, and are recorded as blocked rather than as negatives.

142 files that would have raised the headline figure were declined, because the dataset's own description says the networks were generated.

Performance

19,202 activities and 28.6MB read and computed in 13.5 seconds, on a 2017 four-core mobile i7. Every stage is linear in the activity count and linear in relationship density; past its limit it refuses and names what it refused.

How much of this is tested

Over six thousand tests are collected. Read that as how much was written, not as what is caught — the figure that carries that weight is the mutation score, which is 1,553 of 1,742 mutants killed, 89.2%, across twenty modules.

Do not read that aggregate on its own; the report that owns it says so in terms. It is dragged by one module at 64.8%, four modules sit at 100%, and eight modules have never been measured at all. Four earlier scores in the high nineties were withdrawn when the harness was caught reporting kills it had not made. The report's own assessment is that the suite "tests what the engine computes and not what it reports", and that is the finding rather than the percentage.

Source: web/pages/how-it-works.md. Source commit date: 2026-09-09.

See it in practice

Follow the evidence, from the schedule to the finding.

Explore the worked example