Is this real?
For an engineer who has no reason to trust this and no time. What is claimed, what the evidence is, where it stops. Every figure names the file that owns it, so you can check the owner rather than this page, and carries a date, because three engine fixes moved the headline in one day on 1 September 2026 and two importer fixes moved it further the next day. Section 8 is the commands.
Most of this page is not in the watched list in
engine/tests/test_docs_match_the_catalogue.py, which pins nine named pages to
the files owning their numbers, so a re-measurement of those figures will not
fail it — one more reason to go to the owner. The exception is §3's mutation
figures, as of 2 September 2026. That watch is no longer a list of pages: it
is every page that cites MUTATION-REPORT.md or MUTATION-LEDGER.json, this
page among them, and it was made derived because a list of three missed the four
superseded scores this page was carrying. Twenty-eight false statements have been found in this
project's own documentation in two days (docs/STATE-OF-PLAY.md §4).
1. The number to start with
Agreement with Primavera P6 is 67.85% — 396,735 of 584,687 field comparisons
across 82 projects, P6 5.0 to 24.12, measured 2026-09-02
(engine/oracle/corpus/SWEEP-2.md). Over the 66 projects that pass the harness's
validity gate it is 78.06%, and that belongs beside the headline rather than
instead of it, because the 16 refused projects hold 40.9% of all comparisons.
Three things about it matter more than its level.
The ceiling is 98.06%, so the shortfall is ours. A reader who sees 67.85%
cannot tell an engine carrying thirty points of defects from an engine measured
against a noisy target. That question is now settled and it settled against us.
engine/oracle/corpus/P6-SELF.md measures P6 against itself over the same 82
projects and the same 584,687 comparisons — five predicates, each a statement a
file makes twice using only fields P6 wrote, with our scheduler never called —
and finds 11,330 comparisons sitting on a row whose stored values cannot all
be true at once. No scheduler can reproduce those, so achievable agreement is
capped at 98.06%: of the 32.14-point shortfall, at most 1.94 points are
P6's and at least 30.20 are ours. The two figures are over the same
denominator, which is the only reason the subtraction is allowed. This is the
opposite of a mitigation. It removes the excuse the project had been able to
lean on — some of what we call our defects may be theirs — and on this corpus
the answer is almost none of them: the two projects holding 53.4% of the raw
disagreement hold 5.2% of P6's self-inconsistency. The 98.06% is itself a
bound and not an estimate; it counts only contradictions provable from the
file, so the true ceiling is lower and nothing says how much.
It fell. It was 79.32% on a population of 22 projects and dropped to 60.51%
when the corpus grew fifteenfold, because the old population contained not one
mid-project update and so measured the engine only on the easiest schedules P6
produces (docs/LIMITATIONS.md §1). The fall was kept and explained. It then
rose to 61.77% and to 61.89% on that same fixed corpus as two real arithmetic
defects were fixed, and to 67.50% the next day on two more.
A single arithmetic defect was worth 1.26 points, and the per-project median
went down while the aggregate rose — 85.7% to 85.6% — because the fix reached
nine projects out of 82 (docs/LIMITATIONS.md §1). Defects of that size sitting
in a lag rule and a date converter say how much is still wrong, not how far this
has come. That median is a pre-2 September measurement and has not been
re-derived since; it is the figure most likely to have moved without the
aggregate saying so.
The largest movement of the five was not in the scheduler at all, and reads
the same way. On 2 September 2026 two defects in the importer were fixed — a
project calendar that did not inherit its base calendar's exception days, and a
midnight act_end_date read as a day end where P6 means a day start — and the
figure went 61.89% to 67.50%. Both are fields P6 stores rather than computes,
which is the test this repository applies before a field is allowed into the
model. Over the same commit, agreement with MPXJ — a second, independent
importer — fell, 99.60% to 99.43%, on 1,408 rows where MPXJ keeps P6's raw
midnight stamp. That arm measures agreement with another importer's convention
rather than with P6's stored dates, and both movements are what the evidence
says rather than what would read best.
The third movement of that day is not a movement in agreement at all, and it
is the one most easily misread. is_longest_path had been publishing membership of a
chain — one driving predecessor per hop — where P6's driving_path_flag marks
membership of the set: the backward closure over driving relationships, which
branches at every tie. A chain is a subset of its set, so the disagreement could
only run one way and did, 2,564 rows to 94. Publishing the set took the headline
67.54% to 67.71% and the DRIVING_PATH disagreement class from 2,658 rows to
1,628, with every other class unchanged count for count — which is the evidence
that a definition moved and no date did. The same evidence, scored against a
corrected question. The ordered chain is still computed and published under its
own name, because "is the longest path continuous" is a question a set cannot
answer.
And a fourth movement, of a fourth kind again: 67.71% to 67.80%, with 77.85% to 77.97% beside it. A constraint stamp was being resolved with the start-of-day rule where the constraint it carries asks for the end of one — a calendar rule, neither arithmetic nor a definition. It is +526 comparisons, and one project of the eight it touched went down by one comparison, because two of its rows landed on P6's own stored answer where they had been landing on ours. That fall was kept and reported, which is what this repository does with a correct fix that lowers a number. Twenty-one other commits the same day were measured to move this corpus by exactly zero comparisons, identical project by project across all 82.
Four movements in one day, and no two of them are the same kind of movement: two fields the importer was not reading, then arithmetic, then a change of definition, then a calendar rule. A page that presents them as one number improving four times is telling a false story with correct digits.
If you stop here: the scheduling logic is internally consistent, deterministic and property-checked, which is not the same thing as agreeing with the software that produced the file.
2. What the engine does
It reads a submitted construction schedule and answers two different kinds of
question. First, conformance: does this schedule comply with the
specification that governs it — docs/CONFORMANCE.md publishes 351 rules across
fourteen packs (UFGS 01 32 01.00 10, ANSI/ASCE/CI 67-17, AACE RP 29R-03, the SCL
Protocol 2nd ed., an AACE review checklist pack, and eight contract-named or
agency packs — VDOT, GAO, AACE 84R-13, Caltrans, PASEG, NYSDOT, NAVFAC, WisDOT
and WVDOH), with a governed precedence per jurisdiction so that only
rules from an authority that actually binds appear in the report at all. That
is the size of the library and not what any one command runs, and the two have
been confused on our own pages twice: --jurisdiction us_federal runs 120 of
them, us_state_or_private and uk_scl 72 each, neutral 107, and a
--contract name adds its own pack. Of the 351, none can any longer return a
verdict about a population it cannot observe — ten could until 2 September
2026, eight of them a PASS no schedule could falsify
(engine/quality/PROJECTION-BLINDNESS.md). Second,
forensic delay analysis: all nine AACE RP 29R-03 Methods of Implementation
run end to end, plus prospective TIA under RP 52R-06 (docs/METHODS.md, whose
table is generated from the same catalogue the code uses). ~~Three schedule
formats are read — XER, P6 XML and Microsoft Project MSPDI — detected from file
contents rather than from the suffix.~~ Corrected 6 September 2026: four are
read, and the count was wrong on the page that exists to be checked. The
importer sniffs XER, P6 XML, Microsoft Project MSPDI and USACE SDEF
(cpmcore/sdef.py, selected by cli.py::_detect), from file contents rather
than from the suffix; the tool's own refusal message names all four, and this
sentence named three. Read the correction the way §3 asks you to read every
count here: only the XER reader has been measured against files this project
did not write, the other three rest on our own tests, and a fourth format in
that group is a fourth thing unvalidated rather than a fourth thing proved.
The author holds no PE, no PSP and no
CFCC; credentialing/LEGAL-POSTURE.md binds what may be claimed, and the tool
supplies a computation while a person supplies the opinion.
3. What is measured, and against what denominator
P6's own stored answers, held-out corpus. 67.85% as above. The corpus is 68
harvested public XER files, 82 projects, 86,031 scheduled activities
(engine/oracle/corpus/README.md, 2026-09-01). The files are gitignored and
fetched by a pinned, digest-verified script; most source repositories state no
licence, which is an absence of a grant and not a permission.
P6's own stored answers, first-party fixture. 156 of 160 field comparisons,
97.5%, on 27 activities across 13 networks captured from a real P6 23.12
installation (engine/oracle/README.md). Read it as "no divergence detected on
the semantics these 13 cases exercise" and never as "agrees with P6" — no
network in it is wider than a two- or three-activity chain.
Published worked examples. Better than the corpus per case, because it is the
only oracle in the tree independent of Primavera: if P6 and this engine shared a
misconception, no amount of XER diffing would surface it and an AACE figure
would. The cases are in engine/oracle/cases/, each naming its document,
section, and the file and line range it came from; a test fails if any case
lacks that citation. Two caveats the owning document states and this page will
not soften: the 29R-03 Figure 8/9 topology is a defended reconstruction rather
than the RP's own drawing, and several cases test an assertion the RP makes
using numbers we chose, marked numbers_from_source: false in the case file.
Every case is under six activities, with no progress, constraints or holidays.
Our reader against a second reader. engine/oracle/FIDELITY.md, added
2 September 2026, is the first tier here that measures the importer rather
than the scheduler, which matters because 265 of the 351 conformance rules never
touch the CPM arithmetic. Our import of an XER against MPXJ's import of the same
bytes is 1,923,733 of 1,947,919, 98.76%, over 80 projects in 65 files, and
of the 24,186 remaining disagreements every one has a named cause; one class,
RELATION_TYPE, is an open candidate defect of ours and our reader already warns
about it. (Updated 2026-09-05. It read 99.45% over 64 projects in 50 files
until the fifteen files recorded as unreadable by MPXJ turned out to be our own
test driver crashing; on those same 64 projects the figure is unchanged to the
cell, so the fall is the population and not the reading.) It measures agreement
with another importer's convention, not with
P6's stored dates, so it falls when we move toward P6 and that is not a
regression.
The forensic layer against a delay of known size. Every tier above measures
arithmetic. engine/oracle/injection/MATRIX.md injects a hand-counted delay
into a five-activity network and asks whether each MIP reports the delay that
was injected — the first ground truth in this repository that is neither "us
against P6" nor "us against MPXJ". All five exercised methods recovered every
headline figure, including a placebo and a neutral control that both correctly
reported zero. Read docs/LIMITATIONS.md §11 next and not this paragraph
alone: the same run is where the attribution limits were demonstrated, and it
is the least flattering document in the repository.
How often a rule answers at all. Registered and answering are different
numbers and only the second is the product: 39.8% of rule-file pairs return a
verdict, 48.7% when the submission names its baseline, and all 13,099
abstentions name a specific missing input
(engine/quality/VERDICT-YIELD.md §16, re-measured 2026-09-06 with a control
arm at the same revision, and before that 2026-09-05 from two git
archive extractions outside the repository; the 2026-09-04 run reproduces to
the digit on its own revision, and that one reproduces the 2026-09-02 run).
That figure fell from 40.5% on 2026-09-02, and the reason is the point
rather than the digit. One rule — SCL-CP1-1.59 — had been publishing
"PASS — all 1 programme versions supplied are distinct" on every single-file
submission, because both of its adverse branches quantify over pairs of
programmes and a single submission has none. It could not have failed for any
input whatsoever, and it shipped that verdict 66 times against a Society of
Construction Law clause. It now abstains below two versions. No FAIL count
moved; 66 unfalsifiable passes became 66 honest abstentions, and the yield
dropped 0.3 points because an unfalsifiable PASS was never yield in the first
place (engine/quality/NEVER-ADVERSE.md).
It has since happened twice more, in the same direction and for the same reason.
UFGS-071 was withdrawn on a snapshot that had already computed, and UFGS-044
stopped passing on five files where a widened out-of-sequence check found
progress it had been blind to — so the clause now abstains naming the approvals
register instead of passing over work it had not seen. Three withdrawals, 137
rule-file pairs, no FAIL count moved in any of them. That is the whole of the
fall from 40.5% to 39.9%: no rule gained an answer, three rules stopped
publishing answers they had not earned, and the same repair that produced the
last of the three added twenty adverse findings a reviewer can act on
(engine/quality/VERDICT-YIELD.md §7.1).
It fell again the next day, 39.9% to 38.6%, and the second fall is larger and
of the same kind (engine/quality/VERDICT-YIELD.md §13). A third fall, 38.6%
to 38.2%, is a different kind and §14 keeps it apart: four NAVFAC submission
clauses were made runnable and this corpus — single-file exports with no
baseline named — cannot reach three of them, so the answered count is unchanged
at 7,924 and only the denominator grew. Four more clauses
stopped deciding on evidence they did not have — UFGS-037, UFGS-038,
AACE-29R-03-2.3.D.3, ASCE-67-17-4.2, 61 files each, no rule gaining an
answer. And five corpus files left the population altogether: each holds
more than one project, and until 4 September a file like that produced one
complete, scored, confident review of whichever project the exporter happened to
write first — on one such file, a 181-clause federal report about a
1-activity stub out of 886. The tool now refuses the file and lists what it
holds. Those five were supplying 638 of the published 8,720 answers.
Two repairs went the other way in the same window and neither raised the
headline. UFGS-098's PASS branch was unreachable, so three real files had been
told they breached a federal clause they meet; they now pass. And UFGS-071 —
the clause withdrawn above for passing 66 times on 66 files that could not have
failed it — now fires exactly once, adversely, on the one corpus file with
circular logic, because a loop is reported rather than refused. A clause that
answers once about something true is the product; sixty-six that could not have
said anything else were never yield.
Answering is not discriminating, and this is the finding that most changes how
the number should be read. The same instrument now counts, separately from the
answered total, how many rules return a different verdict on different
schedules. Every contract input a reviewer could supply adds 68 rules that
answer and 8 that tell one schedule from another, across the then-331 rules and the
66 corpus files — the population as it stood on 4 September; §13.5 records that
these counts were not re-measured on 5 September and why no before-arm exists
for them. Under the UK SCL protocol's terms the answering count goes from
19 to 46 and the discriminating count from 12 to 12 — twenty-seven new answers
and no new discrimination, because those clauses interrogate the analysis
rather than the file, and against sixty-six unrelated schedules they give the
same answer sixty-six times. The agency specifications behave the opposite way,
and that is where the value sits: of the 972 new adverse findings the state-DOT
terms produce, 642 vary from file to file, because those terms are approval
registers and numeric limits checked against the reviewer's own activities. A
higher answered count is not automatically a better product
(engine/quality/VERDICT-YIELD.md §8.4, §9.1).
One rate is deliberately not published. That pass could have quoted a
corpus-wide adverse rate with the contract's terms supplied, and refused to,
because 65 of the 66 corpus files carry a data date before the terms file's own
dates and a clause comparing a 2026 date to a 2011 schedule cannot do anything
but fail. What is published instead is the one job those terms are true for:
on a single 800-activity file, 10 federal FAILs became 20, and 18 became 30
under the state-DOT bundle — one job, generated, with terms we wrote ourselves
(engine/quality/VERDICT-YIELD.md §9.1, §9.2).
How big, and how long. 19,202 activities and 28.6MB read and computed in
13.5 seconds on a 2017 four-core mobile i7; every stage linear in the activity
count and linear in relationship density; past the limit it refuses and names
what it refused (engine/quality/PERFORMANCE.md). Before that pass there was no
benchmark, no stated limit and no published figure for runtime or memory at any
size.
Mutation scores, per module, never the aggregate.
engine/quality/MUTATION-REPORT.md says in terms that an aggregate "should not
be quoted on its own". The current record is its seventh pass, 2026-09-02:
twenty modules measured at one fixed revision, b547c5c, on seed 20260901, in
a detached worktree nothing else could edit, every survivor re-run serially —
1,553 of 1,742 mutants killed, 89.2% — with five modules re-measured again
at 0f19183, where that later row is the current one. The spread is what to
read. resources.py at 64.8% exhaustive is the weakest, and is the module
the CLI cannot call at all; graph.py, issues.py, model.py and network.py
are at 100.0%; compare.py is 94.5%, progress_logic.py 96.4%,
modelled.py 90.9%, cpm.py 86.4%. The four figures this page carried
before — 98.2%, 91.8%, 88.3%, 88.2% — are superseded by those rows and are not
corrected by them: cpm.py and progress_logic.py each differ by two mutants
in a 110-mutant sample drawn on a seed the earlier pass did not use, which the
report reads as unchanged, re-measured rather than as a fall.
Four earlier scores in the high nineties were withdrawn when the harness was
caught reporting kills it had not made — both the reason to trust the current
figures and the reason to read the ledger. quality/MUTATION-LEDGER.json now
carries revision and seed on 25 of its 48 rows: every seventh-pass row
records which commit the engine was at and which seed drew the sample, so
git worktree add --detach <path> b547c5c and mutation.py --seed 20260901
draw the same mutants from the same population again. On the 23 rows measured
before those fields existed both are null and are not recoverable — inferring
a commit from a file's mtime would be a guess presented as a record. What is
still missing, in the terms the pass itself named it: the per-mutant survivor
lists are gitignored, so a reader can re-derive these figures and cannot audit
our run; nothing here checks that the run happened, only that the ledger agrees
with the results files it was written from; eight modules named in SUBSETS —
progress, earned, levelling, locations, takt, lastplanner,
weather, portfolio — were never measured at all, so 89.2% is a total over
the twenty modules this project publishes and not over cpmcore; and a score is
still the score of its subset, which widening SUBSETS can only raise.
One movement is worth stating without its percentage. windows.py had been
published at 92.6%, measured 86.2% exhaustive at b547c5c, and is 98.3% at
0f19183. The gap between the first two was real and the exhaustive runs make
it readable: seven of the eight survivors sat in one block,
WINDOWS.NO_COMMON_IDENTITY, which no test in the suite ever touched — it could
have been deleted and CI would have stayed green. That block is what stops a
window publishing a slip, an attribution and a driving path measured across two
schedules that pair no activity at all, which is what P6's renumbered internal
ids produce when a series is matched on ID rather than CODE. One test in
tests/test_mutation_gaps.py closed it and all eleven of the block's mutants
are killed. The finding is a safety property that was unguarded, not twelve
points.
The report's own assessment is that the suite "tests what the engine computes and not what it reports". That is the finding, not the percentages.
How much of the product the 67.85% speaks for. docs/RULE-DEPENDENCE.md,
derived from the rules' own bytecode rather than written by hand, partitions all
351 rules across all fourteen packs: 56 rest on the CPM arithmetic (16.0%), 30
are engine-gated, and 265 do not touch it. The three sum to 351, which is
asserted rather than assumed: engine/tests/test_rule_dependence.py binds the
owner's total row to the code. For UFGS specifically, 35 of 48
rules are independent of the engine entirely. The partition covers every pack in
the package because it discovers them rather than listing them — the defect that
held it at five packs while the library had six is fixed, and the eight packs
that landed afterwards needed no edit to it.
4. What is not measured
Nobody has run this on a real project. Zero customers, zero users. Every
statement anywhere in business/ about what a reviewer wants is derived from
specifications, standards and one published study, not from a reviewer
(docs/LIMITATIONS.md §2, docs/STATE-OF-PLAY.md §3).
Importer fidelity has now been measured, and the admission it used to be is
worth keeping in view because it was the sharpest one available.
265 of the 351 partitioned rules are facts read out of the submitted file — is a
data date declared, are there open ends, is this relationship start-to-finish.
They do not inherit the agreement figure at all; they are exactly as good as the
importer's reading of the file, which docs/RULE-DEPENDENCE.md names as a
separate question. That question went unanswered until 2 September 2026 and is
now answered: engine/oracle/FIDELITY.md reads our import of an XER against
MPXJ's import of the same bytes and reports 1,923,733 of 1,947,919, 98.76%,
over 80 projects in 65 files, with the 24,186 remaining disagreements partitioned
and one open candidate defect of ours among them, which our reader already
warns about. The gate that ROADMAP item 4 asked for exists and owns its figure.
(Updated 2026-09-05 from 99.45% over 64 projects in 50 files; the fifteen files
this page counted as unreadable by MPXJ were our own test driver crashing, and on
the old 64 projects the figure is unchanged to the cell.)
Read it with two cautions rather than as a clean bill. It measures agreement
with another importer's convention, not with what P6 stored — which is why it
correctly fell, 99.60% to 99.43%, over the very commit that moved us toward
P6's own stored dates. And it does not cover every field: where no independent
quantity exists for a field, that field is named as unmeasurable rather than
scored. For how much this should have worried you before it was measured, an
importer bug once made every calendar in every real XER fall back silently to
Monday–Friday, invisible because the fixture used a format P6 does not write
(engine/oracle/README.md).
The customer's actual job is a monthly sequence and the corpus cannot test
one. engine/quality/SERIES-COHERENCE.md records six genuine series and
every one is exactly two data dates long; there is no series of three or
more that this engine can load, and two rules in the pack are unusable as a
result. It answers "can this be used month after month?" with "Not yet."
Two of the kernel defects this project published against itself were not defects, and that is a finding about the method rather than an embarrassment. This bullet named an open defect in the arithmetic that decides criticality — B3, the late finish capped at the project finish — until 2026-09-02. B3 was withdrawn, as M1 was the day before. Neither was closed by a fix:
- M1 was our own comparison adapter stamping a finish constraint at 17:00 against a corpus that stamps 08:00. One day on a half-open axis, which was the whole of the finding.
- B3 reproduces digit for digit and always did; what was wrong was the
verdict. Measured by rescheduling rather than by comparing engines, both of the
engine's numbers are exact — total float 6 because slipping six days leaves the
finish put and seven moves it, free float 12 because the successor first moves
at thirteen.
TF >= FFis not a property of a network carrying a lead. The narrow fix was built and measured before it was refused, and on the one real instance of the shape in 82 projects and 89,596 activities P6 stored the value we already produce.
Read that in whichever direction you find harder. The weak reading is that a differential oracle reports a disagreement and does not report which side is wrong, and this project read a disagreement as a verdict against itself twice out of the three times it named its own kernel — so a tier (b) finding here is a question, not a verdict, and a page like this one carrying "an open kernel defect" was, for a week, simply wrong. The strong reading is that both false positives were caught by us, by measurement written into a test rather than into a paragraph, and that in the B3 case the fix that would have made the disagreement disappear was built, measured, and thrown away because the measurement said not to. Both readings are true and neither cancels the other. What is left in that tier is three unsettled semantics — B5, B6, M9 — each needing a donated P6 file to settle and none with a side established as wrong.
What the checks themselves do not cover is written down. Do not read a green
suite as coverage. engine/tests/test_docs_match_the_catalogue.py publishes a
NOT_CHECKED block naming what escapes its documentation tests;
engine/src/forensic/rules/citations.py publishes one naming the packs whose
citations are unverified and why; docs/CONFORMANCE.md §4 lists what the rule
packs do not check, by clause number. Those three are worth more than the tests
around them and are the first thing to read if you are trying to break this.
5. Two disagreements found while writing this page
Recorded rather than resolved: the owning files are not this page's to edit, and a finding not in a file does not exist.
M1. Resolved 2026-09-02, and the count moved twice more than this entry
expected. As written, this said docs/STATE-OF-PLAY.md §3,
business/BUSINESS-PLAN.md and business/RISKS.md say "two open kernel defects,
B3 and M1, both URGENT and open", against
engine/oracle/differential/FINDINGS.md, which marks M1 WITHDRAWN on
2026-09-01 as an adapter convention. Two corrections to that:
business/RISKS.mdwas never a carrier. Its "M1" is a risk-register event ID in a different namespace. Naming it here was an error, corrected at0016587. The real carriers weredocs/STATE-OF-PLAY.md,business/BUSINESS-PLAN.mdandROADMAP.md.- B3 has since been withdrawn too, at
9609c93on 2026-09-02 — a wrong invariant, not an adapter this time. So the count went two → one → none, and §4 above now carries what that says about the method.
~~The vdot pack is outside the dependence partition.~~ Fixed 2 September
2026, and kept here because it is the seventh instance of the class. It was:
docs/CONFORMANCE.md published 242 rules across six packs;
docs/RULE-DEPENDENCE.md partitioned 216 across five, and
engine/tests/test_rule_dependence.py held it there because the test named five
registries by hand. Both pages were green, so vdot's 26 rules sat outside the
partition and outside the dynamic witness that catches a rule reaching a
computed field it was not classified for — a check whose subject is a list the
check itself maintains. PACKS is now discovered by walking the package, the
partition covers all thirteen, and the eight packs that landed afterwards needed
no edit to it, which is the only proof that the fix was the right shape.
An eighth instance was found the same day, and this one was in the rules
rather than in a test. Ten conformance rules were returning verdicts about
level-of-effort and WBS-summary activities that ExchangeSchedule.to_network()
had already dropped: eight returned a PASS no schedule could falsify, one
restated an unfalsifiable sentence as an observation, and one printed a count of
zero for a population of 297. All ten now decide from the file or report
NOT_EVALUATED naming what would decide them, the count of rules that cannot
fail is 0 of 351, and a test fails if that changes
(engine/quality/PROJECTION-BLINDNESS.md). The residual is a real coverage gap
— on a file carrying such activities, six clauses about their logic and their
place on the critical path are not answered at all — and it is now printed as a
gap in every report on such a file rather than absorbed into a PASS. 11 of the
69 corpus files reach it.
One staleness. engine/oracle/README.md's tier table describes eleven
worked-example cases and 94 assertions; engine/oracle/cases/ holds seventeen
case files as of 1 September 2026. ls settles it in five seconds, which is the
point of §8.
6. The architectural ceiling, and why it is credible
The time axis is whole-day. P6 finishes an in-progress activity with a fractional remaining duration at a mid-day instant and starts its finish-to-start successor at that same instant on that same date; a whole-day engine cannot, so it loses a working day at the link on top of the one lost inside the activity.
That mechanism is controlled, not merely correlated: taking only activities
all of whose predecessors already agree with P6, 5,441 activities in 22 files
hand off at a mid-day instant and the successor's start is one working day late
on 5,429 of them — 99.8% — against a matched control of 1,974 activities handing
off at a day boundary, of which 1,944 agree exactly, 98.5%
(engine/oracle/corpus/MIDDAY-MECHANISM.md).
The ceiling was measured by a failed attempt to breach it, which is why it is worth more than an assertion. A derivation built deliberately stronger than any engine could be — carrying the offset exactly in minutes, and choosing the driving predecessor using P6's own stored dates, an advantage this engine does not have — recovers 70.0% of the affected rows while misfiring on 14.2% of the rows currently correct. That defeats the fix as specified. It is not a proof that no derivation exists, and the owning document does not claim one.
Two qualifications. The mechanism is not a diagnosis of the gap: in the file
where it was found it accounts for 15.5% of the unstarted rows, and the largest
single unexplained thing in the corpus is 230 forward-pass origins in that same
file whose predecessors all agree. And a bound this project published for months
turned out to be false and was replaced by a measured one
(docs/LIMITATIONS.md §1).
7. What should make you look further, and what should make you walk away
Walk away if you need a validated recomputation engine. 67.85% is not a qualification for work an opposing expert will cross-examine, part of the remaining gap has a measured ceiling rather than a fix date, and no customer has ever run this.
Walk away if the venture argument does not survive. docs/POSITIONING.md §6
states the argument against at full strength — the buyer is a person who signs a
report, not a computation; the part that genuinely automates is commoditised at a
few hundred dollars a year; refusal discipline hands the expert back precisely
the questions they were being paid to answer. It then concedes what its own
rebuttal costs: the response moves the venture off high-value forensic work onto
specification conformance, where the nine-of-nine method claim is not what is
being bought. So the strongest form of the argument is not "this cannot be
sold" but "the thing that is differentiated and the thing that is saleable are
not the same thing", and that tension is unresolved. If that is your question,
read §6 before anything else here.
And the failure mode the project names for itself. docs/STATE-OF-PLAY.md
§6: the likeliest way this fails is that it never becomes a product and becomes
an artefact — the work stays excellent and inward. It sets a checkable sign: if
by 15 September 2026 no file in the tree records a conversation with a named
practitioner, the diagnosis is confirmed.
Look further if what you need is the conformance layer. 265 of 351 rules read
the file rather than the arithmetic, all nine methods run, precedence is governed
rather than assumed, and the report refuses to decide what it cannot decide. That
layer is not capped by 67.85%. It is capped by importer fidelity, which is now
measured at 98.76% against MPXJ on the same bytes, over 80 of the 84 projects
on disk — so the thing to ask for is not a better agreement number but what the
remaining 24,186 disagreements are,
and engine/oracle/FIDELITY.md partitions them.
Look further if the discipline is what you are buying. The evidence is behavioural. A leak was found where the tool read P6's own computed finish back in as an input; removing it dropped agreement on one file and raised it thirty points on another, and the fall was kept and published. Four mutation scores were withdrawn when the instrument was caught flattering itself. A plausible fix that raised the number was falsified and refused. And two defects this project published against its own kernel turned out not to be defects — both withdrawn by measurement rather than by argument, one of them after the fix was built and thrown away because measuring it said not to (§4). Note which way that last one cuts: it means a published "urgent, open" defect stood in five documents for a week on the strength of a disagreement nobody had re-measured. The discipline is real and it is not fast. That is the only real differentiator here.
8. Checking any of this yourself
All of it from engine/, after pip install -e ".[dev]":
python check.py # the gate: unit suite, oracle suite, import contracts, P6
python oracle/harness.py oracle/cases/p6-23.12-xval.oracle.xer # the 156/160
pytest oracle/ && ls oracle/cases/*.json # the independent worked examples
pytest tests/test_rule_dependence.py # the 265/30/56 partition, derived
python quality/ledger.py --markdown # every mutation score's arithmetic
python -m forensic check oracle/cases/update-chain-02-update.xer --jurisdiction us_federal
python -m forensic analyse oracle/cases/update-chain-01-baseline.xer \
oracle/cases/update-chain-02-update.xer \
oracle/cases/update-chain-03-update.xer --method 3.3 --baseline 0
The last two lines were corrected 6 September 2026 and the correction is this
page's own subject. They read update-07.xer and update-06.xer — names
this repository has never held — so a sceptic following the section titled
checking any of this yourself was answered update-07.xer: No such file or
directory and exit 2 on the two commands that exercise the product rather
than the test suite. The files above are in the clone. --baseline 0 is on the
second because MIP 3.3 refuses to guess which file is the contract baseline,
and --method 3.3 needs at least two updates to have a window between them.
Both exit 1 here, which is a report with findings and not a failure to run.
The corpus figure. The files are gitignored, so this fetches all 68 by pinned commit and verifies every digest before measuring:
cd oracle/corpus && python fetch_corpus.py --verify && python gapshape.py
Exit code 0 from the CLI means no blocking failure was found, which — given
the coverage the report prints — is a weaker claim than conforms;
READING-A-REPORT.md explains the difference.
Where to go next. LIMITATIONS.md in full,
POSITIONING.md (POSITIONING.md) §6 for the argument against the venture, and
OPEN-ITEMS.md (OPEN-ITEMS.md) for everything recorded anywhere here as
unfinished, unverified, deferred or known-wrong. This page is a route into
those, not a substitute for them.
Source: docs/IS-THIS-REAL.md. Source commit date: 2026-09-06.